mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-10 13:58:09 -05:00
Compare commits
298 Commits
v1.0.0-alp
...
v1.0.0-alp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
551b03d6e6 | ||
|
|
c4e64afd07 | ||
|
|
d98a6dda8f | ||
|
|
8aaa5b6ad0 | ||
|
|
f92244d497 | ||
|
|
e91165b0b4 | ||
|
|
e15a0b08aa | ||
|
|
a3a77ab5a8 | ||
|
|
650ec797da | ||
|
|
f629c72107 | ||
|
|
98a20766c9 | ||
|
|
1f707842d2 | ||
|
|
c944f29c7c | ||
|
|
6b5265d2d4 | ||
|
|
8f64eb622e | ||
|
|
4ddacd57c6 | ||
|
|
a66f434236 | ||
|
|
796c336a29 | ||
|
|
48fcb08ebc | ||
|
|
1315a15d9d | ||
|
|
25ebed9a70 | ||
|
|
703907bd99 | ||
|
|
d4e6ce6998 | ||
|
|
390a589afb | ||
|
|
d34156bfe6 | ||
|
|
7c8492e83f | ||
|
|
668163d740 | ||
|
|
7ad2929f0f | ||
|
|
9ce64e2428 | ||
|
|
ae78546323 | ||
|
|
23bce8d0c5 | ||
|
|
29137f7b39 | ||
|
|
bf4a8dcee9 | ||
|
|
7b5f71229e | ||
|
|
4d7797827e | ||
|
|
c0ed43d920 | ||
|
|
842c15856b | ||
|
|
20ac925ee4 | ||
|
|
6e8ff10003 | ||
|
|
419fad07cd | ||
|
|
cf1c346beb | ||
|
|
3e0b20529b | ||
|
|
d9ae2073e2 | ||
|
|
7b3efcf62b | ||
|
|
c7d01fd73c | ||
|
|
2916d183e8 | ||
|
|
c24fb792cb | ||
|
|
70f3fcdbd9 | ||
|
|
ecfdb354a7 | ||
|
|
690fa12f1a | ||
|
|
63c1057ae6 | ||
|
|
1eee1948bb | ||
|
|
e36e9250f1 | ||
|
|
b589ddd774 | ||
|
|
ba01abbc8f | ||
|
|
fa82b09cec | ||
|
|
7d9a706cfa | ||
|
|
437bab7df0 | ||
|
|
ee747ca6d4 | ||
|
|
de93551332 | ||
|
|
0839f10dbc | ||
|
|
d169b490fa | ||
|
|
490cf9b7ba | ||
|
|
95a5b4945b | ||
|
|
4aea039324 | ||
|
|
23181c8629 | ||
|
|
d23b247a82 | ||
|
|
5178474280 | ||
|
|
d5caee35fa | ||
|
|
558ee2678b | ||
|
|
e1f8a37710 | ||
|
|
e07b71b81d | ||
|
|
db92d90309 | ||
|
|
e2eb2fb0d8 | ||
|
|
953960c860 | ||
|
|
7664eab32d | ||
|
|
16cdcf5dec | ||
|
|
3b5ef50733 | ||
|
|
529554f3f9 | ||
|
|
fe9921457c | ||
|
|
bedb16cfb0 | ||
|
|
0921c00094 | ||
|
|
6ef4995329 | ||
|
|
1e0b4e150e | ||
|
|
951c139cff | ||
|
|
eb3e4944e9 | ||
|
|
bb98046608 | ||
|
|
4ac0bbca19 | ||
|
|
c0c34f3d3a | ||
|
|
77c95f3051 | ||
|
|
68d0c09daf | ||
|
|
282f3eec01 | ||
|
|
4a549ffe2b | ||
|
|
d138c608bc | ||
|
|
c7ff3a4f22 | ||
|
|
7a96412ef2 | ||
|
|
5821454ac7 | ||
|
|
90978cd22e | ||
|
|
76a3070fd7 | ||
|
|
1bc0cc7049 | ||
|
|
ff69375fbd | ||
|
|
5b814009fa | ||
|
|
99164761f5 | ||
|
|
e1cd9143e0 | ||
|
|
4d232feda8 | ||
|
|
d687270a89 | ||
|
|
6d8207801c | ||
|
|
6ad117b175 | ||
|
|
f9e062407f | ||
|
|
dca93ce641 | ||
|
|
347aa14a28 | ||
|
|
3621b2ff25 | ||
|
|
49ae42c249 | ||
|
|
1ce7cd5f50 | ||
|
|
305fdd2e1b | ||
|
|
984cb38680 | ||
|
|
bbdd20e898 | ||
|
|
568cd3c9ec | ||
|
|
b09b1f3fa5 | ||
|
|
22bcfd2c34 | ||
|
|
ba440abe2d | ||
|
|
09640ae22d | ||
|
|
719e99ffd9 | ||
|
|
1a4129f5a6 | ||
|
|
de3f112a05 | ||
|
|
3734bfacce | ||
|
|
d5e2b51d66 | ||
|
|
cdd28abc4b | ||
|
|
8c8f59e242 | ||
|
|
b1f9f97062 | ||
|
|
7545d3f2b3 | ||
|
|
bdf8bf7be2 | ||
|
|
b928e9531c | ||
|
|
1f6afa8547 | ||
|
|
303edbde58 | ||
|
|
208ea56a9c | ||
|
|
c8b91ba7b0 | ||
|
|
268df90ddd | ||
|
|
749aba8d09 | ||
|
|
7920afb12e | ||
|
|
cc147c7097 | ||
|
|
852082cdb4 | ||
|
|
e927a3d170 | ||
|
|
7c2096f209 | ||
|
|
dcdf5d0eac | ||
|
|
3db6784990 | ||
|
|
d51ead76eb | ||
|
|
a2cf235687 | ||
|
|
e1e233a6d0 | ||
|
|
76bac74562 | ||
|
|
a335bbbb61 | ||
|
|
913e4aa538 | ||
|
|
4b4641bae3 | ||
|
|
6bfb2b1e46 | ||
|
|
a97de0d474 | ||
|
|
f6d3c28ae1 | ||
|
|
3197748240 | ||
|
|
14dbc2b74d | ||
|
|
b0917db4c7 | ||
|
|
ee4ebe4c38 | ||
|
|
56d6e05196 | ||
|
|
bb374362e4 | ||
|
|
c1114fa6be | ||
|
|
36c921c601 | ||
|
|
f31f49582b | ||
|
|
cebb62997d | ||
|
|
e477df321c | ||
|
|
828156b9d4 | ||
|
|
aaa3abf630 | ||
|
|
e1aa920fc6 | ||
|
|
fcfd828725 | ||
|
|
3374a06f63 | ||
|
|
0b497e57e4 | ||
|
|
af46fc7707 | ||
|
|
b1e2238df9 | ||
|
|
acddb6035a | ||
|
|
3147a5ee01 | ||
|
|
572227d25e | ||
|
|
84273e9a34 | ||
|
|
114fac5149 | ||
|
|
2d9fe5f2cf | ||
|
|
6daf45cb8f | ||
|
|
c8e93f8789 | ||
|
|
94fa046ce1 | ||
|
|
a74cf5de90 | ||
|
|
6d83770534 | ||
|
|
593442a0fa | ||
|
|
bd46abc71d | ||
|
|
cb1f44872d | ||
|
|
8baa22f065 | ||
|
|
f4848e46d4 | ||
|
|
f04fffb5fe | ||
|
|
51f2cc18e5 | ||
|
|
3de626f0d0 | ||
|
|
a81214219d | ||
|
|
245c18784e | ||
|
|
9219dc77ff | ||
|
|
1de230110d | ||
|
|
b6607fac25 | ||
|
|
e6277ec536 | ||
|
|
0961fef727 | ||
|
|
366b98ac83 | ||
|
|
c2425e81d7 | ||
|
|
8f2950d374 | ||
|
|
f4a6864343 | ||
|
|
c1a7c65e05 | ||
|
|
7fd2536d54 | ||
|
|
0e6797d80d | ||
|
|
b2b4c2660d | ||
|
|
787857c38b | ||
|
|
1cc21ed3c4 | ||
|
|
7588e491ab | ||
|
|
afce363e00 | ||
|
|
7de3ce0b31 | ||
|
|
6e6b871cc1 | ||
|
|
2349012bd0 | ||
|
|
b4c0a89d49 | ||
|
|
d368156a08 | ||
|
|
63149a3dc3 | ||
|
|
fbe088625a | ||
|
|
ecbab20bad | ||
|
|
381b5be0fc | ||
|
|
6803f3308a | ||
|
|
60558b7970 | ||
|
|
7854b91ae0 | ||
|
|
c9c7cc7b93 | ||
|
|
b538f5073d | ||
|
|
3ed7b23ed7 | ||
|
|
c2b94d04ed | ||
|
|
3316516d22 | ||
|
|
12c1daaf2b | ||
|
|
f09620c9f6 | ||
|
|
e47e7067c4 | ||
|
|
4edcf92140 | ||
|
|
7463f2cffd | ||
|
|
fea2cc9e2f | ||
|
|
bd489e345a | ||
|
|
b98b9b740b | ||
|
|
b7175b3482 | ||
|
|
7d28146e1e | ||
|
|
5bfc457904 | ||
|
|
13324674ba | ||
|
|
c78bfab69d | ||
|
|
2ee025ee88 | ||
|
|
0410b14260 | ||
|
|
2c3558e449 | ||
|
|
e95393f671 | ||
|
|
73cb6daf46 | ||
|
|
8a8edf3743 | ||
|
|
900e7114da | ||
|
|
ba00c55f95 | ||
|
|
8240eb0416 | ||
|
|
ba07ccb484 | ||
|
|
3d9cde3e1c | ||
|
|
b291eb7953 | ||
|
|
f61f02e59b | ||
|
|
48fd40e35b | ||
|
|
d8ea41ce35 | ||
|
|
e556ac348a | ||
|
|
c764099231 | ||
|
|
b954db9704 | ||
|
|
c9c4cd9f87 | ||
|
|
880298d844 | ||
|
|
21a56d5419 | ||
|
|
5c9830f0c3 | ||
|
|
5d0f6c5b16 | ||
|
|
5cee10f28e | ||
|
|
78a25f99c3 | ||
|
|
706f375aed | ||
|
|
5977343a0d | ||
|
|
f2afeed9da | ||
|
|
e69ed7c778 | ||
|
|
c9caf5dfc5 | ||
|
|
b4c7a14759 | ||
|
|
92e1a996cc | ||
|
|
6228b3cd9f | ||
|
|
8686a81304 | ||
|
|
05d6dc7a10 | ||
|
|
ec1dd85c44 | ||
|
|
7b0b8ee126 | ||
|
|
55074bcc6c | ||
|
|
89e279f9c8 | ||
|
|
40db6cb0cf | ||
|
|
45e4ed25a3 | ||
|
|
e93d31c60e | ||
|
|
8bdf9db147 | ||
|
|
2bf1332e5c | ||
|
|
7744c3ae47 | ||
|
|
ba5da21026 | ||
|
|
395ea76f44 | ||
|
|
3aa95b9c16 | ||
|
|
bc20591b72 | ||
|
|
85a040bfd2 | ||
|
|
399dc85737 | ||
|
|
9bf80219c9 | ||
|
|
14cd25f9dc | ||
|
|
d81c9ffcfc | ||
|
|
27c8402ae0 |
17
.bazelrc
17
.bazelrc
@@ -33,9 +33,17 @@ build --define kafka_enabled=false
|
||||
test --define kafka_enabled=false
|
||||
run --define kafka_enabled=false
|
||||
|
||||
# Enable blst by default, we use a config so that our fuzzer stops complaining.
|
||||
build --config=blst_enabled
|
||||
test --config=blst_enabled
|
||||
run --config=blst_enabled
|
||||
|
||||
build:kafka_enabled --define kafka_enabled=true
|
||||
build:kafka_enabled --define gotags=kafka_enabled
|
||||
|
||||
build:blst_enabled --define blst_enabled=true
|
||||
build:blst_enabled --define gotags=blst_enabled
|
||||
|
||||
# Release flags
|
||||
build:release --workspace_status_command=./scripts/workspace_status.sh
|
||||
build:release --stamp
|
||||
@@ -69,18 +77,13 @@ 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 --define=gc_goopts=-d=libfuzzer,checkptr
|
||||
build:fuzz --run_under=//tools:fuzz_wrapper
|
||||
build:fuzz --compilation_mode=opt
|
||||
build:fuzz --define=blst_enabled=false
|
||||
|
||||
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
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
#
|
||||
# This config is loaded from https://github.com/bazelbuild/bazel-toolchains/blob/master/bazelrc/latest.bazelrc
|
||||
build:remote-cache --remote_timeout=3600
|
||||
build:remote-cache --spawn_strategy=standalone
|
||||
build:remote-cache --strategy=Javac=standalone
|
||||
build:remote-cache --strategy=Closure=standalone
|
||||
build:remote-cache --strategy=Genrule=standalone
|
||||
#build:remote-cache --spawn_strategy=standalone
|
||||
#build:remote-cache --strategy=Javac=standalone
|
||||
#build:remote-cache --strategy=Closure=standalone
|
||||
#build:remote-cache --strategy=Genrule=standalone
|
||||
|
||||
# Prysm specific remote-cache properties.
|
||||
#build:remote-cache --disk_cache=
|
||||
@@ -34,16 +34,5 @@ build --flaky_test_attempts=5
|
||||
# Disabled race detection due to unstable test results under constrained environment build kite
|
||||
# build --features=race
|
||||
|
||||
# Enable kafka for CI tests only.
|
||||
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
|
||||
|
||||
12
.deepsource.toml
Normal file
12
.deepsource.toml
Normal file
@@ -0,0 +1,12 @@
|
||||
version = 1
|
||||
|
||||
[[analyzers]]
|
||||
name = "go"
|
||||
enabled = true
|
||||
|
||||
[analyzers.meta]
|
||||
import_paths = ["github.com/prysmaticlabs/prysm"]
|
||||
|
||||
[[analyzers]]
|
||||
name = "test-coverage"
|
||||
enabled = true
|
||||
3
.github/workflows/go.yml
vendored
3
.github/workflows/go.yml
vendored
@@ -43,7 +43,8 @@ jobs:
|
||||
go get -v -t -d ./...
|
||||
|
||||
- name: Build
|
||||
run: go build -v ./...
|
||||
# Use blst tag to allow go and bazel builds for blst.
|
||||
run: go build -v --tags=blst_enabled ./...
|
||||
|
||||
# Tests run via Bazel for now...
|
||||
# - name: Test
|
||||
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -29,3 +29,7 @@ password.txt
|
||||
|
||||
# Dist files
|
||||
dist
|
||||
|
||||
# libfuzzer
|
||||
oom-*
|
||||
crash-*
|
||||
|
||||
@@ -104,10 +104,14 @@ nogo(
|
||||
"@org_golang_x_tools//go/analysis/passes/inspect:go_tool_library",
|
||||
"@org_golang_x_tools//go/analysis/passes/asmdecl:go_tool_library",
|
||||
"//tools/analyzers/maligned:go_tool_library",
|
||||
"//tools/analyzers/roughtime:go_tool_library",
|
||||
"//tools/analyzers/cryptorand:go_tool_library",
|
||||
"//tools/analyzers/errcheck:go_tool_library",
|
||||
"//tools/analyzers/featureconfig:go_tool_library",
|
||||
"//tools/analyzers/comparesame:go_tool_library",
|
||||
"//tools/analyzers/shadowpredecl:go_tool_library",
|
||||
"//tools/analyzers/nop:go_tool_library",
|
||||
"//tools/analyzers/slicedirect:go_tool_library",
|
||||
"//tools/analyzers/ineffassign:go_tool_library",
|
||||
] + select({
|
||||
# nogo checks that fail with coverage enabled.
|
||||
":coverage_enabled": [],
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Prysm: An Ethereum 2.0 Client Written in Go
|
||||
|
||||
[](https://buildkite.com/prysmatic-labs/prysm)
|
||||
[](https://github.com/ethereum/eth2.0-specs/tree/v0.12.2)
|
||||
[](https://github.com/ethereum/eth2.0-specs/tree/v0.12.3)
|
||||
[](https://discord.gg/KSA7rPr)
|
||||
[](https://gitter.im/prysmaticlabs/geth-sharding?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
||||
|
||||
|
||||
40
WORKSPACE
40
WORKSPACE
@@ -5,11 +5,11 @@ load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
|
||||
|
||||
http_archive(
|
||||
name = "bazel_toolchains",
|
||||
sha256 = "144290c4166bd67e76a54f96cd504ed86416ca3ca82030282760f0823c10be48",
|
||||
strip_prefix = "bazel-toolchains-3.1.1",
|
||||
sha256 = "db48eed61552e25d36fe051a65d2a329cc0fb08442627e8f13960c5ab087a44e",
|
||||
strip_prefix = "bazel-toolchains-3.2.0",
|
||||
urls = [
|
||||
"https://github.com/bazelbuild/bazel-toolchains/releases/download/3.1.1/bazel-toolchains-3.1.1.tar.gz",
|
||||
"https://mirror.bazel.build/github.com/bazelbuild/bazel-toolchains/archive/3.1.1.tar.gz",
|
||||
"https://mirror.bazel.build/github.com/bazelbuild/bazel-toolchains/releases/download/3.2.0/bazel-toolchains-3.2.0.tar.gz",
|
||||
"https://github.com/bazelbuild/bazel-toolchains/releases/download/3.2.0/bazel-toolchains-3.2.0.tar.gz",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -161,6 +161,10 @@ load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies")
|
||||
|
||||
gazelle_dependencies()
|
||||
|
||||
load("@io_bazel_rules_go//extras:embed_data_deps.bzl", "go_embed_data_dependencies")
|
||||
|
||||
go_embed_data_dependencies()
|
||||
|
||||
load("@com_github_atlassian_bazel_tools//gometalinter:deps.bzl", "gometalinter_dependencies")
|
||||
|
||||
gometalinter_dependencies()
|
||||
@@ -215,8 +219,8 @@ filegroup(
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
""",
|
||||
sha256 = "9e09ada15c5f494388ecdb3ab49f4554d9ed53ce904cd21c42c350e6d7b2f323",
|
||||
url = "https://github.com/ethereum/eth2.0-spec-tests/releases/download/v0.12.2/general.tar.gz",
|
||||
sha256 = "7e5f838e0f9110471ef8be9401ea687a8ed4d499664dc0eac34ecfdfd03c2ac3",
|
||||
url = "https://github.com/ethereum/eth2.0-spec-tests/releases/download/v0.12.3/general.tar.gz",
|
||||
)
|
||||
|
||||
http_archive(
|
||||
@@ -231,8 +235,8 @@ filegroup(
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
""",
|
||||
sha256 = "5fc930e200af7682a176d6025db56cec79807112bb860dca2e1e91fb160312de",
|
||||
url = "https://github.com/ethereum/eth2.0-spec-tests/releases/download/v0.12.2/minimal.tar.gz",
|
||||
sha256 = "72c2f561db879ddcdf729fef93d10e0f9162b4cf3a697c513ef8935b93f6165a",
|
||||
url = "https://github.com/ethereum/eth2.0-spec-tests/releases/download/v0.12.3/minimal.tar.gz",
|
||||
)
|
||||
|
||||
http_archive(
|
||||
@@ -247,8 +251,8 @@ filegroup(
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
""",
|
||||
sha256 = "fbab14605a0178ef4c8f7efea0de275a22b815a8d3245099f0f5525f7a33faf8",
|
||||
url = "https://github.com/ethereum/eth2.0-spec-tests/releases/download/v0.12.2/mainnet.tar.gz",
|
||||
sha256 = "63eca02503692a0b6a2d7b70118e0dd62dff094153a3a542af6dbea721841b0d",
|
||||
url = "https://github.com/ethereum/eth2.0-spec-tests/releases/download/v0.12.3/mainnet.tar.gz",
|
||||
)
|
||||
|
||||
http_archive(
|
||||
@@ -336,6 +340,22 @@ go_binary(
|
||||
urls = ["https://github.com/ferranbt/fastssz/archive/06015a5d84f9e4eefe2c21377ca678fa8f1a1b09.tar.gz"],
|
||||
)
|
||||
|
||||
http_archive(
|
||||
name = "prysm_web_ui",
|
||||
build_file_content = """
|
||||
filegroup(
|
||||
name = "site",
|
||||
srcs = glob(["**/*"]),
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
""",
|
||||
sha256 = "507d574be56a63d5a30a28b4426b9ece89cf70bbb29739e982e0a8fdf1285e3a",
|
||||
urls = [
|
||||
"https://prysmaticlabs.com/uploads/prysm-web-ui.0.0.1-alpha.tar.gz",
|
||||
"https://github.com/prysmaticlabs/prysm-web-ui/releases/download/0.0.1-alpha/prysm-web-ui.tar.gz",
|
||||
],
|
||||
)
|
||||
|
||||
load("//:deps.bzl", "prysm_deps")
|
||||
|
||||
# gazelle:repository_macro deps.bzl%prysm_deps
|
||||
|
||||
@@ -5,6 +5,7 @@ go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"chain_info.go",
|
||||
"checkpoint_info_cache.go",
|
||||
"head.go",
|
||||
"info.go",
|
||||
"init_sync_process_block.go",
|
||||
@@ -17,9 +18,13 @@ go_library(
|
||||
"receive_attestation.go",
|
||||
"receive_block.go",
|
||||
"service.go",
|
||||
"weak_subjectivity_checks.go",
|
||||
],
|
||||
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/blockchain",
|
||||
visibility = ["//beacon-chain:__subpackages__"],
|
||||
visibility = [
|
||||
"//beacon-chain:__subpackages__",
|
||||
"//fuzz:__pkg__",
|
||||
],
|
||||
deps = [
|
||||
"//beacon-chain/cache:go_default_library",
|
||||
"//beacon-chain/cache/depositcache:go_default_library",
|
||||
@@ -30,6 +35,7 @@ go_library(
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//beacon-chain/core/state:go_default_library",
|
||||
"//beacon-chain/db:go_default_library",
|
||||
"//beacon-chain/db/filters:go_default_library",
|
||||
"//beacon-chain/flags:go_default_library",
|
||||
"//beacon-chain/forkchoice:go_default_library",
|
||||
"//beacon-chain/forkchoice/protoarray:go_default_library",
|
||||
@@ -40,17 +46,18 @@ go_library(
|
||||
"//beacon-chain/powchain:go_default_library",
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//beacon-chain/state/stategen:go_default_library",
|
||||
"//beacon-chain/state/stateutil:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//shared/attestationutil:go_default_library",
|
||||
"//shared/bls:go_default_library",
|
||||
"//shared/bytesutil:go_default_library",
|
||||
"//shared/featureconfig:go_default_library",
|
||||
"//shared/hashutil:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"//shared/roughtime:go_default_library",
|
||||
"//shared/slotutil:go_default_library",
|
||||
"//shared/timeutils:go_default_library",
|
||||
"//shared/traceutil:go_default_library",
|
||||
"@com_github_emicklei_dot//:go_default_library",
|
||||
"@com_github_hashicorp_golang_lru//:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@com_github_prometheus_client_golang//prometheus:go_default_library",
|
||||
"@com_github_prometheus_client_golang//prometheus/promauto:go_default_library",
|
||||
@@ -73,6 +80,7 @@ go_test(
|
||||
size = "medium",
|
||||
srcs = [
|
||||
"chain_info_test.go",
|
||||
"checkpoint_info_cache_test.go",
|
||||
"head_test.go",
|
||||
"info_test.go",
|
||||
"process_attestation_test.go",
|
||||
@@ -80,6 +88,7 @@ go_test(
|
||||
"receive_attestation_test.go",
|
||||
"receive_block_test.go",
|
||||
"service_test.go",
|
||||
"weak_subjectivity_checks_test.go",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
|
||||
@@ -5,14 +5,14 @@ import (
|
||||
"time"
|
||||
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"go.opencensus.io/trace"
|
||||
|
||||
"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"
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
|
||||
// ChainInfoFetcher defines a common interface for methods in blockchain service which
|
||||
@@ -97,6 +97,9 @@ func (s *Service) PreviousJustifiedCheckpt() *ethpb.Checkpoint {
|
||||
|
||||
// HeadSlot returns the slot of the head of the chain.
|
||||
func (s *Service) HeadSlot() uint64 {
|
||||
s.headLock.RLock()
|
||||
defer s.headLock.RUnlock()
|
||||
|
||||
if !s.hasHeadState() {
|
||||
return 0
|
||||
}
|
||||
@@ -106,6 +109,9 @@ func (s *Service) HeadSlot() uint64 {
|
||||
|
||||
// HeadRoot returns the root of the head of the chain.
|
||||
func (s *Service) HeadRoot(ctx context.Context) ([]byte, error) {
|
||||
s.headLock.RLock()
|
||||
defer s.headLock.RUnlock()
|
||||
|
||||
if s.headRoot() != params.BeaconConfig().ZeroHash {
|
||||
r := s.headRoot()
|
||||
return r[:], nil
|
||||
@@ -119,7 +125,7 @@ func (s *Service) HeadRoot(ctx context.Context) ([]byte, error) {
|
||||
return params.BeaconConfig().ZeroHash[:], nil
|
||||
}
|
||||
|
||||
r, err := stateutil.BlockRoot(b.Block)
|
||||
r, err := b.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -131,6 +137,9 @@ func (s *Service) HeadRoot(ctx context.Context) ([]byte, error) {
|
||||
// If the head is nil from service struct,
|
||||
// it will attempt to get the head block from DB.
|
||||
func (s *Service) HeadBlock(ctx context.Context) (*ethpb.SignedBeaconBlock, error) {
|
||||
s.headLock.RLock()
|
||||
defer s.headLock.RUnlock()
|
||||
|
||||
if s.hasHeadState() {
|
||||
return s.headBlock(), nil
|
||||
}
|
||||
@@ -144,6 +153,8 @@ func (s *Service) HeadBlock(ctx context.Context) (*ethpb.SignedBeaconBlock, erro
|
||||
func (s *Service) HeadState(ctx context.Context) (*state.BeaconState, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "blockChain.HeadState")
|
||||
defer span.End()
|
||||
s.headLock.RLock()
|
||||
defer s.headLock.RUnlock()
|
||||
|
||||
ok := s.hasHeadState()
|
||||
span.AddAttributes(trace.BoolAttribute("cache_hit", ok))
|
||||
@@ -157,6 +168,9 @@ func (s *Service) HeadState(ctx context.Context) (*state.BeaconState, error) {
|
||||
|
||||
// HeadValidatorsIndices returns a list of active validator indices from the head view of a given epoch.
|
||||
func (s *Service) HeadValidatorsIndices(ctx context.Context, epoch uint64) ([]uint64, error) {
|
||||
s.headLock.RLock()
|
||||
defer s.headLock.RUnlock()
|
||||
|
||||
if !s.hasHeadState() {
|
||||
return []uint64{}, nil
|
||||
}
|
||||
@@ -165,6 +179,9 @@ func (s *Service) HeadValidatorsIndices(ctx context.Context, epoch uint64) ([]ui
|
||||
|
||||
// HeadSeed returns the seed from the head view of a given epoch.
|
||||
func (s *Service) HeadSeed(ctx context.Context, epoch uint64) ([32]byte, error) {
|
||||
s.headLock.RLock()
|
||||
defer s.headLock.RUnlock()
|
||||
|
||||
if !s.hasHeadState() {
|
||||
return [32]byte{}, nil
|
||||
}
|
||||
@@ -174,6 +191,9 @@ func (s *Service) HeadSeed(ctx context.Context, epoch uint64) ([32]byte, error)
|
||||
|
||||
// HeadGenesisValidatorRoot returns genesis validator root of the head state.
|
||||
func (s *Service) HeadGenesisValidatorRoot() [32]byte {
|
||||
s.headLock.RLock()
|
||||
defer s.headLock.RUnlock()
|
||||
|
||||
if !s.hasHeadState() {
|
||||
return [32]byte{}
|
||||
}
|
||||
@@ -183,6 +203,9 @@ func (s *Service) HeadGenesisValidatorRoot() [32]byte {
|
||||
|
||||
// HeadETH1Data returns the eth1data of the current head state.
|
||||
func (s *Service) HeadETH1Data() *ethpb.Eth1Data {
|
||||
s.headLock.RLock()
|
||||
defer s.headLock.RUnlock()
|
||||
|
||||
if !s.hasHeadState() {
|
||||
return ðpb.Eth1Data{}
|
||||
}
|
||||
@@ -202,6 +225,9 @@ func (s *Service) GenesisTime() time.Time {
|
||||
// GenesisValidatorRoot returns the genesis validator
|
||||
// root of the chain.
|
||||
func (s *Service) GenesisValidatorRoot() [32]byte {
|
||||
s.headLock.RLock()
|
||||
defer s.headLock.RUnlock()
|
||||
|
||||
if !s.hasHeadState() {
|
||||
return [32]byte{}
|
||||
}
|
||||
@@ -210,6 +236,9 @@ func (s *Service) GenesisValidatorRoot() [32]byte {
|
||||
|
||||
// CurrentFork retrieves the latest fork information of the beacon chain.
|
||||
func (s *Service) CurrentFork() *pb.Fork {
|
||||
s.headLock.RLock()
|
||||
defer s.headLock.RUnlock()
|
||||
|
||||
if !s.hasHeadState() {
|
||||
return &pb.Fork{
|
||||
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package blockchain
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -11,22 +10,22 @@ import (
|
||||
testDB "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
// Ensure Service implements chain info interface.
|
||||
var _ = ChainInfoFetcher(&Service{})
|
||||
var _ = TimeFetcher(&Service{})
|
||||
var _ = ForkFetcher(&Service{})
|
||||
var _ ChainInfoFetcher = (*Service)(nil)
|
||||
var _ TimeFetcher = (*Service)(nil)
|
||||
var _ ForkFetcher = (*Service)(nil)
|
||||
|
||||
func TestFinalizedCheckpt_Nil(t *testing.T) {
|
||||
db, sc := testDB.SetupDB(t)
|
||||
c := setupBeaconChain(t, db, sc)
|
||||
if !bytes.Equal(c.FinalizedCheckpt().Root, params.BeaconConfig().ZeroHash[:]) {
|
||||
t.Error("Incorrect pre chain start value")
|
||||
}
|
||||
assert.DeepEqual(t, params.BeaconConfig().ZeroHash[:], c.FinalizedCheckpt().Root, "Incorrect pre chain start value")
|
||||
}
|
||||
|
||||
func TestHeadRoot_Nil(t *testing.T) {
|
||||
@@ -34,15 +33,13 @@ func TestHeadRoot_Nil(t *testing.T) {
|
||||
c := setupBeaconChain(t, db, sc)
|
||||
headRoot, err := c.HeadRoot(context.Background())
|
||||
require.NoError(t, err)
|
||||
if !bytes.Equal(headRoot, params.BeaconConfig().ZeroHash[:]) {
|
||||
t.Error("Incorrect pre chain start value")
|
||||
}
|
||||
assert.DeepEqual(t, params.BeaconConfig().ZeroHash[:], headRoot, "Incorrect pre chain start value")
|
||||
}
|
||||
|
||||
func TestFinalizedCheckpt_CanRetrieve(t *testing.T) {
|
||||
db, sc := testDB.SetupDB(t)
|
||||
|
||||
cp := ðpb.Checkpoint{Epoch: 5, Root: []byte("foo")}
|
||||
cp := ðpb.Checkpoint{Epoch: 5, Root: bytesutil.PadTo([]byte("foo"), 32)}
|
||||
c := setupBeaconChain(t, db, sc)
|
||||
c.finalizedCheckpt = cp
|
||||
|
||||
@@ -57,16 +54,13 @@ func TestFinalizedCheckpt_GenesisRootOk(t *testing.T) {
|
||||
c := setupBeaconChain(t, db, sc)
|
||||
c.finalizedCheckpt = cp
|
||||
c.genesisRoot = genesisRoot
|
||||
|
||||
if !bytes.Equal(c.FinalizedCheckpt().Root, c.genesisRoot[:]) {
|
||||
t.Errorf("Got: %v, wanted: %v", c.FinalizedCheckpt().Root, c.genesisRoot[:])
|
||||
}
|
||||
assert.DeepEqual(t, c.genesisRoot[:], c.FinalizedCheckpt().Root)
|
||||
}
|
||||
|
||||
func TestCurrentJustifiedCheckpt_CanRetrieve(t *testing.T) {
|
||||
db, sc := testDB.SetupDB(t)
|
||||
|
||||
cp := ðpb.Checkpoint{Epoch: 6, Root: []byte("foo")}
|
||||
cp := ðpb.Checkpoint{Epoch: 6, Root: bytesutil.PadTo([]byte("foo"), 32)}
|
||||
c := setupBeaconChain(t, db, sc)
|
||||
c.justifiedCheckpt = cp
|
||||
|
||||
@@ -81,19 +75,15 @@ func TestJustifiedCheckpt_GenesisRootOk(t *testing.T) {
|
||||
c := setupBeaconChain(t, db, sc)
|
||||
c.justifiedCheckpt = cp
|
||||
c.genesisRoot = genesisRoot
|
||||
|
||||
if !bytes.Equal(c.CurrentJustifiedCheckpt().Root, c.genesisRoot[:]) {
|
||||
t.Errorf("Got: %v, wanted: %v", c.CurrentJustifiedCheckpt().Root, c.genesisRoot[:])
|
||||
}
|
||||
assert.DeepEqual(t, c.genesisRoot[:], c.CurrentJustifiedCheckpt().Root)
|
||||
}
|
||||
|
||||
func TestPreviousJustifiedCheckpt_CanRetrieve(t *testing.T) {
|
||||
db, sc := testDB.SetupDB(t)
|
||||
|
||||
cp := ðpb.Checkpoint{Epoch: 7, Root: []byte("foo")}
|
||||
cp := ðpb.Checkpoint{Epoch: 7, Root: bytesutil.PadTo([]byte("foo"), 32)}
|
||||
c := setupBeaconChain(t, db, sc)
|
||||
c.prevJustifiedCheckpt = cp
|
||||
|
||||
assert.Equal(t, cp.Epoch, c.PreviousJustifiedCheckpt().Epoch, "Unexpected previous justified epoch")
|
||||
}
|
||||
|
||||
@@ -105,30 +95,28 @@ func TestPrevJustifiedCheckpt_GenesisRootOk(t *testing.T) {
|
||||
c := setupBeaconChain(t, db, sc)
|
||||
c.prevJustifiedCheckpt = cp
|
||||
c.genesisRoot = genesisRoot
|
||||
|
||||
if !bytes.Equal(c.PreviousJustifiedCheckpt().Root, c.genesisRoot[:]) {
|
||||
t.Errorf("Got: %v, wanted: %v", c.PreviousJustifiedCheckpt().Root, c.genesisRoot[:])
|
||||
}
|
||||
assert.DeepEqual(t, c.genesisRoot[:], c.PreviousJustifiedCheckpt().Root)
|
||||
}
|
||||
|
||||
func TestHeadSlot_CanRetrieve(t *testing.T) {
|
||||
c := &Service{}
|
||||
s, err := state.InitializeFromProto(&pb.BeaconState{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
c.head = &head{slot: 100, state: s}
|
||||
assert.Equal(t, uint64(100), c.headSlot())
|
||||
assert.Equal(t, uint64(100), c.HeadSlot())
|
||||
}
|
||||
|
||||
func TestHeadRoot_CanRetrieve(t *testing.T) {
|
||||
c := &Service{}
|
||||
c.head = &head{root: [32]byte{'A'}}
|
||||
assert.Equal(t, [32]byte{'A'}, c.headRoot())
|
||||
r, err := c.HeadRoot(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, [32]byte{'A'}, bytesutil.ToBytes32(r))
|
||||
}
|
||||
|
||||
func TestHeadBlock_CanRetrieve(t *testing.T) {
|
||||
b := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Slot: 1}}
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block.Slot = 1
|
||||
s, err := state.InitializeFromProto(&pb.BeaconState{})
|
||||
require.NoError(t, err)
|
||||
c := &Service{}
|
||||
@@ -146,9 +134,7 @@ func TestHeadState_CanRetrieve(t *testing.T) {
|
||||
c.head = &head{state: s}
|
||||
headState, err := c.HeadState(context.Background())
|
||||
require.NoError(t, err)
|
||||
if !proto.Equal(s.InnerStateUnsafe(), headState.InnerStateUnsafe()) {
|
||||
t.Error("incorrect head state received")
|
||||
}
|
||||
assert.DeepEqual(t, headState.InnerStateUnsafe(), s.InnerStateUnsafe(), "Incorrect head state received")
|
||||
}
|
||||
|
||||
func TestGenesisTime_CanRetrieve(t *testing.T) {
|
||||
|
||||
83
beacon-chain/blockchain/checkpoint_info_cache.go
Normal file
83
beacon-chain/blockchain/checkpoint_info_cache.go
Normal file
@@ -0,0 +1,83 @@
|
||||
package blockchain
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
lru "github.com/hashicorp/golang-lru"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/hashutil"
|
||||
)
|
||||
|
||||
var (
|
||||
// This defines the max number of checkpoint info this cache can store.
|
||||
// Each cache is calculated at 3MB(30K validators), the total cache size is around 100MB.
|
||||
// Due to reorgs and long finality, it's good to keep the old cache around for quickly switch over.
|
||||
maxInfoSize = 32
|
||||
|
||||
// This tracks the number of check point info requests that aren't present in the cache.
|
||||
infoMiss = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "check_point_info_cache_miss",
|
||||
Help: "The number of check point info requests that aren't present in the cache.",
|
||||
})
|
||||
// This tracks the number of check point info requests that are in the cache.
|
||||
infoHit = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "check_point_info_cache_hit",
|
||||
Help: "The number of check point info requests that are present in the cache.",
|
||||
})
|
||||
)
|
||||
|
||||
// checkPtInfoCache is a struct with 1 LRU cache for looking up check point info by checkpoint.
|
||||
type checkPtInfoCache struct {
|
||||
cache *lru.Cache
|
||||
lock sync.RWMutex
|
||||
}
|
||||
|
||||
// newCheckPointInfoCache creates a new checkpoint info cache for storing/accessing processed check point info object.
|
||||
func newCheckPointInfoCache() *checkPtInfoCache {
|
||||
cache, err := lru.New(maxInfoSize)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return &checkPtInfoCache{
|
||||
cache: cache,
|
||||
}
|
||||
}
|
||||
|
||||
// get fetches check point info by check point. Returns the reference of the CheckPtInfo, nil if doesn't exist.
|
||||
func (c *checkPtInfoCache) get(cp *ethpb.Checkpoint) (*pb.CheckPtInfo, error) {
|
||||
c.lock.RLock()
|
||||
defer c.lock.RUnlock()
|
||||
h, err := hashutil.HashProto(cp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
item, exists := c.cache.Get(h)
|
||||
|
||||
if exists && item != nil {
|
||||
infoHit.Inc()
|
||||
// Copy here is unnecessary since the returned check point info object
|
||||
// will only be used to verify attestation signature.
|
||||
return item.(*pb.CheckPtInfo), nil
|
||||
}
|
||||
|
||||
infoMiss.Inc()
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// put adds CheckPtInfo object to the cache. This method also trims the least
|
||||
// recently added CheckPtInfo object if the cache size has ready the max cache size limit.
|
||||
func (c *checkPtInfoCache) put(cp *ethpb.Checkpoint, info *pb.CheckPtInfo) error {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
h, err := hashutil.HashProto(cp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.cache.Add(h, info)
|
||||
return nil
|
||||
}
|
||||
41
beacon-chain/blockchain/checkpoint_info_cache_test.go
Normal file
41
beacon-chain/blockchain/checkpoint_info_cache_test.go
Normal file
@@ -0,0 +1,41 @@
|
||||
package blockchain
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
func TestHotStateCache_RoundTrip(t *testing.T) {
|
||||
c := newCheckPointInfoCache()
|
||||
cp := ðpb.Checkpoint{
|
||||
Epoch: 1,
|
||||
Root: bytesutil.PadTo([]byte{'a'}, 32),
|
||||
}
|
||||
info, err := c.get(cp)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, (*pb.CheckPtInfo)(nil), info)
|
||||
|
||||
i := &pb.CheckPtInfo{
|
||||
Seed: bytesutil.PadTo([]byte{'c'}, 32),
|
||||
GenesisRoot: bytesutil.PadTo([]byte{'d'}, 32),
|
||||
ActiveIndices: []uint64{0, 1, 2, 3},
|
||||
}
|
||||
|
||||
require.NoError(t, c.put(cp, i))
|
||||
info, err = c.get(cp)
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, info, i)
|
||||
}
|
||||
|
||||
func TestHotStateCache_CanPrune(t *testing.T) {
|
||||
c := newCheckPointInfoCache()
|
||||
for i := 0; i < maxInfoSize+1; i++ {
|
||||
cp := ðpb.Checkpoint{Epoch: uint64(i), Root: make([]byte, 32)}
|
||||
require.NoError(t, c.put(cp, &pb.CheckPtInfo{}))
|
||||
}
|
||||
require.Equal(t, len(c.cache.Keys()), maxInfoSize)
|
||||
}
|
||||
@@ -72,7 +72,11 @@ func (s *Service) saveHead(ctx context.Context, headRoot [32]byte) error {
|
||||
defer span.End()
|
||||
|
||||
// Do nothing if head hasn't changed.
|
||||
if headRoot == s.headRoot() {
|
||||
r, err := s.HeadRoot(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if headRoot == bytesutil.ToBytes32(r) {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -101,16 +105,17 @@ func (s *Service) saveHead(ctx context.Context, headRoot [32]byte) error {
|
||||
}
|
||||
|
||||
// A chain re-org occurred, so we fire an event notifying the rest of the services.
|
||||
if bytesutil.ToBytes32(newHeadBlock.Block.ParentRoot) != s.headRoot() {
|
||||
headSlot := s.HeadSlot()
|
||||
if bytesutil.ToBytes32(newHeadBlock.Block.ParentRoot) != bytesutil.ToBytes32(r) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"newSlot": fmt.Sprintf("%d", newHeadBlock.Block.Slot),
|
||||
"oldSlot": fmt.Sprintf("%d", s.headSlot()),
|
||||
"oldSlot": fmt.Sprintf("%d", headSlot),
|
||||
}).Debug("Chain reorg occurred")
|
||||
s.stateNotifier.StateFeed().Send(&feed.Event{
|
||||
Type: statefeed.Reorg,
|
||||
Data: &statefeed.ReorgData{
|
||||
NewSlot: newHeadBlock.Block.Slot,
|
||||
OldSlot: s.headSlot(),
|
||||
OldSlot: headSlot,
|
||||
},
|
||||
})
|
||||
|
||||
@@ -179,60 +184,56 @@ func (s *Service) setHeadInitialSync(root [32]byte, block *ethpb.SignedBeaconBlo
|
||||
}
|
||||
|
||||
// This returns the head slot.
|
||||
// This is a lock free version.
|
||||
func (s *Service) headSlot() uint64 {
|
||||
s.headLock.RLock()
|
||||
defer s.headLock.RUnlock()
|
||||
|
||||
return s.head.slot
|
||||
}
|
||||
|
||||
// This returns the head root.
|
||||
// It does a full copy on head root for immutability.
|
||||
// This is a lock free version.
|
||||
func (s *Service) headRoot() [32]byte {
|
||||
if s.head == nil {
|
||||
return params.BeaconConfig().ZeroHash
|
||||
}
|
||||
|
||||
s.headLock.RLock()
|
||||
defer s.headLock.RUnlock()
|
||||
|
||||
return s.head.root
|
||||
}
|
||||
|
||||
// This returns the head block.
|
||||
// It does a full copy on head block for immutability.
|
||||
// This is a lock free version.
|
||||
func (s *Service) headBlock() *ethpb.SignedBeaconBlock {
|
||||
s.headLock.RLock()
|
||||
defer s.headLock.RUnlock()
|
||||
|
||||
return stateTrie.CopySignedBeaconBlock(s.head.block)
|
||||
}
|
||||
|
||||
// This returns the head state.
|
||||
// It does a full copy on head state for immutability.
|
||||
// This is a lock free version.
|
||||
func (s *Service) headState(ctx context.Context) *stateTrie.BeaconState {
|
||||
ctx, span := trace.StartSpan(ctx, "blockChain.headState")
|
||||
defer span.End()
|
||||
|
||||
s.headLock.RLock()
|
||||
defer s.headLock.RUnlock()
|
||||
|
||||
return s.head.state.Copy()
|
||||
}
|
||||
|
||||
// This returns the genesis validator root of the head state.
|
||||
// This is a lock free version.
|
||||
func (s *Service) headGenesisValidatorRoot() [32]byte {
|
||||
s.headLock.RLock()
|
||||
defer s.headLock.RUnlock()
|
||||
|
||||
return bytesutil.ToBytes32(s.head.state.GenesisValidatorRoot())
|
||||
}
|
||||
|
||||
// Returns true if head state exists.
|
||||
func (s *Service) hasHeadState() bool {
|
||||
// HasHeadState returns true if head state exists.
|
||||
func (s *Service) HasHeadState() bool {
|
||||
s.headLock.RLock()
|
||||
defer s.headLock.RUnlock()
|
||||
|
||||
return s.hasHeadState()
|
||||
}
|
||||
|
||||
// Returns true if head state exists.
|
||||
// This is the lock free version.
|
||||
func (s *Service) hasHeadState() bool {
|
||||
return s.head != nil && s.head.state != nil
|
||||
}
|
||||
|
||||
|
||||
@@ -5,9 +5,7 @@ import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
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"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
@@ -35,11 +33,12 @@ func TestSaveHead_Different(t *testing.T) {
|
||||
oldRoot := [32]byte{'A'}
|
||||
service.head = &head{slot: 0, root: oldRoot}
|
||||
|
||||
newHeadBlock := ðpb.BeaconBlock{Slot: 1}
|
||||
newHeadSignedBlock := ðpb.SignedBeaconBlock{Block: newHeadBlock}
|
||||
newHeadSignedBlock := testutil.NewBeaconBlock()
|
||||
newHeadSignedBlock.Block.Slot = 1
|
||||
newHeadBlock := newHeadSignedBlock.Block
|
||||
|
||||
require.NoError(t, service.beaconDB.SaveBlock(context.Background(), newHeadSignedBlock))
|
||||
newRoot, err := stateutil.BlockRoot(newHeadBlock)
|
||||
newRoot, err := newHeadBlock.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
headState := testutil.NewBeaconState()
|
||||
require.NoError(t, headState.SetSlot(1))
|
||||
@@ -68,14 +67,13 @@ func TestSaveHead_Different_Reorg(t *testing.T) {
|
||||
service.head = &head{slot: 0, root: oldRoot}
|
||||
|
||||
reorgChainParent := [32]byte{'B'}
|
||||
newHeadBlock := ðpb.BeaconBlock{
|
||||
Slot: 1,
|
||||
ParentRoot: reorgChainParent[:],
|
||||
}
|
||||
newHeadSignedBlock := ðpb.SignedBeaconBlock{Block: newHeadBlock}
|
||||
newHeadSignedBlock := testutil.NewBeaconBlock()
|
||||
newHeadSignedBlock.Block.Slot = 1
|
||||
newHeadSignedBlock.Block.ParentRoot = reorgChainParent[:]
|
||||
newHeadBlock := newHeadSignedBlock.Block
|
||||
|
||||
require.NoError(t, service.beaconDB.SaveBlock(context.Background(), newHeadSignedBlock))
|
||||
newRoot, err := stateutil.BlockRoot(newHeadBlock)
|
||||
newRoot, err := newHeadBlock.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
headState := testutil.NewBeaconState()
|
||||
require.NoError(t, headState.SetSlot(1))
|
||||
|
||||
@@ -34,7 +34,12 @@ const template = `<html>
|
||||
|
||||
// TreeHandler is a handler to serve /tree page in metrics.
|
||||
func (s *Service) TreeHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if s.headState(r.Context()) == nil {
|
||||
headState, err := s.HeadState(r.Context())
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Could not get head state")
|
||||
return
|
||||
}
|
||||
if headState == nil {
|
||||
if _, err := w.Write([]byte("Unavailable during initial syncing")); err != nil {
|
||||
log.WithError(err).Error("Failed to render p2p info page")
|
||||
}
|
||||
@@ -47,7 +52,7 @@ func (s *Service) TreeHandler(w http.ResponseWriter, r *http.Request) {
|
||||
graph.Attr("labeljust", "l")
|
||||
|
||||
dotNodes := make([]*dot.Node, len(nodes))
|
||||
avgBalance := uint64(averageBalance(s.headState(r.Context()).Balances()))
|
||||
avgBalance := uint64(averageBalance(headState.Balances()))
|
||||
|
||||
for i := len(nodes) - 1; i >= 0; i-- {
|
||||
// Construct label for each node.
|
||||
@@ -63,7 +68,7 @@ func (s *Service) TreeHandler(w http.ResponseWriter, r *http.Request) {
|
||||
dotN = graph.Node(index).Box().Attr("label", label)
|
||||
}
|
||||
|
||||
if nodes[i].Slot() == s.headSlot() &&
|
||||
if nodes[i].Slot() == s.HeadSlot() &&
|
||||
nodes[i].BestDescendant() == ^uint64(0) &&
|
||||
nodes[i].Parent() != ^uint64(0) {
|
||||
dotN = dotN.Attr("color", "green")
|
||||
|
||||
@@ -33,6 +33,7 @@ func TestService_TreeHandler(t *testing.T) {
|
||||
StateGen: stategen.New(db, sCache),
|
||||
}
|
||||
s, err := NewService(ctx, cfg)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, s.forkChoiceStore.ProcessBlock(ctx, 0, [32]byte{'a'}, [32]byte{'g'}, [32]byte{'c'}, 0, 0))
|
||||
require.NoError(t, s.forkChoiceStore.ProcessBlock(ctx, 1, [32]byte{'b'}, [32]byte{'a'}, [32]byte{'c'}, 0, 0))
|
||||
s.setHead([32]byte{'a'}, testutil.NewBeaconBlock(), headState)
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
@@ -25,9 +26,10 @@ func logStateTransitionData(b *ethpb.BeaconBlock) {
|
||||
func logBlockSyncStatus(block *ethpb.BeaconBlock, blockRoot [32]byte, finalized *ethpb.Checkpoint) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"slot": block.Slot,
|
||||
"slotInEpoch": block.Slot % params.BeaconConfig().SlotsPerEpoch,
|
||||
"block": fmt.Sprintf("0x%s...", hex.EncodeToString(blockRoot[:])[:8]),
|
||||
"epoch": helpers.SlotToEpoch(block.Slot),
|
||||
"finalizedEpoch": finalized.Epoch,
|
||||
"finalizedRoot": fmt.Sprintf("0x%s...", hex.EncodeToString(finalized.Root[:])[:8]),
|
||||
"finalizedRoot": fmt.Sprintf("0x%s...", hex.EncodeToString(finalized.Root)[:8]),
|
||||
}).Info("Synced new block")
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
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"
|
||||
"github.com/prysmaticlabs/prysm/shared/timeutils"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -76,14 +76,26 @@ var (
|
||||
Name: "current_eth1_data_deposit_count",
|
||||
Help: "The current eth1 deposit count in the last processed state eth1data field.",
|
||||
})
|
||||
totalEligibleBalances = promauto.NewGauge(prometheus.GaugeOpts{
|
||||
Name: "total_eligible_balances",
|
||||
Help: "The total amount of ether, in gwei, that is eligible for voting of previous epoch",
|
||||
stateTrieReferences = promauto.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Name: "field_references",
|
||||
Help: "The number of states a particular field is shared with.",
|
||||
}, []string{"state"})
|
||||
prevEpochActiveBalances = promauto.NewGauge(prometheus.GaugeOpts{
|
||||
Name: "beacon_prev_epoch_active_gwei",
|
||||
Help: "The total amount of ether, in gwei, that was active for voting of previous epoch",
|
||||
})
|
||||
totalVotedTargetBalances = promauto.NewGauge(prometheus.GaugeOpts{
|
||||
Name: "total_voted_target_balances",
|
||||
prevEpochSourceBalances = promauto.NewGauge(prometheus.GaugeOpts{
|
||||
Name: "beacon_prev_epoch_source_gwei",
|
||||
Help: "The total amount of ether, in gwei, that has been used in voting attestation source of previous epoch",
|
||||
})
|
||||
prevEpochTargetBalances = promauto.NewGauge(prometheus.GaugeOpts{
|
||||
Name: "beacon_prev_epoch_target_gwei",
|
||||
Help: "The total amount of ether, in gwei, that has been used in voting attestation target of previous epoch",
|
||||
})
|
||||
prevEpochHeadBalances = promauto.NewGauge(prometheus.GaugeOpts{
|
||||
Name: "beacon_prev_epoch_head_gwei",
|
||||
Help: "The total amount of ether, in gwei, that has been used in voting attestation head of previous epoch",
|
||||
})
|
||||
reorgCount = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "beacon_reorg_total",
|
||||
Help: "Count the number of times beacon chain has a reorg",
|
||||
@@ -102,6 +114,15 @@ var (
|
||||
Buckets: []float64{1, 2, 3, 4, 6, 32, 64},
|
||||
},
|
||||
)
|
||||
// TODO(7141): Remove deprecated metrics below.
|
||||
totalEligibleBalances = promauto.NewGauge(prometheus.GaugeOpts{
|
||||
Name: "total_eligible_balances",
|
||||
Help: "The total amount of ether, in gwei, that is eligible for voting of previous epoch",
|
||||
})
|
||||
totalVotedTargetBalances = promauto.NewGauge(prometheus.GaugeOpts{
|
||||
Name: "total_voted_target_balances",
|
||||
Help: "The total amount of ether, in gwei, that has been used in voting attestation target of previous epoch",
|
||||
})
|
||||
)
|
||||
|
||||
// reportSlotMetrics reports slot related metrics.
|
||||
@@ -201,6 +222,14 @@ func reportEpochMetrics(state *stateTrie.BeaconState) {
|
||||
if precompute.Balances != nil {
|
||||
totalEligibleBalances.Set(float64(precompute.Balances.ActivePrevEpoch))
|
||||
totalVotedTargetBalances.Set(float64(precompute.Balances.PrevEpochTargetAttested))
|
||||
prevEpochActiveBalances.Set(float64(precompute.Balances.ActivePrevEpoch))
|
||||
prevEpochSourceBalances.Set(float64(precompute.Balances.PrevEpochAttested))
|
||||
prevEpochTargetBalances.Set(float64(precompute.Balances.PrevEpochTargetAttested))
|
||||
prevEpochHeadBalances.Set(float64(precompute.Balances.PrevEpochHeadAttested))
|
||||
}
|
||||
refMap := state.FieldReferencesCount()
|
||||
for name, val := range refMap {
|
||||
stateTrieReferences.WithLabelValues(name).Set(float64(val))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,7 +239,7 @@ func captureSentTimeMetric(genesisTime uint64, currentSlot uint64) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
diffMs := roughtime.Now().Sub(startTime) / time.Millisecond
|
||||
diffMs := timeutils.Now().Sub(startTime) / time.Millisecond
|
||||
sentBlockPropagationHistogram.Observe(float64(diffMs))
|
||||
|
||||
return nil
|
||||
|
||||
@@ -8,9 +8,12 @@ import (
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"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/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/roughtime"
|
||||
"github.com/prysmaticlabs/prysm/shared/timeutils"
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
|
||||
@@ -66,6 +69,53 @@ func (s *Service) onAttestation(ctx context.Context, a *ethpb.Attestation) ([]ui
|
||||
return nil, ErrTargetRootNotInDB
|
||||
}
|
||||
|
||||
if featureconfig.Get().UseCheckPointInfoCache {
|
||||
c, err := s.AttestationCheckPtInfo(ctx, a)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := s.verifyAttTargetEpoch(ctx, uint64(s.genesisTime.Unix()), uint64(timeutils.Now().Unix()), tgt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := s.verifyBeaconBlock(ctx, a.Data); err != nil {
|
||||
return nil, errors.Wrap(err, "could not verify attestation beacon block")
|
||||
}
|
||||
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")
|
||||
}
|
||||
if err := helpers.VerifySlotTime(uint64(s.genesisTime.Unix()), a.Data.Slot+1, params.BeaconNetworkConfig().MaximumGossipClockDisparity); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
committee, err := helpers.BeaconCommittee(c.ActiveIndices, bytesutil.ToBytes32(c.Seed), a.Data.Slot, a.Data.CommitteeIndex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
indexedAtt := attestationutil.ConvertToIndexed(ctx, a, committee)
|
||||
if err := attestationutil.IsValidAttestationIndices(ctx, indexedAtt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
domain, err := helpers.Domain(c.Fork, indexedAtt.Data.Target.Epoch, params.BeaconConfig().DomainBeaconAttester, c.GenesisRoot)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
indices := indexedAtt.AttestingIndices
|
||||
pubkeys := []bls.PublicKey{}
|
||||
for i := 0; i < len(indices); i++ {
|
||||
pubkeyAtIdx := c.PubKeys[indices[i]]
|
||||
pk, err := bls.PublicKeyFromBytes(pubkeyAtIdx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pubkeys = append(pubkeys, pk)
|
||||
}
|
||||
if err := attestationutil.VerifyIndexedAttestationSig(ctx, indexedAtt, pubkeys, domain); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.forkChoiceStore.ProcessAttestation(ctx, indexedAtt.AttestingIndices, bytesutil.ToBytes32(a.Data.BeaconBlockRoot), a.Data.Target.Epoch)
|
||||
|
||||
return indexedAtt.AttestingIndices, nil
|
||||
}
|
||||
|
||||
// Retrieve attestation's data beacon block pre state. Advance pre state to latest epoch if necessary and
|
||||
// save it to the cache.
|
||||
baseState, err := s.getAttPreState(ctx, tgt)
|
||||
@@ -73,10 +123,10 @@ func (s *Service) onAttestation(ctx context.Context, a *ethpb.Attestation) ([]ui
|
||||
return nil, err
|
||||
}
|
||||
|
||||
genesisTime := helpers.GenesisTime(baseState)
|
||||
genesisTime := baseState.GenesisTime()
|
||||
|
||||
// Verify attestation target is from current epoch or previous epoch.
|
||||
if err := s.verifyAttTargetEpoch(ctx, genesisTime, uint64(roughtime.Now().Unix()), tgt); err != nil {
|
||||
if err := s.verifyAttTargetEpoch(ctx, genesisTime, uint64(timeutils.Now().Unix()), tgt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/state"
|
||||
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/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
@@ -31,14 +32,18 @@ func (s *Service) getAttPreState(ctx context.Context, c *ethpb.Checkpoint) (*sta
|
||||
|
||||
baseState, err := s.stateGen.StateByRoot(ctx, bytesutil.ToBytes32(c.Root))
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not get pre state for slot %d", helpers.StartSlot(c.Epoch))
|
||||
return nil, errors.Wrapf(err, "could not get pre state for epoch %d", c.Epoch)
|
||||
}
|
||||
|
||||
if helpers.StartSlot(c.Epoch) > baseState.Slot() {
|
||||
epochStartSlot, err := helpers.StartSlot(c.Epoch)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if epochStartSlot > baseState.Slot() {
|
||||
baseState = baseState.Copy()
|
||||
baseState, err = state.ProcessSlots(ctx, baseState, helpers.StartSlot(c.Epoch))
|
||||
baseState, err = state.ProcessSlots(ctx, baseState, epochStartSlot)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not process slots up to %d", helpers.StartSlot(c.Epoch))
|
||||
return nil, errors.Wrapf(err, "could not process slots up to epoch %d", c.Epoch)
|
||||
}
|
||||
if err := s.checkpointState.AddCheckpointState(c, baseState); err != nil {
|
||||
return nil, errors.Wrap(err, "could not saved checkpoint state to cache")
|
||||
@@ -59,6 +64,67 @@ func (s *Service) getAttPreState(ctx context.Context, c *ethpb.Checkpoint) (*sta
|
||||
|
||||
}
|
||||
|
||||
// getAttCheckPtInfo retrieves the check point info given a check point. Check point info enables the node
|
||||
// to efficiently verify attestation signature without using beacon state. This function utilizes
|
||||
// the checkpoint info cache and will update the check point info cache on miss.
|
||||
func (s *Service) getAttCheckPtInfo(ctx context.Context, c *ethpb.Checkpoint, e uint64) (*pb.CheckPtInfo, error) {
|
||||
// Return checkpoint info if exists in cache.
|
||||
info, err := s.checkPtInfoCache.get(c)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get cached checkpoint state")
|
||||
}
|
||||
if info != nil {
|
||||
return info, nil
|
||||
}
|
||||
|
||||
// Retrieve checkpoint state to compute checkpoint info.
|
||||
baseState, err := s.stateGen.StateByRoot(ctx, bytesutil.ToBytes32(c.Root))
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not get pre state for epoch %d", c.Epoch)
|
||||
}
|
||||
epochStartSlot, err := helpers.StartSlot(c.Epoch)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if epochStartSlot > baseState.Slot() {
|
||||
baseState = baseState.Copy()
|
||||
baseState, err = state.ProcessSlots(ctx, baseState, epochStartSlot)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not process slots up to epoch %d", c.Epoch)
|
||||
}
|
||||
}
|
||||
f := baseState.Fork()
|
||||
g := bytesutil.ToBytes32(baseState.GenesisValidatorRoot())
|
||||
seed, err := helpers.Seed(baseState, e, params.BeaconConfig().DomainBeaconAttester)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
indices, err := helpers.ActiveValidatorIndices(baseState, e)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
validators := baseState.ValidatorsReadOnly()
|
||||
pks := make([][]byte, len(validators))
|
||||
for i := 0; i < len(pks); i++ {
|
||||
pk := validators[i].PublicKey()
|
||||
pks[i] = pk[:]
|
||||
}
|
||||
|
||||
// Cache and return the checkpoint info.
|
||||
info = &pb.CheckPtInfo{
|
||||
Fork: f,
|
||||
GenesisRoot: g[:],
|
||||
Seed: seed[:],
|
||||
ActiveIndices: indices,
|
||||
PubKeys: pks,
|
||||
}
|
||||
if err := s.checkPtInfoCache.put(c, info); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return info, nil
|
||||
}
|
||||
|
||||
// verifyAttTargetEpoch validates attestation is from the current or previous epoch.
|
||||
func (s *Service) verifyAttTargetEpoch(ctx context.Context, genesisTime uint64, nowTime uint64, c *ethpb.Checkpoint) error {
|
||||
currentSlot := (nowTime - genesisTime) / params.BeaconConfig().SecondsPerSlot
|
||||
@@ -97,7 +163,10 @@ func (s *Service) verifyBeaconBlock(ctx context.Context, data *ethpb.Attestation
|
||||
|
||||
// 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)
|
||||
ffgSlot, err := helpers.StartSlot(ffgEpoch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r, err := s.ancestor(ctx, lmdRoot, ffgSlot)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -2,20 +2,19 @@ package blockchain
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/cache"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/state"
|
||||
testDB "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/protoarray"
|
||||
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/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
@@ -37,103 +36,207 @@ func TestStore_OnAttestation(t *testing.T) {
|
||||
_, err = blockTree1(db, []byte{'g'})
|
||||
require.NoError(t, err)
|
||||
|
||||
BlkWithOutState := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Slot: 0}}
|
||||
BlkWithOutState := testutil.NewBeaconBlock()
|
||||
BlkWithOutState.Block.Slot = 0
|
||||
require.NoError(t, db.SaveBlock(ctx, BlkWithOutState))
|
||||
BlkWithOutStateRoot, err := stateutil.BlockRoot(BlkWithOutState.Block)
|
||||
BlkWithOutStateRoot, err := BlkWithOutState.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
BlkWithStateBadAtt := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Slot: 1}}
|
||||
BlkWithStateBadAtt := testutil.NewBeaconBlock()
|
||||
BlkWithStateBadAtt.Block.Slot = 1
|
||||
require.NoError(t, db.SaveBlock(ctx, BlkWithStateBadAtt))
|
||||
BlkWithStateBadAttRoot, err := stateutil.BlockRoot(BlkWithStateBadAtt.Block)
|
||||
BlkWithStateBadAttRoot, err := BlkWithStateBadAtt.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
s := testutil.NewBeaconState()
|
||||
require.NoError(t, s.SetSlot(100*params.BeaconConfig().SlotsPerEpoch))
|
||||
require.NoError(t, service.beaconDB.SaveState(ctx, s, BlkWithStateBadAttRoot))
|
||||
|
||||
BlkWithValidState := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Slot: 2}}
|
||||
BlkWithValidState := testutil.NewBeaconBlock()
|
||||
BlkWithValidState.Block.Slot = 2
|
||||
require.NoError(t, db.SaveBlock(ctx, BlkWithValidState))
|
||||
|
||||
BlkWithValidStateRoot, err := stateutil.BlockRoot(BlkWithValidState.Block)
|
||||
BlkWithValidStateRoot, err := BlkWithValidState.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
s = testutil.NewBeaconState()
|
||||
if err := s.SetFork(&pb.Fork{
|
||||
err = s.SetFork(&pb.Fork{
|
||||
Epoch: 0,
|
||||
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, service.beaconDB.SaveState(ctx, s, BlkWithValidStateRoot))
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
a *ethpb.Attestation
|
||||
s *pb.BeaconState
|
||||
wantErr bool
|
||||
wantErrString string
|
||||
name string
|
||||
a *ethpb.Attestation
|
||||
wantedErr string
|
||||
}{
|
||||
{
|
||||
name: "attestation's data slot not aligned with target vote",
|
||||
a: ðpb.Attestation{Data: ðpb.AttestationData{Slot: params.BeaconConfig().SlotsPerEpoch, Target: ðpb.Checkpoint{}}},
|
||||
s: &pb.BeaconState{},
|
||||
wantErr: true,
|
||||
wantErrString: "data slot is not in the same epoch as target 1 != 0",
|
||||
name: "attestation's data slot not aligned with target vote",
|
||||
a: ðpb.Attestation{Data: ðpb.AttestationData{Slot: params.BeaconConfig().SlotsPerEpoch, Target: ðpb.Checkpoint{Root: make([]byte, 32)}}},
|
||||
wantedErr: "data slot is not in the same epoch as target 1 != 0",
|
||||
},
|
||||
{
|
||||
name: "attestation's target root not in db",
|
||||
a: ðpb.Attestation{Data: ðpb.AttestationData{Target: ðpb.Checkpoint{Root: []byte{'A'}}}},
|
||||
s: &pb.BeaconState{},
|
||||
wantErr: true,
|
||||
wantErrString: "target root does not exist in db",
|
||||
name: "attestation's target root not in db",
|
||||
a: ðpb.Attestation{Data: ðpb.AttestationData{Target: ðpb.Checkpoint{Root: bytesutil.PadTo([]byte{'A'}, 32)}}},
|
||||
wantedErr: "target root does not exist in db",
|
||||
},
|
||||
{
|
||||
name: "no pre state for attestations's target block",
|
||||
a: ðpb.Attestation{Data: ðpb.AttestationData{Target: ðpb.Checkpoint{Root: BlkWithOutStateRoot[:]}}},
|
||||
s: &pb.BeaconState{},
|
||||
wantErr: true,
|
||||
wantErrString: "could not get pre state for slot 0",
|
||||
name: "no pre state for attestations's target block",
|
||||
a: ðpb.Attestation{Data: ðpb.AttestationData{Target: ðpb.Checkpoint{Root: BlkWithOutStateRoot[:]}}},
|
||||
wantedErr: "could not get pre state for epoch 0",
|
||||
},
|
||||
{
|
||||
name: "process attestation doesn't match current epoch",
|
||||
a: ðpb.Attestation{Data: ðpb.AttestationData{Slot: 100 * params.BeaconConfig().SlotsPerEpoch, Target: ðpb.Checkpoint{Epoch: 100,
|
||||
Root: BlkWithStateBadAttRoot[:]}}},
|
||||
s: &pb.BeaconState{Slot: 100 * params.BeaconConfig().SlotsPerEpoch},
|
||||
wantErr: true,
|
||||
wantErrString: "target epoch 100 does not match current epoch",
|
||||
wantedErr: "target epoch 100 does not match current epoch",
|
||||
},
|
||||
{
|
||||
name: "process nil field (a.Target) in attestation",
|
||||
a: nil,
|
||||
s: &pb.BeaconState{},
|
||||
wantErr: true,
|
||||
wantErrString: "nil attestation",
|
||||
name: "process nil attestation",
|
||||
a: nil,
|
||||
wantedErr: "nil attestation",
|
||||
},
|
||||
{
|
||||
name: "process nil field (a.Data) in attestation",
|
||||
a: ðpb.Attestation{},
|
||||
s: &pb.BeaconState{},
|
||||
wantErr: true,
|
||||
wantErrString: "nil attestation.Data field",
|
||||
name: "process nil field (a.Data) in attestation",
|
||||
a: ðpb.Attestation{},
|
||||
wantedErr: "nil attestation.Data field",
|
||||
},
|
||||
{
|
||||
name: "process nil field (a.Target) in attestation",
|
||||
a: ðpb.Attestation{Data: ðpb.AttestationData{}},
|
||||
s: &pb.BeaconState{},
|
||||
wantErr: true,
|
||||
wantErrString: "nil attestation.Data.Target field",
|
||||
name: "process nil field (a.Target) in attestation",
|
||||
a: ðpb.Attestation{
|
||||
Data: ðpb.AttestationData{
|
||||
BeaconBlockRoot: make([]byte, 32),
|
||||
Target: nil,
|
||||
Source: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
},
|
||||
AggregationBits: make([]byte, 1),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
wantedErr: "nil attestation.Data.Target field",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
_, err := service.onAttestation(ctx, tt.a)
|
||||
if tt.wantErr {
|
||||
if err == nil || !strings.Contains(err.Error(), tt.wantErrString) {
|
||||
t.Errorf("Store.onAttestation() error = %v, wantErr = %v", err, tt.wantErrString)
|
||||
}
|
||||
if tt.wantedErr != "" {
|
||||
assert.ErrorContains(t, tt.wantedErr, err)
|
||||
} else {
|
||||
t.Error(err)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestStore_OnAttestationUsingCheckptCache(t *testing.T) {
|
||||
resetCfg := featureconfig.InitWithReset(&featureconfig.Flags{UseCheckPointInfoCache: true})
|
||||
defer resetCfg()
|
||||
|
||||
ctx := context.Background()
|
||||
db, sc := testDB.SetupDB(t)
|
||||
|
||||
cfg := &Config{
|
||||
BeaconDB: db,
|
||||
ForkChoiceStore: protoarray.New(0, 0, [32]byte{}),
|
||||
StateGen: stategen.New(db, sc),
|
||||
}
|
||||
service, err := NewService(ctx, cfg)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = blockTree1(db, []byte{'g'})
|
||||
require.NoError(t, err)
|
||||
|
||||
BlkWithOutState := testutil.NewBeaconBlock()
|
||||
BlkWithOutState.Block.Slot = 0
|
||||
require.NoError(t, db.SaveBlock(ctx, BlkWithOutState))
|
||||
BlkWithOutStateRoot, err := BlkWithOutState.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
BlkWithStateBadAtt := testutil.NewBeaconBlock()
|
||||
BlkWithStateBadAtt.Block.Slot = 1
|
||||
require.NoError(t, db.SaveBlock(ctx, BlkWithStateBadAtt))
|
||||
BlkWithStateBadAttRoot, err := BlkWithStateBadAtt.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
s := testutil.NewBeaconState()
|
||||
require.NoError(t, s.SetSlot(100*params.BeaconConfig().SlotsPerEpoch))
|
||||
require.NoError(t, service.beaconDB.SaveState(ctx, s, BlkWithStateBadAttRoot))
|
||||
|
||||
BlkWithValidState := testutil.NewBeaconBlock()
|
||||
BlkWithValidState.Block.Slot = 2
|
||||
require.NoError(t, db.SaveBlock(ctx, BlkWithValidState))
|
||||
|
||||
BlkWithValidStateRoot, err := BlkWithValidState.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
s = testutil.NewBeaconState()
|
||||
err = s.SetFork(&pb.Fork{
|
||||
Epoch: 0,
|
||||
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, service.beaconDB.SaveState(ctx, s, BlkWithValidStateRoot))
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
a *ethpb.Attestation
|
||||
wantedErr string
|
||||
}{
|
||||
{
|
||||
name: "attestation's data slot not aligned with target vote",
|
||||
a: ðpb.Attestation{Data: ðpb.AttestationData{Slot: params.BeaconConfig().SlotsPerEpoch, Target: ðpb.Checkpoint{Root: make([]byte, 32)}}},
|
||||
wantedErr: "data slot is not in the same epoch as target 1 != 0",
|
||||
},
|
||||
{
|
||||
name: "attestation's target root not in db",
|
||||
a: ðpb.Attestation{Data: ðpb.AttestationData{Target: ðpb.Checkpoint{Root: bytesutil.PadTo([]byte{'A'}, 32)}}},
|
||||
wantedErr: "target root does not exist in db",
|
||||
},
|
||||
{
|
||||
name: "no pre state for attestations's target block",
|
||||
a: ðpb.Attestation{Data: ðpb.AttestationData{Target: ðpb.Checkpoint{Root: BlkWithOutStateRoot[:]}}},
|
||||
wantedErr: "could not get pre state for epoch 0",
|
||||
},
|
||||
{
|
||||
name: "process attestation doesn't match current epoch",
|
||||
a: ðpb.Attestation{Data: ðpb.AttestationData{Slot: 100 * params.BeaconConfig().SlotsPerEpoch, Target: ðpb.Checkpoint{Epoch: 100,
|
||||
Root: BlkWithStateBadAttRoot[:]}}},
|
||||
wantedErr: "target epoch 100 does not match current epoch",
|
||||
},
|
||||
{
|
||||
name: "process nil attestation",
|
||||
a: nil,
|
||||
wantedErr: "nil attestation",
|
||||
},
|
||||
{
|
||||
name: "process nil field (a.Data) in attestation",
|
||||
a: ðpb.Attestation{},
|
||||
wantedErr: "nil attestation.Data field",
|
||||
},
|
||||
{
|
||||
name: "process nil field (a.Target) in attestation",
|
||||
a: ðpb.Attestation{
|
||||
Data: ðpb.AttestationData{
|
||||
BeaconBlockRoot: make([]byte, 32),
|
||||
Target: nil,
|
||||
Source: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
},
|
||||
AggregationBits: make([]byte, 1),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
wantedErr: "nil attestation.Data.Target field",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
_, err := service.onAttestation(ctx, tt.a)
|
||||
if tt.wantedErr != "" {
|
||||
assert.ErrorContains(t, tt.wantedErr, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -150,22 +253,16 @@ func TestStore_SaveCheckpointState(t *testing.T) {
|
||||
service, err := NewService(ctx, cfg)
|
||||
require.NoError(t, err)
|
||||
|
||||
s, err := stateTrie.InitializeFromProto(&pb.BeaconState{
|
||||
Fork: &pb.Fork{
|
||||
Epoch: 0,
|
||||
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
},
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
StateRoots: make([][]byte, params.BeaconConfig().SlotsPerHistoricalRoot),
|
||||
BlockRoots: make([][]byte, params.BeaconConfig().SlotsPerHistoricalRoot),
|
||||
LatestBlockHeader: ðpb.BeaconBlockHeader{},
|
||||
JustificationBits: []byte{0},
|
||||
Slashings: make([]uint64, params.BeaconConfig().EpochsPerSlashingsVector),
|
||||
FinalizedCheckpoint: ðpb.Checkpoint{Root: bytesutil.PadTo([]byte{'A'}, 32)},
|
||||
Validators: []*ethpb.Validator{{PublicKey: bytesutil.PadTo([]byte("foo"), 48)}},
|
||||
Balances: []uint64{0},
|
||||
})
|
||||
s := testutil.NewBeaconState()
|
||||
err = s.SetFinalizedCheckpoint(ðpb.Checkpoint{Root: bytesutil.PadTo([]byte{'A'}, 32)})
|
||||
require.NoError(t, err)
|
||||
val := ðpb.Validator{
|
||||
PublicKey: bytesutil.PadTo([]byte("foo"), 48),
|
||||
WithdrawalCredentials: bytesutil.PadTo([]byte("bar"), 32),
|
||||
}
|
||||
err = s.SetValidators([]*ethpb.Validator{val})
|
||||
require.NoError(t, err)
|
||||
err = s.SetBalances([]uint64{0})
|
||||
require.NoError(t, err)
|
||||
r := [32]byte{'g'}
|
||||
require.NoError(t, service.beaconDB.SaveState(ctx, s, r))
|
||||
@@ -229,23 +326,24 @@ func TestStore_UpdateCheckpointState(t *testing.T) {
|
||||
|
||||
epoch := uint64(1)
|
||||
baseState, _ := testutil.DeterministicGenesisState(t, 1)
|
||||
require.NoError(t, baseState.SetSlot(epoch*params.BeaconConfig().SlotsPerEpoch))
|
||||
checkpoint := ðpb.Checkpoint{Epoch: epoch}
|
||||
checkpoint := ðpb.Checkpoint{Epoch: epoch, Root: bytesutil.PadTo([]byte("hi"), 32)}
|
||||
require.NoError(t, service.beaconDB.SaveState(ctx, baseState, bytesutil.ToBytes32(checkpoint.Root)))
|
||||
returned, err := service.getAttPreState(ctx, checkpoint)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, returned.Slot(), baseState.Slot(), "Incorrectly returned base state")
|
||||
assert.Equal(t, returned.Slot(), checkpoint.Epoch*params.BeaconConfig().SlotsPerEpoch, "Incorrectly returned base state")
|
||||
|
||||
cached, err := service.checkpointState.StateByCheckpoint(checkpoint)
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, cached, "State should have been cached")
|
||||
assert.Equal(t, returned.Slot(), cached.Slot(), "State should have been cached")
|
||||
|
||||
epoch = uint64(2)
|
||||
newCheckpoint := ðpb.Checkpoint{Epoch: epoch}
|
||||
newCheckpoint := ðpb.Checkpoint{Epoch: epoch, Root: bytesutil.PadTo([]byte("bye"), 32)}
|
||||
require.NoError(t, service.beaconDB.SaveState(ctx, baseState, bytesutil.ToBytes32(newCheckpoint.Root)))
|
||||
returned, err = service.getAttPreState(ctx, newCheckpoint)
|
||||
require.NoError(t, err)
|
||||
baseState, err = state.ProcessSlots(ctx, baseState, helpers.StartSlot(newCheckpoint.Epoch))
|
||||
s, err := helpers.StartSlot(newCheckpoint.Epoch)
|
||||
require.NoError(t, err)
|
||||
baseState, err = state.ProcessSlots(ctx, baseState, s)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, returned.Slot(), baseState.Slot(), "Incorrectly returned base state")
|
||||
|
||||
@@ -264,13 +362,8 @@ func TestAttEpoch_MatchPrevEpoch(t *testing.T) {
|
||||
service, err := NewService(ctx, cfg)
|
||||
require.NoError(t, err)
|
||||
|
||||
if err := service.verifyAttTargetEpoch(
|
||||
ctx,
|
||||
0,
|
||||
params.BeaconConfig().SlotsPerEpoch*params.BeaconConfig().SecondsPerSlot,
|
||||
ðpb.Checkpoint{}); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
nowTime := params.BeaconConfig().SlotsPerEpoch * params.BeaconConfig().SecondsPerSlot
|
||||
require.NoError(t, service.verifyAttTargetEpoch(ctx, 0, nowTime, ðpb.Checkpoint{Root: make([]byte, 32)}))
|
||||
}
|
||||
|
||||
func TestAttEpoch_MatchCurrentEpoch(t *testing.T) {
|
||||
@@ -281,13 +374,8 @@ func TestAttEpoch_MatchCurrentEpoch(t *testing.T) {
|
||||
service, err := NewService(ctx, cfg)
|
||||
require.NoError(t, err)
|
||||
|
||||
if err := service.verifyAttTargetEpoch(
|
||||
ctx,
|
||||
0,
|
||||
params.BeaconConfig().SlotsPerEpoch*params.BeaconConfig().SecondsPerSlot,
|
||||
ðpb.Checkpoint{Epoch: 1}); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
nowTime := params.BeaconConfig().SlotsPerEpoch * params.BeaconConfig().SecondsPerSlot
|
||||
require.NoError(t, service.verifyAttTargetEpoch(ctx, 0, nowTime, ðpb.Checkpoint{Epoch: 1}))
|
||||
}
|
||||
|
||||
func TestAttEpoch_NotMatch(t *testing.T) {
|
||||
@@ -298,14 +386,9 @@ func TestAttEpoch_NotMatch(t *testing.T) {
|
||||
service, err := NewService(ctx, cfg)
|
||||
require.NoError(t, err)
|
||||
|
||||
if err := service.verifyAttTargetEpoch(
|
||||
ctx,
|
||||
0,
|
||||
2*params.BeaconConfig().SlotsPerEpoch*params.BeaconConfig().SecondsPerSlot,
|
||||
ðpb.Checkpoint{}); !strings.Contains(err.Error(),
|
||||
"target epoch 0 does not match current epoch 2 or prev epoch 1") {
|
||||
t.Error("Did not receive wanted error")
|
||||
}
|
||||
nowTime := 2 * params.BeaconConfig().SlotsPerEpoch * params.BeaconConfig().SecondsPerSlot
|
||||
err = service.verifyAttTargetEpoch(ctx, 0, nowTime, ðpb.Checkpoint{Root: make([]byte, 32)})
|
||||
assert.ErrorContains(t, "target epoch 0 does not match current epoch 2 or prev epoch 1", err)
|
||||
}
|
||||
|
||||
func TestVerifyBeaconBlock_NoBlock(t *testing.T) {
|
||||
@@ -316,8 +399,12 @@ func TestVerifyBeaconBlock_NoBlock(t *testing.T) {
|
||||
service, err := NewService(ctx, cfg)
|
||||
require.NoError(t, err)
|
||||
|
||||
d := ðpb.AttestationData{}
|
||||
assert.ErrorContains(t, "beacon block does not exist", service.verifyBeaconBlock(ctx, d))
|
||||
d := ðpb.AttestationData{
|
||||
BeaconBlockRoot: make([]byte, 32),
|
||||
Target: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
Source: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
}
|
||||
assert.ErrorContains(t, "beacon block 0x000000000000 does not exist", service.verifyBeaconBlock(ctx, d))
|
||||
}
|
||||
|
||||
func TestVerifyBeaconBlock_futureBlock(t *testing.T) {
|
||||
@@ -328,9 +415,10 @@ func TestVerifyBeaconBlock_futureBlock(t *testing.T) {
|
||||
service, err := NewService(ctx, cfg)
|
||||
require.NoError(t, err)
|
||||
|
||||
b := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Slot: 2}}
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block.Slot = 2
|
||||
require.NoError(t, service.beaconDB.SaveBlock(ctx, b))
|
||||
r, err := stateutil.BlockRoot(b.Block)
|
||||
r, err := b.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
d := ðpb.AttestationData{Slot: 1, BeaconBlockRoot: r[:]}
|
||||
|
||||
@@ -345,9 +433,10 @@ func TestVerifyBeaconBlock_OK(t *testing.T) {
|
||||
service, err := NewService(ctx, cfg)
|
||||
require.NoError(t, err)
|
||||
|
||||
b := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Slot: 2}}
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block.Slot = 2
|
||||
require.NoError(t, service.beaconDB.SaveBlock(ctx, b))
|
||||
r, err := stateutil.BlockRoot(b.Block)
|
||||
r, err := b.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
d := ðpb.AttestationData{Slot: 2, BeaconBlockRoot: r[:]}
|
||||
|
||||
@@ -362,13 +451,16 @@ func TestVerifyLMDFFGConsistent_NotOK(t *testing.T) {
|
||||
service, err := NewService(ctx, cfg)
|
||||
require.NoError(t, err)
|
||||
|
||||
b32 := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Slot: 32}}
|
||||
b32 := testutil.NewBeaconBlock()
|
||||
b32.Block.Slot = 32
|
||||
require.NoError(t, service.beaconDB.SaveBlock(ctx, b32))
|
||||
r32, err := stateutil.BlockRoot(b32.Block)
|
||||
r32, err := b32.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
b33 := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Slot: 33, ParentRoot: r32[:]}}
|
||||
b33 := testutil.NewBeaconBlock()
|
||||
b33.Block.Slot = 33
|
||||
b33.Block.ParentRoot = r32[:]
|
||||
require.NoError(t, service.beaconDB.SaveBlock(ctx, b33))
|
||||
r33, err := stateutil.BlockRoot(b33.Block)
|
||||
r33, err := b33.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
wanted := "FFG and LMD votes are not consistent"
|
||||
@@ -383,15 +475,62 @@ func TestVerifyLMDFFGConsistent_OK(t *testing.T) {
|
||||
service, err := NewService(ctx, cfg)
|
||||
require.NoError(t, err)
|
||||
|
||||
b32 := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Slot: 32}}
|
||||
b32 := testutil.NewBeaconBlock()
|
||||
b32.Block.Slot = 32
|
||||
require.NoError(t, service.beaconDB.SaveBlock(ctx, b32))
|
||||
r32, err := stateutil.BlockRoot(b32.Block)
|
||||
r32, err := b32.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
b33 := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Slot: 33, ParentRoot: r32[:]}}
|
||||
b33 := testutil.NewBeaconBlock()
|
||||
b33.Block.Slot = 33
|
||||
b33.Block.ParentRoot = r32[:]
|
||||
require.NoError(t, service.beaconDB.SaveBlock(ctx, b33))
|
||||
r33, err := stateutil.BlockRoot(b33.Block)
|
||||
r33, err := b33.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
err = service.verifyLMDFFGConsistent(context.Background(), 1, r32[:], r33[:])
|
||||
assert.NoError(t, err, "Could not verify LMD and FFG votes to be consistent")
|
||||
}
|
||||
|
||||
func TestGetAttCheckptInfo(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
db, _ := testDB.SetupDB(t)
|
||||
cfg := &Config{BeaconDB: db, StateGen: stategen.New(db, cache.NewStateSummaryCache())}
|
||||
service, err := NewService(ctx, cfg)
|
||||
require.NoError(t, err)
|
||||
|
||||
baseState, _ := testutil.DeterministicGenesisState(t, 128)
|
||||
b := testutil.NewBeaconBlock()
|
||||
r, err := b.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, service.beaconDB.SaveState(ctx, baseState, r))
|
||||
require.NoError(t, service.beaconDB.SaveBlock(ctx, b))
|
||||
require.NoError(t, service.beaconDB.SaveGenesisBlockRoot(ctx, r))
|
||||
checkpoint := ðpb.Checkpoint{Root: r[:]}
|
||||
|
||||
returned, err := service.getAttCheckPtInfo(ctx, checkpoint, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
seed, err := helpers.Seed(baseState, 0, params.BeaconConfig().DomainBeaconAttester)
|
||||
require.NoError(t, err)
|
||||
indices, err := helpers.ActiveValidatorIndices(baseState, 0)
|
||||
require.NoError(t, err)
|
||||
validators := baseState.ValidatorsReadOnly()
|
||||
pks := make([][]byte, len(validators))
|
||||
for i := 0; i < len(pks); i++ {
|
||||
pk := validators[i].PublicKey()
|
||||
pks[i] = pk[:]
|
||||
}
|
||||
|
||||
wanted := &pb.CheckPtInfo{
|
||||
Fork: baseState.Fork(),
|
||||
GenesisRoot: baseState.GenesisValidatorRoot(),
|
||||
Seed: seed[:],
|
||||
ActiveIndices: indices,
|
||||
PubKeys: pks,
|
||||
}
|
||||
require.DeepEqual(t, wanted, returned)
|
||||
|
||||
cached, err := service.checkPtInfoCache.get(checkpoint)
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, wanted, cached)
|
||||
}
|
||||
|
||||
@@ -121,7 +121,11 @@ func (s *Service) onBlock(ctx context.Context, signed *ethpb.SignedBeaconBlock,
|
||||
}
|
||||
|
||||
// Update deposit cache.
|
||||
s.depositCache.InsertFinalizedDeposits(ctx, int64(postState.Eth1DepositIndex()))
|
||||
finalizedState, err := s.stateGen.StateByRoot(ctx, fRoot)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not fetch finalized state")
|
||||
}
|
||||
s.depositCache.InsertFinalizedDeposits(ctx, int64(finalizedState.Eth1Data().DepositCount-1))
|
||||
}
|
||||
|
||||
defer reportAttestationInclusion(b)
|
||||
@@ -231,11 +235,11 @@ func (s *Service) onBlockBatch(ctx context.Context, blks []*ethpb.SignedBeaconBl
|
||||
jCheckpoints := make([]*ethpb.Checkpoint, len(blks))
|
||||
fCheckpoints := make([]*ethpb.Checkpoint, len(blks))
|
||||
sigSet := &bls.SignatureSet{
|
||||
Signatures: []bls.Signature{},
|
||||
Signatures: [][]byte{},
|
||||
PublicKeys: []bls.PublicKey{},
|
||||
Messages: [][32]byte{},
|
||||
}
|
||||
set := new(bls.SignatureSet)
|
||||
var set *bls.SignatureSet
|
||||
boundaries := make(map[[32]byte]*stateTrie.BeaconState)
|
||||
for i, b := range blks {
|
||||
set, preState, err = state.ExecuteStateTransitionNoVerifyAnySig(ctx, preState, b)
|
||||
@@ -246,14 +250,14 @@ func (s *Service) onBlockBatch(ctx context.Context, blks []*ethpb.SignedBeaconBl
|
||||
if helpers.IsEpochStart(preState.Slot()) {
|
||||
boundaries[blockRoots[i]] = preState.Copy()
|
||||
if err := s.handleEpochBoundary(preState); err != nil {
|
||||
return nil, nil, fmt.Errorf("could not handle epoch boundary state")
|
||||
return nil, nil, errors.Wrap(err, "could not handle epoch boundary state")
|
||||
}
|
||||
}
|
||||
jCheckpoints[i] = preState.CurrentJustifiedCheckpoint()
|
||||
fCheckpoints[i] = preState.FinalizedCheckpoint()
|
||||
sigSet.Join(set)
|
||||
}
|
||||
verify, err := bls.VerifyMultipleSignatures(sigSet.Signatures, sigSet.Messages, sigSet.PublicKeys)
|
||||
verify, err := sigSet.Verify()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@@ -316,8 +320,11 @@ func (s *Service) handleBlockAfterBatchVerify(ctx context.Context, signed *ethpb
|
||||
func (s *Service) handleEpochBoundary(postState *stateTrie.BeaconState) error {
|
||||
if postState.Slot() >= s.nextEpochBoundarySlot {
|
||||
reportEpochMetrics(postState)
|
||||
s.nextEpochBoundarySlot = helpers.StartSlot(helpers.NextEpoch(postState))
|
||||
|
||||
var err error
|
||||
s.nextEpochBoundarySlot, err = helpers.StartSlot(helpers.NextEpoch(postState))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Update committees cache at epoch boundary slot.
|
||||
if err := helpers.UpdateCommitteeCache(postState, helpers.CurrentEpoch(postState)); err != nil {
|
||||
return err
|
||||
|
||||
@@ -9,23 +9,16 @@ import (
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"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/attestationutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/roughtime"
|
||||
"github.com/prysmaticlabs/prysm/shared/traceutil"
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
|
||||
// CurrentSlot returns the current slot based on time.
|
||||
func (s *Service) CurrentSlot() uint64 {
|
||||
now := roughtime.Now().Unix()
|
||||
genesis := s.genesisTime.Unix()
|
||||
if now < genesis {
|
||||
return 0
|
||||
}
|
||||
return uint64(now-genesis) / params.BeaconConfig().SecondsPerSlot
|
||||
return helpers.CurrentSlot(uint64(s.genesisTime.Unix()))
|
||||
}
|
||||
|
||||
// getBlockPreState returns the pre state of an incoming block. It uses the parent root of the block
|
||||
@@ -49,12 +42,7 @@ func (s *Service) getBlockPreState(ctx context.Context, b *ethpb.BeaconBlock) (*
|
||||
}
|
||||
|
||||
// Verify block slot time is not from the future.
|
||||
if err := helpers.VerifySlotTime(helpers.GenesisTime(preState), b.Slot, params.BeaconNetworkConfig().MaximumGossipClockDisparity); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Verify block is a descendent of a finalized block.
|
||||
if err := s.VerifyBlkDescendant(ctx, bytesutil.ToBytes32(b.ParentRoot)); err != nil {
|
||||
if err := helpers.VerifySlotTime(preState.GenesisTime(), b.Slot, params.BeaconNetworkConfig().MaximumGossipClockDisparity); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -78,6 +66,11 @@ func (s *Service) verifyBlkPreState(ctx context.Context, b *ethpb.BeaconBlock) e
|
||||
if !s.stateGen.StateSummaryExists(ctx, parentRoot) && !s.beaconDB.HasBlock(ctx, parentRoot) {
|
||||
return errors.New("could not reconstruct parent state")
|
||||
}
|
||||
|
||||
if err := s.VerifyBlkDescendant(ctx, bytesutil.ToBytes32(b.ParentRoot)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
has, err := s.stateGen.HasState(ctx, parentRoot)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -126,7 +119,10 @@ func (s *Service) VerifyBlkDescendant(ctx context.Context, root [32]byte) error
|
||||
// verifyBlkFinalizedSlot validates input block is not less than or equal
|
||||
// to current finalized slot.
|
||||
func (s *Service) verifyBlkFinalizedSlot(b *ethpb.BeaconBlock) error {
|
||||
finalizedSlot := helpers.StartSlot(s.finalizedCheckpt.Epoch)
|
||||
finalizedSlot, err := helpers.StartSlot(s.finalizedCheckpt.Epoch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if finalizedSlot >= b.Slot {
|
||||
return fmt.Errorf("block is equal or earlier than finalized block, slot %d < slot %d", b.Slot, finalizedSlot)
|
||||
}
|
||||
@@ -157,7 +153,11 @@ func (s *Service) shouldUpdateCurrentJustified(ctx context.Context, newJustified
|
||||
}
|
||||
|
||||
newJustifiedBlock := newJustifiedBlockSigned.Block
|
||||
if newJustifiedBlock.Slot <= helpers.StartSlot(s.justifiedCheckpt.Epoch) {
|
||||
jSlot, err := helpers.StartSlot(s.justifiedCheckpt.Epoch)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if newJustifiedBlock.Slot <= jSlot {
|
||||
return false, nil
|
||||
}
|
||||
var justifiedBlockSigned *ethpb.SignedBeaconBlock
|
||||
@@ -227,6 +227,10 @@ func (s *Service) updateFinalized(ctx context.Context, cp *ethpb.Checkpoint) err
|
||||
}
|
||||
s.clearInitSyncBlocks()
|
||||
|
||||
if err := s.beaconDB.SaveFinalizedCheckpoint(ctx, cp); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.prevFinalizedCheckpt = s.finalizedCheckpt
|
||||
s.finalizedCheckpt = cp
|
||||
|
||||
@@ -235,9 +239,7 @@ func (s *Service) updateFinalized(ctx context.Context, cp *ethpb.Checkpoint) err
|
||||
return errors.Wrap(err, "could not migrate to cold")
|
||||
}
|
||||
|
||||
s.attPool.ClearSeenAtts()
|
||||
|
||||
return s.beaconDB.SaveFinalizedCheckpoint(ctx, cp)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ancestor returns the block root of an ancestry block from the input block root.
|
||||
@@ -256,16 +258,35 @@ func (s *Service) ancestor(ctx context.Context, root []byte, slot uint64) ([]byt
|
||||
ctx, span := trace.StartSpan(ctx, "forkChoice.ancestor")
|
||||
defer span.End()
|
||||
|
||||
// Stop recursive ancestry lookup if context is cancelled.
|
||||
if ctx.Err() != nil {
|
||||
return nil, ctx.Err()
|
||||
}
|
||||
|
||||
r := bytesutil.ToBytes32(root)
|
||||
// Get ancestor root from fork choice store instead of recursively looking up blocks in DB.
|
||||
// This is most optimal outcome.
|
||||
if s.forkChoiceStore.HasParent(r) {
|
||||
return s.forkChoiceStore.AncestorRoot(ctx, r, slot)
|
||||
ar, err := s.ancestorByForkChoiceStore(ctx, r, slot)
|
||||
if err != nil {
|
||||
// Try getting ancestor root from DB when failed to retrieve from fork choice store.
|
||||
// This is the second line of defense for retrieving ancestor root.
|
||||
ar, err = s.ancestorByDB(ctx, r, slot)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return ar, nil
|
||||
}
|
||||
|
||||
// This retrieves an ancestor root using fork choice store. The look up is looping through the a flat array structure.
|
||||
func (s *Service) ancestorByForkChoiceStore(ctx context.Context, r [32]byte, slot uint64) ([]byte, error) {
|
||||
if !s.forkChoiceStore.HasParent(r) {
|
||||
return nil, errors.New("could not find root in fork choice store")
|
||||
}
|
||||
return s.forkChoiceStore.AncestorRoot(ctx, r, slot)
|
||||
}
|
||||
|
||||
// This retrieves an ancestor root using DB. The look up is recursively looking up DB. Slower than `ancestorByForkChoiceStore`.
|
||||
func (s *Service) ancestorByDB(ctx context.Context, r [32]byte, slot uint64) ([]byte, error) {
|
||||
// Stop recursive ancestry lookup if context is cancelled.
|
||||
if ctx.Err() != nil {
|
||||
return nil, ctx.Err()
|
||||
}
|
||||
|
||||
signed, err := s.beaconDB.Block(ctx, r)
|
||||
@@ -282,10 +303,10 @@ func (s *Service) ancestor(ctx context.Context, root []byte, slot uint64) ([]byt
|
||||
}
|
||||
b := signed.Block
|
||||
if b.Slot == slot || b.Slot < slot {
|
||||
return root, nil
|
||||
return r[:], nil
|
||||
}
|
||||
|
||||
return s.ancestor(ctx, b.ParentRoot, slot)
|
||||
return s.ancestorByDB(ctx, bytesutil.ToBytes32(b.ParentRoot), slot)
|
||||
}
|
||||
|
||||
// This updates justified check point in store, if the new justified is later than stored justified or
|
||||
@@ -308,14 +329,14 @@ func (s *Service) finalizedImpliesNewJustified(ctx context.Context, state *state
|
||||
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
|
||||
return s.cacheJustifiedStateBalances(ctx, bytesutil.ToBytes32(s.justifiedCheckpt.Root))
|
||||
}
|
||||
|
||||
// Update justified if store justified is not in chain with finalized check point.
|
||||
finalizedSlot := helpers.StartSlot(s.finalizedCheckpt.Epoch)
|
||||
finalizedSlot, err := helpers.StartSlot(s.finalizedCheckpt.Epoch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
justifiedRoot := s.ensureRootNotZeros(bytesutil.ToBytes32(s.justifiedCheckpt.Root))
|
||||
anc, err := s.ancestor(ctx, justifiedRoot[:], finalizedSlot)
|
||||
if err != nil {
|
||||
@@ -340,7 +361,11 @@ func (s *Service) fillInForkChoiceMissingBlocks(ctx context.Context, blk *ethpb.
|
||||
parentRoot := bytesutil.ToBytes32(blk.ParentRoot)
|
||||
slot := blk.Slot
|
||||
// Fork choice only matters from last finalized slot.
|
||||
higherThanFinalized := slot > helpers.StartSlot(s.finalizedCheckpt.Epoch)
|
||||
fSlot, err := helpers.StartSlot(s.finalizedCheckpt.Epoch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
higherThanFinalized := slot > fSlot
|
||||
// As long as parent node is not in fork choice store, and parent node is in DB.
|
||||
for !s.forkChoiceStore.HasNode(parentRoot) && s.beaconDB.HasBlock(ctx, parentRoot) && higherThanFinalized {
|
||||
b, err := s.beaconDB.Block(ctx, parentRoot)
|
||||
@@ -351,14 +376,14 @@ func (s *Service) fillInForkChoiceMissingBlocks(ctx context.Context, blk *ethpb.
|
||||
pendingNodes = append(pendingNodes, b.Block)
|
||||
parentRoot = bytesutil.ToBytes32(b.Block.ParentRoot)
|
||||
slot = b.Block.Slot
|
||||
higherThanFinalized = slot > helpers.StartSlot(s.finalizedCheckpt.Epoch)
|
||||
higherThanFinalized = slot > fSlot
|
||||
}
|
||||
|
||||
// Insert parent nodes to fork choice store in reverse order.
|
||||
// Lower slots should be at the end of the list.
|
||||
for i := len(pendingNodes) - 1; i >= 0; i-- {
|
||||
b := pendingNodes[i]
|
||||
r, err := stateutil.BlockRoot(b)
|
||||
r, err := b.HashTreeRoot()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -2,12 +2,11 @@ package blockchain
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"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/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/state"
|
||||
@@ -16,16 +15,14 @@ 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"
|
||||
"github.com/prysmaticlabs/prysm/shared/roughtime"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
"github.com/prysmaticlabs/prysm/shared/timeutils"
|
||||
)
|
||||
|
||||
func TestStore_OnBlock(t *testing.T) {
|
||||
@@ -42,50 +39,66 @@ func TestStore_OnBlock(t *testing.T) {
|
||||
genesisStateRoot := [32]byte{}
|
||||
genesis := blocks.NewGenesisBlock(genesisStateRoot[:])
|
||||
assert.NoError(t, db.SaveBlock(ctx, genesis))
|
||||
validGenesisRoot, err := stateutil.BlockRoot(genesis.Block)
|
||||
validGenesisRoot, err := genesis.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
st := testutil.NewBeaconState()
|
||||
require.NoError(t, service.beaconDB.SaveState(ctx, st.Copy(), validGenesisRoot))
|
||||
roots, err := blockTree1(db, validGenesisRoot[:])
|
||||
require.NoError(t, err)
|
||||
random := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Slot: 1, ParentRoot: validGenesisRoot[:]}}
|
||||
random := testutil.NewBeaconBlock()
|
||||
random.Block.Slot = 1
|
||||
random.Block.ParentRoot = validGenesisRoot[:]
|
||||
assert.NoError(t, db.SaveBlock(ctx, random))
|
||||
randomParentRoot, err := stateutil.BlockRoot(random.Block)
|
||||
randomParentRoot, err := random.Block.HashTreeRoot()
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, service.beaconDB.SaveStateSummary(ctx, &pb.StateSummary{Slot: st.Slot(), Root: randomParentRoot[:]}))
|
||||
require.NoError(t, service.beaconDB.SaveState(ctx, st.Copy(), randomParentRoot))
|
||||
randomParentRoot2 := roots[1]
|
||||
require.NoError(t, service.beaconDB.SaveStateSummary(ctx, &pb.StateSummary{Slot: st.Slot(), Root: randomParentRoot2[:]}))
|
||||
require.NoError(t, service.beaconDB.SaveStateSummary(ctx, &pb.StateSummary{Slot: st.Slot(), Root: randomParentRoot2}))
|
||||
require.NoError(t, service.beaconDB.SaveState(ctx, st.Copy(), bytesutil.ToBytes32(randomParentRoot2)))
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
blk *ethpb.BeaconBlock
|
||||
blk *ethpb.SignedBeaconBlock
|
||||
s *stateTrie.BeaconState
|
||||
time uint64
|
||||
wantErrString string
|
||||
}{
|
||||
{
|
||||
name: "parent block root does not have a state",
|
||||
blk: ðpb.BeaconBlock{},
|
||||
blk: testutil.NewBeaconBlock(),
|
||||
s: st.Copy(),
|
||||
wantErrString: "could not reconstruct parent state",
|
||||
},
|
||||
{
|
||||
name: "block is from the future",
|
||||
blk: ðpb.BeaconBlock{ParentRoot: randomParentRoot[:], Slot: params.BeaconConfig().FarFutureEpoch},
|
||||
name: "block is from the future",
|
||||
blk: func() *ethpb.SignedBeaconBlock {
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block.ParentRoot = randomParentRoot2
|
||||
b.Block.Slot = params.BeaconConfig().FarFutureEpoch
|
||||
return b
|
||||
}(),
|
||||
s: st.Copy(),
|
||||
wantErrString: "far distant future",
|
||||
wantErrString: "is in the far distant future",
|
||||
},
|
||||
{
|
||||
name: "could not get finalized block",
|
||||
blk: ðpb.BeaconBlock{ParentRoot: randomParentRoot[:]},
|
||||
name: "could not get finalized block",
|
||||
blk: func() *ethpb.SignedBeaconBlock {
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block.ParentRoot = randomParentRoot[:]
|
||||
return b
|
||||
}(),
|
||||
s: st.Copy(),
|
||||
wantErrString: "is not a descendent of the current finalized block",
|
||||
},
|
||||
{
|
||||
name: "same slot as finalized block",
|
||||
blk: ðpb.BeaconBlock{Slot: 0, ParentRoot: randomParentRoot2},
|
||||
name: "same slot as finalized block",
|
||||
blk: func() *ethpb.SignedBeaconBlock {
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block.Slot = 0
|
||||
b.Block.ParentRoot = randomParentRoot2
|
||||
return b
|
||||
}(),
|
||||
s: st.Copy(),
|
||||
wantErrString: "block is equal or earlier than finalized block, slot 0 < slot 0",
|
||||
},
|
||||
@@ -99,9 +112,9 @@ func TestStore_OnBlock(t *testing.T) {
|
||||
service.prevFinalizedCheckpt = ðpb.Checkpoint{Root: validGenesisRoot[:]}
|
||||
service.finalizedCheckpt.Root = roots[0]
|
||||
|
||||
root, err := stateutil.BlockRoot(tt.blk)
|
||||
root, err := tt.blk.Block.HashTreeRoot()
|
||||
assert.NoError(t, err)
|
||||
err = service.onBlock(ctx, ðpb.SignedBeaconBlock{Block: tt.blk}, root)
|
||||
err = service.onBlock(ctx, tt.blk, root)
|
||||
assert.ErrorContains(t, tt.wantErrString, err)
|
||||
})
|
||||
}
|
||||
@@ -121,6 +134,13 @@ func TestStore_OnBlockBatch(t *testing.T) {
|
||||
genesisStateRoot := [32]byte{}
|
||||
genesis := blocks.NewGenesisBlock(genesisStateRoot[:])
|
||||
assert.NoError(t, db.SaveBlock(ctx, genesis))
|
||||
gRoot, err := genesis.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
service.finalizedCheckpt = ðpb.Checkpoint{
|
||||
Root: gRoot[:],
|
||||
}
|
||||
service.forkChoiceStore = protoarray.New(0, 0, [32]byte{})
|
||||
service.saveInitSyncBlock(gRoot, genesis)
|
||||
|
||||
st, keys := testutil.DeterministicGenesisState(t, 64)
|
||||
|
||||
@@ -137,11 +157,14 @@ func TestStore_OnBlockBatch(t *testing.T) {
|
||||
if i == 1 {
|
||||
firstState = bState.Copy()
|
||||
}
|
||||
root, err := stateutil.BlockRoot(b.Block)
|
||||
root, err := b.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
service.saveInitSyncBlock(root, b)
|
||||
blks = append(blks, b)
|
||||
blkRoots = append(blkRoots, root)
|
||||
}
|
||||
|
||||
blks[0].Block.ParentRoot = gRoot[:]
|
||||
require.NoError(t, db.SaveBlock(context.Background(), blks[0]))
|
||||
require.NoError(t, service.stateGen.SaveState(ctx, blkRoots[0], firstState))
|
||||
_, _, err = service.onBlockBatch(ctx, blks[1:], blkRoots[1:])
|
||||
@@ -159,17 +182,17 @@ func TestRemoveStateSinceLastFinalized_EmptyStartSlot(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
service.genesisTime = time.Now()
|
||||
|
||||
update, err := service.shouldUpdateCurrentJustified(ctx, ðpb.Checkpoint{})
|
||||
update, err := service.shouldUpdateCurrentJustified(ctx, ðpb.Checkpoint{Root: make([]byte, 32)})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, true, update, "Should be able to update justified")
|
||||
lastJustifiedBlk := testutil.NewBeaconBlock()
|
||||
lastJustifiedBlk.Block.ParentRoot = bytesutil.PadTo([]byte{'G'}, 32)
|
||||
lastJustifiedRoot, err := stateutil.BlockRoot(lastJustifiedBlk.Block)
|
||||
lastJustifiedRoot, err := lastJustifiedBlk.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
newJustifiedBlk := testutil.NewBeaconBlock()
|
||||
newJustifiedBlk.Block.Slot = 1
|
||||
newJustifiedBlk.Block.ParentRoot = bytesutil.PadTo(lastJustifiedRoot[:], 32)
|
||||
newJustifiedRoot, err := stateutil.BlockRoot(newJustifiedBlk.Block)
|
||||
newJustifiedRoot, err := newJustifiedBlk.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, service.beaconDB.SaveBlock(ctx, newJustifiedBlk))
|
||||
require.NoError(t, service.beaconDB.SaveBlock(ctx, lastJustifiedBlk))
|
||||
@@ -193,11 +216,11 @@ func TestShouldUpdateJustified_ReturnFalse(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
lastJustifiedBlk := testutil.NewBeaconBlock()
|
||||
lastJustifiedBlk.Block.ParentRoot = bytesutil.PadTo([]byte{'G'}, 32)
|
||||
lastJustifiedRoot, err := stateutil.BlockRoot(lastJustifiedBlk.Block)
|
||||
lastJustifiedRoot, err := lastJustifiedBlk.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
newJustifiedBlk := testutil.NewBeaconBlock()
|
||||
newJustifiedBlk.Block.ParentRoot = bytesutil.PadTo(lastJustifiedRoot[:], 32)
|
||||
newJustifiedRoot, err := stateutil.BlockRoot(newJustifiedBlk.Block)
|
||||
newJustifiedRoot, err := newJustifiedBlk.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, service.beaconDB.SaveBlock(ctx, newJustifiedBlk))
|
||||
require.NoError(t, service.beaconDB.SaveBlock(ctx, lastJustifiedBlk))
|
||||
@@ -212,9 +235,6 @@ func TestShouldUpdateJustified_ReturnFalse(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCachedPreState_CanGetFromStateSummary(t *testing.T) {
|
||||
resetCfg := featureconfig.InitWithReset(&featureconfig.Flags{NewStateMgmt: true})
|
||||
defer resetCfg()
|
||||
|
||||
ctx := context.Background()
|
||||
db, sc := testDB.SetupDB(t)
|
||||
|
||||
@@ -227,17 +247,27 @@ func TestCachedPreState_CanGetFromStateSummary(t *testing.T) {
|
||||
|
||||
s, err := stateTrie.InitializeFromProto(&pb.BeaconState{Slot: 1, GenesisValidatorsRoot: params.BeaconConfig().ZeroHash[:]})
|
||||
require.NoError(t, err)
|
||||
r := [32]byte{'A'}
|
||||
b := ðpb.BeaconBlock{Slot: 1, ParentRoot: r[:]}
|
||||
require.NoError(t, service.beaconDB.SaveStateSummary(ctx, &pb.StateSummary{Slot: 1, Root: r[:]}))
|
||||
require.NoError(t, service.stateGen.SaveState(ctx, r, s))
|
||||
require.NoError(t, service.verifyBlkPreState(ctx, b))
|
||||
|
||||
genesisStateRoot := [32]byte{}
|
||||
genesis := blocks.NewGenesisBlock(genesisStateRoot[:])
|
||||
assert.NoError(t, db.SaveBlock(ctx, genesis))
|
||||
gRoot, err := genesis.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
service.finalizedCheckpt = ðpb.Checkpoint{
|
||||
Root: gRoot[:],
|
||||
}
|
||||
service.forkChoiceStore = protoarray.New(0, 0, [32]byte{})
|
||||
service.saveInitSyncBlock(gRoot, genesis)
|
||||
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block.Slot = 1
|
||||
b.Block.ParentRoot = gRoot[:]
|
||||
require.NoError(t, service.beaconDB.SaveStateSummary(ctx, &pb.StateSummary{Slot: 1, Root: gRoot[:]}))
|
||||
require.NoError(t, service.stateGen.SaveState(ctx, gRoot, s))
|
||||
require.NoError(t, service.verifyBlkPreState(ctx, b.Block))
|
||||
}
|
||||
|
||||
func TestCachedPreState_CanGetFromDB(t *testing.T) {
|
||||
resetCfg := featureconfig.InitWithReset(&featureconfig.Flags{NewStateMgmt: true})
|
||||
defer resetCfg()
|
||||
|
||||
ctx := context.Background()
|
||||
db, sc := testDB.SetupDB(t)
|
||||
|
||||
@@ -248,19 +278,30 @@ func TestCachedPreState_CanGetFromDB(t *testing.T) {
|
||||
service, err := NewService(ctx, cfg)
|
||||
require.NoError(t, err)
|
||||
|
||||
r := [32]byte{'A'}
|
||||
b := ðpb.BeaconBlock{Slot: 1, ParentRoot: r[:]}
|
||||
genesisStateRoot := [32]byte{}
|
||||
genesis := blocks.NewGenesisBlock(genesisStateRoot[:])
|
||||
assert.NoError(t, db.SaveBlock(ctx, genesis))
|
||||
gRoot, err := genesis.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
service.finalizedCheckpt = ðpb.Checkpoint{
|
||||
Root: gRoot[:],
|
||||
}
|
||||
service.forkChoiceStore = protoarray.New(0, 0, [32]byte{})
|
||||
service.saveInitSyncBlock(gRoot, genesis)
|
||||
|
||||
service.finalizedCheckpt = ðpb.Checkpoint{Root: r[:]}
|
||||
err = service.verifyBlkPreState(ctx, b)
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block.Slot = 1
|
||||
service.finalizedCheckpt = ðpb.Checkpoint{Root: gRoot[:]}
|
||||
err = service.verifyBlkPreState(ctx, b.Block)
|
||||
wanted := "could not reconstruct parent state"
|
||||
assert.ErrorContains(t, wanted, err)
|
||||
|
||||
b.Block.ParentRoot = gRoot[:]
|
||||
s, err := stateTrie.InitializeFromProto(&pb.BeaconState{Slot: 1})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, service.beaconDB.SaveStateSummary(ctx, &pb.StateSummary{Slot: 1, Root: r[:]}))
|
||||
require.NoError(t, service.stateGen.SaveState(ctx, r, s))
|
||||
require.NoError(t, service.verifyBlkPreState(ctx, b))
|
||||
require.NoError(t, service.beaconDB.SaveStateSummary(ctx, &pb.StateSummary{Slot: 1, Root: gRoot[:]}))
|
||||
require.NoError(t, service.stateGen.SaveState(ctx, gRoot, s))
|
||||
require.NoError(t, service.verifyBlkPreState(ctx, b.Block))
|
||||
}
|
||||
|
||||
func TestUpdateJustified_CouldUpdateBest(t *testing.T) {
|
||||
@@ -271,9 +312,9 @@ func TestUpdateJustified_CouldUpdateBest(t *testing.T) {
|
||||
service, err := NewService(ctx, cfg)
|
||||
require.NoError(t, err)
|
||||
|
||||
signedBlock := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{}}
|
||||
signedBlock := testutil.NewBeaconBlock()
|
||||
require.NoError(t, db.SaveBlock(ctx, signedBlock))
|
||||
r, err := stateutil.BlockRoot(signedBlock.Block)
|
||||
r, err := signedBlock.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
service.justifiedCheckpt = ðpb.Checkpoint{Root: []byte{'A'}}
|
||||
service.bestJustifiedCheckpt = ðpb.Checkpoint{Root: []byte{'A'}}
|
||||
@@ -303,12 +344,12 @@ func TestFillForkChoiceMissingBlocks_CanSave(t *testing.T) {
|
||||
service, err := NewService(ctx, cfg)
|
||||
require.NoError(t, err)
|
||||
service.forkChoiceStore = protoarray.New(0, 0, [32]byte{'A'})
|
||||
service.finalizedCheckpt = ðpb.Checkpoint{}
|
||||
service.finalizedCheckpt = ðpb.Checkpoint{Root: make([]byte, 32)}
|
||||
|
||||
genesisStateRoot := [32]byte{}
|
||||
genesis := blocks.NewGenesisBlock(genesisStateRoot[:])
|
||||
require.NoError(t, db.SaveBlock(ctx, genesis))
|
||||
validGenesisRoot, err := stateutil.BlockRoot(genesis.Block)
|
||||
validGenesisRoot, err := genesis.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
st := testutil.NewBeaconState()
|
||||
|
||||
@@ -317,10 +358,12 @@ func TestFillForkChoiceMissingBlocks_CanSave(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
beaconState, _ := testutil.DeterministicGenesisState(t, 32)
|
||||
block := ðpb.BeaconBlock{Slot: 9, ParentRoot: roots[8], Body: ðpb.BeaconBlockBody{Graffiti: []byte{}}}
|
||||
block := testutil.NewBeaconBlock()
|
||||
block.Block.Slot = 9
|
||||
block.Block.ParentRoot = roots[8]
|
||||
|
||||
err = service.fillInForkChoiceMissingBlocks(
|
||||
context.Background(), block, beaconState.FinalizedCheckpoint(), beaconState.CurrentJustifiedCheckpoint())
|
||||
context.Background(), block.Block, beaconState.FinalizedCheckpoint(), beaconState.CurrentJustifiedCheckpoint())
|
||||
require.NoError(t, err)
|
||||
|
||||
// 5 nodes from the block tree 1. B0 - B3 - B4 - B6 - B8
|
||||
@@ -344,22 +387,27 @@ func TestFillForkChoiceMissingBlocks_FilterFinalized(t *testing.T) {
|
||||
genesisStateRoot := [32]byte{}
|
||||
genesis := blocks.NewGenesisBlock(genesisStateRoot[:])
|
||||
assert.NoError(t, db.SaveBlock(ctx, genesis))
|
||||
validGenesisRoot, err := stateutil.BlockRoot(genesis.Block)
|
||||
validGenesisRoot, err := genesis.Block.HashTreeRoot()
|
||||
assert.NoError(t, err)
|
||||
st := testutil.NewBeaconState()
|
||||
|
||||
require.NoError(t, service.beaconDB.SaveState(ctx, st.Copy(), validGenesisRoot))
|
||||
|
||||
// Define a tree branch, slot 63 <- 64 <- 65
|
||||
b63 := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Slot: 63, Body: ðpb.BeaconBlockBody{}}}
|
||||
b63 := testutil.NewBeaconBlock()
|
||||
b63.Block.Slot = 63
|
||||
require.NoError(t, service.beaconDB.SaveBlock(ctx, b63))
|
||||
r63, err := stateutil.BlockRoot(b63.Block)
|
||||
r63, err := b63.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
b64 := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Slot: 64, ParentRoot: r63[:], Body: ðpb.BeaconBlockBody{}}}
|
||||
b64 := testutil.NewBeaconBlock()
|
||||
b64.Block.Slot = 64
|
||||
b64.Block.ParentRoot = r63[:]
|
||||
require.NoError(t, service.beaconDB.SaveBlock(ctx, b64))
|
||||
r64, err := stateutil.BlockRoot(b64.Block)
|
||||
r64, err := b64.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
b65 := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Slot: 65, ParentRoot: r64[:], Body: ðpb.BeaconBlockBody{}}}
|
||||
b65 := testutil.NewBeaconBlock()
|
||||
b65.Block.Slot = 65
|
||||
b65.Block.ParentRoot = r64[:]
|
||||
require.NoError(t, service.beaconDB.SaveBlock(ctx, b65))
|
||||
|
||||
beaconState, _ := testutil.DeterministicGenesisState(t, 32)
|
||||
@@ -380,58 +428,74 @@ func TestFillForkChoiceMissingBlocks_FilterFinalized(t *testing.T) {
|
||||
// \- B3 - B4 - B6 - B8
|
||||
// (B1, and B3 are all from the same slots)
|
||||
func blockTree1(db db.Database, genesisRoot []byte) ([][]byte, error) {
|
||||
b0 := ðpb.BeaconBlock{Slot: 0, ParentRoot: genesisRoot}
|
||||
r0, err := ssz.HashTreeRoot(b0)
|
||||
genesisRoot = bytesutil.PadTo(genesisRoot, 32)
|
||||
b0 := testutil.NewBeaconBlock()
|
||||
b0.Block.Slot = 0
|
||||
b0.Block.ParentRoot = genesisRoot
|
||||
r0, err := b0.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b1 := ðpb.BeaconBlock{Slot: 1, ParentRoot: r0[:]}
|
||||
r1, err := ssz.HashTreeRoot(b1)
|
||||
b1 := testutil.NewBeaconBlock()
|
||||
b1.Block.Slot = 1
|
||||
b1.Block.ParentRoot = r0[:]
|
||||
r1, err := b1.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b3 := ðpb.BeaconBlock{Slot: 3, ParentRoot: r0[:]}
|
||||
r3, err := ssz.HashTreeRoot(b3)
|
||||
b3 := testutil.NewBeaconBlock()
|
||||
b3.Block.Slot = 3
|
||||
b3.Block.ParentRoot = r0[:]
|
||||
r3, err := b3.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b4 := ðpb.BeaconBlock{Slot: 4, ParentRoot: r3[:]}
|
||||
r4, err := ssz.HashTreeRoot(b4)
|
||||
b4 := testutil.NewBeaconBlock()
|
||||
b4.Block.Slot = 4
|
||||
b4.Block.ParentRoot = r3[:]
|
||||
r4, err := b4.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b5 := ðpb.BeaconBlock{Slot: 5, ParentRoot: r4[:]}
|
||||
r5, err := ssz.HashTreeRoot(b5)
|
||||
b5 := testutil.NewBeaconBlock()
|
||||
b5.Block.Slot = 5
|
||||
b5.Block.ParentRoot = r4[:]
|
||||
r5, err := b5.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b6 := ðpb.BeaconBlock{Slot: 6, ParentRoot: r4[:]}
|
||||
r6, err := ssz.HashTreeRoot(b6)
|
||||
b6 := testutil.NewBeaconBlock()
|
||||
b6.Block.Slot = 6
|
||||
b6.Block.ParentRoot = r4[:]
|
||||
r6, err := b6.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b7 := ðpb.BeaconBlock{Slot: 7, ParentRoot: r5[:]}
|
||||
r7, err := ssz.HashTreeRoot(b7)
|
||||
b7 := testutil.NewBeaconBlock()
|
||||
b7.Block.Slot = 7
|
||||
b7.Block.ParentRoot = r5[:]
|
||||
r7, err := b7.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b8 := ðpb.BeaconBlock{Slot: 8, ParentRoot: r6[:]}
|
||||
r8, err := ssz.HashTreeRoot(b8)
|
||||
b8 := testutil.NewBeaconBlock()
|
||||
b8.Block.Slot = 8
|
||||
b8.Block.ParentRoot = r6[:]
|
||||
r8, err := b8.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
st := testutil.NewBeaconState()
|
||||
|
||||
for _, b := range []*ethpb.BeaconBlock{b0, b1, b3, b4, b5, b6, b7, b8} {
|
||||
for _, b := range []*ethpb.SignedBeaconBlock{b0, b1, b3, b4, b5, b6, b7, b8} {
|
||||
beaconBlock := testutil.NewBeaconBlock()
|
||||
beaconBlock.Block.Slot = b.Slot
|
||||
beaconBlock.Block.ParentRoot = bytesutil.PadTo(b.ParentRoot, 32)
|
||||
beaconBlock.Block.Body = ðpb.BeaconBlockBody{}
|
||||
beaconBlock.Block.Slot = b.Block.Slot
|
||||
beaconBlock.Block.ParentRoot = bytesutil.PadTo(b.Block.ParentRoot, 32)
|
||||
if err := db.SaveBlock(context.Background(), beaconBlock); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := db.SaveState(context.Background(), st.Copy(), bytesutil.ToBytes32(beaconBlock.Block.ParentRoot)); err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "could not save state")
|
||||
}
|
||||
}
|
||||
if err := db.SaveState(context.Background(), st.Copy(), r1); err != nil {
|
||||
@@ -447,11 +511,20 @@ func blockTree1(db db.Database, genesisRoot []byte) ([][]byte, error) {
|
||||
}
|
||||
|
||||
func TestCurrentSlot_HandlesOverflow(t *testing.T) {
|
||||
svc := Service{genesisTime: roughtime.Now().Add(1 * time.Hour)}
|
||||
svc := Service{genesisTime: timeutils.Now().Add(1 * time.Hour)}
|
||||
|
||||
slot := svc.CurrentSlot()
|
||||
require.Equal(t, uint64(0), slot, "Unexpected slot")
|
||||
}
|
||||
func TestAncestorByDB_CtxErr(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
service, err := NewService(ctx, &Config{})
|
||||
require.NoError(t, err)
|
||||
|
||||
cancel()
|
||||
_, err = service.ancestorByDB(ctx, [32]byte{}, 0)
|
||||
require.ErrorContains(t, "context canceled", err)
|
||||
}
|
||||
|
||||
func TestAncestor_HandleSkipSlot(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
@@ -461,20 +534,25 @@ func TestAncestor_HandleSkipSlot(t *testing.T) {
|
||||
service, err := NewService(ctx, cfg)
|
||||
require.NoError(t, err)
|
||||
|
||||
b1 := ðpb.BeaconBlock{Slot: 1, ParentRoot: []byte{'a'}}
|
||||
r1, err := ssz.HashTreeRoot(b1)
|
||||
b1 := testutil.NewBeaconBlock()
|
||||
b1.Block.Slot = 1
|
||||
b1.Block.ParentRoot = bytesutil.PadTo([]byte{'a'}, 32)
|
||||
r1, err := b1.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
b100 := ðpb.BeaconBlock{Slot: 100, ParentRoot: r1[:]}
|
||||
r100, err := ssz.HashTreeRoot(b100)
|
||||
b100 := testutil.NewBeaconBlock()
|
||||
b100.Block.Slot = 100
|
||||
b100.Block.ParentRoot = r1[:]
|
||||
r100, err := b100.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
b200 := ðpb.BeaconBlock{Slot: 200, ParentRoot: r100[:]}
|
||||
r200, err := ssz.HashTreeRoot(b200)
|
||||
b200 := testutil.NewBeaconBlock()
|
||||
b200.Block.Slot = 200
|
||||
b200.Block.ParentRoot = r100[:]
|
||||
r200, err := b200.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
for _, b := range []*ethpb.BeaconBlock{b1, b100, b200} {
|
||||
for _, b := range []*ethpb.SignedBeaconBlock{b1, b100, b200} {
|
||||
beaconBlock := testutil.NewBeaconBlock()
|
||||
beaconBlock.Block.Slot = b.Slot
|
||||
beaconBlock.Block.ParentRoot = bytesutil.PadTo(b.ParentRoot, 32)
|
||||
beaconBlock.Block.Body = ðpb.BeaconBlockBody{}
|
||||
beaconBlock.Block.Slot = b.Block.Slot
|
||||
beaconBlock.Block.ParentRoot = bytesutil.PadTo(b.Block.ParentRoot, 32)
|
||||
require.NoError(t, db.SaveBlock(context.Background(), beaconBlock))
|
||||
}
|
||||
|
||||
@@ -493,6 +571,82 @@ func TestAncestor_HandleSkipSlot(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestAncestor_CanUseForkchoice(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
cfg := &Config{ForkChoiceStore: protoarray.New(0, 0, [32]byte{})}
|
||||
service, err := NewService(ctx, cfg)
|
||||
require.NoError(t, err)
|
||||
|
||||
b1 := testutil.NewBeaconBlock()
|
||||
b1.Block.Slot = 1
|
||||
b1.Block.ParentRoot = bytesutil.PadTo([]byte{'a'}, 32)
|
||||
r1, err := b1.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
b100 := testutil.NewBeaconBlock()
|
||||
b100.Block.Slot = 100
|
||||
b100.Block.ParentRoot = r1[:]
|
||||
r100, err := b100.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
b200 := testutil.NewBeaconBlock()
|
||||
b200.Block.Slot = 200
|
||||
b200.Block.ParentRoot = r100[:]
|
||||
r200, err := b200.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
for _, b := range []*ethpb.SignedBeaconBlock{b1, b100, b200} {
|
||||
beaconBlock := testutil.NewBeaconBlock()
|
||||
beaconBlock.Block.Slot = b.Block.Slot
|
||||
beaconBlock.Block.ParentRoot = bytesutil.PadTo(b.Block.ParentRoot, 32)
|
||||
r, err := b.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, service.forkChoiceStore.ProcessBlock(context.Background(), b.Block.Slot, r, bytesutil.ToBytes32(b.Block.ParentRoot), [32]byte{}, 0, 0)) // Saves blocks to fork choice store.
|
||||
}
|
||||
|
||||
r, err := service.ancestor(context.Background(), r200[:], 150)
|
||||
require.NoError(t, err)
|
||||
if bytesutil.ToBytes32(r) != r100 {
|
||||
t.Error("Did not get correct root")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAncestor_CanUseDB(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
db, _ := testDB.SetupDB(t)
|
||||
|
||||
cfg := &Config{BeaconDB: db, ForkChoiceStore: protoarray.New(0, 0, [32]byte{})}
|
||||
service, err := NewService(ctx, cfg)
|
||||
require.NoError(t, err)
|
||||
|
||||
b1 := testutil.NewBeaconBlock()
|
||||
b1.Block.Slot = 1
|
||||
b1.Block.ParentRoot = bytesutil.PadTo([]byte{'a'}, 32)
|
||||
r1, err := b1.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
b100 := testutil.NewBeaconBlock()
|
||||
b100.Block.Slot = 100
|
||||
b100.Block.ParentRoot = r1[:]
|
||||
r100, err := b100.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
b200 := testutil.NewBeaconBlock()
|
||||
b200.Block.Slot = 200
|
||||
b200.Block.ParentRoot = r100[:]
|
||||
r200, err := b200.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
for _, b := range []*ethpb.SignedBeaconBlock{b1, b100, b200} {
|
||||
beaconBlock := testutil.NewBeaconBlock()
|
||||
beaconBlock.Block.Slot = b.Block.Slot
|
||||
beaconBlock.Block.ParentRoot = bytesutil.PadTo(b.Block.ParentRoot, 32)
|
||||
require.NoError(t, db.SaveBlock(context.Background(), beaconBlock)) // Saves blocks to DB.
|
||||
}
|
||||
|
||||
require.NoError(t, service.forkChoiceStore.ProcessBlock(context.Background(), 200, r200, r200, [32]byte{}, 0, 0))
|
||||
|
||||
r, err := service.ancestor(context.Background(), r200[:], 150)
|
||||
require.NoError(t, err)
|
||||
if bytesutil.ToBytes32(r) != r100 {
|
||||
t.Error("Did not get correct root")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnsureRootNotZeroHashes(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
cfg := &Config{}
|
||||
@@ -557,16 +711,20 @@ func TestFinalizedImpliesNewJustified(t *testing.T) {
|
||||
require.NoError(t, service.beaconDB.SaveState(ctx, genesisState, bytesutil.ToBytes32(test.want.Root)))
|
||||
|
||||
if test.args.diffFinalizedCheckPoint {
|
||||
b1 := ðpb.BeaconBlock{Slot: 1, ParentRoot: []byte{'a'}}
|
||||
r1, err := ssz.HashTreeRoot(b1)
|
||||
b1 := testutil.NewBeaconBlock()
|
||||
b1.Block.Slot = 1
|
||||
b1.Block.ParentRoot = bytesutil.PadTo([]byte{'a'}, 32)
|
||||
r1, err := b1.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
b100 := ðpb.BeaconBlock{Slot: 100, ParentRoot: r1[:]}
|
||||
r100, err := ssz.HashTreeRoot(b100)
|
||||
b100 := testutil.NewBeaconBlock()
|
||||
b100.Block.Slot = 100
|
||||
b100.Block.ParentRoot = r1[:]
|
||||
r100, err := b100.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
for _, b := range []*ethpb.BeaconBlock{b1, b100} {
|
||||
for _, b := range []*ethpb.SignedBeaconBlock{b1, b100} {
|
||||
beaconBlock := testutil.NewBeaconBlock()
|
||||
beaconBlock.Block.Slot = b.Slot
|
||||
beaconBlock.Block.ParentRoot = bytesutil.PadTo(b.ParentRoot, 32)
|
||||
beaconBlock.Block.Slot = b.Block.Slot
|
||||
beaconBlock.Block.ParentRoot = bytesutil.PadTo(b.Block.ParentRoot, 32)
|
||||
require.NoError(t, service.beaconDB.SaveBlock(context.Background(), beaconBlock))
|
||||
}
|
||||
service.finalizedCheckpt = ðpb.Checkpoint{Root: []byte{'c'}, Epoch: 1}
|
||||
@@ -584,14 +742,14 @@ func TestVerifyBlkDescendant(t *testing.T) {
|
||||
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block.Slot = 1
|
||||
r, err := stateutil.BlockRoot(b.Block)
|
||||
r, err := b.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, db.SaveBlock(ctx, b))
|
||||
|
||||
b1 := testutil.NewBeaconBlock()
|
||||
b1.Block.Slot = 1
|
||||
b1.Block.Body.Graffiti = bytesutil.PadTo([]byte{'a'}, 32)
|
||||
r1, err := stateutil.BlockRoot(b1.Block)
|
||||
r1, err := b1.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, db.SaveBlock(ctx, b1))
|
||||
|
||||
@@ -601,18 +759,16 @@ func TestVerifyBlkDescendant(t *testing.T) {
|
||||
finalizedSlot uint64
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
shouldError bool
|
||||
err string
|
||||
name string
|
||||
args args
|
||||
wantedErr string
|
||||
}{
|
||||
{
|
||||
name: "could not get finalized block in block service cache",
|
||||
args: args{
|
||||
finalizedRoot: [32]byte{'a'},
|
||||
},
|
||||
shouldError: true,
|
||||
err: "nil finalized block",
|
||||
wantedErr: "nil finalized block",
|
||||
},
|
||||
{
|
||||
name: "could not get finalized block root in DB",
|
||||
@@ -620,8 +776,7 @@ func TestVerifyBlkDescendant(t *testing.T) {
|
||||
finalizedRoot: r,
|
||||
parentRoot: [32]byte{'a'},
|
||||
},
|
||||
shouldError: true,
|
||||
err: "could not get finalized block root",
|
||||
wantedErr: "could not get finalized block root",
|
||||
},
|
||||
{
|
||||
name: "is not descendant",
|
||||
@@ -629,8 +784,7 @@ func TestVerifyBlkDescendant(t *testing.T) {
|
||||
finalizedRoot: r1,
|
||||
parentRoot: r,
|
||||
},
|
||||
shouldError: true,
|
||||
err: "is not a descendent of the current finalized block slot",
|
||||
wantedErr: "is not a descendent of the current finalized block slot",
|
||||
},
|
||||
{
|
||||
name: "is descendant",
|
||||
@@ -638,22 +792,19 @@ func TestVerifyBlkDescendant(t *testing.T) {
|
||||
finalizedRoot: r,
|
||||
parentRoot: r,
|
||||
},
|
||||
shouldError: false,
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
for _, tt := range tests {
|
||||
service, err := NewService(ctx, &Config{BeaconDB: db, StateGen: stategen.New(db, sc), ForkChoiceStore: protoarray.New(0, 0, [32]byte{})})
|
||||
require.NoError(t, err)
|
||||
service.finalizedCheckpt = ðpb.Checkpoint{
|
||||
Root: test.args.finalizedRoot[:],
|
||||
Root: tt.args.finalizedRoot[:],
|
||||
}
|
||||
err = service.VerifyBlkDescendant(ctx, test.args.parentRoot)
|
||||
if test.shouldError {
|
||||
if err == nil || !strings.Contains(err.Error(), test.err) {
|
||||
t.Error("Did not get wanted error")
|
||||
}
|
||||
err = service.VerifyBlkDescendant(ctx, tt.args.parentRoot)
|
||||
if tt.wantedErr != "" {
|
||||
assert.ErrorContains(t, tt.wantedErr, err)
|
||||
} else if err != nil {
|
||||
t.Error(err)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -665,8 +816,8 @@ func TestUpdateJustifiedInitSync(t *testing.T) {
|
||||
service, err := NewService(ctx, cfg)
|
||||
require.NoError(t, err)
|
||||
|
||||
gBlk := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{}}
|
||||
gRoot, err := stateutil.BlockRoot(gBlk.Block)
|
||||
gBlk := testutil.NewBeaconBlock()
|
||||
gRoot, err := gBlk.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, service.beaconDB.SaveBlock(ctx, gBlk))
|
||||
require.NoError(t, service.beaconDB.SaveGenesisBlockRoot(ctx, gRoot))
|
||||
@@ -683,8 +834,6 @@ func TestUpdateJustifiedInitSync(t *testing.T) {
|
||||
assert.DeepEqual(t, currentCp, service.prevJustifiedCheckpt, "Incorrect previous justified checkpoint")
|
||||
assert.DeepEqual(t, newCp, service.CurrentJustifiedCheckpt(), "Incorrect current justified checkpoint in cache")
|
||||
cp, err := service.beaconDB.JustifiedCheckpoint(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, newCp, cp, "Incorrect current justified checkpoint in db")
|
||||
}
|
||||
|
||||
@@ -10,11 +10,12 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/feed"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/roughtime"
|
||||
"github.com/prysmaticlabs/prysm/shared/slotutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/timeutils"
|
||||
"github.com/sirupsen/logrus"
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
@@ -24,6 +25,8 @@ 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)
|
||||
AttestationCheckPtInfo(ctx context.Context, att *ethpb.Attestation) (*pb.CheckPtInfo, error)
|
||||
VerifyLmdFfgConsistency(ctx context.Context, att *ethpb.Attestation) error
|
||||
}
|
||||
|
||||
// ReceiveAttestationNoPubsub is a function that defines the operations that are performed on
|
||||
@@ -61,7 +64,7 @@ func (s *Service) IsValidAttestation(ctx context.Context, att *ethpb.Attestation
|
||||
return false
|
||||
}
|
||||
|
||||
if err := blocks.VerifyAttestation(ctx, baseState, att); err != nil {
|
||||
if err := blocks.VerifyAttestationSignature(ctx, baseState, att); err != nil {
|
||||
log.WithError(err).Error("Failed to validate attestation")
|
||||
return false
|
||||
}
|
||||
@@ -71,9 +74,34 @@ func (s *Service) IsValidAttestation(ctx context.Context, att *ethpb.Attestation
|
||||
|
||||
// AttestationPreState returns the pre state of attestation.
|
||||
func (s *Service) AttestationPreState(ctx context.Context, att *ethpb.Attestation) (*state.BeaconState, error) {
|
||||
ss, err := helpers.StartSlot(att.Data.Target.Epoch)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := helpers.ValidateSlotClock(ss, uint64(s.genesisTime.Unix())); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s.getAttPreState(ctx, att.Data.Target)
|
||||
}
|
||||
|
||||
// AttestationCheckPtInfo returns the check point info of attestation that can be used to verify the attestation
|
||||
// contents and signatures.
|
||||
func (s *Service) AttestationCheckPtInfo(ctx context.Context, att *ethpb.Attestation) (*pb.CheckPtInfo, error) {
|
||||
ss, err := helpers.StartSlot(att.Data.Target.Epoch)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := helpers.ValidateSlotClock(ss, uint64(s.genesisTime.Unix())); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s.getAttCheckPtInfo(ctx, att.Data.Target, helpers.SlotToEpoch(att.Data.Slot))
|
||||
}
|
||||
|
||||
// VerifyLmdFfgConsistency verifies that attestation's LMD and FFG votes are consistency to each other.
|
||||
func (s *Service) VerifyLmdFfgConsistency(ctx context.Context, a *ethpb.Attestation) error {
|
||||
return s.verifyLMDFFGConsistent(ctx, a.Data.Target.Epoch, a.Data.Target.Root, a.Data.BeaconBlockRoot)
|
||||
}
|
||||
|
||||
// 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.
|
||||
@@ -89,7 +117,7 @@ func (s *Service) processAttestation(subscribedToStateEvents chan struct{}) {
|
||||
case <-s.ctx.Done():
|
||||
return
|
||||
case <-st.C():
|
||||
ctx := context.Background()
|
||||
ctx := s.ctx
|
||||
atts := s.attPool.ForkchoiceAttestations()
|
||||
for _, a := range atts {
|
||||
// Based on the spec, don't process the attestation until the subsequent slot.
|
||||
@@ -131,7 +159,7 @@ func (s *Service) processAttestation(subscribedToStateEvents chan struct{}) {
|
||||
// This verifies the epoch of input checkpoint is within current epoch and previous epoch
|
||||
// with respect to current time. Returns true if it's within, false if it's not.
|
||||
func (s *Service) verifyCheckpointEpoch(c *ethpb.Checkpoint) bool {
|
||||
now := uint64(roughtime.Now().Unix())
|
||||
now := uint64(timeutils.Now().Unix())
|
||||
genesisTime := uint64(s.genesisTime.Unix())
|
||||
currentSlot := (now - genesisTime) / params.BeaconConfig().SecondsPerSlot
|
||||
currentEpoch := helpers.SlotToEpoch(currentSlot)
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
package blockchain
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"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"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
func TestVerifyCheckpointEpoch_Ok(t *testing.T) {
|
||||
@@ -17,6 +20,30 @@ func TestVerifyCheckpointEpoch_Ok(t *testing.T) {
|
||||
chainService := setupBeaconChain(t, db, sc)
|
||||
chainService.genesisTime = time.Now()
|
||||
|
||||
assert.Equal(t, true, chainService.verifyCheckpointEpoch(ðpb.Checkpoint{}))
|
||||
assert.Equal(t, true, chainService.verifyCheckpointEpoch(ðpb.Checkpoint{Root: make([]byte, 32)}))
|
||||
assert.Equal(t, false, chainService.verifyCheckpointEpoch(ðpb.Checkpoint{Epoch: 1}))
|
||||
}
|
||||
|
||||
func TestAttestationPreState_FarFutureSlot(t *testing.T) {
|
||||
helpers.ClearCache()
|
||||
db, sc := testDB.SetupDB(t)
|
||||
|
||||
chainService := setupBeaconChain(t, db, sc)
|
||||
chainService.genesisTime = time.Now()
|
||||
|
||||
e := helpers.MaxSlotBuffer/params.BeaconConfig().SlotsPerEpoch + 1
|
||||
_, err := chainService.AttestationCheckPtInfo(context.Background(), ðpb.Attestation{Data: ðpb.AttestationData{Target: ðpb.Checkpoint{Epoch: e}}})
|
||||
require.ErrorContains(t, "exceeds max allowed value relative to the local clock", err)
|
||||
}
|
||||
|
||||
func TestAttestationCheckPtInfo_FarFutureSlot(t *testing.T) {
|
||||
helpers.ClearCache()
|
||||
db, sc := testDB.SetupDB(t)
|
||||
|
||||
chainService := setupBeaconChain(t, db, sc)
|
||||
chainService.genesisTime = time.Now()
|
||||
|
||||
e := helpers.MaxSlotBuffer/params.BeaconConfig().SlotsPerEpoch + 1
|
||||
_, err := chainService.AttestationPreState(context.Background(), ðpb.Attestation{Data: ðpb.AttestationData{Target: ðpb.Checkpoint{Epoch: e}}})
|
||||
require.ErrorContains(t, "exceeds max allowed value relative to the local clock", err)
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ func (s *Service) ReceiveBlock(ctx context.Context, block *ethpb.SignedBeaconBlo
|
||||
}
|
||||
|
||||
// Reports on block and fork choice metrics.
|
||||
reportSlotMetrics(blockCopy.Block.Slot, s.headSlot(), s.CurrentSlot(), s.finalizedCheckpt)
|
||||
reportSlotMetrics(blockCopy.Block.Slot, s.HeadSlot(), s.CurrentSlot(), s.finalizedCheckpt)
|
||||
|
||||
// Log block sync status.
|
||||
logBlockSyncStatus(blockCopy.Block, blockRoot, s.finalizedCheckpt)
|
||||
@@ -95,7 +95,7 @@ func (s *Service) ReceiveBlockInitialSync(ctx context.Context, block *ethpb.Sign
|
||||
})
|
||||
|
||||
// Reports on blockCopy and fork choice metrics.
|
||||
reportSlotMetrics(blockCopy.Block.Slot, s.headSlot(), s.CurrentSlot(), s.finalizedCheckpt)
|
||||
reportSlotMetrics(blockCopy.Block.Slot, s.HeadSlot(), s.CurrentSlot(), s.finalizedCheckpt)
|
||||
|
||||
// Log state transition data.
|
||||
log.WithFields(logrus.Fields{
|
||||
@@ -139,7 +139,14 @@ func (s *Service) ReceiveBlockBatch(ctx context.Context, blocks []*ethpb.SignedB
|
||||
})
|
||||
|
||||
// Reports on blockCopy and fork choice metrics.
|
||||
reportSlotMetrics(blockCopy.Block.Slot, s.headSlot(), s.CurrentSlot(), s.finalizedCheckpt)
|
||||
reportSlotMetrics(blockCopy.Block.Slot, s.HeadSlot(), s.CurrentSlot(), s.finalizedCheckpt)
|
||||
}
|
||||
|
||||
if err := s.VerifyWeakSubjectivityRoot(s.ctx); err != nil {
|
||||
// log.Fatalf will prevent defer from being called
|
||||
span.End()
|
||||
// Exit run time if the node failed to verify weak subjectivity checkpoint.
|
||||
log.Fatalf("Could not verify weak subjectivity checkpoint: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -12,7 +12,6 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/operations/attestations"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/operations/voluntaryexits"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stategen"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
@@ -37,10 +36,10 @@ func TestService_ReceiveBlock(t *testing.T) {
|
||||
block *ethpb.SignedBeaconBlock
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantErr bool
|
||||
check func(*testing.T, *Service)
|
||||
name string
|
||||
args args
|
||||
wantedErr string
|
||||
check func(*testing.T, *Service)
|
||||
}{
|
||||
{
|
||||
name: "applies block with state transition",
|
||||
@@ -139,13 +138,16 @@ func TestService_ReceiveBlock(t *testing.T) {
|
||||
require.NoError(t, s.saveGenesisData(ctx, genesis))
|
||||
gBlk, err := s.beaconDB.GenesisBlock(ctx)
|
||||
require.NoError(t, err)
|
||||
gRoot, err := stateutil.BlockRoot(gBlk.Block)
|
||||
s.finalizedCheckpt = ðpb.Checkpoint{Root: gRoot[:]}
|
||||
root, err := stateutil.BlockRoot(tt.args.block.Block)
|
||||
gRoot, err := gBlk.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
if err := s.ReceiveBlock(ctx, tt.args.block, root); (err != nil) != tt.wantErr {
|
||||
t.Errorf("ReceiveBlock() error = %v, wantErr %v", err, tt.wantErr)
|
||||
s.finalizedCheckpt = ðpb.Checkpoint{Root: gRoot[:]}
|
||||
root, err := tt.args.block.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
err = s.ReceiveBlock(ctx, tt.args.block, root)
|
||||
if tt.wantedErr != "" {
|
||||
assert.ErrorContains(t, tt.wantedErr, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
tt.check(t, s)
|
||||
}
|
||||
})
|
||||
@@ -177,9 +179,10 @@ func TestService_ReceiveBlockUpdateHead(t *testing.T) {
|
||||
require.NoError(t, s.saveGenesisData(ctx, genesis))
|
||||
gBlk, err := s.beaconDB.GenesisBlock(ctx)
|
||||
require.NoError(t, err)
|
||||
gRoot, err := stateutil.BlockRoot(gBlk.Block)
|
||||
gRoot, err := gBlk.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
s.finalizedCheckpt = ðpb.Checkpoint{Root: gRoot[:]}
|
||||
root, err := stateutil.BlockRoot(b.Block)
|
||||
root, err := b.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
wg := sync.WaitGroup{}
|
||||
wg.Add(1)
|
||||
@@ -201,9 +204,7 @@ func TestService_ReceiveBlockInitialSync(t *testing.T) {
|
||||
genesis, keys := testutil.DeterministicGenesisState(t, 64)
|
||||
genFullBlock := func(t *testing.T, conf *testutil.BlockGenConfig, slot uint64) *ethpb.SignedBeaconBlock {
|
||||
blk, err := testutil.GenerateFullBlock(genesis, keys, conf, slot)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
return blk
|
||||
}
|
||||
|
||||
@@ -211,10 +212,10 @@ func TestService_ReceiveBlockInitialSync(t *testing.T) {
|
||||
block *ethpb.SignedBeaconBlock
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantErr bool
|
||||
check func(*testing.T, *Service)
|
||||
name string
|
||||
args args
|
||||
wantedErr string
|
||||
check func(*testing.T, *Service)
|
||||
}{
|
||||
{
|
||||
name: "applies block with state transition",
|
||||
@@ -261,14 +262,17 @@ func TestService_ReceiveBlockInitialSync(t *testing.T) {
|
||||
gBlk, err := s.beaconDB.GenesisBlock(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
gRoot, err := stateutil.BlockRoot(gBlk.Block)
|
||||
gRoot, err := gBlk.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
s.finalizedCheckpt = ðpb.Checkpoint{Root: gRoot[:]}
|
||||
root, err := stateutil.BlockRoot(tt.args.block.Block)
|
||||
root, err := tt.args.block.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
if err := s.ReceiveBlockInitialSync(ctx, tt.args.block, root); (err != nil) != tt.wantErr {
|
||||
t.Errorf("ReceiveBlockInitialSync() error = %v, wantErr %v", err, tt.wantErr)
|
||||
err = s.ReceiveBlockInitialSync(ctx, tt.args.block, root)
|
||||
if tt.wantedErr != "" {
|
||||
assert.ErrorContains(t, tt.wantedErr, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
tt.check(t, s)
|
||||
}
|
||||
})
|
||||
@@ -281,9 +285,7 @@ func TestService_ReceiveBlockBatch(t *testing.T) {
|
||||
genesis, keys := testutil.DeterministicGenesisState(t, 64)
|
||||
genFullBlock := func(t *testing.T, conf *testutil.BlockGenConfig, slot uint64) *ethpb.SignedBeaconBlock {
|
||||
blk, err := testutil.GenerateFullBlock(genesis, keys, conf, slot)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
return blk
|
||||
}
|
||||
|
||||
@@ -291,10 +293,10 @@ func TestService_ReceiveBlockBatch(t *testing.T) {
|
||||
block *ethpb.SignedBeaconBlock
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantErr bool
|
||||
check func(*testing.T, *Service)
|
||||
name string
|
||||
args args
|
||||
wantedErr string
|
||||
check func(*testing.T, *Service)
|
||||
}{
|
||||
{
|
||||
name: "applies block with state transition",
|
||||
@@ -322,8 +324,8 @@ func TestService_ReceiveBlockBatch(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
db, stateSummaryCache := testDB.SetupDB(t)
|
||||
genesisBlockRoot := bytesutil.ToBytes32(nil)
|
||||
|
||||
genesisBlockRoot, err := genesis.HashTreeRoot(ctx)
|
||||
require.NoError(t, err)
|
||||
cfg := &Config{
|
||||
BeaconDB: db,
|
||||
ForkChoiceStore: protoarray.New(
|
||||
@@ -341,15 +343,18 @@ func TestService_ReceiveBlockBatch(t *testing.T) {
|
||||
gBlk, err := s.beaconDB.GenesisBlock(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
gRoot, err := stateutil.BlockRoot(gBlk.Block)
|
||||
gRoot, err := gBlk.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
s.finalizedCheckpt = ðpb.Checkpoint{Root: gRoot[:]}
|
||||
root, err := stateutil.BlockRoot(tt.args.block.Block)
|
||||
root, err := tt.args.block.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
blks := []*ethpb.SignedBeaconBlock{tt.args.block}
|
||||
roots := [][32]byte{root}
|
||||
if err := s.ReceiveBlockBatch(ctx, blks, roots); (err != nil) != tt.wantErr {
|
||||
t.Errorf("ReceiveBlockBatch() error = %v, wantErr %v", err, tt.wantErr)
|
||||
err = s.ReceiveBlockBatch(ctx, blks, roots)
|
||||
if tt.wantedErr != "" {
|
||||
assert.ErrorContains(t, tt.wantedErr, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
tt.check(t, s)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -30,7 +30,6 @@ 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/params"
|
||||
@@ -75,6 +74,10 @@ type Service struct {
|
||||
recentCanonicalBlocksLock sync.RWMutex
|
||||
justifiedBalances []uint64
|
||||
justifiedBalancesLock sync.RWMutex
|
||||
checkPtInfoCache *checkPtInfoCache
|
||||
wsEpoch uint64
|
||||
wsRoot []byte
|
||||
wsVerified bool
|
||||
}
|
||||
|
||||
// Config options for the service.
|
||||
@@ -92,6 +95,8 @@ type Config struct {
|
||||
ForkChoiceStore f.ForkChoicer
|
||||
OpsService *attestations.Service
|
||||
StateGen *stategen.State
|
||||
WspBlockRoot []byte
|
||||
WspEpoch uint64
|
||||
}
|
||||
|
||||
// NewService instantiates a new block service instance that will
|
||||
@@ -119,6 +124,9 @@ func NewService(ctx context.Context, cfg *Config) (*Service, error) {
|
||||
initSyncBlocks: make(map[[32]byte]*ethpb.SignedBeaconBlock),
|
||||
recentCanonicalBlocks: make(map[[32]byte]bool),
|
||||
justifiedBalances: make([]uint64, 0),
|
||||
checkPtInfoCache: newCheckPointInfoCache(),
|
||||
wsEpoch: cfg.WspEpoch,
|
||||
wsRoot: cfg.WspBlockRoot,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -138,7 +146,23 @@ func (s *Service) Start() {
|
||||
}
|
||||
|
||||
if beaconState == nil {
|
||||
beaconState, err = s.stateGen.StateByRoot(s.ctx, bytesutil.ToBytes32(cp.Root))
|
||||
r := bytesutil.ToBytes32(cp.Root)
|
||||
// Before the first finalized epoch, in the current epoch,
|
||||
// the finalized root is defined as zero hashes instead of genesis root hash.
|
||||
// We want to use genesis root to retrieve for state.
|
||||
if r == params.BeaconConfig().ZeroHash {
|
||||
genesisBlock, err := s.beaconDB.GenesisBlock(s.ctx)
|
||||
if err != nil {
|
||||
log.Fatalf("Could not fetch finalized cp: %v", err)
|
||||
}
|
||||
if genesisBlock != nil {
|
||||
r, err = genesisBlock.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
log.Fatalf("Could not tree hash genesis block: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
beaconState, err = s.stateGen.StateByRoot(s.ctx, r)
|
||||
if err != nil {
|
||||
log.Fatalf("Could not fetch beacon state by root: %v", err)
|
||||
}
|
||||
@@ -150,8 +174,8 @@ func (s *Service) Start() {
|
||||
// If the chain has already been initialized, simply start the block processing routine.
|
||||
if beaconState != nil {
|
||||
log.Info("Blockchain data already exists in DB, initializing...")
|
||||
s.genesisTime = time.Unix(int64(helpers.GenesisTime(beaconState)), 0)
|
||||
s.opsService.SetGenesisTime(helpers.GenesisTime(beaconState))
|
||||
s.genesisTime = time.Unix(int64(beaconState.GenesisTime()), 0)
|
||||
s.opsService.SetGenesisTime(beaconState.GenesisTime())
|
||||
if err := s.initializeChainInfo(s.ctx); err != nil {
|
||||
log.Fatalf("Could not set up chain info: %v", err)
|
||||
}
|
||||
@@ -183,6 +207,11 @@ func (s *Service) Start() {
|
||||
s.prevFinalizedCheckpt = stateTrie.CopyCheckpoint(finalizedCheckpoint)
|
||||
s.resumeForkChoice(justifiedCheckpoint, finalizedCheckpoint)
|
||||
|
||||
if err := s.VerifyWeakSubjectivityRoot(s.ctx); err != nil {
|
||||
// Exit run time if the node failed to verify weak subjectivity checkpoint.
|
||||
log.Fatalf("Could not verify weak subjectivity checkpoint: %v", err)
|
||||
}
|
||||
|
||||
s.stateNotifier.StateFeed().Send(&feed.Event{
|
||||
Type: statefeed.Initialized,
|
||||
Data: &statefeed.InitializedData{
|
||||
@@ -258,7 +287,7 @@ func (s *Service) initializeBeaconChain(
|
||||
genesisTime time.Time,
|
||||
preGenesisState *stateTrie.BeaconState,
|
||||
eth1data *ethpb.Eth1Data) (*stateTrie.BeaconState, error) {
|
||||
_, span := trace.StartSpan(context.Background(), "beacon-chain.Service.initializeBeaconChain")
|
||||
ctx, span := trace.StartSpan(ctx, "beacon-chain.Service.initializeBeaconChain")
|
||||
defer span.End()
|
||||
s.genesisTime = genesisTime
|
||||
unixTime := uint64(genesisTime.Unix())
|
||||
@@ -285,7 +314,7 @@ func (s *Service) initializeBeaconChain(
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.opsService.SetGenesisTime(helpers.GenesisTime(genesisState))
|
||||
s.opsService.SetGenesisTime(genesisState.GenesisTime())
|
||||
|
||||
return genesisState, nil
|
||||
}
|
||||
@@ -295,9 +324,13 @@ func (s *Service) Stop() error {
|
||||
defer s.cancel()
|
||||
|
||||
if s.stateGen != nil && s.head != nil && s.head.state != nil {
|
||||
return s.stateGen.ForceCheckpoint(s.ctx, s.head.state.FinalizedCheckpoint().Root)
|
||||
if err := s.stateGen.ForceCheckpoint(s.ctx, s.head.state.FinalizedCheckpoint().Root); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
// Save initial sync cached blocks to the DB before stop.
|
||||
return s.beaconDB.SaveBlocks(s.ctx, s.getInitSyncBlocks())
|
||||
}
|
||||
|
||||
// Status always returns nil unless there is an error condition that causes
|
||||
@@ -322,7 +355,7 @@ func (s *Service) saveGenesisData(ctx context.Context, genesisState *stateTrie.B
|
||||
return err
|
||||
}
|
||||
genesisBlk := blocks.NewGenesisBlock(stateRoot[:])
|
||||
genesisBlkRoot, err := stateutil.BlockRoot(genesisBlk.Block)
|
||||
genesisBlkRoot, err := genesisBlk.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get genesis block root")
|
||||
}
|
||||
@@ -386,7 +419,7 @@ func (s *Service) initializeChainInfo(ctx context.Context) error {
|
||||
if genesisBlock == nil {
|
||||
return errors.New("no genesis block in db")
|
||||
}
|
||||
genesisBlkRoot, err := stateutil.BlockRoot(genesisBlock.Block)
|
||||
genesisBlkRoot, err := genesisBlock.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get signing root of genesis block")
|
||||
}
|
||||
@@ -397,7 +430,7 @@ func (s *Service) initializeChainInfo(ctx context.Context) error {
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not retrieve head block")
|
||||
}
|
||||
headRoot, err := stateutil.BlockRoot(headBlock.Block)
|
||||
headRoot, err := headBlock.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not hash head block")
|
||||
}
|
||||
@@ -418,17 +451,13 @@ func (s *Service) initializeChainInfo(ctx context.Context) error {
|
||||
// would be the genesis state and block.
|
||||
return errors.New("no finalized epoch in the database")
|
||||
}
|
||||
finalizedRoot := bytesutil.ToBytes32(finalized.Root)
|
||||
finalizedRoot := s.ensureRootNotZeros(bytesutil.ToBytes32(finalized.Root))
|
||||
var finalizedState *stateTrie.BeaconState
|
||||
|
||||
finalizedState, err = s.stateGen.Resume(ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get finalized state from db")
|
||||
}
|
||||
finalizedRoot = s.beaconDB.LastArchivedRoot(ctx)
|
||||
if finalizedRoot == params.BeaconConfig().ZeroHash {
|
||||
finalizedRoot = bytesutil.ToBytes32(finalized.Root)
|
||||
}
|
||||
|
||||
finalizedBlock, err := s.beaconDB.Block(ctx, finalizedRoot)
|
||||
if err != nil {
|
||||
|
||||
@@ -11,7 +11,6 @@ import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"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/cache/depositcache"
|
||||
b "github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
@@ -25,7 +24,6 @@ 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"
|
||||
@@ -69,7 +67,7 @@ func (mb *mockBroadcaster) BroadcastAttestation(_ context.Context, _ uint64, _ *
|
||||
return nil
|
||||
}
|
||||
|
||||
var _ = p2p.Broadcaster(&mockBroadcaster{})
|
||||
var _ p2p.Broadcaster = (*mockBroadcaster)(nil)
|
||||
|
||||
func setupBeaconChain(t *testing.T, beaconDB db.Database, sc *cache.StateSummaryCache) *Service {
|
||||
endpoint := "http://127.0.0.1"
|
||||
@@ -103,7 +101,7 @@ func setupBeaconChain(t *testing.T, beaconDB db.Database, sc *cache.StateSummary
|
||||
opsService, err := attestations.NewService(ctx, &attestations.Config{Pool: attestations.NewPool()})
|
||||
require.NoError(t, err)
|
||||
|
||||
depositCache, err := depositcache.NewDepositCache()
|
||||
depositCache, err := depositcache.New()
|
||||
require.NoError(t, err)
|
||||
|
||||
cfg := &Config{
|
||||
@@ -120,9 +118,7 @@ func setupBeaconChain(t *testing.T, beaconDB db.Database, sc *cache.StateSummary
|
||||
}
|
||||
|
||||
// Safe a state in stategen to purposes of testing a service stop / shutdown.
|
||||
if err := cfg.StateGen.SaveState(ctx, bytesutil.ToBytes32(bState.FinalizedCheckpoint().Root), bState); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, cfg.StateGen.SaveState(ctx, bytesutil.ToBytes32(bState.FinalizedCheckpoint().Root), bState))
|
||||
|
||||
chainService, err := NewService(ctx, cfg)
|
||||
require.NoError(t, err, "Unable to setup chain service")
|
||||
@@ -139,7 +135,7 @@ func TestChainStartStop_Initialized(t *testing.T) {
|
||||
chainService := setupBeaconChain(t, db, sc)
|
||||
|
||||
genesisBlk := testutil.NewBeaconBlock()
|
||||
blkRoot, err := stateutil.BlockRoot(genesisBlk.Block)
|
||||
blkRoot, err := genesisBlk.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, db.SaveBlock(ctx, genesisBlk))
|
||||
s := testutil.NewBeaconState()
|
||||
@@ -148,6 +144,33 @@ func TestChainStartStop_Initialized(t *testing.T) {
|
||||
require.NoError(t, db.SaveHeadBlockRoot(ctx, blkRoot))
|
||||
require.NoError(t, db.SaveGenesisBlockRoot(ctx, blkRoot))
|
||||
require.NoError(t, db.SaveJustifiedCheckpoint(ctx, ðpb.Checkpoint{Root: blkRoot[:]}))
|
||||
require.NoError(t, db.SaveFinalizedCheckpoint(ctx, ðpb.Checkpoint{Root: blkRoot[:]}))
|
||||
|
||||
// Test the start function.
|
||||
chainService.Start()
|
||||
|
||||
require.NoError(t, chainService.Stop(), "Unable to stop chain service")
|
||||
|
||||
// The context should have been canceled.
|
||||
assert.Equal(t, context.Canceled, chainService.ctx.Err(), "Context was not canceled")
|
||||
require.LogsContain(t, hook, "data already exists")
|
||||
}
|
||||
|
||||
func TestChainStartStop_GenesisZeroHashes(t *testing.T) {
|
||||
hook := logTest.NewGlobal()
|
||||
ctx := context.Background()
|
||||
db, sc := testDB.SetupDB(t)
|
||||
|
||||
chainService := setupBeaconChain(t, db, sc)
|
||||
|
||||
genesisBlk := testutil.NewBeaconBlock()
|
||||
blkRoot, err := genesisBlk.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, db.SaveBlock(ctx, genesisBlk))
|
||||
s := testutil.NewBeaconState()
|
||||
require.NoError(t, db.SaveState(ctx, s, blkRoot))
|
||||
require.NoError(t, db.SaveGenesisBlockRoot(ctx, blkRoot))
|
||||
require.NoError(t, db.SaveJustifiedCheckpoint(ctx, ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}))
|
||||
|
||||
// Test the start function.
|
||||
chainService.Start()
|
||||
@@ -179,11 +202,13 @@ func TestChainService_InitializeBeaconChain(t *testing.T) {
|
||||
err = genState.SetEth1Data(ðpb.Eth1Data{
|
||||
DepositRoot: hashTreeRoot[:],
|
||||
DepositCount: uint64(len(deposits)),
|
||||
BlockHash: make([]byte, 32),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
genState, err = b.ProcessPreGenesisDeposits(ctx, genState, deposits)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = bc.initializeBeaconChain(ctx, time.Unix(0, 0), genState, ðpb.Eth1Data{DepositRoot: hashTreeRoot[:]})
|
||||
_, err = bc.initializeBeaconChain(ctx, time.Unix(0, 0), genState, ðpb.Eth1Data{DepositRoot: hashTreeRoot[:], BlockHash: make([]byte, 32)})
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = bc.HeadState(ctx)
|
||||
@@ -193,7 +218,9 @@ func TestChainService_InitializeBeaconChain(t *testing.T) {
|
||||
if headBlk == nil {
|
||||
t.Error("Head state can't be nil after initialize beacon chain")
|
||||
}
|
||||
if bc.headRoot() == params.BeaconConfig().ZeroHash {
|
||||
r, err := bc.HeadRoot(ctx)
|
||||
require.NoError(t, err)
|
||||
if bytesutil.ToBytes32(r) == params.BeaconConfig().ZeroHash {
|
||||
t.Error("Canonical root for slot 0 can't be zeros after initialize beacon chain")
|
||||
}
|
||||
}
|
||||
@@ -205,7 +232,7 @@ func TestChainService_CorrectGenesisRoots(t *testing.T) {
|
||||
chainService := setupBeaconChain(t, db, sc)
|
||||
|
||||
genesisBlk := testutil.NewBeaconBlock()
|
||||
blkRoot, err := stateutil.BlockRoot(genesisBlk.Block)
|
||||
blkRoot, err := genesisBlk.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, db.SaveBlock(ctx, genesisBlk))
|
||||
s := testutil.NewBeaconState()
|
||||
@@ -213,10 +240,12 @@ func TestChainService_CorrectGenesisRoots(t *testing.T) {
|
||||
require.NoError(t, db.SaveState(ctx, s, blkRoot))
|
||||
require.NoError(t, db.SaveHeadBlockRoot(ctx, blkRoot))
|
||||
require.NoError(t, db.SaveGenesisBlockRoot(ctx, blkRoot))
|
||||
require.NoError(t, db.SaveFinalizedCheckpoint(ctx, ðpb.Checkpoint{Root: blkRoot[:]}))
|
||||
|
||||
// Test the start function.
|
||||
chainService.Start()
|
||||
|
||||
require.DeepEqual(t, params.BeaconConfig().ZeroHash[:], chainService.finalizedCheckpt.Root, "Finalize Checkpoint root is incorrect")
|
||||
require.DeepEqual(t, blkRoot[:], chainService.finalizedCheckpt.Root, "Finalize Checkpoint root is incorrect")
|
||||
require.DeepEqual(t, params.BeaconConfig().ZeroHash[:], chainService.justifiedCheckpt.Root, "Justified Checkpoint root is incorrect")
|
||||
|
||||
require.NoError(t, chainService.Stop(), "Unable to stop chain service")
|
||||
@@ -228,7 +257,7 @@ func TestChainService_InitializeChainInfo(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
genesis := testutil.NewBeaconBlock()
|
||||
genesisRoot, err := stateutil.BlockRoot(genesis.Block)
|
||||
genesisRoot, err := genesis.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, db.SaveGenesisBlockRoot(ctx, genesisRoot))
|
||||
require.NoError(t, db.SaveBlock(ctx, genesis))
|
||||
@@ -240,17 +269,12 @@ func TestChainService_InitializeChainInfo(t *testing.T) {
|
||||
headState := testutil.NewBeaconState()
|
||||
require.NoError(t, headState.SetSlot(finalizedSlot))
|
||||
require.NoError(t, headState.SetGenesisValidatorRoot(params.BeaconConfig().ZeroHash[:]))
|
||||
headRoot, err := stateutil.BlockRoot(headBlock.Block)
|
||||
headRoot, err := headBlock.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, db.SaveState(ctx, headState, headRoot))
|
||||
require.NoError(t, db.SaveState(ctx, headState, genesisRoot))
|
||||
require.NoError(t, db.SaveBlock(ctx, headBlock))
|
||||
if err := db.SaveFinalizedCheckpoint(ctx, ðpb.Checkpoint{
|
||||
Epoch: helpers.SlotToEpoch(finalizedSlot),
|
||||
Root: headRoot[:],
|
||||
}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, db.SaveFinalizedCheckpoint(ctx, ðpb.Checkpoint{Epoch: helpers.SlotToEpoch(finalizedSlot), Root: headRoot[:]}))
|
||||
c := &Service{beaconDB: db, stateGen: stategen.New(db, sc)}
|
||||
require.NoError(t, c.initializeChainInfo(ctx))
|
||||
headBlk, err := c.HeadBlock(ctx)
|
||||
@@ -268,6 +292,37 @@ func TestChainService_InitializeChainInfo(t *testing.T) {
|
||||
assert.Equal(t, genesisRoot, c.genesisRoot, "Genesis block root incorrect")
|
||||
}
|
||||
|
||||
func TestChainService_InitializeChainInfo_SetHeadAtGenesis(t *testing.T) {
|
||||
db, sc := testDB.SetupDB(t)
|
||||
ctx := context.Background()
|
||||
|
||||
genesis := testutil.NewBeaconBlock()
|
||||
genesisRoot, err := genesis.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, db.SaveGenesisBlockRoot(ctx, genesisRoot))
|
||||
require.NoError(t, db.SaveBlock(ctx, genesis))
|
||||
|
||||
finalizedSlot := params.BeaconConfig().SlotsPerEpoch*2 + 1
|
||||
headBlock := testutil.NewBeaconBlock()
|
||||
headBlock.Block.Slot = finalizedSlot
|
||||
headBlock.Block.ParentRoot = bytesutil.PadTo(genesisRoot[:], 32)
|
||||
headState := testutil.NewBeaconState()
|
||||
require.NoError(t, headState.SetSlot(finalizedSlot))
|
||||
require.NoError(t, headState.SetGenesisValidatorRoot(params.BeaconConfig().ZeroHash[:]))
|
||||
headRoot, err := headBlock.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, db.SaveState(ctx, headState, headRoot))
|
||||
require.NoError(t, db.SaveState(ctx, headState, genesisRoot))
|
||||
require.NoError(t, db.SaveBlock(ctx, headBlock))
|
||||
c := &Service{beaconDB: db, stateGen: stategen.New(db, sc)}
|
||||
require.NoError(t, c.initializeChainInfo(ctx))
|
||||
s, err := c.HeadState(ctx)
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, headState.InnerStateUnsafe(), s.InnerStateUnsafe(), "Head state incorrect")
|
||||
assert.Equal(t, genesisRoot, c.genesisRoot, "Genesis block root incorrect")
|
||||
assert.DeepEqual(t, genesis, c.head.block)
|
||||
}
|
||||
|
||||
func TestChainService_SaveHeadNoDB(t *testing.T) {
|
||||
db, sc := testDB.SetupDB(t)
|
||||
ctx := context.Background()
|
||||
@@ -275,8 +330,9 @@ func TestChainService_SaveHeadNoDB(t *testing.T) {
|
||||
beaconDB: db,
|
||||
stateGen: stategen.New(db, sc),
|
||||
}
|
||||
b := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Slot: 1}}
|
||||
r, err := ssz.HashTreeRoot(b)
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block.Slot = 1
|
||||
r, err := b.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
newState := testutil.NewBeaconState()
|
||||
require.NoError(t, s.stateGen.SaveState(ctx, r, newState))
|
||||
@@ -294,30 +350,45 @@ func TestHasBlock_ForkChoiceAndDB(t *testing.T) {
|
||||
db, _ := testDB.SetupDB(t)
|
||||
s := &Service{
|
||||
forkChoiceStore: protoarray.New(0, 0, [32]byte{}),
|
||||
finalizedCheckpt: ðpb.Checkpoint{},
|
||||
finalizedCheckpt: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
beaconDB: db,
|
||||
}
|
||||
block := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Body: ðpb.BeaconBlockBody{}}}
|
||||
r, err := stateutil.BlockRoot(block.Block)
|
||||
require.NoError(t, err)
|
||||
bs := &pb.BeaconState{FinalizedCheckpoint: ðpb.Checkpoint{}, CurrentJustifiedCheckpoint: ðpb.Checkpoint{}}
|
||||
state, err := beaconstate.InitializeFromProto(bs)
|
||||
block := testutil.NewBeaconBlock()
|
||||
r, err := block.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
state := testutil.NewBeaconState()
|
||||
require.NoError(t, s.insertBlockAndAttestationsToForkChoiceStore(ctx, block.Block, r, state))
|
||||
|
||||
assert.Equal(t, false, s.hasBlock(ctx, [32]byte{}), "Should not have block")
|
||||
assert.Equal(t, true, s.hasBlock(ctx, r), "Should have block")
|
||||
}
|
||||
|
||||
func TestServiceStop_SaveCachedBlocks(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
db, _ := testDB.SetupDB(t)
|
||||
s := &Service{
|
||||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
beaconDB: db,
|
||||
initSyncBlocks: make(map[[32]byte]*ethpb.SignedBeaconBlock),
|
||||
}
|
||||
b := testutil.NewBeaconBlock()
|
||||
r, err := b.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
s.saveInitSyncBlock(r, b)
|
||||
require.NoError(t, s.Stop())
|
||||
require.Equal(t, true, s.beaconDB.HasBlock(ctx, r))
|
||||
}
|
||||
|
||||
func BenchmarkHasBlockDB(b *testing.B) {
|
||||
db, _ := testDB.SetupDB(b)
|
||||
ctx := context.Background()
|
||||
s := &Service{
|
||||
beaconDB: db,
|
||||
}
|
||||
block := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{}}
|
||||
block := testutil.NewBeaconBlock()
|
||||
require.NoError(b, s.beaconDB.SaveBlock(ctx, block))
|
||||
r, err := stateutil.BlockRoot(block.Block)
|
||||
r, err := block.Block.HashTreeRoot()
|
||||
require.NoError(b, err)
|
||||
|
||||
b.ResetTimer()
|
||||
@@ -331,13 +402,13 @@ func BenchmarkHasBlockForkChoiceStore(b *testing.B) {
|
||||
db, _ := testDB.SetupDB(b)
|
||||
s := &Service{
|
||||
forkChoiceStore: protoarray.New(0, 0, [32]byte{}),
|
||||
finalizedCheckpt: ðpb.Checkpoint{},
|
||||
finalizedCheckpt: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
beaconDB: db,
|
||||
}
|
||||
block := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Body: ðpb.BeaconBlockBody{}}}
|
||||
r, err := stateutil.BlockRoot(block.Block)
|
||||
r, err := block.Block.HashTreeRoot()
|
||||
require.NoError(b, err)
|
||||
bs := &pb.BeaconState{FinalizedCheckpoint: ðpb.Checkpoint{}, CurrentJustifiedCheckpoint: ðpb.Checkpoint{}}
|
||||
bs := &pb.BeaconState{FinalizedCheckpoint: ðpb.Checkpoint{Root: make([]byte, 32)}, CurrentJustifiedCheckpoint: ðpb.Checkpoint{Root: make([]byte, 32)}}
|
||||
state, err := beaconstate.InitializeFromProto(bs)
|
||||
require.NoError(b, err)
|
||||
require.NoError(b, s.insertBlockAndAttestationsToForkChoiceStore(ctx, block.Block, r, state))
|
||||
|
||||
@@ -19,8 +19,8 @@ go_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/bytesutil:go_default_library",
|
||||
"//shared/event:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
|
||||
@@ -19,8 +19,8 @@ import (
|
||||
"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/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/event"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/sirupsen/logrus"
|
||||
@@ -152,7 +152,7 @@ func (ms *ChainService) ReceiveBlockInitialSync(ctx context.Context, block *ethp
|
||||
return err
|
||||
}
|
||||
ms.BlocksReceived = append(ms.BlocksReceived, block)
|
||||
signingRoot, err := stateutil.BlockRoot(block.Block)
|
||||
signingRoot, err := block.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -180,7 +180,7 @@ func (ms *ChainService) ReceiveBlockBatch(ctx context.Context, blks []*ethpb.Sig
|
||||
return err
|
||||
}
|
||||
ms.BlocksReceived = append(ms.BlocksReceived, block)
|
||||
signingRoot, err := stateutil.BlockRoot(block.Block)
|
||||
signingRoot, err := block.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -208,7 +208,7 @@ func (ms *ChainService) ReceiveBlock(ctx context.Context, block *ethpb.SignedBea
|
||||
return err
|
||||
}
|
||||
ms.BlocksReceived = append(ms.BlocksReceived, block)
|
||||
signingRoot, err := stateutil.BlockRoot(block.Block)
|
||||
signingRoot, err := block.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -233,8 +233,10 @@ func (ms *ChainService) HeadSlot() uint64 {
|
||||
|
||||
// HeadRoot mocks HeadRoot method in chain service.
|
||||
func (ms *ChainService) HeadRoot(ctx context.Context) ([]byte, error) {
|
||||
return ms.Root, nil
|
||||
|
||||
if len(ms.Root) > 0 {
|
||||
return ms.Root, nil
|
||||
}
|
||||
return make([]byte, 32), nil
|
||||
}
|
||||
|
||||
// HeadBlock mocks HeadBlock method in chain service.
|
||||
@@ -353,3 +355,38 @@ func (ms *ChainService) HeadGenesisValidatorRoot() [32]byte {
|
||||
func (ms *ChainService) VerifyBlkDescendant(ctx context.Context, root [32]byte) error {
|
||||
return ms.VerifyBlkDescendantErr
|
||||
}
|
||||
|
||||
// VerifyLmdFfgConsistency mocks VerifyLmdFfgConsistency and always returns nil.
|
||||
func (ms *ChainService) VerifyLmdFfgConsistency(ctx context.Context, att *ethpb.Attestation) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// AttestationCheckPtInfo mocks AttestationCheckPtInfo and always returns nil.
|
||||
func (ms *ChainService) AttestationCheckPtInfo(ctx context.Context, att *ethpb.Attestation) (*pb.CheckPtInfo, error) {
|
||||
f := ms.State.Fork()
|
||||
g := bytesutil.ToBytes32(ms.State.GenesisValidatorRoot())
|
||||
seed, err := helpers.Seed(ms.State, helpers.SlotToEpoch(att.Data.Slot), params.BeaconConfig().DomainBeaconAttester)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
indices, err := helpers.ActiveValidatorIndices(ms.State, helpers.SlotToEpoch(att.Data.Slot))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
validators := ms.State.ValidatorsReadOnly()
|
||||
pks := make([][]byte, len(validators))
|
||||
for i := 0; i < len(pks); i++ {
|
||||
pk := validators[i].PublicKey()
|
||||
pks[i] = pk[:]
|
||||
}
|
||||
|
||||
info := &pb.CheckPtInfo{
|
||||
Fork: f,
|
||||
GenesisRoot: g[:],
|
||||
Seed: seed[:],
|
||||
ActiveIndices: indices,
|
||||
PubKeys: pks,
|
||||
}
|
||||
|
||||
return info, nil
|
||||
}
|
||||
|
||||
60
beacon-chain/blockchain/weak_subjectivity_checks.go
Normal file
60
beacon-chain/blockchain/weak_subjectivity_checks.go
Normal file
@@ -0,0 +1,60 @@
|
||||
package blockchain
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/db/filters"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
// VerifyWeakSubjectivityRoot verifies the weak subjectivity root in the service struct.
|
||||
// Reference design: https://github.com/ethereum/eth2.0-specs/blob/master/specs/phase0/weak-subjectivity.md#weak-subjectivity-sync-procedure
|
||||
func (s *Service) VerifyWeakSubjectivityRoot(ctx context.Context) error {
|
||||
// TODO(7342): Remove the following to fully use weak subjectivity in production.
|
||||
if len(s.wsRoot) == 0 || s.wsEpoch == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Do nothing if the weak subjectivity has previously been verified,
|
||||
// or weak subjectivity epoch is higher than last finalized epoch.
|
||||
if s.wsVerified {
|
||||
return nil
|
||||
}
|
||||
if s.wsEpoch > s.finalizedCheckpt.Epoch {
|
||||
return nil
|
||||
}
|
||||
|
||||
r := bytesutil.ToBytes32(s.wsRoot)
|
||||
log.Infof("Performing weak subjectivity check for root %#x in epoch %d", r, s.wsEpoch)
|
||||
// Save initial sync cached blocks to DB.
|
||||
if err := s.beaconDB.SaveBlocks(ctx, s.getInitSyncBlocks()); err != nil {
|
||||
return err
|
||||
}
|
||||
// A node should have the weak subjectivity block in the DB.
|
||||
if !s.beaconDB.HasBlock(ctx, r) {
|
||||
return fmt.Errorf("node does not have root in DB: %#x", r)
|
||||
}
|
||||
|
||||
startSlot, err := helpers.StartSlot(s.wsEpoch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// A node should have the weak subjectivity block corresponds to the correct epoch in the DB.
|
||||
filter := filters.NewFilter().SetStartSlot(startSlot).SetEndSlot(startSlot + params.BeaconConfig().SlotsPerEpoch)
|
||||
roots, err := s.beaconDB.BlockRoots(ctx, filter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, root := range roots {
|
||||
if r == root {
|
||||
log.Info("Weak subjectivity check has passed")
|
||||
s.wsVerified = true
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Errorf("node does not have root in db corresponding to epoch: %#x %d", r, s.wsEpoch)
|
||||
}
|
||||
85
beacon-chain/blockchain/weak_subjectivity_checks_test.go
Normal file
85
beacon-chain/blockchain/weak_subjectivity_checks_test.go
Normal file
@@ -0,0 +1,85 @@
|
||||
package blockchain
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
testDB "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
func TestService_VerifyWeakSubjectivityRoot(t *testing.T) {
|
||||
db, _ := testDB.SetupDB(t)
|
||||
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block.Slot = 32
|
||||
require.NoError(t, db.SaveBlock(context.Background(), b))
|
||||
r, err := b.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
tests := []struct {
|
||||
wsVerified bool
|
||||
wantErr bool
|
||||
wsRoot [32]byte
|
||||
wsEpoch uint64
|
||||
finalizedEpoch uint64
|
||||
errString string
|
||||
name string
|
||||
}{
|
||||
{
|
||||
name: "nil root and epoch",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "already verified",
|
||||
wsEpoch: 2,
|
||||
finalizedEpoch: 2,
|
||||
wsVerified: true,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "not yet to verify, ws epoch higher than finalized epoch",
|
||||
wsEpoch: 2,
|
||||
finalizedEpoch: 1,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "can't find the block in DB",
|
||||
wsEpoch: 1,
|
||||
wsRoot: [32]byte{'a'},
|
||||
finalizedEpoch: 3,
|
||||
wantErr: true,
|
||||
errString: "node does not have root in DB",
|
||||
},
|
||||
{
|
||||
name: "can't find the block corresponds to ws epoch in DB",
|
||||
wsEpoch: 2,
|
||||
wsRoot: r, // Root belongs in epoch 1.
|
||||
finalizedEpoch: 3,
|
||||
wantErr: true,
|
||||
errString: "node does not have root in db corresponding to epoch",
|
||||
},
|
||||
{
|
||||
name: "can verify and pass",
|
||||
wsEpoch: 1,
|
||||
wsRoot: r,
|
||||
finalizedEpoch: 3,
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
s := &Service{
|
||||
beaconDB: db,
|
||||
wsRoot: tt.wsRoot[:],
|
||||
wsEpoch: tt.wsEpoch,
|
||||
wsVerified: tt.wsVerified,
|
||||
finalizedCheckpt: ðpb.Checkpoint{Epoch: tt.finalizedEpoch},
|
||||
}
|
||||
if err := s.VerifyWeakSubjectivityRoot(context.Background()); (err != nil) != tt.wantErr {
|
||||
require.ErrorContains(t, tt.errString, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
17
beacon-chain/cache/BUILD.bazel
vendored
17
beacon-chain/cache/BUILD.bazel
vendored
@@ -1,19 +1,31 @@
|
||||
load("@prysm//tools/go:def.bzl", "go_library")
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_test")
|
||||
|
||||
# gazelle:ignore committee_disabled.go
|
||||
# gazelle:ignore proposer_indices_disabled.go
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"attestation_data.go",
|
||||
"checkpoint_state.go",
|
||||
"committee.go",
|
||||
"committees.go",
|
||||
"common.go",
|
||||
"doc.go",
|
||||
"hot_state_cache.go",
|
||||
"skip_slot_cache.go",
|
||||
"state_summary.go",
|
||||
"subnet_ids.go",
|
||||
],
|
||||
"proposer_indices_type.go",
|
||||
] + select({
|
||||
"//fuzz:fuzzing_enabled": [
|
||||
"committee_disabled.go",
|
||||
"proposer_indices_disabled.go"
|
||||
],
|
||||
"//conditions:default": [
|
||||
"committee.go",
|
||||
"proposer_indices.go",
|
||||
],
|
||||
}),
|
||||
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/cache",
|
||||
visibility = [
|
||||
"//beacon-chain:__subpackages__",
|
||||
@@ -49,6 +61,7 @@ go_test(
|
||||
"hot_state_cache_test.go",
|
||||
"skip_slot_cache_test.go",
|
||||
"subnet_ids_test.go",
|
||||
"proposer_indices_test.go"
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
|
||||
2
beacon-chain/cache/attestation_data_test.go
vendored
2
beacon-chain/cache/attestation_data_test.go
vendored
@@ -26,7 +26,7 @@ func TestAttestationCache_RoundTrip(t *testing.T) {
|
||||
assert.NoError(t, c.MarkInProgress(req))
|
||||
|
||||
res := ðpb.AttestationData{
|
||||
Target: ðpb.Checkpoint{Epoch: 5},
|
||||
Target: ðpb.Checkpoint{Epoch: 5, Root: make([]byte, 32)},
|
||||
}
|
||||
|
||||
assert.NoError(t, c.Put(ctx, req, res))
|
||||
|
||||
2
beacon-chain/cache/checkpoint_state_test.go
vendored
2
beacon-chain/cache/checkpoint_state_test.go
vendored
@@ -61,7 +61,7 @@ func TestCheckpointStateCache_MaxSize(t *testing.T) {
|
||||
|
||||
for i := uint64(0); i < uint64(maxCheckpointStateSize+100); i++ {
|
||||
require.NoError(t, st.SetSlot(i))
|
||||
require.NoError(t, c.AddCheckpointState(ðpb.Checkpoint{Epoch: i}, st))
|
||||
require.NoError(t, c.AddCheckpointState(ðpb.Checkpoint{Epoch: i, Root: make([]byte, 32)}, st))
|
||||
}
|
||||
|
||||
assert.Equal(t, maxCheckpointStateSize, len(c.cache.Keys()))
|
||||
|
||||
70
beacon-chain/cache/committee.go
vendored
70
beacon-chain/cache/committee.go
vendored
@@ -1,3 +1,5 @@
|
||||
// +build !libfuzzer
|
||||
|
||||
package cache
|
||||
|
||||
import (
|
||||
@@ -12,10 +14,6 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrNotCommittee will be returned when a cache object is not a pointer to
|
||||
// a Committee struct.
|
||||
ErrNotCommittee = errors.New("object is not a committee struct")
|
||||
|
||||
// maxCommitteesCacheSize defines the max number of shuffled committees on per randao basis can cache.
|
||||
// Due to reorgs and long finality, it's good to keep the old cache around for quickly switch over.
|
||||
maxCommitteesCacheSize = uint64(32)
|
||||
@@ -32,15 +30,6 @@ var (
|
||||
})
|
||||
)
|
||||
|
||||
// Committees defines the shuffled committees seed.
|
||||
type Committees struct {
|
||||
CommitteeCount uint64
|
||||
Seed [32]byte
|
||||
ShuffledIndices []uint64
|
||||
SortedIndices []uint64
|
||||
ProposerIndices []uint64
|
||||
}
|
||||
|
||||
// CommitteeCache is a struct with 1 queue for looking up shuffled indices list by seed.
|
||||
type CommitteeCache struct {
|
||||
CommitteeCache *cache.FIFO
|
||||
@@ -115,35 +104,6 @@ func (c *CommitteeCache) AddCommitteeShuffledList(committees *Committees) error
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddProposerIndicesList updates the committee shuffled list with proposer indices.
|
||||
func (c *CommitteeCache) AddProposerIndicesList(seed [32]byte, indices []uint64) error {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
|
||||
obj, exists, err := c.CommitteeCache.GetByKey(key(seed))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !exists {
|
||||
committees := &Committees{ProposerIndices: indices}
|
||||
if err := c.CommitteeCache.Add(committees); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
committees, ok := obj.(*Committees)
|
||||
if !ok {
|
||||
return ErrNotCommittee
|
||||
}
|
||||
committees.ProposerIndices = indices
|
||||
if err := c.CommitteeCache.Add(committees); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
trim(c.CommitteeCache, maxCommitteesCacheSize)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ActiveIndices returns the active indices of a given seed stored in cache.
|
||||
func (c *CommitteeCache) ActiveIndices(seed [32]byte) ([]uint64, error) {
|
||||
c.lock.RLock()
|
||||
@@ -192,28 +152,10 @@ func (c *CommitteeCache) ActiveIndicesCount(seed [32]byte) (int, error) {
|
||||
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()
|
||||
defer c.lock.RUnlock()
|
||||
obj, exists, err := c.CommitteeCache.GetByKey(key(seed))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if exists {
|
||||
CommitteeCacheHit.Inc()
|
||||
} else {
|
||||
CommitteeCacheMiss.Inc()
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
item, ok := obj.(*Committees)
|
||||
if !ok {
|
||||
return nil, ErrNotCommittee
|
||||
}
|
||||
|
||||
return item.ProposerIndices, nil
|
||||
// HasEntry returns true if the committee cache has a value.
|
||||
func (c *CommitteeCache) HasEntry(seed string) bool {
|
||||
_, ok, err := c.CommitteeCache.GetByKey(seed)
|
||||
return err == nil && ok
|
||||
}
|
||||
|
||||
func startEndIndices(c *Committees, index uint64) (uint64, uint64) {
|
||||
|
||||
50
beacon-chain/cache/committee_disabled.go
vendored
Normal file
50
beacon-chain/cache/committee_disabled.go
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
// +build libfuzzer
|
||||
|
||||
// This file is used in fuzzer builds to bypass global committee caches.
|
||||
package cache
|
||||
|
||||
// FakeCommitteeCache is a struct with 1 queue for looking up shuffled indices list by seed.
|
||||
type FakeCommitteeCache struct {
|
||||
}
|
||||
|
||||
// NewCommitteesCache creates a new committee cache for storing/accessing shuffled indices of a committee.
|
||||
func NewCommitteesCache() *FakeCommitteeCache {
|
||||
return &FakeCommitteeCache{}
|
||||
}
|
||||
|
||||
// Committee fetches the shuffled indices by slot and committee index. Every list of indices
|
||||
// represent one committee. Returns true if the list exists with slot and committee index. Otherwise returns false, nil.
|
||||
func (c *FakeCommitteeCache) Committee(slot uint64, seed [32]byte, index uint64) ([]uint64, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// AddCommitteeShuffledList adds Committee shuffled list object to the cache. T
|
||||
// his method also trims the least recently list if the cache size has ready the max cache size limit.
|
||||
func (c *FakeCommitteeCache) AddCommitteeShuffledList(committees *Committees) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddProposerIndicesList updates the committee shuffled list with proposer indices.
|
||||
func (c *FakeCommitteeCache) AddProposerIndicesList(seed [32]byte, indices []uint64) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ActiveIndices returns the active indices of a given seed stored in cache.
|
||||
func (c *FakeCommitteeCache) ActiveIndices(seed [32]byte) ([]uint64, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// ActiveIndicesCount returns the active indices count of a given seed stored in cache.
|
||||
func (c *FakeCommitteeCache) ActiveIndicesCount(seed [32]byte) (int, error) {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// ProposerIndices returns the proposer indices of a given seed.
|
||||
func (c *FakeCommitteeCache) ProposerIndices(seed [32]byte) ([]uint64, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// HasEntry returns true if the committee cache has a value.
|
||||
func (c *FakeCommitteeCache) HasEntry(string) bool {
|
||||
return false
|
||||
}
|
||||
32
beacon-chain/cache/committee_test.go
vendored
32
beacon-chain/cache/committee_test.go
vendored
@@ -87,37 +87,6 @@ func TestCommitteeCache_ActiveCount(t *testing.T) {
|
||||
assert.Equal(t, len(item.SortedIndices), count)
|
||||
}
|
||||
|
||||
func TestCommitteeCache_AddProposerIndicesList(t *testing.T) {
|
||||
cache := NewCommitteesCache()
|
||||
|
||||
seed := [32]byte{'A'}
|
||||
indices := []uint64{1, 2, 3, 4, 5}
|
||||
indices, err := cache.ProposerIndices(seed)
|
||||
require.NoError(t, err)
|
||||
if indices != nil {
|
||||
t.Error("Expected committee count not to exist in empty cache")
|
||||
}
|
||||
require.NoError(t, cache.AddProposerIndicesList(seed, indices))
|
||||
|
||||
received, err := cache.ProposerIndices(seed)
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, received, indices)
|
||||
|
||||
item := &Committees{Seed: [32]byte{'B'}, SortedIndices: []uint64{1, 2, 3, 4, 5, 6}}
|
||||
require.NoError(t, cache.AddCommitteeShuffledList(item))
|
||||
|
||||
indices, err = cache.ProposerIndices(item.Seed)
|
||||
require.NoError(t, err)
|
||||
if indices != nil {
|
||||
t.Error("Expected committee count not to exist in empty cache")
|
||||
}
|
||||
require.NoError(t, cache.AddProposerIndicesList(item.Seed, indices))
|
||||
|
||||
received, err = cache.ProposerIndices(item.Seed)
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, received, indices)
|
||||
}
|
||||
|
||||
func TestCommitteeCache_CanRotate(t *testing.T) {
|
||||
cache := NewCommitteesCache()
|
||||
|
||||
@@ -152,7 +121,6 @@ func TestCommitteeCacheOutOfRange(t *testing.T) {
|
||||
Seed: seed,
|
||||
ShuffledIndices: []uint64{0},
|
||||
SortedIndices: []uint64{},
|
||||
ProposerIndices: []uint64{},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
|
||||
15
beacon-chain/cache/committees.go
vendored
Normal file
15
beacon-chain/cache/committees.go
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
package cache
|
||||
|
||||
import "errors"
|
||||
|
||||
// ErrNotCommittee will be returned when a cache object is not a pointer to
|
||||
// a Committee struct.
|
||||
var ErrNotCommittee = errors.New("object is not a committee struct")
|
||||
|
||||
// Committees defines the shuffled committees seed.
|
||||
type Committees struct {
|
||||
CommitteeCount uint64
|
||||
Seed [32]byte
|
||||
ShuffledIndices []uint64
|
||||
SortedIndices []uint64
|
||||
}
|
||||
2
beacon-chain/cache/depositcache/BUILD.bazel
vendored
2
beacon-chain/cache/depositcache/BUILD.bazel
vendored
@@ -18,7 +18,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",
|
||||
],
|
||||
@@ -40,7 +39,6 @@ go_test(
|
||||
"//shared/trieutil:go_default_library",
|
||||
"@com_github_gogo_protobuf//proto:go_default_library",
|
||||
"@com_github_prysmaticlabs_ethereumapis//eth/v1alpha1:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_ssz//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//hooks/test:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -15,7 +15,6 @@ import (
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/go-ssz"
|
||||
dbpb "github.com/prysmaticlabs/prysm/proto/beacon/db"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
@@ -59,8 +58,8 @@ type DepositCache struct {
|
||||
chainStartPubkeys map[string]bool
|
||||
}
|
||||
|
||||
// NewDepositCache instantiates a new deposit cache
|
||||
func NewDepositCache() (*DepositCache, error) {
|
||||
// New instantiates a new deposit cache
|
||||
func New() (*DepositCache, error) {
|
||||
finalizedDepositsTrie, err := trieutil.NewTrie(int(params.BeaconConfig().DepositContractTreeDepth))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -128,7 +127,7 @@ func (dc *DepositCache) InsertFinalizedDeposits(ctx context.Context, eth1Deposit
|
||||
if d.Index > eth1DepositIndex {
|
||||
break
|
||||
}
|
||||
depHash, err := ssz.HashTreeRoot(d.Deposit.Data)
|
||||
depHash, err := d.Deposit.Data.HashTreeRoot()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Could not hash deposit data. Finalized deposit cache not updated.")
|
||||
return
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"testing"
|
||||
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/go-ssz"
|
||||
dbpb "github.com/prysmaticlabs/prysm/proto/beacon/db"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
@@ -20,11 +19,11 @@ import (
|
||||
|
||||
const nilDepositErr = "Ignoring nil deposit insertion"
|
||||
|
||||
var _ = DepositFetcher(&DepositCache{})
|
||||
var _ DepositFetcher = (*DepositCache)(nil)
|
||||
|
||||
func TestInsertDeposit_LogsOnNilDepositInsertion(t *testing.T) {
|
||||
hook := logTest.NewGlobal()
|
||||
dc, err := NewDepositCache()
|
||||
dc, err := New()
|
||||
require.NoError(t, err)
|
||||
|
||||
dc.InsertDeposit(context.Background(), nil, 1, 0, [32]byte{})
|
||||
@@ -34,7 +33,7 @@ func TestInsertDeposit_LogsOnNilDepositInsertion(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestInsertDeposit_MaintainsSortedOrderByIndex(t *testing.T) {
|
||||
dc, err := NewDepositCache()
|
||||
dc, err := New()
|
||||
require.NoError(t, err)
|
||||
|
||||
insertions := []struct {
|
||||
@@ -76,7 +75,7 @@ func TestInsertDeposit_MaintainsSortedOrderByIndex(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestAllDeposits_ReturnsAllDeposits(t *testing.T) {
|
||||
dc, err := NewDepositCache()
|
||||
dc, err := New()
|
||||
require.NoError(t, err)
|
||||
|
||||
deposits := []*dbpb.DepositContainer{
|
||||
@@ -116,7 +115,7 @@ func TestAllDeposits_ReturnsAllDeposits(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestAllDeposits_FiltersDepositUpToAndIncludingBlockNumber(t *testing.T) {
|
||||
dc, err := NewDepositCache()
|
||||
dc, err := New()
|
||||
require.NoError(t, err)
|
||||
|
||||
deposits := []*dbpb.DepositContainer{
|
||||
@@ -156,38 +155,80 @@ func TestAllDeposits_FiltersDepositUpToAndIncludingBlockNumber(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDepositsNumberAndRootAtHeight_ReturnsAppropriateCountAndRoot(t *testing.T) {
|
||||
dc, err := NewDepositCache()
|
||||
dc, err := New()
|
||||
require.NoError(t, err)
|
||||
|
||||
dc.deposits = []*dbpb.DepositContainer{
|
||||
{
|
||||
Eth1BlockHeight: 10,
|
||||
Deposit: ðpb.Deposit{},
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: make([]byte, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Eth1BlockHeight: 10,
|
||||
Deposit: ðpb.Deposit{},
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: make([]byte, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Eth1BlockHeight: 10,
|
||||
Deposit: ðpb.Deposit{},
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: make([]byte, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Eth1BlockHeight: 10,
|
||||
Deposit: ðpb.Deposit{},
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: make([]byte, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Eth1BlockHeight: 11,
|
||||
Deposit: ðpb.Deposit{},
|
||||
DepositRoot: []byte("root"),
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: make([]byte, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
DepositRoot: bytesutil.PadTo([]byte("root"), 32),
|
||||
},
|
||||
{
|
||||
Eth1BlockHeight: 12,
|
||||
Deposit: ðpb.Deposit{},
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: make([]byte, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Eth1BlockHeight: 12,
|
||||
Deposit: ðpb.Deposit{},
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: make([]byte, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -197,19 +238,31 @@ func TestDepositsNumberAndRootAtHeight_ReturnsAppropriateCountAndRoot(t *testing
|
||||
}
|
||||
|
||||
func TestDepositsNumberAndRootAtHeight_ReturnsEmptyTrieIfBlockHeightLessThanOldestDeposit(t *testing.T) {
|
||||
dc, err := NewDepositCache()
|
||||
dc, err := New()
|
||||
require.NoError(t, err)
|
||||
|
||||
dc.deposits = []*dbpb.DepositContainer{
|
||||
{
|
||||
Eth1BlockHeight: 10,
|
||||
Deposit: ðpb.Deposit{},
|
||||
DepositRoot: []byte("root"),
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: make([]byte, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
DepositRoot: bytesutil.PadTo([]byte("root"), 32),
|
||||
},
|
||||
{
|
||||
Eth1BlockHeight: 11,
|
||||
Deposit: ðpb.Deposit{},
|
||||
DepositRoot: []byte("root"),
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: make([]byte, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
DepositRoot: bytesutil.PadTo([]byte("root"), 32),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -219,7 +272,7 @@ func TestDepositsNumberAndRootAtHeight_ReturnsEmptyTrieIfBlockHeightLessThanOlde
|
||||
}
|
||||
|
||||
func TestDepositByPubkey_ReturnsFirstMatchingDeposit(t *testing.T) {
|
||||
dc, err := NewDepositCache()
|
||||
dc, err := New()
|
||||
require.NoError(t, err)
|
||||
|
||||
dc.deposits = []*dbpb.DepositContainer{
|
||||
@@ -227,7 +280,9 @@ func TestDepositByPubkey_ReturnsFirstMatchingDeposit(t *testing.T) {
|
||||
Eth1BlockHeight: 9,
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: []byte("pk0"),
|
||||
PublicKey: bytesutil.PadTo([]byte("pk0"), 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -235,7 +290,9 @@ func TestDepositByPubkey_ReturnsFirstMatchingDeposit(t *testing.T) {
|
||||
Eth1BlockHeight: 10,
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: []byte("pk1"),
|
||||
PublicKey: bytesutil.PadTo([]byte("pk1"), 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -243,7 +300,9 @@ func TestDepositByPubkey_ReturnsFirstMatchingDeposit(t *testing.T) {
|
||||
Eth1BlockHeight: 11,
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: []byte("pk1"),
|
||||
PublicKey: bytesutil.PadTo([]byte("pk1"), 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -251,15 +310,18 @@ func TestDepositByPubkey_ReturnsFirstMatchingDeposit(t *testing.T) {
|
||||
Eth1BlockHeight: 12,
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: []byte("pk2"),
|
||||
PublicKey: bytesutil.PadTo([]byte("pk2"), 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
dep, blkNum := dc.DepositByPubkey(context.Background(), []byte("pk1"))
|
||||
pk1 := bytesutil.PadTo([]byte("pk1"), 48)
|
||||
dep, blkNum := dc.DepositByPubkey(context.Background(), pk1)
|
||||
|
||||
if !bytes.Equal(dep.Data.PublicKey, []byte("pk1")) {
|
||||
if dep == nil || !bytes.Equal(dep.Data.PublicKey, pk1) {
|
||||
t.Error("Returned wrong deposit")
|
||||
}
|
||||
assert.Equal(t, 0, blkNum.Cmp(big.NewInt(10)),
|
||||
@@ -267,14 +329,16 @@ func TestDepositByPubkey_ReturnsFirstMatchingDeposit(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFinalizedDeposits_DepositsCachedCorrectly(t *testing.T) {
|
||||
dc, err := NewDepositCache()
|
||||
dc, err := New()
|
||||
require.NoError(t, err)
|
||||
|
||||
finalizedDeposits := []*dbpb.DepositContainer{
|
||||
{
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: []byte{0},
|
||||
PublicKey: bytesutil.PadTo([]byte{0}, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
Index: 0,
|
||||
@@ -282,7 +346,9 @@ func TestFinalizedDeposits_DepositsCachedCorrectly(t *testing.T) {
|
||||
{
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: []byte{1},
|
||||
PublicKey: bytesutil.PadTo([]byte{1}, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
Index: 1,
|
||||
@@ -290,7 +356,9 @@ func TestFinalizedDeposits_DepositsCachedCorrectly(t *testing.T) {
|
||||
{
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: []byte{2},
|
||||
PublicKey: bytesutil.PadTo([]byte{2}, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
Index: 2,
|
||||
@@ -299,7 +367,9 @@ func TestFinalizedDeposits_DepositsCachedCorrectly(t *testing.T) {
|
||||
dc.deposits = append(finalizedDeposits, &dbpb.DepositContainer{
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: []byte{3},
|
||||
PublicKey: bytesutil.PadTo([]byte{3}, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
Index: 3,
|
||||
@@ -313,7 +383,7 @@ func TestFinalizedDeposits_DepositsCachedCorrectly(t *testing.T) {
|
||||
|
||||
var deps [][]byte
|
||||
for _, d := range finalizedDeposits {
|
||||
hash, err := ssz.HashTreeRoot(d.Deposit.Data)
|
||||
hash, err := d.Deposit.Data.HashTreeRoot()
|
||||
require.NoError(t, err, "Could not hash deposit data")
|
||||
deps = append(deps, hash[:])
|
||||
}
|
||||
@@ -323,14 +393,16 @@ func TestFinalizedDeposits_DepositsCachedCorrectly(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFinalizedDeposits_UtilizesPreviouslyCachedDeposits(t *testing.T) {
|
||||
dc, err := NewDepositCache()
|
||||
dc, err := New()
|
||||
require.NoError(t, err)
|
||||
|
||||
oldFinalizedDeposits := []*dbpb.DepositContainer{
|
||||
{
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: []byte{0},
|
||||
PublicKey: bytesutil.PadTo([]byte{0}, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
Index: 0,
|
||||
@@ -338,7 +410,9 @@ func TestFinalizedDeposits_UtilizesPreviouslyCachedDeposits(t *testing.T) {
|
||||
{
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: []byte{1},
|
||||
PublicKey: bytesutil.PadTo([]byte{1}, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
Index: 1,
|
||||
@@ -347,7 +421,9 @@ func TestFinalizedDeposits_UtilizesPreviouslyCachedDeposits(t *testing.T) {
|
||||
newFinalizedDeposit := dbpb.DepositContainer{
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: []byte{2},
|
||||
PublicKey: bytesutil.PadTo([]byte{2}, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
Index: 2,
|
||||
@@ -365,7 +441,7 @@ func TestFinalizedDeposits_UtilizesPreviouslyCachedDeposits(t *testing.T) {
|
||||
|
||||
var deps [][]byte
|
||||
for _, d := range append(oldFinalizedDeposits, &newFinalizedDeposit) {
|
||||
hash, err := ssz.HashTreeRoot(d.Deposit.Data)
|
||||
hash, err := d.Deposit.Data.HashTreeRoot()
|
||||
require.NoError(t, err, "Could not hash deposit data")
|
||||
deps = append(deps, hash[:])
|
||||
}
|
||||
@@ -375,7 +451,7 @@ func TestFinalizedDeposits_UtilizesPreviouslyCachedDeposits(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFinalizedDeposits_InitializedCorrectly(t *testing.T) {
|
||||
dc, err := NewDepositCache()
|
||||
dc, err := New()
|
||||
require.NoError(t, err)
|
||||
|
||||
finalizedDeposits := dc.finalizedDeposits
|
||||
@@ -385,7 +461,7 @@ func TestFinalizedDeposits_InitializedCorrectly(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestNonFinalizedDeposits_ReturnsAllNonFinalizedDeposits(t *testing.T) {
|
||||
dc, err := NewDepositCache()
|
||||
dc, err := New()
|
||||
require.NoError(t, err)
|
||||
|
||||
finalizedDeposits := []*dbpb.DepositContainer{
|
||||
@@ -393,7 +469,9 @@ func TestNonFinalizedDeposits_ReturnsAllNonFinalizedDeposits(t *testing.T) {
|
||||
Eth1BlockHeight: 10,
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: []byte{0},
|
||||
PublicKey: bytesutil.PadTo([]byte{0}, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
Index: 0,
|
||||
@@ -402,7 +480,9 @@ func TestNonFinalizedDeposits_ReturnsAllNonFinalizedDeposits(t *testing.T) {
|
||||
Eth1BlockHeight: 10,
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: []byte{1},
|
||||
PublicKey: bytesutil.PadTo([]byte{1}, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
Index: 1,
|
||||
@@ -413,7 +493,9 @@ func TestNonFinalizedDeposits_ReturnsAllNonFinalizedDeposits(t *testing.T) {
|
||||
Eth1BlockHeight: 10,
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: []byte{2},
|
||||
PublicKey: bytesutil.PadTo([]byte{2}, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
Index: 2,
|
||||
@@ -422,7 +504,9 @@ func TestNonFinalizedDeposits_ReturnsAllNonFinalizedDeposits(t *testing.T) {
|
||||
Eth1BlockHeight: 11,
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: []byte{3},
|
||||
PublicKey: bytesutil.PadTo([]byte{3}, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
Index: 3,
|
||||
@@ -434,7 +518,7 @@ func TestNonFinalizedDeposits_ReturnsAllNonFinalizedDeposits(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestNonFinalizedDeposits_ReturnsNonFinalizedDepositsUpToBlockNumber(t *testing.T) {
|
||||
dc, err := NewDepositCache()
|
||||
dc, err := New()
|
||||
require.NoError(t, err)
|
||||
|
||||
finalizedDeposits := []*dbpb.DepositContainer{
|
||||
@@ -442,7 +526,9 @@ func TestNonFinalizedDeposits_ReturnsNonFinalizedDepositsUpToBlockNumber(t *test
|
||||
Eth1BlockHeight: 10,
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: []byte{0},
|
||||
PublicKey: bytesutil.PadTo([]byte{0}, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
Index: 0,
|
||||
@@ -451,7 +537,9 @@ func TestNonFinalizedDeposits_ReturnsNonFinalizedDepositsUpToBlockNumber(t *test
|
||||
Eth1BlockHeight: 10,
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: []byte{1},
|
||||
PublicKey: bytesutil.PadTo([]byte{1}, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
Index: 1,
|
||||
@@ -462,7 +550,9 @@ func TestNonFinalizedDeposits_ReturnsNonFinalizedDepositsUpToBlockNumber(t *test
|
||||
Eth1BlockHeight: 10,
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: []byte{2},
|
||||
PublicKey: bytesutil.PadTo([]byte{2}, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
Index: 2,
|
||||
@@ -471,7 +561,9 @@ func TestNonFinalizedDeposits_ReturnsNonFinalizedDepositsUpToBlockNumber(t *test
|
||||
Eth1BlockHeight: 11,
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: []byte{3},
|
||||
PublicKey: bytesutil.PadTo([]byte{3}, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
Index: 3,
|
||||
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
)
|
||||
|
||||
var _ = PendingDepositsFetcher(&DepositCache{})
|
||||
var _ PendingDepositsFetcher = (*DepositCache)(nil)
|
||||
|
||||
func TestInsertPendingDeposit_OK(t *testing.T) {
|
||||
dc := DepositCache{}
|
||||
@@ -29,14 +29,28 @@ func TestInsertPendingDeposit_ignoresNilDeposit(t *testing.T) {
|
||||
assert.Equal(t, 0, len(dc.pendingDeposits))
|
||||
}
|
||||
|
||||
func makeDepositProof() [][]byte {
|
||||
proof := make([][]byte, int(params.BeaconConfig().DepositContractTreeDepth)+1)
|
||||
for i := range proof {
|
||||
proof[i] = make([]byte, 32)
|
||||
}
|
||||
return proof
|
||||
}
|
||||
|
||||
func TestRemovePendingDeposit_OK(t *testing.T) {
|
||||
db := DepositCache{}
|
||||
proof1 := make([][]byte, int(params.BeaconConfig().DepositContractTreeDepth)+1)
|
||||
proof1 := makeDepositProof()
|
||||
proof1[0] = bytesutil.PadTo([]byte{'A'}, 32)
|
||||
proof2 := make([][]byte, int(params.BeaconConfig().DepositContractTreeDepth)+1)
|
||||
proof2 := makeDepositProof()
|
||||
proof2[0] = bytesutil.PadTo([]byte{'A'}, 32)
|
||||
depToRemove := ðpb.Deposit{Proof: proof1}
|
||||
otherDep := ðpb.Deposit{Proof: proof2}
|
||||
data := ðpb.Deposit_Data{
|
||||
PublicKey: make([]byte, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Amount: 0,
|
||||
Signature: make([]byte, 96),
|
||||
}
|
||||
depToRemove := ðpb.Deposit{Proof: proof1, Data: data}
|
||||
otherDep := ðpb.Deposit{Proof: proof2, Data: data}
|
||||
db.pendingDeposits = []*dbpb.DepositContainer{
|
||||
{Deposit: depToRemove, Index: 1},
|
||||
{Deposit: otherDep, Index: 5},
|
||||
@@ -57,9 +71,15 @@ func TestRemovePendingDeposit_IgnoresNilDeposit(t *testing.T) {
|
||||
|
||||
func TestPendingDeposit_RoundTrip(t *testing.T) {
|
||||
dc := DepositCache{}
|
||||
proof := make([][]byte, int(params.BeaconConfig().DepositContractTreeDepth)+1)
|
||||
proof := makeDepositProof()
|
||||
proof[0] = bytesutil.PadTo([]byte{'A'}, 32)
|
||||
dep := ðpb.Deposit{Proof: proof}
|
||||
data := ðpb.Deposit_Data{
|
||||
PublicKey: make([]byte, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Amount: 0,
|
||||
Signature: make([]byte, 96),
|
||||
}
|
||||
dep := ðpb.Deposit{Proof: proof, Data: data}
|
||||
dc.InsertPendingDeposit(context.Background(), dep, 111, 100, [32]byte{})
|
||||
dc.RemovePendingDeposit(context.Background(), dep)
|
||||
assert.Equal(t, 0, len(dc.pendingDeposits), "Failed to insert & delete a pending deposit")
|
||||
|
||||
5
beacon-chain/cache/feature_flag_test.go
vendored
5
beacon-chain/cache/feature_flag_test.go
vendored
@@ -10,5 +10,8 @@ import (
|
||||
func TestMain(m *testing.M) {
|
||||
resetCfg := featureconfig.InitWithReset(&featureconfig.Flags{EnableEth1DataVoteCache: true})
|
||||
defer resetCfg()
|
||||
os.Exit(m.Run())
|
||||
code := m.Run()
|
||||
// os.Exit will prevent defer from being called
|
||||
resetCfg()
|
||||
os.Exit(code)
|
||||
}
|
||||
|
||||
88
beacon-chain/cache/proposer_indices.go
vendored
Normal file
88
beacon-chain/cache/proposer_indices.go
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
// +build !libfuzzer
|
||||
|
||||
package cache
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
var (
|
||||
// maxProposerIndicesCacheSize defines the max number of proposer indices on per block root basis can cache.
|
||||
// Due to reorgs and long finality, it's good to keep the old cache around for quickly switch over.
|
||||
maxProposerIndicesCacheSize = uint64(8)
|
||||
|
||||
// ProposerIndicesCacheMiss tracks the number of proposerIndices requests that aren't present in the cache.
|
||||
ProposerIndicesCacheMiss = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "proposer_indices_cache_miss",
|
||||
Help: "The number of proposer indices requests that aren't present in the cache.",
|
||||
})
|
||||
// ProposerIndicesCacheHit tracks the number of proposerIndices requests that are in the cache.
|
||||
ProposerIndicesCacheHit = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "proposer_indices_cache_hit",
|
||||
Help: "The number of proposer indices requests that are present in the cache.",
|
||||
})
|
||||
)
|
||||
|
||||
// ProposerIndicesCache is a struct with 1 queue for looking up proposer indices by root.
|
||||
type ProposerIndicesCache struct {
|
||||
ProposerIndicesCache *cache.FIFO
|
||||
lock sync.RWMutex
|
||||
}
|
||||
|
||||
// proposerIndicesKeyFn takes the block root as the key to retrieve proposer indices in a given epoch.
|
||||
func proposerIndicesKeyFn(obj interface{}) (string, error) {
|
||||
info, ok := obj.(*ProposerIndices)
|
||||
if !ok {
|
||||
return "", ErrNotProposerIndices
|
||||
}
|
||||
|
||||
return key(info.BlockRoot), nil
|
||||
}
|
||||
|
||||
// NewProposerIndicesCache creates a new proposer indices cache for storing/accessing proposer index assignments of an epoch.
|
||||
func NewProposerIndicesCache() *ProposerIndicesCache {
|
||||
return &ProposerIndicesCache{
|
||||
ProposerIndicesCache: cache.NewFIFO(proposerIndicesKeyFn),
|
||||
}
|
||||
}
|
||||
|
||||
// AddProposerIndices adds ProposerIndices object to the cache.
|
||||
// This method also trims the least recently list if the cache size has ready the max cache size limit.
|
||||
func (c *ProposerIndicesCache) AddProposerIndices(p *ProposerIndices) error {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
|
||||
if err := c.ProposerIndicesCache.AddIfNotPresent(p); err != nil {
|
||||
return err
|
||||
}
|
||||
trim(c.ProposerIndicesCache, maxProposerIndicesCacheSize)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ProposerIndices returns the proposer indices of a block root seed.
|
||||
func (c *ProposerIndicesCache) ProposerIndices(r [32]byte) ([]uint64, error) {
|
||||
c.lock.RLock()
|
||||
defer c.lock.RUnlock()
|
||||
obj, exists, err := c.ProposerIndicesCache.GetByKey(key(r))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if exists {
|
||||
ProposerIndicesCacheHit.Inc()
|
||||
} else {
|
||||
ProposerIndicesCacheMiss.Inc()
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
item, ok := obj.(*ProposerIndices)
|
||||
if !ok {
|
||||
return nil, ErrNotProposerIndices
|
||||
}
|
||||
|
||||
return item.ProposerIndices, nil
|
||||
}
|
||||
24
beacon-chain/cache/proposer_indices_disabled.go
vendored
Normal file
24
beacon-chain/cache/proposer_indices_disabled.go
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
// +build libfuzzer
|
||||
|
||||
// This file is used in fuzzer builds to bypass proposer indices caches.
|
||||
package cache
|
||||
|
||||
// FakeProposerIndicesCache is a struct with 1 queue for looking up proposer indices by root.
|
||||
type FakeProposerIndicesCache struct {
|
||||
}
|
||||
|
||||
// NewProposerIndicesCache creates a new proposer indices cache for storing/accessing proposer index assignments of an epoch.
|
||||
func NewProposerIndicesCache() *FakeProposerIndicesCache {
|
||||
return &FakeProposerIndicesCache{}
|
||||
}
|
||||
|
||||
// AddProposerIndices adds ProposerIndices object to the cache.
|
||||
// This method also trims the least recently list if the cache size has ready the max cache size limit.
|
||||
func (c *FakeProposerIndicesCache) AddProposerIndices(p *ProposerIndices) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ProposerIndices returns the proposer indices of a block root seed.
|
||||
func (c *FakeProposerIndicesCache) ProposerIndices(r [32]byte) ([]uint64, error) {
|
||||
return nil, nil
|
||||
}
|
||||
63
beacon-chain/cache/proposer_indices_test.go
vendored
Normal file
63
beacon-chain/cache/proposer_indices_test.go
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
func TestProposerKeyFn_OK(t *testing.T) {
|
||||
item := &ProposerIndices{
|
||||
BlockRoot: [32]byte{'A'},
|
||||
ProposerIndices: []uint64{1, 2, 3, 4, 5},
|
||||
}
|
||||
|
||||
k, err := proposerIndicesKeyFn(item)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, key(item.BlockRoot), k)
|
||||
}
|
||||
|
||||
func TestProposerKeyFn_InvalidObj(t *testing.T) {
|
||||
_, err := proposerIndicesKeyFn("bad")
|
||||
assert.Equal(t, ErrNotProposerIndices, err)
|
||||
}
|
||||
|
||||
func TestProposerCache_AddProposerIndicesList(t *testing.T) {
|
||||
cache := NewProposerIndicesCache()
|
||||
bRoot := [32]byte{'A'}
|
||||
indices, err := cache.ProposerIndices(bRoot)
|
||||
require.NoError(t, err)
|
||||
if indices != nil {
|
||||
t.Error("Expected committee count not to exist in empty cache")
|
||||
}
|
||||
require.NoError(t, cache.AddProposerIndices(&ProposerIndices{
|
||||
ProposerIndices: indices,
|
||||
BlockRoot: bRoot,
|
||||
}))
|
||||
|
||||
received, err := cache.ProposerIndices(bRoot)
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, received, indices)
|
||||
|
||||
item := &ProposerIndices{BlockRoot: [32]byte{'B'}, ProposerIndices: []uint64{1, 2, 3, 4, 5, 6}}
|
||||
require.NoError(t, cache.AddProposerIndices(item))
|
||||
|
||||
received, err = cache.ProposerIndices(item.BlockRoot)
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, item.ProposerIndices, received)
|
||||
}
|
||||
|
||||
func TestProposerCache_CanRotate(t *testing.T) {
|
||||
cache := NewProposerIndicesCache()
|
||||
for i := 0; i < int(maxProposerIndicesCacheSize)+1; i++ {
|
||||
s := []byte(strconv.Itoa(i))
|
||||
item := &ProposerIndices{BlockRoot: bytesutil.ToBytes32(s)}
|
||||
require.NoError(t, cache.AddProposerIndices(item))
|
||||
}
|
||||
|
||||
k := cache.ProposerIndicesCache.ListKeys()
|
||||
assert.Equal(t, maxProposerIndicesCacheSize, uint64(len(k)))
|
||||
}
|
||||
13
beacon-chain/cache/proposer_indices_type.go
vendored
Normal file
13
beacon-chain/cache/proposer_indices_type.go
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
package cache
|
||||
|
||||
import "errors"
|
||||
|
||||
// ErrNotProposerIndices will be returned when a cache object is not a pointer to
|
||||
// a ProposerIndices struct.
|
||||
var ErrNotProposerIndices = errors.New("object is not a proposer indices struct")
|
||||
|
||||
// ProposerIndices defines the cached struct for proposer indices.
|
||||
type ProposerIndices struct {
|
||||
BlockRoot [32]byte
|
||||
ProposerIndices []uint64
|
||||
}
|
||||
2
beacon-chain/cache/subnet_ids_test.go
vendored
2
beacon-chain/cache/subnet_ids_test.go
vendored
@@ -42,12 +42,10 @@ func TestSubnetIDsCache_RoundTrip(t *testing.T) {
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@ go_library(
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//beacon-chain/core/validators:go_default_library",
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//beacon-chain/state/stateutil:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//shared/attestationutil:go_default_library",
|
||||
"//shared/bls:go_default_library",
|
||||
@@ -63,10 +62,10 @@ go_test(
|
||||
"randao_test.go",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
shard_count = 2,
|
||||
deps = [
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//beacon-chain/state/stateutil:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//shared/aggregation:go_default_library",
|
||||
"//shared/aggregation/attestations:go_default_library",
|
||||
@@ -82,7 +81,6 @@ go_test(
|
||||
"@com_github_google_gofuzz//:go_default_library",
|
||||
"@com_github_prysmaticlabs_ethereumapis//eth/v1alpha1:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_ssz//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/attestationutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
@@ -21,10 +22,14 @@ import (
|
||||
func ProcessAttestations(
|
||||
ctx context.Context,
|
||||
beaconState *stateTrie.BeaconState,
|
||||
body *ethpb.BeaconBlockBody,
|
||||
b *ethpb.SignedBeaconBlock,
|
||||
) (*stateTrie.BeaconState, error) {
|
||||
if b.Block == nil || b.Block.Body == nil {
|
||||
return nil, errors.New("block and block body can't be nil")
|
||||
}
|
||||
|
||||
var err error
|
||||
for idx, attestation := range body.Attestations {
|
||||
for idx, attestation := range b.Block.Body.Attestations {
|
||||
beaconState, err = ProcessAttestation(ctx, beaconState, attestation)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not verify attestation at index %d in block", idx)
|
||||
@@ -67,23 +72,27 @@ func ProcessAttestation(
|
||||
beaconState *stateTrie.BeaconState,
|
||||
att *ethpb.Attestation,
|
||||
) (*stateTrie.BeaconState, error) {
|
||||
beaconState, err := ProcessAttestationNoVerify(ctx, beaconState, att)
|
||||
beaconState, err := ProcessAttestationNoVerifySignature(ctx, beaconState, att)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return beaconState, VerifyAttestation(ctx, beaconState, att)
|
||||
return beaconState, VerifyAttestationSignature(ctx, beaconState, att)
|
||||
}
|
||||
|
||||
// ProcessAttestationsNoVerify applies processing operations to a block's inner attestation
|
||||
// ProcessAttestationsNoVerifySignature applies processing operations to a block's inner attestation
|
||||
// records. The only difference would be that the attestation signature would not be verified.
|
||||
func ProcessAttestationsNoVerify(
|
||||
func ProcessAttestationsNoVerifySignature(
|
||||
ctx context.Context,
|
||||
beaconState *stateTrie.BeaconState,
|
||||
body *ethpb.BeaconBlockBody,
|
||||
b *ethpb.SignedBeaconBlock,
|
||||
) (*stateTrie.BeaconState, error) {
|
||||
if b.Block == nil || b.Block.Body == nil {
|
||||
return nil, errors.New("block and block body can't be nil")
|
||||
}
|
||||
body := b.Block.Body
|
||||
var err error
|
||||
for idx, attestation := range body.Attestations {
|
||||
beaconState, err = ProcessAttestationNoVerify(ctx, beaconState, attestation)
|
||||
beaconState, err = ProcessAttestationNoVerifySignature(ctx, beaconState, attestation)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not verify attestation at index %d in block", idx)
|
||||
}
|
||||
@@ -91,14 +100,14 @@ func ProcessAttestationsNoVerify(
|
||||
return beaconState, nil
|
||||
}
|
||||
|
||||
// ProcessAttestationNoVerify processes the attestation without verifying the attestation signature. This
|
||||
// ProcessAttestationNoVerifySignature processes the attestation without verifying the attestation signature. This
|
||||
// method is used to validate attestations whose signatures have already been verified.
|
||||
func ProcessAttestationNoVerify(
|
||||
func ProcessAttestationNoVerifySignature(
|
||||
ctx context.Context,
|
||||
beaconState *stateTrie.BeaconState,
|
||||
att *ethpb.Attestation,
|
||||
) (*stateTrie.BeaconState, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "core.ProcessAttestationNoVerify")
|
||||
ctx, span := trace.StartSpan(ctx, "core.ProcessAttestationNoVerifySignature")
|
||||
defer span.End()
|
||||
|
||||
if att == nil || att.Data == nil || att.Data.Target == nil {
|
||||
@@ -196,17 +205,28 @@ func ProcessAttestationNoVerify(
|
||||
return nil, fmt.Errorf("expected target epoch %d, received %d", ffgTargetEpoch, data.Target.Epoch)
|
||||
}
|
||||
|
||||
// Verify attesting indices are correct.
|
||||
committee, err := helpers.BeaconCommitteeFromState(beaconState, att.Data.Slot, att.Data.CommitteeIndex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
indexedAtt := attestationutil.ConvertToIndexed(ctx, att, committee)
|
||||
if err := attestationutil.IsValidAttestationIndices(ctx, indexedAtt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return beaconState, nil
|
||||
}
|
||||
|
||||
// VerifyAttestations will verify the signatures of the provided attestations. This method performs
|
||||
// VerifyAttestationsSignatures 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")
|
||||
func VerifyAttestationsSignatures(ctx context.Context, beaconState *stateTrie.BeaconState, b *ethpb.SignedBeaconBlock) error {
|
||||
ctx, span := trace.StartSpan(ctx, "core.VerifyAttestationsSignatures")
|
||||
defer span.End()
|
||||
atts := b.Block.Body.Attestations
|
||||
span.AddAttributes(trace.Int64Attribute("attestations", int64(len(atts))))
|
||||
|
||||
if len(atts) == 0 {
|
||||
@@ -234,7 +254,7 @@ func VerifyAttestations(ctx context.Context, beaconState *stateTrie.BeaconState,
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := verifyAttestationsWithDomain(ctx, beaconState, preForkAtts, prevDomain); err != nil {
|
||||
if err := verifyAttestationsSigWithDomain(ctx, beaconState, preForkAtts, prevDomain); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if len(preForkAtts) > 0 {
|
||||
@@ -249,12 +269,12 @@ func VerifyAttestations(ctx context.Context, beaconState *stateTrie.BeaconState,
|
||||
return err
|
||||
}
|
||||
|
||||
return verifyAttestationsWithDomain(ctx, beaconState, postForkAtts, currDomain)
|
||||
return verifyAttestationsSigWithDomain(ctx, beaconState, postForkAtts, currDomain)
|
||||
}
|
||||
|
||||
// VerifyAttestation converts and attestation into an indexed attestation and verifies
|
||||
// VerifyAttestationSignature converts and attestation into an indexed attestation and verifies
|
||||
// the signature in that attestation.
|
||||
func VerifyAttestation(ctx context.Context, beaconState *stateTrie.BeaconState, att *ethpb.Attestation) error {
|
||||
func VerifyAttestationSignature(ctx context.Context, beaconState *stateTrie.BeaconState, att *ethpb.Attestation) error {
|
||||
if att == nil || att.Data == nil || att.AggregationBits.Count() == 0 {
|
||||
return fmt.Errorf("nil or missing attestation data: %v", att)
|
||||
}
|
||||
@@ -308,7 +328,7 @@ func VerifyIndexedAttestation(ctx context.Context, beaconState *stateTrie.Beacon
|
||||
|
||||
// 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 {
|
||||
func verifyAttestationsSigWithDomain(ctx context.Context, beaconState *stateTrie.BeaconState, atts []*ethpb.Attestation, domain []byte) error {
|
||||
if len(atts) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -316,7 +336,7 @@ func verifyAttestationsWithDomain(ctx context.Context, beaconState *stateTrie.Be
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
verify, err := bls.VerifyMultipleSignatures(set.Signatures, set.Messages, set.PublicKeys)
|
||||
verify, err := set.Verify()
|
||||
if err != nil {
|
||||
return errors.Errorf("got error in multiple verification: %v", err)
|
||||
}
|
||||
@@ -325,3 +345,35 @@ func verifyAttestationsWithDomain(ctx context.Context, beaconState *stateTrie.Be
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// VerifyAttSigUseCheckPt uses the checkpoint info object to verify attestation signature.
|
||||
func VerifyAttSigUseCheckPt(ctx context.Context, c *pb.CheckPtInfo, att *ethpb.Attestation) error {
|
||||
if att == nil || att.Data == nil || att.AggregationBits.Count() == 0 {
|
||||
return fmt.Errorf("nil or missing attestation data: %v", att)
|
||||
}
|
||||
seed := bytesutil.ToBytes32(c.Seed)
|
||||
committee, err := helpers.BeaconCommittee(c.ActiveIndices, seed, att.Data.Slot, att.Data.CommitteeIndex)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
indexedAtt := attestationutil.ConvertToIndexed(ctx, att, committee)
|
||||
if err := attestationutil.IsValidAttestationIndices(ctx, indexedAtt); err != nil {
|
||||
return err
|
||||
}
|
||||
domain, err := helpers.Domain(c.Fork, indexedAtt.Data.Target.Epoch, params.BeaconConfig().DomainBeaconAttester, c.GenesisRoot)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
indices := indexedAtt.AttestingIndices
|
||||
pubkeys := []bls.PublicKey{}
|
||||
for i := 0; i < len(indices); i++ {
|
||||
pubkeyAtIdx := c.PubKeys[indices[i]]
|
||||
pk, err := bls.PublicKeyFromBytes(pubkeyAtIdx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not deserialize validator public key")
|
||||
}
|
||||
pubkeys = append(pubkeys, pk)
|
||||
}
|
||||
|
||||
return attestationutil.VerifyIndexedAttestationSig(ctx, indexedAtt, pubkeys, domain)
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
attaggregation "github.com/prysmaticlabs/prysm/shared/aggregation/attestations"
|
||||
"github.com/prysmaticlabs/prysm/shared/attestationutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
@@ -25,12 +26,13 @@ func TestProcessAttestations_InclusionDelayFailure(t *testing.T) {
|
||||
attestations := []*ethpb.Attestation{
|
||||
{
|
||||
Data: ðpb.AttestationData{
|
||||
Target: ðpb.Checkpoint{Epoch: 0},
|
||||
Target: ðpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
|
||||
Slot: 5,
|
||||
},
|
||||
},
|
||||
}
|
||||
block := ðpb.BeaconBlock{
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block = ðpb.BeaconBlock{
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
Attestations: attestations,
|
||||
},
|
||||
@@ -43,7 +45,7 @@ func TestProcessAttestations_InclusionDelayFailure(t *testing.T) {
|
||||
params.BeaconConfig().MinAttestationInclusionDelay,
|
||||
beaconState.Slot(),
|
||||
)
|
||||
_, err := blocks.ProcessAttestations(context.Background(), beaconState, block.Body)
|
||||
_, err := blocks.ProcessAttestations(context.Background(), beaconState, b)
|
||||
assert.ErrorContains(t, want, err)
|
||||
}
|
||||
|
||||
@@ -53,7 +55,8 @@ func TestProcessAttestations_NeitherCurrentNorPrevEpoch(t *testing.T) {
|
||||
Source: ðpb.Checkpoint{Epoch: 0, Root: []byte("hello-world")},
|
||||
Target: ðpb.Checkpoint{Epoch: 0}}}
|
||||
|
||||
block := ðpb.BeaconBlock{
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block = ðpb.BeaconBlock{
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
Attestations: []*ethpb.Attestation{att},
|
||||
},
|
||||
@@ -72,7 +75,7 @@ func TestProcessAttestations_NeitherCurrentNorPrevEpoch(t *testing.T) {
|
||||
helpers.PrevEpoch(beaconState),
|
||||
helpers.CurrentEpoch(beaconState),
|
||||
)
|
||||
_, err = blocks.ProcessAttestations(context.Background(), beaconState, block.Body)
|
||||
_, err = blocks.ProcessAttestations(context.Background(), beaconState, b)
|
||||
assert.ErrorContains(t, want, err)
|
||||
}
|
||||
|
||||
@@ -81,13 +84,14 @@ func TestProcessAttestations_CurrentEpochFFGDataMismatches(t *testing.T) {
|
||||
attestations := []*ethpb.Attestation{
|
||||
{
|
||||
Data: ðpb.AttestationData{
|
||||
Target: ðpb.Checkpoint{Epoch: 0},
|
||||
Source: ðpb.Checkpoint{Epoch: 1},
|
||||
Target: ðpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
|
||||
Source: ðpb.Checkpoint{Epoch: 1, Root: make([]byte, 32)},
|
||||
},
|
||||
AggregationBits: aggBits,
|
||||
},
|
||||
}
|
||||
block := ðpb.BeaconBlock{
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block = ðpb.BeaconBlock{
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
Attestations: attestations,
|
||||
},
|
||||
@@ -104,18 +108,18 @@ func TestProcessAttestations_CurrentEpochFFGDataMismatches(t *testing.T) {
|
||||
helpers.CurrentEpoch(beaconState),
|
||||
attestations[0].Data.Source.Epoch,
|
||||
)
|
||||
_, err := blocks.ProcessAttestations(context.Background(), beaconState, block.Body)
|
||||
_, err := blocks.ProcessAttestations(context.Background(), beaconState, b)
|
||||
assert.ErrorContains(t, want, err)
|
||||
|
||||
block.Body.Attestations[0].Data.Source.Epoch = helpers.CurrentEpoch(beaconState)
|
||||
block.Body.Attestations[0].Data.Source.Root = []byte{}
|
||||
b.Block.Body.Attestations[0].Data.Source.Epoch = helpers.CurrentEpoch(beaconState)
|
||||
b.Block.Body.Attestations[0].Data.Source.Root = []byte{}
|
||||
|
||||
want = fmt.Sprintf(
|
||||
"expected source root %#x, received %#x",
|
||||
beaconState.CurrentJustifiedCheckpoint().Root,
|
||||
attestations[0].Data.Source.Root,
|
||||
)
|
||||
_, err = blocks.ProcessAttestations(context.Background(), beaconState, block.Body)
|
||||
_, err = blocks.ProcessAttestations(context.Background(), beaconState, b)
|
||||
assert.ErrorContains(t, want, err)
|
||||
}
|
||||
|
||||
@@ -127,14 +131,15 @@ func TestProcessAttestations_PrevEpochFFGDataMismatches(t *testing.T) {
|
||||
attestations := []*ethpb.Attestation{
|
||||
{
|
||||
Data: ðpb.AttestationData{
|
||||
Source: ðpb.Checkpoint{Epoch: 1},
|
||||
Target: ðpb.Checkpoint{Epoch: 1},
|
||||
Source: ðpb.Checkpoint{Epoch: 1, Root: make([]byte, 32)},
|
||||
Target: ðpb.Checkpoint{Epoch: 1, Root: make([]byte, 32)},
|
||||
Slot: params.BeaconConfig().SlotsPerEpoch,
|
||||
},
|
||||
AggregationBits: aggBits,
|
||||
},
|
||||
}
|
||||
block := ðpb.BeaconBlock{
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block = ðpb.BeaconBlock{
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
Attestations: attestations,
|
||||
},
|
||||
@@ -152,19 +157,19 @@ func TestProcessAttestations_PrevEpochFFGDataMismatches(t *testing.T) {
|
||||
helpers.PrevEpoch(beaconState),
|
||||
attestations[0].Data.Source.Epoch,
|
||||
)
|
||||
_, err = blocks.ProcessAttestations(context.Background(), beaconState, block.Body)
|
||||
_, err = blocks.ProcessAttestations(context.Background(), beaconState, b)
|
||||
assert.ErrorContains(t, want, err)
|
||||
|
||||
block.Body.Attestations[0].Data.Source.Epoch = helpers.PrevEpoch(beaconState)
|
||||
block.Body.Attestations[0].Data.Target.Epoch = helpers.CurrentEpoch(beaconState)
|
||||
block.Body.Attestations[0].Data.Source.Root = []byte{}
|
||||
b.Block.Body.Attestations[0].Data.Source.Epoch = helpers.PrevEpoch(beaconState)
|
||||
b.Block.Body.Attestations[0].Data.Target.Epoch = helpers.CurrentEpoch(beaconState)
|
||||
b.Block.Body.Attestations[0].Data.Source.Root = []byte{}
|
||||
|
||||
want = fmt.Sprintf(
|
||||
"expected source root %#x, received %#x",
|
||||
beaconState.CurrentJustifiedCheckpoint().Root,
|
||||
attestations[0].Data.Source.Root,
|
||||
)
|
||||
_, err = blocks.ProcessAttestations(context.Background(), beaconState, block.Body)
|
||||
_, err = blocks.ProcessAttestations(context.Background(), beaconState, b)
|
||||
assert.ErrorContains(t, want, err)
|
||||
}
|
||||
|
||||
@@ -179,7 +184,8 @@ func TestProcessAttestations_InvalidAggregationBitsLength(t *testing.T) {
|
||||
AggregationBits: aggBits,
|
||||
}
|
||||
|
||||
block := ðpb.BeaconBlock{
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block = ðpb.BeaconBlock{
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
Attestations: []*ethpb.Attestation{att},
|
||||
},
|
||||
@@ -194,7 +200,7 @@ func TestProcessAttestations_InvalidAggregationBitsLength(t *testing.T) {
|
||||
require.NoError(t, beaconState.SetCurrentEpochAttestations([]*pb.PendingAttestation{}))
|
||||
|
||||
expected := "failed to verify aggregation bitfield: wanted participants bitfield length 3, got: 4"
|
||||
_, err = blocks.ProcessAttestations(context.Background(), beaconState, block.Body)
|
||||
_, err = blocks.ProcessAttestations(context.Background(), beaconState, b)
|
||||
assert.ErrorContains(t, expected, err)
|
||||
}
|
||||
|
||||
@@ -207,10 +213,12 @@ func TestProcessAttestations_OK(t *testing.T) {
|
||||
copy(mockRoot[:], "hello-world")
|
||||
att := ðpb.Attestation{
|
||||
Data: ðpb.AttestationData{
|
||||
Source: ðpb.Checkpoint{Epoch: 0, Root: mockRoot[:]},
|
||||
Target: ðpb.Checkpoint{Epoch: 0, Root: mockRoot[:]},
|
||||
Source: ðpb.Checkpoint{Epoch: 0, Root: mockRoot[:]},
|
||||
Target: ðpb.Checkpoint{Epoch: 0, Root: mockRoot[:]},
|
||||
BeaconBlockRoot: make([]byte, 32),
|
||||
},
|
||||
AggregationBits: aggBits,
|
||||
Signature: make([]byte, 96),
|
||||
}
|
||||
|
||||
cfc := beaconState.CurrentJustifiedCheckpoint()
|
||||
@@ -230,25 +238,23 @@ func TestProcessAttestations_OK(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
sigs[i] = sig
|
||||
}
|
||||
att.Signature = bls.AggregateSignatures(sigs).Marshal()[:]
|
||||
att.Signature = bls.AggregateSignatures(sigs).Marshal()
|
||||
|
||||
block := ðpb.BeaconBlock{
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
Attestations: []*ethpb.Attestation{att},
|
||||
},
|
||||
}
|
||||
block := testutil.NewBeaconBlock()
|
||||
block.Block.Body.Attestations = []*ethpb.Attestation{att}
|
||||
|
||||
err = beaconState.SetSlot(beaconState.Slot() + params.BeaconConfig().MinAttestationInclusionDelay)
|
||||
require.NoError(t, err)
|
||||
_, err = blocks.ProcessAttestations(context.Background(), beaconState, block.Body)
|
||||
_, err = blocks.ProcessAttestations(context.Background(), beaconState, block)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestProcessAggregatedAttestation_OverlappingBits(t *testing.T) {
|
||||
beaconState, privKeys := testutil.DeterministicGenesisState(t, 100)
|
||||
data := ðpb.AttestationData{
|
||||
Source: ðpb.Checkpoint{Epoch: 0, Root: []byte("hello-world")},
|
||||
Target: ðpb.Checkpoint{Epoch: 0, Root: []byte("hello-world")},
|
||||
Source: ðpb.Checkpoint{Epoch: 0, Root: bytesutil.PadTo([]byte("hello-world"), 32)},
|
||||
Target: ðpb.Checkpoint{Epoch: 0, Root: bytesutil.PadTo([]byte("hello-world"), 32)},
|
||||
BeaconBlockRoot: make([]byte, 32),
|
||||
}
|
||||
aggBits1 := bitfield.NewBitlist(4)
|
||||
aggBits1.SetBitAt(0, true)
|
||||
@@ -260,7 +266,7 @@ func TestProcessAggregatedAttestation_OverlappingBits(t *testing.T) {
|
||||
}
|
||||
|
||||
cfc := beaconState.CurrentJustifiedCheckpoint()
|
||||
cfc.Root = []byte("hello-world")
|
||||
cfc.Root = bytesutil.PadTo([]byte("hello-world"), 32)
|
||||
require.NoError(t, beaconState.SetCurrentJustifiedCheckpoint(cfc))
|
||||
require.NoError(t, beaconState.SetCurrentEpochAttestations([]*pb.PendingAttestation{}))
|
||||
|
||||
@@ -276,7 +282,7 @@ func TestProcessAggregatedAttestation_OverlappingBits(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
sigs[i] = sig
|
||||
}
|
||||
att1.Signature = bls.AggregateSignatures(sigs).Marshal()[:]
|
||||
att1.Signature = bls.AggregateSignatures(sigs).Marshal()
|
||||
|
||||
aggBits2 := bitfield.NewBitlist(4)
|
||||
aggBits2.SetBitAt(1, true)
|
||||
@@ -299,7 +305,7 @@ func TestProcessAggregatedAttestation_OverlappingBits(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
sigs[i] = sig
|
||||
}
|
||||
att2.Signature = bls.AggregateSignatures(sigs).Marshal()[:]
|
||||
att2.Signature = bls.AggregateSignatures(sigs).Marshal()
|
||||
|
||||
_, err = attaggregation.AggregatePair(att1, att2)
|
||||
assert.ErrorContains(t, aggregation.ErrBitsOverlap.Error(), err)
|
||||
@@ -311,8 +317,9 @@ func TestProcessAggregatedAttestation_NoOverlappingBits(t *testing.T) {
|
||||
var mockRoot [32]byte
|
||||
copy(mockRoot[:], "hello-world")
|
||||
data := ðpb.AttestationData{
|
||||
Source: ðpb.Checkpoint{Epoch: 0, Root: mockRoot[:]},
|
||||
Target: ðpb.Checkpoint{Epoch: 0, Root: mockRoot[:]},
|
||||
Source: ðpb.Checkpoint{Epoch: 0, Root: mockRoot[:]},
|
||||
Target: ðpb.Checkpoint{Epoch: 0, Root: mockRoot[:]},
|
||||
BeaconBlockRoot: make([]byte, 32),
|
||||
}
|
||||
aggBits1 := bitfield.NewBitlist(9)
|
||||
aggBits1.SetBitAt(0, true)
|
||||
@@ -320,6 +327,7 @@ func TestProcessAggregatedAttestation_NoOverlappingBits(t *testing.T) {
|
||||
att1 := ðpb.Attestation{
|
||||
Data: data,
|
||||
AggregationBits: aggBits1,
|
||||
Signature: make([]byte, 32),
|
||||
}
|
||||
|
||||
cfc := beaconState.CurrentJustifiedCheckpoint()
|
||||
@@ -339,7 +347,7 @@ func TestProcessAggregatedAttestation_NoOverlappingBits(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
sigs[i] = sig
|
||||
}
|
||||
att1.Signature = bls.AggregateSignatures(sigs).Marshal()[:]
|
||||
att1.Signature = bls.AggregateSignatures(sigs).Marshal()
|
||||
|
||||
aggBits2 := bitfield.NewBitlist(9)
|
||||
aggBits2.SetBitAt(2, true)
|
||||
@@ -347,6 +355,7 @@ func TestProcessAggregatedAttestation_NoOverlappingBits(t *testing.T) {
|
||||
att2 := ðpb.Attestation{
|
||||
Data: data,
|
||||
AggregationBits: aggBits2,
|
||||
Signature: make([]byte, 32),
|
||||
}
|
||||
|
||||
committee, err = helpers.BeaconCommitteeFromState(beaconState, att2.Data.Slot, att2.Data.CommitteeIndex)
|
||||
@@ -361,20 +370,17 @@ func TestProcessAggregatedAttestation_NoOverlappingBits(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
sigs[i] = sig
|
||||
}
|
||||
att2.Signature = bls.AggregateSignatures(sigs).Marshal()[:]
|
||||
att2.Signature = bls.AggregateSignatures(sigs).Marshal()
|
||||
|
||||
aggregatedAtt, err := attaggregation.AggregatePair(att1, att2)
|
||||
require.NoError(t, err)
|
||||
block := ðpb.BeaconBlock{
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
Attestations: []*ethpb.Attestation{aggregatedAtt},
|
||||
},
|
||||
}
|
||||
block := testutil.NewBeaconBlock()
|
||||
block.Block.Body.Attestations = []*ethpb.Attestation{aggregatedAtt}
|
||||
|
||||
err = beaconState.SetSlot(beaconState.Slot() + params.BeaconConfig().MinAttestationInclusionDelay)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = blocks.ProcessAttestations(context.Background(), beaconState, block.Body)
|
||||
_, err = blocks.ProcessAttestations(context.Background(), beaconState, block)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
@@ -384,11 +390,11 @@ func TestProcessAttestationsNoVerify_IncorrectSlotTargetEpoch(t *testing.T) {
|
||||
att := ðpb.Attestation{
|
||||
Data: ðpb.AttestationData{
|
||||
Slot: params.BeaconConfig().SlotsPerEpoch,
|
||||
Target: ðpb.Checkpoint{},
|
||||
Target: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
},
|
||||
}
|
||||
wanted := fmt.Sprintf("data slot is not in the same epoch as target %d != %d", helpers.SlotToEpoch(att.Data.Slot), att.Data.Target.Epoch)
|
||||
_, err := blocks.ProcessAttestationNoVerify(context.TODO(), beaconState, att)
|
||||
_, err := blocks.ProcessAttestationNoVerifySignature(context.TODO(), beaconState, att)
|
||||
assert.ErrorContains(t, wanted, err)
|
||||
}
|
||||
|
||||
@@ -404,7 +410,7 @@ func TestProcessAttestationsNoVerify_OK(t *testing.T) {
|
||||
att := ðpb.Attestation{
|
||||
Data: ðpb.AttestationData{
|
||||
Source: ðpb.Checkpoint{Epoch: 0, Root: mockRoot[:]},
|
||||
Target: ðpb.Checkpoint{Epoch: 0},
|
||||
Target: ðpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
|
||||
},
|
||||
AggregationBits: aggBits,
|
||||
}
|
||||
@@ -419,7 +425,7 @@ func TestProcessAttestationsNoVerify_OK(t *testing.T) {
|
||||
require.NoError(t, beaconState.SetCurrentJustifiedCheckpoint(ckp))
|
||||
require.NoError(t, beaconState.SetCurrentEpochAttestations([]*pb.PendingAttestation{}))
|
||||
|
||||
_, err = blocks.ProcessAttestationNoVerify(context.TODO(), beaconState, att)
|
||||
_, err = blocks.ProcessAttestationNoVerifySignature(context.TODO(), beaconState, att)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
@@ -433,7 +439,7 @@ func TestProcessAttestationsNoVerify_BadAttIdx(t *testing.T) {
|
||||
Data: ðpb.AttestationData{
|
||||
CommitteeIndex: 100,
|
||||
Source: ðpb.Checkpoint{Epoch: 0, Root: mockRoot[:]},
|
||||
Target: ðpb.Checkpoint{Epoch: 0},
|
||||
Target: ðpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
|
||||
},
|
||||
AggregationBits: aggBits,
|
||||
}
|
||||
@@ -444,7 +450,7 @@ func TestProcessAttestationsNoVerify_BadAttIdx(t *testing.T) {
|
||||
copy(ckp.Root, "hello-world")
|
||||
require.NoError(t, beaconState.SetCurrentJustifiedCheckpoint(ckp))
|
||||
require.NoError(t, beaconState.SetCurrentEpochAttestations([]*pb.PendingAttestation{}))
|
||||
_, err := blocks.ProcessAttestationNoVerify(context.TODO(), beaconState, att)
|
||||
_, err := blocks.ProcessAttestationNoVerifySignature(context.TODO(), beaconState, att)
|
||||
require.ErrorContains(t, "committee index 100 >= committee count 1", err)
|
||||
}
|
||||
|
||||
@@ -486,8 +492,8 @@ func TestConvertToIndexed_OK(t *testing.T) {
|
||||
attestation := ðpb.Attestation{
|
||||
Signature: sig[:],
|
||||
Data: ðpb.AttestationData{
|
||||
Source: ðpb.Checkpoint{Epoch: 0},
|
||||
Target: ðpb.Checkpoint{Epoch: 0},
|
||||
Source: ðpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
|
||||
Target: ðpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
@@ -512,8 +518,9 @@ func TestVerifyIndexedAttestation_OK(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
for i := 0; i < len(validators); i++ {
|
||||
validators[i] = ðpb.Validator{
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
PublicKey: keys[i].PublicKey().Marshal(),
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
PublicKey: keys[i].PublicKey().Marshal(),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -535,33 +542,57 @@ func TestVerifyIndexedAttestation_OK(t *testing.T) {
|
||||
Data: ðpb.AttestationData{
|
||||
Target: ðpb.Checkpoint{
|
||||
Epoch: 2,
|
||||
Root: make([]byte, 32),
|
||||
},
|
||||
Source: ðpb.Checkpoint{
|
||||
Root: make([]byte, 32),
|
||||
},
|
||||
BeaconBlockRoot: make([]byte, 32),
|
||||
},
|
||||
AttestingIndices: []uint64{1},
|
||||
Signature: make([]byte, 96),
|
||||
}},
|
||||
{attestation: ðpb.IndexedAttestation{
|
||||
Data: ðpb.AttestationData{
|
||||
Target: ðpb.Checkpoint{
|
||||
Epoch: 1,
|
||||
Root: make([]byte, 32),
|
||||
},
|
||||
Source: ðpb.Checkpoint{
|
||||
Root: make([]byte, 32),
|
||||
},
|
||||
BeaconBlockRoot: make([]byte, 32),
|
||||
},
|
||||
AttestingIndices: []uint64{47, 99, 101},
|
||||
Signature: make([]byte, 96),
|
||||
}},
|
||||
{attestation: ðpb.IndexedAttestation{
|
||||
Data: ðpb.AttestationData{
|
||||
Target: ðpb.Checkpoint{
|
||||
Epoch: 4,
|
||||
Root: make([]byte, 32),
|
||||
},
|
||||
Source: ðpb.Checkpoint{
|
||||
Root: make([]byte, 32),
|
||||
},
|
||||
BeaconBlockRoot: make([]byte, 32),
|
||||
},
|
||||
AttestingIndices: []uint64{21, 72},
|
||||
Signature: make([]byte, 96),
|
||||
}},
|
||||
{attestation: ðpb.IndexedAttestation{
|
||||
Data: ðpb.AttestationData{
|
||||
Target: ðpb.Checkpoint{
|
||||
Epoch: 7,
|
||||
Root: make([]byte, 32),
|
||||
},
|
||||
Source: ðpb.Checkpoint{
|
||||
Root: make([]byte, 32),
|
||||
},
|
||||
BeaconBlockRoot: make([]byte, 32),
|
||||
},
|
||||
AttestingIndices: []uint64{100, 121, 122},
|
||||
Signature: make([]byte, 96),
|
||||
}},
|
||||
}
|
||||
|
||||
@@ -653,32 +684,28 @@ func TestVerifyAttestations_VerifiesMultipleAttestations(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
for i := 0; i < len(validators); i++ {
|
||||
validators[i] = ðpb.Validator{
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
PublicKey: keys[i].PublicKey().Marshal(),
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
PublicKey: keys[i].PublicKey().Marshal(),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
}
|
||||
}
|
||||
|
||||
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),
|
||||
})
|
||||
st := testutil.NewBeaconState()
|
||||
require.NoError(t, st.SetSlot(5))
|
||||
require.NoError(t, st.SetValidators(validators))
|
||||
|
||||
comm1, err := helpers.BeaconCommitteeFromState(st, 1 /*slot*/, 0 /*committeeIndex*/)
|
||||
require.NoError(t, err)
|
||||
att1 := ðpb.Attestation{
|
||||
AggregationBits: bitfield.NewBitlist(uint64(len(comm1))),
|
||||
Data: ðpb.AttestationData{
|
||||
Slot: 1,
|
||||
CommitteeIndex: 0,
|
||||
Target: new(ethpb.Checkpoint),
|
||||
Slot: 1,
|
||||
CommitteeIndex: 0,
|
||||
BeaconBlockRoot: make([]byte, 32),
|
||||
Target: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
Source: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
},
|
||||
Signature: nil,
|
||||
Signature: make([]byte, 96),
|
||||
}
|
||||
domain, err := helpers.Domain(st.Fork(), st.Fork().Epoch, params.BeaconConfig().DomainBeaconAttester, st.GenesisValidatorRoot())
|
||||
require.NoError(t, err)
|
||||
@@ -696,11 +723,13 @@ func TestVerifyAttestations_VerifiesMultipleAttestations(t *testing.T) {
|
||||
att2 := ðpb.Attestation{
|
||||
AggregationBits: bitfield.NewBitlist(uint64(len(comm2))),
|
||||
Data: ðpb.AttestationData{
|
||||
Slot: 1,
|
||||
CommitteeIndex: 1,
|
||||
Target: new(ethpb.Checkpoint),
|
||||
Slot: 1,
|
||||
CommitteeIndex: 1,
|
||||
BeaconBlockRoot: make([]byte, 32),
|
||||
Target: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
Source: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
},
|
||||
Signature: nil,
|
||||
Signature: make([]byte, 96),
|
||||
}
|
||||
root, err = helpers.ComputeSigningRoot(att2.Data, domain)
|
||||
require.NoError(t, err)
|
||||
@@ -711,7 +740,9 @@ func TestVerifyAttestations_VerifiesMultipleAttestations(t *testing.T) {
|
||||
}
|
||||
att2.Signature = bls.AggregateSignatures(sigs).Marshal()
|
||||
|
||||
require.NoError(t, blocks.VerifyAttestations(ctx, st, []*ethpb.Attestation{att1, att2}))
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block.Body.Attestations = []*ethpb.Attestation{att1, att2}
|
||||
require.NoError(t, blocks.VerifyAttestationsSignatures(ctx, st, b))
|
||||
}
|
||||
|
||||
func TestVerifyAttestations_HandlesPlannedFork(t *testing.T) {
|
||||
@@ -723,32 +754,33 @@ func TestVerifyAttestations_HandlesPlannedFork(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
for i := 0; i < len(validators); i++ {
|
||||
validators[i] = ðpb.Validator{
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
PublicKey: keys[i].PublicKey().Marshal(),
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
PublicKey: keys[i].PublicKey().Marshal(),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
}
|
||||
}
|
||||
|
||||
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),
|
||||
})
|
||||
st := testutil.NewBeaconState()
|
||||
require.NoError(t, st.SetSlot(35))
|
||||
require.NoError(t, st.SetValidators(validators))
|
||||
require.NoError(t, st.SetFork(&pb.Fork{
|
||||
Epoch: 1,
|
||||
CurrentVersion: []byte{0, 1, 2, 3},
|
||||
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
}))
|
||||
|
||||
comm1, err := helpers.BeaconCommitteeFromState(st, 1 /*slot*/, 0 /*committeeIndex*/)
|
||||
require.NoError(t, err)
|
||||
att1 := ðpb.Attestation{
|
||||
AggregationBits: bitfield.NewBitlist(uint64(len(comm1))),
|
||||
Data: ðpb.AttestationData{
|
||||
Slot: 1,
|
||||
CommitteeIndex: 0,
|
||||
Target: new(ethpb.Checkpoint),
|
||||
Slot: 1,
|
||||
CommitteeIndex: 0,
|
||||
BeaconBlockRoot: make([]byte, 32),
|
||||
Source: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
Target: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
},
|
||||
Signature: nil,
|
||||
Signature: make([]byte, 96),
|
||||
}
|
||||
prevDomain, err := helpers.Domain(st.Fork(), st.Fork().Epoch-1, params.BeaconConfig().DomainBeaconAttester, st.GenesisValidatorRoot())
|
||||
require.NoError(t, err)
|
||||
@@ -766,13 +798,16 @@ func TestVerifyAttestations_HandlesPlannedFork(t *testing.T) {
|
||||
att2 := ðpb.Attestation{
|
||||
AggregationBits: bitfield.NewBitlist(uint64(len(comm2))),
|
||||
Data: ðpb.AttestationData{
|
||||
Slot: 1*params.BeaconConfig().SlotsPerEpoch + 1,
|
||||
CommitteeIndex: 1,
|
||||
Target: new(ethpb.Checkpoint),
|
||||
Slot: 1*params.BeaconConfig().SlotsPerEpoch + 1,
|
||||
CommitteeIndex: 1,
|
||||
BeaconBlockRoot: make([]byte, 32),
|
||||
Source: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
Target: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
},
|
||||
Signature: nil,
|
||||
Signature: make([]byte, 96),
|
||||
}
|
||||
currDomain, err := helpers.Domain(st.Fork(), st.Fork().Epoch, params.BeaconConfig().DomainBeaconAttester, st.GenesisValidatorRoot())
|
||||
require.NoError(t, err)
|
||||
root, err = helpers.ComputeSigningRoot(att2.Data, currDomain)
|
||||
require.NoError(t, err)
|
||||
sigs = nil
|
||||
@@ -782,7 +817,9 @@ func TestVerifyAttestations_HandlesPlannedFork(t *testing.T) {
|
||||
}
|
||||
att2.Signature = bls.AggregateSignatures(sigs).Marshal()
|
||||
|
||||
require.NoError(t, blocks.VerifyAttestations(ctx, st, []*ethpb.Attestation{att1, att2}))
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block.Body.Attestations = []*ethpb.Attestation{att1, att2}
|
||||
require.NoError(t, blocks.VerifyAttestationsSignatures(ctx, st, b))
|
||||
}
|
||||
|
||||
func TestRetrieveAttestationSignatureSet_VerifiesMultipleAttestations(t *testing.T) {
|
||||
@@ -793,32 +830,28 @@ func TestRetrieveAttestationSignatureSet_VerifiesMultipleAttestations(t *testing
|
||||
require.NoError(t, err)
|
||||
for i := 0; i < len(validators); i++ {
|
||||
validators[i] = ðpb.Validator{
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
PublicKey: keys[i].PublicKey().Marshal(),
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
PublicKey: keys[i].PublicKey().Marshal(),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
}
|
||||
}
|
||||
|
||||
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),
|
||||
})
|
||||
st := testutil.NewBeaconState()
|
||||
require.NoError(t, st.SetSlot(5))
|
||||
require.NoError(t, st.SetValidators(validators))
|
||||
|
||||
comm1, err := helpers.BeaconCommitteeFromState(st, 1 /*slot*/, 0 /*committeeIndex*/)
|
||||
require.NoError(t, err)
|
||||
att1 := ðpb.Attestation{
|
||||
AggregationBits: bitfield.NewBitlist(uint64(len(comm1))),
|
||||
Data: ðpb.AttestationData{
|
||||
Slot: 1,
|
||||
CommitteeIndex: 0,
|
||||
Target: new(ethpb.Checkpoint),
|
||||
Slot: 1,
|
||||
CommitteeIndex: 0,
|
||||
BeaconBlockRoot: make([]byte, 32),
|
||||
Target: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
Source: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
},
|
||||
Signature: nil,
|
||||
Signature: make([]byte, 96),
|
||||
}
|
||||
domain, err := helpers.Domain(st.Fork(), st.Fork().Epoch, params.BeaconConfig().DomainBeaconAttester, st.GenesisValidatorRoot())
|
||||
require.NoError(t, err)
|
||||
@@ -836,11 +869,13 @@ func TestRetrieveAttestationSignatureSet_VerifiesMultipleAttestations(t *testing
|
||||
att2 := ðpb.Attestation{
|
||||
AggregationBits: bitfield.NewBitlist(uint64(len(comm2))),
|
||||
Data: ðpb.AttestationData{
|
||||
Slot: 1,
|
||||
CommitteeIndex: 1,
|
||||
Target: new(ethpb.Checkpoint),
|
||||
Slot: 1,
|
||||
CommitteeIndex: 1,
|
||||
BeaconBlockRoot: make([]byte, 32),
|
||||
Target: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
Source: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
},
|
||||
Signature: nil,
|
||||
Signature: make([]byte, 96),
|
||||
}
|
||||
root, err = helpers.ComputeSigningRoot(att2.Data, domain)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -35,8 +35,13 @@ import (
|
||||
func ProcessAttesterSlashings(
|
||||
ctx context.Context,
|
||||
beaconState *stateTrie.BeaconState,
|
||||
body *ethpb.BeaconBlockBody,
|
||||
b *ethpb.SignedBeaconBlock,
|
||||
) (*stateTrie.BeaconState, error) {
|
||||
if b.Block == nil || b.Block.Body == nil {
|
||||
return nil, errors.New("block and block body can't be nil")
|
||||
}
|
||||
|
||||
body := b.Block.Body
|
||||
for idx, slashing := range body.AttesterSlashings {
|
||||
if err := VerifyAttesterSlashing(ctx, beaconState, slashing); err != nil {
|
||||
return nil, errors.Wrapf(err, "could not verify attester slashing %d", idx)
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
@@ -19,12 +20,14 @@ import (
|
||||
|
||||
func TestSlashableAttestationData_CanSlash(t *testing.T) {
|
||||
att1 := ðpb.AttestationData{
|
||||
Target: ðpb.Checkpoint{Epoch: 1},
|
||||
Source: ðpb.Checkpoint{Root: []byte{'A'}},
|
||||
Target: ðpb.Checkpoint{Epoch: 1, Root: make([]byte, 32)},
|
||||
Source: ðpb.Checkpoint{Root: bytesutil.PadTo([]byte{'A'}, 32)},
|
||||
BeaconBlockRoot: make([]byte, 32),
|
||||
}
|
||||
att2 := ðpb.AttestationData{
|
||||
Target: ðpb.Checkpoint{Epoch: 1},
|
||||
Source: ðpb.Checkpoint{Root: []byte{'B'}},
|
||||
Target: ðpb.Checkpoint{Epoch: 1, Root: make([]byte, 32)},
|
||||
Source: ðpb.Checkpoint{Root: bytesutil.PadTo([]byte{'B'}, 32)},
|
||||
BeaconBlockRoot: make([]byte, 32),
|
||||
}
|
||||
assert.Equal(t, true, blocks.IsSlashableAttestationData(att1, att2), "Atts should have been slashable")
|
||||
att1.Target.Epoch = 4
|
||||
@@ -38,15 +41,19 @@ func TestProcessAttesterSlashings_DataNotSlashable(t *testing.T) {
|
||||
{
|
||||
Attestation_1: ðpb.IndexedAttestation{
|
||||
Data: ðpb.AttestationData{
|
||||
Source: ðpb.Checkpoint{Epoch: 0},
|
||||
Target: ðpb.Checkpoint{Epoch: 0},
|
||||
Source: ðpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
|
||||
Target: ðpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
|
||||
BeaconBlockRoot: make([]byte, 32),
|
||||
},
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
Attestation_2: ðpb.IndexedAttestation{
|
||||
Data: ðpb.AttestationData{
|
||||
Source: ðpb.Checkpoint{Epoch: 1},
|
||||
Target: ðpb.Checkpoint{Epoch: 1},
|
||||
Source: ðpb.Checkpoint{Epoch: 1, Root: make([]byte, 32)},
|
||||
Target: ðpb.Checkpoint{Epoch: 1, Root: make([]byte, 32)},
|
||||
BeaconBlockRoot: make([]byte, 32),
|
||||
},
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -58,13 +65,14 @@ func TestProcessAttesterSlashings_DataNotSlashable(t *testing.T) {
|
||||
Slot: currentSlot,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
block := ðpb.BeaconBlock{
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block = ðpb.BeaconBlock{
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
AttesterSlashings: slashings,
|
||||
},
|
||||
}
|
||||
want := fmt.Sprint("attestations are not slashable")
|
||||
_, err = blocks.ProcessAttesterSlashings(context.Background(), beaconState, block.Body)
|
||||
_, err = blocks.ProcessAttesterSlashings(context.Background(), beaconState, b)
|
||||
assert.ErrorContains(t, want, err)
|
||||
}
|
||||
|
||||
@@ -82,29 +90,34 @@ func TestProcessAttesterSlashings_IndexedAttestationFailedToVerify(t *testing.T)
|
||||
{
|
||||
Attestation_1: ðpb.IndexedAttestation{
|
||||
Data: ðpb.AttestationData{
|
||||
Source: ðpb.Checkpoint{Epoch: 1},
|
||||
Target: ðpb.Checkpoint{Epoch: 0},
|
||||
Source: ðpb.Checkpoint{Epoch: 1, Root: make([]byte, 32)},
|
||||
Target: ðpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
|
||||
BeaconBlockRoot: make([]byte, 32),
|
||||
},
|
||||
AttestingIndices: make([]uint64, params.BeaconConfig().MaxValidatorsPerCommittee+1),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
Attestation_2: ðpb.IndexedAttestation{
|
||||
Data: ðpb.AttestationData{
|
||||
Source: ðpb.Checkpoint{Epoch: 0},
|
||||
Target: ðpb.Checkpoint{Epoch: 0},
|
||||
Source: ðpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
|
||||
Target: ðpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
|
||||
BeaconBlockRoot: make([]byte, 32),
|
||||
},
|
||||
AttestingIndices: make([]uint64, params.BeaconConfig().MaxValidatorsPerCommittee+1),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
block := ðpb.BeaconBlock{
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block = ðpb.BeaconBlock{
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
AttesterSlashings: slashings,
|
||||
},
|
||||
}
|
||||
|
||||
want := fmt.Sprint("validator indices count exceeds MAX_VALIDATORS_PER_COMMITTEE")
|
||||
_, err = blocks.ProcessAttesterSlashings(context.Background(), beaconState, block.Body)
|
||||
_, err = blocks.ProcessAttesterSlashings(context.Background(), beaconState, b)
|
||||
assert.ErrorContains(t, want, err)
|
||||
}
|
||||
|
||||
@@ -116,8 +129,9 @@ func TestProcessAttesterSlashings_AppliesCorrectStatus(t *testing.T) {
|
||||
|
||||
att1 := ðpb.IndexedAttestation{
|
||||
Data: ðpb.AttestationData{
|
||||
Source: ðpb.Checkpoint{Epoch: 1},
|
||||
Target: ðpb.Checkpoint{Epoch: 0},
|
||||
Source: ðpb.Checkpoint{Epoch: 1, Root: make([]byte, 32)},
|
||||
Target: ðpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
|
||||
BeaconBlockRoot: make([]byte, 32),
|
||||
},
|
||||
AttestingIndices: []uint64{0, 1},
|
||||
}
|
||||
@@ -128,12 +142,13 @@ func TestProcessAttesterSlashings_AppliesCorrectStatus(t *testing.T) {
|
||||
sig0 := privKeys[0].Sign(signingRoot[:])
|
||||
sig1 := privKeys[1].Sign(signingRoot[:])
|
||||
aggregateSig := bls.AggregateSignatures([]bls.Signature{sig0, sig1})
|
||||
att1.Signature = aggregateSig.Marshal()[:]
|
||||
att1.Signature = aggregateSig.Marshal()
|
||||
|
||||
att2 := ðpb.IndexedAttestation{
|
||||
Data: ðpb.AttestationData{
|
||||
Source: ðpb.Checkpoint{Epoch: 0},
|
||||
Target: ðpb.Checkpoint{Epoch: 0},
|
||||
Source: ðpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
|
||||
Target: ðpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
|
||||
BeaconBlockRoot: make([]byte, 32),
|
||||
},
|
||||
AttestingIndices: []uint64{0, 1},
|
||||
}
|
||||
@@ -142,7 +157,7 @@ func TestProcessAttesterSlashings_AppliesCorrectStatus(t *testing.T) {
|
||||
sig0 = privKeys[0].Sign(signingRoot[:])
|
||||
sig1 = privKeys[1].Sign(signingRoot[:])
|
||||
aggregateSig = bls.AggregateSignatures([]bls.Signature{sig0, sig1})
|
||||
att2.Signature = aggregateSig.Marshal()[:]
|
||||
att2.Signature = aggregateSig.Marshal()
|
||||
|
||||
slashings := []*ethpb.AttesterSlashing{
|
||||
{
|
||||
@@ -154,13 +169,14 @@ func TestProcessAttesterSlashings_AppliesCorrectStatus(t *testing.T) {
|
||||
currentSlot := 2 * params.BeaconConfig().SlotsPerEpoch
|
||||
require.NoError(t, beaconState.SetSlot(currentSlot))
|
||||
|
||||
block := ðpb.BeaconBlock{
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block = ðpb.BeaconBlock{
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
AttesterSlashings: slashings,
|
||||
},
|
||||
}
|
||||
|
||||
newState, err := blocks.ProcessAttesterSlashings(context.Background(), beaconState, block.Body)
|
||||
newState, err := blocks.ProcessAttesterSlashings(context.Background(), beaconState, b)
|
||||
require.NoError(t, err)
|
||||
newRegistry := newState.Validators()
|
||||
|
||||
|
||||
@@ -6,13 +6,12 @@ import (
|
||||
|
||||
fuzz "github.com/google/gofuzz"
|
||||
eth "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
beaconstate "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
ethereum_beacon_p2p_v1 "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
|
||||
//"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
beaconstate "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
ethereum_beacon_p2p_v1 "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
func TestFuzzProcessAttestationNoVerify_10000(t *testing.T) {
|
||||
@@ -25,7 +24,8 @@ func TestFuzzProcessAttestationNoVerify_10000(t *testing.T) {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(att)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
_, err = ProcessAttestationNoVerify(ctx, s, att)
|
||||
require.NoError(t, err)
|
||||
_, err = ProcessAttestationNoVerifySignature(ctx, s, att)
|
||||
_ = err
|
||||
}
|
||||
}
|
||||
@@ -40,7 +40,8 @@ func TestFuzzProcessBlockHeader_10000(t *testing.T) {
|
||||
fuzzer.Fuzz(block)
|
||||
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
_, err = ProcessBlockHeader(s, block)
|
||||
require.NoError(t, err)
|
||||
_, err = ProcessBlockHeader(context.Background(), s, block)
|
||||
_ = err
|
||||
}
|
||||
}
|
||||
@@ -63,6 +64,7 @@ func TestFuzzverifyDepositDataSigningRoot_10000(t *testing.T) {
|
||||
fuzzer.Fuzz(&s)
|
||||
fuzzer.Fuzz(&d)
|
||||
err := verifySignature(ba, pubkey[:], sig[:], domain[:])
|
||||
_ = err
|
||||
err = verifySignature(ba, p, s, d)
|
||||
_ = err
|
||||
}
|
||||
@@ -70,14 +72,14 @@ func TestFuzzverifyDepositDataSigningRoot_10000(t *testing.T) {
|
||||
|
||||
func TestFuzzProcessEth1DataInBlock_10000(t *testing.T) {
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
block := ð.BeaconBlock{}
|
||||
b := ð.SignedBeaconBlock{}
|
||||
state := &stateTrie.BeaconState{}
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(block)
|
||||
s, err := ProcessEth1DataInBlock(state, block)
|
||||
fuzzer.Fuzz(b)
|
||||
s, err := ProcessEth1DataInBlock(context.Background(), state, b)
|
||||
if err != nil && s != nil {
|
||||
t.Fatalf("state should be nil on err. found: %v on error: %v for state: %v and block: %v", s, err, state, block)
|
||||
t.Fatalf("state should be nil on err. found: %v on error: %v for state: %v and block: %v", s, err, state, b)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -105,6 +107,7 @@ func TestFuzzEth1DataHasEnoughSupport_10000(t *testing.T) {
|
||||
s, err := beaconstate.InitializeFromProto(ðereum_beacon_p2p_v1.BeaconState{
|
||||
Eth1DataVotes: stateVotes,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
_, err = Eth1DataHasEnoughSupport(s, eth1data)
|
||||
_ = err
|
||||
}
|
||||
@@ -120,6 +123,7 @@ func TestFuzzProcessBlockHeaderNoVerify_10000(t *testing.T) {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(block)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
require.NoError(t, err)
|
||||
_, err = ProcessBlockHeaderNoVerify(s, block)
|
||||
_ = err
|
||||
}
|
||||
@@ -128,15 +132,16 @@ func TestFuzzProcessBlockHeaderNoVerify_10000(t *testing.T) {
|
||||
func TestFuzzProcessRandao_10000(t *testing.T) {
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
state := ðereum_beacon_p2p_v1.BeaconState{}
|
||||
blockBody := ð.BeaconBlockBody{}
|
||||
b := ð.SignedBeaconBlock{}
|
||||
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(blockBody)
|
||||
fuzzer.Fuzz(b)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
r, err := ProcessRandao(s, blockBody)
|
||||
require.NoError(t, err)
|
||||
r, err := ProcessRandao(context.Background(), s, b)
|
||||
if err != nil && r != nil {
|
||||
t.Fatalf("return value should be nil on err. found: %v on error: %v for state: %v and block: %v", r, err, state, blockBody)
|
||||
t.Fatalf("return value should be nil on err. found: %v on error: %v for state: %v and block: %v", r, err, state, b)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -150,6 +155,7 @@ func TestFuzzProcessRandaoNoVerify_10000(t *testing.T) {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(blockBody)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
require.NoError(t, err)
|
||||
r, err := ProcessRandaoNoVerify(s, blockBody)
|
||||
if err != nil && r != nil {
|
||||
t.Fatalf("return value should be nil on err. found: %v on error: %v for state: %v and block: %v", r, err, state, blockBody)
|
||||
@@ -160,15 +166,16 @@ func TestFuzzProcessRandaoNoVerify_10000(t *testing.T) {
|
||||
func TestFuzzProcessProposerSlashings_10000(t *testing.T) {
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
state := ðereum_beacon_p2p_v1.BeaconState{}
|
||||
blockBody := ð.BeaconBlockBody{}
|
||||
b := ð.SignedBeaconBlock{}
|
||||
ctx := context.Background()
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(blockBody)
|
||||
fuzzer.Fuzz(b)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
r, err := ProcessProposerSlashings(ctx, s, blockBody)
|
||||
require.NoError(t, err)
|
||||
r, err := ProcessProposerSlashings(ctx, s, b)
|
||||
if err != nil && r != nil {
|
||||
t.Fatalf("return value should be nil on err. found: %v on error: %v for state: %v and block: %v", r, err, state, blockBody)
|
||||
t.Fatalf("return value should be nil on err. found: %v on error: %v for state: %v and block: %v", r, err, state, b)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -181,6 +188,7 @@ func TestFuzzVerifyProposerSlashing_10000(t *testing.T) {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(proposerSlashing)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
require.NoError(t, err)
|
||||
err = VerifyProposerSlashing(s, proposerSlashing)
|
||||
_ = err
|
||||
}
|
||||
@@ -189,15 +197,16 @@ func TestFuzzVerifyProposerSlashing_10000(t *testing.T) {
|
||||
func TestFuzzProcessAttesterSlashings_10000(t *testing.T) {
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
state := ðereum_beacon_p2p_v1.BeaconState{}
|
||||
blockBody := ð.BeaconBlockBody{}
|
||||
b := ð.SignedBeaconBlock{}
|
||||
ctx := context.Background()
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(blockBody)
|
||||
fuzzer.Fuzz(b)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
r, err := ProcessAttesterSlashings(ctx, s, blockBody)
|
||||
require.NoError(t, err)
|
||||
r, err := ProcessAttesterSlashings(ctx, s, b)
|
||||
if err != nil && r != nil {
|
||||
t.Fatalf("return value should be nil on err. found: %v on error: %v for state: %v and block: %v", r, err, state, blockBody)
|
||||
t.Fatalf("return value should be nil on err. found: %v on error: %v for state: %v and block: %v", r, err, state, b)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -211,6 +220,7 @@ func TestFuzzVerifyAttesterSlashing_10000(t *testing.T) {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(attesterSlashing)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
require.NoError(t, err)
|
||||
err = VerifyAttesterSlashing(ctx, s, attesterSlashing)
|
||||
_ = err
|
||||
}
|
||||
@@ -241,15 +251,16 @@ func TestFuzzslashableAttesterIndices_10000(t *testing.T) {
|
||||
func TestFuzzProcessAttestations_10000(t *testing.T) {
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
state := ðereum_beacon_p2p_v1.BeaconState{}
|
||||
blockBody := ð.BeaconBlockBody{}
|
||||
b := ð.SignedBeaconBlock{}
|
||||
ctx := context.Background()
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(blockBody)
|
||||
fuzzer.Fuzz(b)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
r, err := ProcessAttestations(ctx, s, blockBody)
|
||||
require.NoError(t, err)
|
||||
r, err := ProcessAttestations(ctx, s, b)
|
||||
if err != nil && r != nil {
|
||||
t.Fatalf("return value should be nil on err. found: %v on error: %v for state: %v and block: %v", r, err, state, blockBody)
|
||||
t.Fatalf("return value should be nil on err. found: %v on error: %v for state: %v and block: %v", r, err, state, b)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -257,15 +268,16 @@ func TestFuzzProcessAttestations_10000(t *testing.T) {
|
||||
func TestFuzzProcessAttestationsNoVerify_10000(t *testing.T) {
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
state := ðereum_beacon_p2p_v1.BeaconState{}
|
||||
blockBody := ð.BeaconBlockBody{}
|
||||
b := ð.SignedBeaconBlock{}
|
||||
ctx := context.Background()
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(blockBody)
|
||||
fuzzer.Fuzz(b)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
r, err := ProcessAttestationsNoVerify(ctx, s, blockBody)
|
||||
require.NoError(t, err)
|
||||
r, err := ProcessAttestationsNoVerifySignature(ctx, s, b)
|
||||
if err != nil && r != nil {
|
||||
t.Fatalf("return value should be nil on err. found: %v on error: %v for state: %v and block: %v", r, err, state, blockBody)
|
||||
t.Fatalf("return value should be nil on err. found: %v on error: %v for state: %v and block: %v", r, err, state, b)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -279,6 +291,7 @@ func TestFuzzProcessAttestation_10000(t *testing.T) {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(attestation)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
require.NoError(t, err)
|
||||
r, err := ProcessAttestation(ctx, s, attestation)
|
||||
if err != nil && r != nil {
|
||||
t.Fatalf("return value should be nil on err. found: %v on error: %v for state: %v and block: %v", r, err, state, attestation)
|
||||
@@ -295,6 +308,7 @@ func TestFuzzVerifyIndexedAttestationn_10000(t *testing.T) {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(idxAttestation)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
require.NoError(t, err)
|
||||
err = VerifyIndexedAttestation(ctx, s, idxAttestation)
|
||||
_ = err
|
||||
}
|
||||
@@ -309,7 +323,8 @@ func TestFuzzVerifyAttestation_10000(t *testing.T) {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(attestation)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
err = VerifyAttestation(ctx, s, attestation)
|
||||
require.NoError(t, err)
|
||||
err = VerifyAttestationSignature(ctx, s, attestation)
|
||||
_ = err
|
||||
}
|
||||
}
|
||||
@@ -317,15 +332,16 @@ func TestFuzzVerifyAttestation_10000(t *testing.T) {
|
||||
func TestFuzzProcessDeposits_10000(t *testing.T) {
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
state := ðereum_beacon_p2p_v1.BeaconState{}
|
||||
blockBody := ð.BeaconBlockBody{}
|
||||
b := ð.SignedBeaconBlock{}
|
||||
ctx := context.Background()
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(blockBody)
|
||||
fuzzer.Fuzz(b)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
r, err := ProcessDeposits(ctx, s, blockBody.Deposits)
|
||||
require.NoError(t, err)
|
||||
r, err := ProcessDeposits(ctx, s, b)
|
||||
if err != nil && r != nil {
|
||||
t.Fatalf("return value should be nil on err. found: %v on error: %v for state: %v and block: %v", r, err, state, blockBody)
|
||||
t.Fatalf("return value should be nil on err. found: %v on error: %v for state: %v and block: %v", r, err, state, b)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -340,6 +356,7 @@ func TestFuzzProcessPreGenesisDeposit_10000(t *testing.T) {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(deposit)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
require.NoError(t, err)
|
||||
r, err := ProcessPreGenesisDeposits(ctx, s, []*eth.Deposit{deposit})
|
||||
if err != nil && r != nil {
|
||||
t.Fatalf("return value should be nil on err. found: %v on error: %v for state: %v and block: %v", r, err, state, deposit)
|
||||
@@ -356,6 +373,7 @@ func TestFuzzProcessDeposit_10000(t *testing.T) {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(deposit)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
require.NoError(t, err)
|
||||
r, err := ProcessDeposit(s, deposit, true)
|
||||
if err != nil && r != nil {
|
||||
t.Fatalf("return value should be nil on err. found: %v on error: %v for state: %v and block: %v", r, err, state, deposit)
|
||||
@@ -371,6 +389,7 @@ func TestFuzzverifyDeposit_10000(t *testing.T) {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(deposit)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
require.NoError(t, err)
|
||||
err = verifyDeposit(s, deposit)
|
||||
_ = err
|
||||
}
|
||||
@@ -379,15 +398,16 @@ func TestFuzzverifyDeposit_10000(t *testing.T) {
|
||||
func TestFuzzProcessVoluntaryExits_10000(t *testing.T) {
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
state := ðereum_beacon_p2p_v1.BeaconState{}
|
||||
blockBody := ð.BeaconBlockBody{}
|
||||
b := ð.SignedBeaconBlock{}
|
||||
ctx := context.Background()
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(blockBody)
|
||||
fuzzer.Fuzz(b)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
r, err := ProcessVoluntaryExits(ctx, s, blockBody)
|
||||
require.NoError(t, err)
|
||||
r, err := ProcessVoluntaryExits(ctx, s, b)
|
||||
if err != nil && r != nil {
|
||||
t.Fatalf("return value should be nil on err. found: %v on error: %v for state: %v and block: %v", r, err, state, blockBody)
|
||||
t.Fatalf("return value should be nil on err. found: %v on error: %v for state: %v and block: %v", r, err, state, b)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -395,14 +415,15 @@ func TestFuzzProcessVoluntaryExits_10000(t *testing.T) {
|
||||
func TestFuzzProcessVoluntaryExitsNoVerify_10000(t *testing.T) {
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
state := ðereum_beacon_p2p_v1.BeaconState{}
|
||||
blockBody := ð.BeaconBlockBody{}
|
||||
b := ð.SignedBeaconBlock{}
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(blockBody)
|
||||
fuzzer.Fuzz(b)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
r, err := ProcessVoluntaryExitsNoVerify(s, blockBody)
|
||||
require.NoError(t, err)
|
||||
r, err := ProcessVoluntaryExits(context.Background(), s, b)
|
||||
if err != nil && r != nil {
|
||||
t.Fatalf("return value should be nil on err. found: %v on error: %v for state: %v and block: %v", r, err, state, blockBody)
|
||||
t.Fatalf("return value should be nil on err. found: %v on error: %v for state: %v and block: %v", r, err, state, b)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -419,7 +440,7 @@ func TestFuzzVerifyExit_10000(t *testing.T) {
|
||||
fuzzer.Fuzz(val)
|
||||
fuzzer.Fuzz(fork)
|
||||
fuzzer.Fuzz(&slot)
|
||||
err := VerifyExit(val, slot, fork, ve, params.BeaconConfig().ZeroHash[:])
|
||||
err := VerifyExitAndSignature(val, slot, fork, ve, params.BeaconConfig().ZeroHash[:])
|
||||
_ = err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,10 +39,12 @@ func TestProcessAttesterSlashings_RegressionSlashableIndices(t *testing.T) {
|
||||
root1 := [32]byte{'d', 'o', 'u', 'b', 'l', 'e', '1'}
|
||||
att1 := ðpb.IndexedAttestation{
|
||||
Data: ðpb.AttestationData{
|
||||
Source: ðpb.Checkpoint{Epoch: 0},
|
||||
Target: ðpb.Checkpoint{Epoch: 0, Root: root1[:]},
|
||||
Source: ðpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
|
||||
Target: ðpb.Checkpoint{Epoch: 0, Root: root1[:]},
|
||||
BeaconBlockRoot: make([]byte, 32),
|
||||
},
|
||||
AttestingIndices: setA,
|
||||
Signature: make([]byte, 96),
|
||||
}
|
||||
domain, err := helpers.Domain(beaconState.Fork(), 0, params.BeaconConfig().DomainBeaconAttester, beaconState.GenesisValidatorRoot())
|
||||
require.NoError(t, err)
|
||||
@@ -54,15 +56,17 @@ func TestProcessAttesterSlashings_RegressionSlashableIndices(t *testing.T) {
|
||||
aggSigs = append(aggSigs, sig)
|
||||
}
|
||||
aggregateSig := bls.AggregateSignatures(aggSigs)
|
||||
att1.Signature = aggregateSig.Marshal()[:]
|
||||
att1.Signature = aggregateSig.Marshal()
|
||||
|
||||
root2 := [32]byte{'d', 'o', 'u', 'b', 'l', 'e', '2'}
|
||||
att2 := ðpb.IndexedAttestation{
|
||||
Data: ðpb.AttestationData{
|
||||
Source: ðpb.Checkpoint{Epoch: 0},
|
||||
Target: ðpb.Checkpoint{Epoch: 0, Root: root2[:]},
|
||||
Source: ðpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
|
||||
Target: ðpb.Checkpoint{Epoch: 0, Root: root2[:]},
|
||||
BeaconBlockRoot: make([]byte, 32),
|
||||
},
|
||||
AttestingIndices: setB,
|
||||
Signature: make([]byte, 96),
|
||||
}
|
||||
signingRoot, err = helpers.ComputeSigningRoot(att2.Data, domain)
|
||||
assert.NoError(t, err, "Could not get signing root of beacon block header")
|
||||
@@ -72,7 +76,7 @@ func TestProcessAttesterSlashings_RegressionSlashableIndices(t *testing.T) {
|
||||
aggSigs = append(aggSigs, sig)
|
||||
}
|
||||
aggregateSig = bls.AggregateSignatures(aggSigs)
|
||||
att2.Signature = aggregateSig.Marshal()[:]
|
||||
att2.Signature = aggregateSig.Marshal()
|
||||
|
||||
slashings := []*ethpb.AttesterSlashing{
|
||||
{
|
||||
@@ -84,13 +88,14 @@ func TestProcessAttesterSlashings_RegressionSlashableIndices(t *testing.T) {
|
||||
currentSlot := 2 * params.BeaconConfig().SlotsPerEpoch
|
||||
require.NoError(t, beaconState.SetSlot(currentSlot))
|
||||
|
||||
block := ðpb.BeaconBlock{
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block = ðpb.BeaconBlock{
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
AttesterSlashings: slashings,
|
||||
},
|
||||
}
|
||||
|
||||
newState, err := blocks.ProcessAttesterSlashings(context.Background(), beaconState, block.Body)
|
||||
newState, err := blocks.ProcessAttesterSlashings(context.Background(), beaconState, b)
|
||||
require.NoError(t, err)
|
||||
newRegistry := newState.Validators()
|
||||
if !newRegistry[expectedSlashedVal].Slashed {
|
||||
|
||||
@@ -25,7 +25,8 @@ func ProcessPreGenesisDeposits(
|
||||
deposits []*ethpb.Deposit,
|
||||
) (*stateTrie.BeaconState, error) {
|
||||
var err error
|
||||
beaconState, err = ProcessDeposits(ctx, beaconState, deposits)
|
||||
beaconState, err = ProcessDeposits(ctx, beaconState, ðpb.SignedBeaconBlock{
|
||||
Block: ðpb.BeaconBlock{Body: ðpb.BeaconBlockBody{Deposits: deposits}}})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not process deposit")
|
||||
}
|
||||
@@ -66,10 +67,14 @@ func ProcessPreGenesisDeposits(
|
||||
func ProcessDeposits(
|
||||
ctx context.Context,
|
||||
beaconState *stateTrie.BeaconState,
|
||||
deposits []*ethpb.Deposit,
|
||||
b *ethpb.SignedBeaconBlock,
|
||||
) (*stateTrie.BeaconState, error) {
|
||||
var err error
|
||||
if b.Block == nil || b.Block.Body == nil {
|
||||
return nil, errors.New("block and block body can't be nil")
|
||||
}
|
||||
|
||||
deposits := b.Block.Body.Deposits
|
||||
var err error
|
||||
domain, err := helpers.ComputeDomain(params.BeaconConfig().DomainDeposit, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -197,7 +202,7 @@ func verifyDeposit(beaconState *stateTrie.BeaconState, deposit *ethpb.Deposit) e
|
||||
}
|
||||
|
||||
receiptRoot := eth1Data.DepositRoot
|
||||
leaf, err := ssz.HashTreeRoot(deposit.Data)
|
||||
leaf, err := deposit.Data.HashTreeRoot()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not tree hash deposit data")
|
||||
}
|
||||
@@ -206,12 +211,14 @@ func verifyDeposit(beaconState *stateTrie.BeaconState, deposit *ethpb.Deposit) e
|
||||
leaf[:],
|
||||
int(beaconState.Eth1DepositIndex()),
|
||||
deposit.Proof,
|
||||
params.BeaconConfig().DepositContractTreeDepth,
|
||||
); !ok {
|
||||
return fmt.Errorf(
|
||||
"deposit merkle branch of deposit root did not verify for root: %#x",
|
||||
receiptRoot,
|
||||
)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -225,7 +232,7 @@ func verifyDepositDataWithDomain(ctx context.Context, deps []*ethpb.Deposit, dom
|
||||
return nil
|
||||
}
|
||||
pks := make([]bls.PublicKey, len(deps))
|
||||
sigs := make([]bls.Signature, len(deps))
|
||||
sigs := make([][]byte, len(deps))
|
||||
msgs := make([][32]byte, len(deps))
|
||||
for i, dep := range deps {
|
||||
if ctx.Err() != nil {
|
||||
@@ -234,17 +241,12 @@ func verifyDepositDataWithDomain(ctx context.Context, deps []*ethpb.Deposit, dom
|
||||
if dep == nil || dep.Data == nil {
|
||||
return errors.New("nil deposit")
|
||||
}
|
||||
|
||||
dpk, err := bls.PublicKeyFromBytes(dep.Data.PublicKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pks[i] = dpk
|
||||
dsig, err := bls.SignatureFromBytes(dep.Data.Signature)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sigs[i] = dsig
|
||||
sigs[i] = dep.Data.Signature
|
||||
root, err := ssz.SigningRoot(dep.Data)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get signing root")
|
||||
@@ -253,7 +255,7 @@ func verifyDepositDataWithDomain(ctx context.Context, deps []*ethpb.Deposit, dom
|
||||
ObjectRoot: root[:],
|
||||
Domain: domain,
|
||||
}
|
||||
ctrRoot, err := ssz.HashTreeRoot(signingData)
|
||||
ctrRoot, err := signingData.HashTreeRoot()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get container root")
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ 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/beacon-chain/core/helpers"
|
||||
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
@@ -26,7 +25,8 @@ func TestProcessDeposits_SameValidatorMultipleDepositsSameBlock(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
eth1Data, err := testutil.DeterministicEth1Data(len(dep))
|
||||
require.NoError(t, err)
|
||||
block := ðpb.BeaconBlock{
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block = ðpb.BeaconBlock{
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
// 3 deposits from the same validator
|
||||
Deposits: []*ethpb.Deposit{dep[0], dep[1], dep[2]},
|
||||
@@ -49,7 +49,7 @@ func TestProcessDeposits_SameValidatorMultipleDepositsSameBlock(t *testing.T) {
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
newState, err := blocks.ProcessDeposits(context.Background(), beaconState, block.Body.Deposits)
|
||||
newState, err := blocks.ProcessDeposits(context.Background(), beaconState, b)
|
||||
require.NoError(t, err, "Expected block deposits to process correctly")
|
||||
|
||||
assert.Equal(t, 2, len(newState.Validators()), "Incorrect validator count")
|
||||
@@ -58,11 +58,12 @@ func TestProcessDeposits_SameValidatorMultipleDepositsSameBlock(t *testing.T) {
|
||||
func TestProcessDeposits_MerkleBranchFailsVerification(t *testing.T) {
|
||||
deposit := ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: []byte{1, 2, 3},
|
||||
Signature: make([]byte, 96),
|
||||
PublicKey: bytesutil.PadTo([]byte{1, 2, 3}, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
}
|
||||
leaf, err := ssz.HashTreeRoot(deposit.Data)
|
||||
leaf, err := deposit.Data.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
// We then create a merkle branch for the test.
|
||||
@@ -72,7 +73,8 @@ func TestProcessDeposits_MerkleBranchFailsVerification(t *testing.T) {
|
||||
require.NoError(t, err, "Could not generate proof")
|
||||
|
||||
deposit.Proof = proof
|
||||
block := ðpb.BeaconBlock{
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block = ðpb.BeaconBlock{
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
Deposits: []*ethpb.Deposit{deposit},
|
||||
},
|
||||
@@ -85,7 +87,7 @@ func TestProcessDeposits_MerkleBranchFailsVerification(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
want := "deposit root did not verify"
|
||||
_, err = blocks.ProcessDeposits(context.Background(), beaconState, block.Body.Deposits)
|
||||
_, err = blocks.ProcessDeposits(context.Background(), beaconState, b)
|
||||
assert.ErrorContains(t, want, err)
|
||||
}
|
||||
|
||||
@@ -95,7 +97,8 @@ func TestProcessDeposits_AddsNewValidatorDeposit(t *testing.T) {
|
||||
eth1Data, err := testutil.DeterministicEth1Data(len(dep))
|
||||
require.NoError(t, err)
|
||||
|
||||
block := ðpb.BeaconBlock{
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block = ðpb.BeaconBlock{
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
Deposits: []*ethpb.Deposit{dep[0]},
|
||||
},
|
||||
@@ -117,7 +120,7 @@ func TestProcessDeposits_AddsNewValidatorDeposit(t *testing.T) {
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
newState, err := blocks.ProcessDeposits(context.Background(), beaconState, block.Body.Deposits)
|
||||
newState, err := blocks.ProcessDeposits(context.Background(), beaconState, b)
|
||||
require.NoError(t, err, "Expected block deposits to process correctly")
|
||||
if newState.Balances()[1] != dep[0].Data.Amount {
|
||||
t.Errorf(
|
||||
@@ -132,15 +135,17 @@ func TestProcessDeposits_RepeatedDeposit_IncreasesValidatorBalance(t *testing.T)
|
||||
sk := bls.RandKey()
|
||||
deposit := ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: sk.PublicKey().Marshal(),
|
||||
Amount: 1000,
|
||||
PublicKey: sk.PublicKey().Marshal(),
|
||||
Amount: 1000,
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
}
|
||||
sr, err := helpers.ComputeSigningRoot(deposit.Data, bytesutil.ToBytes(3, 8))
|
||||
sr, err := helpers.ComputeSigningRoot(deposit.Data, bytesutil.ToBytes(3, 32))
|
||||
require.NoError(t, err)
|
||||
sig := sk.Sign(sr[:])
|
||||
deposit.Data.Signature = sig.Marshal()
|
||||
leaf, err := ssz.HashTreeRoot(deposit.Data)
|
||||
leaf, err := deposit.Data.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
// We then create a merkle branch for the test.
|
||||
@@ -150,7 +155,8 @@ func TestProcessDeposits_RepeatedDeposit_IncreasesValidatorBalance(t *testing.T)
|
||||
require.NoError(t, err, "Could not generate proof")
|
||||
|
||||
deposit.Proof = proof
|
||||
block := ðpb.BeaconBlock{
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block = ðpb.BeaconBlock{
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
Deposits: []*ethpb.Deposit{deposit},
|
||||
},
|
||||
@@ -175,7 +181,7 @@ func TestProcessDeposits_RepeatedDeposit_IncreasesValidatorBalance(t *testing.T)
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
newState, err := blocks.ProcessDeposits(context.Background(), beaconState, block.Body.Deposits)
|
||||
newState, err := blocks.ProcessDeposits(context.Background(), beaconState, b)
|
||||
require.NoError(t, err, "Process deposit failed")
|
||||
assert.Equal(t, uint64(1000+50), newState.Balances()[1], "Expected balance at index 1 to be 1050")
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package blocks
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
@@ -18,7 +19,8 @@ import (
|
||||
// state.eth1_data_votes.append(body.eth1_data)
|
||||
// if state.eth1_data_votes.count(body.eth1_data) * 2 > EPOCHS_PER_ETH1_VOTING_PERIOD * SLOTS_PER_EPOCH:
|
||||
// state.latest_eth1_data = body.eth1_data
|
||||
func ProcessEth1DataInBlock(beaconState *stateTrie.BeaconState, block *ethpb.BeaconBlock) (*stateTrie.BeaconState, error) {
|
||||
func ProcessEth1DataInBlock(ctx context.Context, beaconState *stateTrie.BeaconState, b *ethpb.SignedBeaconBlock) (*stateTrie.BeaconState, error) {
|
||||
block := b.Block
|
||||
if beaconState == nil {
|
||||
return nil, errors.New("nil state")
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package blocks_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
@@ -9,7 +10,9 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
beaconstate "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
@@ -19,7 +22,7 @@ func FakeDeposits(n uint64) []*ethpb.Eth1Data {
|
||||
for i := uint64(0); i < n; i++ {
|
||||
deposits[i] = ðpb.Eth1Data{
|
||||
DepositCount: 1,
|
||||
DepositRoot: []byte("root"),
|
||||
DepositRoot: bytesutil.PadTo([]byte("root"), 32),
|
||||
}
|
||||
}
|
||||
return deposits
|
||||
@@ -36,7 +39,7 @@ func TestEth1DataHasEnoughSupport(t *testing.T) {
|
||||
stateVotes: FakeDeposits(4 * params.BeaconConfig().SlotsPerEpoch),
|
||||
data: ðpb.Eth1Data{
|
||||
DepositCount: 1,
|
||||
DepositRoot: []byte("root"),
|
||||
DepositRoot: bytesutil.PadTo([]byte("root"), 32),
|
||||
},
|
||||
hasSupport: true,
|
||||
votingPeriodLength: 7,
|
||||
@@ -44,7 +47,7 @@ func TestEth1DataHasEnoughSupport(t *testing.T) {
|
||||
stateVotes: FakeDeposits(4 * params.BeaconConfig().SlotsPerEpoch),
|
||||
data: ðpb.Eth1Data{
|
||||
DepositCount: 1,
|
||||
DepositRoot: []byte("root"),
|
||||
DepositRoot: bytesutil.PadTo([]byte("root"), 32),
|
||||
},
|
||||
hasSupport: false,
|
||||
votingPeriodLength: 8,
|
||||
@@ -52,7 +55,7 @@ func TestEth1DataHasEnoughSupport(t *testing.T) {
|
||||
stateVotes: FakeDeposits(4 * params.BeaconConfig().SlotsPerEpoch),
|
||||
data: ðpb.Eth1Data{
|
||||
DepositCount: 1,
|
||||
DepositRoot: []byte("root"),
|
||||
DepositRoot: bytesutil.PadTo([]byte("root"), 32),
|
||||
},
|
||||
hasSupport: false,
|
||||
votingPeriodLength: 10,
|
||||
@@ -161,7 +164,8 @@ func TestProcessEth1Data_SetsCorrectly(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
block := ðpb.BeaconBlock{
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block = ðpb.BeaconBlock{
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
Eth1Data: ðpb.Eth1Data{
|
||||
DepositRoot: []byte{2},
|
||||
@@ -172,7 +176,7 @@ func TestProcessEth1Data_SetsCorrectly(t *testing.T) {
|
||||
|
||||
period := params.BeaconConfig().EpochsPerEth1VotingPeriod * params.BeaconConfig().SlotsPerEpoch
|
||||
for i := uint64(0); i < period; i++ {
|
||||
beaconState, err = blocks.ProcessEth1DataInBlock(beaconState, block)
|
||||
beaconState, err = blocks.ProcessEth1DataInBlock(context.Background(), beaconState, b)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
@@ -180,10 +184,10 @@ func TestProcessEth1Data_SetsCorrectly(t *testing.T) {
|
||||
if len(newETH1DataVotes) <= 1 {
|
||||
t.Error("Expected new ETH1 data votes to have length > 1")
|
||||
}
|
||||
if !proto.Equal(beaconState.Eth1Data(), beaconstate.CopyETH1Data(block.Body.Eth1Data)) {
|
||||
if !proto.Equal(beaconState.Eth1Data(), beaconstate.CopyETH1Data(b.Block.Body.Eth1Data)) {
|
||||
t.Errorf(
|
||||
"Expected latest eth1 data to have been set to %v, received %v",
|
||||
block.Body.Eth1Data,
|
||||
b.Block.Body.Eth1Data,
|
||||
beaconState.Eth1Data(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -39,8 +39,13 @@ import (
|
||||
func ProcessVoluntaryExits(
|
||||
ctx context.Context,
|
||||
beaconState *stateTrie.BeaconState,
|
||||
body *ethpb.BeaconBlockBody,
|
||||
b *ethpb.SignedBeaconBlock,
|
||||
) (*stateTrie.BeaconState, error) {
|
||||
if b.Block == nil || b.Block.Body == nil {
|
||||
return nil, errors.New("block and block body can't be nil")
|
||||
}
|
||||
|
||||
body := b.Block.Body
|
||||
exits := body.VoluntaryExits
|
||||
for idx, exit := range exits {
|
||||
if exit == nil || exit.Exit == nil {
|
||||
@@ -50,7 +55,7 @@ func ProcessVoluntaryExits(
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := VerifyExit(val, beaconState.Slot(), beaconState.Fork(), exit, beaconState.GenesisValidatorRoot()); err != nil {
|
||||
if err := VerifyExitAndSignature(val, beaconState.Slot(), beaconState.Fork(), exit, beaconState.GenesisValidatorRoot()); err != nil {
|
||||
return nil, errors.Wrapf(err, "could not verify exit %d", idx)
|
||||
}
|
||||
beaconState, err = v.InitiateValidatorExit(beaconState, exit.Exit.ValidatorIndex)
|
||||
@@ -61,9 +66,10 @@ func ProcessVoluntaryExits(
|
||||
return beaconState, nil
|
||||
}
|
||||
|
||||
// ProcessVoluntaryExitsNoVerify processes all the voluntary exits in
|
||||
// ProcessVoluntaryExitsNoVerifySignature processes all the voluntary exits in
|
||||
// a block body, without verifying their BLS signatures.
|
||||
func ProcessVoluntaryExitsNoVerify(
|
||||
// This function is here to satisfy fuzz tests.
|
||||
func ProcessVoluntaryExitsNoVerifySignature(
|
||||
beaconState *stateTrie.BeaconState,
|
||||
body *ethpb.BeaconBlockBody,
|
||||
) (*stateTrie.BeaconState, error) {
|
||||
@@ -93,7 +99,7 @@ func ProcessVoluntaryExitsNoVerify(
|
||||
return beaconState, nil
|
||||
}
|
||||
|
||||
// VerifyExit implements the spec defined validation for voluntary exits.
|
||||
// VerifyExitAndSignature implements the spec defined validation for voluntary exits.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// def process_voluntary_exit(state: BeaconState, exit: VoluntaryExit) -> None:
|
||||
@@ -112,7 +118,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 *stateTrie.ReadOnlyValidator, currentSlot uint64, fork *pb.Fork, signed *ethpb.SignedVoluntaryExit, genesisRoot []byte) error {
|
||||
func VerifyExitAndSignature(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")
|
||||
}
|
||||
@@ -154,9 +160,11 @@ func verifyExitConditions(validator *stateTrie.ReadOnlyValidator, currentSlot ui
|
||||
if !helpers.IsActiveValidatorUsingTrie(validator, currentEpoch) {
|
||||
return errors.New("non-active validator cannot exit")
|
||||
}
|
||||
// Verify the validator has not yet exited.
|
||||
// Verify the validator has not yet submitted an exit.
|
||||
if validator.ExitEpoch() != params.BeaconConfig().FarFutureEpoch {
|
||||
return fmt.Errorf("validator has already exited at epoch: %v", validator.ExitEpoch())
|
||||
return fmt.Errorf(
|
||||
"validator has already submitted an exit, which will take place at epoch: %v",
|
||||
validator.ExitEpoch())
|
||||
}
|
||||
// Exits must specify an epoch when they become valid; they are not valid before then.
|
||||
if currentEpoch < exit.Epoch {
|
||||
@@ -165,7 +173,7 @@ func verifyExitConditions(validator *stateTrie.ReadOnlyValidator, currentSlot ui
|
||||
// Verify the validator has been active long enough.
|
||||
if currentEpoch < validator.ActivationEpoch()+params.BeaconConfig().ShardCommitteePeriod {
|
||||
return fmt.Errorf(
|
||||
"validator has not been active long enough to exit, wanted epoch %d >= %d",
|
||||
"validator has not been active long enough to exit: %d epochs vs required %d epochs",
|
||||
currentEpoch,
|
||||
validator.ActivationEpoch()+params.BeaconConfig().ShardCommitteePeriod,
|
||||
)
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
@@ -32,18 +33,19 @@ func TestProcessVoluntaryExits_ValidatorNotActive(t *testing.T) {
|
||||
Validators: registry,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
block := ðpb.BeaconBlock{
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block = ðpb.BeaconBlock{
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
VoluntaryExits: exits,
|
||||
},
|
||||
}
|
||||
|
||||
want := "non-active validator cannot exit"
|
||||
_, err = blocks.ProcessVoluntaryExits(context.Background(), state, block.Body)
|
||||
_, err = blocks.ProcessVoluntaryExits(context.Background(), state, b)
|
||||
assert.ErrorContains(t, want, err)
|
||||
|
||||
// Check conformance of no verify method.
|
||||
_, err = blocks.ProcessVoluntaryExitsNoVerify(state, block.Body)
|
||||
_, err = blocks.ProcessVoluntaryExitsNoVerifySignature(state, b.Block.Body)
|
||||
assert.ErrorContains(t, want, err)
|
||||
}
|
||||
|
||||
@@ -65,20 +67,20 @@ func TestProcessVoluntaryExits_InvalidExitEpoch(t *testing.T) {
|
||||
Slot: 0,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
block := ðpb.BeaconBlock{
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block = ðpb.BeaconBlock{
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
VoluntaryExits: exits,
|
||||
},
|
||||
}
|
||||
|
||||
want := "expected current epoch >= exit epoch"
|
||||
_, err = blocks.ProcessVoluntaryExits(context.Background(), state, block.Body)
|
||||
_, err = blocks.ProcessVoluntaryExits(context.Background(), state, b)
|
||||
assert.ErrorContains(t, want, err)
|
||||
|
||||
// Check conformance of no verify method.
|
||||
_, err = blocks.ProcessVoluntaryExitsNoVerify(state, block.Body)
|
||||
_, err = blocks.ProcessVoluntaryExitsNoVerifySignature(state, b.Block.Body)
|
||||
assert.ErrorContains(t, want, err)
|
||||
|
||||
}
|
||||
|
||||
func TestProcessVoluntaryExits_NotActiveLongEnoughToExit(t *testing.T) {
|
||||
@@ -100,14 +102,45 @@ func TestProcessVoluntaryExits_NotActiveLongEnoughToExit(t *testing.T) {
|
||||
Slot: 10,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
block := ðpb.BeaconBlock{
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block = ðpb.BeaconBlock{
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
VoluntaryExits: exits,
|
||||
},
|
||||
}
|
||||
|
||||
want := "validator has not been active long enough to exit"
|
||||
_, err = blocks.ProcessVoluntaryExits(context.Background(), state, block.Body)
|
||||
_, err = blocks.ProcessVoluntaryExits(context.Background(), state, b)
|
||||
assert.ErrorContains(t, want, err)
|
||||
}
|
||||
|
||||
func TestProcessVoluntaryExits_ExitAlreadySubmitted(t *testing.T) {
|
||||
exits := []*ethpb.SignedVoluntaryExit{
|
||||
{
|
||||
Exit: ðpb.VoluntaryExit{
|
||||
Epoch: 10,
|
||||
},
|
||||
},
|
||||
}
|
||||
registry := []*ethpb.Validator{
|
||||
{
|
||||
ExitEpoch: 10,
|
||||
},
|
||||
}
|
||||
state, err := stateTrie.InitializeFromProto(&pb.BeaconState{
|
||||
Validators: registry,
|
||||
Slot: 0,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block = ðpb.BeaconBlock{
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
VoluntaryExits: exits,
|
||||
},
|
||||
}
|
||||
|
||||
want := "validator has already submitted an exit, which will take place at epoch: 10"
|
||||
_, err = blocks.ProcessVoluntaryExits(context.Background(), state, b)
|
||||
assert.ErrorContains(t, want, err)
|
||||
}
|
||||
|
||||
@@ -141,19 +174,20 @@ func TestProcessVoluntaryExits_AppliesCorrectStatus(t *testing.T) {
|
||||
priv := bls.RandKey()
|
||||
val, err := state.ValidatorAtIndex(0)
|
||||
require.NoError(t, err)
|
||||
val.PublicKey = priv.PublicKey().Marshal()[:]
|
||||
val.PublicKey = priv.PublicKey().Marshal()
|
||||
require.NoError(t, state.UpdateValidatorAtIndex(0, val))
|
||||
exits[0].Signature, err = helpers.ComputeDomainAndSign(state, helpers.CurrentEpoch(state), exits[0].Exit, params.BeaconConfig().DomainVoluntaryExit, priv)
|
||||
require.NoError(t, err)
|
||||
|
||||
block := ðpb.BeaconBlock{
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block = ðpb.BeaconBlock{
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
VoluntaryExits: exits,
|
||||
},
|
||||
}
|
||||
|
||||
stateCopy := state.Copy()
|
||||
newState, err := blocks.ProcessVoluntaryExits(context.Background(), state, block.Body)
|
||||
newState, err := blocks.ProcessVoluntaryExits(context.Background(), state, b)
|
||||
require.NoError(t, err, "Could not process exits")
|
||||
newRegistry := newState.Validators()
|
||||
if newRegistry[0].ExitEpoch != helpers.ActivationExitEpoch(state.Slot()/params.BeaconConfig().SlotsPerEpoch) {
|
||||
@@ -162,12 +196,11 @@ func TestProcessVoluntaryExits_AppliesCorrectStatus(t *testing.T) {
|
||||
}
|
||||
|
||||
// Check conformance with NoVerify Exit Method.
|
||||
newState, err = blocks.ProcessVoluntaryExitsNoVerify(stateCopy, block.Body)
|
||||
newState, err = blocks.ProcessVoluntaryExitsNoVerifySignature(stateCopy, b.Block.Body)
|
||||
require.NoError(t, err, "Could not process exits")
|
||||
newRegistry = newState.Validators()
|
||||
if newRegistry[0].ExitEpoch != helpers.ActivationExitEpoch(stateCopy.Slot()/params.BeaconConfig().SlotsPerEpoch) {
|
||||
t.Errorf("Expected validator exit epoch to be %d, got %d",
|
||||
helpers.ActivationExitEpoch(stateCopy.Slot()/params.BeaconConfig().SlotsPerEpoch), newRegistry[0].ExitEpoch)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,19 +4,27 @@ package blocks
|
||||
|
||||
import (
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
// NewGenesisBlock returns the canonical, genesis block for the beacon chain protocol.
|
||||
func NewGenesisBlock(stateRoot []byte) *ethpb.SignedBeaconBlock {
|
||||
zeroHash := params.BeaconConfig().ZeroHash[:]
|
||||
genBlock := ðpb.BeaconBlock{
|
||||
ParentRoot: zeroHash,
|
||||
StateRoot: stateRoot,
|
||||
Body: ðpb.BeaconBlockBody{},
|
||||
}
|
||||
return ðpb.SignedBeaconBlock{
|
||||
Block: genBlock,
|
||||
block := ðpb.SignedBeaconBlock{
|
||||
Block: ðpb.BeaconBlock{
|
||||
ParentRoot: zeroHash,
|
||||
StateRoot: bytesutil.PadTo(stateRoot, 32),
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
RandaoReveal: make([]byte, 96),
|
||||
Eth1Data: ðpb.Eth1Data{
|
||||
DepositRoot: make([]byte, 32),
|
||||
BlockHash: make([]byte, 32),
|
||||
},
|
||||
Graffiti: make([]byte, 32),
|
||||
},
|
||||
},
|
||||
Signature: params.BeaconConfig().EmptySignature[:],
|
||||
}
|
||||
return block
|
||||
}
|
||||
|
||||
@@ -4,11 +4,12 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
)
|
||||
|
||||
func TestGenesisBlock_InitializedCorrectly(t *testing.T) {
|
||||
stateHash := []byte{0}
|
||||
stateHash := bytesutil.PadTo([]byte{0}, 32)
|
||||
b1 := blocks.NewGenesisBlock(stateHash)
|
||||
|
||||
assert.NotNil(t, b1.Block.ParentRoot, "Genesis block missing ParentHash field")
|
||||
|
||||
@@ -2,13 +2,13 @@ package blocks
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"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/params"
|
||||
)
|
||||
|
||||
@@ -37,6 +37,7 @@ import (
|
||||
// # Verify proposer signature
|
||||
// assert bls_verify(proposer.pubkey, signing_root(block), block.signature, get_domain(state, DOMAIN_BEACON_PROPOSER))
|
||||
func ProcessBlockHeader(
|
||||
ctx context.Context,
|
||||
beaconState *stateTrie.BeaconState,
|
||||
block *ethpb.SignedBeaconBlock,
|
||||
) (*stateTrie.BeaconState, error) {
|
||||
@@ -99,7 +100,7 @@ func ProcessBlockHeaderNoVerify(
|
||||
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)
|
||||
parentRoot, err := parentHeader.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -118,7 +119,7 @@ func ProcessBlockHeaderNoVerify(
|
||||
return nil, fmt.Errorf("proposer at index %d was previously slashed", idx)
|
||||
}
|
||||
|
||||
bodyRoot, err := stateutil.BlockBodyRoot(block.Body)
|
||||
bodyRoot, err := block.Body.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -1,23 +1,22 @@
|
||||
package blocks_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/go-ssz"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
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/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -28,40 +27,35 @@ 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,
|
||||
PublicKey: make([]byte, 32),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
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),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
state := testutil.NewBeaconState()
|
||||
require.NoError(t, state.SetSlot(10))
|
||||
require.NoError(t, state.SetValidators(validators))
|
||||
require.NoError(t, state.SetLatestBlockHeader(ðpb.BeaconBlockHeader{
|
||||
Slot: 10, // Must be less than block.Slot
|
||||
ParentRoot: make([]byte, 32),
|
||||
StateRoot: make([]byte, 32),
|
||||
BodyRoot: make([]byte, 32),
|
||||
}))
|
||||
|
||||
latestBlockSignedRoot, err := stateutil.BlockHeaderRoot(state.LatestBlockHeader())
|
||||
latestBlockSignedRoot, err := state.LatestBlockHeader().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
currentEpoch := helpers.CurrentEpoch(state)
|
||||
priv := bls.RandKey()
|
||||
pID, err := helpers.BeaconProposerIndex(state)
|
||||
require.NoError(t, err)
|
||||
block := ðpb.SignedBeaconBlock{
|
||||
Block: ðpb.BeaconBlock{
|
||||
ProposerIndex: pID,
|
||||
Slot: 10,
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
RandaoReveal: []byte{'A', 'B', 'C'},
|
||||
},
|
||||
ParentRoot: latestBlockSignedRoot[:],
|
||||
},
|
||||
}
|
||||
block := testutil.NewBeaconBlock()
|
||||
block.Block.ProposerIndex = pID
|
||||
block.Block.Slot = 10
|
||||
block.Block.Body.RandaoReveal = bytesutil.PadTo([]byte{'A', 'B', 'C'}, 96)
|
||||
block.Block.ParentRoot = latestBlockSignedRoot[:]
|
||||
block.Signature, err = helpers.ComputeDomainAndSign(state, currentEpoch, block.Block, params.BeaconConfig().DomainBeaconProposer, priv)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -72,36 +66,36 @@ func TestProcessBlockHeader_ImproperBlockSlot(t *testing.T) {
|
||||
err = state.UpdateValidatorAtIndex(proposerIdx, validators[proposerIdx])
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = blocks.ProcessBlockHeader(state, block)
|
||||
_, err = blocks.ProcessBlockHeader(context.Background(), state, block)
|
||||
assert.ErrorContains(t, "block.Slot 10 must be greater than state.LatestBlockHeader.Slot 10", err)
|
||||
}
|
||||
|
||||
func TestProcessBlockHeader_WrongProposerSig(t *testing.T) {
|
||||
testutil.ResetCache()
|
||||
beaconState, privKeys := testutil.DeterministicGenesisState(t, 100)
|
||||
require.NoError(t, beaconState.SetLatestBlockHeader(ðpb.BeaconBlockHeader{Slot: 9}))
|
||||
require.NoError(t, beaconState.SetLatestBlockHeader(ðpb.BeaconBlockHeader{
|
||||
Slot: 9,
|
||||
ParentRoot: make([]byte, 32),
|
||||
StateRoot: make([]byte, 32),
|
||||
BodyRoot: make([]byte, 32),
|
||||
}))
|
||||
require.NoError(t, beaconState.SetSlot(10))
|
||||
|
||||
lbhdr, err := stateutil.BlockHeaderRoot(beaconState.LatestBlockHeader())
|
||||
lbhdr, err := beaconState.LatestBlockHeader().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
proposerIdx, err := helpers.BeaconProposerIndex(beaconState)
|
||||
require.NoError(t, err)
|
||||
|
||||
block := ðpb.SignedBeaconBlock{
|
||||
Block: ðpb.BeaconBlock{
|
||||
ProposerIndex: proposerIdx,
|
||||
Slot: 10,
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
RandaoReveal: []byte{'A', 'B', 'C'},
|
||||
},
|
||||
ParentRoot: lbhdr[:],
|
||||
},
|
||||
}
|
||||
block := testutil.NewBeaconBlock()
|
||||
block.Block.ProposerIndex = proposerIdx
|
||||
block.Block.Slot = 10
|
||||
block.Block.Body.RandaoReveal = bytesutil.PadTo([]byte{'A', 'B', 'C'}, 96)
|
||||
block.Block.ParentRoot = lbhdr[:]
|
||||
block.Signature, err = helpers.ComputeDomainAndSign(beaconState, 0, block.Block, params.BeaconConfig().DomainBeaconProposer, privKeys[proposerIdx+1])
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = blocks.ProcessBlockHeader(beaconState, block)
|
||||
_, err = blocks.ProcessBlockHeader(context.Background(), beaconState, block)
|
||||
want := "signature did not verify"
|
||||
assert.ErrorContains(t, want, err)
|
||||
}
|
||||
@@ -110,24 +104,25 @@ func TestProcessBlockHeader_DifferentSlots(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,
|
||||
PublicKey: make([]byte, 32),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
Slashed: true,
|
||||
}
|
||||
}
|
||||
|
||||
state, err := stateTrie.InitializeFromProto(&pb.BeaconState{
|
||||
Validators: validators,
|
||||
Slot: 10,
|
||||
LatestBlockHeader: ðpb.BeaconBlockHeader{Slot: 9},
|
||||
Fork: &pb.Fork{
|
||||
PreviousVersion: []byte{0, 0, 0, 0},
|
||||
CurrentVersion: []byte{0, 0, 0, 0},
|
||||
},
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
state := testutil.NewBeaconState()
|
||||
require.NoError(t, state.SetValidators(validators))
|
||||
require.NoError(t, state.SetSlot(10))
|
||||
require.NoError(t, state.SetLatestBlockHeader(ðpb.BeaconBlockHeader{
|
||||
Slot: 9,
|
||||
ProposerIndex: 0,
|
||||
ParentRoot: make([]byte, 32),
|
||||
StateRoot: make([]byte, 32),
|
||||
BodyRoot: make([]byte, 32),
|
||||
}))
|
||||
|
||||
lbhsr, err := ssz.HashTreeRoot(state.LatestBlockHeader())
|
||||
lbhsr, err := state.LatestBlockHeader().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
currentEpoch := helpers.CurrentEpoch(state)
|
||||
|
||||
@@ -146,7 +141,7 @@ func TestProcessBlockHeader_DifferentSlots(t *testing.T) {
|
||||
Signature: blockSig,
|
||||
}
|
||||
|
||||
_, err = blocks.ProcessBlockHeader(state, block)
|
||||
_, err = blocks.ProcessBlockHeader(context.Background(), state, block)
|
||||
want := "is different than block slot"
|
||||
assert.ErrorContains(t, want, err)
|
||||
}
|
||||
@@ -155,23 +150,19 @@ func TestProcessBlockHeader_PreviousBlockRootNotSignedRoot(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,
|
||||
PublicKey: make([]byte, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
Slashed: true,
|
||||
}
|
||||
}
|
||||
|
||||
state, err := stateTrie.InitializeFromProto(&pb.BeaconState{
|
||||
Validators: validators,
|
||||
Slot: 10,
|
||||
LatestBlockHeader: ðpb.BeaconBlockHeader{Slot: 9},
|
||||
Fork: &pb.Fork{
|
||||
PreviousVersion: []byte{0, 0, 0, 0},
|
||||
CurrentVersion: []byte{0, 0, 0, 0},
|
||||
},
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
state := testutil.NewBeaconState()
|
||||
require.NoError(t, state.SetValidators(validators))
|
||||
require.NoError(t, state.SetSlot(10))
|
||||
bh := state.LatestBlockHeader()
|
||||
bh.Slot = 9
|
||||
require.NoError(t, state.SetLatestBlockHeader(bh))
|
||||
currentEpoch := helpers.CurrentEpoch(state)
|
||||
priv := bls.RandKey()
|
||||
blockSig, err := helpers.ComputeDomainAndSign(state, currentEpoch, []byte("hello"), params.BeaconConfig().DomainBeaconProposer, priv)
|
||||
@@ -179,19 +170,14 @@ func TestProcessBlockHeader_PreviousBlockRootNotSignedRoot(t *testing.T) {
|
||||
validators[5896].PublicKey = priv.PublicKey().Marshal()
|
||||
pID, err := helpers.BeaconProposerIndex(state)
|
||||
require.NoError(t, err)
|
||||
block := ðpb.SignedBeaconBlock{
|
||||
Block: ðpb.BeaconBlock{
|
||||
ProposerIndex: pID,
|
||||
Slot: 10,
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
RandaoReveal: []byte{'A', 'B', 'C'},
|
||||
},
|
||||
ParentRoot: []byte{'A'},
|
||||
},
|
||||
Signature: blockSig,
|
||||
}
|
||||
block := testutil.NewBeaconBlock()
|
||||
block.Block.Slot = 10
|
||||
block.Block.ProposerIndex = pID
|
||||
block.Block.Body.RandaoReveal = bytesutil.PadTo([]byte{'A', 'B', 'C'}, 96)
|
||||
block.Block.ParentRoot = bytesutil.PadTo([]byte{'A'}, 32)
|
||||
block.Signature = blockSig
|
||||
|
||||
_, err = blocks.ProcessBlockHeader(state, block)
|
||||
_, err = blocks.ProcessBlockHeader(context.Background(), state, block)
|
||||
want := "does not match"
|
||||
assert.ErrorContains(t, want, err)
|
||||
}
|
||||
@@ -200,24 +186,20 @@ func TestProcessBlockHeader_SlashedProposer(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,
|
||||
PublicKey: make([]byte, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
Slashed: true,
|
||||
}
|
||||
}
|
||||
|
||||
state, err := stateTrie.InitializeFromProto(&pb.BeaconState{
|
||||
Validators: validators,
|
||||
Slot: 10,
|
||||
LatestBlockHeader: ðpb.BeaconBlockHeader{Slot: 9},
|
||||
Fork: &pb.Fork{
|
||||
PreviousVersion: []byte{0, 0, 0, 0},
|
||||
CurrentVersion: []byte{0, 0, 0, 0},
|
||||
},
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
parentRoot, err := stateutil.BlockHeaderRoot(state.LatestBlockHeader())
|
||||
state := testutil.NewBeaconState()
|
||||
require.NoError(t, state.SetValidators(validators))
|
||||
require.NoError(t, state.SetSlot(10))
|
||||
bh := state.LatestBlockHeader()
|
||||
bh.Slot = 9
|
||||
require.NoError(t, state.SetLatestBlockHeader(bh))
|
||||
parentRoot, err := state.LatestBlockHeader().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
currentEpoch := helpers.CurrentEpoch(state)
|
||||
priv := bls.RandKey()
|
||||
@@ -227,19 +209,14 @@ func TestProcessBlockHeader_SlashedProposer(t *testing.T) {
|
||||
validators[12683].PublicKey = priv.PublicKey().Marshal()
|
||||
pID, err := helpers.BeaconProposerIndex(state)
|
||||
require.NoError(t, err)
|
||||
block := ðpb.SignedBeaconBlock{
|
||||
Block: ðpb.BeaconBlock{
|
||||
ProposerIndex: pID,
|
||||
Slot: 10,
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
RandaoReveal: []byte{'A', 'B', 'C'},
|
||||
},
|
||||
ParentRoot: parentRoot[:],
|
||||
},
|
||||
Signature: blockSig,
|
||||
}
|
||||
block := testutil.NewBeaconBlock()
|
||||
block.Block.Slot = 10
|
||||
block.Block.ProposerIndex = pID
|
||||
block.Block.Body.RandaoReveal = bytesutil.PadTo([]byte{'A', 'B', 'C'}, 96)
|
||||
block.Block.ParentRoot = parentRoot[:]
|
||||
block.Signature = blockSig
|
||||
|
||||
_, err = blocks.ProcessBlockHeader(state, block)
|
||||
_, err = blocks.ProcessBlockHeader(context.Background(), state, block)
|
||||
want := "was previously slashed"
|
||||
assert.ErrorContains(t, want, err)
|
||||
}
|
||||
@@ -248,43 +225,39 @@ func TestProcessBlockHeader_OK(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,
|
||||
PublicKey: make([]byte, 32),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
Slashed: true,
|
||||
}
|
||||
}
|
||||
|
||||
state, err := stateTrie.InitializeFromProto(&pb.BeaconState{
|
||||
Validators: validators,
|
||||
Slot: 10,
|
||||
LatestBlockHeader: ðpb.BeaconBlockHeader{Slot: 9},
|
||||
Fork: &pb.Fork{
|
||||
PreviousVersion: []byte{0, 0, 0, 0},
|
||||
CurrentVersion: []byte{0, 0, 0, 0},
|
||||
},
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
state := testutil.NewBeaconState()
|
||||
require.NoError(t, state.SetValidators(validators))
|
||||
require.NoError(t, state.SetSlot(10))
|
||||
require.NoError(t, state.SetLatestBlockHeader(ðpb.BeaconBlockHeader{
|
||||
Slot: 9,
|
||||
ProposerIndex: 0,
|
||||
ParentRoot: make([]byte, 32),
|
||||
StateRoot: make([]byte, 32),
|
||||
BodyRoot: make([]byte, 32),
|
||||
}))
|
||||
|
||||
latestBlockSignedRoot, err := stateutil.BlockHeaderRoot(state.LatestBlockHeader())
|
||||
latestBlockSignedRoot, err := state.LatestBlockHeader().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
currentEpoch := helpers.CurrentEpoch(state)
|
||||
priv := bls.RandKey()
|
||||
pID, err := helpers.BeaconProposerIndex(state)
|
||||
require.NoError(t, err)
|
||||
block := ðpb.SignedBeaconBlock{
|
||||
Block: ðpb.BeaconBlock{
|
||||
ProposerIndex: pID,
|
||||
Slot: 10,
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
RandaoReveal: []byte{'A', 'B', 'C'},
|
||||
},
|
||||
ParentRoot: latestBlockSignedRoot[:],
|
||||
},
|
||||
}
|
||||
block := testutil.NewBeaconBlock()
|
||||
block.Block.ProposerIndex = pID
|
||||
block.Block.Slot = 10
|
||||
block.Block.Body.RandaoReveal = bytesutil.PadTo([]byte{'A', 'B', 'C'}, 96)
|
||||
block.Block.ParentRoot = latestBlockSignedRoot[:]
|
||||
block.Signature, err = helpers.ComputeDomainAndSign(state, currentEpoch, block.Block, params.BeaconConfig().DomainBeaconProposer, priv)
|
||||
require.NoError(t, err)
|
||||
bodyRoot, err := stateutil.BlockBodyRoot(block.Block.Body)
|
||||
bodyRoot, err := block.Block.Body.HashTreeRoot()
|
||||
require.NoError(t, err, "Failed to hash block bytes got")
|
||||
|
||||
proposerIdx, err := helpers.BeaconProposerIndex(state)
|
||||
@@ -294,7 +267,7 @@ func TestProcessBlockHeader_OK(t *testing.T) {
|
||||
err = state.UpdateValidatorAtIndex(proposerIdx, validators[proposerIdx])
|
||||
require.NoError(t, err)
|
||||
|
||||
newState, err := blocks.ProcessBlockHeader(state, block)
|
||||
newState, err := blocks.ProcessBlockHeader(context.Background(), state, block)
|
||||
require.NoError(t, err, "Failed to process block header got")
|
||||
var zeroHash [32]byte
|
||||
nsh := newState.LatestBlockHeader()
|
||||
@@ -312,40 +285,36 @@ func TestBlockSignatureSet_OK(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,
|
||||
PublicKey: make([]byte, 32),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
Slashed: true,
|
||||
}
|
||||
}
|
||||
|
||||
state, err := stateTrie.InitializeFromProto(&pb.BeaconState{
|
||||
Validators: validators,
|
||||
Slot: 10,
|
||||
LatestBlockHeader: ðpb.BeaconBlockHeader{Slot: 9},
|
||||
Fork: &pb.Fork{
|
||||
PreviousVersion: []byte{0, 0, 0, 0},
|
||||
CurrentVersion: []byte{0, 0, 0, 0},
|
||||
},
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
state := testutil.NewBeaconState()
|
||||
require.NoError(t, state.SetValidators(validators))
|
||||
require.NoError(t, state.SetSlot(10))
|
||||
require.NoError(t, state.SetLatestBlockHeader(ðpb.BeaconBlockHeader{
|
||||
Slot: 9,
|
||||
ProposerIndex: 0,
|
||||
ParentRoot: make([]byte, 32),
|
||||
StateRoot: make([]byte, 32),
|
||||
BodyRoot: make([]byte, 32),
|
||||
}))
|
||||
|
||||
latestBlockSignedRoot, err := stateutil.BlockHeaderRoot(state.LatestBlockHeader())
|
||||
latestBlockSignedRoot, err := state.LatestBlockHeader().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
currentEpoch := helpers.CurrentEpoch(state)
|
||||
priv := bls.RandKey()
|
||||
pID, err := helpers.BeaconProposerIndex(state)
|
||||
require.NoError(t, err)
|
||||
block := ðpb.SignedBeaconBlock{
|
||||
Block: ðpb.BeaconBlock{
|
||||
ProposerIndex: pID,
|
||||
Slot: 10,
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
RandaoReveal: []byte{'A', 'B', 'C'},
|
||||
},
|
||||
ParentRoot: latestBlockSignedRoot[:],
|
||||
},
|
||||
}
|
||||
block := testutil.NewBeaconBlock()
|
||||
block.Block.Slot = 10
|
||||
block.Block.ProposerIndex = pID
|
||||
block.Block.Body.RandaoReveal = bytesutil.PadTo([]byte{'A', 'B', 'C'}, 96)
|
||||
block.Block.ParentRoot = latestBlockSignedRoot[:]
|
||||
block.Signature, err = helpers.ComputeDomainAndSign(state, currentEpoch, block.Block, params.BeaconConfig().DomainBeaconProposer, priv)
|
||||
require.NoError(t, err)
|
||||
proposerIdx, err := helpers.BeaconProposerIndex(state)
|
||||
|
||||
@@ -38,8 +38,13 @@ import (
|
||||
func ProcessProposerSlashings(
|
||||
ctx context.Context,
|
||||
beaconState *stateTrie.BeaconState,
|
||||
body *ethpb.BeaconBlockBody,
|
||||
b *ethpb.SignedBeaconBlock,
|
||||
) (*stateTrie.BeaconState, error) {
|
||||
if b.Block == nil || b.Block.Body == nil {
|
||||
return nil, errors.New("block and block body can't be nil")
|
||||
}
|
||||
|
||||
body := b.Block.Body
|
||||
var err error
|
||||
for idx, slashing := range body.ProposerSlashings {
|
||||
if slashing == nil {
|
||||
@@ -74,14 +79,14 @@ func VerifyProposerSlashing(
|
||||
if pIdx != slashing.Header_2.Header.ProposerIndex {
|
||||
return fmt.Errorf("mismatched indices, received %d == %d", slashing.Header_1.Header.ProposerIndex, slashing.Header_2.Header.ProposerIndex)
|
||||
}
|
||||
if proto.Equal(slashing.Header_1, slashing.Header_2) {
|
||||
if proto.Equal(slashing.Header_1.Header, slashing.Header_2.Header) {
|
||||
return errors.New("expected slashing headers to differ")
|
||||
}
|
||||
proposer, err := beaconState.ValidatorAtIndexReadOnly(slashing.Header_1.Header.ProposerIndex)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !helpers.IsSlashableValidatorUsingTrie(proposer, helpers.SlotToEpoch(beaconState.Slot())) {
|
||||
if !helpers.IsSlashableValidatorUsingTrie(proposer, helpers.SlotToEpoch(hSlot)) {
|
||||
return fmt.Errorf("validator with key %#x is not slashable", proposer.PublicKey())
|
||||
}
|
||||
headers := []*ethpb.SignedBeaconBlockHeader{slashing.Header_1, slashing.Header_2}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
@@ -39,13 +40,14 @@ func TestProcessProposerSlashings_UnmatchedHeaderSlots(t *testing.T) {
|
||||
}
|
||||
require.NoError(t, beaconState.SetSlot(currentSlot))
|
||||
|
||||
block := ðpb.BeaconBlock{
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block = ðpb.BeaconBlock{
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
ProposerSlashings: slashings,
|
||||
},
|
||||
}
|
||||
want := "mismatched header slots"
|
||||
_, err := blocks.ProcessProposerSlashings(context.Background(), beaconState, block.Body)
|
||||
_, err := blocks.ProcessProposerSlashings(context.Background(), beaconState, b)
|
||||
assert.ErrorContains(t, want, err)
|
||||
}
|
||||
|
||||
@@ -71,13 +73,14 @@ func TestProcessProposerSlashings_SameHeaders(t *testing.T) {
|
||||
}
|
||||
|
||||
require.NoError(t, beaconState.SetSlot(currentSlot))
|
||||
block := ðpb.BeaconBlock{
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block = ðpb.BeaconBlock{
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
ProposerSlashings: slashings,
|
||||
},
|
||||
}
|
||||
want := "expected slashing headers to differ"
|
||||
_, err := blocks.ProcessProposerSlashings(context.Background(), beaconState, block.Body)
|
||||
_, err := blocks.ProcessProposerSlashings(context.Background(), beaconState, b)
|
||||
assert.ErrorContains(t, want, err)
|
||||
}
|
||||
|
||||
@@ -97,15 +100,17 @@ func TestProcessProposerSlashings_ValidatorNotSlashable(t *testing.T) {
|
||||
Header: ðpb.BeaconBlockHeader{
|
||||
ProposerIndex: 0,
|
||||
Slot: 0,
|
||||
BodyRoot: []byte("foo"),
|
||||
},
|
||||
Signature: []byte("A"),
|
||||
Signature: bytesutil.PadTo([]byte("A"), 96),
|
||||
},
|
||||
Header_2: ðpb.SignedBeaconBlockHeader{
|
||||
Header: ðpb.BeaconBlockHeader{
|
||||
ProposerIndex: 0,
|
||||
Slot: 0,
|
||||
BodyRoot: []byte("bar"),
|
||||
},
|
||||
Signature: []byte("B"),
|
||||
Signature: bytesutil.PadTo([]byte("B"), 96),
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -115,7 +120,8 @@ func TestProcessProposerSlashings_ValidatorNotSlashable(t *testing.T) {
|
||||
Slot: currentSlot,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
block := ðpb.BeaconBlock{
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block = ðpb.BeaconBlock{
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
ProposerSlashings: slashings,
|
||||
},
|
||||
@@ -124,7 +130,7 @@ func TestProcessProposerSlashings_ValidatorNotSlashable(t *testing.T) {
|
||||
"validator with key %#x is not slashable",
|
||||
bytesutil.ToBytes48(beaconState.Validators()[0].PublicKey),
|
||||
)
|
||||
_, err = blocks.ProcessProposerSlashings(context.Background(), beaconState, block.Body)
|
||||
_, err = blocks.ProcessProposerSlashings(context.Background(), beaconState, b)
|
||||
assert.ErrorContains(t, want, err)
|
||||
}
|
||||
|
||||
@@ -138,7 +144,9 @@ func TestProcessProposerSlashings_AppliesCorrectStatus(t *testing.T) {
|
||||
Header: ðpb.BeaconBlockHeader{
|
||||
ProposerIndex: proposerIdx,
|
||||
Slot: 0,
|
||||
StateRoot: []byte("A"),
|
||||
ParentRoot: make([]byte, 32),
|
||||
BodyRoot: make([]byte, 32),
|
||||
StateRoot: bytesutil.PadTo([]byte("A"), 32),
|
||||
},
|
||||
}
|
||||
var err error
|
||||
@@ -149,7 +157,9 @@ func TestProcessProposerSlashings_AppliesCorrectStatus(t *testing.T) {
|
||||
Header: ðpb.BeaconBlockHeader{
|
||||
ProposerIndex: proposerIdx,
|
||||
Slot: 0,
|
||||
StateRoot: []byte("B"),
|
||||
ParentRoot: make([]byte, 32),
|
||||
BodyRoot: make([]byte, 32),
|
||||
StateRoot: bytesutil.PadTo([]byte("B"), 32),
|
||||
},
|
||||
}
|
||||
header2.Signature, err = helpers.ComputeDomainAndSign(beaconState, 0, header2.Header, params.BeaconConfig().DomainBeaconProposer, privKeys[proposerIdx])
|
||||
@@ -162,13 +172,10 @@ func TestProcessProposerSlashings_AppliesCorrectStatus(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
block := ðpb.BeaconBlock{
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
ProposerSlashings: slashings,
|
||||
},
|
||||
}
|
||||
block := testutil.NewBeaconBlock()
|
||||
block.Block.Body.ProposerSlashings = slashings
|
||||
|
||||
newState, err := blocks.ProcessProposerSlashings(context.Background(), beaconState, block.Body)
|
||||
newState, err := blocks.ProcessProposerSlashings(context.Background(), beaconState, block)
|
||||
require.NoError(t, err)
|
||||
|
||||
newStateVals := newState.Validators()
|
||||
@@ -177,3 +184,125 @@ func TestProcessProposerSlashings_AppliesCorrectStatus(t *testing.T) {
|
||||
newStateVals[1].ExitEpoch, beaconState.Validators()[1].ExitEpoch)
|
||||
}
|
||||
}
|
||||
|
||||
func TestVerifyProposerSlashing(t *testing.T) {
|
||||
type args struct {
|
||||
beaconState *stateTrie.BeaconState
|
||||
slashing *ethpb.ProposerSlashing
|
||||
}
|
||||
|
||||
beaconState, sks := testutil.DeterministicGenesisState(t, 2)
|
||||
currentSlot := uint64(0)
|
||||
require.NoError(t, beaconState.SetSlot(currentSlot))
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "same header, same slot as state",
|
||||
args: args{
|
||||
slashing: ðpb.ProposerSlashing{
|
||||
Header_1: ðpb.SignedBeaconBlockHeader{
|
||||
Header: ðpb.BeaconBlockHeader{
|
||||
ProposerIndex: 1,
|
||||
Slot: currentSlot,
|
||||
StateRoot: bytesutil.PadTo([]byte{}, 32),
|
||||
BodyRoot: bytesutil.PadTo([]byte{}, 32),
|
||||
ParentRoot: bytesutil.PadTo([]byte{}, 32),
|
||||
},
|
||||
},
|
||||
Header_2: ðpb.SignedBeaconBlockHeader{
|
||||
Header: ðpb.BeaconBlockHeader{
|
||||
ProposerIndex: 1,
|
||||
Slot: currentSlot,
|
||||
StateRoot: bytesutil.PadTo([]byte{}, 32),
|
||||
BodyRoot: bytesutil.PadTo([]byte{}, 32),
|
||||
ParentRoot: bytesutil.PadTo([]byte{}, 32),
|
||||
},
|
||||
},
|
||||
},
|
||||
beaconState: beaconState,
|
||||
},
|
||||
wantErr: "expected slashing headers to differ",
|
||||
},
|
||||
{ // Regression test for https://github.com/sigp/beacon-fuzz/issues/74
|
||||
name: "same header, different signatures",
|
||||
args: args{
|
||||
slashing: ðpb.ProposerSlashing{
|
||||
Header_1: ðpb.SignedBeaconBlockHeader{
|
||||
Header: ðpb.BeaconBlockHeader{
|
||||
ProposerIndex: 1,
|
||||
Slot: 0,
|
||||
StateRoot: bytesutil.PadTo([]byte{}, 32),
|
||||
BodyRoot: bytesutil.PadTo([]byte{}, 32),
|
||||
ParentRoot: bytesutil.PadTo([]byte{}, 32),
|
||||
},
|
||||
Signature: bls.RandKey().Sign([]byte("foo")).Marshal(),
|
||||
},
|
||||
Header_2: ðpb.SignedBeaconBlockHeader{
|
||||
Header: ðpb.BeaconBlockHeader{
|
||||
ProposerIndex: 1,
|
||||
Slot: 0,
|
||||
StateRoot: bytesutil.PadTo([]byte{}, 32),
|
||||
BodyRoot: bytesutil.PadTo([]byte{}, 32),
|
||||
ParentRoot: bytesutil.PadTo([]byte{}, 32),
|
||||
},
|
||||
Signature: bls.RandKey().Sign([]byte("bar")).Marshal(),
|
||||
},
|
||||
},
|
||||
beaconState: beaconState,
|
||||
},
|
||||
wantErr: "expected slashing headers to differ",
|
||||
},
|
||||
{
|
||||
name: "slashing in future epoch",
|
||||
args: args{
|
||||
slashing: ðpb.ProposerSlashing{
|
||||
Header_1: ðpb.SignedBeaconBlockHeader{
|
||||
Header: ðpb.BeaconBlockHeader{
|
||||
ProposerIndex: 1,
|
||||
Slot: 65,
|
||||
StateRoot: bytesutil.PadTo([]byte{}, 32),
|
||||
BodyRoot: bytesutil.PadTo([]byte{}, 32),
|
||||
ParentRoot: bytesutil.PadTo([]byte("foo"), 32),
|
||||
},
|
||||
},
|
||||
Header_2: ðpb.SignedBeaconBlockHeader{
|
||||
Header: ðpb.BeaconBlockHeader{
|
||||
ProposerIndex: 1,
|
||||
Slot: 65,
|
||||
StateRoot: bytesutil.PadTo([]byte{}, 32),
|
||||
BodyRoot: bytesutil.PadTo([]byte{}, 32),
|
||||
ParentRoot: bytesutil.PadTo([]byte("bar"), 32),
|
||||
},
|
||||
},
|
||||
},
|
||||
beaconState: beaconState,
|
||||
},
|
||||
wantErr: "",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
testutil.ResetCache()
|
||||
sk := sks[tt.args.slashing.Header_1.Header.ProposerIndex]
|
||||
d, err := helpers.Domain(tt.args.beaconState.Fork(), helpers.SlotToEpoch(tt.args.slashing.Header_1.Header.Slot), params.BeaconConfig().DomainBeaconProposer, tt.args.beaconState.GenesisValidatorRoot())
|
||||
require.NoError(t, err)
|
||||
if tt.args.slashing.Header_1.Signature == nil {
|
||||
sr, err := helpers.ComputeSigningRoot(tt.args.slashing.Header_1.Header, d)
|
||||
require.NoError(t, err)
|
||||
tt.args.slashing.Header_1.Signature = sk.Sign(sr[:]).Marshal()
|
||||
}
|
||||
if tt.args.slashing.Header_2.Signature == nil {
|
||||
sr, err := helpers.ComputeSigningRoot(tt.args.slashing.Header_2.Header, d)
|
||||
require.NoError(t, err)
|
||||
tt.args.slashing.Header_2.Signature = sk.Sign(sr[:]).Marshal()
|
||||
}
|
||||
if err := blocks.VerifyProposerSlashing(tt.args.beaconState, tt.args.slashing); (err != nil || tt.wantErr != "") && err.Error() != tt.wantErr {
|
||||
t.Errorf("VerifyProposerSlashing() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package blocks
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
@@ -24,14 +26,20 @@ import (
|
||||
// mix = xor(get_randao_mix(state, epoch), hash(body.randao_reveal))
|
||||
// state.randao_mixes[epoch % EPOCHS_PER_HISTORICAL_VECTOR] = mix
|
||||
func ProcessRandao(
|
||||
ctx context.Context,
|
||||
beaconState *stateTrie.BeaconState,
|
||||
body *ethpb.BeaconBlockBody,
|
||||
b *ethpb.SignedBeaconBlock,
|
||||
) (*stateTrie.BeaconState, error) {
|
||||
if b.Block == nil || b.Block.Body == nil {
|
||||
return nil, errors.New("block and block body can't be nil")
|
||||
}
|
||||
|
||||
body := b.Block.Body
|
||||
buf, proposerPub, domain, err := randaoSigningData(beaconState)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := verifySignature(buf, proposerPub[:], body.RandaoReveal, domain); err != nil {
|
||||
if err := verifySignature(buf, proposerPub, body.RandaoReveal, domain); err != nil {
|
||||
return nil, errors.Wrap(err, "could not verify block randao")
|
||||
}
|
||||
|
||||
|
||||
@@ -2,11 +2,11 @@ package blocks_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"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/beacon-chain/core/helpers"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
@@ -26,18 +26,19 @@ func TestProcessRandao_IncorrectProposerFailsVerification(t *testing.T) {
|
||||
binary.LittleEndian.PutUint64(buf, epoch)
|
||||
domain, err := helpers.Domain(beaconState.Fork(), epoch, params.BeaconConfig().DomainRandao, beaconState.GenesisValidatorRoot())
|
||||
require.NoError(t, err)
|
||||
root, err := ssz.HashTreeRoot(&pb.SigningData{ObjectRoot: buf, Domain: domain})
|
||||
root, err := (&pb.SigningData{ObjectRoot: buf, Domain: domain}).HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
// We make the previous validator's index sign the message instead of the proposer.
|
||||
epochSignature := privKeys[proposerIdx-1].Sign(root[:])
|
||||
block := ðpb.BeaconBlock{
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block = ðpb.BeaconBlock{
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
RandaoReveal: epochSignature.Marshal(),
|
||||
},
|
||||
}
|
||||
|
||||
want := "block randao: signature did not verify"
|
||||
_, err = blocks.ProcessRandao(beaconState, block.Body)
|
||||
_, err = blocks.ProcessRandao(context.Background(), beaconState, b)
|
||||
assert.ErrorContains(t, want, err)
|
||||
}
|
||||
|
||||
@@ -48,15 +49,17 @@ func TestProcessRandao_SignatureVerifiesAndUpdatesLatestStateMixes(t *testing.T)
|
||||
epochSignature, err := testutil.RandaoReveal(beaconState, epoch, privKeys)
|
||||
require.NoError(t, err)
|
||||
|
||||
block := ðpb.BeaconBlock{
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block = ðpb.BeaconBlock{
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
RandaoReveal: epochSignature,
|
||||
},
|
||||
}
|
||||
|
||||
newState, err := blocks.ProcessRandao(
|
||||
context.Background(),
|
||||
beaconState,
|
||||
block.Body,
|
||||
b,
|
||||
)
|
||||
require.NoError(t, err, "Unexpected error processing block randao")
|
||||
currentEpoch := helpers.CurrentEpoch(beaconState)
|
||||
|
||||
@@ -6,7 +6,6 @@ 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"
|
||||
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
@@ -21,20 +20,16 @@ func retrieveSignatureSet(signedData []byte, pub []byte, signature []byte, domai
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not convert bytes to public key")
|
||||
}
|
||||
sig, err := bls.SignatureFromBytes(signature)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not convert bytes to signature")
|
||||
}
|
||||
signingData := &pb.SigningData{
|
||||
ObjectRoot: signedData,
|
||||
Domain: domain,
|
||||
}
|
||||
root, err := ssz.HashTreeRoot(signingData)
|
||||
root, err := signingData.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not hash container")
|
||||
}
|
||||
return &bls.SignatureSet{
|
||||
Signatures: []bls.Signature{sig},
|
||||
Signatures: [][]byte{signature},
|
||||
PublicKeys: []bls.PublicKey{publicKey},
|
||||
Messages: [][32]byte{root},
|
||||
}, nil
|
||||
@@ -53,7 +48,11 @@ func verifySignature(signedData []byte, pub []byte, signature []byte, domain []b
|
||||
sig := set.Signatures[0]
|
||||
publicKey := set.PublicKeys[0]
|
||||
root := set.Messages[0]
|
||||
if !sig.Verify(publicKey, root[:]) {
|
||||
rSig, err := bls.SignatureFromBytes(sig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !rSig.Verify(publicKey, root[:]) {
|
||||
return helpers.ErrSigFailedToVerify
|
||||
}
|
||||
return nil
|
||||
@@ -71,7 +70,7 @@ func VerifyBlockSignature(beaconState *stateTrie.BeaconState, block *ethpb.Signe
|
||||
return err
|
||||
}
|
||||
proposerPubKey := proposer.PublicKey
|
||||
return helpers.VerifyBlockSigningRoot(block.Block, proposerPubKey[:], block.Signature, domain)
|
||||
return helpers.VerifyBlockSigningRoot(block.Block, proposerPubKey, block.Signature, domain)
|
||||
}
|
||||
|
||||
// BlockSignatureSet retrieves the block signature set from the provided block and its corresponding state.
|
||||
@@ -98,7 +97,7 @@ func RandaoSignatureSet(beaconState *stateTrie.BeaconState,
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
set, err := retrieveSignatureSet(buf, proposerPub[:], body.RandaoReveal, domain)
|
||||
set, err := retrieveSignatureSet(buf, proposerPub, body.RandaoReveal, domain)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@@ -130,15 +129,11 @@ func createAttestationSignatureSet(ctx context.Context, beaconState *stateTrie.B
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
sigs := make([]bls.Signature, len(atts))
|
||||
sigs := make([][]byte, 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 nil, err
|
||||
}
|
||||
sigs[i] = sig
|
||||
sigs[i] = a.Signature
|
||||
c, err := helpers.BeaconCommitteeFromState(beaconState, a.Data.Slot, a.Data.CommitteeIndex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -148,20 +143,16 @@ func createAttestationSignatureSet(ctx context.Context, beaconState *stateTrie.B
|
||||
return nil, err
|
||||
}
|
||||
indices := ia.AttestingIndices
|
||||
var pk bls.PublicKey
|
||||
pubkeys := make([][]byte, len(indices))
|
||||
for i := 0; i < len(indices); i++ {
|
||||
pubkeyAtIdx := beaconState.PubkeyAtIndex(indices[i])
|
||||
p, err := bls.PublicKeyFromBytes(pubkeyAtIdx[:])
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not deserialize validator public key")
|
||||
}
|
||||
if pk == nil {
|
||||
pk = p
|
||||
} else {
|
||||
pk.Aggregate(p)
|
||||
}
|
||||
pubkeys[i] = pubkeyAtIdx[:]
|
||||
}
|
||||
pks[i] = pk
|
||||
aggP, err := bls.AggregatePublicKeys(pubkeys)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pks[i] = aggP
|
||||
|
||||
root, err := helpers.ComputeSigningRoot(ia.Data, domain)
|
||||
if err != nil {
|
||||
|
||||
@@ -41,8 +41,8 @@ func runBlockHeaderTest(t *testing.T, config string) {
|
||||
postSSZExists := true
|
||||
if err != nil && strings.Contains(err.Error(), "could not locate file") {
|
||||
postSSZExists = false
|
||||
} else if err != nil {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
// Spectest blocks are not signed, so we'll call NoVerify to skip sig verification.
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
package spectest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/shared/params/spectest"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
@@ -26,9 +24,7 @@ func runDepositTest(t *testing.T, config string) {
|
||||
require.NoError(t, deposit.UnmarshalSSZ(depositFile), "Failed to unmarshal")
|
||||
|
||||
body := ðpb.BeaconBlockBody{Deposits: []*ethpb.Deposit{deposit}}
|
||||
testutil.RunBlockOperationTest(t, folderPath, body, func(ctx context.Context, state *state.BeaconState, body *ethpb.BeaconBlockBody) (*state.BeaconState, error) {
|
||||
return blocks.ProcessDeposits(ctx, state, body.Deposits)
|
||||
})
|
||||
testutil.RunBlockOperationTest(t, folderPath, body, blocks.ProcessDeposits)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ go_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",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -33,6 +32,7 @@ go_test(
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"//shared/testutil:go_default_library",
|
||||
"//shared/testutil/assert:go_default_library",
|
||||
"//shared/testutil/require:go_default_library",
|
||||
"@com_github_gogo_protobuf//proto:go_default_library",
|
||||
|
||||
@@ -10,7 +10,6 @@ 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/core/validators"
|
||||
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
@@ -46,7 +45,7 @@ func (s sortableIndices) Less(i, j int) bool {
|
||||
// def get_attesting_balance(state: BeaconState, attestations: List[PendingAttestation]) -> Gwei:
|
||||
// return get_total_balance(state, get_unslashed_attesting_indices(state, attestations))
|
||||
func AttestingBalance(state *stateTrie.BeaconState, atts []*pb.PendingAttestation) (uint64, error) {
|
||||
indices, err := unslashedAttestingIndices(state, atts)
|
||||
indices, err := UnslashedAttestingIndices(state, atts)
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "could not get attesting indices")
|
||||
}
|
||||
@@ -148,10 +147,11 @@ func ProcessRegistryUpdates(state *stateTrie.BeaconState) (*stateTrie.BeaconStat
|
||||
// def process_slashings(state: BeaconState) -> None:
|
||||
// epoch = get_current_epoch(state)
|
||||
// total_balance = get_total_active_balance(state)
|
||||
// adjusted_total_slashing_balance = min(sum(state.slashings) * PROPORTIONAL_SLASHING_MULTIPLIER, total_balance)
|
||||
// for index, validator in enumerate(state.validators):
|
||||
// if validator.slashed and epoch + EPOCHS_PER_SLASHINGS_VECTOR // 2 == validator.withdrawable_epoch:
|
||||
// increment = EFFECTIVE_BALANCE_INCREMENT # Factored out from penalty numerator to avoid uint64 overflow
|
||||
// penalty_numerator = validator.effective_balance // increment * min(sum(state.slashings) * 3, total_balance)
|
||||
// penalty_numerator = validator.effective_balance // increment * adjusted_total_slashing_balance
|
||||
// penalty = penalty_numerator // total_balance * increment
|
||||
// decrease_balance(state, ValidatorIndex(index), penalty)
|
||||
func ProcessSlashings(state *stateTrie.BeaconState) (*stateTrie.BeaconState, error) {
|
||||
@@ -174,10 +174,10 @@ 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
|
||||
minSlashing := mathutil.Min(totalSlashing*params.BeaconConfig().ProportionalSlashingMultiplier, totalBalance)
|
||||
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)
|
||||
penaltyNumerator := val.EffectiveBalance / increment * minSlashing
|
||||
penalty := penaltyNumerator / totalBalance * increment
|
||||
if err := helpers.DecreaseBalance(state, uint64(idx), penalty); err != nil {
|
||||
@@ -311,7 +311,7 @@ func ProcessFinalUpdates(state *stateTrie.BeaconState) (*stateTrie.BeaconState,
|
||||
BlockRoots: state.BlockRoots(),
|
||||
StateRoots: state.StateRoots(),
|
||||
}
|
||||
batchRoot, err := ssz.HashTreeRoot(historicalBatch)
|
||||
batchRoot, err := historicalBatch.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not hash historical batch")
|
||||
}
|
||||
@@ -330,7 +330,7 @@ func ProcessFinalUpdates(state *stateTrie.BeaconState) (*stateTrie.BeaconState,
|
||||
return state, nil
|
||||
}
|
||||
|
||||
// unslashedAttestingIndices returns all the attesting indices from a list of attestations,
|
||||
// UnslashedAttestingIndices returns all the attesting indices from a list of attestations,
|
||||
// it sorts the indices and filters out the slashed ones.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
@@ -340,7 +340,7 @@ func ProcessFinalUpdates(state *stateTrie.BeaconState) (*stateTrie.BeaconState,
|
||||
// for a in attestations:
|
||||
// output = output.union(get_attesting_indices(state, a.data, a.aggregation_bits))
|
||||
// return set(filter(lambda index: not state.validators[index].slashed, output))
|
||||
func unslashedAttestingIndices(state *stateTrie.BeaconState, atts []*pb.PendingAttestation) ([]uint64, error) {
|
||||
func UnslashedAttestingIndices(state *stateTrie.BeaconState, atts []*pb.PendingAttestation) ([]uint64, error) {
|
||||
var setIndices []uint64
|
||||
seen := make(map[uint64]bool)
|
||||
|
||||
|
||||
@@ -18,5 +18,6 @@ func TestFuzzFinalUpdates_10000(t *testing.T) {
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(base)
|
||||
require.NoError(t, err)
|
||||
_, err = ProcessFinalUpdates(s)
|
||||
_ = err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
package epoch
|
||||
package epoch_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/go-bitfield"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/epoch"
|
||||
"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/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
@@ -20,8 +21,8 @@ func TestUnslashedAttestingIndices_CanSortAndFilter(t *testing.T) {
|
||||
atts := make([]*pb.PendingAttestation, 2)
|
||||
for i := 0; i < len(atts); i++ {
|
||||
atts[i] = &pb.PendingAttestation{
|
||||
Data: ðpb.AttestationData{Source: ðpb.Checkpoint{},
|
||||
Target: ðpb.Checkpoint{Epoch: 0},
|
||||
Data: ðpb.AttestationData{Source: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
Target: ðpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
|
||||
},
|
||||
AggregationBits: bitfield.Bitlist{0xFF, 0xFF, 0xFF},
|
||||
}
|
||||
@@ -42,7 +43,7 @@ func TestUnslashedAttestingIndices_CanSortAndFilter(t *testing.T) {
|
||||
state, err := state.InitializeFromProto(base)
|
||||
require.NoError(t, err)
|
||||
|
||||
indices, err := unslashedAttestingIndices(state, atts)
|
||||
indices, err := epoch.UnslashedAttestingIndices(state, atts)
|
||||
require.NoError(t, err)
|
||||
for i := 0; i < len(indices)-1; i++ {
|
||||
if indices[i] >= indices[i+1] {
|
||||
@@ -55,7 +56,7 @@ func TestUnslashedAttestingIndices_CanSortAndFilter(t *testing.T) {
|
||||
validators = state.Validators()
|
||||
validators[slashedValidator].Slashed = true
|
||||
require.NoError(t, state.SetValidators(validators))
|
||||
indices, err = unslashedAttestingIndices(state, atts)
|
||||
indices, err = epoch.UnslashedAttestingIndices(state, atts)
|
||||
require.NoError(t, err)
|
||||
for i := 0; i < len(indices); i++ {
|
||||
assert.NotEqual(t, slashedValidator, indices[i], "Slashed validator %d is not filtered", slashedValidator)
|
||||
@@ -67,7 +68,7 @@ func TestUnslashedAttestingIndices_DuplicatedAttestations(t *testing.T) {
|
||||
atts := make([]*pb.PendingAttestation, 5)
|
||||
for i := 0; i < len(atts); i++ {
|
||||
atts[i] = &pb.PendingAttestation{
|
||||
Data: ðpb.AttestationData{Source: ðpb.Checkpoint{},
|
||||
Data: ðpb.AttestationData{Source: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
Target: ðpb.Checkpoint{Epoch: 0}},
|
||||
AggregationBits: bitfield.Bitlist{0xFF, 0xFF, 0xFF},
|
||||
}
|
||||
@@ -88,7 +89,7 @@ func TestUnslashedAttestingIndices_DuplicatedAttestations(t *testing.T) {
|
||||
state, err := state.InitializeFromProto(base)
|
||||
require.NoError(t, err)
|
||||
|
||||
indices, err := unslashedAttestingIndices(state, atts)
|
||||
indices, err := epoch.UnslashedAttestingIndices(state, atts)
|
||||
require.NoError(t, err)
|
||||
|
||||
for i := 0; i < len(indices)-1; i++ {
|
||||
@@ -105,8 +106,8 @@ func TestAttestingBalance_CorrectBalance(t *testing.T) {
|
||||
for i := 0; i < len(atts); i++ {
|
||||
atts[i] = &pb.PendingAttestation{
|
||||
Data: ðpb.AttestationData{
|
||||
Target: ðpb.Checkpoint{},
|
||||
Source: ðpb.Checkpoint{},
|
||||
Target: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
Source: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
Slot: uint64(i),
|
||||
},
|
||||
AggregationBits: bitfield.Bitlist{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
@@ -134,7 +135,7 @@ func TestAttestingBalance_CorrectBalance(t *testing.T) {
|
||||
state, err := state.InitializeFromProto(base)
|
||||
require.NoError(t, err)
|
||||
|
||||
balance, err := AttestingBalance(state, atts)
|
||||
balance, err := epoch.AttestingBalance(state, atts)
|
||||
require.NoError(t, err)
|
||||
wanted := 256 * params.BeaconConfig().MaxEffectiveBalance
|
||||
assert.Equal(t, wanted, balance)
|
||||
@@ -159,9 +160,9 @@ func TestBaseReward_AccurateRewards(t *testing.T) {
|
||||
}
|
||||
state, err := state.InitializeFromProto(base)
|
||||
require.NoError(t, err)
|
||||
c, err := BaseReward(state, 0)
|
||||
c, err := epoch.BaseReward(state, 0)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tt.c, c, "BaseReward(%d)", tt.a)
|
||||
assert.Equal(t, tt.c, c, "epoch.BaseReward(%d)", tt.a)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,7 +175,7 @@ func TestProcessSlashings_NotSlashed(t *testing.T) {
|
||||
}
|
||||
s, err := state.InitializeFromProto(base)
|
||||
require.NoError(t, err)
|
||||
newState, err := ProcessSlashings(s)
|
||||
newState, err := epoch.ProcessSlashings(s)
|
||||
require.NoError(t, err)
|
||||
wanted := params.BeaconConfig().MaxEffectiveBalance
|
||||
assert.Equal(t, wanted, newState.Balances()[0], "Unexpected slashed balance")
|
||||
@@ -252,7 +253,7 @@ func TestProcessSlashings_SlashedLess(t *testing.T) {
|
||||
original := proto.Clone(tt.state)
|
||||
s, err := state.InitializeFromProto(tt.state)
|
||||
require.NoError(t, err)
|
||||
newState, err := ProcessSlashings(s)
|
||||
newState, err := epoch.ProcessSlashings(s)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tt.want, newState.Balances()[0], "ProcessSlashings({%v}) = newState; newState.Balances[0] = %d", original, newState.Balances()[0])
|
||||
})
|
||||
@@ -260,7 +261,7 @@ func TestProcessSlashings_SlashedLess(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestProcessFinalUpdates_CanProcess(t *testing.T) {
|
||||
s := buildState(params.BeaconConfig().SlotsPerHistoricalRoot-1, params.BeaconConfig().SlotsPerEpoch)
|
||||
s := buildState(t, params.BeaconConfig().SlotsPerHistoricalRoot-1, params.BeaconConfig().SlotsPerEpoch)
|
||||
ce := helpers.CurrentEpoch(s)
|
||||
ne := ce + 1
|
||||
require.NoError(t, s.SetEth1DataVotes([]*ethpb.Eth1Data{}))
|
||||
@@ -275,7 +276,7 @@ func TestProcessFinalUpdates_CanProcess(t *testing.T) {
|
||||
mixes := s.RandaoMixes()
|
||||
mixes[ce] = []byte{'A'}
|
||||
require.NoError(t, s.SetRandaoMixes(mixes))
|
||||
newS, err := ProcessFinalUpdates(s)
|
||||
newS, err := epoch.ProcessFinalUpdates(s)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify effective balance is correctly updated.
|
||||
@@ -286,9 +287,9 @@ func TestProcessFinalUpdates_CanProcess(t *testing.T) {
|
||||
assert.Equal(t, newS.Slashings()[ce], newS.Slashings()[ne], "Unexpected slashed balance")
|
||||
|
||||
// Verify randao is correctly updated in the right position.
|
||||
if mix, err := newS.RandaoMixAtIndex(ne); err != nil || bytes.Equal(mix, params.BeaconConfig().ZeroHash[:]) {
|
||||
t.Error("latest RANDAO still zero hashes")
|
||||
}
|
||||
mix, err := newS.RandaoMixAtIndex(ne)
|
||||
assert.NoError(t, err)
|
||||
assert.DeepNotEqual(t, params.BeaconConfig().ZeroHash[:], mix, "latest RANDAO still zero hashes")
|
||||
|
||||
// Verify historical root accumulator was appended.
|
||||
assert.Equal(t, 1, len(newS.HistoricalRoots()), "Unexpected slashed balance")
|
||||
@@ -306,11 +307,11 @@ func TestProcessRegistryUpdates_NoRotation(t *testing.T) {
|
||||
params.BeaconConfig().MaxEffectiveBalance,
|
||||
params.BeaconConfig().MaxEffectiveBalance,
|
||||
},
|
||||
FinalizedCheckpoint: ðpb.Checkpoint{},
|
||||
FinalizedCheckpoint: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
}
|
||||
state, err := state.InitializeFromProto(base)
|
||||
require.NoError(t, err)
|
||||
newState, err := ProcessRegistryUpdates(state)
|
||||
newState, err := epoch.ProcessRegistryUpdates(state)
|
||||
require.NoError(t, err)
|
||||
for i, validator := range newState.Validators() {
|
||||
assert.Equal(t, params.BeaconConfig().MaxSeedLookahead, validator.ExitEpoch, "Could not update registry %d", i)
|
||||
@@ -320,7 +321,7 @@ func TestProcessRegistryUpdates_NoRotation(t *testing.T) {
|
||||
func TestProcessRegistryUpdates_EligibleToActivate(t *testing.T) {
|
||||
base := &pb.BeaconState{
|
||||
Slot: 5 * params.BeaconConfig().SlotsPerEpoch,
|
||||
FinalizedCheckpoint: ðpb.Checkpoint{Epoch: 6},
|
||||
FinalizedCheckpoint: ðpb.Checkpoint{Epoch: 6, Root: make([]byte, 32)},
|
||||
}
|
||||
limit, err := helpers.ValidatorChurnLimit(0)
|
||||
require.NoError(t, err)
|
||||
@@ -332,8 +333,9 @@ func TestProcessRegistryUpdates_EligibleToActivate(t *testing.T) {
|
||||
})
|
||||
}
|
||||
state, err := state.InitializeFromProto(base)
|
||||
require.NoError(t, err)
|
||||
currentEpoch := helpers.CurrentEpoch(state)
|
||||
newState, err := ProcessRegistryUpdates(state)
|
||||
newState, err := epoch.ProcessRegistryUpdates(state)
|
||||
require.NoError(t, err)
|
||||
for i, validator := range newState.Validators() {
|
||||
assert.Equal(t, currentEpoch+1, validator.ActivationEligibilityEpoch, "Could not update registry %d, unexpected activation eligibility epoch", i)
|
||||
@@ -357,11 +359,11 @@ func TestProcessRegistryUpdates_ActivationCompletes(t *testing.T) {
|
||||
{ExitEpoch: params.BeaconConfig().MaxSeedLookahead,
|
||||
ActivationEpoch: 5 + params.BeaconConfig().MaxSeedLookahead + 1},
|
||||
},
|
||||
FinalizedCheckpoint: ðpb.Checkpoint{},
|
||||
FinalizedCheckpoint: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
}
|
||||
state, err := state.InitializeFromProto(base)
|
||||
require.NoError(t, err)
|
||||
newState, err := ProcessRegistryUpdates(state)
|
||||
newState, err := epoch.ProcessRegistryUpdates(state)
|
||||
require.NoError(t, err)
|
||||
for i, validator := range newState.Validators() {
|
||||
assert.Equal(t, params.BeaconConfig().MaxSeedLookahead, validator.ExitEpoch, "Could not update registry %d, unexpected exit slot", i)
|
||||
@@ -381,11 +383,11 @@ func TestProcessRegistryUpdates_ValidatorsEjected(t *testing.T) {
|
||||
EffectiveBalance: params.BeaconConfig().EjectionBalance - 1,
|
||||
},
|
||||
},
|
||||
FinalizedCheckpoint: ðpb.Checkpoint{},
|
||||
FinalizedCheckpoint: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
}
|
||||
state, err := state.InitializeFromProto(base)
|
||||
require.NoError(t, err)
|
||||
newState, err := ProcessRegistryUpdates(state)
|
||||
newState, err := epoch.ProcessRegistryUpdates(state)
|
||||
require.NoError(t, err)
|
||||
for i, validator := range newState.Validators() {
|
||||
assert.Equal(t, params.BeaconConfig().MaxSeedLookahead+1, validator.ExitEpoch, "Could not update registry %d, unexpected exit slot", i)
|
||||
@@ -393,11 +395,11 @@ func TestProcessRegistryUpdates_ValidatorsEjected(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestProcessRegistryUpdates_CanExits(t *testing.T) {
|
||||
epoch := uint64(5)
|
||||
exitEpoch := helpers.ActivationExitEpoch(epoch)
|
||||
e := uint64(5)
|
||||
exitEpoch := helpers.ActivationExitEpoch(e)
|
||||
minWithdrawalDelay := params.BeaconConfig().MinValidatorWithdrawabilityDelay
|
||||
base := &pb.BeaconState{
|
||||
Slot: epoch * params.BeaconConfig().SlotsPerEpoch,
|
||||
Slot: e * params.BeaconConfig().SlotsPerEpoch,
|
||||
Validators: []*ethpb.Validator{
|
||||
{
|
||||
ExitEpoch: exitEpoch,
|
||||
@@ -406,18 +408,18 @@ func TestProcessRegistryUpdates_CanExits(t *testing.T) {
|
||||
ExitEpoch: exitEpoch,
|
||||
WithdrawableEpoch: exitEpoch + minWithdrawalDelay},
|
||||
},
|
||||
FinalizedCheckpoint: ðpb.Checkpoint{},
|
||||
FinalizedCheckpoint: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
}
|
||||
state, err := state.InitializeFromProto(base)
|
||||
require.NoError(t, err)
|
||||
newState, err := ProcessRegistryUpdates(state)
|
||||
newState, err := epoch.ProcessRegistryUpdates(state)
|
||||
require.NoError(t, err)
|
||||
for i, validator := range newState.Validators() {
|
||||
assert.Equal(t, exitEpoch, validator.ExitEpoch, "Could not update registry %d, unexpected exit slot", i)
|
||||
}
|
||||
}
|
||||
|
||||
func buildState(slot uint64, validatorCount uint64) *state.BeaconState {
|
||||
func buildState(t testing.TB, slot uint64, validatorCount uint64) *state.BeaconState {
|
||||
validators := make([]*ethpb.Validator, validatorCount)
|
||||
for i := 0; i < len(validators); i++ {
|
||||
validators[i] = ðpb.Validator{
|
||||
@@ -443,19 +445,15 @@ func buildState(slot uint64, validatorCount uint64) *state.BeaconState {
|
||||
for i := 0; i < len(latestRandaoMixes); i++ {
|
||||
latestRandaoMixes[i] = params.BeaconConfig().ZeroHash[:]
|
||||
}
|
||||
s, err := state.InitializeFromProto(&pb.BeaconState{
|
||||
Slot: slot,
|
||||
Balances: validatorBalances,
|
||||
Validators: validators,
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
Slashings: make([]uint64, params.BeaconConfig().EpochsPerSlashingsVector),
|
||||
BlockRoots: make([][]byte, params.BeaconConfig().SlotsPerEpoch*10),
|
||||
FinalizedCheckpoint: ðpb.Checkpoint{},
|
||||
PreviousJustifiedCheckpoint: ðpb.Checkpoint{},
|
||||
CurrentJustifiedCheckpoint: ðpb.Checkpoint{},
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
s := testutil.NewBeaconState()
|
||||
if err := s.SetSlot(slot); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if err := s.SetBalances(validatorBalances); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if err := s.SetValidators(validators); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
@@ -178,8 +178,7 @@ func TestProcessAttestations(t *testing.T) {
|
||||
for i := 0; i < len(pVals); i++ {
|
||||
pVals[i] = &precompute.Validator{CurrentEpochEffectiveBalance: 100}
|
||||
}
|
||||
pBal := &precompute.Balance{}
|
||||
pVals, pBal, err = precompute.ProcessAttestations(context.Background(), beaconState, pVals, pBal)
|
||||
pVals, _, err = precompute.ProcessAttestations(context.Background(), beaconState, pVals, &precompute.Balance{})
|
||||
require.NoError(t, err)
|
||||
|
||||
committee, err := helpers.BeaconCommitteeFromState(beaconState, att1.Data.Slot, att1.Data.CommitteeIndex)
|
||||
|
||||
@@ -49,7 +49,11 @@ import (
|
||||
// if all(bits[0:2]) and old_current_justified_checkpoint.epoch + 1 == current_epoch:
|
||||
// state.finalized_checkpoint = old_current_justified_checkpoint
|
||||
func ProcessJustificationAndFinalizationPreCompute(state *stateTrie.BeaconState, pBal *Balance) (*stateTrie.BeaconState, error) {
|
||||
if state.Slot() <= helpers.StartSlot(2) {
|
||||
canProcessSlot, err := helpers.StartSlot(2 /*epoch*/)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if state.Slot() <= canProcessSlot {
|
||||
return state, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ func TestProcessJustificationAndFinalizationPreCompute_ConsecutiveEpochs(t *test
|
||||
Epoch: 0,
|
||||
Root: params.BeaconConfig().ZeroHash[:],
|
||||
},
|
||||
FinalizedCheckpoint: ðpb.Checkpoint{},
|
||||
FinalizedCheckpoint: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
JustificationBits: bitfield.Bitvector4{0x0F}, // 0b1111
|
||||
Validators: []*ethpb.Validator{{ExitEpoch: e}, {ExitEpoch: e}, {ExitEpoch: e}, {ExitEpoch: e}},
|
||||
Balances: []uint64{a, a, a, a}, // validator total balance should be 128000000000
|
||||
@@ -67,7 +67,7 @@ func TestProcessJustificationAndFinalizationPreCompute_JustifyCurrentEpoch(t *te
|
||||
Epoch: 0,
|
||||
Root: params.BeaconConfig().ZeroHash[:],
|
||||
},
|
||||
FinalizedCheckpoint: ðpb.Checkpoint{},
|
||||
FinalizedCheckpoint: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
JustificationBits: bitfield.Bitvector4{0x03}, // 0b0011
|
||||
Validators: []*ethpb.Validator{{ExitEpoch: e}, {ExitEpoch: e}, {ExitEpoch: e}, {ExitEpoch: e}},
|
||||
Balances: []uint64{a, a, a, a}, // validator total balance should be 128000000000
|
||||
@@ -107,7 +107,7 @@ func TestProcessJustificationAndFinalizationPreCompute_JustifyPrevEpoch(t *testi
|
||||
JustificationBits: bitfield.Bitvector4{0x03}, // 0b0011
|
||||
Validators: []*ethpb.Validator{{ExitEpoch: e}, {ExitEpoch: e}, {ExitEpoch: e}, {ExitEpoch: e}},
|
||||
Balances: []uint64{a, a, a, a}, // validator total balance should be 128000000000
|
||||
BlockRoots: blockRoots, FinalizedCheckpoint: ðpb.Checkpoint{},
|
||||
BlockRoots: blockRoots, FinalizedCheckpoint: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
}
|
||||
state, err := beaconstate.InitializeFromProto(base)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -24,8 +24,8 @@ func TestProcessRewardsAndPenaltiesPrecompute(t *testing.T) {
|
||||
for i := 0; i < len(atts); i++ {
|
||||
atts[i] = &pb.PendingAttestation{
|
||||
Data: ðpb.AttestationData{
|
||||
Target: ðpb.Checkpoint{},
|
||||
Source: ðpb.Checkpoint{},
|
||||
Target: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
Source: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
},
|
||||
AggregationBits: bitfield.Bitlist{0xC0, 0xC0, 0xC0, 0xC0, 0x01},
|
||||
InclusionDelay: 1,
|
||||
@@ -202,7 +202,7 @@ func TestAttestationDeltas_ZeroInclusionDelay(t *testing.T) {
|
||||
|
||||
pVals, pBal, err := New(context.Background(), state)
|
||||
require.NoError(t, err)
|
||||
pVals, pBal, err = ProcessAttestations(context.Background(), state, pVals, pBal)
|
||||
_, _, err = ProcessAttestations(context.Background(), state, pVals, pBal)
|
||||
require.ErrorContains(t, "attestation with inclusion delay of 0", err)
|
||||
}
|
||||
|
||||
@@ -214,8 +214,8 @@ func TestProcessRewardsAndPenaltiesPrecompute_SlashedInactivePenalty(t *testing.
|
||||
for i := 0; i < len(atts); i++ {
|
||||
atts[i] = &pb.PendingAttestation{
|
||||
Data: ðpb.AttestationData{
|
||||
Target: ðpb.Checkpoint{},
|
||||
Source: ðpb.Checkpoint{},
|
||||
Target: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
Source: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
},
|
||||
AggregationBits: bitfield.Bitlist{0xC0, 0xC0, 0xC0, 0xC0, 0x01},
|
||||
InclusionDelay: 1,
|
||||
@@ -287,9 +287,9 @@ func buildState(slot uint64, validatorCount uint64) *pb.BeaconState {
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
Slashings: make([]uint64, params.BeaconConfig().EpochsPerSlashingsVector),
|
||||
BlockRoots: make([][]byte, params.BeaconConfig().SlotsPerEpoch*10),
|
||||
FinalizedCheckpoint: ðpb.Checkpoint{},
|
||||
PreviousJustifiedCheckpoint: ðpb.Checkpoint{},
|
||||
CurrentJustifiedCheckpoint: ðpb.Checkpoint{},
|
||||
FinalizedCheckpoint: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
PreviousJustifiedCheckpoint: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
CurrentJustifiedCheckpoint: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ func ProcessSlashingsPrecompute(state *stateTrie.BeaconState, pBal *Balance) err
|
||||
totalSlashing += slashing
|
||||
}
|
||||
|
||||
minSlashing := mathutil.Min(totalSlashing*3, pBal.ActiveCurrentEpoch)
|
||||
minSlashing := mathutil.Min(totalSlashing*params.BeaconConfig().ProportionalSlashingMultiplier, pBal.ActiveCurrentEpoch)
|
||||
epochToWithdraw := currentEpoch + exitLength/2
|
||||
increment := params.BeaconConfig().EffectiveBalanceIncrement
|
||||
validatorFunc := func(idx int, val *ethpb.Validator) (bool, error) {
|
||||
|
||||
@@ -26,14 +26,16 @@ var deltaFiles = []string{"source_deltas.yaml", "target_deltas.yaml", "head_delt
|
||||
|
||||
func runPrecomputeRewardsAndPenaltiesTests(t *testing.T, config string) {
|
||||
require.NoError(t, spectest.SetConfig(t, config))
|
||||
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)
|
||||
})
|
||||
testPaths := []string{"rewards/basic/pyspec_tests", "rewards/leak/pyspec_tests", "rewards/random/pyspec_tests"}
|
||||
for _, testPath := range testPaths {
|
||||
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)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +57,7 @@ func runPrecomputeRewardsAndPenaltiesTest(t *testing.T, testFolderPath string) {
|
||||
require.NoError(t, err)
|
||||
pRewards, err := precompute.ProposersDelta(preBeaconState, bp, vp)
|
||||
require.NoError(t, err)
|
||||
if len(rewards) != len(penalties) && len(pRewards) != len(pRewards) {
|
||||
if len(rewards) != len(penalties) && len(rewards) != len(pRewards) {
|
||||
t.Fatal("Incorrect lengths")
|
||||
}
|
||||
for i, reward := range rewards {
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package spectest
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestRewardsAndPenaltiesMainnet(t *testing.T) {
|
||||
runRewardsAndPenaltiesTests(t, "mainnet")
|
||||
}
|
||||
@@ -4,5 +4,8 @@ go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["event.go"],
|
||||
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/core/feed",
|
||||
visibility = ["//beacon-chain:__subpackages__"],
|
||||
visibility = [
|
||||
"//beacon-chain:__subpackages__",
|
||||
"//shared:__subpackages__",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -45,7 +45,7 @@ type SyncedData struct {
|
||||
type InitializedData struct {
|
||||
// StartTime is the time at which the chain started.
|
||||
StartTime time.Time
|
||||
// GenesisValidatorsRoot represents ssz.HashTreeRoot(state.validators).
|
||||
// GenesisValidatorsRoot represents state.validators.HashTreeRoot().
|
||||
GenesisValidatorsRoot []byte
|
||||
}
|
||||
|
||||
|
||||
@@ -18,12 +18,13 @@ go_library(
|
||||
visibility = [
|
||||
"//beacon-chain:__subpackages__",
|
||||
"//endtoend/evaluators:__pkg__",
|
||||
"//fuzz:__pkg__",
|
||||
"//shared/attestationutil:__pkg__",
|
||||
"//shared/benchutil/benchmark_files:__subpackages__",
|
||||
"//shared/depositutil:__pkg__",
|
||||
"//shared/interop:__pkg__",
|
||||
"//shared/keystore:__pkg__",
|
||||
"//shared/depositutil:__pkg__",
|
||||
"//shared/p2putils:__pkg__",
|
||||
"//shared/attestationutil:__pkg__",
|
||||
"//shared/testutil:__pkg__",
|
||||
"//slasher:__subpackages__",
|
||||
"//tools:__subpackages__",
|
||||
@@ -32,14 +33,16 @@ go_library(
|
||||
deps = [
|
||||
"//beacon-chain/cache:go_default_library",
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//beacon-chain/state/stateutil:go_default_library",
|
||||
"//proto/beacon/p2p/v1: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",
|
||||
"//shared/roughtime:go_default_library",
|
||||
"//shared/sliceutil:go_default_library",
|
||||
"//shared/timeutils:go_default_library",
|
||||
"@com_github_ferranbt_fastssz//:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@com_github_prysmaticlabs_ethereumapis//eth/v1alpha1:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
|
||||
@@ -66,17 +69,16 @@ go_test(
|
||||
deps = [
|
||||
"//beacon-chain/cache:go_default_library",
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//beacon-chain/state/stateutil:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//shared/bls:go_default_library",
|
||||
"//shared/bytesutil:go_default_library",
|
||||
"//shared/hashutil:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"//shared/roughtime:go_default_library",
|
||||
"//shared/sliceutil:go_default_library",
|
||||
"//shared/testutil:go_default_library",
|
||||
"//shared/testutil/assert:go_default_library",
|
||||
"//shared/testutil/require:go_default_library",
|
||||
"//shared/timeutils:go_default_library",
|
||||
"@com_github_google_gofuzz//:go_default_library",
|
||||
"@com_github_prysmaticlabs_ethereumapis//eth/v1alpha1:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
|
||||
|
||||
@@ -6,32 +6,12 @@ import (
|
||||
"time"
|
||||
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/hashutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/roughtime"
|
||||
"github.com/prysmaticlabs/prysm/shared/timeutils"
|
||||
)
|
||||
|
||||
// SlotSignature returns the signed signature of the hash tree root of input slot.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// def get_slot_signature(state: BeaconState, slot: Slot, privkey: int) -> BLSSignature:
|
||||
// domain = get_domain(state, DOMAIN_SELECTION_PROOF, compute_epoch_at_slot(slot))
|
||||
// signing_root = compute_signing_root(slot, domain)
|
||||
// return bls.Sign(privkey, signing_root)
|
||||
func SlotSignature(state *stateTrie.BeaconState, slot uint64, privKey bls.SecretKey) (bls.Signature, error) {
|
||||
d, err := Domain(state.Fork(), CurrentEpoch(state), params.BeaconConfig().DomainBeaconAttester, state.GenesisValidatorRoot())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s, err := ComputeSigningRoot(slot, d)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return privKey.Sign(s[:]), nil
|
||||
}
|
||||
|
||||
// IsAggregator returns true if the signature is from the input validator. The committee
|
||||
// count is provided as an argument rather than direct implementation from spec. Having
|
||||
// committee count as an argument allows cheaper computation at run time.
|
||||
@@ -124,7 +104,13 @@ func ComputeSubnetFromCommitteeAndSlot(activeValCount, comIdx, attSlot uint64) u
|
||||
// valid_attestation_slot = 98
|
||||
// In the attestation must be within the range of 95 to 100 in the example above.
|
||||
func ValidateAttestationTime(attSlot uint64, genesisTime time.Time) error {
|
||||
attTime := genesisTime.Add(time.Duration(attSlot*params.BeaconConfig().SecondsPerSlot) * time.Second)
|
||||
if err := ValidateSlotClock(attSlot, uint64(genesisTime.Unix())); err != nil {
|
||||
return err
|
||||
}
|
||||
attTime, err := SlotToTime(uint64(genesisTime.Unix()), attSlot)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
currentSlot := SlotsSince(genesisTime)
|
||||
|
||||
// A clock disparity allows for minor tolerances outside of the expected range. This value is
|
||||
@@ -133,7 +119,7 @@ func ValidateAttestationTime(attSlot uint64, genesisTime time.Time) error {
|
||||
|
||||
// An attestation cannot be from the future, so the upper bounds is set to now, with a minor
|
||||
// tolerance for peer clock disparity.
|
||||
upperBounds := roughtime.Now().Add(clockDisparity)
|
||||
upperBounds := timeutils.Now().Add(clockDisparity)
|
||||
|
||||
// An attestation cannot be older than the current slot - attestation propagation slot range
|
||||
// with a minor tolerance for peer clock disparity.
|
||||
@@ -141,9 +127,11 @@ func ValidateAttestationTime(attSlot uint64, genesisTime time.Time) error {
|
||||
if currentSlot > params.BeaconNetworkConfig().AttestationPropagationSlotRange {
|
||||
lowerBoundsSlot = currentSlot - params.BeaconNetworkConfig().AttestationPropagationSlotRange
|
||||
}
|
||||
lowerBounds := genesisTime.Add(
|
||||
time.Duration(lowerBoundsSlot*params.BeaconConfig().SecondsPerSlot) * time.Second,
|
||||
).Add(-clockDisparity)
|
||||
lowerTime, err := SlotToTime(uint64(genesisTime.Unix()), lowerBoundsSlot)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
lowerBounds := lowerTime.Add(-clockDisparity)
|
||||
|
||||
// Verify attestation slot within the time range.
|
||||
if attTime.Before(lowerBounds) || attTime.After(upperBounds) {
|
||||
|
||||
@@ -12,33 +12,12 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/roughtime"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
"github.com/prysmaticlabs/prysm/shared/timeutils"
|
||||
)
|
||||
|
||||
func TestAttestation_SlotSignature(t *testing.T) {
|
||||
priv := bls.RandKey()
|
||||
pub := priv.PublicKey()
|
||||
state, err := beaconstate.InitializeFromProto(&pb.BeaconState{
|
||||
Validators: []*ethpb.Validator{{PublicKey: pub.Marshal()}},
|
||||
Fork: &pb.Fork{
|
||||
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
Epoch: 0,
|
||||
},
|
||||
Slot: 100,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
slot := uint64(101)
|
||||
|
||||
sig, err := helpers.SlotSignature(state, slot, priv)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, helpers.ComputeDomainVerifySigningRoot(state, 0, helpers.CurrentEpoch(state), slot,
|
||||
params.BeaconConfig().DomainBeaconAttester, sig.Marshal()))
|
||||
}
|
||||
|
||||
func TestAttestation_IsAggregator(t *testing.T) {
|
||||
t.Run("aggregator", func(t *testing.T) {
|
||||
beaconState, privKeys := testutil.DeterministicGenesisState(t, 100)
|
||||
@@ -89,7 +68,7 @@ func TestAttestation_AggregateSignature(t *testing.T) {
|
||||
for i := 0; i < 100; i++ {
|
||||
priv := bls.RandKey()
|
||||
pub := priv.PublicKey()
|
||||
sig := priv.Sign(msg[:])
|
||||
sig := priv.Sign(msg)
|
||||
pubkeys = append(pubkeys, pub)
|
||||
att := ðpb.Attestation{Signature: sig.Marshal()}
|
||||
atts = append(atts, att)
|
||||
@@ -154,77 +133,83 @@ func Test_ValidateAttestationTime(t *testing.T) {
|
||||
genesisTime time.Time
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantErr bool
|
||||
name string
|
||||
args args
|
||||
wantedErr string
|
||||
}{
|
||||
{
|
||||
name: "attestation.slot == current_slot",
|
||||
args: args{
|
||||
attSlot: 15,
|
||||
genesisTime: roughtime.Now().Add(-15 * time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Second),
|
||||
genesisTime: timeutils.Now().Add(-15 * time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Second),
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "attestation.slot == current_slot, received in middle of slot",
|
||||
args: args{
|
||||
attSlot: 15,
|
||||
genesisTime: roughtime.Now().Add(
|
||||
genesisTime: timeutils.Now().Add(
|
||||
-15 * time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Second,
|
||||
).Add(-(time.Duration(params.BeaconConfig().SecondsPerSlot/2) * time.Second)),
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "attestation.slot == current_slot, received 200ms early",
|
||||
args: args{
|
||||
attSlot: 16,
|
||||
genesisTime: roughtime.Now().Add(
|
||||
genesisTime: timeutils.Now().Add(
|
||||
-16 * time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Second,
|
||||
).Add(-200 * time.Millisecond),
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "attestation.slot > current_slot",
|
||||
args: args{
|
||||
attSlot: 16,
|
||||
genesisTime: roughtime.Now().Add(-15 * time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Second),
|
||||
genesisTime: timeutils.Now().Add(-15 * time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Second),
|
||||
},
|
||||
wantErr: true,
|
||||
wantedErr: "not within attestation propagation range",
|
||||
},
|
||||
{
|
||||
name: "attestation.slot < current_slot-ATTESTATION_PROPAGATION_SLOT_RANGE",
|
||||
args: args{
|
||||
attSlot: 100 - params.BeaconNetworkConfig().AttestationPropagationSlotRange - 1,
|
||||
genesisTime: roughtime.Now().Add(-100 * time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Second),
|
||||
genesisTime: timeutils.Now().Add(-100 * time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Second),
|
||||
},
|
||||
wantErr: true,
|
||||
wantedErr: "not within attestation propagation range",
|
||||
},
|
||||
{
|
||||
name: "attestation.slot = current_slot-ATTESTATION_PROPAGATION_SLOT_RANGE",
|
||||
args: args{
|
||||
attSlot: 100 - params.BeaconNetworkConfig().AttestationPropagationSlotRange,
|
||||
genesisTime: roughtime.Now().Add(-100 * time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Second),
|
||||
genesisTime: timeutils.Now().Add(-100 * time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Second),
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "attestation.slot = current_slot-ATTESTATION_PROPAGATION_SLOT_RANGE, received 200ms late",
|
||||
args: args{
|
||||
attSlot: 100 - params.BeaconNetworkConfig().AttestationPropagationSlotRange,
|
||||
genesisTime: roughtime.Now().Add(
|
||||
genesisTime: timeutils.Now().Add(
|
||||
-100 * time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Second,
|
||||
).Add(200 * time.Millisecond),
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "attestation.slot is well beyond current slot",
|
||||
args: args{
|
||||
attSlot: 1 << 32,
|
||||
genesisTime: timeutils.Now().Add(-15 * time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Second),
|
||||
},
|
||||
wantedErr: "which exceeds max allowed value relative to the local clock",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if err := helpers.ValidateAttestationTime(tt.args.attSlot, tt.args.genesisTime); (err != nil) != tt.wantErr {
|
||||
t.Errorf("validateAggregateAttTime() error = %v, wantErr %v", err, tt.wantErr)
|
||||
err := helpers.ValidateAttestationTime(tt.args.attSlot, tt.args.genesisTime)
|
||||
if tt.wantedErr != "" {
|
||||
assert.ErrorContains(t, tt.wantedErr, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -32,5 +32,9 @@ func BlockRootAtSlot(state *stateTrie.BeaconState, slot uint64) ([]byte, error)
|
||||
// """
|
||||
// return get_block_root_at_slot(state, compute_start_slot_at_epoch(epoch))
|
||||
func BlockRoot(state *stateTrie.BeaconState, epoch uint64) ([]byte, error) {
|
||||
return BlockRootAtSlot(state, StartSlot(epoch))
|
||||
s, err := StartSlot(epoch)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return BlockRootAtSlot(state, s)
|
||||
}
|
||||
|
||||
@@ -12,12 +12,14 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/cache"
|
||||
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/hashutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/sliceutil"
|
||||
)
|
||||
|
||||
var committeeCache = cache.NewCommitteesCache()
|
||||
var proposerIndicesCache = cache.NewProposerIndicesCache()
|
||||
|
||||
// SlotCommitteeCount returns the number of crosslink committees of a slot. The
|
||||
// active validator count is provided as an argument rather than a direct implementation
|
||||
@@ -143,7 +145,30 @@ func ComputeCommittee(
|
||||
// for fast computation of committees.
|
||||
// Reference implementation: https://github.com/protolambda/eth2-shuffle
|
||||
shuffledList, err := UnshuffleList(shuffledIndices, seed)
|
||||
return shuffledList[start:end], err
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// This updates the cache on a miss.
|
||||
if featureconfig.Get().UseCheckPointInfoCache {
|
||||
sortedIndices := make([]uint64, len(indices))
|
||||
copy(sortedIndices, indices)
|
||||
sort.Slice(sortedIndices, func(i, j int) bool {
|
||||
return sortedIndices[i] < sortedIndices[j]
|
||||
})
|
||||
|
||||
count = SlotCommitteeCount(uint64(len(shuffledIndices)))
|
||||
if err := committeeCache.AddCommitteeShuffledList(&cache.Committees{
|
||||
ShuffledIndices: shuffledList,
|
||||
CommitteeCount: count * params.BeaconConfig().SlotsPerEpoch,
|
||||
Seed: seed,
|
||||
SortedIndices: sortedIndices,
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return shuffledList[start:end], nil
|
||||
}
|
||||
|
||||
// CommitteeAssignmentContainer represents a committee, index, and attester slot for a given epoch.
|
||||
@@ -176,7 +201,10 @@ func CommitteeAssignments(
|
||||
// We determine the slots in which proposers are supposed to act.
|
||||
// Some validators may need to propose multiple times per epoch, so
|
||||
// we use a map of proposer idx -> []slot to keep track of this possibility.
|
||||
startSlot := StartSlot(epoch)
|
||||
startSlot, err := StartSlot(epoch)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
proposerIndexToSlots := make(map[uint64][]uint64, params.BeaconConfig().SlotsPerEpoch)
|
||||
for slot := startSlot; slot < startSlot+params.BeaconConfig().SlotsPerEpoch; slot++ {
|
||||
// Skip proposer assignment for genesis slot.
|
||||
@@ -285,7 +313,8 @@ func UpdateCommitteeCache(state *stateTrie.BeaconState, epoch uint64) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, exists, err := committeeCache.CommitteeCache.GetByKey(string(seed[:])); err == nil && exists {
|
||||
|
||||
if committeeCache.HasEntry(string(seed[:])) {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -320,29 +349,38 @@ func UpdateCommitteeCache(state *stateTrie.BeaconState, epoch uint64) error {
|
||||
|
||||
// UpdateProposerIndicesInCache updates proposer indices entry of the committee cache.
|
||||
func UpdateProposerIndicesInCache(state *stateTrie.BeaconState, epoch uint64) error {
|
||||
// The cache uses the block root at the last epoch slot as key. (e.g. for epoch 1, the key is root at slot 31)
|
||||
// Which is the reason why we skip genesis epoch.
|
||||
if epoch <= params.BeaconConfig().GenesisEpoch {
|
||||
return nil
|
||||
}
|
||||
|
||||
indices, err := ActiveValidatorIndices(state, epoch)
|
||||
if err != nil {
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
proposerIndices, err := precomputeProposerIndices(state, indices)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// The committee cache uses attester domain seed as key.
|
||||
seed, err := Seed(state, epoch, params.BeaconConfig().DomainBeaconAttester)
|
||||
s, err := EndSlot(PrevEpoch(state))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := committeeCache.AddProposerIndicesList(seed, proposerIndices); err != nil {
|
||||
r, err := BlockRootAtSlot(state, s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
return proposerIndicesCache.AddProposerIndices(&cache.ProposerIndices{
|
||||
BlockRoot: bytesutil.ToBytes32(r),
|
||||
ProposerIndices: proposerIndices,
|
||||
})
|
||||
}
|
||||
|
||||
// ClearCache clears the committee cache
|
||||
func ClearCache() {
|
||||
committeeCache = cache.NewCommitteesCache()
|
||||
proposerIndicesCache = cache.NewProposerIndicesCache()
|
||||
}
|
||||
|
||||
// This computes proposer indices of the current epoch and returns a list of proposer indices,
|
||||
@@ -356,7 +394,10 @@ func precomputeProposerIndices(state *stateTrie.BeaconState, activeIndices []uin
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not generate seed")
|
||||
}
|
||||
slot := StartSlot(e)
|
||||
slot, err := StartSlot(e)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i := uint64(0); i < params.BeaconConfig().SlotsPerEpoch; i++ {
|
||||
seedWithSlot := append(seed[:], bytesutil.Bytes8(slot+i)...)
|
||||
seedWithSlotHash := hashFunc(seedWithSlot)
|
||||
|
||||
@@ -230,8 +230,10 @@ func TestCommitteeAssignments_EverySlotHasMin1Proposer(t *testing.T) {
|
||||
}
|
||||
}
|
||||
assert.Equal(t, params.BeaconConfig().SlotsPerEpoch, uint64(len(slotsWithProposers)), "Unexpected slots")
|
||||
startSlot := StartSlot(epoch)
|
||||
endSlot := StartSlot(epoch + 1)
|
||||
startSlot, err := StartSlot(epoch)
|
||||
require.NoError(t, err)
|
||||
endSlot, err := StartSlot(epoch + 1)
|
||||
require.NoError(t, err)
|
||||
for i := startSlot; i < endSlot; i++ {
|
||||
hasProposer := slotsWithProposers[i]
|
||||
assert.Equal(t, true, hasProposer, "Expected every slot in epoch 1 to have a proposer, slot %d did not", i)
|
||||
@@ -263,7 +265,7 @@ func TestVerifyAttestationBitfieldLengths_OK(t *testing.T) {
|
||||
AggregationBits: bitfield.Bitlist{0x05},
|
||||
Data: ðpb.AttestationData{
|
||||
CommitteeIndex: 5,
|
||||
Target: ðpb.Checkpoint{},
|
||||
Target: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
},
|
||||
},
|
||||
stateSlot: 5,
|
||||
@@ -274,7 +276,7 @@ func TestVerifyAttestationBitfieldLengths_OK(t *testing.T) {
|
||||
AggregationBits: bitfield.Bitlist{0x06},
|
||||
Data: ðpb.AttestationData{
|
||||
CommitteeIndex: 10,
|
||||
Target: ðpb.Checkpoint{},
|
||||
Target: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
},
|
||||
},
|
||||
stateSlot: 10,
|
||||
@@ -284,7 +286,7 @@ func TestVerifyAttestationBitfieldLengths_OK(t *testing.T) {
|
||||
AggregationBits: bitfield.Bitlist{0x06},
|
||||
Data: ðpb.AttestationData{
|
||||
CommitteeIndex: 20,
|
||||
Target: ðpb.Checkpoint{},
|
||||
Target: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
},
|
||||
},
|
||||
stateSlot: 20,
|
||||
@@ -294,7 +296,7 @@ func TestVerifyAttestationBitfieldLengths_OK(t *testing.T) {
|
||||
AggregationBits: bitfield.Bitlist{0x06},
|
||||
Data: ðpb.AttestationData{
|
||||
CommitteeIndex: 20,
|
||||
Target: ðpb.Checkpoint{},
|
||||
Target: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
},
|
||||
},
|
||||
stateSlot: 20,
|
||||
@@ -304,7 +306,7 @@ func TestVerifyAttestationBitfieldLengths_OK(t *testing.T) {
|
||||
AggregationBits: bitfield.Bitlist{0xFF, 0xC0, 0x01},
|
||||
Data: ðpb.AttestationData{
|
||||
CommitteeIndex: 5,
|
||||
Target: ðpb.Checkpoint{},
|
||||
Target: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
},
|
||||
},
|
||||
stateSlot: 5,
|
||||
@@ -315,7 +317,7 @@ func TestVerifyAttestationBitfieldLengths_OK(t *testing.T) {
|
||||
AggregationBits: bitfield.Bitlist{0xFF, 0x01},
|
||||
Data: ðpb.AttestationData{
|
||||
CommitteeIndex: 20,
|
||||
Target: ðpb.Checkpoint{},
|
||||
Target: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
},
|
||||
},
|
||||
stateSlot: 20,
|
||||
@@ -328,14 +330,9 @@ func TestVerifyAttestationBitfieldLengths_OK(t *testing.T) {
|
||||
require.NoError(t, state.SetSlot(tt.stateSlot))
|
||||
err := VerifyAttestationBitfieldLengths(state, tt.attestation)
|
||||
if tt.verificationFailure {
|
||||
if err == nil {
|
||||
t.Error("verification succeeded when it was supposed to fail")
|
||||
}
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("%d Failed to verify bitfield: %v", i, err)
|
||||
continue
|
||||
assert.NotNil(t, err, "Verification succeeded when it was supposed to fail")
|
||||
} else {
|
||||
assert.NoError(t, err, "%d Failed to verify bitfield: %v", i, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -395,7 +392,7 @@ func TestUpdateCommitteeCache_CanUpdate(t *testing.T) {
|
||||
seed, err := Seed(state, epoch, params.BeaconConfig().DomainBeaconAttester)
|
||||
require.NoError(t, err)
|
||||
|
||||
indices, err = committeeCache.Committee(StartSlot(epoch), seed, idx)
|
||||
indices, err = committeeCache.Committee(epoch*params.BeaconConfig().SlotsPerEpoch, seed, idx)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, params.BeaconConfig().TargetCommitteeSize, uint64(len(indices)), "Did not save correct indices lengths")
|
||||
}
|
||||
@@ -631,3 +628,9 @@ func TestPrecomputeProposerIndices_Ok(t *testing.T) {
|
||||
}
|
||||
assert.DeepEqual(t, wantedProposerIndices, proposerIndices, "Did not precompute proposer indices correctly")
|
||||
}
|
||||
|
||||
func TestUpdateProposerIndicesInCache_CouldNotGetActiveIndices(t *testing.T) {
|
||||
err := UpdateProposerIndicesInCache(&beaconstate.BeaconState{}, 1)
|
||||
want := "nil inner state"
|
||||
require.ErrorContains(t, want, err)
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package helpers
|
||||
|
||||
import (
|
||||
fssz "github.com/ferranbt/fastssz"
|
||||
"github.com/pkg/errors"
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/go-ssz"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
|
||||
p2ppb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
@@ -48,16 +48,14 @@ func ComputeDomainAndSign(state *state.BeaconState, epoch uint64, obj interface{
|
||||
// domain=domain,
|
||||
// ))
|
||||
func ComputeSigningRoot(object interface{}, domain []byte) ([32]byte, error) {
|
||||
if object == nil {
|
||||
return [32]byte{}, errors.New("cannot compute signing root of nil")
|
||||
}
|
||||
return signingData(func() ([32]byte, error) {
|
||||
switch t := object.(type) {
|
||||
case *ethpb.BeaconBlock:
|
||||
return stateutil.BlockRoot(t)
|
||||
case *ethpb.AttestationData:
|
||||
return stateutil.AttestationDataRoot(t)
|
||||
default:
|
||||
// utilise generic ssz library
|
||||
return ssz.HashTreeRoot(object)
|
||||
if v, ok := object.(fssz.HashRoot); ok {
|
||||
return v.HashTreeRoot()
|
||||
}
|
||||
return ssz.HashTreeRoot(object)
|
||||
}, domain)
|
||||
}
|
||||
|
||||
@@ -72,7 +70,7 @@ func signingData(rootFunc func() ([32]byte, error), domain []byte) ([32]byte, er
|
||||
ObjectRoot: objRoot[:],
|
||||
Domain: domain,
|
||||
}
|
||||
return ssz.HashTreeRoot(container)
|
||||
return container.HashTreeRoot()
|
||||
}
|
||||
|
||||
// ComputeDomainVerifySigningRoot computes domain and verifies signing root of an object given the beacon state, validator index and signature.
|
||||
@@ -119,7 +117,11 @@ func VerifyBlockSigningRoot(blk *ethpb.BeaconBlock, pub []byte, signature []byte
|
||||
publicKey := set.PublicKeys[0]
|
||||
root := set.Messages[0]
|
||||
|
||||
if !sig.Verify(publicKey, root[:]) {
|
||||
rSig, err := bls.SignatureFromBytes(sig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !rSig.Verify(publicKey, root[:]) {
|
||||
return ErrSigFailedToVerify
|
||||
}
|
||||
return nil
|
||||
@@ -132,19 +134,13 @@ func RetrieveBlockSignatureSet(blk *ethpb.BeaconBlock, pub []byte, signature []b
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not convert bytes to public key")
|
||||
}
|
||||
sig, err := bls.SignatureFromBytes(signature)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not convert bytes to signature")
|
||||
}
|
||||
root, err := signingData(func() ([32]byte, error) {
|
||||
// utilize custom block hashing function
|
||||
return stateutil.BlockRoot(blk)
|
||||
}, domain)
|
||||
// utilize custom block hashing function
|
||||
root, err := signingData(blk.HashTreeRoot, domain)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not compute signing root")
|
||||
}
|
||||
return &bls.SignatureSet{
|
||||
Signatures: []bls.Signature{sig},
|
||||
Signatures: [][]byte{signature},
|
||||
PublicKeys: []bls.PublicKey{publicKey},
|
||||
Messages: [][32]byte{root},
|
||||
}, nil
|
||||
@@ -160,9 +156,7 @@ func VerifyBlockHeaderSigningRoot(blkHdr *ethpb.BeaconBlockHeader, pub []byte, s
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not convert bytes to signature")
|
||||
}
|
||||
root, err := signingData(func() ([32]byte, error) {
|
||||
return stateutil.BlockHeaderRoot(blkHdr)
|
||||
}, domain)
|
||||
root, err := signingData(blkHdr.HashTreeRoot, domain)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not compute signing root")
|
||||
}
|
||||
@@ -225,10 +219,10 @@ func domain(domainType [DomainByteLength]byte, forkDataRoot []byte) []byte {
|
||||
// genesis_validators_root=genesis_validators_root,
|
||||
// ))
|
||||
func computeForkDataRoot(version []byte, root []byte) ([32]byte, error) {
|
||||
r, err := ssz.HashTreeRoot(&pb.ForkData{
|
||||
r, err := (&pb.ForkData{
|
||||
CurrentVersion: version,
|
||||
GenesisValidatorsRoot: root,
|
||||
})
|
||||
}).HashTreeRoot()
|
||||
if err != nil {
|
||||
return [32]byte{}, err
|
||||
}
|
||||
@@ -248,7 +242,7 @@ func computeForkDataRoot(version []byte, root []byte) ([32]byte, error) {
|
||||
func ComputeForkDigest(version []byte, genesisValidatorsRoot []byte) ([4]byte, error) {
|
||||
dataRoot, err := computeForkDataRoot(version, genesisValidatorsRoot)
|
||||
if err != nil {
|
||||
return [4]byte{}, nil
|
||||
return [4]byte{}, err
|
||||
}
|
||||
return bytesutil.ToBytes4(dataRoot[:]), nil
|
||||
}
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
package helpers
|
||||
package helpers_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
fuzz "github.com/google/gofuzz"
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
ethereum_beacon_p2p_v1 "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
func TestSigningRoot_ComputeOK(t *testing.T) {
|
||||
emptyBlock := ðpb.BeaconBlock{}
|
||||
_, err := ComputeSigningRoot(emptyBlock, []byte{'T', 'E', 'S', 'T'})
|
||||
emptyBlock := testutil.NewBeaconBlock()
|
||||
_, err := helpers.ComputeSigningRoot(emptyBlock, bytesutil.PadTo([]byte{'T', 'E', 'S', 'T'}, 32))
|
||||
assert.NoError(t, err, "Could not compute signing root of block")
|
||||
}
|
||||
|
||||
@@ -25,38 +25,21 @@ func TestComputeDomain_OK(t *testing.T) {
|
||||
domainType [4]byte
|
||||
domain []byte
|
||||
}{
|
||||
{epoch: 1, domainType: [4]byte{4, 0, 0, 0}, domain: []byte{4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
|
||||
{epoch: 2, domainType: [4]byte{4, 0, 0, 0}, domain: []byte{4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
|
||||
{epoch: 2, domainType: [4]byte{5, 0, 0, 0}, domain: []byte{5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
|
||||
{epoch: 3, domainType: [4]byte{4, 0, 0, 0}, domain: []byte{4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
|
||||
{epoch: 3, domainType: [4]byte{5, 0, 0, 0}, domain: []byte{5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
|
||||
{epoch: 1, domainType: [4]byte{4, 0, 0, 0}, domain: []byte{4, 0, 0, 0, 245, 165, 253, 66, 209, 106, 32, 48, 39, 152, 239, 110, 211, 9, 151, 155, 67, 0, 61, 35, 32, 217, 240, 232, 234, 152, 49, 169}},
|
||||
{epoch: 2, domainType: [4]byte{4, 0, 0, 0}, domain: []byte{4, 0, 0, 0, 245, 165, 253, 66, 209, 106, 32, 48, 39, 152, 239, 110, 211, 9, 151, 155, 67, 0, 61, 35, 32, 217, 240, 232, 234, 152, 49, 169}},
|
||||
{epoch: 2, domainType: [4]byte{5, 0, 0, 0}, domain: []byte{5, 0, 0, 0, 245, 165, 253, 66, 209, 106, 32, 48, 39, 152, 239, 110, 211, 9, 151, 155, 67, 0, 61, 35, 32, 217, 240, 232, 234, 152, 49, 169}},
|
||||
{epoch: 3, domainType: [4]byte{4, 0, 0, 0}, domain: []byte{4, 0, 0, 0, 245, 165, 253, 66, 209, 106, 32, 48, 39, 152, 239, 110, 211, 9, 151, 155, 67, 0, 61, 35, 32, 217, 240, 232, 234, 152, 49, 169}},
|
||||
{epoch: 3, domainType: [4]byte{5, 0, 0, 0}, domain: []byte{5, 0, 0, 0, 245, 165, 253, 66, 209, 106, 32, 48, 39, 152, 239, 110, 211, 9, 151, 155, 67, 0, 61, 35, 32, 217, 240, 232, 234, 152, 49, 169}},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
if !bytes.Equal(domain(tt.domainType, params.BeaconConfig().ZeroHash[:]), tt.domain) {
|
||||
t.Errorf("wanted domain version: %d, got: %d", tt.domain, domain(tt.domainType, params.BeaconConfig().ZeroHash[:]))
|
||||
if got, err := helpers.ComputeDomain(tt.domainType, nil, nil); !bytes.Equal(got, tt.domain) {
|
||||
t.Errorf("wanted domain version: %d, got: %d", tt.domain, got)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSigningRoot_Compatibility(t *testing.T) {
|
||||
parRoot := [32]byte{'A'}
|
||||
stateRoot := [32]byte{'B'}
|
||||
blk := ðpb.BeaconBlock{
|
||||
Slot: 20,
|
||||
ProposerIndex: 20,
|
||||
ParentRoot: parRoot[:],
|
||||
StateRoot: stateRoot[:],
|
||||
Body: ðpb.BeaconBlockBody{},
|
||||
}
|
||||
root, err := ComputeSigningRoot(blk, params.BeaconConfig().DomainBeaconProposer[:])
|
||||
require.NoError(t, err)
|
||||
newRoot, err := signingData(func() ([32]byte, error) {
|
||||
return stateutil.BlockRoot(blk)
|
||||
}, params.BeaconConfig().DomainBeaconProposer[:])
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, root, newRoot, "Wanted root of %#x but got %#x", root, newRoot)
|
||||
}
|
||||
|
||||
func TestComputeForkDigest_OK(t *testing.T) {
|
||||
tests := []struct {
|
||||
version []byte
|
||||
@@ -68,7 +51,7 @@ func TestComputeForkDigest_OK(t *testing.T) {
|
||||
{version: []byte{'b', 'w', 'r', 't'}, root: [32]byte{'r', 'd', 'c'}, result: [4]byte{0x83, 0x34, 0x38, 0x88}},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
digest, err := ComputeForkDigest(tt.version, tt.root[:])
|
||||
digest, err := helpers.ComputeForkDigest(tt.version, tt.root[:])
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tt.result, digest, "Wanted domain version: %#x, got: %#x", digest, tt.result)
|
||||
}
|
||||
@@ -92,8 +75,9 @@ func TestFuzzverifySigningRoot_10000(t *testing.T) {
|
||||
fuzzer.Fuzz(&p)
|
||||
fuzzer.Fuzz(&s)
|
||||
fuzzer.Fuzz(&d)
|
||||
err := VerifySigningRoot(state, pubkey[:], sig[:], domain[:])
|
||||
err = VerifySigningRoot(state, p, s, d)
|
||||
err := helpers.VerifySigningRoot(state, pubkey[:], sig[:], domain[:])
|
||||
_ = err
|
||||
err = helpers.VerifySigningRoot(state, p, s, d)
|
||||
_ = err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,11 +5,17 @@ import (
|
||||
"math"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/shared/mathutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/roughtime"
|
||||
"github.com/prysmaticlabs/prysm/shared/timeutils"
|
||||
)
|
||||
|
||||
// MaxSlotBuffer specifies the max buffer given to slots from
|
||||
// incoming objects. (24 mins with mainnet spec)
|
||||
const MaxSlotBuffer = uint64(1 << 7)
|
||||
|
||||
// SlotToEpoch returns the epoch number of the input slot.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
@@ -68,9 +74,26 @@ func NextEpoch(state *stateTrie.BeaconState) uint64 {
|
||||
// """
|
||||
// Return the start slot of ``epoch``.
|
||||
// """
|
||||
// return Slot(epoch * SLOTS_PER_EPOCH
|
||||
func StartSlot(epoch uint64) uint64 {
|
||||
return epoch * params.BeaconConfig().SlotsPerEpoch
|
||||
// return Slot(epoch * SLOTS_PER_EPOCH)
|
||||
func StartSlot(epoch uint64) (uint64, error) {
|
||||
slot, err := mathutil.Mul64(epoch, params.BeaconConfig().SlotsPerEpoch)
|
||||
if err != nil {
|
||||
return slot, errors.Errorf("start slot calculation overflows: %v", err)
|
||||
}
|
||||
return slot, nil
|
||||
}
|
||||
|
||||
// EndSlot returns the last slot number of the
|
||||
// current epoch.
|
||||
func EndSlot(epoch uint64) (uint64, error) {
|
||||
if epoch == math.MaxUint64 {
|
||||
return 0, errors.New("start slot calculation overflows")
|
||||
}
|
||||
slot, err := StartSlot(epoch + 1)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return slot - 1, nil
|
||||
}
|
||||
|
||||
// IsEpochStart returns true if the given slot number is an epoch starting slot
|
||||
@@ -87,7 +110,7 @@ func IsEpochEnd(slot uint64) bool {
|
||||
|
||||
// SlotsSinceEpochStarts returns number of slots since the start of the epoch.
|
||||
func SlotsSinceEpochStarts(slot uint64) uint64 {
|
||||
return slot - StartSlot(SlotToEpoch(slot))
|
||||
return slot % params.BeaconConfig().SlotsPerEpoch
|
||||
}
|
||||
|
||||
// VerifySlotTime validates the input slot is not from the future.
|
||||
@@ -96,7 +119,14 @@ func VerifySlotTime(genesisTime uint64, slot uint64, timeTolerance time.Duration
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
currentTime := roughtime.Now()
|
||||
|
||||
// Defensive check to ensure unreasonable slots are rejected
|
||||
// straight away.
|
||||
if err := ValidateSlotClock(slot, genesisTime); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
currentTime := timeutils.Now()
|
||||
diff := slotTime.Sub(currentTime)
|
||||
|
||||
if diff > timeTolerance {
|
||||
@@ -107,25 +137,44 @@ func VerifySlotTime(genesisTime uint64, slot uint64, timeTolerance time.Duration
|
||||
|
||||
// SlotToTime takes the given slot and genesis time to determine the start time of the slot.
|
||||
func SlotToTime(genesisTimeSec uint64, slot uint64) (time.Time, error) {
|
||||
if slot >= math.MaxInt64 {
|
||||
return time.Unix(0, 0), fmt.Errorf("slot (%d) is in the far distant future", slot)
|
||||
timeSinceGenesis, err := mathutil.Mul64(slot, params.BeaconConfig().SecondsPerSlot)
|
||||
if err != nil {
|
||||
return time.Unix(0, 0), fmt.Errorf("slot (%d) is in the far distant future: %v", slot, err)
|
||||
}
|
||||
timeSinceGenesis := slot * params.BeaconConfig().SecondsPerSlot
|
||||
return time.Unix(int64(genesisTimeSec+timeSinceGenesis), 0), nil
|
||||
sTime, err := mathutil.Add64(genesisTimeSec, timeSinceGenesis)
|
||||
if err != nil {
|
||||
return time.Unix(0, 0), fmt.Errorf("slot (%d) is in the far distant future: %v", slot, err)
|
||||
}
|
||||
return time.Unix(int64(sTime), 0), nil
|
||||
}
|
||||
|
||||
// SlotsSince computes the number of time slots that have occurred since the given timestamp.
|
||||
func SlotsSince(time time.Time) uint64 {
|
||||
return uint64(roughtime.Since(time).Seconds()) / params.BeaconConfig().SecondsPerSlot
|
||||
return CurrentSlot(uint64(time.Unix()))
|
||||
}
|
||||
|
||||
// GenesisTime prioritizes to return the genesis time in config unless the config
|
||||
// genesis time is 0. Then it returns the genesis time in state.
|
||||
func GenesisTime(state *stateTrie.BeaconState) uint64 {
|
||||
if params.BeaconConfig().GenesisTime == 0 {
|
||||
return state.GenesisTime()
|
||||
// CurrentSlot returns the current slot as determined by the local clock and
|
||||
// provided genesis time.
|
||||
func CurrentSlot(genesisTimeSec uint64) uint64 {
|
||||
now := timeutils.Now().Unix()
|
||||
genesis := int64(genesisTimeSec)
|
||||
if now < genesis {
|
||||
return 0
|
||||
}
|
||||
return params.BeaconConfig().GenesisTime
|
||||
return uint64(now-genesis) / params.BeaconConfig().SecondsPerSlot
|
||||
}
|
||||
|
||||
// ValidateSlotClock validates a provided slot against the local
|
||||
// clock to ensure slots that are unreasonable are returned with
|
||||
// an error.
|
||||
func ValidateSlotClock(slot uint64, genesisTimeSec uint64) error {
|
||||
maxPossibleSlot := CurrentSlot(genesisTimeSec) + MaxSlotBuffer
|
||||
// Defensive check to ensure that we only process slots up to a hard limit
|
||||
// from our local clock.
|
||||
if slot > maxPossibleSlot {
|
||||
return fmt.Errorf("slot %d > %d which exceeds max allowed value relative to the local clock", slot, maxPossibleSlot)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RoundUpToNearestEpoch rounds up the provided slot value to the nearest epoch.
|
||||
@@ -136,3 +185,36 @@ func RoundUpToNearestEpoch(slot uint64) uint64 {
|
||||
}
|
||||
return slot
|
||||
}
|
||||
|
||||
// WeakSubjectivityCheckptEpoch returns the epoch of the latest weak subjectivity checkpoint for the active validator count and
|
||||
// finalized epoch.
|
||||
//
|
||||
// Reference spec implementation:
|
||||
// https://github.com/ethereum/eth2.0-specs/blob/weak-subjectivity-guide/specs/phase0/weak-subjectivity.md#calculating-the-weak-subjectivity-period
|
||||
// def compute_weak_subjectivity_period(state):
|
||||
// weak_subjectivity_period = MIN_VALIDATOR_WITHDRAWABILITY_DELAY
|
||||
// val_count = len(get_active_validator_indices(state, get_current_epoch(state)))
|
||||
// if val_count >= MIN_PER_EPOCH_CHURN_LIMIT * CHURN_LIMIT_QUOTIENT:
|
||||
// weak_subjectivity_period += SAFETY_DECAY*CHURN_LIMIT_QUOTIENT/(2*100)
|
||||
// else:
|
||||
// weak_subjectivity_period += SAFETY_DECAY*val_count/(2*100*MIN_PER_EPOCH_CHURN_LIMIT)
|
||||
// return weak_subjectivity_period
|
||||
func WeakSubjectivityCheckptEpoch(valCount uint64) (uint64, error) {
|
||||
wsp := params.BeaconConfig().MinValidatorWithdrawabilityDelay
|
||||
|
||||
m := params.BeaconConfig().MinPerEpochChurnLimit
|
||||
q := params.BeaconConfig().ChurnLimitQuotient
|
||||
d := params.BeaconConfig().SafetyDecay
|
||||
if valCount >= m*q {
|
||||
v := d * q / (2 * 100)
|
||||
wsp += v
|
||||
} else {
|
||||
v, err := mathutil.Mul64(d, valCount)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
v = v / (2 * 100 * m)
|
||||
wsp += v
|
||||
}
|
||||
return wsp, nil
|
||||
}
|
||||
|
||||
@@ -2,13 +2,12 @@ package helpers
|
||||
|
||||
import (
|
||||
"math"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/shared/roughtime"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
"github.com/prysmaticlabs/prysm/shared/timeutils"
|
||||
|
||||
beaconstate "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
@@ -87,14 +86,47 @@ func TestEpochStartSlot_OK(t *testing.T) {
|
||||
tests := []struct {
|
||||
epoch uint64
|
||||
startSlot uint64
|
||||
error bool
|
||||
}{
|
||||
{epoch: 0, startSlot: 0 * params.BeaconConfig().SlotsPerEpoch},
|
||||
{epoch: 1, startSlot: 1 * params.BeaconConfig().SlotsPerEpoch},
|
||||
{epoch: 10, startSlot: 10 * params.BeaconConfig().SlotsPerEpoch},
|
||||
{epoch: 0, startSlot: 0 * params.BeaconConfig().SlotsPerEpoch, error: false},
|
||||
{epoch: 1, startSlot: 1 * params.BeaconConfig().SlotsPerEpoch, error: false},
|
||||
{epoch: 10, startSlot: 10 * params.BeaconConfig().SlotsPerEpoch, error: false},
|
||||
{epoch: 1 << 58, startSlot: 1 << 63, error: false},
|
||||
{epoch: 1 << 59, startSlot: 1 << 63, error: true},
|
||||
{epoch: 1 << 60, startSlot: 1 << 63, error: true},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
state := &pb.BeaconState{Slot: tt.epoch}
|
||||
assert.Equal(t, tt.startSlot, StartSlot(tt.epoch), "StartSlot(%d)", state.Slot)
|
||||
ss, err := StartSlot(tt.epoch)
|
||||
if !tt.error {
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tt.startSlot, ss, "StartSlot(%d)", tt.epoch)
|
||||
} else {
|
||||
require.ErrorContains(t, "start slot calculation overflow", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEpochEndSlot_OK(t *testing.T) {
|
||||
tests := []struct {
|
||||
epoch uint64
|
||||
startSlot uint64
|
||||
error bool
|
||||
}{
|
||||
{epoch: 0, startSlot: 1*params.BeaconConfig().SlotsPerEpoch - 1, error: false},
|
||||
{epoch: 1, startSlot: 2*params.BeaconConfig().SlotsPerEpoch - 1, error: false},
|
||||
{epoch: 10, startSlot: 11*params.BeaconConfig().SlotsPerEpoch - 1, error: false},
|
||||
{epoch: 1 << 59, startSlot: 1 << 63, error: true},
|
||||
{epoch: 1 << 60, startSlot: 1 << 63, error: true},
|
||||
{epoch: math.MaxUint64, startSlot: 0, error: true},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
ss, err := EndSlot(tt.epoch)
|
||||
if !tt.error {
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tt.startSlot, ss, "StartSlot(%d)", tt.epoch)
|
||||
} else {
|
||||
require.ErrorContains(t, "start slot calculation overflow", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,10 +222,10 @@ func TestSlotToTime(t *testing.T) {
|
||||
slot uint64
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want time.Time
|
||||
wantErr bool
|
||||
name string
|
||||
args args
|
||||
want time.Time
|
||||
wantedErr string
|
||||
}{
|
||||
{
|
||||
name: "slot_0",
|
||||
@@ -201,8 +233,7 @@ func TestSlotToTime(t *testing.T) {
|
||||
genesisTimeSec: 0,
|
||||
slot: 0,
|
||||
},
|
||||
want: time.Unix(0, 0),
|
||||
wantErr: false,
|
||||
want: time.Unix(0, 0),
|
||||
},
|
||||
{
|
||||
name: "slot_1",
|
||||
@@ -210,8 +241,7 @@ func TestSlotToTime(t *testing.T) {
|
||||
genesisTimeSec: 0,
|
||||
slot: 1,
|
||||
},
|
||||
want: time.Unix(int64(1*params.BeaconConfig().SecondsPerSlot), 0),
|
||||
wantErr: false,
|
||||
want: time.Unix(int64(1*params.BeaconConfig().SecondsPerSlot), 0),
|
||||
},
|
||||
{
|
||||
name: "slot_12",
|
||||
@@ -219,8 +249,7 @@ func TestSlotToTime(t *testing.T) {
|
||||
genesisTimeSec: 500,
|
||||
slot: 12,
|
||||
},
|
||||
want: time.Unix(500+int64(12*params.BeaconConfig().SecondsPerSlot), 0),
|
||||
wantErr: false,
|
||||
want: time.Unix(500+int64(12*params.BeaconConfig().SecondsPerSlot), 0),
|
||||
},
|
||||
{
|
||||
name: "overflow",
|
||||
@@ -228,13 +257,17 @@ func TestSlotToTime(t *testing.T) {
|
||||
genesisTimeSec: 500,
|
||||
slot: math.MaxUint64,
|
||||
},
|
||||
wantErr: true,
|
||||
wantedErr: "is in the far distant future",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got, err := SlotToTime(tt.args.genesisTimeSec, tt.args.slot); (err != nil) != tt.wantErr && !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("SlotToTime() = %v, want %v", got, tt.want)
|
||||
got, err := SlotToTime(tt.args.genesisTimeSec, tt.args.slot)
|
||||
if tt.wantedErr != "" {
|
||||
assert.ErrorContains(t, tt.wantedErr, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
assert.DeepEqual(t, tt.want, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -247,76 +280,91 @@ func TestVerifySlotTime(t *testing.T) {
|
||||
timeTolerance time.Duration
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantErr bool
|
||||
name string
|
||||
args args
|
||||
wantedErr string
|
||||
}{
|
||||
{
|
||||
name: "Past slot",
|
||||
args: args{
|
||||
genesisTime: roughtime.Now().Add(-1 * 5 * time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Second).Unix(),
|
||||
genesisTime: timeutils.Now().Add(-1 * 5 * time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Second).Unix(),
|
||||
slot: 3,
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "within tolerance",
|
||||
args: args{
|
||||
genesisTime: roughtime.Now().Add(-1 * 5 * time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Second).Add(20 * time.Millisecond).Unix(),
|
||||
genesisTime: timeutils.Now().Add(-1 * 5 * time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Second).Add(20 * time.Millisecond).Unix(),
|
||||
slot: 5,
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "future slot",
|
||||
args: args{
|
||||
genesisTime: roughtime.Now().Add(-1 * 5 * time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Second).Unix(),
|
||||
genesisTime: timeutils.Now().Add(-1 * 5 * time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Second).Unix(),
|
||||
slot: 6,
|
||||
},
|
||||
wantErr: true,
|
||||
wantedErr: "could not process slot from the future",
|
||||
},
|
||||
{
|
||||
name: "max future slot",
|
||||
args: args{
|
||||
genesisTime: timeutils.Now().Add(-1 * 5 * time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Second).Unix(),
|
||||
slot: MaxSlotBuffer + 6,
|
||||
},
|
||||
wantedErr: "exceeds max allowed value relative to the local clock",
|
||||
},
|
||||
{
|
||||
name: "evil future slot",
|
||||
args: args{
|
||||
genesisTime: timeutils.Now().Add(-1 * 24 * time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Second).Unix(), // 24 slots in the past
|
||||
// Gets multiplied with slot duration, and results in an overflow. Wraps around to a valid time.
|
||||
// Lower than max signed int. And chosen specifically to wrap to a valid slot 24
|
||||
slot: ((^uint64(0)) / params.BeaconConfig().SecondsPerSlot) + 24,
|
||||
},
|
||||
wantedErr: "is in the far distant future",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if err := VerifySlotTime(uint64(tt.args.genesisTime), tt.args.slot, tt.args.timeTolerance); (err != nil) != tt.wantErr {
|
||||
t.Errorf("VerifySlotTime() error = %v, wantErr %v", err, tt.wantErr)
|
||||
err := VerifySlotTime(uint64(tt.args.genesisTime), tt.args.slot, tt.args.timeTolerance)
|
||||
if tt.wantedErr != "" {
|
||||
assert.ErrorContains(t, tt.wantedErr, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenesisTime(t *testing.T) {
|
||||
type args struct {
|
||||
configTime uint64
|
||||
stateTime uint64
|
||||
}
|
||||
func TestValidateSlotClock_HandlesBadSlot(t *testing.T) {
|
||||
genTime := timeutils.Now().Add(-1 * time.Duration(MaxSlotBuffer) * time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Second).Unix()
|
||||
|
||||
assert.NoError(t, ValidateSlotClock(MaxSlotBuffer, uint64(genTime)), "unexpected error validating slot")
|
||||
assert.NoError(t, ValidateSlotClock(2*MaxSlotBuffer, uint64(genTime)), "unexpected error validating slot")
|
||||
assert.ErrorContains(t, "which exceeds max allowed value relative to the local clock", ValidateSlotClock(2*MaxSlotBuffer+1, uint64(genTime)), "no error from bad slot")
|
||||
assert.ErrorContains(t, "which exceeds max allowed value relative to the local clock", ValidateSlotClock(1<<63, uint64(genTime)), "no error from bad slot")
|
||||
}
|
||||
|
||||
func TestWeakSubjectivityCheckptEpoch(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want uint64
|
||||
valCount uint64
|
||||
want uint64
|
||||
}{
|
||||
{
|
||||
name: "Use config genesis time",
|
||||
args: args{configTime: 1, stateTime: 2},
|
||||
want: 1,
|
||||
},
|
||||
{
|
||||
name: "Use state genesis time",
|
||||
args: args{configTime: 0, stateTime: 2},
|
||||
want: 2,
|
||||
},
|
||||
// Verifying these numbers aligned with the reference table defined:
|
||||
// https://github.com/ethereum/eth2.0-specs/blob/weak-subjectivity-guide/specs/phase0/weak-subjectivity.md#calculating-the-weak-subjectivity-period
|
||||
{valCount: params.BeaconConfig().MinGenesisActiveValidatorCount, want: 460},
|
||||
{valCount: params.BeaconConfig().MinGenesisActiveValidatorCount * 2, want: 665},
|
||||
{valCount: params.BeaconConfig().MinGenesisActiveValidatorCount * 4, want: 1075},
|
||||
{valCount: params.BeaconConfig().MinGenesisActiveValidatorCount * 8, want: 1894},
|
||||
{valCount: params.BeaconConfig().MinGenesisActiveValidatorCount * 16, want: 3532},
|
||||
{valCount: params.BeaconConfig().MinGenesisActiveValidatorCount * 32, want: 3532},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
c := params.BeaconConfig()
|
||||
c.GenesisTime = tt.args.configTime
|
||||
params.OverrideBeaconConfig(c)
|
||||
s := &pb.BeaconState{GenesisTime: tt.args.stateTime}
|
||||
state, err := beaconstate.InitializeFromProto(s)
|
||||
require.NoError(t, err)
|
||||
if got := GenesisTime(state); got != tt.want {
|
||||
t.Errorf("GenesisTime() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
got, err := WeakSubjectivityCheckptEpoch(tt.valCount)
|
||||
require.NoError(t, err)
|
||||
if got != tt.want {
|
||||
t.Errorf("WeakSubjectivityCheckptEpoch() = %v, want %v", got, tt.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,20 +175,30 @@ func ValidatorChurnLimit(activeValidatorCount uint64) (uint64, error) {
|
||||
// return compute_proposer_index(state, indices, seed)
|
||||
func BeaconProposerIndex(state *stateTrie.BeaconState) (uint64, error) {
|
||||
e := CurrentEpoch(state)
|
||||
|
||||
seed, err := Seed(state, e, params.BeaconConfig().DomainBeaconAttester)
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "could not generate seed")
|
||||
}
|
||||
proposerIndices, err := committeeCache.ProposerIndices(seed)
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "could not interface with committee cache")
|
||||
}
|
||||
if proposerIndices != nil {
|
||||
return proposerIndices[state.Slot()%params.BeaconConfig().SlotsPerEpoch], nil
|
||||
// The cache uses the block root of the previous epoch's last slot as key. (e.g. Starting epoch 1, slot 32, the key would be block root at slot 31)
|
||||
// For simplicity, the node will skip caching of genesis epoch.
|
||||
if e > params.BeaconConfig().GenesisEpoch {
|
||||
s, err := EndSlot(PrevEpoch(state))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
r, err := BlockRootAtSlot(state, s)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
proposerIndices, err := proposerIndicesCache.ProposerIndices(bytesutil.ToBytes32(r))
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "could not interface with committee cache")
|
||||
}
|
||||
if proposerIndices != nil {
|
||||
return proposerIndices[state.Slot()%params.BeaconConfig().SlotsPerEpoch], nil
|
||||
}
|
||||
if err := UpdateProposerIndicesInCache(state, e); err != nil {
|
||||
return 0, errors.Wrap(err, "could not update committee cache")
|
||||
}
|
||||
}
|
||||
|
||||
seed, err = Seed(state, e, params.BeaconConfig().DomainBeaconProposer)
|
||||
seed, err := Seed(state, e, params.BeaconConfig().DomainBeaconProposer)
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "could not generate seed")
|
||||
}
|
||||
@@ -201,19 +211,11 @@ func BeaconProposerIndex(state *stateTrie.BeaconState) (uint64, error) {
|
||||
return 0, errors.Wrap(err, "could not get active indices")
|
||||
}
|
||||
|
||||
if err := UpdateProposerIndicesInCache(state, e); err != nil {
|
||||
return 0, errors.Wrap(err, "could not update committee cache")
|
||||
}
|
||||
|
||||
return ComputeProposerIndex(state, indices, seedWithSlotHash)
|
||||
}
|
||||
|
||||
// ComputeProposerIndex returns the index sampled by effective balance, which is used to calculate proposer.
|
||||
//
|
||||
// This method is more efficient than ComputeProposerIndexWithValidators as it uses the read only validator
|
||||
// abstraction to retrieve validator related data. Whereas the other method requires a whole copy of the validator
|
||||
// set.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// def compute_proposer_index(state: BeaconState, indices: Sequence[ValidatorIndex], seed: Hash) -> ValidatorIndex:
|
||||
// """
|
||||
@@ -250,7 +252,7 @@ func ComputeProposerIndex(bState *stateTrie.BeaconState, activeIndices []uint64,
|
||||
randomByte := hashFunc(b)[i%32]
|
||||
v, err := bState.ValidatorAtIndexReadOnly(candidateIndex)
|
||||
if err != nil {
|
||||
return 0, nil
|
||||
return 0, err
|
||||
}
|
||||
effectiveBal := v.EffectiveBalance()
|
||||
|
||||
@@ -260,57 +262,6 @@ func ComputeProposerIndex(bState *stateTrie.BeaconState, activeIndices []uint64,
|
||||
}
|
||||
}
|
||||
|
||||
// ComputeProposerIndexWithValidators returns the index sampled by effective balance, which is used to calculate proposer.
|
||||
//
|
||||
// Note: This method signature deviates slightly from the spec recommended definition. The full
|
||||
// state object is not required to compute the proposer index.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// def compute_proposer_index(state: BeaconState, indices: Sequence[ValidatorIndex], seed: Hash) -> ValidatorIndex:
|
||||
// """
|
||||
// Return from ``indices`` a random index sampled by effective balance.
|
||||
// """
|
||||
// assert len(indices) > 0
|
||||
// MAX_RANDOM_BYTE = 2**8 - 1
|
||||
// i = 0
|
||||
// while True:
|
||||
// candidate_index = indices[compute_shuffled_index(ValidatorIndex(i % len(indices)), len(indices), seed)]
|
||||
// random_byte = hash(seed + int_to_bytes(i // 32, length=8))[i % 32]
|
||||
// effective_balance = state.validators[candidate_index].effective_balance
|
||||
// if effective_balance * MAX_RANDOM_BYTE >= MAX_EFFECTIVE_BALANCE * random_byte:
|
||||
// return ValidatorIndex(candidate_index)
|
||||
// i += 1
|
||||
// Deprecated: Prefer using the beacon state with ComputeProposerIndex to avoid an unnecessary copy of the validator set.
|
||||
func ComputeProposerIndexWithValidators(validators []*ethpb.Validator, activeIndices []uint64, seed [32]byte) (uint64, error) {
|
||||
length := uint64(len(activeIndices))
|
||||
if length == 0 {
|
||||
return 0, errors.New("empty active indices list")
|
||||
}
|
||||
maxRandomByte := uint64(1<<8 - 1)
|
||||
hashFunc := hashutil.CustomSHA256Hasher()
|
||||
|
||||
for i := uint64(0); ; i++ {
|
||||
candidateIndex, err := ComputeShuffledIndex(i%length, length, seed, true /* shuffle */)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
candidateIndex = activeIndices[candidateIndex]
|
||||
if candidateIndex >= uint64(len(validators)) {
|
||||
return 0, errors.New("active index out of range")
|
||||
}
|
||||
b := append(seed[:], bytesutil.Bytes8(i/32)...)
|
||||
randomByte := hashFunc(b)[i%32]
|
||||
v := validators[candidateIndex]
|
||||
var effectiveBal uint64
|
||||
if v != nil {
|
||||
effectiveBal = v.EffectiveBalance
|
||||
}
|
||||
if effectiveBal*maxRandomByte >= params.BeaconConfig().MaxEffectiveBalance*uint64(randomByte) {
|
||||
return candidateIndex, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Domain returns the domain version for BLS private key to sign and verify.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user