mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-10 05:47:59 -05:00
Compare commits
461 Commits
v1.4.3
...
v2.0.0-rc.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4db77ce691 | ||
|
|
1919484cae | ||
|
|
b28d65dc34 | ||
|
|
89637634f6 | ||
|
|
643e20c50a | ||
|
|
b870b126f1 | ||
|
|
bb68c591f2 | ||
|
|
873335c93f | ||
|
|
f8355bb241 | ||
|
|
8122da6c97 | ||
|
|
8e9976be54 | ||
|
|
1936f991eb | ||
|
|
49440c90ba | ||
|
|
47ee6fa17e | ||
|
|
de907fc362 | ||
|
|
a1c0bee397 | ||
|
|
b42465a7dd | ||
|
|
8fe22422a6 | ||
|
|
aa2f058a8e | ||
|
|
f516e71167 | ||
|
|
61702e101b | ||
|
|
bcaefd34e7 | ||
|
|
ede85c21e2 | ||
|
|
df2cebb4e3 | ||
|
|
8813ed35d4 | ||
|
|
a9f2170657 | ||
|
|
e80ce8be95 | ||
|
|
3a528147a2 | ||
|
|
c8cffbbf02 | ||
|
|
75a4ad364d | ||
|
|
acdf29ef44 | ||
|
|
1691cea615 | ||
|
|
1f102c256d | ||
|
|
e3492698f8 | ||
|
|
5256751e8b | ||
|
|
225f9a74f6 | ||
|
|
d77616f705 | ||
|
|
621aff1b86 | ||
|
|
aad0dd80d1 | ||
|
|
a217d71d08 | ||
|
|
efa1f29311 | ||
|
|
136b157d00 | ||
|
|
c1280867ed | ||
|
|
0dd7a8b078 | ||
|
|
6dc70c53ec | ||
|
|
17f3816976 | ||
|
|
f05ac82c6f | ||
|
|
41ab27402f | ||
|
|
e78e554d27 | ||
|
|
9668ab0fea | ||
|
|
6c435382dc | ||
|
|
1aa1165428 | ||
|
|
6c086080c5 | ||
|
|
c9dd3faf7a | ||
|
|
86259e76de | ||
|
|
7a9c717ae0 | ||
|
|
a5998fab2f | ||
|
|
8df6854a74 | ||
|
|
3de168b806 | ||
|
|
bfdaf8a3f5 | ||
|
|
38787353a2 | ||
|
|
170e2e115b | ||
|
|
be85b7f909 | ||
|
|
ad048a8750 | ||
|
|
90ea158301 | ||
|
|
d26f52a7cc | ||
|
|
ef9eff29b8 | ||
|
|
4cce4f1ee5 | ||
|
|
ce10be9a16 | ||
|
|
4f0b00894b | ||
|
|
57fac9b74f | ||
|
|
395feeb35d | ||
|
|
7bc22e4ddf | ||
|
|
f3a8397f75 | ||
|
|
016beb51c0 | ||
|
|
456b4d463e | ||
|
|
4d33068496 | ||
|
|
5212cc649a | ||
|
|
6e9faa3618 | ||
|
|
043850d972 | ||
|
|
fd42cb712f | ||
|
|
c5b68b4f03 | ||
|
|
e2238bd6d1 | ||
|
|
239d904d27 | ||
|
|
461be99fac | ||
|
|
9572add171 | ||
|
|
17cf2e5377 | ||
|
|
e4388c7fce | ||
|
|
47c28e6cd6 | ||
|
|
0c1fc65604 | ||
|
|
5c36d59672 | ||
|
|
7576442ef0 | ||
|
|
d130bf0035 | ||
|
|
df291e2ffb | ||
|
|
5ba5b303d3 | ||
|
|
f2ce4dcab3 | ||
|
|
8765c3ac42 | ||
|
|
57fff2d88e | ||
|
|
c010a972e7 | ||
|
|
0d818a5709 | ||
|
|
560fe69425 | ||
|
|
012d279663 | ||
|
|
fcd4938ec0 | ||
|
|
c02ed805b0 | ||
|
|
4db0dfc4f1 | ||
|
|
93adf4980a | ||
|
|
cf4ff3d6f9 | ||
|
|
3fe969992a | ||
|
|
2135108830 | ||
|
|
4c146dc896 | ||
|
|
042a3cda02 | ||
|
|
b8676480f0 | ||
|
|
711022d34e | ||
|
|
eec93be4ed | ||
|
|
21d096622f | ||
|
|
62846d61b8 | ||
|
|
a228a407be | ||
|
|
f527b676da | ||
|
|
5bd4e10dd6 | ||
|
|
d19e13352b | ||
|
|
6bda9a0bf2 | ||
|
|
2da6b7bb97 | ||
|
|
9145310647 | ||
|
|
21c79f4dfa | ||
|
|
98f7f82b2f | ||
|
|
f16b9859e7 | ||
|
|
7faed861c4 | ||
|
|
8b9129d84e | ||
|
|
a372e30c8f | ||
|
|
8b219b14da | ||
|
|
415973fca3 | ||
|
|
2d9915d2d9 | ||
|
|
c6bd7a2f83 | ||
|
|
7129af5ccf | ||
|
|
f700808c8b | ||
|
|
5bf9bd3d73 | ||
|
|
59f12c8ac1 | ||
|
|
1ea1c69174 | ||
|
|
1094ca0838 | ||
|
|
ebe4b309c0 | ||
|
|
54772596e0 | ||
|
|
a556cf27c4 | ||
|
|
ea94f0e70d | ||
|
|
47443e130d | ||
|
|
4dfa5c2757 | ||
|
|
1851d40f74 | ||
|
|
eee1d47655 | ||
|
|
7ce76652fb | ||
|
|
5b5c8f4d3f | ||
|
|
245dc23cde | ||
|
|
837cd4eb8f | ||
|
|
8c8f1bb9c1 | ||
|
|
a8c49c50ad | ||
|
|
14d0d9195f | ||
|
|
8db0c9a0e6 | ||
|
|
938a038c42 | ||
|
|
30e93f5763 | ||
|
|
be82c8714f | ||
|
|
19e6f0c19a | ||
|
|
c0076cc7a2 | ||
|
|
6470e2718a | ||
|
|
30cd5c076e | ||
|
|
03d8af5cda | ||
|
|
194f0cb76d | ||
|
|
2a0e8510d4 | ||
|
|
a8363405f8 | ||
|
|
2d10bcf179 | ||
|
|
5e35f778b9 | ||
|
|
526596a679 | ||
|
|
5864795ca5 | ||
|
|
b7919b3115 | ||
|
|
715aa408e3 | ||
|
|
ceb1ec451a | ||
|
|
b35c3ab2e7 | ||
|
|
c8685d256c | ||
|
|
0fb43aec34 | ||
|
|
9addb5f7c3 | ||
|
|
972ae7f169 | ||
|
|
80fafaddff | ||
|
|
33f7582d25 | ||
|
|
e6ecdfde0d | ||
|
|
1daf51788d | ||
|
|
6dadb80cc4 | ||
|
|
ae140073e7 | ||
|
|
b667d30d3f | ||
|
|
e7bdf35721 | ||
|
|
c780301096 | ||
|
|
35055539a7 | ||
|
|
e1d543a77b | ||
|
|
81ab3ca46c | ||
|
|
2ffe8336fc | ||
|
|
5895b10678 | ||
|
|
11d9e7da9b | ||
|
|
53e02b1601 | ||
|
|
7ea645ed37 | ||
|
|
a900792160 | ||
|
|
cd87bfd8ab | ||
|
|
98477a0286 | ||
|
|
2d1a63d9f4 | ||
|
|
52be270f0a | ||
|
|
895a86fd53 | ||
|
|
af6246a5f9 | ||
|
|
5e80ceeff9 | ||
|
|
3a35a953bf | ||
|
|
8d1c9fe1e2 | ||
|
|
4229b466ae | ||
|
|
412ddbb29e | ||
|
|
8a7010f5aa | ||
|
|
40a96bc2b6 | ||
|
|
1beb0071b5 | ||
|
|
2a0c4e0d5f | ||
|
|
dad205bd04 | ||
|
|
15bfcf8ff6 | ||
|
|
15704053e1 | ||
|
|
ee661971f0 | ||
|
|
cc7e36776d | ||
|
|
14a9d9a1ad | ||
|
|
5be1ccd3cf | ||
|
|
97e6eb14e2 | ||
|
|
6f126c92c0 | ||
|
|
2b9fb29ed2 | ||
|
|
223d5309a0 | ||
|
|
31d2482f9c | ||
|
|
3ef0c5d6e5 | ||
|
|
187a1ca53d | ||
|
|
17d7fc492e | ||
|
|
9300d1026f | ||
|
|
48345eb68e | ||
|
|
f029fdd44a | ||
|
|
60d14f1806 | ||
|
|
d80d4d01a6 | ||
|
|
44d266313e | ||
|
|
1a9a46d042 | ||
|
|
71c8c75bc3 | ||
|
|
275192680f | ||
|
|
9ca958064e | ||
|
|
604958da6c | ||
|
|
ade94444f2 | ||
|
|
b22935a724 | ||
|
|
4df2f4c790 | ||
|
|
3f8f5edb3f | ||
|
|
0ad4e433a5 | ||
|
|
1be2503e82 | ||
|
|
3ff5b95945 | ||
|
|
e6bd5f31b1 | ||
|
|
9a4ab41761 | ||
|
|
7f0749c398 | ||
|
|
d73ac71ee6 | ||
|
|
0dd228bb94 | ||
|
|
78450ea557 | ||
|
|
6ba741f251 | ||
|
|
f0e6d4a0bd | ||
|
|
4ebb008bc9 | ||
|
|
97901c90a5 | ||
|
|
1379dbfc23 | ||
|
|
19dbc7e249 | ||
|
|
76a70065f2 | ||
|
|
51f513b246 | ||
|
|
2b349a1b06 | ||
|
|
a819caca16 | ||
|
|
e7116d4ea8 | ||
|
|
f8cd989161 | ||
|
|
4c19265ac5 | ||
|
|
f361bf781f | ||
|
|
a458e556e0 | ||
|
|
773b259cd5 | ||
|
|
2bb3da1ba3 | ||
|
|
47367d98b4 | ||
|
|
1ff18c07a4 | ||
|
|
279a95deba | ||
|
|
c0bfa6ef79 | ||
|
|
7e961c2be9 | ||
|
|
c7c7f9bf1b | ||
|
|
7ce85cac31 | ||
|
|
2d836f485d | ||
|
|
780253b786 | ||
|
|
710bb98575 | ||
|
|
d5387851d0 | ||
|
|
ab8dd3788f | ||
|
|
bf1b550b7d | ||
|
|
705564108c | ||
|
|
3df82e7540 | ||
|
|
d0a749ce4b | ||
|
|
081c80998c | ||
|
|
8c62f10b74 | ||
|
|
e232b3ce30 | ||
|
|
17153bb4e9 | ||
|
|
329a45c06a | ||
|
|
1c82394a69 | ||
|
|
856081c80c | ||
|
|
6fff327864 | ||
|
|
e2879f8352 | ||
|
|
523fe58f61 | ||
|
|
04a303c8d2 | ||
|
|
0844bd62ea | ||
|
|
816dc47b17 | ||
|
|
caeec851d4 | ||
|
|
062933af35 | ||
|
|
169573c32e | ||
|
|
e7a7b2861e | ||
|
|
fe6c80fe95 | ||
|
|
2f52dfe96e | ||
|
|
93a7b96f16 | ||
|
|
f078b62c3e | ||
|
|
f476c39708 | ||
|
|
c02e507422 | ||
|
|
ece07e5fbb | ||
|
|
6bbe3dbd10 | ||
|
|
18bfc2a34e | ||
|
|
b774af9535 | ||
|
|
719a5fca02 | ||
|
|
b4a0e4375a | ||
|
|
4d276d2fdf | ||
|
|
8797179cfb | ||
|
|
7cc38108aa | ||
|
|
365ced285e | ||
|
|
97e5730fd9 | ||
|
|
3919b49000 | ||
|
|
7f13396e44 | ||
|
|
ae3e5718e6 | ||
|
|
97a49240ba | ||
|
|
232d519445 | ||
|
|
afd815bb5d | ||
|
|
56d383a354 | ||
|
|
733023df03 | ||
|
|
9d9ce13753 | ||
|
|
975e7a76bf | ||
|
|
20ae23bd42 | ||
|
|
63cf429fa0 | ||
|
|
2aab4e2efe | ||
|
|
e2156f25e0 | ||
|
|
a537833f75 | ||
|
|
61bf95e4e2 | ||
|
|
357d3f3b6a | ||
|
|
b0bbfcab7f | ||
|
|
06801a5230 | ||
|
|
278857d576 | ||
|
|
9c5c70fb32 | ||
|
|
54326af141 | ||
|
|
6020682ad1 | ||
|
|
3f45d54986 | ||
|
|
ecb51dc55d | ||
|
|
cbf4aeb859 | ||
|
|
b107bd2a5a | ||
|
|
a5e2c3f551 | ||
|
|
efffaeb359 | ||
|
|
144576cf36 | ||
|
|
fcf2be08d8 | ||
|
|
2b5cd139f0 | ||
|
|
77a4fdb509 | ||
|
|
a14d37b0ad | ||
|
|
38e28af51e | ||
|
|
6dbe6cfd8c | ||
|
|
c156c1fb91 | ||
|
|
393a744091 | ||
|
|
f83993b211 | ||
|
|
41433f8b2e | ||
|
|
95f62de465 | ||
|
|
fbb140eff7 | ||
|
|
22483a285a | ||
|
|
1d835d9859 | ||
|
|
98f8ab331a | ||
|
|
0e88418b12 | ||
|
|
ef3ff6f1d5 | ||
|
|
7c22496c65 | ||
|
|
c5256d09e0 | ||
|
|
d3d1eb833e | ||
|
|
2d9fd4ea29 | ||
|
|
be168e4034 | ||
|
|
f7c2b9c197 | ||
|
|
89b7cf9be3 | ||
|
|
3591f85a66 | ||
|
|
6ba5ad0325 | ||
|
|
76b16a8989 | ||
|
|
74a19741b4 | ||
|
|
fdb68c482e | ||
|
|
b51729bd2f | ||
|
|
aef1269223 | ||
|
|
9fc1683ec7 | ||
|
|
3790c5edb2 | ||
|
|
c6c7f8234d | ||
|
|
c66ea88da8 | ||
|
|
9a8facd76b | ||
|
|
ca7e0e4807 | ||
|
|
6acedb7dfd | ||
|
|
a3183bc33e | ||
|
|
f6caf627e1 | ||
|
|
fa696a883d | ||
|
|
cbbf188637 | ||
|
|
4d3e65bdcd | ||
|
|
0be2bde4cc | ||
|
|
d5662556bc | ||
|
|
26a10ca56e | ||
|
|
bda70352ca | ||
|
|
fbd45dbf50 | ||
|
|
119ef0f8fa | ||
|
|
04f38324ba | ||
|
|
fa27b6e24c | ||
|
|
fe647e99fc | ||
|
|
bbcaa7eaf2 | ||
|
|
1c1b2eb811 | ||
|
|
427e792073 | ||
|
|
463481febe | ||
|
|
6e41923388 | ||
|
|
17798f878a | ||
|
|
d502f0825a | ||
|
|
96fe2b76bf | ||
|
|
a51a4ca9eb | ||
|
|
9dd8a1737c | ||
|
|
c97f74ccef | ||
|
|
806a923974 | ||
|
|
4b4c2b97b7 | ||
|
|
9d22ea840e | ||
|
|
8a507d749a | ||
|
|
2850581611 | ||
|
|
59bc0c679c | ||
|
|
969dec8ad2 | ||
|
|
91fb8eea8c | ||
|
|
e7ebdb11be | ||
|
|
ff3bb0aa8a | ||
|
|
5945849cb4 | ||
|
|
3435a61413 | ||
|
|
a3b69600ef | ||
|
|
01841434ec | ||
|
|
f60edb055c | ||
|
|
ee3d106a36 | ||
|
|
9b41a069eb | ||
|
|
dc1d5b778b | ||
|
|
224b92781f | ||
|
|
6f54a9d057 | ||
|
|
7906e571a8 | ||
|
|
458817d5ad | ||
|
|
06290c6805 | ||
|
|
1adf1f1bef | ||
|
|
af57cf5e96 | ||
|
|
d59ba818f0 | ||
|
|
9aa2dd1ae6 | ||
|
|
f3abe70838 | ||
|
|
fe4a852e78 | ||
|
|
6af0f619c9 | ||
|
|
3d405910e7 | ||
|
|
2779daee32 | ||
|
|
a0ba4a8563 | ||
|
|
926b3725a1 | ||
|
|
5cc9f4df0b | ||
|
|
fd297999b8 | ||
|
|
0d45eeac56 | ||
|
|
e2fcd25039 | ||
|
|
2436d84370 | ||
|
|
5418d8c367 | ||
|
|
55e5dee7ab | ||
|
|
6a06a4bf98 | ||
|
|
a9d981dce1 | ||
|
|
a69947ba51 | ||
|
|
6a32b18ca9 | ||
|
|
9ebf8651b4 | ||
|
|
8467485aec | ||
|
|
fdb6cf9b57 | ||
|
|
3da55ad7a4 | ||
|
|
773d561361 | ||
|
|
7f6d3ccb36 |
0
.bazelignore
Normal file
0
.bazelignore
Normal file
5
.bazelrc
5
.bazelrc
@@ -24,11 +24,6 @@ build --sandbox_default_allow_network=false
|
||||
build --workspace_status_command=./scripts/workspace_status.sh
|
||||
build --stamp
|
||||
|
||||
# Use mainnet protobufs at runtime
|
||||
run --define ssz=mainnet
|
||||
test --define ssz=mainnet
|
||||
build --define ssz=mainnet
|
||||
|
||||
# Prevent PATH changes from rebuilding when switching from IDE to command line.
|
||||
build --incompatible_strict_action_env
|
||||
test --incompatible_strict_action_env
|
||||
|
||||
4
.github/workflows/go.yml
vendored
4
.github/workflows/go.yml
vendored
@@ -31,6 +31,10 @@ jobs:
|
||||
with:
|
||||
goimports-path: ./
|
||||
|
||||
- name: Gosec security scanner
|
||||
uses: securego/gosec@master
|
||||
with:
|
||||
args: '-exclude-dir=shared/bls/herumi ./...'
|
||||
build:
|
||||
name: Build
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
30
WORKSPACE
30
WORKSPACE
@@ -197,6 +197,8 @@ filegroup(
|
||||
url = "https://github.com/eth2-clients/slashing-protection-interchange-tests/archive/b8413ca42dc92308019d0d4db52c87e9e125c4e9.tar.gz",
|
||||
)
|
||||
|
||||
eth2_spec_version = "v1.1.0-beta.1"
|
||||
|
||||
http_archive(
|
||||
name = "eth2_spec_tests_general",
|
||||
build_file_content = """
|
||||
@@ -209,8 +211,8 @@ filegroup(
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
""",
|
||||
sha256 = "deacc076365c727d653ac064894ecf0d1b0a675d86704dc8de271259f6a7314b",
|
||||
url = "https://github.com/ethereum/eth2.0-spec-tests/releases/download/v1.1.0-alpha.3/general.tar.gz",
|
||||
sha256 = "e9b4cc60a3e676c6b4a9348424e44cff1ebada603ffb31b0df600dbd70e7fbf6",
|
||||
url = "https://github.com/ethereum/eth2.0-spec-tests/releases/download/%s/general.tar.gz" % eth2_spec_version,
|
||||
)
|
||||
|
||||
http_archive(
|
||||
@@ -225,8 +227,8 @@ filegroup(
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
""",
|
||||
sha256 = "6e9886af3d2f024e563249d70388129e28e3e92f742f289238ed9b7ec7a7f930",
|
||||
url = "https://github.com/ethereum/eth2.0-spec-tests/releases/download/v1.1.0-alpha.3/minimal.tar.gz",
|
||||
sha256 = "cf82dc729ffe7b924f852e57d1973e1a6377c5b52acc903c953277fa9b4e6de8",
|
||||
url = "https://github.com/ethereum/eth2.0-spec-tests/releases/download/%s/minimal.tar.gz" % eth2_spec_version,
|
||||
)
|
||||
|
||||
http_archive(
|
||||
@@ -241,8 +243,24 @@ filegroup(
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
""",
|
||||
sha256 = "a7b3d0ffc02a567250f424d69b2474fdc9477cd56eada60af7474560b46a8527",
|
||||
url = "https://github.com/ethereum/eth2.0-spec-tests/releases/download/v1.1.0-alpha.3/mainnet.tar.gz",
|
||||
sha256 = "6c6792375b81858037014e282d28a64b0cf12e12daf16054265c85403b8b329f",
|
||||
url = "https://github.com/ethereum/eth2.0-spec-tests/releases/download/%s/mainnet.tar.gz" % eth2_spec_version,
|
||||
)
|
||||
|
||||
http_archive(
|
||||
name = "eth2_spec",
|
||||
build_file_content = """
|
||||
filegroup(
|
||||
name = "spec_data",
|
||||
srcs = glob([
|
||||
"**/*.yaml",
|
||||
]),
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
""",
|
||||
sha256 = "16094dad1bab4e8ab3adb60c10e311cd1e294cd7bbf5a89505f24bebd3d0e513",
|
||||
strip_prefix = "eth2.0-specs-" + eth2_spec_version[1:],
|
||||
url = "https://github.com/ethereum/eth2.0-specs/archive/refs/tags/%s.tar.gz" % eth2_spec_version,
|
||||
)
|
||||
|
||||
http_archive(
|
||||
|
||||
@@ -5,6 +5,7 @@ go_library(
|
||||
srcs = [
|
||||
"chain_info.go",
|
||||
"head.go",
|
||||
"head_sync_committee_info.go",
|
||||
"info.go",
|
||||
"init_sync_process_block.go",
|
||||
"log.go",
|
||||
@@ -26,6 +27,7 @@ go_library(
|
||||
deps = [
|
||||
"//beacon-chain/cache:go_default_library",
|
||||
"//beacon-chain/cache/depositcache:go_default_library",
|
||||
"//beacon-chain/core/altair:go_default_library",
|
||||
"//beacon-chain/core/epoch/precompute:go_default_library",
|
||||
"//beacon-chain/core/feed:go_default_library",
|
||||
"//beacon-chain/core/feed/state:go_default_library",
|
||||
@@ -40,13 +42,13 @@ go_library(
|
||||
"//beacon-chain/operations/voluntaryexits:go_default_library",
|
||||
"//beacon-chain/p2p:go_default_library",
|
||||
"//beacon-chain/powchain:go_default_library",
|
||||
"//beacon-chain/state/interface:go_default_library",
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//beacon-chain/state/stategen:go_default_library",
|
||||
"//beacon-chain/state/v2:go_default_library",
|
||||
"//cmd/beacon-chain/flags:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//proto/eth/v1:go_default_library",
|
||||
"//proto/eth/v1alpha1:go_default_library",
|
||||
"//proto/interfaces:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//proto/prysm/v1alpha1/block:go_default_library",
|
||||
"//shared/attestationutil:go_default_library",
|
||||
"//shared/bls:go_default_library",
|
||||
"//shared/bytesutil:go_default_library",
|
||||
@@ -57,7 +59,9 @@ go_library(
|
||||
"//shared/slotutil:go_default_library",
|
||||
"//shared/timeutils:go_default_library",
|
||||
"//shared/traceutil:go_default_library",
|
||||
"//shared/version: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",
|
||||
@@ -107,10 +111,8 @@ go_test(
|
||||
"//beacon-chain/powchain:go_default_library",
|
||||
"//beacon-chain/state/stateutil:go_default_library",
|
||||
"//beacon-chain/state/v1:go_default_library",
|
||||
"//proto/beacon/db:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//proto/eth/v1alpha1:go_default_library",
|
||||
"//proto/eth/v1alpha1/wrapper:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//proto/prysm/v1alpha1/wrapper:go_default_library",
|
||||
"//shared/bytesutil:go_default_library",
|
||||
"//shared/event:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
@@ -158,9 +160,8 @@ go_test(
|
||||
"//beacon-chain/db/testing:go_default_library",
|
||||
"//beacon-chain/p2p:go_default_library",
|
||||
"//beacon-chain/powchain:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//proto/eth/v1alpha1:go_default_library",
|
||||
"//proto/eth/v1alpha1/wrapper:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//proto/prysm/v1alpha1/wrapper:go_default_library",
|
||||
"//shared/bytesutil:go_default_library",
|
||||
"//shared/event:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
|
||||
@@ -7,10 +7,9 @@ import (
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/protoarray"
|
||||
iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/interfaces"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/block"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/copyutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
@@ -25,6 +24,8 @@ type ChainInfoFetcher interface {
|
||||
GenesisFetcher
|
||||
CanonicalFetcher
|
||||
ForkFetcher
|
||||
TimeFetcher
|
||||
HeadDomainFetcher
|
||||
}
|
||||
|
||||
// TimeFetcher retrieves the Ethereum consensus data that's related to time.
|
||||
@@ -43,19 +44,23 @@ type GenesisFetcher interface {
|
||||
type HeadFetcher interface {
|
||||
HeadSlot() types.Slot
|
||||
HeadRoot(ctx context.Context) ([]byte, error)
|
||||
HeadBlock(ctx context.Context) (interfaces.SignedBeaconBlock, error)
|
||||
HeadState(ctx context.Context) (iface.BeaconState, error)
|
||||
HeadBlock(ctx context.Context) (block.SignedBeaconBlock, error)
|
||||
HeadState(ctx context.Context) (state.BeaconState, error)
|
||||
HeadValidatorsIndices(ctx context.Context, epoch types.Epoch) ([]types.ValidatorIndex, error)
|
||||
HeadSeed(ctx context.Context, epoch types.Epoch) ([32]byte, error)
|
||||
HeadGenesisValidatorRoot() [32]byte
|
||||
HeadETH1Data() *ethpb.Eth1Data
|
||||
HeadPublicKeyToValidatorIndex(ctx context.Context, pubKey [48]byte) (types.ValidatorIndex, bool)
|
||||
HeadValidatorIndexToPublicKey(ctx context.Context, index types.ValidatorIndex) ([48]byte, error)
|
||||
ProtoArrayStore() *protoarray.Store
|
||||
ChainHeads() ([][32]byte, []types.Slot)
|
||||
HeadSyncCommitteeFetcher
|
||||
HeadDomainFetcher
|
||||
}
|
||||
|
||||
// ForkFetcher retrieves the current fork information of the Ethereum beacon chain.
|
||||
type ForkFetcher interface {
|
||||
CurrentFork() *pb.Fork
|
||||
CurrentFork() *ethpb.Fork
|
||||
}
|
||||
|
||||
// CanonicalFetcher retrieves the current chain's canonical information.
|
||||
@@ -140,7 +145,7 @@ func (s *Service) HeadRoot(ctx context.Context) ([]byte, error) {
|
||||
// HeadBlock returns the head block of the chain.
|
||||
// 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) (interfaces.SignedBeaconBlock, error) {
|
||||
func (s *Service) HeadBlock(ctx context.Context) (block.SignedBeaconBlock, error) {
|
||||
s.headLock.RLock()
|
||||
defer s.headLock.RUnlock()
|
||||
|
||||
@@ -154,7 +159,7 @@ func (s *Service) HeadBlock(ctx context.Context) (interfaces.SignedBeaconBlock,
|
||||
// HeadState returns the head state of the chain.
|
||||
// If the head is nil from service struct,
|
||||
// it will attempt to get the head state from DB.
|
||||
func (s *Service) HeadState(ctx context.Context) (iface.BeaconState, error) {
|
||||
func (s *Service) HeadState(ctx context.Context) (state.BeaconState, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "blockChain.HeadState")
|
||||
defer span.End()
|
||||
s.headLock.RLock()
|
||||
@@ -239,12 +244,12 @@ func (s *Service) GenesisValidatorRoot() [32]byte {
|
||||
}
|
||||
|
||||
// CurrentFork retrieves the latest fork information of the beacon chain.
|
||||
func (s *Service) CurrentFork() *pb.Fork {
|
||||
func (s *Service) CurrentFork() *ethpb.Fork {
|
||||
s.headLock.RLock()
|
||||
defer s.headLock.RUnlock()
|
||||
|
||||
if !s.hasHeadState() {
|
||||
return &pb.Fork{
|
||||
return ðpb.Fork{
|
||||
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
}
|
||||
@@ -284,3 +289,23 @@ func (s *Service) ChainHeads() ([][32]byte, []types.Slot) {
|
||||
|
||||
return headsRoots, headsSlots
|
||||
}
|
||||
|
||||
// HeadPublicKeyToValidatorIndex returns the validator index of the `pubkey` in current head state.
|
||||
func (s *Service) HeadPublicKeyToValidatorIndex(ctx context.Context, pubKey [48]byte) (types.ValidatorIndex, bool) {
|
||||
s.headLock.RLock()
|
||||
defer s.headLock.RUnlock()
|
||||
|
||||
return s.headState(ctx).ValidatorIndexByPubkey(pubKey)
|
||||
}
|
||||
|
||||
// HeadValidatorIndexToPublicKey returns the pubkey of the validator `index` in current head state.
|
||||
func (s *Service) HeadValidatorIndexToPublicKey(ctx context.Context, index types.ValidatorIndex) ([48]byte, error) {
|
||||
s.headLock.RLock()
|
||||
defer s.headLock.RUnlock()
|
||||
|
||||
v, err := s.headState(ctx).ValidatorAtIndexReadOnly(index)
|
||||
if err != nil {
|
||||
return [48]byte{}, err
|
||||
}
|
||||
return v.PublicKey(), nil
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@ import (
|
||||
|
||||
testDB "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stategen"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/eth/v1alpha1/wrapper"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/wrapper"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
|
||||
@@ -9,10 +9,9 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
testDB "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/protoarray"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/eth/v1alpha1/wrapper"
|
||||
v1 "github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/wrapper"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
@@ -105,7 +104,7 @@ func TestPrevJustifiedCheckpt_GenesisRootOk(t *testing.T) {
|
||||
|
||||
func TestHeadSlot_CanRetrieve(t *testing.T) {
|
||||
c := &Service{}
|
||||
s, err := v1.InitializeFromProto(&pb.BeaconState{})
|
||||
s, err := v1.InitializeFromProto(ðpb.BeaconState{})
|
||||
require.NoError(t, err)
|
||||
c.head = &head{slot: 100, state: s}
|
||||
assert.Equal(t, types.Slot(100), c.HeadSlot())
|
||||
@@ -127,7 +126,7 @@ func TestHeadRoot_UseDB(t *testing.T) {
|
||||
br, err := b.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, beaconDB.SaveBlock(context.Background(), wrapper.WrappedPhase0SignedBeaconBlock(b)))
|
||||
require.NoError(t, beaconDB.SaveStateSummary(context.Background(), &pb.StateSummary{Root: br[:]}))
|
||||
require.NoError(t, beaconDB.SaveStateSummary(context.Background(), ðpb.StateSummary{Root: br[:]}))
|
||||
require.NoError(t, beaconDB.SaveHeadBlockRoot(context.Background(), br))
|
||||
r, err := c.HeadRoot(context.Background())
|
||||
require.NoError(t, err)
|
||||
@@ -137,7 +136,7 @@ func TestHeadRoot_UseDB(t *testing.T) {
|
||||
func TestHeadBlock_CanRetrieve(t *testing.T) {
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block.Slot = 1
|
||||
s, err := v1.InitializeFromProto(&pb.BeaconState{})
|
||||
s, err := v1.InitializeFromProto(ðpb.BeaconState{})
|
||||
require.NoError(t, err)
|
||||
c := &Service{}
|
||||
c.head = &head{block: wrapper.WrappedPhase0SignedBeaconBlock(b), state: s}
|
||||
@@ -148,7 +147,7 @@ func TestHeadBlock_CanRetrieve(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestHeadState_CanRetrieve(t *testing.T) {
|
||||
s, err := v1.InitializeFromProto(&pb.BeaconState{Slot: 2, GenesisValidatorsRoot: params.BeaconConfig().ZeroHash[:]})
|
||||
s, err := v1.InitializeFromProto(ðpb.BeaconState{Slot: 2, GenesisValidatorsRoot: params.BeaconConfig().ZeroHash[:]})
|
||||
require.NoError(t, err)
|
||||
c := &Service{}
|
||||
c.head = &head{state: s}
|
||||
@@ -164,8 +163,8 @@ func TestGenesisTime_CanRetrieve(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCurrentFork_CanRetrieve(t *testing.T) {
|
||||
f := &pb.Fork{Epoch: 999}
|
||||
s, err := v1.InitializeFromProto(&pb.BeaconState{Fork: f})
|
||||
f := ðpb.Fork{Epoch: 999}
|
||||
s, err := v1.InitializeFromProto(ðpb.BeaconState{Fork: f})
|
||||
require.NoError(t, err)
|
||||
c := &Service{}
|
||||
c.head = &head{state: s}
|
||||
@@ -175,7 +174,7 @@ func TestCurrentFork_CanRetrieve(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCurrentFork_NilHeadSTate(t *testing.T) {
|
||||
f := &pb.Fork{
|
||||
f := ðpb.Fork{
|
||||
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
}
|
||||
@@ -190,7 +189,7 @@ func TestGenesisValidatorRoot_CanRetrieve(t *testing.T) {
|
||||
c := &Service{}
|
||||
assert.Equal(t, [32]byte{}, c.GenesisValidatorRoot(), "Did not get correct genesis validator root")
|
||||
|
||||
s, err := v1.InitializeFromProto(&pb.BeaconState{GenesisValidatorsRoot: []byte{'a'}})
|
||||
s, err := v1.InitializeFromProto(ðpb.BeaconState{GenesisValidatorsRoot: []byte{'a'}})
|
||||
require.NoError(t, err)
|
||||
c.head = &head{state: s}
|
||||
assert.Equal(t, [32]byte{'a'}, c.GenesisValidatorRoot(), "Did not get correct genesis validator root")
|
||||
@@ -204,7 +203,7 @@ func TestHeadETH1Data_Nil(t *testing.T) {
|
||||
|
||||
func TestHeadETH1Data_CanRetrieve(t *testing.T) {
|
||||
d := ðpb.Eth1Data{DepositCount: 999}
|
||||
s, err := v1.InitializeFromProto(&pb.BeaconState{Eth1Data: d})
|
||||
s, err := v1.InitializeFromProto(ðpb.BeaconState{Eth1Data: d})
|
||||
require.NoError(t, err)
|
||||
c := &Service{}
|
||||
c.head = &head{state: s}
|
||||
@@ -297,3 +296,33 @@ func TestService_ChainHeads(t *testing.T) {
|
||||
require.DeepEqual(t, [][32]byte{{'c'}, {'d'}, {'e'}}, roots)
|
||||
require.DeepEqual(t, []types.Slot{102, 103, 104}, slots)
|
||||
}
|
||||
|
||||
func TestService_HeadPublicKeyToValidatorIndex(t *testing.T) {
|
||||
s, _ := testutil.DeterministicGenesisState(t, 10)
|
||||
c := &Service{}
|
||||
c.head = &head{state: s}
|
||||
|
||||
_, e := c.HeadPublicKeyToValidatorIndex(context.Background(), [48]byte{})
|
||||
require.Equal(t, false, e)
|
||||
|
||||
v, err := s.ValidatorAtIndex(0)
|
||||
require.NoError(t, err)
|
||||
|
||||
i, e := c.HeadPublicKeyToValidatorIndex(context.Background(), bytesutil.ToBytes48(v.PublicKey))
|
||||
require.Equal(t, true, e)
|
||||
require.Equal(t, types.ValidatorIndex(0), i)
|
||||
}
|
||||
|
||||
func TestService_HeadValidatorIndexToPublicKey(t *testing.T) {
|
||||
s, _ := testutil.DeterministicGenesisState(t, 10)
|
||||
c := &Service{}
|
||||
c.head = &head{state: s}
|
||||
|
||||
p, err := c.HeadValidatorIndexToPublicKey(context.Background(), 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
v, err := s.ValidatorAtIndex(0)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, bytesutil.ToBytes48(v.PublicKey), p)
|
||||
}
|
||||
|
||||
@@ -11,9 +11,9 @@ import (
|
||||
statefeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/protoarray"
|
||||
iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
ethpbv1 "github.com/prysmaticlabs/prysm/proto/eth/v1"
|
||||
"github.com/prysmaticlabs/prysm/proto/interfaces"
|
||||
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/block"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/slotutil"
|
||||
@@ -23,10 +23,10 @@ import (
|
||||
|
||||
// This defines the current chain service's view of head.
|
||||
type head struct {
|
||||
slot types.Slot // current head slot.
|
||||
root [32]byte // current head root.
|
||||
block interfaces.SignedBeaconBlock // current head block.
|
||||
state iface.BeaconState // current head state.
|
||||
slot types.Slot // current head slot.
|
||||
root [32]byte // current head root.
|
||||
block block.SignedBeaconBlock // current head block.
|
||||
state state.BeaconState // current head state.
|
||||
}
|
||||
|
||||
// Determined the head from the fork choice service and saves its new data
|
||||
@@ -168,7 +168,7 @@ func (s *Service) saveHead(ctx context.Context, headRoot [32]byte) error {
|
||||
// This gets called to update canonical root mapping. It does not save head block
|
||||
// root in DB. With the inception of initial-sync-cache-state flag, it uses finalized
|
||||
// check point as anchors to resume sync therefore head is no longer needed to be saved on per slot basis.
|
||||
func (s *Service) saveHeadNoDB(ctx context.Context, b interfaces.SignedBeaconBlock, r [32]byte, hs iface.BeaconState) error {
|
||||
func (s *Service) saveHeadNoDB(ctx context.Context, b block.SignedBeaconBlock, r [32]byte, hs state.BeaconState) error {
|
||||
if err := helpers.VerifyNilBeaconBlock(b); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -185,7 +185,7 @@ func (s *Service) saveHeadNoDB(ctx context.Context, b interfaces.SignedBeaconBlo
|
||||
}
|
||||
|
||||
// This sets head view object which is used to track the head slot, root, block and state.
|
||||
func (s *Service) setHead(root [32]byte, block interfaces.SignedBeaconBlock, state iface.BeaconState) {
|
||||
func (s *Service) setHead(root [32]byte, block block.SignedBeaconBlock, state state.BeaconState) {
|
||||
s.headLock.Lock()
|
||||
defer s.headLock.Unlock()
|
||||
|
||||
@@ -201,7 +201,7 @@ func (s *Service) setHead(root [32]byte, block interfaces.SignedBeaconBlock, sta
|
||||
// This sets head view object which is used to track the head slot, root, block and state. The method
|
||||
// assumes that state being passed into the method will not be modified by any other alternate
|
||||
// caller which holds the state's reference.
|
||||
func (s *Service) setHeadInitialSync(root [32]byte, block interfaces.SignedBeaconBlock, state iface.BeaconState) {
|
||||
func (s *Service) setHeadInitialSync(root [32]byte, block block.SignedBeaconBlock, state state.BeaconState) {
|
||||
s.headLock.Lock()
|
||||
defer s.headLock.Unlock()
|
||||
|
||||
@@ -234,14 +234,14 @@ func (s *Service) headRoot() [32]byte {
|
||||
// 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() interfaces.SignedBeaconBlock {
|
||||
func (s *Service) headBlock() block.SignedBeaconBlock {
|
||||
return s.head.block.Copy()
|
||||
}
|
||||
|
||||
// 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) iface.BeaconState {
|
||||
func (s *Service) headState(ctx context.Context) state.BeaconState {
|
||||
ctx, span := trace.StartSpan(ctx, "blockChain.headState")
|
||||
defer span.End()
|
||||
|
||||
@@ -268,7 +268,7 @@ func (s *Service) cacheJustifiedStateBalances(ctx context.Context, justifiedRoot
|
||||
|
||||
s.clearInitSyncBlocks()
|
||||
|
||||
var justifiedState iface.BeaconState
|
||||
var justifiedState state.BeaconState
|
||||
var err error
|
||||
if justifiedRoot == s.genesisRoot {
|
||||
justifiedState, err = s.cfg.BeaconDB.GenesisState(ctx)
|
||||
@@ -288,7 +288,7 @@ func (s *Service) cacheJustifiedStateBalances(ctx context.Context, justifiedRoot
|
||||
epoch := helpers.CurrentEpoch(justifiedState)
|
||||
|
||||
justifiedBalances := make([]uint64, justifiedState.NumValidators())
|
||||
if err := justifiedState.ReadFromEveryValidator(func(idx int, val iface.ReadOnlyValidator) error {
|
||||
if err := justifiedState.ReadFromEveryValidator(func(idx int, val state.ReadOnlyValidator) error {
|
||||
if helpers.IsActiveValidatorUsingTrie(val, epoch) {
|
||||
justifiedBalances[idx] = val.EffectiveBalance()
|
||||
} else {
|
||||
@@ -315,7 +315,7 @@ func (s *Service) getJustifiedBalances() []uint64 {
|
||||
// chain head is determined, set, and saved to disk.
|
||||
func (s *Service) notifyNewHeadEvent(
|
||||
newHeadSlot types.Slot,
|
||||
newHeadState iface.BeaconState,
|
||||
newHeadState state.BeaconState,
|
||||
newHeadStateRoot,
|
||||
newHeadRoot []byte,
|
||||
) error {
|
||||
|
||||
188
beacon-chain/blockchain/head_sync_committee_info.go
Normal file
188
beacon-chain/blockchain/head_sync_committee_info.go
Normal file
@@ -0,0 +1,188 @@
|
||||
package blockchain
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
|
||||
lru "github.com/hashicorp/golang-lru"
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/altair"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
core "github.com/prysmaticlabs/prysm/beacon-chain/core/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
stateAltair "github.com/prysmaticlabs/prysm/beacon-chain/state/v2"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
// HeadSyncCommitteeFetcher is the interface that wraps the head sync committee related functions.
|
||||
// The head sync committee functions return callers sync committee indices and public keys with respect to current head state.
|
||||
type HeadSyncCommitteeFetcher interface {
|
||||
HeadCurrentSyncCommitteeIndices(ctx context.Context, index types.ValidatorIndex, slot types.Slot) ([]types.CommitteeIndex, error)
|
||||
HeadNextSyncCommitteeIndices(ctx context.Context, index types.ValidatorIndex, slot types.Slot) ([]types.CommitteeIndex, error)
|
||||
HeadSyncCommitteePubKeys(ctx context.Context, slot types.Slot, committeeIndex types.CommitteeIndex) ([][]byte, error)
|
||||
}
|
||||
|
||||
// HeadDomainFetcher is the interface that wraps the head sync domain related functions.
|
||||
// The head sync committee domain functions return callers domain data with respect to slot and head state.
|
||||
type HeadDomainFetcher interface {
|
||||
HeadSyncCommitteeDomain(ctx context.Context, slot types.Slot) ([]byte, error)
|
||||
HeadSyncSelectionProofDomain(ctx context.Context, slot types.Slot) ([]byte, error)
|
||||
HeadSyncContributionProofDomain(ctx context.Context, slot types.Slot) ([]byte, error)
|
||||
}
|
||||
|
||||
// HeadSyncCommitteeDomain returns the head sync committee domain using current head state advanced up to `slot`.
|
||||
func (s *Service) HeadSyncCommitteeDomain(ctx context.Context, slot types.Slot) ([]byte, error) {
|
||||
s.headLock.RLock()
|
||||
defer s.headLock.RUnlock()
|
||||
|
||||
return s.domainWithHeadState(ctx, slot, params.BeaconConfig().DomainSyncCommittee)
|
||||
}
|
||||
|
||||
// HeadSyncSelectionProofDomain returns the head sync committee domain using current head state advanced up to `slot`.
|
||||
func (s *Service) HeadSyncSelectionProofDomain(ctx context.Context, slot types.Slot) ([]byte, error) {
|
||||
s.headLock.RLock()
|
||||
defer s.headLock.RUnlock()
|
||||
|
||||
return s.domainWithHeadState(ctx, slot, params.BeaconConfig().DomainSyncCommitteeSelectionProof)
|
||||
}
|
||||
|
||||
// HeadSyncContributionProofDomain returns the head sync committee domain using current head state advanced up to `slot`.
|
||||
func (s *Service) HeadSyncContributionProofDomain(ctx context.Context, slot types.Slot) ([]byte, error) {
|
||||
s.headLock.RLock()
|
||||
defer s.headLock.RUnlock()
|
||||
|
||||
return s.domainWithHeadState(ctx, slot, params.BeaconConfig().DomainContributionAndProof)
|
||||
}
|
||||
|
||||
// HeadCurrentSyncCommitteeIndices returns the input validator `index`'s position indices in the current sync committee with respect to `slot`.
|
||||
// Head state advanced up to `slot` is used for calculation.
|
||||
func (s *Service) HeadCurrentSyncCommitteeIndices(ctx context.Context, index types.ValidatorIndex, slot types.Slot) ([]types.CommitteeIndex, error) {
|
||||
s.headLock.RLock()
|
||||
defer s.headLock.RUnlock()
|
||||
|
||||
headState, err := s.getSyncCommitteeHeadState(ctx, slot)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return helpers.CurrentPeriodSyncSubcommitteeIndices(headState, index)
|
||||
}
|
||||
|
||||
// HeadNextSyncCommitteeIndices returns the input validator `index`'s position indices in the next sync committee with respect to `slot`.
|
||||
// Head state advanced up to `slot` is used for calculation.
|
||||
func (s *Service) HeadNextSyncCommitteeIndices(ctx context.Context, index types.ValidatorIndex, slot types.Slot) ([]types.CommitteeIndex, error) {
|
||||
s.headLock.RLock()
|
||||
defer s.headLock.RUnlock()
|
||||
|
||||
headState, err := s.getSyncCommitteeHeadState(ctx, slot)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return helpers.NextPeriodSyncSubcommitteeIndices(headState, index)
|
||||
}
|
||||
|
||||
// HeadSyncCommitteePubKeys returns the head sync committee public keys with respect to `slot` and subcommittee index `committeeIndex`.
|
||||
// Head state advanced up to `slot` is used for calculation.
|
||||
func (s *Service) HeadSyncCommitteePubKeys(ctx context.Context, slot types.Slot, committeeIndex types.CommitteeIndex) ([][]byte, error) {
|
||||
s.headLock.RLock()
|
||||
defer s.headLock.RUnlock()
|
||||
|
||||
headState, err := s.getSyncCommitteeHeadState(ctx, slot)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
nextSlotEpoch := helpers.SlotToEpoch(headState.Slot() + 1)
|
||||
currEpoch := helpers.SlotToEpoch(headState.Slot())
|
||||
|
||||
var syncCommittee *ethpb.SyncCommittee
|
||||
if helpers.SyncCommitteePeriod(currEpoch) == helpers.SyncCommitteePeriod(nextSlotEpoch) {
|
||||
syncCommittee, err = headState.CurrentSyncCommittee()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
syncCommittee, err = headState.NextSyncCommittee()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return altair.SyncSubCommitteePubkeys(syncCommittee, committeeIndex)
|
||||
}
|
||||
|
||||
// returns calculated domain using input `domain` and `slot`.
|
||||
func (s *Service) domainWithHeadState(ctx context.Context, slot types.Slot, domain [4]byte) ([]byte, error) {
|
||||
headState, err := s.getSyncCommitteeHeadState(ctx, slot)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return helpers.Domain(headState.Fork(), helpers.SlotToEpoch(headState.Slot()), domain, headState.GenesisValidatorRoot())
|
||||
}
|
||||
|
||||
// returns the head state that is advanced up to `slot`. It utilizes the cache `syncCommitteeHeadState` by retrieving using `slot` as key.
|
||||
// For the cache miss, it processes head state up to slot and fill the cache with `slot` as key.
|
||||
func (s *Service) getSyncCommitteeHeadState(ctx context.Context, slot types.Slot) (state.BeaconState, error) {
|
||||
var headState state.BeaconState
|
||||
var err error
|
||||
|
||||
// If there's already a head state exists with the request slot, we don't need to process slots.
|
||||
cachedState := syncCommitteeHeadStateCache.get(slot)
|
||||
if cachedState != nil && !cachedState.IsNil() {
|
||||
syncHeadStateHit.Inc()
|
||||
headState = cachedState
|
||||
} else {
|
||||
headState, err = s.HeadState(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if slot > headState.Slot() {
|
||||
headState, err = core.ProcessSlots(ctx, headState, slot)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
syncHeadStateMiss.Inc()
|
||||
syncCommitteeHeadStateCache.add(slot, headState)
|
||||
}
|
||||
|
||||
return headState, nil
|
||||
}
|
||||
|
||||
var syncCommitteeHeadStateCache = newSyncCommitteeHeadState()
|
||||
|
||||
// syncCommitteeHeadState to caches latest head state requested by the sync committee participant.
|
||||
type syncCommitteeHeadState struct {
|
||||
cache *lru.Cache
|
||||
lock sync.RWMutex
|
||||
}
|
||||
|
||||
// newSyncCommitteeHeadState initializes the lru cache for `syncCommitteeHeadState` with size of 1.
|
||||
func newSyncCommitteeHeadState() *syncCommitteeHeadState {
|
||||
c, err := lru.New(1) // only need size of 1 to avoid redundant state copy, HTR, and process slots.
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return &syncCommitteeHeadState{cache: c}
|
||||
}
|
||||
|
||||
// add `slot` as key and `state` as value onto the lru cache.
|
||||
func (c *syncCommitteeHeadState) add(slot types.Slot, state state.BeaconState) {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
c.cache.Add(slot, state)
|
||||
}
|
||||
|
||||
// get `state` using `slot` as key. Return nil if nothing is found.
|
||||
func (c *syncCommitteeHeadState) get(slot types.Slot) state.BeaconState {
|
||||
c.lock.RLock()
|
||||
defer c.lock.RUnlock()
|
||||
val, exists := c.cache.Get(slot)
|
||||
if !exists {
|
||||
return nil
|
||||
}
|
||||
if val == nil {
|
||||
return nil
|
||||
}
|
||||
return val.(*stateAltair.BeaconState)
|
||||
}
|
||||
108
beacon-chain/blockchain/head_sync_committee_info_test.go
Normal file
108
beacon-chain/blockchain/head_sync_committee_info_test.go
Normal file
@@ -0,0 +1,108 @@
|
||||
package blockchain
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
func TestService_HeadCurrentSyncCommitteeIndices(t *testing.T) {
|
||||
s, _ := testutil.DeterministicGenesisStateAltair(t, params.BeaconConfig().TargetCommitteeSize)
|
||||
c := &Service{}
|
||||
c.head = &head{state: s}
|
||||
|
||||
// Process slot up to `EpochsPerSyncCommitteePeriod` so it can `ProcessSyncCommitteeUpdates`.
|
||||
slot := uint64(params.BeaconConfig().EpochsPerSyncCommitteePeriod)*uint64(params.BeaconConfig().SlotsPerEpoch) + 1
|
||||
indices, err := c.HeadCurrentSyncCommitteeIndices(context.Background(), 0, types.Slot(slot))
|
||||
require.NoError(t, err)
|
||||
|
||||
// NextSyncCommittee becomes CurrentSyncCommittee so it should be empty by default.
|
||||
require.Equal(t, 0, len(indices))
|
||||
}
|
||||
|
||||
func TestService_HeadNextSyncCommitteeIndices(t *testing.T) {
|
||||
s, _ := testutil.DeterministicGenesisStateAltair(t, params.BeaconConfig().TargetCommitteeSize)
|
||||
c := &Service{}
|
||||
c.head = &head{state: s}
|
||||
|
||||
// Process slot up to `EpochsPerSyncCommitteePeriod` so it can `ProcessSyncCommitteeUpdates`.
|
||||
slot := uint64(params.BeaconConfig().EpochsPerSyncCommitteePeriod)*uint64(params.BeaconConfig().SlotsPerEpoch) + 1
|
||||
indices, err := c.HeadNextSyncCommitteeIndices(context.Background(), 0, types.Slot(slot))
|
||||
require.NoError(t, err)
|
||||
|
||||
// NextSyncCommittee should be be empty after `ProcessSyncCommitteeUpdates`. Validator should get indices.
|
||||
require.NotEqual(t, 0, len(indices))
|
||||
}
|
||||
|
||||
func TestService_HeadSyncCommitteePubKeys(t *testing.T) {
|
||||
s, _ := testutil.DeterministicGenesisStateAltair(t, params.BeaconConfig().TargetCommitteeSize)
|
||||
c := &Service{}
|
||||
c.head = &head{state: s}
|
||||
|
||||
// Process slot up to 2 * `EpochsPerSyncCommitteePeriod` so it can run `ProcessSyncCommitteeUpdates` twice.
|
||||
slot := uint64(2*params.BeaconConfig().EpochsPerSyncCommitteePeriod)*uint64(params.BeaconConfig().SlotsPerEpoch) + 1
|
||||
pubkeys, err := c.HeadSyncCommitteePubKeys(context.Background(), types.Slot(slot), 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Any subcommittee should match the subcommittee size.
|
||||
subCommitteeSize := params.BeaconConfig().SyncCommitteeSize / params.BeaconConfig().SyncCommitteeSubnetCount
|
||||
require.Equal(t, int(subCommitteeSize), len(pubkeys))
|
||||
}
|
||||
|
||||
func TestService_HeadSyncCommitteeDomain(t *testing.T) {
|
||||
s, _ := testutil.DeterministicGenesisStateAltair(t, params.BeaconConfig().TargetCommitteeSize)
|
||||
c := &Service{}
|
||||
c.head = &head{state: s}
|
||||
|
||||
wanted, err := helpers.Domain(s.Fork(), helpers.SlotToEpoch(s.Slot()), params.BeaconConfig().DomainSyncCommittee, s.GenesisValidatorRoot())
|
||||
require.NoError(t, err)
|
||||
|
||||
d, err := c.HeadSyncCommitteeDomain(context.Background(), 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.DeepEqual(t, wanted, d)
|
||||
}
|
||||
|
||||
func TestService_HeadSyncContributionProofDomain(t *testing.T) {
|
||||
s, _ := testutil.DeterministicGenesisStateAltair(t, params.BeaconConfig().TargetCommitteeSize)
|
||||
c := &Service{}
|
||||
c.head = &head{state: s}
|
||||
|
||||
wanted, err := helpers.Domain(s.Fork(), helpers.SlotToEpoch(s.Slot()), params.BeaconConfig().DomainContributionAndProof, s.GenesisValidatorRoot())
|
||||
require.NoError(t, err)
|
||||
|
||||
d, err := c.HeadSyncContributionProofDomain(context.Background(), 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.DeepEqual(t, wanted, d)
|
||||
}
|
||||
|
||||
func TestService_HeadSyncSelectionProofDomain(t *testing.T) {
|
||||
s, _ := testutil.DeterministicGenesisStateAltair(t, params.BeaconConfig().TargetCommitteeSize)
|
||||
c := &Service{}
|
||||
c.head = &head{state: s}
|
||||
|
||||
wanted, err := helpers.Domain(s.Fork(), helpers.SlotToEpoch(s.Slot()), params.BeaconConfig().DomainSyncCommitteeSelectionProof, s.GenesisValidatorRoot())
|
||||
require.NoError(t, err)
|
||||
|
||||
d, err := c.HeadSyncSelectionProofDomain(context.Background(), 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.DeepEqual(t, wanted, d)
|
||||
}
|
||||
|
||||
func TestSyncCommitteeHeadStateCache_RoundTrip(t *testing.T) {
|
||||
c := newSyncCommitteeHeadState()
|
||||
beaconState, _ := testutil.DeterministicGenesisStateAltair(t, 100)
|
||||
require.NoError(t, beaconState.SetSlot(100))
|
||||
cachedState := c.get(101)
|
||||
require.Equal(t, nil, cachedState)
|
||||
c.add(101, beaconState)
|
||||
cachedState = c.get(101)
|
||||
require.DeepEqual(t, beaconState, cachedState)
|
||||
}
|
||||
@@ -9,10 +9,9 @@ import (
|
||||
mock "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/testing"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
testDB "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
ethpbv1 "github.com/prysmaticlabs/prysm/proto/eth/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/eth/v1alpha1/wrapper"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/wrapper"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
@@ -60,7 +59,7 @@ func TestSaveHead_Different(t *testing.T) {
|
||||
headState, err := testutil.NewBeaconState()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, headState.SetSlot(1))
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveStateSummary(context.Background(), &pb.StateSummary{Slot: 1, Root: newRoot[:]}))
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveStateSummary(context.Background(), ðpb.StateSummary{Slot: 1, Root: newRoot[:]}))
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveState(context.Background(), headState, newRoot))
|
||||
require.NoError(t, service.saveHead(context.Background(), newRoot))
|
||||
|
||||
@@ -105,7 +104,7 @@ func TestSaveHead_Different_Reorg(t *testing.T) {
|
||||
headState, err := testutil.NewBeaconState()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, headState.SetSlot(1))
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveStateSummary(context.Background(), &pb.StateSummary{Slot: 1, Root: newRoot[:]}))
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveStateSummary(context.Background(), ðpb.StateSummary{Slot: 1, Root: newRoot[:]}))
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveState(context.Background(), headState, newRoot))
|
||||
require.NoError(t, service.saveHead(context.Background(), newRoot))
|
||||
|
||||
@@ -127,7 +126,7 @@ func TestCacheJustifiedStateBalances_CanCache(t *testing.T) {
|
||||
|
||||
state, _ := testutil.DeterministicGenesisState(t, 100)
|
||||
r := [32]byte{'a'}
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveStateSummary(context.Background(), &pb.StateSummary{Root: r[:]}))
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveStateSummary(context.Background(), ðpb.StateSummary{Root: r[:]}))
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveState(context.Background(), state, r))
|
||||
require.NoError(t, service.cacheJustifiedStateBalances(context.Background(), r))
|
||||
require.DeepEqual(t, service.getJustifiedBalances(), state.Balances(), "Incorrect justified balances")
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
testDB "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/protoarray"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stategen"
|
||||
"github.com/prysmaticlabs/prysm/proto/eth/v1alpha1/wrapper"
|
||||
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/wrapper"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package blockchain
|
||||
|
||||
import (
|
||||
"github.com/prysmaticlabs/prysm/proto/interfaces"
|
||||
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/block"
|
||||
)
|
||||
|
||||
// This saves a beacon block to the initial sync blocks cache.
|
||||
func (s *Service) saveInitSyncBlock(r [32]byte, b interfaces.SignedBeaconBlock) {
|
||||
func (s *Service) saveInitSyncBlock(r [32]byte, b block.SignedBeaconBlock) {
|
||||
s.initSyncBlocksLock.Lock()
|
||||
defer s.initSyncBlocksLock.Unlock()
|
||||
s.initSyncBlocks[r] = b
|
||||
@@ -22,7 +22,7 @@ func (s *Service) hasInitSyncBlock(r [32]byte) bool {
|
||||
|
||||
// This retrieves a beacon block from the initial sync blocks cache using the root of
|
||||
// the block.
|
||||
func (s *Service) getInitSyncBlock(r [32]byte) interfaces.SignedBeaconBlock {
|
||||
func (s *Service) getInitSyncBlock(r [32]byte) block.SignedBeaconBlock {
|
||||
s.initSyncBlocksLock.RLock()
|
||||
defer s.initSyncBlocksLock.RUnlock()
|
||||
b := s.initSyncBlocks[r]
|
||||
@@ -31,11 +31,11 @@ func (s *Service) getInitSyncBlock(r [32]byte) interfaces.SignedBeaconBlock {
|
||||
|
||||
// This retrieves all the beacon blocks from the initial sync blocks cache, the returned
|
||||
// blocks are unordered.
|
||||
func (s *Service) getInitSyncBlocks() []interfaces.SignedBeaconBlock {
|
||||
func (s *Service) getInitSyncBlocks() []block.SignedBeaconBlock {
|
||||
s.initSyncBlocksLock.RLock()
|
||||
defer s.initSyncBlocksLock.RUnlock()
|
||||
|
||||
blks := make([]interfaces.SignedBeaconBlock, 0, len(s.initSyncBlocks))
|
||||
blks := make([]block.SignedBeaconBlock, 0, len(s.initSyncBlocks))
|
||||
for _, b := range s.initSyncBlocks {
|
||||
blks = append(blks, b)
|
||||
}
|
||||
@@ -46,5 +46,5 @@ func (s *Service) getInitSyncBlocks() []interfaces.SignedBeaconBlock {
|
||||
func (s *Service) clearInitSyncBlocks() {
|
||||
s.initSyncBlocksLock.Lock()
|
||||
defer s.initSyncBlocksLock.Unlock()
|
||||
s.initSyncBlocks = make(map[[32]byte]interfaces.SignedBeaconBlock)
|
||||
s.initSyncBlocks = make(map[[32]byte]block.SignedBeaconBlock)
|
||||
}
|
||||
|
||||
@@ -6,18 +6,19 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/interfaces"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/block"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/timeutils"
|
||||
"github.com/prysmaticlabs/prysm/shared/version"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var log = logrus.WithField("prefix", "blockchain")
|
||||
|
||||
// logs state transition related data every slot.
|
||||
func logStateTransitionData(b interfaces.BeaconBlock) {
|
||||
log := log.WithField("slot", b.Slot)
|
||||
func logStateTransitionData(b block.BeaconBlock) {
|
||||
log := log.WithField("slot", b.Slot())
|
||||
if len(b.Body().Attestations()) > 0 {
|
||||
log = log.WithField("attestations", len(b.Body().Attestations()))
|
||||
}
|
||||
@@ -33,10 +34,16 @@ func logStateTransitionData(b interfaces.BeaconBlock) {
|
||||
if len(b.Body().VoluntaryExits()) > 0 {
|
||||
log = log.WithField("voluntaryExits", len(b.Body().VoluntaryExits()))
|
||||
}
|
||||
if b.Version() == version.Altair {
|
||||
agg, err := b.Body().SyncAggregate()
|
||||
if err == nil {
|
||||
log = log.WithField("syncBitsCount", agg.SyncCommitteeBits.Count())
|
||||
}
|
||||
}
|
||||
log.Info("Finished applying state transition")
|
||||
}
|
||||
|
||||
func logBlockSyncStatus(block interfaces.BeaconBlock, blockRoot [32]byte, finalized *ethpb.Checkpoint, receivedTime time.Time, genesisTime uint64) error {
|
||||
func logBlockSyncStatus(block block.BeaconBlock, blockRoot [32]byte, finalized *ethpb.Checkpoint, receivedTime time.Time, genesisTime uint64) error {
|
||||
startTime, err := helpers.SlotToTime(genesisTime, block.Slot())
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -3,9 +3,9 @@ package blockchain
|
||||
import (
|
||||
"testing"
|
||||
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/eth/v1alpha1/wrapper"
|
||||
"github.com/prysmaticlabs/prysm/proto/interfaces"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/block"
|
||||
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/wrapper"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
logTest "github.com/sirupsen/logrus/hooks/test"
|
||||
)
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
func Test_logStateTransitionData(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
b interfaces.BeaconBlock
|
||||
b block.BeaconBlock
|
||||
want string
|
||||
}{
|
||||
{name: "empty block body",
|
||||
|
||||
@@ -3,15 +3,18 @@ package blockchain
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/altair"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/epoch/precompute"
|
||||
iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/interfaces"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/block"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/version"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -107,6 +110,14 @@ var (
|
||||
Buckets: []float64{1, 2, 3, 4, 6, 32, 64},
|
||||
},
|
||||
)
|
||||
syncHeadStateMiss = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "sync_head_state_miss",
|
||||
Help: "The number of sync head state requests that are present in the cache.",
|
||||
})
|
||||
syncHeadStateHit = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "sync_head_state_hit",
|
||||
Help: "The number of sync head state requests that are not present in the cache.",
|
||||
})
|
||||
)
|
||||
|
||||
// reportSlotMetrics reports slot related metrics.
|
||||
@@ -121,7 +132,7 @@ func reportSlotMetrics(stateSlot, headSlot, clockSlot types.Slot, finalizedCheck
|
||||
}
|
||||
|
||||
// reportEpochMetrics reports epoch related metrics.
|
||||
func reportEpochMetrics(ctx context.Context, postState, headState iface.BeaconState) error {
|
||||
func reportEpochMetrics(ctx context.Context, postState, headState state.BeaconState) error {
|
||||
currentEpoch := types.Epoch(postState.Slot() / params.BeaconConfig().SlotsPerEpoch)
|
||||
|
||||
// Validator instances
|
||||
@@ -206,14 +217,31 @@ func reportEpochMetrics(ctx context.Context, postState, headState iface.BeaconSt
|
||||
beaconFinalizedRoot.Set(float64(bytesutil.ToLowInt64(postState.FinalizedCheckpoint().Root)))
|
||||
currentEth1DataDepositCount.Set(float64(postState.Eth1Data().DepositCount))
|
||||
|
||||
// Validator participation should be viewed on the canonical chain.
|
||||
v, b, err := precompute.New(ctx, headState)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, b, err = precompute.ProcessAttestations(ctx, headState, v, b)
|
||||
if err != nil {
|
||||
return err
|
||||
var b *precompute.Balance
|
||||
var v []*precompute.Validator
|
||||
var err error
|
||||
switch headState.Version() {
|
||||
case version.Phase0:
|
||||
// Validator participation should be viewed on the canonical chain.
|
||||
v, b, err = precompute.New(ctx, headState)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, b, err = precompute.ProcessAttestations(ctx, headState, v, b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case version.Altair:
|
||||
v, b, err = altair.InitializeEpochValidators(ctx, headState)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, b, err = altair.ProcessEpochParticipation(ctx, headState, b, v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
return errors.Errorf("invalid state type provided: %T", headState.InnerStateUnsafe())
|
||||
}
|
||||
prevEpochActiveBalances.Set(float64(b.ActivePrevEpoch))
|
||||
prevEpochSourceBalances.Set(float64(b.PrevEpochAttested))
|
||||
@@ -228,7 +256,7 @@ func reportEpochMetrics(ctx context.Context, postState, headState iface.BeaconSt
|
||||
return nil
|
||||
}
|
||||
|
||||
func reportAttestationInclusion(blk interfaces.BeaconBlock) {
|
||||
func reportAttestationInclusion(blk block.BeaconBlock) {
|
||||
for _, att := range blk.Body().Attestations() {
|
||||
attestationInclusionDelay.Observe(float64(blk.Slot() - att.Data.Slot))
|
||||
}
|
||||
|
||||
@@ -4,8 +4,7 @@ import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
eth "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
||||
eth "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
@@ -25,7 +24,7 @@ func TestReportEpochMetrics_BadAttestation(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
h, err := testutil.NewBeaconState()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, h.AppendCurrentEpochAttestations(&pb.PendingAttestation{InclusionDelay: 0}))
|
||||
require.NoError(t, h.AppendCurrentEpochAttestations(ð.PendingAttestation{InclusionDelay: 0}))
|
||||
err = reportEpochMetrics(context.Background(), s, h)
|
||||
require.ErrorContains(t, "attestation with inclusion delay of 0", err)
|
||||
}
|
||||
@@ -36,7 +35,7 @@ func TestReportEpochMetrics_SlashedValidatorOutOfBound(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
v.Slashed = true
|
||||
require.NoError(t, h.UpdateValidatorAtIndex(0, v))
|
||||
require.NoError(t, h.AppendCurrentEpochAttestations(&pb.PendingAttestation{InclusionDelay: 1, Data: testutil.HydrateAttestationData(ð.AttestationData{})}))
|
||||
require.NoError(t, h.AppendCurrentEpochAttestations(ð.PendingAttestation{InclusionDelay: 1, Data: testutil.HydrateAttestationData(ð.AttestationData{})}))
|
||||
err = reportEpochMetrics(context.Background(), h, h)
|
||||
require.ErrorContains(t, "slot 0 out of bounds", err)
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/shared/attestationutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/copyutil"
|
||||
|
||||
@@ -8,9 +8,9 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/state"
|
||||
iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
||||
core "github.com/prysmaticlabs/prysm/beacon-chain/core/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
"github.com/prysmaticlabs/prysm/shared/mputil"
|
||||
@@ -18,7 +18,7 @@ import (
|
||||
)
|
||||
|
||||
// getAttPreState retrieves the att pre state by either from the cache or the DB.
|
||||
func (s *Service) getAttPreState(ctx context.Context, c *ethpb.Checkpoint) (iface.BeaconState, error) {
|
||||
func (s *Service) getAttPreState(ctx context.Context, c *ethpb.Checkpoint) (state.BeaconState, error) {
|
||||
// Use a multilock to allow scoped holding of a mutex by a checkpoint root + epoch
|
||||
// allowing us to behave smarter in terms of how this function is used concurrently.
|
||||
epochKey := strconv.FormatUint(uint64(c.Epoch), 10 /* base 10 */)
|
||||
@@ -44,32 +44,23 @@ func (s *Service) getAttPreState(ctx context.Context, c *ethpb.Checkpoint) (ifac
|
||||
}
|
||||
if epochStartSlot > baseState.Slot() {
|
||||
if featureconfig.Get().EnableNextSlotStateCache {
|
||||
baseState, err = state.ProcessSlotsUsingNextSlotCache(ctx, baseState, c.Root, epochStartSlot)
|
||||
baseState, err = core.ProcessSlotsUsingNextSlotCache(ctx, baseState, c.Root, epochStartSlot)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not process slots up to epoch %d", c.Epoch)
|
||||
}
|
||||
} else {
|
||||
baseState, err = state.ProcessSlots(ctx, baseState, epochStartSlot)
|
||||
baseState, err = core.ProcessSlots(ctx, baseState, epochStartSlot)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not process slots up to epoch %d", c.Epoch)
|
||||
}
|
||||
}
|
||||
if err := s.checkpointStateCache.AddCheckpointState(c, baseState); err != nil {
|
||||
return nil, errors.Wrap(err, "could not saved checkpoint state to cache")
|
||||
}
|
||||
return baseState, nil
|
||||
}
|
||||
|
||||
// To avoid sharing the same state across checkpoint state cache and hot state cache,
|
||||
// we don't add the state to check point cache.
|
||||
has, err := s.cfg.StateGen.HasStateInCache(ctx, bytesutil.ToBytes32(c.Root))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !has {
|
||||
if err := s.checkpointStateCache.AddCheckpointState(c, baseState); err != nil {
|
||||
return nil, errors.Wrap(err, "could not saved checkpoint state to cache")
|
||||
}
|
||||
// Sharing the same state across caches is perfectly fine here, the fetching
|
||||
// of attestation prestate is by far the most accessed state fetching pattern in
|
||||
// the beacon node. An extra state instance cached isn't an issue in the bigger
|
||||
// picture.
|
||||
if err := s.checkpointStateCache.AddCheckpointState(c, baseState); err != nil {
|
||||
return nil, errors.Wrap(err, "could not save checkpoint state to cache")
|
||||
}
|
||||
return baseState, nil
|
||||
|
||||
|
||||
@@ -10,9 +10,8 @@ import (
|
||||
testDB "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/protoarray"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stategen"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/eth/v1alpha1/wrapper"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/wrapper"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
@@ -61,7 +60,7 @@ func TestStore_OnAttestation_ErrorConditions(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
s, err = testutil.NewBeaconState()
|
||||
require.NoError(t, err)
|
||||
err = s.SetFork(&pb.Fork{
|
||||
err = s.SetFork(ðpb.Fork{
|
||||
Epoch: 0,
|
||||
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
@@ -186,7 +185,7 @@ func TestStore_SaveCheckpointState(t *testing.T) {
|
||||
r = bytesutil.ToBytes32([]byte{'A'})
|
||||
cp1 := ðpb.Checkpoint{Epoch: 1, Root: bytesutil.PadTo([]byte{'A'}, 32)}
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveState(ctx, s, bytesutil.ToBytes32([]byte{'A'})))
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveStateSummary(ctx, &pb.StateSummary{Root: bytesutil.PadTo([]byte{'A'}, 32)}))
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveStateSummary(ctx, ðpb.StateSummary{Root: bytesutil.PadTo([]byte{'A'}, 32)}))
|
||||
|
||||
s1, err := service.getAttPreState(ctx, cp1)
|
||||
require.NoError(t, err)
|
||||
@@ -194,7 +193,7 @@ func TestStore_SaveCheckpointState(t *testing.T) {
|
||||
|
||||
cp2 := ðpb.Checkpoint{Epoch: 2, Root: bytesutil.PadTo([]byte{'B'}, 32)}
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveState(ctx, s, bytesutil.ToBytes32([]byte{'B'})))
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveStateSummary(ctx, &pb.StateSummary{Root: bytesutil.PadTo([]byte{'B'}, 32)}))
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveStateSummary(ctx, ðpb.StateSummary{Root: bytesutil.PadTo([]byte{'B'}, 32)}))
|
||||
s2, err := service.getAttPreState(ctx, cp2)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 2*params.BeaconConfig().SlotsPerEpoch, s2.Slot(), "Unexpected state slot")
|
||||
@@ -218,7 +217,7 @@ func TestStore_SaveCheckpointState(t *testing.T) {
|
||||
service.prevFinalizedCheckpt = ðpb.Checkpoint{Root: r[:]}
|
||||
cp3 := ðpb.Checkpoint{Epoch: 1, Root: bytesutil.PadTo([]byte{'C'}, 32)}
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveState(ctx, s, bytesutil.ToBytes32([]byte{'C'})))
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveStateSummary(ctx, &pb.StateSummary{Root: bytesutil.PadTo([]byte{'C'}, 32)}))
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveStateSummary(ctx, ðpb.StateSummary{Root: bytesutil.PadTo([]byte{'C'}, 32)}))
|
||||
s3, err := service.getAttPreState(ctx, cp3)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, s.Slot(), s3.Slot(), "Unexpected state slot")
|
||||
|
||||
@@ -9,12 +9,11 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/feed"
|
||||
statefeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/state"
|
||||
iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
core "github.com/prysmaticlabs/prysm/beacon-chain/core/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
ethpbv1 "github.com/prysmaticlabs/prysm/proto/eth/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/interfaces"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/block"
|
||||
"github.com/prysmaticlabs/prysm/shared/attestationutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
@@ -83,7 +82,7 @@ var initialSyncBlockCacheSize = uint64(2 * params.BeaconConfig().SlotsPerEpoch)
|
||||
// ancestor_at_finalized_slot = get_ancestor(store, store.justified_checkpoint.root, finalized_slot)
|
||||
// if ancestor_at_finalized_slot != store.finalized_checkpoint.root:
|
||||
// store.justified_checkpoint = state.current_justified_checkpoint
|
||||
func (s *Service) onBlock(ctx context.Context, signed interfaces.SignedBeaconBlock, blockRoot [32]byte) error {
|
||||
func (s *Service) onBlock(ctx context.Context, signed block.SignedBeaconBlock, blockRoot [32]byte) error {
|
||||
ctx, span := trace.StartSpan(ctx, "blockChain.onBlock")
|
||||
defer span.End()
|
||||
|
||||
@@ -97,7 +96,7 @@ func (s *Service) onBlock(ctx context.Context, signed interfaces.SignedBeaconBlo
|
||||
return err
|
||||
}
|
||||
|
||||
postState, err := state.ExecuteStateTransition(ctx, preState, signed)
|
||||
postState, err := core.ExecuteStateTransition(ctx, preState, signed)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -114,7 +113,7 @@ func (s *Service) onBlock(ctx context.Context, signed interfaces.SignedBeaconBlo
|
||||
// with a custom deadline, therefore using the background context instead.
|
||||
slotCtx, cancel := context.WithTimeout(context.Background(), slotDeadline)
|
||||
defer cancel()
|
||||
if err := state.UpdateNextSlotCache(slotCtx, blockRoot[:], postState); err != nil {
|
||||
if err := core.UpdateNextSlotCache(slotCtx, blockRoot[:], postState); err != nil {
|
||||
log.WithError(err).Debug("could not update next slot state cache")
|
||||
}
|
||||
}()
|
||||
@@ -195,7 +194,7 @@ func (s *Service) onBlock(ctx context.Context, signed interfaces.SignedBeaconBlo
|
||||
return s.handleEpochBoundary(ctx, postState)
|
||||
}
|
||||
|
||||
func (s *Service) onBlockBatch(ctx context.Context, blks []interfaces.SignedBeaconBlock,
|
||||
func (s *Service) onBlockBatch(ctx context.Context, blks []block.SignedBeaconBlock,
|
||||
blockRoots [][32]byte) ([]*ethpb.Checkpoint, []*ethpb.Checkpoint, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "blockChain.onBlockBatch")
|
||||
defer span.End()
|
||||
@@ -228,9 +227,9 @@ func (s *Service) onBlockBatch(ctx context.Context, blks []interfaces.SignedBeac
|
||||
Messages: [][32]byte{},
|
||||
}
|
||||
var set *bls.SignatureSet
|
||||
boundaries := make(map[[32]byte]iface.BeaconState)
|
||||
boundaries := make(map[[32]byte]state.BeaconState)
|
||||
for i, b := range blks {
|
||||
set, preState, err = state.ExecuteStateTransitionNoVerifyAnySig(ctx, preState, b)
|
||||
set, preState, err = core.ExecuteStateTransitionNoVerifyAnySig(ctx, preState, b)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@@ -271,7 +270,7 @@ func (s *Service) onBlockBatch(ctx context.Context, blks []interfaces.SignedBeac
|
||||
|
||||
// handles a block after the block's batch has been verified, where we can save blocks
|
||||
// their state summaries and split them off to relative hot/cold storage.
|
||||
func (s *Service) handleBlockAfterBatchVerify(ctx context.Context, signed interfaces.SignedBeaconBlock,
|
||||
func (s *Service) handleBlockAfterBatchVerify(ctx context.Context, signed block.SignedBeaconBlock,
|
||||
blockRoot [32]byte, fCheckpoint, jCheckpoint *ethpb.Checkpoint) error {
|
||||
b := signed.Block()
|
||||
|
||||
@@ -279,7 +278,7 @@ func (s *Service) handleBlockAfterBatchVerify(ctx context.Context, signed interf
|
||||
if err := s.insertBlockToForkChoiceStore(ctx, b, blockRoot, fCheckpoint, jCheckpoint); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.cfg.BeaconDB.SaveStateSummary(ctx, &pb.StateSummary{
|
||||
if err := s.cfg.BeaconDB.SaveStateSummary(ctx, ðpb.StateSummary{
|
||||
Slot: signed.Block().Slot(),
|
||||
Root: blockRoot[:],
|
||||
}); err != nil {
|
||||
@@ -305,19 +304,26 @@ func (s *Service) handleBlockAfterBatchVerify(ctx context.Context, signed interf
|
||||
if err := s.updateFinalized(ctx, fCheckpoint); err != nil {
|
||||
return err
|
||||
}
|
||||
if featureconfig.Get().UpdateHeadTimely {
|
||||
s.prevFinalizedCheckpt = s.finalizedCheckpt
|
||||
s.finalizedCheckpt = fCheckpoint
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Epoch boundary bookkeeping such as logging epoch summaries.
|
||||
func (s *Service) handleEpochBoundary(ctx context.Context, postState iface.BeaconState) error {
|
||||
func (s *Service) handleEpochBoundary(ctx context.Context, postState state.BeaconState) error {
|
||||
ctx, span := trace.StartSpan(ctx, "blockChain.handleEpochBoundary")
|
||||
defer span.End()
|
||||
|
||||
if postState.Slot()+1 == s.nextEpochBoundarySlot {
|
||||
// Update caches for the next epoch at epoch boundary slot - 1.
|
||||
if err := helpers.UpdateCommitteeCache(postState, helpers.NextEpoch(postState)); err != nil {
|
||||
return err
|
||||
}
|
||||
copied := postState.Copy()
|
||||
copied, err := state.ProcessSlots(ctx, copied, copied.Slot()+1)
|
||||
copied, err := core.ProcessSlots(ctx, copied, copied.Slot()+1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -349,8 +355,11 @@ func (s *Service) handleEpochBoundary(ctx context.Context, postState iface.Beaco
|
||||
|
||||
// This feeds in the block and block's attestations to fork choice store. It's allows fork choice store
|
||||
// to gain information on the most current chain.
|
||||
func (s *Service) insertBlockAndAttestationsToForkChoiceStore(ctx context.Context, blk interfaces.BeaconBlock, root [32]byte,
|
||||
st iface.BeaconState) error {
|
||||
func (s *Service) insertBlockAndAttestationsToForkChoiceStore(ctx context.Context, blk block.BeaconBlock, root [32]byte,
|
||||
st state.BeaconState) error {
|
||||
ctx, span := trace.StartSpan(ctx, "blockChain.insertBlockAndAttestationsToForkChoiceStore")
|
||||
defer span.End()
|
||||
|
||||
fCheckpoint := st.FinalizedCheckpoint()
|
||||
jCheckpoint := st.CurrentJustifiedCheckpoint()
|
||||
if err := s.insertBlockToForkChoiceStore(ctx, blk, root, fCheckpoint, jCheckpoint); err != nil {
|
||||
@@ -371,7 +380,7 @@ func (s *Service) insertBlockAndAttestationsToForkChoiceStore(ctx context.Contex
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) insertBlockToForkChoiceStore(ctx context.Context, blk interfaces.BeaconBlock,
|
||||
func (s *Service) insertBlockToForkChoiceStore(ctx context.Context, blk block.BeaconBlock,
|
||||
root [32]byte, fCheckpoint, jCheckpoint *ethpb.Checkpoint) error {
|
||||
if err := s.fillInForkChoiceMissingBlocks(ctx, blk, fCheckpoint, jCheckpoint); err != nil {
|
||||
return err
|
||||
@@ -388,7 +397,7 @@ func (s *Service) insertBlockToForkChoiceStore(ctx context.Context, blk interfac
|
||||
|
||||
// This saves post state info to DB or cache. This also saves post state info to fork choice store.
|
||||
// Post state info consists of processed block and state. Do not call this method unless the block and state are verified.
|
||||
func (s *Service) savePostStateInfo(ctx context.Context, r [32]byte, b interfaces.SignedBeaconBlock, st iface.BeaconState, initSync bool) error {
|
||||
func (s *Service) savePostStateInfo(ctx context.Context, r [32]byte, b block.SignedBeaconBlock, st state.BeaconState, initSync bool) error {
|
||||
ctx, span := trace.StartSpan(ctx, "blockChain.savePostStateInfo")
|
||||
defer span.End()
|
||||
if initSync {
|
||||
|
||||
@@ -8,9 +8,9 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/interfaces"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/block"
|
||||
"github.com/prysmaticlabs/prysm/shared/attestationutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
@@ -27,7 +27,7 @@ func (s *Service) CurrentSlot() types.Slot {
|
||||
// getBlockPreState returns the pre state of an incoming block. It uses the parent root of the block
|
||||
// to retrieve the state in DB. It verifies the pre state's validity and the incoming block
|
||||
// is in the correct time window.
|
||||
func (s *Service) getBlockPreState(ctx context.Context, b interfaces.BeaconBlock) (iface.BeaconState, error) {
|
||||
func (s *Service) getBlockPreState(ctx context.Context, b block.BeaconBlock) (state.BeaconState, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "blockChain.getBlockPreState")
|
||||
defer span.End()
|
||||
|
||||
@@ -58,7 +58,7 @@ func (s *Service) getBlockPreState(ctx context.Context, b interfaces.BeaconBlock
|
||||
}
|
||||
|
||||
// verifyBlkPreState validates input block has a valid pre-state.
|
||||
func (s *Service) verifyBlkPreState(ctx context.Context, b interfaces.BeaconBlock) error {
|
||||
func (s *Service) verifyBlkPreState(ctx context.Context, b block.BeaconBlock) error {
|
||||
ctx, span := trace.StartSpan(ctx, "blockChain.verifyBlkPreState")
|
||||
defer span.End()
|
||||
|
||||
@@ -121,7 +121,7 @@ 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 interfaces.BeaconBlock) error {
|
||||
func (s *Service) verifyBlkFinalizedSlot(b block.BeaconBlock) error {
|
||||
finalizedSlot, err := helpers.StartSlot(s.finalizedCheckpt.Epoch)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -137,10 +137,13 @@ func (s *Service) verifyBlkFinalizedSlot(b interfaces.BeaconBlock) error {
|
||||
// Otherwise, delay incorporation of new justified checkpoint until next epoch boundary.
|
||||
// See https://ethresear.ch/t/prevention-of-bouncing-attack-on-ffg/6114 for more detailed analysis and discussion.
|
||||
func (s *Service) shouldUpdateCurrentJustified(ctx context.Context, newJustifiedCheckpt *ethpb.Checkpoint) (bool, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "blockChain.shouldUpdateCurrentJustified")
|
||||
defer span.End()
|
||||
|
||||
if helpers.SlotsSinceEpochStarts(s.CurrentSlot()) < params.BeaconConfig().SafeSlotsToUpdateJustified {
|
||||
return true, nil
|
||||
}
|
||||
var newJustifiedBlockSigned interfaces.SignedBeaconBlock
|
||||
var newJustifiedBlockSigned block.SignedBeaconBlock
|
||||
justifiedRoot := s.ensureRootNotZeros(bytesutil.ToBytes32(newJustifiedCheckpt.Root))
|
||||
var err error
|
||||
if s.hasInitSyncBlock(justifiedRoot) {
|
||||
@@ -163,7 +166,7 @@ func (s *Service) shouldUpdateCurrentJustified(ctx context.Context, newJustified
|
||||
if newJustifiedBlock.Slot() <= jSlot {
|
||||
return false, nil
|
||||
}
|
||||
var justifiedBlockSigned interfaces.SignedBeaconBlock
|
||||
var justifiedBlockSigned block.SignedBeaconBlock
|
||||
cachedJustifiedRoot := s.ensureRootNotZeros(bytesutil.ToBytes32(s.justifiedCheckpt.Root))
|
||||
if s.hasInitSyncBlock(cachedJustifiedRoot) {
|
||||
justifiedBlockSigned = s.getInitSyncBlock(cachedJustifiedRoot)
|
||||
@@ -188,7 +191,10 @@ func (s *Service) shouldUpdateCurrentJustified(ctx context.Context, newJustified
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (s *Service) updateJustified(ctx context.Context, state iface.ReadOnlyBeaconState) error {
|
||||
func (s *Service) updateJustified(ctx context.Context, state state.ReadOnlyBeaconState) error {
|
||||
ctx, span := trace.StartSpan(ctx, "blockChain.updateJustified")
|
||||
defer span.End()
|
||||
|
||||
cpt := state.CurrentJustifiedCheckpoint()
|
||||
if cpt.Epoch > s.bestJustifiedCheckpt.Epoch {
|
||||
s.bestJustifiedCheckpt = cpt
|
||||
@@ -223,6 +229,9 @@ func (s *Service) updateJustifiedInitSync(ctx context.Context, cp *ethpb.Checkpo
|
||||
}
|
||||
|
||||
func (s *Service) updateFinalized(ctx context.Context, cp *ethpb.Checkpoint) error {
|
||||
ctx, span := trace.StartSpan(ctx, "blockChain.updateFinalized")
|
||||
defer span.End()
|
||||
|
||||
// Blocks need to be saved so that we can retrieve finalized block from
|
||||
// DB when migrating states.
|
||||
if err := s.cfg.BeaconDB.SaveBlocks(ctx, s.getInitSyncBlocks()); err != nil {
|
||||
@@ -334,7 +343,7 @@ func (s *Service) ancestorByDB(ctx context.Context, r [32]byte, slot types.Slot)
|
||||
// ancestor_at_finalized_slot = get_ancestor(store, store.justified_checkpoint.root, finalized_slot)
|
||||
// if ancestor_at_finalized_slot != store.finalized_checkpoint.root:
|
||||
// store.justified_checkpoint = state.current_justified_checkpoint
|
||||
func (s *Service) finalizedImpliesNewJustified(ctx context.Context, state iface.BeaconState) error {
|
||||
func (s *Service) finalizedImpliesNewJustified(ctx context.Context, state state.BeaconState) error {
|
||||
// Update justified if it's different than the one cached in the store.
|
||||
if !attestationutil.CheckPointIsEqual(s.justifiedCheckpt, state.CurrentJustifiedCheckpoint()) {
|
||||
if state.CurrentJustifiedCheckpoint().Epoch > s.justifiedCheckpt.Epoch {
|
||||
@@ -364,9 +373,9 @@ func (s *Service) finalizedImpliesNewJustified(ctx context.Context, state iface.
|
||||
|
||||
// This retrieves missing blocks from DB (ie. the blocks that couldn't be received over sync) and inserts them to fork choice store.
|
||||
// This is useful for block tree visualizer and additional vote accounting.
|
||||
func (s *Service) fillInForkChoiceMissingBlocks(ctx context.Context, blk interfaces.BeaconBlock,
|
||||
func (s *Service) fillInForkChoiceMissingBlocks(ctx context.Context, blk block.BeaconBlock,
|
||||
fCheckpoint, jCheckpoint *ethpb.Checkpoint) error {
|
||||
pendingNodes := make([]interfaces.BeaconBlock, 0)
|
||||
pendingNodes := make([]block.BeaconBlock, 0)
|
||||
pendingRoots := make([][32]byte, 0)
|
||||
|
||||
parentRoot := bytesutil.ToBytes32(blk.ParentRoot())
|
||||
|
||||
@@ -13,17 +13,16 @@ import (
|
||||
mock "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/testing"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/cache/depositcache"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/state"
|
||||
core "github.com/prysmaticlabs/prysm/beacon-chain/core/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/db"
|
||||
testDB "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/protoarray"
|
||||
iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stategen"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/eth/v1alpha1/wrapper"
|
||||
"github.com/prysmaticlabs/prysm/proto/interfaces"
|
||||
v1 "github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/block"
|
||||
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/wrapper"
|
||||
"github.com/prysmaticlabs/prysm/shared/attestationutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
@@ -60,16 +59,16 @@ func TestStore_OnBlock(t *testing.T) {
|
||||
assert.NoError(t, beaconDB.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(random)))
|
||||
randomParentRoot, err := random.Block.HashTreeRoot()
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveStateSummary(ctx, &pb.StateSummary{Slot: st.Slot(), Root: randomParentRoot[:]}))
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveStateSummary(ctx, ðpb.StateSummary{Slot: st.Slot(), Root: randomParentRoot[:]}))
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveState(ctx, st.Copy(), randomParentRoot))
|
||||
randomParentRoot2 := roots[1]
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveStateSummary(ctx, &pb.StateSummary{Slot: st.Slot(), Root: randomParentRoot2}))
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveStateSummary(ctx, ðpb.StateSummary{Slot: st.Slot(), Root: randomParentRoot2}))
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveState(ctx, st.Copy(), bytesutil.ToBytes32(randomParentRoot2)))
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
blk *ethpb.SignedBeaconBlock
|
||||
s iface.BeaconState
|
||||
s state.BeaconState
|
||||
time uint64
|
||||
wantErrString string
|
||||
}{
|
||||
@@ -155,13 +154,13 @@ func TestStore_OnBlockBatch(t *testing.T) {
|
||||
|
||||
bState := st.Copy()
|
||||
|
||||
var blks []interfaces.SignedBeaconBlock
|
||||
var blks []block.SignedBeaconBlock
|
||||
var blkRoots [][32]byte
|
||||
var firstState iface.BeaconState
|
||||
var firstState state.BeaconState
|
||||
for i := 1; i < 10; i++ {
|
||||
b, err := testutil.GenerateFullBlock(bState, keys, testutil.DefaultBlockGenConfig(), types.Slot(i))
|
||||
require.NoError(t, err)
|
||||
bState, err = state.ExecuteStateTransition(ctx, bState, wrapper.WrappedPhase0SignedBeaconBlock(b))
|
||||
bState, err = core.ExecuteStateTransition(ctx, bState, wrapper.WrappedPhase0SignedBeaconBlock(b))
|
||||
require.NoError(t, err)
|
||||
if i == 1 {
|
||||
firstState = bState.Copy()
|
||||
@@ -256,7 +255,7 @@ func TestCachedPreState_CanGetFromStateSummary(t *testing.T) {
|
||||
service, err := NewService(ctx, cfg)
|
||||
require.NoError(t, err)
|
||||
|
||||
s, err := v1.InitializeFromProto(&pb.BeaconState{Slot: 1, GenesisValidatorsRoot: params.BeaconConfig().ZeroHash[:]})
|
||||
s, err := v1.InitializeFromProto(ðpb.BeaconState{Slot: 1, GenesisValidatorsRoot: params.BeaconConfig().ZeroHash[:]})
|
||||
require.NoError(t, err)
|
||||
|
||||
genesisStateRoot := [32]byte{}
|
||||
@@ -273,7 +272,7 @@ func TestCachedPreState_CanGetFromStateSummary(t *testing.T) {
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block.Slot = 1
|
||||
b.Block.ParentRoot = gRoot[:]
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveStateSummary(ctx, &pb.StateSummary{Slot: 1, Root: gRoot[:]}))
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveStateSummary(ctx, ðpb.StateSummary{Slot: 1, Root: gRoot[:]}))
|
||||
require.NoError(t, service.cfg.StateGen.SaveState(ctx, gRoot, s))
|
||||
require.NoError(t, service.verifyBlkPreState(ctx, wrapper.WrappedPhase0BeaconBlock(b.Block)))
|
||||
}
|
||||
@@ -308,9 +307,9 @@ func TestCachedPreState_CanGetFromDB(t *testing.T) {
|
||||
assert.ErrorContains(t, wanted, err)
|
||||
|
||||
b.Block.ParentRoot = gRoot[:]
|
||||
s, err := v1.InitializeFromProto(&pb.BeaconState{Slot: 1})
|
||||
s, err := v1.InitializeFromProto(ðpb.BeaconState{Slot: 1})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveStateSummary(ctx, &pb.StateSummary{Slot: 1, Root: gRoot[:]}))
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveStateSummary(ctx, ðpb.StateSummary{Slot: 1, Root: gRoot[:]}))
|
||||
require.NoError(t, service.cfg.StateGen.SaveState(ctx, gRoot, s))
|
||||
require.NoError(t, service.verifyBlkPreState(ctx, wrapper.WrappedPhase0SignedBeaconBlock(b).Block()))
|
||||
}
|
||||
@@ -763,7 +762,7 @@ func TestFinalizedImpliesNewJustified(t *testing.T) {
|
||||
service, err := NewService(ctx, &Config{BeaconDB: beaconDB, StateGen: stategen.New(beaconDB), ForkChoiceStore: protoarray.New(0, 0, [32]byte{})})
|
||||
require.NoError(t, err)
|
||||
service.justifiedCheckpt = test.args.cachedCheckPoint
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveStateSummary(ctx, &pb.StateSummary{Root: bytesutil.PadTo(test.want.Root, 32)}))
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveStateSummary(ctx, ðpb.StateSummary{Root: bytesutil.PadTo(test.want.Root, 32)}))
|
||||
genesisState, err := testutil.NewBeaconState()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveState(ctx, genesisState, bytesutil.ToBytes32(test.want.Root)))
|
||||
@@ -878,7 +877,7 @@ func TestUpdateJustifiedInitSync(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(gBlk)))
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveGenesisBlockRoot(ctx, gRoot))
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveStateSummary(ctx, &pb.StateSummary{Root: gRoot[:]}))
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveStateSummary(ctx, ðpb.StateSummary{Root: gRoot[:]}))
|
||||
beaconState, _ := testutil.DeterministicGenesisState(t, 32)
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveState(ctx, beaconState, gRoot))
|
||||
service.genesisRoot = gRoot
|
||||
|
||||
@@ -9,8 +9,8 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/feed"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/slotutil"
|
||||
@@ -21,7 +21,7 @@ import (
|
||||
// AttestationReceiver interface defines the methods of chain service receive and processing new attestations.
|
||||
type AttestationReceiver interface {
|
||||
ReceiveAttestationNoPubsub(ctx context.Context, att *ethpb.Attestation) error
|
||||
AttestationPreState(ctx context.Context, att *ethpb.Attestation) (iface.BeaconState, error)
|
||||
AttestationPreState(ctx context.Context, att *ethpb.Attestation) (state.BeaconState, error)
|
||||
VerifyLmdFfgConsistency(ctx context.Context, att *ethpb.Attestation) error
|
||||
VerifyFinalizedConsistency(ctx context.Context, root []byte) error
|
||||
}
|
||||
@@ -43,7 +43,7 @@ func (s *Service) ReceiveAttestationNoPubsub(ctx context.Context, att *ethpb.Att
|
||||
}
|
||||
|
||||
// AttestationPreState returns the pre state of attestation.
|
||||
func (s *Service) AttestationPreState(ctx context.Context, att *ethpb.Attestation) (iface.BeaconState, error) {
|
||||
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
|
||||
|
||||
@@ -12,8 +12,8 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/protoarray"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/operations/attestations"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stategen"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/eth/v1alpha1/wrapper"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/wrapper"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/feed"
|
||||
statefeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/proto/interfaces"
|
||||
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/block"
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
"github.com/prysmaticlabs/prysm/shared/timeutils"
|
||||
"github.com/prysmaticlabs/prysm/shared/traceutil"
|
||||
@@ -20,8 +20,8 @@ var epochsSinceFinalitySaveHotStateDB = types.Epoch(100)
|
||||
|
||||
// BlockReceiver interface defines the methods of chain service receive and processing new blocks.
|
||||
type BlockReceiver interface {
|
||||
ReceiveBlock(ctx context.Context, block interfaces.SignedBeaconBlock, blockRoot [32]byte) error
|
||||
ReceiveBlockBatch(ctx context.Context, blocks []interfaces.SignedBeaconBlock, blkRoots [][32]byte) error
|
||||
ReceiveBlock(ctx context.Context, block block.SignedBeaconBlock, blockRoot [32]byte) error
|
||||
ReceiveBlockBatch(ctx context.Context, blocks []block.SignedBeaconBlock, blkRoots [][32]byte) error
|
||||
HasInitSyncBlock(root [32]byte) bool
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ type BlockReceiver interface {
|
||||
// 1. Validate block, apply state transition and update check points
|
||||
// 2. Apply fork choice to the processed block
|
||||
// 3. Save latest head info
|
||||
func (s *Service) ReceiveBlock(ctx context.Context, block interfaces.SignedBeaconBlock, blockRoot [32]byte) error {
|
||||
func (s *Service) ReceiveBlock(ctx context.Context, block block.SignedBeaconBlock, blockRoot [32]byte) error {
|
||||
ctx, span := trace.StartSpan(ctx, "blockChain.ReceiveBlock")
|
||||
defer span.End()
|
||||
receivedTime := timeutils.Now()
|
||||
@@ -86,7 +86,7 @@ func (s *Service) ReceiveBlock(ctx context.Context, block interfaces.SignedBeaco
|
||||
// ReceiveBlockBatch processes the whole block batch at once, assuming the block batch is linear ,transitioning
|
||||
// the state, performing batch verification of all collected signatures and then performing the appropriate
|
||||
// actions for a block post-transition.
|
||||
func (s *Service) ReceiveBlockBatch(ctx context.Context, blocks []interfaces.SignedBeaconBlock, blkRoots [][32]byte) error {
|
||||
func (s *Service) ReceiveBlockBatch(ctx context.Context, blocks []block.SignedBeaconBlock, blkRoots [][32]byte) error {
|
||||
ctx, span := trace.StartSpan(ctx, "blockChain.ReceiveBlockBatch")
|
||||
defer span.End()
|
||||
|
||||
@@ -134,7 +134,7 @@ func (s *Service) HasInitSyncBlock(root [32]byte) bool {
|
||||
return s.hasInitSyncBlock(root)
|
||||
}
|
||||
|
||||
func (s *Service) handlePostBlockOperations(b interfaces.BeaconBlock) error {
|
||||
func (s *Service) handlePostBlockOperations(b block.BeaconBlock) error {
|
||||
// Delete the processed block attestations from attestation pool.
|
||||
if err := s.deletePoolAtts(b.Body().Attestations()); err != nil {
|
||||
return err
|
||||
|
||||
@@ -8,15 +8,17 @@ import (
|
||||
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
blockchainTesting "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/testing"
|
||||
"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"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/operations/attestations"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/operations/voluntaryexits"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stategen"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/eth/v1alpha1/wrapper"
|
||||
"github.com/prysmaticlabs/prysm/proto/interfaces"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/block"
|
||||
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/wrapper"
|
||||
"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"
|
||||
@@ -270,7 +272,7 @@ func TestService_ReceiveBlockBatch(t *testing.T) {
|
||||
s.finalizedCheckpt = ðpb.Checkpoint{Root: gRoot[:]}
|
||||
root, err := tt.args.block.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
blks := []interfaces.SignedBeaconBlock{wrapper.WrappedPhase0SignedBeaconBlock(tt.args.block)}
|
||||
blks := []block.SignedBeaconBlock{wrapper.WrappedPhase0SignedBeaconBlock(tt.args.block)}
|
||||
roots := [][32]byte{root}
|
||||
err = s.ReceiveBlockBatch(ctx, blks, roots)
|
||||
if tt.wantedErr != "" {
|
||||
@@ -283,6 +285,62 @@ func TestService_ReceiveBlockBatch(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestService_ReceiveBlockBatch_UpdateFinalizedCheckpoint(t *testing.T) {
|
||||
// Must enable head timely feature flag to test this.
|
||||
resetCfg := featureconfig.InitWithReset(&featureconfig.Flags{
|
||||
UpdateHeadTimely: true,
|
||||
})
|
||||
defer resetCfg()
|
||||
|
||||
ctx := context.Background()
|
||||
genesis, keys := testutil.DeterministicGenesisState(t, 64)
|
||||
|
||||
// Generate 5 epochs worth of blocks.
|
||||
var blks []block.SignedBeaconBlock
|
||||
var roots [][32]byte
|
||||
copied := genesis.Copy()
|
||||
for i := types.Slot(1); i < params.BeaconConfig().SlotsPerEpoch*5; i++ {
|
||||
b, err := testutil.GenerateFullBlock(copied, keys, testutil.DefaultBlockGenConfig(), i)
|
||||
assert.NoError(t, err)
|
||||
copied, err = state.ExecuteStateTransition(context.Background(), copied, wrapper.WrappedPhase0SignedBeaconBlock(b))
|
||||
assert.NoError(t, err)
|
||||
r, err := b.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
blks = append(blks, wrapper.WrappedPhase0SignedBeaconBlock(b))
|
||||
roots = append(roots, r)
|
||||
}
|
||||
|
||||
beaconDB := testDB.SetupDB(t)
|
||||
genesisBlockRoot, err := genesis.HashTreeRoot(ctx)
|
||||
require.NoError(t, err)
|
||||
cfg := &Config{
|
||||
BeaconDB: beaconDB,
|
||||
ForkChoiceStore: protoarray.New(
|
||||
0, // justifiedEpoch
|
||||
0, // finalizedEpoch
|
||||
genesisBlockRoot,
|
||||
),
|
||||
StateNotifier: &blockchainTesting.MockStateNotifier{RecordEvents: false},
|
||||
StateGen: stategen.New(beaconDB),
|
||||
}
|
||||
s, err := NewService(ctx, cfg)
|
||||
require.NoError(t, err)
|
||||
err = s.saveGenesisData(ctx, genesis)
|
||||
require.NoError(t, err)
|
||||
gBlk, err := s.cfg.BeaconDB.GenesisBlock(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
gRoot, err := gBlk.Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
s.finalizedCheckpt = ðpb.Checkpoint{Root: gRoot[:]}
|
||||
|
||||
// Process 5 epochs worth of blocks.
|
||||
require.NoError(t, s.ReceiveBlockBatch(ctx, blks, roots))
|
||||
|
||||
// Finalized epoch must be updated.
|
||||
require.Equal(t, types.Epoch(2), s.finalizedCheckpt.Epoch)
|
||||
}
|
||||
|
||||
func TestService_HasInitSyncBlock(t *testing.T) {
|
||||
s, err := NewService(context.Background(), &Config{StateNotifier: &blockchainTesting.MockStateNotifier{}})
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -16,7 +16,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/feed"
|
||||
statefeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/state"
|
||||
core "github.com/prysmaticlabs/prysm/beacon-chain/core/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/db"
|
||||
f "github.com/prysmaticlabs/prysm/beacon-chain/forkchoice"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/protoarray"
|
||||
@@ -25,11 +25,11 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/operations/voluntaryexits"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/p2p"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/powchain"
|
||||
iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stategen"
|
||||
"github.com/prysmaticlabs/prysm/cmd/beacon-chain/flags"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/interfaces"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/block"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/copyutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
@@ -60,7 +60,7 @@ type Service struct {
|
||||
nextEpochBoundarySlot types.Slot
|
||||
boundaryRoots [][32]byte
|
||||
checkpointStateCache *cache.CheckpointStateCache
|
||||
initSyncBlocks map[[32]byte]interfaces.SignedBeaconBlock
|
||||
initSyncBlocks map[[32]byte]block.SignedBeaconBlock
|
||||
initSyncBlocksLock sync.RWMutex
|
||||
justifiedBalances []uint64
|
||||
justifiedBalancesLock sync.RWMutex
|
||||
@@ -95,7 +95,7 @@ func NewService(ctx context.Context, cfg *Config) (*Service, error) {
|
||||
cancel: cancel,
|
||||
boundaryRoots: [][32]byte{},
|
||||
checkpointStateCache: cache.NewCheckpointStateCache(),
|
||||
initSyncBlocks: make(map[[32]byte]interfaces.SignedBeaconBlock),
|
||||
initSyncBlocks: make(map[[32]byte]block.SignedBeaconBlock),
|
||||
justifiedBalances: make([]uint64, 0),
|
||||
}, nil
|
||||
}
|
||||
@@ -271,14 +271,14 @@ func (s *Service) processChainStartTime(ctx context.Context, genesisTime time.Ti
|
||||
func (s *Service) initializeBeaconChain(
|
||||
ctx context.Context,
|
||||
genesisTime time.Time,
|
||||
preGenesisState iface.BeaconState,
|
||||
eth1data *ethpb.Eth1Data) (iface.BeaconState, error) {
|
||||
preGenesisState state.BeaconState,
|
||||
eth1data *ethpb.Eth1Data) (state.BeaconState, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "beacon-chain.Service.initializeBeaconChain")
|
||||
defer span.End()
|
||||
s.genesisTime = genesisTime
|
||||
unixTime := uint64(genesisTime.Unix())
|
||||
|
||||
genesisState, err := state.OptimizedGenesisBeaconState(unixTime, preGenesisState, eth1data)
|
||||
genesisState, err := core.OptimizedGenesisBeaconState(unixTime, preGenesisState, eth1data)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not initialize genesis state")
|
||||
}
|
||||
@@ -332,7 +332,7 @@ func (s *Service) Status() error {
|
||||
}
|
||||
|
||||
// This gets called when beacon chain is first initialized to save genesis data (state, block, and more) in db.
|
||||
func (s *Service) saveGenesisData(ctx context.Context, genesisState iface.BeaconState) error {
|
||||
func (s *Service) saveGenesisData(ctx context.Context, genesisState state.BeaconState) error {
|
||||
if err := s.cfg.BeaconDB.SaveGenesisData(ctx, genesisState); err != nil {
|
||||
return errors.Wrap(err, "could not save genesis data")
|
||||
}
|
||||
@@ -399,7 +399,7 @@ func (s *Service) initializeChainInfo(ctx context.Context) error {
|
||||
return errors.New("no finalized epoch in the database")
|
||||
}
|
||||
finalizedRoot := s.ensureRootNotZeros(bytesutil.ToBytes32(finalized.Root))
|
||||
var finalizedState iface.BeaconState
|
||||
var finalizedState state.BeaconState
|
||||
|
||||
finalizedState, err = s.cfg.StateGen.Resume(ctx)
|
||||
if err != nil {
|
||||
|
||||
@@ -21,13 +21,11 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/p2p"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/powchain"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stategen"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
|
||||
v1 "github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
|
||||
"github.com/prysmaticlabs/prysm/cmd/beacon-chain/flags"
|
||||
protodb "github.com/prysmaticlabs/prysm/proto/beacon/db"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/eth/v1alpha1/wrapper"
|
||||
"github.com/prysmaticlabs/prysm/proto/interfaces"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/block"
|
||||
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/wrapper"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/event"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
@@ -64,6 +62,11 @@ func (mb *mockBroadcaster) BroadcastAttestation(_ context.Context, _ uint64, _ *
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mb *mockBroadcaster) BroadcastSyncCommitteeMessage(_ context.Context, _ uint64, _ *ethpb.SyncCommitteeMessage) error {
|
||||
mb.broadcastCalled = true
|
||||
return nil
|
||||
}
|
||||
|
||||
var _ p2p.Broadcaster = (*mockBroadcaster)(nil)
|
||||
|
||||
func setupBeaconChain(t *testing.T, beaconDB db.Database) *Service {
|
||||
@@ -74,20 +77,20 @@ func setupBeaconChain(t *testing.T, beaconDB db.Database) *Service {
|
||||
bState, _ := testutil.DeterministicGenesisState(t, 10)
|
||||
pbState, err := v1.ProtobufBeaconState(bState.InnerStateUnsafe())
|
||||
require.NoError(t, err)
|
||||
err = beaconDB.SavePowchainData(ctx, &protodb.ETH1ChainData{
|
||||
err = beaconDB.SavePowchainData(ctx, ðpb.ETH1ChainData{
|
||||
BeaconState: pbState,
|
||||
Trie: &protodb.SparseMerkleTrie{},
|
||||
CurrentEth1Data: &protodb.LatestETH1Data{
|
||||
Trie: ðpb.SparseMerkleTrie{},
|
||||
CurrentEth1Data: ðpb.LatestETH1Data{
|
||||
BlockHash: make([]byte, 32),
|
||||
},
|
||||
ChainstartData: &protodb.ChainStartData{
|
||||
ChainstartData: ðpb.ChainStartData{
|
||||
Eth1Data: ðpb.Eth1Data{
|
||||
DepositRoot: make([]byte, 32),
|
||||
DepositCount: 0,
|
||||
BlockHash: make([]byte, 32),
|
||||
},
|
||||
},
|
||||
DepositContainers: []*protodb.DepositContainer{},
|
||||
DepositContainers: []*ethpb.DepositContainer{},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
web3Service, err = powchain.NewService(ctx, &powchain.Web3ServiceConfig{
|
||||
@@ -456,7 +459,7 @@ func TestServiceStop_SaveCachedBlocks(t *testing.T) {
|
||||
cfg: &Config{BeaconDB: beaconDB, StateGen: stategen.New(beaconDB)},
|
||||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
initSyncBlocks: make(map[[32]byte]interfaces.SignedBeaconBlock),
|
||||
initSyncBlocks: make(map[[32]byte]block.SignedBeaconBlock),
|
||||
}
|
||||
block := testutil.NewBeaconBlock()
|
||||
r, err := block.Block.HashTreeRoot()
|
||||
@@ -507,7 +510,7 @@ func BenchmarkHasBlockForkChoiceStore(b *testing.B) {
|
||||
block := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Body: ðpb.BeaconBlockBody{}}}
|
||||
r, err := block.Block.HashTreeRoot()
|
||||
require.NoError(b, err)
|
||||
bs := &pb.BeaconState{FinalizedCheckpoint: ðpb.Checkpoint{Root: make([]byte, 32)}, CurrentJustifiedCheckpoint: ðpb.Checkpoint{Root: make([]byte, 32)}}
|
||||
bs := ðpb.BeaconState{FinalizedCheckpoint: ðpb.Checkpoint{Root: make([]byte, 32)}, CurrentJustifiedCheckpoint: ðpb.Checkpoint{Root: make([]byte, 32)}}
|
||||
beaconState, err := v1.InitializeFromProto(bs)
|
||||
require.NoError(b, err)
|
||||
require.NoError(b, s.insertBlockAndAttestationsToForkChoiceStore(ctx, wrapper.WrappedPhase0SignedBeaconBlock(block).Block(), r, beaconState))
|
||||
|
||||
@@ -18,11 +18,10 @@ go_library(
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//beacon-chain/db:go_default_library",
|
||||
"//beacon-chain/forkchoice/protoarray:go_default_library",
|
||||
"//beacon-chain/state/interface:go_default_library",
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//beacon-chain/state/v1:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//proto/eth/v1alpha1:go_default_library",
|
||||
"//proto/interfaces:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//proto/prysm/v1alpha1/block:go_default_library",
|
||||
"//shared/bytesutil:go_default_library",
|
||||
"//shared/event:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
|
||||
@@ -18,11 +18,10 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/db"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/protoarray"
|
||||
iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/interfaces"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
v1 "github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/block"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/event"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
@@ -31,18 +30,18 @@ import (
|
||||
|
||||
// ChainService defines the mock interface for testing
|
||||
type ChainService struct {
|
||||
State iface.BeaconState
|
||||
State state.BeaconState
|
||||
Root []byte
|
||||
Block interfaces.SignedBeaconBlock
|
||||
Block block.SignedBeaconBlock
|
||||
FinalizedCheckPoint *ethpb.Checkpoint
|
||||
CurrentJustifiedCheckPoint *ethpb.Checkpoint
|
||||
PreviousJustifiedCheckPoint *ethpb.Checkpoint
|
||||
BlocksReceived []interfaces.SignedBeaconBlock
|
||||
BlocksReceived []block.SignedBeaconBlock
|
||||
Balance *precompute.Balance
|
||||
Genesis time.Time
|
||||
ValidatorsRoot [32]byte
|
||||
CanonicalRoots map[[32]byte]bool
|
||||
Fork *pb.Fork
|
||||
Fork *ethpb.Fork
|
||||
ETH1Data *ethpb.Eth1Data
|
||||
DB db.Database
|
||||
stateNotifier statefeed.Notifier
|
||||
@@ -52,6 +51,13 @@ type ChainService struct {
|
||||
ForkChoiceStore *protoarray.Store
|
||||
VerifyBlkDescendantErr error
|
||||
Slot *types.Slot // Pointer because 0 is a useful value, so checking against it can be incorrect.
|
||||
CurrentSyncCommitteeIndices []types.CommitteeIndex
|
||||
NextSyncCommitteeIndices []types.CommitteeIndex
|
||||
SyncCommitteeDomain []byte
|
||||
SyncSelectionProofDomain []byte
|
||||
SyncContributionProofDomain []byte
|
||||
PublicKey [48]byte
|
||||
SyncCommitteePubkeys [][]byte
|
||||
}
|
||||
|
||||
// StateNotifier mocks the same method in the chain service.
|
||||
@@ -150,7 +156,7 @@ func (mon *MockOperationNotifier) OperationFeed() *event.Feed {
|
||||
}
|
||||
|
||||
// ReceiveBlockInitialSync mocks ReceiveBlockInitialSync method in chain service.
|
||||
func (s *ChainService) ReceiveBlockInitialSync(ctx context.Context, block interfaces.SignedBeaconBlock, _ [32]byte) error {
|
||||
func (s *ChainService) ReceiveBlockInitialSync(ctx context.Context, block block.SignedBeaconBlock, _ [32]byte) error {
|
||||
if s.State == nil {
|
||||
s.State = &v1.BeaconState{}
|
||||
}
|
||||
@@ -177,7 +183,7 @@ func (s *ChainService) ReceiveBlockInitialSync(ctx context.Context, block interf
|
||||
}
|
||||
|
||||
// ReceiveBlockBatch processes blocks in batches from initial-sync.
|
||||
func (s *ChainService) ReceiveBlockBatch(ctx context.Context, blks []interfaces.SignedBeaconBlock, _ [][32]byte) error {
|
||||
func (s *ChainService) ReceiveBlockBatch(ctx context.Context, blks []block.SignedBeaconBlock, _ [][32]byte) error {
|
||||
if s.State == nil {
|
||||
s.State = &v1.BeaconState{}
|
||||
}
|
||||
@@ -206,7 +212,7 @@ func (s *ChainService) ReceiveBlockBatch(ctx context.Context, blks []interfaces.
|
||||
}
|
||||
|
||||
// ReceiveBlock mocks ReceiveBlock method in chain service.
|
||||
func (s *ChainService) ReceiveBlock(ctx context.Context, block interfaces.SignedBeaconBlock, _ [32]byte) error {
|
||||
func (s *ChainService) ReceiveBlock(ctx context.Context, block block.SignedBeaconBlock, _ [32]byte) error {
|
||||
if s.State == nil {
|
||||
s.State = &v1.BeaconState{}
|
||||
}
|
||||
@@ -249,17 +255,17 @@ func (s *ChainService) HeadRoot(_ context.Context) ([]byte, error) {
|
||||
}
|
||||
|
||||
// HeadBlock mocks HeadBlock method in chain service.
|
||||
func (s *ChainService) HeadBlock(context.Context) (interfaces.SignedBeaconBlock, error) {
|
||||
func (s *ChainService) HeadBlock(context.Context) (block.SignedBeaconBlock, error) {
|
||||
return s.Block, nil
|
||||
}
|
||||
|
||||
// HeadState mocks HeadState method in chain service.
|
||||
func (s *ChainService) HeadState(context.Context) (iface.BeaconState, error) {
|
||||
func (s *ChainService) HeadState(context.Context) (state.BeaconState, error) {
|
||||
return s.State, nil
|
||||
}
|
||||
|
||||
// CurrentFork mocks HeadState method in chain service.
|
||||
func (s *ChainService) CurrentFork() *pb.Fork {
|
||||
func (s *ChainService) CurrentFork() *ethpb.Fork {
|
||||
return s.Fork
|
||||
}
|
||||
|
||||
@@ -289,7 +295,7 @@ func (s *ChainService) ReceiveAttestationNoPubsub(context.Context, *ethpb.Attest
|
||||
}
|
||||
|
||||
// AttestationPreState mocks AttestationPreState method in chain service.
|
||||
func (s *ChainService) AttestationPreState(_ context.Context, _ *ethpb.Attestation) (iface.BeaconState, error) {
|
||||
func (s *ChainService) AttestationPreState(_ context.Context, _ *ethpb.Attestation) (state.BeaconState, error) {
|
||||
return s.State, nil
|
||||
}
|
||||
|
||||
@@ -393,3 +399,43 @@ func (s *ChainService) ChainHeads() ([][32]byte, []types.Slot) {
|
||||
},
|
||||
[]types.Slot{0, 1}
|
||||
}
|
||||
|
||||
// HeadPublicKeyToValidatorIndex mocks HeadPublicKeyToValidatorIndex and always return 0 and true.
|
||||
func (s *ChainService) HeadPublicKeyToValidatorIndex(ctx context.Context, pubKey [48]byte) (types.ValidatorIndex, bool) {
|
||||
return 0, true
|
||||
}
|
||||
|
||||
// HeadValidatorIndexToPublicKey mocks HeadValidatorIndexToPublicKey and always return empty and nil.
|
||||
func (s *ChainService) HeadValidatorIndexToPublicKey(ctx context.Context, index types.ValidatorIndex) ([48]byte, error) {
|
||||
return s.PublicKey, nil
|
||||
}
|
||||
|
||||
// HeadCurrentSyncCommitteeIndices mocks HeadCurrentSyncCommitteeIndices and always return `CurrentSyncCommitteeIndices`.
|
||||
func (s *ChainService) HeadCurrentSyncCommitteeIndices(ctx context.Context, index types.ValidatorIndex, slot types.Slot) ([]types.CommitteeIndex, error) {
|
||||
return s.CurrentSyncCommitteeIndices, nil
|
||||
}
|
||||
|
||||
// HeadNextSyncCommitteeIndices mocks HeadNextSyncCommitteeIndices and always return `HeadNextSyncCommitteeIndices`.
|
||||
func (s *ChainService) HeadNextSyncCommitteeIndices(ctx context.Context, index types.ValidatorIndex, slot types.Slot) ([]types.CommitteeIndex, error) {
|
||||
return s.NextSyncCommitteeIndices, nil
|
||||
}
|
||||
|
||||
// HeadSyncCommitteePubKeys mocks HeadSyncCommitteePubKeys and always return empty nil.
|
||||
func (s *ChainService) HeadSyncCommitteePubKeys(ctx context.Context, slot types.Slot, committeeIndex types.CommitteeIndex) ([][]byte, error) {
|
||||
return s.SyncCommitteePubkeys, nil
|
||||
}
|
||||
|
||||
// HeadSyncCommitteeDomain mocks HeadSyncCommitteeDomain and always return empty nil.
|
||||
func (s *ChainService) HeadSyncCommitteeDomain(ctx context.Context, slot types.Slot) ([]byte, error) {
|
||||
return s.SyncCommitteeDomain, nil
|
||||
}
|
||||
|
||||
// HeadSyncSelectionProofDomain mocks HeadSyncSelectionProofDomain and always return empty nil.
|
||||
func (s *ChainService) HeadSyncSelectionProofDomain(ctx context.Context, slot types.Slot) ([]byte, error) {
|
||||
return s.SyncSelectionProofDomain, nil
|
||||
}
|
||||
|
||||
// HeadSyncContributionProofDomain mocks HeadSyncContributionProofDomain and always return empty nil.
|
||||
func (s *ChainService) HeadSyncContributionProofDomain(ctx context.Context, slot types.Slot) ([]byte, error) {
|
||||
return s.SyncContributionProofDomain, nil
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@ import (
|
||||
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
testDB "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/eth/v1alpha1/wrapper"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/wrapper"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
|
||||
18
beacon-chain/cache/BUILD.bazel
vendored
18
beacon-chain/cache/BUILD.bazel
vendored
@@ -10,17 +10,21 @@ go_library(
|
||||
"committees.go",
|
||||
"common.go",
|
||||
"doc.go",
|
||||
"error.go",
|
||||
"proposer_indices_type.go",
|
||||
"skip_slot_cache.go",
|
||||
"subnet_ids.go",
|
||||
"sync_subnet_ids.go",
|
||||
] + select({
|
||||
"//fuzz:fuzzing_enabled": [
|
||||
"committee_disabled.go",
|
||||
"proposer_indices_disabled.go",
|
||||
"sync_committee_disabled.go",
|
||||
],
|
||||
"//conditions:default": [
|
||||
"committee.go",
|
||||
"proposer_indices.go",
|
||||
"sync_committee.go",
|
||||
],
|
||||
}),
|
||||
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/cache",
|
||||
@@ -30,11 +34,13 @@ go_library(
|
||||
"//tools:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
"//beacon-chain/state/interface:go_default_library",
|
||||
"//proto/eth/v1alpha1:go_default_library",
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//shared/bytesutil:go_default_library",
|
||||
"//shared/copyutil:go_default_library",
|
||||
"//shared/hashutil:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"//shared/rand:go_default_library",
|
||||
"//shared/sliceutil:go_default_library",
|
||||
"@com_github_hashicorp_golang_lru//:go_default_library",
|
||||
"@com_github_patrickmn_go_cache//:go_default_library",
|
||||
@@ -58,15 +64,17 @@ go_test(
|
||||
"proposer_indices_test.go",
|
||||
"skip_slot_cache_test.go",
|
||||
"subnet_ids_test.go",
|
||||
"sync_committee_test.go",
|
||||
"sync_subnet_ids_test.go",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//beacon-chain/state/interface:go_default_library",
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//beacon-chain/state/v1:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//proto/eth/v1alpha1:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//shared/bytesutil: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_google_gofuzz//:go_default_library",
|
||||
|
||||
2
beacon-chain/cache/attestation_data.go
vendored
2
beacon-chain/cache/attestation_data.go
vendored
@@ -10,7 +10,7 @@ import (
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/shared/copyutil"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
2
beacon-chain/cache/attestation_data_test.go
vendored
2
beacon-chain/cache/attestation_data_test.go
vendored
@@ -5,7 +5,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/cache"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
10
beacon-chain/cache/checkpoint_state.go
vendored
10
beacon-chain/cache/checkpoint_state.go
vendored
@@ -6,8 +6,8 @@ import (
|
||||
lru "github.com/hashicorp/golang-lru"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/shared/hashutil"
|
||||
)
|
||||
|
||||
@@ -47,7 +47,7 @@ func NewCheckpointStateCache() *CheckpointStateCache {
|
||||
|
||||
// StateByCheckpoint fetches state by checkpoint. Returns true with a
|
||||
// reference to the CheckpointState info, if exists. Otherwise returns false, nil.
|
||||
func (c *CheckpointStateCache) StateByCheckpoint(cp *ethpb.Checkpoint) (iface.BeaconState, error) {
|
||||
func (c *CheckpointStateCache) StateByCheckpoint(cp *ethpb.Checkpoint) (state.BeaconState, error) {
|
||||
c.lock.RLock()
|
||||
defer c.lock.RUnlock()
|
||||
h, err := hashutil.HashProto(cp)
|
||||
@@ -60,7 +60,7 @@ func (c *CheckpointStateCache) StateByCheckpoint(cp *ethpb.Checkpoint) (iface.Be
|
||||
if exists && item != nil {
|
||||
checkpointStateHit.Inc()
|
||||
// Copy here is unnecessary since the return will only be used to verify attestation signature.
|
||||
return item.(iface.BeaconState), nil
|
||||
return item.(state.BeaconState), nil
|
||||
}
|
||||
|
||||
checkpointStateMiss.Inc()
|
||||
@@ -69,7 +69,7 @@ func (c *CheckpointStateCache) StateByCheckpoint(cp *ethpb.Checkpoint) (iface.Be
|
||||
|
||||
// AddCheckpointState adds CheckpointState object to the cache. This method also trims the least
|
||||
// recently added CheckpointState object if the cache size has ready the max cache size limit.
|
||||
func (c *CheckpointStateCache) AddCheckpointState(cp *ethpb.Checkpoint, s iface.ReadOnlyBeaconState) error {
|
||||
func (c *CheckpointStateCache) AddCheckpointState(cp *ethpb.Checkpoint, s state.ReadOnlyBeaconState) error {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
h, err := hashutil.HashProto(cp)
|
||||
|
||||
33
beacon-chain/cache/checkpoint_state_test.go
vendored
33
beacon-chain/cache/checkpoint_state_test.go
vendored
@@ -4,10 +4,9 @@ import (
|
||||
"testing"
|
||||
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
v1 "github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
@@ -19,48 +18,48 @@ func TestCheckpointStateCache_StateByCheckpoint(t *testing.T) {
|
||||
cache := NewCheckpointStateCache()
|
||||
|
||||
cp1 := ðpb.Checkpoint{Epoch: 1, Root: bytesutil.PadTo([]byte{'A'}, 32)}
|
||||
st, err := v1.InitializeFromProto(&pb.BeaconState{
|
||||
st, err := v1.InitializeFromProto(ðpb.BeaconState{
|
||||
GenesisValidatorsRoot: params.BeaconConfig().ZeroHash[:],
|
||||
Slot: 64,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
state, err := cache.StateByCheckpoint(cp1)
|
||||
s, err := cache.StateByCheckpoint(cp1)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, iface.BeaconState(nil), state, "Expected state not to exist in empty cache")
|
||||
assert.Equal(t, state.BeaconState(nil), s, "Expected state not to exist in empty cache")
|
||||
|
||||
require.NoError(t, cache.AddCheckpointState(cp1, st))
|
||||
|
||||
state, err = cache.StateByCheckpoint(cp1)
|
||||
s, err = cache.StateByCheckpoint(cp1)
|
||||
require.NoError(t, err)
|
||||
|
||||
pbState1, err := v1.ProtobufBeaconState(state.InnerStateUnsafe())
|
||||
pbState1, err := v1.ProtobufBeaconState(s.InnerStateUnsafe())
|
||||
require.NoError(t, err)
|
||||
pbState2, err := v1.ProtobufBeaconState(st.InnerStateUnsafe())
|
||||
pbstate, err := v1.ProtobufBeaconState(st.InnerStateUnsafe())
|
||||
require.NoError(t, err)
|
||||
if !proto.Equal(pbState1, pbState2) {
|
||||
if !proto.Equal(pbState1, pbstate) {
|
||||
t.Error("incorrectly cached state")
|
||||
}
|
||||
|
||||
cp2 := ðpb.Checkpoint{Epoch: 2, Root: bytesutil.PadTo([]byte{'B'}, 32)}
|
||||
st2, err := v1.InitializeFromProto(&pb.BeaconState{
|
||||
st2, err := v1.InitializeFromProto(ðpb.BeaconState{
|
||||
Slot: 128,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, cache.AddCheckpointState(cp2, st2))
|
||||
|
||||
state, err = cache.StateByCheckpoint(cp2)
|
||||
s, err = cache.StateByCheckpoint(cp2)
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, st2.CloneInnerState(), state.CloneInnerState(), "incorrectly cached state")
|
||||
assert.DeepEqual(t, st2.CloneInnerState(), s.CloneInnerState(), "incorrectly cached state")
|
||||
|
||||
state, err = cache.StateByCheckpoint(cp1)
|
||||
s, err = cache.StateByCheckpoint(cp1)
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, st.CloneInnerState(), state.CloneInnerState(), "incorrectly cached state")
|
||||
assert.DeepEqual(t, st.CloneInnerState(), s.CloneInnerState(), "incorrectly cached state")
|
||||
}
|
||||
|
||||
func TestCheckpointStateCache_MaxSize(t *testing.T) {
|
||||
c := NewCheckpointStateCache()
|
||||
st, err := v1.InitializeFromProto(&pb.BeaconState{
|
||||
st, err := v1.InitializeFromProto(ðpb.BeaconState{
|
||||
Slot: 0,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
29
beacon-chain/cache/committee.go
vendored
29
beacon-chain/cache/committee.go
vendored
@@ -127,6 +127,35 @@ func (c *CommitteeCache) ActiveIndices(seed [32]byte) ([]types.ValidatorIndex, e
|
||||
return item.SortedIndices, nil
|
||||
}
|
||||
|
||||
// ActiveBalance returns the total active balance of a given seed stored in cache.
|
||||
func (c *CommitteeCache) ActiveBalance(seed [32]byte) (uint64, error) {
|
||||
c.lock.RLock()
|
||||
defer c.lock.RUnlock()
|
||||
obj, exists := c.CommitteeCache.Get(key(seed))
|
||||
|
||||
if exists {
|
||||
CommitteeCacheHit.Inc()
|
||||
} else {
|
||||
CommitteeCacheMiss.Inc()
|
||||
return 0, ErrNonCommitteeKey
|
||||
}
|
||||
|
||||
item, ok := obj.(*Committees)
|
||||
if !ok {
|
||||
return 0, ErrNotCommittee
|
||||
}
|
||||
if item == nil || item.ActiveBalance == nil {
|
||||
return 0, errors.New("item is nil")
|
||||
}
|
||||
|
||||
// Return `ErrNonCommitteeKey` if active balance field doesnt exist in item.
|
||||
if !item.ActiveBalance.Exist {
|
||||
return 0, ErrNonCommitteeKey
|
||||
}
|
||||
|
||||
return item.ActiveBalance.Total, nil
|
||||
}
|
||||
|
||||
// ActiveIndicesCount returns the active indices count of a given seed stored in cache.
|
||||
func (c *CommitteeCache) ActiveIndicesCount(seed [32]byte) (int, error) {
|
||||
c.lock.RLock()
|
||||
|
||||
5
beacon-chain/cache/committee_disabled.go
vendored
5
beacon-chain/cache/committee_disabled.go
vendored
@@ -41,6 +41,11 @@ func (c *FakeCommitteeCache) ActiveIndicesCount(seed [32]byte) (int, error) {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// ActiveBalance returns the active balance of a given seed stored in cache.
|
||||
func (c *FakeCommitteeCache) ActiveBalance(seed [32]byte) (uint64, error) {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// ProposerIndices returns the proposer indices of a given seed.
|
||||
func (c *FakeCommitteeCache) ProposerIndices(seed [32]byte) ([]types.ValidatorIndex, error) {
|
||||
return nil, nil
|
||||
|
||||
18
beacon-chain/cache/committee_test.go
vendored
18
beacon-chain/cache/committee_test.go
vendored
@@ -88,6 +88,24 @@ func TestCommitteeCache_ActiveCount(t *testing.T) {
|
||||
assert.Equal(t, len(item.SortedIndices), count)
|
||||
}
|
||||
|
||||
func TestCommitteeCache_ActiveBalance(t *testing.T) {
|
||||
cache := NewCommitteesCache()
|
||||
|
||||
balances := &Balance{
|
||||
Exist: true,
|
||||
Total: uint64(10000),
|
||||
}
|
||||
item := &Committees{Seed: [32]byte{'A'}, ActiveBalance: balances}
|
||||
_, err := cache.ActiveBalance(item.Seed)
|
||||
require.Equal(t, ErrNonCommitteeKey, err)
|
||||
|
||||
require.NoError(t, cache.AddCommitteeShuffledList(item))
|
||||
|
||||
got, err := cache.ActiveBalance(item.Seed)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, balances.Total, got)
|
||||
}
|
||||
|
||||
func TestCommitteeCache_CanRotate(t *testing.T) {
|
||||
cache := NewCommitteesCache()
|
||||
|
||||
|
||||
12
beacon-chain/cache/committees.go
vendored
12
beacon-chain/cache/committees.go
vendored
@@ -10,10 +10,22 @@ import (
|
||||
// a Committee struct.
|
||||
var ErrNotCommittee = errors.New("object is not a committee struct")
|
||||
|
||||
// ErrNonCommitteeKey will be returned when the committee key does not exist in cache.
|
||||
var ErrNonCommitteeKey = errors.New("committee key does not exist")
|
||||
|
||||
// Committees defines the shuffled committees seed.
|
||||
type Committees struct {
|
||||
CommitteeCount uint64
|
||||
Seed [32]byte
|
||||
ShuffledIndices []types.ValidatorIndex
|
||||
SortedIndices []types.ValidatorIndex
|
||||
ActiveBalance *Balance
|
||||
}
|
||||
|
||||
// Balance tracks active balance.
|
||||
// Given default uint64 is 0, `Exist` is used to distinguish whether
|
||||
// this field has been filed.
|
||||
type Balance struct {
|
||||
Exist bool
|
||||
Total uint64
|
||||
}
|
||||
|
||||
6
beacon-chain/cache/depositcache/BUILD.bazel
vendored
6
beacon-chain/cache/depositcache/BUILD.bazel
vendored
@@ -10,8 +10,7 @@ go_library(
|
||||
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/cache/depositcache",
|
||||
visibility = ["//beacon-chain:__subpackages__"],
|
||||
deps = [
|
||||
"//proto/beacon/db:go_default_library",
|
||||
"//proto/eth/v1alpha1:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//shared/bytesutil:go_default_library",
|
||||
"//shared/hashutil:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
@@ -32,8 +31,7 @@ go_test(
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//proto/beacon/db:go_default_library",
|
||||
"//proto/eth/v1alpha1:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//shared/bytesutil:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"//shared/testutil/assert:go_default_library",
|
||||
|
||||
@@ -15,8 +15,8 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
dbpb "github.com/prysmaticlabs/prysm/proto/beacon/db"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
||||
dbpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/trieutil"
|
||||
|
||||
@@ -7,8 +7,8 @@ import (
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
dbpb "github.com/prysmaticlabs/prysm/proto/beacon/db"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
||||
dbpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
|
||||
@@ -7,8 +7,8 @@ import (
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
dbpb "github.com/prysmaticlabs/prysm/proto/beacon/db"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
||||
dbpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/shared/hashutil"
|
||||
"github.com/sirupsen/logrus"
|
||||
"go.opencensus.io/trace"
|
||||
|
||||
@@ -5,8 +5,8 @@ import (
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
dbpb "github.com/prysmaticlabs/prysm/proto/beacon/db"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
||||
dbpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
9
beacon-chain/cache/error.go
vendored
Normal file
9
beacon-chain/cache/error.go
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
package cache
|
||||
|
||||
import "errors"
|
||||
|
||||
// Sync committee cache related errors
|
||||
|
||||
// ErrNonExistingSyncCommitteeKey when sync committee key (root) does not exist in cache.
|
||||
var ErrNonExistingSyncCommitteeKey = errors.New("does not exist sync committee key")
|
||||
var errNotSyncCommitteeIndexPosition = errors.New("not syncCommitteeIndexPosition struct")
|
||||
8
beacon-chain/cache/skip_slot_cache.go
vendored
8
beacon-chain/cache/skip_slot_cache.go
vendored
@@ -9,7 +9,7 @@ import (
|
||||
lru "github.com/hashicorp/golang-lru"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
|
||||
@@ -57,7 +57,7 @@ func (c *SkipSlotCache) Disable() {
|
||||
|
||||
// Get waits for any in progress calculation to complete before returning a
|
||||
// cached response, if any.
|
||||
func (c *SkipSlotCache) Get(ctx context.Context, r [32]byte) (iface.BeaconState, error) {
|
||||
func (c *SkipSlotCache) Get(ctx context.Context, r [32]byte) (state.BeaconState, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "skipSlotCache.Get")
|
||||
defer span.End()
|
||||
if c.disabled {
|
||||
@@ -97,7 +97,7 @@ func (c *SkipSlotCache) Get(ctx context.Context, r [32]byte) (iface.BeaconState,
|
||||
if exists && item != nil {
|
||||
skipSlotCacheHit.Inc()
|
||||
span.AddAttributes(trace.BoolAttribute("hit", true))
|
||||
return item.(iface.BeaconState).Copy(), nil
|
||||
return item.(state.BeaconState).Copy(), nil
|
||||
}
|
||||
skipSlotCacheMiss.Inc()
|
||||
span.AddAttributes(trace.BoolAttribute("hit", false))
|
||||
@@ -136,7 +136,7 @@ func (c *SkipSlotCache) MarkNotInProgress(r [32]byte) error {
|
||||
}
|
||||
|
||||
// Put the response in the cache.
|
||||
func (c *SkipSlotCache) Put(_ context.Context, r [32]byte, state iface.BeaconState) error {
|
||||
func (c *SkipSlotCache) Put(_ context.Context, r [32]byte, state state.BeaconState) error {
|
||||
if c.disabled {
|
||||
return nil
|
||||
}
|
||||
|
||||
16
beacon-chain/cache/skip_slot_cache_test.go
vendored
16
beacon-chain/cache/skip_slot_cache_test.go
vendored
@@ -5,9 +5,9 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/cache"
|
||||
iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
v1 "github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
@@ -17,21 +17,21 @@ func TestSkipSlotCache_RoundTrip(t *testing.T) {
|
||||
c := cache.NewSkipSlotCache()
|
||||
|
||||
r := [32]byte{'a'}
|
||||
state, err := c.Get(ctx, r)
|
||||
s, err := c.Get(ctx, r)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, iface.BeaconState(nil), state, "Empty cache returned an object")
|
||||
assert.Equal(t, state.BeaconState(nil), s, "Empty cache returned an object")
|
||||
|
||||
require.NoError(t, c.MarkInProgress(r))
|
||||
|
||||
state, err = v1.InitializeFromProto(&pb.BeaconState{
|
||||
s, err = v1.InitializeFromProto(ðpb.BeaconState{
|
||||
Slot: 10,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NoError(t, c.Put(ctx, r, state))
|
||||
require.NoError(t, c.Put(ctx, r, s))
|
||||
require.NoError(t, c.MarkNotInProgress(r))
|
||||
|
||||
res, err := c.Get(ctx, r)
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, res.CloneInnerState(), state.CloneInnerState(), "Expected equal protos to return from cache")
|
||||
assert.DeepEqual(t, res.CloneInnerState(), s.CloneInnerState(), "Expected equal protos to return from cache")
|
||||
}
|
||||
|
||||
187
beacon-chain/cache/sync_committee.go
vendored
Normal file
187
beacon-chain/cache/sync_committee.go
vendored
Normal file
@@ -0,0 +1,187 @@
|
||||
// +build !libfuzzer
|
||||
|
||||
package cache
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
var (
|
||||
maxSyncCommitteeSize = uint64(3) // Allows 3 forks to happen around `EPOCHS_PER_SYNC_COMMITTEE_PERIOD` boundary.
|
||||
|
||||
// SyncCommitteeCacheMiss tracks the number of committee requests that aren't present in the cache.
|
||||
SyncCommitteeCacheMiss = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "sync_committee_index_cache_miss_total",
|
||||
Help: "The number of committee requests that aren't present in the sync committee index cache.",
|
||||
})
|
||||
// SyncCommitteeCacheHit tracks the number of committee requests that are in the cache.
|
||||
SyncCommitteeCacheHit = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "sync_committee_index_cache_hit_total",
|
||||
Help: "The number of committee requests that are present in the sync committee index cache.",
|
||||
})
|
||||
)
|
||||
|
||||
// SyncCommitteeCache utilizes a FIFO cache to sufficiently cache validator position within sync committee.
|
||||
// It is thread safe with concurrent read write.
|
||||
type SyncCommitteeCache struct {
|
||||
cache *cache.FIFO
|
||||
lock sync.RWMutex
|
||||
}
|
||||
|
||||
// Index position of all validators in sync committee where `currentSyncCommitteeRoot` is the
|
||||
// key and `vIndexToPositionMap` is value. Inside `vIndexToPositionMap`, validator positions
|
||||
// are cached where key is the validator index and the value is the `positionInCommittee` struct.
|
||||
type syncCommitteeIndexPosition struct {
|
||||
currentSyncCommitteeRoot [32]byte
|
||||
vIndexToPositionMap map[types.ValidatorIndex]*positionInCommittee
|
||||
}
|
||||
|
||||
// Index position of individual validator of current period and next period sync committee.
|
||||
type positionInCommittee struct {
|
||||
currentPeriod []types.CommitteeIndex
|
||||
nextPeriod []types.CommitteeIndex
|
||||
}
|
||||
|
||||
// NewSyncCommittee initializes and returns a new SyncCommitteeCache.
|
||||
func NewSyncCommittee() *SyncCommitteeCache {
|
||||
return &SyncCommitteeCache{
|
||||
cache: cache.NewFIFO(keyFn),
|
||||
}
|
||||
}
|
||||
|
||||
// CurrentPeriodIndexPosition returns current period index position of a validator index with respect with
|
||||
// sync committee. If the input validator index has no assignment, an empty list will be returned.
|
||||
// If the input root does not exist in cache, `ErrNonExistingSyncCommitteeKey` is returned.
|
||||
// Manual checking of state for index position in state is recommended when `ErrNonExistingSyncCommitteeKey` is returned.
|
||||
func (s *SyncCommitteeCache) CurrentPeriodIndexPosition(root [32]byte, valIdx types.ValidatorIndex) ([]types.CommitteeIndex, error) {
|
||||
s.lock.RLock()
|
||||
defer s.lock.RUnlock()
|
||||
|
||||
pos, err := s.idxPositionInCommittee(root, valIdx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if pos == nil {
|
||||
return []types.CommitteeIndex{}, nil
|
||||
}
|
||||
|
||||
return pos.currentPeriod, nil
|
||||
}
|
||||
|
||||
// NextPeriodIndexPosition returns next period index position of a validator index in respect with sync committee.
|
||||
// If the input validator index has no assignment, an empty list will be returned.
|
||||
// If the input root does not exist in cache, `ErrNonExistingSyncCommitteeKey` is returned.
|
||||
// Manual checking of state for index position in state is recommended when `ErrNonExistingSyncCommitteeKey` is returned.
|
||||
func (s *SyncCommitteeCache) NextPeriodIndexPosition(root [32]byte, valIdx types.ValidatorIndex) ([]types.CommitteeIndex, error) {
|
||||
s.lock.RLock()
|
||||
defer s.lock.RUnlock()
|
||||
|
||||
pos, err := s.idxPositionInCommittee(root, valIdx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if pos == nil {
|
||||
return []types.CommitteeIndex{}, nil
|
||||
}
|
||||
return pos.nextPeriod, nil
|
||||
}
|
||||
|
||||
// Helper function for `CurrentPeriodIndexPosition` and `NextPeriodIndexPosition` to return a mapping
|
||||
// of validator index to its index(s) position in the sync committee.
|
||||
func (s *SyncCommitteeCache) idxPositionInCommittee(
|
||||
root [32]byte, valIdx types.ValidatorIndex,
|
||||
) (*positionInCommittee, error) {
|
||||
obj, exists, err := s.cache.GetByKey(key(root))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !exists {
|
||||
SyncCommitteeCacheMiss.Inc()
|
||||
return nil, ErrNonExistingSyncCommitteeKey
|
||||
}
|
||||
item, ok := obj.(*syncCommitteeIndexPosition)
|
||||
if !ok {
|
||||
return nil, errNotSyncCommitteeIndexPosition
|
||||
}
|
||||
idxInCommittee, ok := item.vIndexToPositionMap[valIdx]
|
||||
if !ok {
|
||||
SyncCommitteeCacheMiss.Inc()
|
||||
return nil, nil
|
||||
}
|
||||
SyncCommitteeCacheHit.Inc()
|
||||
return idxInCommittee, nil
|
||||
}
|
||||
|
||||
// UpdatePositionsInCommittee updates caching of validators position in sync committee in respect to
|
||||
// current epoch and next epoch. This should be called when `current_sync_committee` and `next_sync_committee`
|
||||
// change and that happens every `EPOCHS_PER_SYNC_COMMITTEE_PERIOD`.
|
||||
func (s *SyncCommitteeCache) UpdatePositionsInCommittee(syncCommitteeBoundaryRoot [32]byte, st state.BeaconStateAltair) error {
|
||||
csc, err := st.CurrentSyncCommittee()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
positionsMap := make(map[types.ValidatorIndex]*positionInCommittee)
|
||||
for i, pubkey := range csc.Pubkeys {
|
||||
p := bytesutil.ToBytes48(pubkey)
|
||||
validatorIndex, ok := st.ValidatorIndexByPubkey(p)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if _, ok := positionsMap[validatorIndex]; !ok {
|
||||
m := &positionInCommittee{currentPeriod: []types.CommitteeIndex{types.CommitteeIndex(i)}, nextPeriod: []types.CommitteeIndex{}}
|
||||
positionsMap[validatorIndex] = m
|
||||
} else {
|
||||
positionsMap[validatorIndex].currentPeriod = append(positionsMap[validatorIndex].currentPeriod, types.CommitteeIndex(i))
|
||||
}
|
||||
}
|
||||
|
||||
nsc, err := st.NextSyncCommittee()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for i, pubkey := range nsc.Pubkeys {
|
||||
p := bytesutil.ToBytes48(pubkey)
|
||||
validatorIndex, ok := st.ValidatorIndexByPubkey(p)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if _, ok := positionsMap[validatorIndex]; !ok {
|
||||
m := &positionInCommittee{nextPeriod: []types.CommitteeIndex{types.CommitteeIndex(i)}, currentPeriod: []types.CommitteeIndex{}}
|
||||
positionsMap[validatorIndex] = m
|
||||
} else {
|
||||
positionsMap[validatorIndex].nextPeriod = append(positionsMap[validatorIndex].nextPeriod, types.CommitteeIndex(i))
|
||||
}
|
||||
}
|
||||
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
if err := s.cache.Add(&syncCommitteeIndexPosition{
|
||||
currentSyncCommitteeRoot: syncCommitteeBoundaryRoot,
|
||||
vIndexToPositionMap: positionsMap,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
trim(s.cache, maxSyncCommitteeSize)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Given the `syncCommitteeIndexPosition` object, this returns the key of the object.
|
||||
// The key is the `currentSyncCommitteeRoot` within the field.
|
||||
// Error gets returned if input does not comply with `currentSyncCommitteeRoot` object.
|
||||
func keyFn(obj interface{}) (string, error) {
|
||||
info, ok := obj.(*syncCommitteeIndexPosition)
|
||||
if !ok {
|
||||
return "", errNotSyncCommitteeIndexPosition
|
||||
}
|
||||
|
||||
return string(info.currentSyncCommitteeRoot[:]), nil
|
||||
}
|
||||
32
beacon-chain/cache/sync_committee_disabled.go
vendored
Normal file
32
beacon-chain/cache/sync_committee_disabled.go
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
// +build libfuzzer
|
||||
|
||||
package cache
|
||||
|
||||
import (
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
)
|
||||
|
||||
// FakeSyncCommitteeCache is a fake `SyncCommitteeCache` to satisfy fuzzing.
|
||||
type FakeSyncCommitteeCache struct {
|
||||
}
|
||||
|
||||
// NewSyncCommittee initializes and returns a new SyncCommitteeCache.
|
||||
func NewSyncCommittee() *FakeSyncCommitteeCache {
|
||||
return &FakeSyncCommitteeCache{}
|
||||
}
|
||||
|
||||
// CurrentEpochIndexPosition -- fake.
|
||||
func (s *FakeSyncCommitteeCache) CurrentPeriodIndexPosition(root [32]byte, valIdx types.ValidatorIndex) ([]types.CommitteeIndex, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// NextEpochIndexPosition -- fake.
|
||||
func (s *FakeSyncCommitteeCache) NextPeriodIndexPosition(root [32]byte, valIdx types.ValidatorIndex) ([]types.CommitteeIndex, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// UpdatePositionsInCommittee -- fake.
|
||||
func (s *FakeSyncCommitteeCache) UpdatePositionsInCommittee(syncCommitteeBoundaryRoot [32]byte, state state.BeaconStateAltair) error {
|
||||
return nil
|
||||
}
|
||||
222
beacon-chain/cache/sync_committee_test.go
vendored
Normal file
222
beacon-chain/cache/sync_committee_test.go
vendored
Normal file
@@ -0,0 +1,222 @@
|
||||
package cache_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/cache"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
func TestSyncCommitteeCache_CanUpdateAndRetrieve(t *testing.T) {
|
||||
numValidators := 101
|
||||
deterministicState, _ := testutil.DeterministicGenesisStateAltair(t, uint64(numValidators))
|
||||
pubKeys := make([][]byte, deterministicState.NumValidators())
|
||||
for i, val := range deterministicState.Validators() {
|
||||
pubKeys[i] = val.PublicKey
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
currentSyncCommittee *ethpb.SyncCommittee
|
||||
nextSyncCommittee *ethpb.SyncCommittee
|
||||
currentSyncMap map[types.ValidatorIndex][]types.CommitteeIndex
|
||||
nextSyncMap map[types.ValidatorIndex][]types.CommitteeIndex
|
||||
}{
|
||||
{
|
||||
name: "only current epoch",
|
||||
currentSyncCommittee: convertToCommittee([][]byte{
|
||||
pubKeys[1], pubKeys[2], pubKeys[3], pubKeys[2], pubKeys[2],
|
||||
}),
|
||||
nextSyncCommittee: convertToCommittee([][]byte{}),
|
||||
currentSyncMap: map[types.ValidatorIndex][]types.CommitteeIndex{
|
||||
1: {0},
|
||||
2: {1, 3, 4},
|
||||
3: {2},
|
||||
},
|
||||
nextSyncMap: map[types.ValidatorIndex][]types.CommitteeIndex{
|
||||
1: {},
|
||||
2: {},
|
||||
3: {},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "only next epoch",
|
||||
currentSyncCommittee: convertToCommittee([][]byte{}),
|
||||
nextSyncCommittee: convertToCommittee([][]byte{
|
||||
pubKeys[1], pubKeys[2], pubKeys[3], pubKeys[2], pubKeys[2],
|
||||
}),
|
||||
currentSyncMap: map[types.ValidatorIndex][]types.CommitteeIndex{
|
||||
1: {},
|
||||
2: {},
|
||||
3: {},
|
||||
},
|
||||
nextSyncMap: map[types.ValidatorIndex][]types.CommitteeIndex{
|
||||
1: {0},
|
||||
2: {1, 3, 4},
|
||||
3: {2},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "some current epoch and some next epoch",
|
||||
currentSyncCommittee: convertToCommittee([][]byte{
|
||||
pubKeys[1],
|
||||
pubKeys[2],
|
||||
pubKeys[3],
|
||||
pubKeys[2],
|
||||
pubKeys[2],
|
||||
}),
|
||||
nextSyncCommittee: convertToCommittee([][]byte{
|
||||
pubKeys[7],
|
||||
pubKeys[6],
|
||||
pubKeys[5],
|
||||
pubKeys[4],
|
||||
pubKeys[7],
|
||||
}),
|
||||
currentSyncMap: map[types.ValidatorIndex][]types.CommitteeIndex{
|
||||
1: {0},
|
||||
2: {1, 3, 4},
|
||||
3: {2},
|
||||
},
|
||||
nextSyncMap: map[types.ValidatorIndex][]types.CommitteeIndex{
|
||||
7: {0, 4},
|
||||
6: {1},
|
||||
5: {2},
|
||||
4: {3},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "some current epoch and some next epoch duplicated across",
|
||||
currentSyncCommittee: convertToCommittee([][]byte{
|
||||
pubKeys[1],
|
||||
pubKeys[2],
|
||||
pubKeys[3],
|
||||
pubKeys[2],
|
||||
pubKeys[2],
|
||||
}),
|
||||
nextSyncCommittee: convertToCommittee([][]byte{
|
||||
pubKeys[2],
|
||||
pubKeys[1],
|
||||
pubKeys[3],
|
||||
pubKeys[2],
|
||||
pubKeys[1],
|
||||
}),
|
||||
currentSyncMap: map[types.ValidatorIndex][]types.CommitteeIndex{
|
||||
1: {0},
|
||||
2: {1, 3, 4},
|
||||
3: {2},
|
||||
},
|
||||
nextSyncMap: map[types.ValidatorIndex][]types.CommitteeIndex{
|
||||
1: {1, 4},
|
||||
2: {0, 3},
|
||||
3: {2},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "all duplicated",
|
||||
currentSyncCommittee: convertToCommittee([][]byte{
|
||||
pubKeys[100],
|
||||
pubKeys[100],
|
||||
pubKeys[100],
|
||||
pubKeys[100],
|
||||
}),
|
||||
nextSyncCommittee: convertToCommittee([][]byte{
|
||||
pubKeys[100],
|
||||
pubKeys[100],
|
||||
pubKeys[100],
|
||||
pubKeys[100],
|
||||
}),
|
||||
currentSyncMap: map[types.ValidatorIndex][]types.CommitteeIndex{
|
||||
100: {0, 1, 2, 3},
|
||||
},
|
||||
nextSyncMap: map[types.ValidatorIndex][]types.CommitteeIndex{
|
||||
100: {0, 1, 2, 3},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "unknown keys",
|
||||
currentSyncCommittee: convertToCommittee([][]byte{
|
||||
pubKeys[100],
|
||||
pubKeys[100],
|
||||
pubKeys[100],
|
||||
pubKeys[100],
|
||||
}),
|
||||
nextSyncCommittee: convertToCommittee([][]byte{
|
||||
pubKeys[100],
|
||||
pubKeys[100],
|
||||
pubKeys[100],
|
||||
pubKeys[100],
|
||||
}),
|
||||
currentSyncMap: map[types.ValidatorIndex][]types.CommitteeIndex{
|
||||
1: {},
|
||||
},
|
||||
nextSyncMap: map[types.ValidatorIndex][]types.CommitteeIndex{
|
||||
1: {},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
s, _ := testutil.DeterministicGenesisStateAltair(t, uint64(numValidators))
|
||||
require.NoError(t, s.SetCurrentSyncCommittee(tt.currentSyncCommittee))
|
||||
require.NoError(t, s.SetNextSyncCommittee(tt.nextSyncCommittee))
|
||||
cache := cache.NewSyncCommittee()
|
||||
r := [32]byte{'a'}
|
||||
require.NoError(t, cache.UpdatePositionsInCommittee(r, s))
|
||||
for key, indices := range tt.currentSyncMap {
|
||||
pos, err := cache.CurrentPeriodIndexPosition(r, key)
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, indices, pos)
|
||||
}
|
||||
for key, indices := range tt.nextSyncMap {
|
||||
pos, err := cache.NextPeriodIndexPosition(r, key)
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, indices, pos)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSyncCommitteeCache_RootDoesNotExist(t *testing.T) {
|
||||
c := cache.NewSyncCommittee()
|
||||
_, err := c.CurrentPeriodIndexPosition([32]byte{}, 0)
|
||||
require.Equal(t, cache.ErrNonExistingSyncCommitteeKey, err)
|
||||
}
|
||||
|
||||
func TestSyncCommitteeCache_CanRotate(t *testing.T) {
|
||||
c := cache.NewSyncCommittee()
|
||||
s, _ := testutil.DeterministicGenesisStateAltair(t, 64)
|
||||
require.NoError(t, s.SetCurrentSyncCommittee(convertToCommittee([][]byte{{1}})))
|
||||
require.NoError(t, c.UpdatePositionsInCommittee([32]byte{'a'}, s))
|
||||
require.NoError(t, s.SetCurrentSyncCommittee(convertToCommittee([][]byte{{2}})))
|
||||
require.NoError(t, c.UpdatePositionsInCommittee([32]byte{'b'}, s))
|
||||
require.NoError(t, s.SetCurrentSyncCommittee(convertToCommittee([][]byte{{3}})))
|
||||
require.NoError(t, c.UpdatePositionsInCommittee([32]byte{'c'}, s))
|
||||
require.NoError(t, s.SetCurrentSyncCommittee(convertToCommittee([][]byte{{4}})))
|
||||
require.NoError(t, c.UpdatePositionsInCommittee([32]byte{'d'}, s))
|
||||
|
||||
_, err := c.CurrentPeriodIndexPosition([32]byte{'a'}, 0)
|
||||
require.Equal(t, cache.ErrNonExistingSyncCommitteeKey, err)
|
||||
|
||||
_, err = c.CurrentPeriodIndexPosition([32]byte{'c'}, 0)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func convertToCommittee(inputKeys [][]byte) *ethpb.SyncCommittee {
|
||||
var pubKeys [][]byte
|
||||
for i := uint64(0); i < params.BeaconConfig().SyncCommitteeSize; i++ {
|
||||
if i < uint64(len(inputKeys)) {
|
||||
pubKeys = append(pubKeys, bytesutil.PadTo(inputKeys[i], params.BeaconConfig().BLSPubkeyLength))
|
||||
} else {
|
||||
pubKeys = append(pubKeys, bytesutil.PadTo([]byte{}, params.BeaconConfig().BLSPubkeyLength))
|
||||
}
|
||||
}
|
||||
|
||||
return ðpb.SyncCommittee{
|
||||
Pubkeys: pubKeys,
|
||||
AggregatePubkey: bytesutil.PadTo([]byte{}, params.BeaconConfig().BLSPubkeyLength),
|
||||
}
|
||||
}
|
||||
131
beacon-chain/cache/sync_subnet_ids.go
vendored
Normal file
131
beacon-chain/cache/sync_subnet_ids.go
vendored
Normal file
@@ -0,0 +1,131 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/patrickmn/go-cache"
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/rand"
|
||||
"github.com/prysmaticlabs/prysm/shared/sliceutil"
|
||||
)
|
||||
|
||||
type syncSubnetIDs struct {
|
||||
sCommittee *cache.Cache
|
||||
sCommiteeLock sync.RWMutex
|
||||
}
|
||||
|
||||
// SyncSubnetIDs for sync committee participant.
|
||||
var SyncSubnetIDs = newSyncSubnetIDs()
|
||||
|
||||
func newSyncSubnetIDs() *syncSubnetIDs {
|
||||
epochDuration := time.Duration(params.BeaconConfig().SlotsPerEpoch.Mul(params.BeaconConfig().SecondsPerSlot))
|
||||
// Set the default duration of a sync subnet index as the whole sync committee period.
|
||||
subLength := epochDuration * time.Duration(params.BeaconConfig().EpochsPerSyncCommitteePeriod)
|
||||
persistentCache := cache.New(subLength*time.Second, epochDuration*time.Second)
|
||||
return &syncSubnetIDs{sCommittee: persistentCache}
|
||||
}
|
||||
|
||||
// GetSyncCommitteeSubnets retrieves the sync committee subnet and expiration time of that validator's subscription.
|
||||
func (s *syncSubnetIDs) GetSyncCommitteeSubnets(pubkey []byte, epoch types.Epoch) ([]uint64, types.Epoch, bool, time.Time) {
|
||||
s.sCommiteeLock.RLock()
|
||||
defer s.sCommiteeLock.RUnlock()
|
||||
|
||||
id, duration, ok := s.sCommittee.GetWithExpiration(keyBuilder(pubkey, epoch))
|
||||
if !ok {
|
||||
return []uint64{}, 0, ok, time.Time{}
|
||||
}
|
||||
// Retrieve indices from the cache.
|
||||
idxs, ok := id.([]uint64)
|
||||
if !ok {
|
||||
return []uint64{}, 0, ok, time.Time{}
|
||||
}
|
||||
// If no committees are saved, we return nothing.
|
||||
if len(idxs) <= 1 {
|
||||
return []uint64{}, 0, ok, time.Time{}
|
||||
}
|
||||
|
||||
// Index 0 was used to store validator's join epoch. We do not
|
||||
// return it to the caller.
|
||||
// Index 1 and beyond were used to store subnets.
|
||||
return idxs[1:], types.Epoch(idxs[0]), ok, duration
|
||||
}
|
||||
|
||||
// GetAllSubnets retrieves all the non-expired subscribed subnets of all the validators
|
||||
// in the cache. This method also takes the epoch as an argument to only retrieve
|
||||
// assignments for epochs that have happened.
|
||||
func (s *syncSubnetIDs) GetAllSubnets(currEpoch types.Epoch) []uint64 {
|
||||
s.sCommiteeLock.RLock()
|
||||
defer s.sCommiteeLock.RUnlock()
|
||||
|
||||
itemsMap := s.sCommittee.Items()
|
||||
var committees []uint64
|
||||
|
||||
for _, v := range itemsMap {
|
||||
if v.Expired() {
|
||||
continue
|
||||
}
|
||||
idxs, ok := v.Object.([]uint64)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
// We skip if we do not have a join
|
||||
// epoch or any relevant committee indices.
|
||||
if len(idxs) <= 1 {
|
||||
continue
|
||||
}
|
||||
// Check if the subnet is valid in the current epoch. If our
|
||||
// join epoch is still in the future we skip retrieving the
|
||||
// relevant committee index.
|
||||
if types.Epoch(idxs[0]) > currEpoch {
|
||||
continue
|
||||
}
|
||||
// Ignore the first index as that represents the
|
||||
// epoch of the validator's assignments.
|
||||
committees = append(committees, idxs[1:]...)
|
||||
}
|
||||
return sliceutil.SetUint64(committees)
|
||||
}
|
||||
|
||||
// AddSyncCommitteeSubnets adds the relevant committee for that particular validator along with its
|
||||
// expiration period. An Epoch argument here denotes the epoch from which the sync committee subnets
|
||||
// will be active.
|
||||
func (s *syncSubnetIDs) AddSyncCommitteeSubnets(pubkey []byte, epoch types.Epoch, comIndex []uint64, duration time.Duration) {
|
||||
s.sCommiteeLock.Lock()
|
||||
defer s.sCommiteeLock.Unlock()
|
||||
subComCount := params.BeaconConfig().SyncCommitteeSubnetCount
|
||||
// To join a sync committee subnet, select a random number of epochs before the end of the
|
||||
// current sync committee period between 1 and SYNC_COMMITTEE_SUBNET_COUNT, inclusive.
|
||||
// This is to smoothing out the join and exiting of the subnets so not everyone surging at the same time.
|
||||
diff := (rand.NewGenerator().Uint64() % subComCount) + 1
|
||||
joinEpoch, err := epoch.SafeSub(diff)
|
||||
if err != nil {
|
||||
// If we underflow here, we simply set the value to join
|
||||
// at 0.
|
||||
joinEpoch = 0
|
||||
}
|
||||
// Append the epoch of the subnet into the first index here. The join epoch is a special
|
||||
// value, it is the epoch at which a node is supposed to join the relevant subnets.
|
||||
s.sCommittee.Set(keyBuilder(pubkey, epoch), append([]uint64{uint64(joinEpoch)}, comIndex...), duration)
|
||||
}
|
||||
|
||||
// EmptyAllCaches empties out all the related caches and flushes any stored
|
||||
// entries on them. This should only ever be used for testing, in normal
|
||||
// production, handling of the relevant subnets for each role is done
|
||||
// separately.
|
||||
func (s *syncSubnetIDs) EmptyAllCaches() {
|
||||
// Clear the cache.
|
||||
|
||||
s.sCommiteeLock.Lock()
|
||||
s.sCommittee.Flush()
|
||||
s.sCommiteeLock.Unlock()
|
||||
}
|
||||
|
||||
// build a key composed of both the pubkey and epoch here. The epoch
|
||||
// here would be the 1st epoch of the sync committee period.
|
||||
func keyBuilder(pubkey []byte, epoch types.Epoch) string {
|
||||
epochBytes := bytesutil.Bytes8(uint64(epoch))
|
||||
return string(append(pubkey, epochBytes...))
|
||||
}
|
||||
57
beacon-chain/cache/sync_subnet_ids_test.go
vendored
Normal file
57
beacon-chain/cache/sync_subnet_ids_test.go
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
func TestSyncSubnetIDsCache_Roundtrip(t *testing.T) {
|
||||
c := newSyncSubnetIDs()
|
||||
|
||||
for i := 0; i < 20; i++ {
|
||||
pubkey := [48]byte{byte(i)}
|
||||
c.AddSyncCommitteeSubnets(pubkey[:], 100, []uint64{uint64(i)}, 0)
|
||||
}
|
||||
|
||||
for i := uint64(0); i < 20; i++ {
|
||||
pubkey := [48]byte{byte(i)}
|
||||
|
||||
idxs, _, ok, _ := c.GetSyncCommitteeSubnets(pubkey[:], 100)
|
||||
if !ok {
|
||||
t.Errorf("Couldn't find entry in cache for pubkey %#x", pubkey)
|
||||
continue
|
||||
}
|
||||
require.Equal(t, i, idxs[0])
|
||||
}
|
||||
coms := c.GetAllSubnets(100)
|
||||
assert.Equal(t, 20, len(coms))
|
||||
}
|
||||
|
||||
func TestSyncSubnetIDsCache_ValidateCurrentEpoch(t *testing.T) {
|
||||
c := newSyncSubnetIDs()
|
||||
|
||||
for i := 0; i < 20; i++ {
|
||||
pubkey := [48]byte{byte(i)}
|
||||
c.AddSyncCommitteeSubnets(pubkey[:], 100, []uint64{uint64(i)}, 0)
|
||||
}
|
||||
|
||||
coms := c.GetAllSubnets(50)
|
||||
assert.Equal(t, 0, len(coms))
|
||||
|
||||
for i := uint64(0); i < 20; i++ {
|
||||
pubkey := [48]byte{byte(i)}
|
||||
|
||||
_, jEpoch, ok, _ := c.GetSyncCommitteeSubnets(pubkey[:], 100)
|
||||
if !ok {
|
||||
t.Errorf("Couldn't find entry in cache for pubkey %#x", pubkey)
|
||||
continue
|
||||
}
|
||||
require.Equal(t, true, uint64(jEpoch) >= 100-params.BeaconConfig().SyncCommitteeSubnetCount)
|
||||
}
|
||||
|
||||
coms = c.GetAllSubnets(99)
|
||||
assert.Equal(t, 20, len(coms))
|
||||
}
|
||||
86
beacon-chain/core/altair/BUILD.bazel
Normal file
86
beacon-chain/core/altair/BUILD.bazel
Normal file
@@ -0,0 +1,86 @@
|
||||
load("@prysm//tools/go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"attestation.go",
|
||||
"block.go",
|
||||
"deposit.go",
|
||||
"epoch_precompute.go",
|
||||
"epoch_spec.go",
|
||||
"reward.go",
|
||||
"sync_committee.go",
|
||||
"transition.go",
|
||||
"upgrade.go",
|
||||
"validator.go",
|
||||
],
|
||||
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/core/altair",
|
||||
visibility = [
|
||||
"//beacon-chain:__subpackages__",
|
||||
"//shared/testutil:__pkg__",
|
||||
"//spectest:__subpackages__",
|
||||
"//validator/client:__pkg__",
|
||||
],
|
||||
deps = [
|
||||
"//beacon-chain/core/blocks:go_default_library",
|
||||
"//beacon-chain/core/epoch:go_default_library",
|
||||
"//beacon-chain/core/epoch/precompute:go_default_library",
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//beacon-chain/core/validators:go_default_library",
|
||||
"//beacon-chain/p2p/types:go_default_library",
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//beacon-chain/state/v2:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//proto/prysm/v1alpha1/block:go_default_library",
|
||||
"//shared/attestationutil:go_default_library",
|
||||
"//shared/bls:go_default_library",
|
||||
"//shared/bytesutil:go_default_library",
|
||||
"//shared/hashutil:go_default_library",
|
||||
"//shared/mathutil:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@com_github_prysmaticlabs_eth2_types//:go_default_library",
|
||||
"@io_opencensus_go//trace:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"attestation_test.go",
|
||||
"block_test.go",
|
||||
"deposit_fuzz_test.go",
|
||||
"deposit_test.go",
|
||||
"epoch_precompute_test.go",
|
||||
"epoch_spec_test.go",
|
||||
"reward_test.go",
|
||||
"sync_committee_test.go",
|
||||
"transition_test.go",
|
||||
"upgrade_test.go",
|
||||
"validator_test.go",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//beacon-chain/core/epoch/precompute:go_default_library",
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//beacon-chain/p2p/types:go_default_library",
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//beacon-chain/state/v2:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//proto/prysm/v1alpha1/wrapper:go_default_library",
|
||||
"//shared/attestationutil:go_default_library",
|
||||
"//shared/bls:go_default_library",
|
||||
"//shared/bytesutil:go_default_library",
|
||||
"//shared/mathutil: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",
|
||||
"//shared/timeutils:go_default_library",
|
||||
"//shared/trieutil:go_default_library",
|
||||
"@com_github_google_gofuzz//:go_default_library",
|
||||
"@com_github_prysmaticlabs_eth2_types//:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
|
||||
"@org_golang_google_protobuf//proto:go_default_library",
|
||||
],
|
||||
)
|
||||
299
beacon-chain/core/altair/attestation.go
Normal file
299
beacon-chain/core/altair/attestation.go
Normal file
@@ -0,0 +1,299 @@
|
||||
package altair
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/block"
|
||||
"github.com/prysmaticlabs/prysm/shared/attestationutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
|
||||
// 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 ProcessAttestationsNoVerifySignature(
|
||||
ctx context.Context,
|
||||
beaconState state.BeaconState,
|
||||
b block.SignedBeaconBlock,
|
||||
) (state.BeaconState, error) {
|
||||
if err := helpers.VerifyNilBeaconBlock(b); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
body := b.Block().Body()
|
||||
var err error
|
||||
for idx, attestation := range body.Attestations() {
|
||||
beaconState, err = ProcessAttestationNoVerifySignature(ctx, beaconState, attestation)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not verify attestation at index %d in block", idx)
|
||||
}
|
||||
}
|
||||
return beaconState, nil
|
||||
}
|
||||
|
||||
// ProcessAttestationNoVerifySignature processes the attestation without verifying the attestation signature. This
|
||||
// method is used to validate attestations whose signatures have already been verified or will be verified later.
|
||||
func ProcessAttestationNoVerifySignature(
|
||||
ctx context.Context,
|
||||
beaconState state.BeaconStateAltair,
|
||||
att *ethpb.Attestation,
|
||||
) (state.BeaconStateAltair, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "altair.ProcessAttestationNoVerifySignature")
|
||||
defer span.End()
|
||||
|
||||
if err := blocks.VerifyAttestationNoVerifySignature(ctx, beaconState, att); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
delay, err := beaconState.Slot().SafeSubSlot(att.Data.Slot)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("att slot %d can't be greater than state slot %d", att.Data.Slot, beaconState.Slot())
|
||||
}
|
||||
participatedFlags, err := AttestationParticipationFlagIndices(beaconState, att.Data, delay)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
committee, err := helpers.BeaconCommitteeFromState(beaconState, att.Data.Slot, att.Data.CommitteeIndex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
indices, err := attestationutil.AttestingIndices(att.AggregationBits, committee)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return SetParticipationAndRewardProposer(beaconState, att.Data.Target.Epoch, indices, participatedFlags)
|
||||
}
|
||||
|
||||
// SetParticipationAndRewardProposer retrieves and sets the epoch participation bits in state. Based on the epoch participation, it rewards
|
||||
// the proposer in state.
|
||||
//
|
||||
// Spec code:
|
||||
// # Update epoch participation flags
|
||||
// if data.target.epoch == get_current_epoch(state):
|
||||
// epoch_participation = state.current_epoch_participation
|
||||
// else:
|
||||
// epoch_participation = state.previous_epoch_participation
|
||||
//
|
||||
// proposer_reward_numerator = 0
|
||||
// for index in get_attesting_indices(state, data, attestation.aggregation_bits):
|
||||
// for flag_index, weight in enumerate(PARTICIPATION_FLAG_WEIGHTS):
|
||||
// if flag_index in participation_flag_indices and not has_flag(epoch_participation[index], flag_index):
|
||||
// epoch_participation[index] = add_flag(epoch_participation[index], flag_index)
|
||||
// proposer_reward_numerator += get_base_reward(state, index) * weight
|
||||
//
|
||||
// # Reward proposer
|
||||
// proposer_reward_denominator = (WEIGHT_DENOMINATOR - PROPOSER_WEIGHT) * WEIGHT_DENOMINATOR // PROPOSER_WEIGHT
|
||||
// proposer_reward = Gwei(proposer_reward_numerator // proposer_reward_denominator)
|
||||
// increase_balance(state, get_beacon_proposer_index(state), proposer_reward)
|
||||
func SetParticipationAndRewardProposer(
|
||||
beaconState state.BeaconState,
|
||||
targetEpoch types.Epoch,
|
||||
indices []uint64,
|
||||
participatedFlags map[uint8]bool) (state.BeaconState, error) {
|
||||
var epochParticipation []byte
|
||||
currentEpoch := helpers.CurrentEpoch(beaconState)
|
||||
var err error
|
||||
if targetEpoch == currentEpoch {
|
||||
epochParticipation, err = beaconState.CurrentEpochParticipation()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
epochParticipation, err = beaconState.PreviousEpochParticipation()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
proposerRewardNumerator, epochParticipation, err := EpochParticipation(beaconState, indices, epochParticipation, participatedFlags)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if targetEpoch == currentEpoch {
|
||||
if err := beaconState.SetCurrentParticipationBits(epochParticipation); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
if err := beaconState.SetPreviousParticipationBits(epochParticipation); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if err := RewardProposer(beaconState, proposerRewardNumerator); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return beaconState, nil
|
||||
}
|
||||
|
||||
// HasValidatorFlag returns true if the flag at position has set.
|
||||
func HasValidatorFlag(flag, flagPosition uint8) bool {
|
||||
return ((flag >> flagPosition) & 1) == 1
|
||||
}
|
||||
|
||||
// AddValidatorFlag adds new validator flag to existing one.
|
||||
func AddValidatorFlag(flag, flagPosition uint8) uint8 {
|
||||
return flag | (1 << flagPosition)
|
||||
}
|
||||
|
||||
// EpochParticipation sets and returns the proposer reward numerator and epoch participation.
|
||||
//
|
||||
// Spec code:
|
||||
// proposer_reward_numerator = 0
|
||||
// for index in get_attesting_indices(state, data, attestation.aggregation_bits):
|
||||
// for flag_index, weight in enumerate(PARTICIPATION_FLAG_WEIGHTS):
|
||||
// if flag_index in participation_flag_indices and not has_flag(epoch_participation[index], flag_index):
|
||||
// epoch_participation[index] = add_flag(epoch_participation[index], flag_index)
|
||||
// proposer_reward_numerator += get_base_reward(state, index) * weight
|
||||
func EpochParticipation(beaconState state.BeaconState, indices []uint64, epochParticipation []byte, participatedFlags map[uint8]bool) (uint64, []byte, error) {
|
||||
cfg := params.BeaconConfig()
|
||||
sourceFlagIndex := cfg.TimelySourceFlagIndex
|
||||
targetFlagIndex := cfg.TimelyTargetFlagIndex
|
||||
headFlagIndex := cfg.TimelyHeadFlagIndex
|
||||
proposerRewardNumerator := uint64(0)
|
||||
totalBalance, err := helpers.TotalActiveBalance(beaconState)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
for _, index := range indices {
|
||||
if index >= uint64(len(epochParticipation)) {
|
||||
return 0, nil, fmt.Errorf("index %d exceeds participation length %d", index, len(epochParticipation))
|
||||
}
|
||||
br, err := BaseRewardWithTotalBalance(beaconState, types.ValidatorIndex(index), totalBalance)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
if participatedFlags[sourceFlagIndex] && !HasValidatorFlag(epochParticipation[index], sourceFlagIndex) {
|
||||
epochParticipation[index] = AddValidatorFlag(epochParticipation[index], sourceFlagIndex)
|
||||
proposerRewardNumerator += br * cfg.TimelySourceWeight
|
||||
}
|
||||
if participatedFlags[targetFlagIndex] && !HasValidatorFlag(epochParticipation[index], targetFlagIndex) {
|
||||
epochParticipation[index] = AddValidatorFlag(epochParticipation[index], targetFlagIndex)
|
||||
proposerRewardNumerator += br * cfg.TimelyTargetWeight
|
||||
}
|
||||
if participatedFlags[headFlagIndex] && !HasValidatorFlag(epochParticipation[index], headFlagIndex) {
|
||||
epochParticipation[index] = AddValidatorFlag(epochParticipation[index], headFlagIndex)
|
||||
proposerRewardNumerator += br * cfg.TimelyHeadWeight
|
||||
}
|
||||
}
|
||||
|
||||
return proposerRewardNumerator, epochParticipation, nil
|
||||
}
|
||||
|
||||
// RewardProposer rewards proposer by increasing proposer's balance with input reward numerator and calculated reward denominator.
|
||||
//
|
||||
// Spec code:
|
||||
// proposer_reward_denominator = (WEIGHT_DENOMINATOR - PROPOSER_WEIGHT) * WEIGHT_DENOMINATOR // PROPOSER_WEIGHT
|
||||
// proposer_reward = Gwei(proposer_reward_numerator // proposer_reward_denominator)
|
||||
// increase_balance(state, get_beacon_proposer_index(state), proposer_reward)
|
||||
func RewardProposer(beaconState state.BeaconState, proposerRewardNumerator uint64) error {
|
||||
cfg := params.BeaconConfig()
|
||||
d := (cfg.WeightDenominator - cfg.ProposerWeight) * cfg.WeightDenominator / cfg.ProposerWeight
|
||||
proposerReward := proposerRewardNumerator / d
|
||||
i, err := helpers.BeaconProposerIndex(beaconState)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return helpers.IncreaseBalance(beaconState, i, proposerReward)
|
||||
}
|
||||
|
||||
// AttestationParticipationFlagIndices retrieves a map of attestation scoring based on Altair's participation flag indices.
|
||||
// This is used to facilitate process attestation during state transition and during upgrade to altair state.
|
||||
//
|
||||
// Spec code:
|
||||
// def get_attestation_participation_flag_indices(state: BeaconState,
|
||||
// data: AttestationData,
|
||||
// inclusion_delay: uint64) -> Sequence[int]:
|
||||
// """
|
||||
// Return the flag indices that are satisfied by an attestation.
|
||||
// """
|
||||
// if data.target.epoch == get_current_epoch(state):
|
||||
// justified_checkpoint = state.current_justified_checkpoint
|
||||
// else:
|
||||
// justified_checkpoint = state.previous_justified_checkpoint
|
||||
//
|
||||
// # Matching roots
|
||||
// is_matching_source = data.source == justified_checkpoint
|
||||
// is_matching_target = is_matching_source and data.target.root == get_block_root(state, data.target.epoch)
|
||||
// is_matching_head = is_matching_target and data.beacon_block_root == get_block_root_at_slot(state, data.slot)
|
||||
// assert is_matching_source
|
||||
//
|
||||
// participation_flag_indices = []
|
||||
// if is_matching_source and inclusion_delay <= integer_squareroot(SLOTS_PER_EPOCH):
|
||||
// participation_flag_indices.append(TIMELY_SOURCE_FLAG_INDEX)
|
||||
// if is_matching_target and inclusion_delay <= SLOTS_PER_EPOCH:
|
||||
// participation_flag_indices.append(TIMELY_TARGET_FLAG_INDEX)
|
||||
// if is_matching_head and inclusion_delay == MIN_ATTESTATION_INCLUSION_DELAY:
|
||||
// participation_flag_indices.append(TIMELY_HEAD_FLAG_INDEX)
|
||||
//
|
||||
// return participation_flag_indices
|
||||
func AttestationParticipationFlagIndices(beaconState state.BeaconStateAltair, data *ethpb.AttestationData, delay types.Slot) (map[uint8]bool, error) {
|
||||
currEpoch := helpers.CurrentEpoch(beaconState)
|
||||
var justifiedCheckpt *ethpb.Checkpoint
|
||||
if data.Target.Epoch == currEpoch {
|
||||
justifiedCheckpt = beaconState.CurrentJustifiedCheckpoint()
|
||||
} else {
|
||||
justifiedCheckpt = beaconState.PreviousJustifiedCheckpoint()
|
||||
}
|
||||
|
||||
matchedSrc, matchedTgt, matchedHead, err := MatchingStatus(beaconState, data, justifiedCheckpt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !matchedSrc {
|
||||
return nil, errors.New("source epoch does not match")
|
||||
}
|
||||
|
||||
participatedFlags := make(map[uint8]bool)
|
||||
cfg := params.BeaconConfig()
|
||||
sourceFlagIndex := cfg.TimelySourceFlagIndex
|
||||
targetFlagIndex := cfg.TimelyTargetFlagIndex
|
||||
headFlagIndex := cfg.TimelyHeadFlagIndex
|
||||
slotsPerEpoch := cfg.SlotsPerEpoch
|
||||
sqtRootSlots := cfg.SqrRootSlotsPerEpoch
|
||||
if matchedSrc && delay <= sqtRootSlots {
|
||||
participatedFlags[sourceFlagIndex] = true
|
||||
}
|
||||
matchedSrcTgt := matchedSrc && matchedTgt
|
||||
if matchedSrcTgt && delay <= slotsPerEpoch {
|
||||
participatedFlags[targetFlagIndex] = true
|
||||
}
|
||||
matchedSrcTgtHead := matchedHead && matchedSrcTgt
|
||||
if matchedSrcTgtHead && delay == cfg.MinAttestationInclusionDelay {
|
||||
participatedFlags[headFlagIndex] = true
|
||||
}
|
||||
return participatedFlags, nil
|
||||
}
|
||||
|
||||
// MatchingStatus returns the matching statues for attestation data's source target and head.
|
||||
//
|
||||
// Spec code:
|
||||
// is_matching_source = data.source == justified_checkpoint
|
||||
// is_matching_target = is_matching_source and data.target.root == get_block_root(state, data.target.epoch)
|
||||
// is_matching_head = is_matching_target and data.beacon_block_root == get_block_root_at_slot(state, data.slot)
|
||||
func MatchingStatus(beaconState state.BeaconState, data *ethpb.AttestationData, cp *ethpb.Checkpoint) (matchedSrc bool, matchedTgt bool, matchedHead bool, err error) {
|
||||
matchedSrc = attestationutil.CheckPointIsEqual(data.Source, cp)
|
||||
|
||||
r, err := helpers.BlockRoot(beaconState, data.Target.Epoch)
|
||||
if err != nil {
|
||||
return false, false, false, err
|
||||
}
|
||||
matchedTgt = bytes.Equal(r, data.Target.Root)
|
||||
|
||||
r, err = helpers.BlockRootAtSlot(beaconState, data.Slot)
|
||||
if err != nil {
|
||||
return false, false, false, err
|
||||
}
|
||||
matchedHead = bytes.Equal(r, data.BeaconBlockRoot)
|
||||
return
|
||||
}
|
||||
746
beacon-chain/core/altair/attestation_test.go
Normal file
746
beacon-chain/core/altair/attestation_test.go
Normal file
@@ -0,0 +1,746 @@
|
||||
package altair_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
fuzz "github.com/google/gofuzz"
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/go-bitfield"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/altair"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
stateAltair "github.com/prysmaticlabs/prysm/beacon-chain/state/v2"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/wrapper"
|
||||
"github.com/prysmaticlabs/prysm/shared/attestationutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/mathutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
func TestProcessAttestations_InclusionDelayFailure(t *testing.T) {
|
||||
attestations := []*ethpb.Attestation{
|
||||
testutil.HydrateAttestation(ðpb.Attestation{
|
||||
Data: ðpb.AttestationData{
|
||||
Target: ðpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
|
||||
Slot: 5,
|
||||
},
|
||||
}),
|
||||
}
|
||||
b := testutil.NewBeaconBlockAltair()
|
||||
b.Block = ðpb.BeaconBlockAltair{
|
||||
Body: ðpb.BeaconBlockBodyAltair{
|
||||
Attestations: attestations,
|
||||
},
|
||||
}
|
||||
beaconState, _ := testutil.DeterministicGenesisStateAltair(t, 100)
|
||||
|
||||
want := fmt.Sprintf(
|
||||
"attestation slot %d + inclusion delay %d > state slot %d",
|
||||
attestations[0].Data.Slot,
|
||||
params.BeaconConfig().MinAttestationInclusionDelay,
|
||||
beaconState.Slot(),
|
||||
)
|
||||
wsb, err := wrapper.WrappedAltairSignedBeaconBlock(b)
|
||||
require.NoError(t, err)
|
||||
_, err = altair.ProcessAttestationsNoVerifySignature(context.Background(), beaconState, wsb)
|
||||
require.ErrorContains(t, want, err)
|
||||
}
|
||||
|
||||
func TestProcessAttestations_NeitherCurrentNorPrevEpoch(t *testing.T) {
|
||||
att := testutil.HydrateAttestation(ðpb.Attestation{
|
||||
Data: ðpb.AttestationData{
|
||||
Source: ðpb.Checkpoint{Epoch: 0, Root: []byte("hello-world")},
|
||||
Target: ðpb.Checkpoint{Epoch: 0}}})
|
||||
|
||||
b := testutil.NewBeaconBlockAltair()
|
||||
b.Block = ðpb.BeaconBlockAltair{
|
||||
Body: ðpb.BeaconBlockBodyAltair{
|
||||
Attestations: []*ethpb.Attestation{att},
|
||||
},
|
||||
}
|
||||
beaconState, _ := testutil.DeterministicGenesisStateAltair(t, 100)
|
||||
err := beaconState.SetSlot(beaconState.Slot() + params.BeaconConfig().SlotsPerEpoch*4 + params.BeaconConfig().MinAttestationInclusionDelay)
|
||||
require.NoError(t, err)
|
||||
pfc := beaconState.PreviousJustifiedCheckpoint()
|
||||
pfc.Root = []byte("hello-world")
|
||||
require.NoError(t, beaconState.SetPreviousJustifiedCheckpoint(pfc))
|
||||
|
||||
want := fmt.Sprintf(
|
||||
"expected target epoch (%d) to be the previous epoch (%d) or the current epoch (%d)",
|
||||
att.Data.Target.Epoch,
|
||||
helpers.PrevEpoch(beaconState),
|
||||
helpers.CurrentEpoch(beaconState),
|
||||
)
|
||||
wsb, err := wrapper.WrappedAltairSignedBeaconBlock(b)
|
||||
require.NoError(t, err)
|
||||
_, err = altair.ProcessAttestationsNoVerifySignature(context.Background(), beaconState, wsb)
|
||||
require.ErrorContains(t, want, err)
|
||||
}
|
||||
|
||||
func TestProcessAttestations_CurrentEpochFFGDataMismatches(t *testing.T) {
|
||||
attestations := []*ethpb.Attestation{
|
||||
{
|
||||
Data: ðpb.AttestationData{
|
||||
Target: ðpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
|
||||
Source: ðpb.Checkpoint{Epoch: 1, Root: make([]byte, 32)},
|
||||
},
|
||||
AggregationBits: bitfield.Bitlist{0x09},
|
||||
},
|
||||
}
|
||||
b := testutil.NewBeaconBlockAltair()
|
||||
b.Block = ðpb.BeaconBlockAltair{
|
||||
Body: ðpb.BeaconBlockBodyAltair{
|
||||
Attestations: attestations,
|
||||
},
|
||||
}
|
||||
beaconState, _ := testutil.DeterministicGenesisStateAltair(t, 100)
|
||||
require.NoError(t, beaconState.SetSlot(beaconState.Slot()+params.BeaconConfig().MinAttestationInclusionDelay))
|
||||
cfc := beaconState.CurrentJustifiedCheckpoint()
|
||||
cfc.Root = []byte("hello-world")
|
||||
require.NoError(t, beaconState.SetCurrentJustifiedCheckpoint(cfc))
|
||||
|
||||
want := "source check point not equal to current justified checkpoint"
|
||||
wsb, err := wrapper.WrappedAltairSignedBeaconBlock(b)
|
||||
require.NoError(t, err)
|
||||
_, err = altair.ProcessAttestationsNoVerifySignature(context.Background(), beaconState, wsb)
|
||||
require.ErrorContains(t, want, err)
|
||||
b.Block.Body.Attestations[0].Data.Source.Epoch = helpers.CurrentEpoch(beaconState)
|
||||
b.Block.Body.Attestations[0].Data.Source.Root = []byte{}
|
||||
wsb, err = wrapper.WrappedAltairSignedBeaconBlock(b)
|
||||
require.NoError(t, err)
|
||||
_, err = altair.ProcessAttestationsNoVerifySignature(context.Background(), beaconState, wsb)
|
||||
require.ErrorContains(t, want, err)
|
||||
}
|
||||
|
||||
func TestProcessAttestations_PrevEpochFFGDataMismatches(t *testing.T) {
|
||||
beaconState, _ := testutil.DeterministicGenesisStateAltair(t, 100)
|
||||
|
||||
aggBits := bitfield.NewBitlist(3)
|
||||
aggBits.SetBitAt(0, true)
|
||||
attestations := []*ethpb.Attestation{
|
||||
{
|
||||
Data: ðpb.AttestationData{
|
||||
Source: ðpb.Checkpoint{Epoch: 1, Root: make([]byte, 32)},
|
||||
Target: ðpb.Checkpoint{Epoch: 1, Root: make([]byte, 32)},
|
||||
Slot: params.BeaconConfig().SlotsPerEpoch,
|
||||
},
|
||||
AggregationBits: aggBits,
|
||||
},
|
||||
}
|
||||
b := testutil.NewBeaconBlockAltair()
|
||||
b.Block = ðpb.BeaconBlockAltair{
|
||||
Body: ðpb.BeaconBlockBodyAltair{
|
||||
Attestations: attestations,
|
||||
},
|
||||
}
|
||||
|
||||
err := beaconState.SetSlot(beaconState.Slot() + 2*params.BeaconConfig().SlotsPerEpoch)
|
||||
require.NoError(t, err)
|
||||
pfc := beaconState.PreviousJustifiedCheckpoint()
|
||||
pfc.Root = []byte("hello-world")
|
||||
require.NoError(t, beaconState.SetPreviousJustifiedCheckpoint(pfc))
|
||||
|
||||
want := "source check point not equal to previous justified checkpoint"
|
||||
wsb, err := wrapper.WrappedAltairSignedBeaconBlock(b)
|
||||
require.NoError(t, err)
|
||||
_, err = altair.ProcessAttestationsNoVerifySignature(context.Background(), beaconState, wsb)
|
||||
require.ErrorContains(t, want, err)
|
||||
b.Block.Body.Attestations[0].Data.Source.Epoch = helpers.PrevEpoch(beaconState)
|
||||
b.Block.Body.Attestations[0].Data.Target.Epoch = helpers.PrevEpoch(beaconState)
|
||||
b.Block.Body.Attestations[0].Data.Source.Root = []byte{}
|
||||
wsb, err = wrapper.WrappedAltairSignedBeaconBlock(b)
|
||||
require.NoError(t, err)
|
||||
_, err = altair.ProcessAttestationsNoVerifySignature(context.Background(), beaconState, wsb)
|
||||
require.ErrorContains(t, want, err)
|
||||
}
|
||||
|
||||
func TestProcessAttestations_InvalidAggregationBitsLength(t *testing.T) {
|
||||
beaconState, _ := testutil.DeterministicGenesisStateAltair(t, 100)
|
||||
|
||||
aggBits := bitfield.NewBitlist(4)
|
||||
att := ðpb.Attestation{
|
||||
Data: ðpb.AttestationData{
|
||||
Source: ðpb.Checkpoint{Epoch: 0, Root: []byte("hello-world")},
|
||||
Target: ðpb.Checkpoint{Epoch: 0}},
|
||||
AggregationBits: aggBits,
|
||||
}
|
||||
|
||||
b := testutil.NewBeaconBlockAltair()
|
||||
b.Block = ðpb.BeaconBlockAltair{
|
||||
Body: ðpb.BeaconBlockBodyAltair{
|
||||
Attestations: []*ethpb.Attestation{att},
|
||||
},
|
||||
}
|
||||
|
||||
err := beaconState.SetSlot(beaconState.Slot() + params.BeaconConfig().MinAttestationInclusionDelay)
|
||||
require.NoError(t, err)
|
||||
|
||||
cfc := beaconState.CurrentJustifiedCheckpoint()
|
||||
cfc.Root = []byte("hello-world")
|
||||
require.NoError(t, beaconState.SetCurrentJustifiedCheckpoint(cfc))
|
||||
|
||||
expected := "failed to verify aggregation bitfield: wanted participants bitfield length 3, got: 4"
|
||||
wsb, err := wrapper.WrappedAltairSignedBeaconBlock(b)
|
||||
require.NoError(t, err)
|
||||
_, err = altair.ProcessAttestationsNoVerifySignature(context.Background(), beaconState, wsb)
|
||||
require.ErrorContains(t, expected, err)
|
||||
}
|
||||
|
||||
func TestProcessAttestations_OK(t *testing.T) {
|
||||
beaconState, privKeys := testutil.DeterministicGenesisStateAltair(t, 100)
|
||||
|
||||
aggBits := bitfield.NewBitlist(3)
|
||||
aggBits.SetBitAt(0, true)
|
||||
var mockRoot [32]byte
|
||||
copy(mockRoot[:], "hello-world")
|
||||
att := testutil.HydrateAttestation(ðpb.Attestation{
|
||||
Data: ðpb.AttestationData{
|
||||
Source: ðpb.Checkpoint{Root: mockRoot[:]},
|
||||
Target: ðpb.Checkpoint{Root: mockRoot[:]},
|
||||
},
|
||||
AggregationBits: aggBits,
|
||||
})
|
||||
|
||||
cfc := beaconState.CurrentJustifiedCheckpoint()
|
||||
cfc.Root = mockRoot[:]
|
||||
require.NoError(t, beaconState.SetCurrentJustifiedCheckpoint(cfc))
|
||||
|
||||
committee, err := helpers.BeaconCommitteeFromState(beaconState, att.Data.Slot, att.Data.CommitteeIndex)
|
||||
require.NoError(t, err)
|
||||
attestingIndices, err := attestationutil.AttestingIndices(att.AggregationBits, committee)
|
||||
require.NoError(t, err)
|
||||
sigs := make([]bls.Signature, len(attestingIndices))
|
||||
for i, indice := range attestingIndices {
|
||||
sb, err := helpers.ComputeDomainAndSign(beaconState, 0, att.Data, params.BeaconConfig().DomainBeaconAttester, privKeys[indice])
|
||||
require.NoError(t, err)
|
||||
sig, err := bls.SignatureFromBytes(sb)
|
||||
require.NoError(t, err)
|
||||
sigs[i] = sig
|
||||
}
|
||||
att.Signature = bls.AggregateSignatures(sigs).Marshal()
|
||||
|
||||
block := testutil.NewBeaconBlockAltair()
|
||||
block.Block.Body.Attestations = []*ethpb.Attestation{att}
|
||||
|
||||
err = beaconState.SetSlot(beaconState.Slot() + params.BeaconConfig().MinAttestationInclusionDelay)
|
||||
require.NoError(t, err)
|
||||
wsb, err := wrapper.WrappedAltairSignedBeaconBlock(block)
|
||||
require.NoError(t, err)
|
||||
_, err = altair.ProcessAttestationsNoVerifySignature(context.Background(), beaconState, wsb)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestProcessAttestationNoVerify_SourceTargetHead(t *testing.T) {
|
||||
beaconState, _ := testutil.DeterministicGenesisStateAltair(t, 64)
|
||||
err := beaconState.SetSlot(beaconState.Slot() + params.BeaconConfig().MinAttestationInclusionDelay)
|
||||
require.NoError(t, err)
|
||||
|
||||
aggBits := bitfield.NewBitlist(2)
|
||||
aggBits.SetBitAt(0, true)
|
||||
aggBits.SetBitAt(1, true)
|
||||
r, err := helpers.BlockRootAtSlot(beaconState, 0)
|
||||
require.NoError(t, err)
|
||||
att := ðpb.Attestation{
|
||||
Data: ðpb.AttestationData{
|
||||
BeaconBlockRoot: r,
|
||||
Source: ðpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
|
||||
Target: ðpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
|
||||
},
|
||||
AggregationBits: aggBits,
|
||||
}
|
||||
zeroSig := [96]byte{}
|
||||
att.Signature = zeroSig[:]
|
||||
|
||||
ckp := beaconState.CurrentJustifiedCheckpoint()
|
||||
copy(ckp.Root, make([]byte, 32))
|
||||
require.NoError(t, beaconState.SetCurrentJustifiedCheckpoint(ckp))
|
||||
|
||||
beaconState, err = altair.ProcessAttestationNoVerifySignature(context.Background(), beaconState, att)
|
||||
require.NoError(t, err)
|
||||
|
||||
p, err := beaconState.CurrentEpochParticipation()
|
||||
require.NoError(t, err)
|
||||
|
||||
committee, err := helpers.BeaconCommitteeFromState(beaconState, att.Data.Slot, att.Data.CommitteeIndex)
|
||||
require.NoError(t, err)
|
||||
indices, err := attestationutil.AttestingIndices(att.AggregationBits, committee)
|
||||
require.NoError(t, err)
|
||||
for _, index := range indices {
|
||||
require.Equal(t, true, altair.HasValidatorFlag(p[index], params.BeaconConfig().TimelyHeadFlagIndex))
|
||||
require.Equal(t, true, altair.HasValidatorFlag(p[index], params.BeaconConfig().TimelyTargetFlagIndex))
|
||||
require.Equal(t, true, altair.HasValidatorFlag(p[index], params.BeaconConfig().TimelySourceFlagIndex))
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidatorFlag_Has(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
set uint8
|
||||
expected []uint8
|
||||
}{
|
||||
{name: "none",
|
||||
set: 0,
|
||||
expected: []uint8{},
|
||||
},
|
||||
{
|
||||
name: "source",
|
||||
set: 1,
|
||||
expected: []uint8{params.BeaconConfig().TimelySourceFlagIndex},
|
||||
},
|
||||
{
|
||||
name: "target",
|
||||
set: 2,
|
||||
expected: []uint8{params.BeaconConfig().TimelyTargetFlagIndex},
|
||||
},
|
||||
{
|
||||
name: "head",
|
||||
set: 4,
|
||||
expected: []uint8{params.BeaconConfig().TimelyHeadFlagIndex},
|
||||
},
|
||||
{
|
||||
name: "source, target",
|
||||
set: 3,
|
||||
expected: []uint8{params.BeaconConfig().TimelySourceFlagIndex, params.BeaconConfig().TimelyTargetFlagIndex},
|
||||
},
|
||||
{
|
||||
name: "source, head",
|
||||
set: 5,
|
||||
expected: []uint8{params.BeaconConfig().TimelySourceFlagIndex, params.BeaconConfig().TimelyHeadFlagIndex},
|
||||
},
|
||||
{
|
||||
name: "target, head",
|
||||
set: 6,
|
||||
expected: []uint8{params.BeaconConfig().TimelyTargetFlagIndex, params.BeaconConfig().TimelyTargetFlagIndex},
|
||||
},
|
||||
{
|
||||
name: "source, target, head",
|
||||
set: 7,
|
||||
expected: []uint8{params.BeaconConfig().TimelySourceFlagIndex, params.BeaconConfig().TimelyTargetFlagIndex, params.BeaconConfig().TimelyHeadFlagIndex},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
for _, f := range tt.expected {
|
||||
require.Equal(t, true, altair.HasValidatorFlag(tt.set, f))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidatorFlag_Add(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
set []uint8
|
||||
expectedTrue []uint8
|
||||
expectedFalse []uint8
|
||||
}{
|
||||
{name: "none",
|
||||
set: []uint8{},
|
||||
expectedTrue: []uint8{},
|
||||
expectedFalse: []uint8{params.BeaconConfig().TimelySourceFlagIndex, params.BeaconConfig().TimelyTargetFlagIndex, params.BeaconConfig().TimelyHeadFlagIndex},
|
||||
},
|
||||
{
|
||||
name: "source",
|
||||
set: []uint8{params.BeaconConfig().TimelySourceFlagIndex},
|
||||
expectedTrue: []uint8{params.BeaconConfig().TimelySourceFlagIndex},
|
||||
expectedFalse: []uint8{params.BeaconConfig().TimelyTargetFlagIndex, params.BeaconConfig().TimelyHeadFlagIndex},
|
||||
},
|
||||
{
|
||||
name: "source, target",
|
||||
set: []uint8{params.BeaconConfig().TimelySourceFlagIndex, params.BeaconConfig().TimelyTargetFlagIndex},
|
||||
expectedTrue: []uint8{params.BeaconConfig().TimelySourceFlagIndex, params.BeaconConfig().TimelyTargetFlagIndex},
|
||||
expectedFalse: []uint8{params.BeaconConfig().TimelyHeadFlagIndex},
|
||||
},
|
||||
{
|
||||
name: "source, target, head",
|
||||
set: []uint8{params.BeaconConfig().TimelySourceFlagIndex, params.BeaconConfig().TimelyTargetFlagIndex, params.BeaconConfig().TimelyHeadFlagIndex},
|
||||
expectedTrue: []uint8{params.BeaconConfig().TimelySourceFlagIndex, params.BeaconConfig().TimelyTargetFlagIndex, params.BeaconConfig().TimelyHeadFlagIndex},
|
||||
expectedFalse: []uint8{},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
b := uint8(0)
|
||||
for _, f := range tt.set {
|
||||
b = altair.AddValidatorFlag(b, f)
|
||||
}
|
||||
for _, f := range tt.expectedFalse {
|
||||
require.Equal(t, false, altair.HasValidatorFlag(b, f))
|
||||
}
|
||||
for _, f := range tt.expectedTrue {
|
||||
require.Equal(t, true, altair.HasValidatorFlag(b, f))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestFuzzProcessAttestationsNoVerify_10000(t *testing.T) {
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
state := ðpb.BeaconStateAltair{}
|
||||
b := ðpb.SignedBeaconBlockAltair{Block: ðpb.BeaconBlockAltair{}}
|
||||
ctx := context.Background()
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(b)
|
||||
if b.Block == nil {
|
||||
b.Block = ðpb.BeaconBlockAltair{}
|
||||
}
|
||||
s, err := stateAltair.InitializeFromProtoUnsafe(state)
|
||||
require.NoError(t, err)
|
||||
wsb, err := wrapper.WrappedAltairSignedBeaconBlock(b)
|
||||
require.NoError(t, err)
|
||||
r, err := altair.ProcessAttestationsNoVerifySignature(ctx, s, wsb)
|
||||
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, b)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetParticipationAndRewardProposer(t *testing.T) {
|
||||
cfg := params.BeaconConfig()
|
||||
sourceFlagIndex := cfg.TimelySourceFlagIndex
|
||||
targetFlagIndex := cfg.TimelyTargetFlagIndex
|
||||
headFlagIndex := cfg.TimelyHeadFlagIndex
|
||||
tests := []struct {
|
||||
name string
|
||||
indices []uint64
|
||||
epochParticipation []byte
|
||||
participatedFlags map[uint8]bool
|
||||
epoch types.Epoch
|
||||
wantedBalance uint64
|
||||
wantedParticipation []byte
|
||||
}{
|
||||
{name: "none participated",
|
||||
indices: []uint64{}, epochParticipation: []byte{0, 0, 0, 0, 0, 0, 0, 0}, participatedFlags: map[uint8]bool{
|
||||
sourceFlagIndex: false,
|
||||
targetFlagIndex: false,
|
||||
headFlagIndex: false,
|
||||
},
|
||||
wantedParticipation: []byte{0, 0, 0, 0, 0, 0, 0, 0},
|
||||
wantedBalance: 32000000000,
|
||||
},
|
||||
{name: "some participated without flags",
|
||||
indices: []uint64{0, 1, 2, 3}, epochParticipation: []byte{0, 0, 0, 0, 0, 0, 0, 0}, participatedFlags: map[uint8]bool{
|
||||
sourceFlagIndex: false,
|
||||
targetFlagIndex: false,
|
||||
headFlagIndex: false,
|
||||
},
|
||||
wantedParticipation: []byte{0, 0, 0, 0, 0, 0, 0, 0},
|
||||
wantedBalance: 32000000000,
|
||||
},
|
||||
{name: "some participated with some flags",
|
||||
indices: []uint64{0, 1, 2, 3}, epochParticipation: []byte{0, 0, 0, 0, 0, 0, 0, 0}, participatedFlags: map[uint8]bool{
|
||||
sourceFlagIndex: true,
|
||||
targetFlagIndex: true,
|
||||
headFlagIndex: false,
|
||||
},
|
||||
wantedParticipation: []byte{3, 3, 3, 3, 0, 0, 0, 0},
|
||||
wantedBalance: 32000090342,
|
||||
},
|
||||
{name: "all participated with some flags",
|
||||
indices: []uint64{0, 1, 2, 3, 4, 5, 6, 7}, epochParticipation: []byte{0, 0, 0, 0, 0, 0, 0, 0}, participatedFlags: map[uint8]bool{
|
||||
sourceFlagIndex: true,
|
||||
targetFlagIndex: false,
|
||||
headFlagIndex: false,
|
||||
},
|
||||
wantedParticipation: []byte{1, 1, 1, 1, 1, 1, 1, 1},
|
||||
wantedBalance: 32000063240,
|
||||
},
|
||||
{name: "all participated with all flags",
|
||||
indices: []uint64{0, 1, 2, 3, 4, 5, 6, 7}, epochParticipation: []byte{0, 0, 0, 0, 0, 0, 0, 0}, participatedFlags: map[uint8]bool{
|
||||
sourceFlagIndex: true,
|
||||
targetFlagIndex: true,
|
||||
headFlagIndex: true,
|
||||
},
|
||||
wantedParticipation: []byte{7, 7, 7, 7, 7, 7, 7, 7},
|
||||
wantedBalance: 32000243925,
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
beaconState, _ := testutil.DeterministicGenesisStateAltair(t, params.BeaconConfig().MaxValidatorsPerCommittee)
|
||||
require.NoError(t, beaconState.SetSlot(params.BeaconConfig().SlotsPerEpoch))
|
||||
|
||||
currentEpoch := helpers.CurrentEpoch(beaconState)
|
||||
if test.epoch == currentEpoch {
|
||||
require.NoError(t, beaconState.SetCurrentParticipationBits(test.epochParticipation))
|
||||
} else {
|
||||
require.NoError(t, beaconState.SetPreviousParticipationBits(test.epochParticipation))
|
||||
}
|
||||
st, err := altair.SetParticipationAndRewardProposer(beaconState, test.epoch, test.indices, test.participatedFlags)
|
||||
require.NoError(t, err)
|
||||
|
||||
i, err := helpers.BeaconProposerIndex(st)
|
||||
require.NoError(t, err)
|
||||
b, err := beaconState.BalanceAtIndex(i)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, test.wantedBalance, b)
|
||||
|
||||
if test.epoch == currentEpoch {
|
||||
p, err := beaconState.CurrentEpochParticipation()
|
||||
require.NoError(t, err)
|
||||
require.DeepSSZEqual(t, test.wantedParticipation, p)
|
||||
} else {
|
||||
p, err := beaconState.PreviousEpochParticipation()
|
||||
require.NoError(t, err)
|
||||
require.DeepSSZEqual(t, test.wantedParticipation, p)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestEpochParticipation(t *testing.T) {
|
||||
beaconState, _ := testutil.DeterministicGenesisStateAltair(t, params.BeaconConfig().MaxValidatorsPerCommittee)
|
||||
cfg := params.BeaconConfig()
|
||||
sourceFlagIndex := cfg.TimelySourceFlagIndex
|
||||
targetFlagIndex := cfg.TimelyTargetFlagIndex
|
||||
headFlagIndex := cfg.TimelyHeadFlagIndex
|
||||
tests := []struct {
|
||||
name string
|
||||
indices []uint64
|
||||
epochParticipation []byte
|
||||
participatedFlags map[uint8]bool
|
||||
wantedNumerator uint64
|
||||
wantedEpochParticipation []byte
|
||||
}{
|
||||
{name: "none participated",
|
||||
indices: []uint64{}, epochParticipation: []byte{0, 0, 0, 0, 0, 0, 0, 0}, participatedFlags: map[uint8]bool{
|
||||
sourceFlagIndex: false,
|
||||
targetFlagIndex: false,
|
||||
headFlagIndex: false,
|
||||
},
|
||||
wantedNumerator: 0,
|
||||
wantedEpochParticipation: []byte{0, 0, 0, 0, 0, 0, 0, 0},
|
||||
},
|
||||
{name: "some participated without flags",
|
||||
indices: []uint64{0, 1, 2, 3}, epochParticipation: []byte{0, 0, 0, 0, 0, 0, 0, 0}, participatedFlags: map[uint8]bool{
|
||||
sourceFlagIndex: false,
|
||||
targetFlagIndex: false,
|
||||
headFlagIndex: false,
|
||||
},
|
||||
wantedNumerator: 0,
|
||||
wantedEpochParticipation: []byte{0, 0, 0, 0, 0, 0, 0, 0},
|
||||
},
|
||||
{name: "some participated with some flags",
|
||||
indices: []uint64{0, 1, 2, 3}, epochParticipation: []byte{0, 0, 0, 0, 0, 0, 0, 0}, participatedFlags: map[uint8]bool{
|
||||
sourceFlagIndex: true,
|
||||
targetFlagIndex: true,
|
||||
headFlagIndex: false,
|
||||
},
|
||||
wantedNumerator: 40473600,
|
||||
wantedEpochParticipation: []byte{3, 3, 3, 3, 0, 0, 0, 0},
|
||||
},
|
||||
{name: "all participated with some flags",
|
||||
indices: []uint64{0, 1, 2, 3, 4, 5, 6, 7}, epochParticipation: []byte{0, 0, 0, 0, 0, 0, 0, 0}, participatedFlags: map[uint8]bool{
|
||||
sourceFlagIndex: true,
|
||||
targetFlagIndex: false,
|
||||
headFlagIndex: false,
|
||||
},
|
||||
wantedNumerator: 28331520,
|
||||
wantedEpochParticipation: []byte{1, 1, 1, 1, 1, 1, 1, 1},
|
||||
},
|
||||
{name: "all participated with all flags",
|
||||
indices: []uint64{0, 1, 2, 3, 4, 5, 6, 7}, epochParticipation: []byte{0, 0, 0, 0, 0, 0, 0, 0}, participatedFlags: map[uint8]bool{
|
||||
sourceFlagIndex: true,
|
||||
targetFlagIndex: true,
|
||||
headFlagIndex: true,
|
||||
},
|
||||
wantedNumerator: 109278720,
|
||||
wantedEpochParticipation: []byte{7, 7, 7, 7, 7, 7, 7, 7},
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
n, p, err := altair.EpochParticipation(beaconState, test.indices, test.epochParticipation, test.participatedFlags)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, test.wantedNumerator, n)
|
||||
require.DeepSSZEqual(t, test.wantedEpochParticipation, p)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRewardProposer(t *testing.T) {
|
||||
beaconState, _ := testutil.DeterministicGenesisStateAltair(t, params.BeaconConfig().MaxValidatorsPerCommittee)
|
||||
require.NoError(t, beaconState.SetSlot(1))
|
||||
tests := []struct {
|
||||
rewardNumerator uint64
|
||||
want uint64
|
||||
}{
|
||||
{rewardNumerator: 1, want: 32000000000},
|
||||
{rewardNumerator: 10000, want: 32000000022},
|
||||
{rewardNumerator: 1000000, want: 32000002254},
|
||||
{rewardNumerator: 1000000000, want: 32002234396},
|
||||
{rewardNumerator: 1000000000000, want: 34234377253},
|
||||
}
|
||||
for _, test := range tests {
|
||||
require.NoError(t, altair.RewardProposer(beaconState, test.rewardNumerator))
|
||||
i, err := helpers.BeaconProposerIndex(beaconState)
|
||||
require.NoError(t, err)
|
||||
b, err := beaconState.BalanceAtIndex(i)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, test.want, b)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAttestationParticipationFlagIndices(t *testing.T) {
|
||||
beaconState, _ := testutil.DeterministicGenesisStateAltair(t, params.BeaconConfig().MaxValidatorsPerCommittee)
|
||||
require.NoError(t, beaconState.SetSlot(1))
|
||||
cfg := params.BeaconConfig()
|
||||
sourceFlagIndex := cfg.TimelySourceFlagIndex
|
||||
targetFlagIndex := cfg.TimelyTargetFlagIndex
|
||||
headFlagIndex := cfg.TimelyHeadFlagIndex
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
inputState state.BeaconState
|
||||
inputData *ethpb.AttestationData
|
||||
inputDelay types.Slot
|
||||
participationIndices map[uint8]bool
|
||||
}{
|
||||
{
|
||||
name: "none",
|
||||
inputState: func() state.BeaconState {
|
||||
return beaconState
|
||||
}(),
|
||||
inputData: ðpb.AttestationData{
|
||||
Source: ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]},
|
||||
Target: ðpb.Checkpoint{},
|
||||
},
|
||||
inputDelay: params.BeaconConfig().SlotsPerEpoch,
|
||||
participationIndices: map[uint8]bool{},
|
||||
},
|
||||
{
|
||||
name: "participated source",
|
||||
inputState: func() state.BeaconState {
|
||||
return beaconState
|
||||
}(),
|
||||
inputData: ðpb.AttestationData{
|
||||
Source: ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]},
|
||||
Target: ðpb.Checkpoint{},
|
||||
},
|
||||
inputDelay: types.Slot(mathutil.IntegerSquareRoot(uint64(cfg.SlotsPerEpoch)) - 1),
|
||||
participationIndices: map[uint8]bool{
|
||||
sourceFlagIndex: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "participated source and target",
|
||||
inputState: func() state.BeaconState {
|
||||
return beaconState
|
||||
}(),
|
||||
inputData: ðpb.AttestationData{
|
||||
Source: ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]},
|
||||
Target: ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]},
|
||||
},
|
||||
inputDelay: types.Slot(mathutil.IntegerSquareRoot(uint64(cfg.SlotsPerEpoch)) - 1),
|
||||
participationIndices: map[uint8]bool{
|
||||
sourceFlagIndex: true,
|
||||
targetFlagIndex: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "participated source and target and head",
|
||||
inputState: func() state.BeaconState {
|
||||
return beaconState
|
||||
}(),
|
||||
inputData: ðpb.AttestationData{
|
||||
BeaconBlockRoot: params.BeaconConfig().ZeroHash[:],
|
||||
Source: ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]},
|
||||
Target: ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]},
|
||||
},
|
||||
inputDelay: 1,
|
||||
participationIndices: map[uint8]bool{
|
||||
sourceFlagIndex: true,
|
||||
targetFlagIndex: true,
|
||||
headFlagIndex: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
flagIndices, err := altair.AttestationParticipationFlagIndices(test.inputState, test.inputData, test.inputDelay)
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, test.participationIndices, flagIndices)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMatchingStatus(t *testing.T) {
|
||||
beaconState, _ := testutil.DeterministicGenesisStateAltair(t, params.BeaconConfig().MaxValidatorsPerCommittee)
|
||||
require.NoError(t, beaconState.SetSlot(1))
|
||||
tests := []struct {
|
||||
name string
|
||||
inputState state.BeaconState
|
||||
inputData *ethpb.AttestationData
|
||||
inputCheckpt *ethpb.Checkpoint
|
||||
matchedSource bool
|
||||
matchedTarget bool
|
||||
matchedHead bool
|
||||
}{
|
||||
{
|
||||
name: "non matched",
|
||||
inputState: beaconState,
|
||||
inputData: ðpb.AttestationData{
|
||||
Source: ðpb.Checkpoint{Epoch: 1},
|
||||
Target: ðpb.Checkpoint{},
|
||||
},
|
||||
inputCheckpt: ðpb.Checkpoint{},
|
||||
},
|
||||
{
|
||||
name: "source matched",
|
||||
inputState: beaconState,
|
||||
inputData: ðpb.AttestationData{
|
||||
Source: ðpb.Checkpoint{},
|
||||
Target: ðpb.Checkpoint{},
|
||||
},
|
||||
inputCheckpt: ðpb.Checkpoint{},
|
||||
matchedSource: true,
|
||||
},
|
||||
{
|
||||
name: "target matched",
|
||||
inputState: beaconState,
|
||||
inputData: ðpb.AttestationData{
|
||||
Source: ðpb.Checkpoint{Epoch: 1},
|
||||
Target: ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]},
|
||||
},
|
||||
inputCheckpt: ðpb.Checkpoint{},
|
||||
matchedTarget: true,
|
||||
},
|
||||
{
|
||||
name: "head matched",
|
||||
inputState: beaconState,
|
||||
inputData: ðpb.AttestationData{
|
||||
Source: ðpb.Checkpoint{Epoch: 1},
|
||||
Target: ðpb.Checkpoint{},
|
||||
BeaconBlockRoot: params.BeaconConfig().ZeroHash[:],
|
||||
},
|
||||
inputCheckpt: ðpb.Checkpoint{},
|
||||
matchedHead: true,
|
||||
},
|
||||
{
|
||||
name: "everything matched",
|
||||
inputState: beaconState,
|
||||
inputData: ðpb.AttestationData{
|
||||
Source: ðpb.Checkpoint{},
|
||||
Target: ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]},
|
||||
BeaconBlockRoot: params.BeaconConfig().ZeroHash[:],
|
||||
},
|
||||
inputCheckpt: ðpb.Checkpoint{},
|
||||
matchedSource: true,
|
||||
matchedTarget: true,
|
||||
matchedHead: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
src, tgt, head, err := altair.MatchingStatus(test.inputState, test.inputData, test.inputCheckpt)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, test.matchedSource, src)
|
||||
require.Equal(t, test.matchedTarget, tgt)
|
||||
require.Equal(t, test.matchedHead, head)
|
||||
}
|
||||
}
|
||||
175
beacon-chain/core/altair/block.go
Normal file
175
beacon-chain/core/altair/block.go
Normal file
@@ -0,0 +1,175 @@
|
||||
package altair
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
p2pType "github.com/prysmaticlabs/prysm/beacon-chain/p2p/types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
// ProcessSyncAggregate verifies sync committee aggregate signature signing over the previous slot block root.
|
||||
//
|
||||
// Spec code:
|
||||
// def process_sync_aggregate(state: BeaconState, sync_aggregate: SyncAggregate) -> None:
|
||||
// # Verify sync committee aggregate signature signing over the previous slot block root
|
||||
// committee_pubkeys = state.current_sync_committee.pubkeys
|
||||
// participant_pubkeys = [pubkey for pubkey, bit in zip(committee_pubkeys, sync_aggregate.sync_committee_bits) if bit]
|
||||
// previous_slot = max(state.slot, Slot(1)) - Slot(1)
|
||||
// domain = get_domain(state, DOMAIN_SYNC_COMMITTEE, compute_epoch_at_slot(previous_slot))
|
||||
// signing_root = compute_signing_root(get_block_root_at_slot(state, previous_slot), domain)
|
||||
// assert eth2_fast_aggregate_verify(participant_pubkeys, signing_root, sync_aggregate.sync_committee_signature)
|
||||
//
|
||||
// # Compute participant and proposer rewards
|
||||
// total_active_increments = get_total_active_balance(state) // EFFECTIVE_BALANCE_INCREMENT
|
||||
// total_base_rewards = Gwei(get_base_reward_per_increment(state) * total_active_increments)
|
||||
// max_participant_rewards = Gwei(total_base_rewards * SYNC_REWARD_WEIGHT // WEIGHT_DENOMINATOR // SLOTS_PER_EPOCH)
|
||||
// participant_reward = Gwei(max_participant_rewards // SYNC_COMMITTEE_SIZE)
|
||||
// proposer_reward = Gwei(participant_reward * PROPOSER_WEIGHT // (WEIGHT_DENOMINATOR - PROPOSER_WEIGHT))
|
||||
//
|
||||
// # Apply participant and proposer rewards
|
||||
// all_pubkeys = [v.pubkey for v in state.validators]
|
||||
// committee_indices = [ValidatorIndex(all_pubkeys.index(pubkey)) for pubkey in state.current_sync_committee.pubkeys]
|
||||
// for participant_index, participation_bit in zip(committee_indices, sync_aggregate.sync_committee_bits):
|
||||
// if participation_bit:
|
||||
// increase_balance(state, participant_index, participant_reward)
|
||||
// increase_balance(state, get_beacon_proposer_index(state), proposer_reward)
|
||||
// else:
|
||||
// decrease_balance(state, participant_index, participant_reward)
|
||||
func ProcessSyncAggregate(s state.BeaconStateAltair, sync *ethpb.SyncAggregate) (state.BeaconStateAltair, error) {
|
||||
votedKeys, votedIndices, didntVoteIndices, err := FilterSyncCommitteeVotes(s, sync)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := VerifySyncCommitteeSig(s, votedKeys, sync.SyncCommitteeSignature); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ApplySyncRewardsPenalties(s, votedIndices, didntVoteIndices)
|
||||
}
|
||||
|
||||
// FilterSyncCommitteeVotes filters the validator public keys and indices for the ones that voted and didn't vote.
|
||||
func FilterSyncCommitteeVotes(s state.BeaconStateAltair, sync *ethpb.SyncAggregate) (
|
||||
votedKeys []bls.PublicKey,
|
||||
votedIndices []types.ValidatorIndex,
|
||||
didntVoteIndices []types.ValidatorIndex,
|
||||
err error) {
|
||||
currentSyncCommittee, err := s.CurrentSyncCommittee()
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
if currentSyncCommittee == nil {
|
||||
return nil, nil, nil, errors.New("nil current sync committee in state")
|
||||
}
|
||||
committeeKeys := currentSyncCommittee.Pubkeys
|
||||
if sync.SyncCommitteeBits.Len() > uint64(len(committeeKeys)) {
|
||||
return nil, nil, nil, errors.New("bits length exceeds committee length")
|
||||
}
|
||||
votedKeys = make([]bls.PublicKey, 0, len(committeeKeys))
|
||||
votedIndices = make([]types.ValidatorIndex, 0, len(committeeKeys))
|
||||
didntVoteIndices = make([]types.ValidatorIndex, 0) // No allocation. Expect most votes.
|
||||
|
||||
for i := uint64(0); i < sync.SyncCommitteeBits.Len(); i++ {
|
||||
vIdx, exists := s.ValidatorIndexByPubkey(bytesutil.ToBytes48(committeeKeys[i]))
|
||||
// Impossible scenario.
|
||||
if !exists {
|
||||
return nil, nil, nil, errors.New("validator public key does not exist in state")
|
||||
}
|
||||
|
||||
if sync.SyncCommitteeBits.BitAt(i) {
|
||||
pubKey, err := bls.PublicKeyFromBytes(committeeKeys[i])
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
votedKeys = append(votedKeys, pubKey)
|
||||
votedIndices = append(votedIndices, vIdx)
|
||||
} else {
|
||||
didntVoteIndices = append(didntVoteIndices, vIdx)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// VerifySyncCommitteeSig verifies sync committee signature `syncSig` is valid with respect to public keys `syncKeys`.
|
||||
func VerifySyncCommitteeSig(s state.BeaconStateAltair, syncKeys []bls.PublicKey, syncSig []byte) error {
|
||||
ps := helpers.PrevSlot(s.Slot())
|
||||
d, err := helpers.Domain(s.Fork(), helpers.SlotToEpoch(ps), params.BeaconConfig().DomainSyncCommittee, s.GenesisValidatorRoot())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pbr, err := helpers.BlockRootAtSlot(s, ps)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sszBytes := p2pType.SSZBytes(pbr)
|
||||
r, err := helpers.ComputeSigningRoot(&sszBytes, d)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sig, err := bls.SignatureFromBytes(syncSig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !sig.Eth2FastAggregateVerify(syncKeys, r) {
|
||||
return errors.New("invalid sync committee signature")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ApplySyncRewardsPenalties applies rewards and penalties for proposer and sync committee participants.
|
||||
func ApplySyncRewardsPenalties(s state.BeaconStateAltair, votedIndices, didntVoteIndices []types.ValidatorIndex) (state.BeaconStateAltair, error) {
|
||||
activeBalance, err := helpers.TotalActiveBalance(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
proposerReward, participantReward, err := SyncRewards(activeBalance)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Apply sync committee rewards.
|
||||
earnedProposerReward := uint64(0)
|
||||
for _, index := range votedIndices {
|
||||
if err := helpers.IncreaseBalance(s, index, participantReward); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
earnedProposerReward += proposerReward
|
||||
}
|
||||
// Apply proposer rewards.
|
||||
proposerIndex, err := helpers.BeaconProposerIndex(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := helpers.IncreaseBalance(s, proposerIndex, earnedProposerReward); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Apply sync committee penalties.
|
||||
for _, index := range didntVoteIndices {
|
||||
if err := helpers.DecreaseBalance(s, index, participantReward); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// SyncRewards returns the proposer reward and the sync participant reward given the total active balance in state.
|
||||
func SyncRewards(activeBalance uint64) (proposerReward uint64, participantReward uint64, err error) {
|
||||
cfg := params.BeaconConfig()
|
||||
totalActiveIncrements := activeBalance / cfg.EffectiveBalanceIncrement
|
||||
baseRewardPerInc, err := BaseRewardPerIncrement(activeBalance)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
totalBaseRewards := baseRewardPerInc * totalActiveIncrements
|
||||
maxParticipantRewards := totalBaseRewards * cfg.SyncRewardWeight / cfg.WeightDenominator / uint64(cfg.SlotsPerEpoch)
|
||||
participantReward = maxParticipantRewards / cfg.SyncCommitteeSize
|
||||
proposerReward = participantReward * cfg.ProposerWeight / (cfg.WeightDenominator - cfg.ProposerWeight)
|
||||
return
|
||||
}
|
||||
317
beacon-chain/core/altair/block_test.go
Normal file
317
beacon-chain/core/altair/block_test.go
Normal file
@@ -0,0 +1,317 @@
|
||||
package altair_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math"
|
||||
"testing"
|
||||
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/go-bitfield"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/altair"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
p2pType "github.com/prysmaticlabs/prysm/beacon-chain/p2p/types"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"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/require"
|
||||
)
|
||||
|
||||
func TestProcessSyncCommittee_PerfectParticipation(t *testing.T) {
|
||||
beaconState, privKeys := testutil.DeterministicGenesisStateAltair(t, params.BeaconConfig().MaxValidatorsPerCommittee)
|
||||
require.NoError(t, beaconState.SetSlot(1))
|
||||
committee, err := altair.NextSyncCommittee(context.Background(), beaconState)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, beaconState.SetCurrentSyncCommittee(committee))
|
||||
|
||||
syncBits := bitfield.NewBitvector512()
|
||||
for i := range syncBits {
|
||||
syncBits[i] = 0xff
|
||||
}
|
||||
indices, err := altair.NextSyncCommitteeIndices(context.Background(), beaconState)
|
||||
require.NoError(t, err)
|
||||
ps := helpers.PrevSlot(beaconState.Slot())
|
||||
pbr, err := helpers.BlockRootAtSlot(beaconState, ps)
|
||||
require.NoError(t, err)
|
||||
sigs := make([]bls.Signature, len(indices))
|
||||
for i, indice := range indices {
|
||||
b := p2pType.SSZBytes(pbr)
|
||||
sb, err := helpers.ComputeDomainAndSign(beaconState, helpers.CurrentEpoch(beaconState), &b, params.BeaconConfig().DomainSyncCommittee, privKeys[indice])
|
||||
require.NoError(t, err)
|
||||
sig, err := bls.SignatureFromBytes(sb)
|
||||
require.NoError(t, err)
|
||||
sigs[i] = sig
|
||||
}
|
||||
aggregatedSig := bls.AggregateSignatures(sigs).Marshal()
|
||||
syncAggregate := ðpb.SyncAggregate{
|
||||
SyncCommitteeBits: syncBits,
|
||||
SyncCommitteeSignature: aggregatedSig,
|
||||
}
|
||||
|
||||
beaconState, err = altair.ProcessSyncAggregate(beaconState, syncAggregate)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Use a non-sync committee index to compare profitability.
|
||||
syncCommittee := make(map[types.ValidatorIndex]bool)
|
||||
for _, index := range indices {
|
||||
syncCommittee[index] = true
|
||||
}
|
||||
nonSyncIndex := types.ValidatorIndex(params.BeaconConfig().MaxValidatorsPerCommittee + 1)
|
||||
for i := types.ValidatorIndex(0); uint64(i) < params.BeaconConfig().MaxValidatorsPerCommittee; i++ {
|
||||
if !syncCommittee[i] {
|
||||
nonSyncIndex = i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Sync committee should be more profitable than non sync committee
|
||||
balances := beaconState.Balances()
|
||||
require.Equal(t, true, balances[indices[0]] > balances[nonSyncIndex])
|
||||
|
||||
// Proposer should be more profitable than rest of the sync committee
|
||||
proposerIndex, err := helpers.BeaconProposerIndex(beaconState)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, true, balances[proposerIndex] > balances[indices[0]])
|
||||
|
||||
// Sync committee should have the same profits, except you are a proposer
|
||||
for i := 1; i < len(indices); i++ {
|
||||
if proposerIndex == indices[i-1] || proposerIndex == indices[i] {
|
||||
continue
|
||||
}
|
||||
require.Equal(t, balances[indices[i-1]], balances[indices[i]])
|
||||
}
|
||||
|
||||
// Increased balance validator count should equal to sync committee count
|
||||
increased := uint64(0)
|
||||
for _, balance := range balances {
|
||||
if balance > params.BeaconConfig().MaxEffectiveBalance {
|
||||
increased++
|
||||
}
|
||||
}
|
||||
require.Equal(t, params.BeaconConfig().SyncCommitteeSize, increased)
|
||||
}
|
||||
|
||||
func TestProcessSyncCommittee_MixParticipation_BadSignature(t *testing.T) {
|
||||
beaconState, privKeys := testutil.DeterministicGenesisStateAltair(t, params.BeaconConfig().MaxValidatorsPerCommittee)
|
||||
require.NoError(t, beaconState.SetSlot(1))
|
||||
committee, err := altair.NextSyncCommittee(context.Background(), beaconState)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, beaconState.SetCurrentSyncCommittee(committee))
|
||||
|
||||
syncBits := bitfield.NewBitvector512()
|
||||
for i := range syncBits {
|
||||
syncBits[i] = 0xAA
|
||||
}
|
||||
indices, err := altair.NextSyncCommitteeIndices(context.Background(), beaconState)
|
||||
require.NoError(t, err)
|
||||
ps := helpers.PrevSlot(beaconState.Slot())
|
||||
pbr, err := helpers.BlockRootAtSlot(beaconState, ps)
|
||||
require.NoError(t, err)
|
||||
sigs := make([]bls.Signature, len(indices))
|
||||
for i, indice := range indices {
|
||||
b := p2pType.SSZBytes(pbr)
|
||||
sb, err := helpers.ComputeDomainAndSign(beaconState, helpers.CurrentEpoch(beaconState), &b, params.BeaconConfig().DomainSyncCommittee, privKeys[indice])
|
||||
require.NoError(t, err)
|
||||
sig, err := bls.SignatureFromBytes(sb)
|
||||
require.NoError(t, err)
|
||||
sigs[i] = sig
|
||||
}
|
||||
aggregatedSig := bls.AggregateSignatures(sigs).Marshal()
|
||||
syncAggregate := ðpb.SyncAggregate{
|
||||
SyncCommitteeBits: syncBits,
|
||||
SyncCommitteeSignature: aggregatedSig,
|
||||
}
|
||||
|
||||
_, err = altair.ProcessSyncAggregate(beaconState, syncAggregate)
|
||||
require.ErrorContains(t, "invalid sync committee signature", err)
|
||||
}
|
||||
|
||||
func TestProcessSyncCommittee_MixParticipation_GoodSignature(t *testing.T) {
|
||||
beaconState, privKeys := testutil.DeterministicGenesisStateAltair(t, params.BeaconConfig().MaxValidatorsPerCommittee)
|
||||
require.NoError(t, beaconState.SetSlot(1))
|
||||
committee, err := altair.NextSyncCommittee(context.Background(), beaconState)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, beaconState.SetCurrentSyncCommittee(committee))
|
||||
|
||||
syncBits := bitfield.NewBitvector512()
|
||||
for i := range syncBits {
|
||||
syncBits[i] = 0xAA
|
||||
}
|
||||
indices, err := altair.NextSyncCommitteeIndices(context.Background(), beaconState)
|
||||
require.NoError(t, err)
|
||||
ps := helpers.PrevSlot(beaconState.Slot())
|
||||
pbr, err := helpers.BlockRootAtSlot(beaconState, ps)
|
||||
require.NoError(t, err)
|
||||
sigs := make([]bls.Signature, 0, len(indices))
|
||||
for i, indice := range indices {
|
||||
if syncBits.BitAt(uint64(i)) {
|
||||
b := p2pType.SSZBytes(pbr)
|
||||
sb, err := helpers.ComputeDomainAndSign(beaconState, helpers.CurrentEpoch(beaconState), &b, params.BeaconConfig().DomainSyncCommittee, privKeys[indice])
|
||||
require.NoError(t, err)
|
||||
sig, err := bls.SignatureFromBytes(sb)
|
||||
require.NoError(t, err)
|
||||
sigs = append(sigs, sig)
|
||||
}
|
||||
}
|
||||
aggregatedSig := bls.AggregateSignatures(sigs).Marshal()
|
||||
syncAggregate := ðpb.SyncAggregate{
|
||||
SyncCommitteeBits: syncBits,
|
||||
SyncCommitteeSignature: aggregatedSig,
|
||||
}
|
||||
|
||||
_, err = altair.ProcessSyncAggregate(beaconState, syncAggregate)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestProcessSyncCommittee_FilterSyncCommitteeVotes(t *testing.T) {
|
||||
beaconState, _ := testutil.DeterministicGenesisStateAltair(t, params.BeaconConfig().MaxValidatorsPerCommittee)
|
||||
require.NoError(t, beaconState.SetSlot(1))
|
||||
committee, err := altair.NextSyncCommittee(context.Background(), beaconState)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, beaconState.SetCurrentSyncCommittee(committee))
|
||||
|
||||
syncBits := bitfield.NewBitvector512()
|
||||
for i := range syncBits {
|
||||
syncBits[i] = 0xAA
|
||||
}
|
||||
syncAggregate := ðpb.SyncAggregate{
|
||||
SyncCommitteeBits: syncBits,
|
||||
}
|
||||
|
||||
votedKeys, votedIndices, didntVoteIndices, err := altair.FilterSyncCommitteeVotes(beaconState, syncAggregate)
|
||||
require.NoError(t, err)
|
||||
votedMap := make(map[[48]byte]bool)
|
||||
for _, key := range votedKeys {
|
||||
votedMap[bytesutil.ToBytes48(key.Marshal())] = true
|
||||
}
|
||||
require.Equal(t, int(syncBits.Len()/2), len(votedKeys))
|
||||
require.Equal(t, int(syncBits.Len()/2), len(votedIndices))
|
||||
require.Equal(t, int(syncBits.Len()/2), len(didntVoteIndices))
|
||||
|
||||
for i := 0; i < len(syncBits); i++ {
|
||||
if syncBits.BitAt(uint64(i)) {
|
||||
pk := beaconState.PubkeyAtIndex(votedIndices[i])
|
||||
require.DeepEqual(t, true, votedMap[pk])
|
||||
} else {
|
||||
pk := beaconState.PubkeyAtIndex(didntVoteIndices[i])
|
||||
require.DeepEqual(t, false, votedMap[pk])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Test_VerifySyncCommitteeSig(t *testing.T) {
|
||||
beaconState, privKeys := testutil.DeterministicGenesisStateAltair(t, params.BeaconConfig().MaxValidatorsPerCommittee)
|
||||
require.NoError(t, beaconState.SetSlot(1))
|
||||
committee, err := altair.NextSyncCommittee(context.Background(), beaconState)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, beaconState.SetCurrentSyncCommittee(committee))
|
||||
|
||||
syncBits := bitfield.NewBitvector512()
|
||||
for i := range syncBits {
|
||||
syncBits[i] = 0xff
|
||||
}
|
||||
indices, err := altair.NextSyncCommitteeIndices(context.Background(), beaconState)
|
||||
require.NoError(t, err)
|
||||
ps := helpers.PrevSlot(beaconState.Slot())
|
||||
pbr, err := helpers.BlockRootAtSlot(beaconState, ps)
|
||||
require.NoError(t, err)
|
||||
sigs := make([]bls.Signature, len(indices))
|
||||
pks := make([]bls.PublicKey, len(indices))
|
||||
for i, indice := range indices {
|
||||
b := p2pType.SSZBytes(pbr)
|
||||
sb, err := helpers.ComputeDomainAndSign(beaconState, helpers.CurrentEpoch(beaconState), &b, params.BeaconConfig().DomainSyncCommittee, privKeys[indice])
|
||||
require.NoError(t, err)
|
||||
sig, err := bls.SignatureFromBytes(sb)
|
||||
require.NoError(t, err)
|
||||
sigs[i] = sig
|
||||
pks[i] = privKeys[indice].PublicKey()
|
||||
}
|
||||
aggregatedSig := bls.AggregateSignatures(sigs).Marshal()
|
||||
|
||||
blsKey, err := bls.RandKey()
|
||||
require.NoError(t, err)
|
||||
require.ErrorContains(t, "invalid sync committee signature", altair.VerifySyncCommitteeSig(beaconState, pks, blsKey.Sign([]byte{'m', 'e', 'o', 'w'}).Marshal()))
|
||||
|
||||
require.NoError(t, altair.VerifySyncCommitteeSig(beaconState, pks, aggregatedSig))
|
||||
}
|
||||
|
||||
func Test_ApplySyncRewardsPenalties(t *testing.T) {
|
||||
beaconState, _ := testutil.DeterministicGenesisStateAltair(t, params.BeaconConfig().MaxValidatorsPerCommittee)
|
||||
beaconState, err := altair.ApplySyncRewardsPenalties(beaconState,
|
||||
[]types.ValidatorIndex{0, 1}, // voted
|
||||
[]types.ValidatorIndex{2, 3}) // didn't vote
|
||||
require.NoError(t, err)
|
||||
balances := beaconState.Balances()
|
||||
require.Equal(t, uint64(32000000988), balances[0])
|
||||
require.Equal(t, balances[0], balances[1])
|
||||
require.Equal(t, uint64(31999999012), balances[2])
|
||||
require.Equal(t, balances[2], balances[3])
|
||||
proposerIndex, err := helpers.BeaconProposerIndex(beaconState)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, uint64(32000000282), balances[proposerIndex])
|
||||
}
|
||||
|
||||
func Test_SyncRewards(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
activeBalance uint64
|
||||
wantProposerReward uint64
|
||||
wantParticipantReward uint64
|
||||
errString string
|
||||
}{
|
||||
{
|
||||
name: "active balance is 0",
|
||||
activeBalance: 0,
|
||||
wantProposerReward: 0,
|
||||
wantParticipantReward: 0,
|
||||
errString: "active balance can't be 0",
|
||||
},
|
||||
{
|
||||
name: "active balance is 1",
|
||||
activeBalance: 1,
|
||||
wantProposerReward: 0,
|
||||
wantParticipantReward: 0,
|
||||
errString: "",
|
||||
},
|
||||
{
|
||||
name: "active balance is 1eth",
|
||||
activeBalance: params.BeaconConfig().EffectiveBalanceIncrement,
|
||||
wantProposerReward: 0,
|
||||
wantParticipantReward: 3,
|
||||
errString: "",
|
||||
},
|
||||
{
|
||||
name: "active balance is 32eth",
|
||||
activeBalance: params.BeaconConfig().MaxEffectiveBalance,
|
||||
wantProposerReward: 3,
|
||||
wantParticipantReward: 21,
|
||||
errString: "",
|
||||
},
|
||||
{
|
||||
name: "active balance is 32eth * 1m validators",
|
||||
activeBalance: params.BeaconConfig().MaxEffectiveBalance * 1e9,
|
||||
wantProposerReward: 62780,
|
||||
wantParticipantReward: 439463,
|
||||
errString: "",
|
||||
},
|
||||
{
|
||||
name: "active balance is max uint64",
|
||||
activeBalance: math.MaxUint64,
|
||||
wantProposerReward: 70368,
|
||||
wantParticipantReward: 492581,
|
||||
errString: "",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
proposerReward, participarntReward, err := altair.SyncRewards(tt.activeBalance)
|
||||
if (err != nil) && (tt.errString != "") {
|
||||
require.ErrorContains(t, tt.errString, err)
|
||||
return
|
||||
}
|
||||
require.Equal(t, tt.wantProposerReward, proposerReward)
|
||||
require.Equal(t, tt.wantParticipantReward, participarntReward)
|
||||
})
|
||||
}
|
||||
}
|
||||
55
beacon-chain/core/altair/deposit.go
Normal file
55
beacon-chain/core/altair/deposit.go
Normal file
@@ -0,0 +1,55 @@
|
||||
package altair
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
)
|
||||
|
||||
// ProcessDeposits processes validator deposits for beacon state Altair.
|
||||
func ProcessDeposits(
|
||||
ctx context.Context,
|
||||
beaconState state.BeaconStateAltair,
|
||||
deposits []*ethpb.Deposit,
|
||||
) (state.BeaconStateAltair, error) {
|
||||
batchVerified, err := blocks.BatchVerifyDepositsSignatures(ctx, deposits)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, deposit := range deposits {
|
||||
if deposit == nil || deposit.Data == nil {
|
||||
return nil, errors.New("got a nil deposit in block")
|
||||
}
|
||||
beaconState, err = ProcessDeposit(ctx, beaconState, deposit, batchVerified)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not process deposit from %#x", bytesutil.Trunc(deposit.Data.PublicKey))
|
||||
}
|
||||
}
|
||||
return beaconState, nil
|
||||
}
|
||||
|
||||
// ProcessDeposit processes validator deposit for beacon state Altair.
|
||||
func ProcessDeposit(ctx context.Context, beaconState state.BeaconStateAltair, deposit *ethpb.Deposit, verifySignature bool) (state.BeaconStateAltair, error) {
|
||||
beaconState, isNewValidator, err := blocks.ProcessDeposit(beaconState, deposit, verifySignature)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if isNewValidator {
|
||||
if err := beaconState.AppendInactivityScore(0); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := beaconState.AppendPreviousParticipationBits(0); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := beaconState.AppendCurrentParticipationBits(0); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return beaconState, nil
|
||||
}
|
||||
48
beacon-chain/core/altair/deposit_fuzz_test.go
Normal file
48
beacon-chain/core/altair/deposit_fuzz_test.go
Normal file
@@ -0,0 +1,48 @@
|
||||
package altair_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
fuzz "github.com/google/gofuzz"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/altair"
|
||||
stateAltair "github.com/prysmaticlabs/prysm/beacon-chain/state/v2"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
func TestFuzzProcessDeposits_10000(t *testing.T) {
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
state := ðpb.BeaconStateAltair{}
|
||||
deposits := make([]*ethpb.Deposit, 100)
|
||||
ctx := context.Background()
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
for i := range deposits {
|
||||
fuzzer.Fuzz(deposits[i])
|
||||
}
|
||||
s, err := stateAltair.InitializeFromProtoUnsafe(state)
|
||||
require.NoError(t, err)
|
||||
r, err := altair.ProcessDeposits(ctx, s, deposits)
|
||||
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, deposits)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFuzzProcessDeposit_10000(t *testing.T) {
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
state := ðpb.BeaconStateAltair{}
|
||||
deposit := ðpb.Deposit{}
|
||||
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(deposit)
|
||||
s, err := stateAltair.InitializeFromProtoUnsafe(state)
|
||||
require.NoError(t, err)
|
||||
r, err := altair.ProcessDeposit(context.Background(), 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
245
beacon-chain/core/altair/deposit_test.go
Normal file
245
beacon-chain/core/altair/deposit_test.go
Normal file
@@ -0,0 +1,245 @@
|
||||
package altair_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/altair"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
stateAltair "github.com/prysmaticlabs/prysm/beacon-chain/state/v2"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"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/require"
|
||||
"github.com/prysmaticlabs/prysm/shared/trieutil"
|
||||
)
|
||||
|
||||
func TestProcessDeposits_SameValidatorMultipleDepositsSameBlock(t *testing.T) {
|
||||
// Same validator created 3 valid deposits within the same block
|
||||
dep, _, err := testutil.DeterministicDepositsAndKeysSameValidator(3)
|
||||
require.NoError(t, err)
|
||||
eth1Data, err := testutil.DeterministicEth1Data(len(dep))
|
||||
require.NoError(t, err)
|
||||
registry := []*ethpb.Validator{
|
||||
{
|
||||
PublicKey: []byte{1},
|
||||
WithdrawalCredentials: []byte{1, 2, 3},
|
||||
},
|
||||
}
|
||||
balances := []uint64{0}
|
||||
beaconState, err := stateAltair.InitializeFromProto(ðpb.BeaconStateAltair{
|
||||
Validators: registry,
|
||||
Balances: balances,
|
||||
Eth1Data: eth1Data,
|
||||
Fork: ðpb.Fork{
|
||||
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
newState, err := altair.ProcessDeposits(context.Background(), beaconState, []*ethpb.Deposit{dep[0], dep[1], dep[2]})
|
||||
require.NoError(t, err, "Expected block deposits to process correctly")
|
||||
require.Equal(t, 2, len(newState.Validators()), "Incorrect validator count")
|
||||
}
|
||||
|
||||
func TestProcessDeposits_MerkleBranchFailsVerification(t *testing.T) {
|
||||
deposit := ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: bytesutil.PadTo([]byte{1, 2, 3}, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
}
|
||||
leaf, err := deposit.Data.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
// We then create a merkle branch for the test.
|
||||
depositTrie, err := trieutil.GenerateTrieFromItems([][]byte{leaf[:]}, params.BeaconConfig().DepositContractTreeDepth)
|
||||
require.NoError(t, err, "Could not generate trie")
|
||||
proof, err := depositTrie.MerkleProof(0)
|
||||
require.NoError(t, err, "Could not generate proof")
|
||||
|
||||
deposit.Proof = proof
|
||||
beaconState, err := stateAltair.InitializeFromProto(ðpb.BeaconStateAltair{
|
||||
Eth1Data: ðpb.Eth1Data{
|
||||
DepositRoot: []byte{0},
|
||||
BlockHash: []byte{1},
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
want := "deposit root did not verify"
|
||||
_, err = altair.ProcessDeposits(context.Background(), beaconState, []*ethpb.Deposit{deposit})
|
||||
require.ErrorContains(t, want, err)
|
||||
}
|
||||
|
||||
func TestProcessDeposits_AddsNewValidatorDeposit(t *testing.T) {
|
||||
dep, _, err := testutil.DeterministicDepositsAndKeys(1)
|
||||
require.NoError(t, err)
|
||||
eth1Data, err := testutil.DeterministicEth1Data(len(dep))
|
||||
require.NoError(t, err)
|
||||
|
||||
registry := []*ethpb.Validator{
|
||||
{
|
||||
PublicKey: []byte{1},
|
||||
WithdrawalCredentials: []byte{1, 2, 3},
|
||||
},
|
||||
}
|
||||
balances := []uint64{0}
|
||||
beaconState, err := stateAltair.InitializeFromProto(ðpb.BeaconStateAltair{
|
||||
Validators: registry,
|
||||
Balances: balances,
|
||||
Eth1Data: eth1Data,
|
||||
Fork: ðpb.Fork{
|
||||
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
newState, err := altair.ProcessDeposits(context.Background(), beaconState, []*ethpb.Deposit{dep[0]})
|
||||
require.NoError(t, err, "Expected block deposits to process correctly")
|
||||
if newState.Balances()[1] != dep[0].Data.Amount {
|
||||
t.Errorf(
|
||||
"Expected state validator balances index 0 to equal %d, received %d",
|
||||
dep[0].Data.Amount,
|
||||
newState.Balances()[1],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessDeposits_RepeatedDeposit_IncreasesValidatorBalance(t *testing.T) {
|
||||
sk, err := bls.RandKey()
|
||||
require.NoError(t, err)
|
||||
deposit := ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: sk.PublicKey().Marshal(),
|
||||
Amount: 1000,
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
}
|
||||
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 := deposit.Data.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
// We then create a merkle branch for the test.
|
||||
depositTrie, err := trieutil.GenerateTrieFromItems([][]byte{leaf[:]}, params.BeaconConfig().DepositContractTreeDepth)
|
||||
require.NoError(t, err, "Could not generate trie")
|
||||
proof, err := depositTrie.MerkleProof(0)
|
||||
require.NoError(t, err, "Could not generate proof")
|
||||
|
||||
deposit.Proof = proof
|
||||
registry := []*ethpb.Validator{
|
||||
{
|
||||
PublicKey: []byte{1, 2, 3},
|
||||
},
|
||||
{
|
||||
PublicKey: sk.PublicKey().Marshal(),
|
||||
WithdrawalCredentials: []byte{1},
|
||||
},
|
||||
}
|
||||
balances := []uint64{0, 50}
|
||||
root := depositTrie.Root()
|
||||
beaconState, err := stateAltair.InitializeFromProto(ðpb.BeaconStateAltair{
|
||||
Validators: registry,
|
||||
Balances: balances,
|
||||
Eth1Data: ðpb.Eth1Data{
|
||||
DepositRoot: root[:],
|
||||
BlockHash: root[:],
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
newState, err := altair.ProcessDeposits(context.Background(), beaconState, []*ethpb.Deposit{deposit})
|
||||
require.NoError(t, err, "Process deposit failed")
|
||||
require.Equal(t, uint64(1000+50), newState.Balances()[1], "Expected balance at index 1 to be 1050")
|
||||
}
|
||||
|
||||
func TestProcessDeposit_AddsNewValidatorDeposit(t *testing.T) {
|
||||
// Similar to TestProcessDeposits_AddsNewValidatorDeposit except that this test directly calls ProcessDeposit
|
||||
dep, _, err := testutil.DeterministicDepositsAndKeys(1)
|
||||
require.NoError(t, err)
|
||||
eth1Data, err := testutil.DeterministicEth1Data(len(dep))
|
||||
require.NoError(t, err)
|
||||
|
||||
registry := []*ethpb.Validator{
|
||||
{
|
||||
PublicKey: []byte{1},
|
||||
WithdrawalCredentials: []byte{1, 2, 3},
|
||||
},
|
||||
}
|
||||
balances := []uint64{0}
|
||||
beaconState, err := stateAltair.InitializeFromProto(ðpb.BeaconStateAltair{
|
||||
Validators: registry,
|
||||
Balances: balances,
|
||||
Eth1Data: eth1Data,
|
||||
Fork: ðpb.Fork{
|
||||
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
newState, err := altair.ProcessDeposit(context.Background(), beaconState, dep[0], true)
|
||||
require.NoError(t, err, "Process deposit failed")
|
||||
require.Equal(t, 2, len(newState.Validators()), "Expected validator list to have length 2")
|
||||
require.Equal(t, 2, len(newState.Balances()), "Expected validator balances list to have length 2")
|
||||
if newState.Balances()[1] != dep[0].Data.Amount {
|
||||
t.Errorf(
|
||||
"Expected state validator balances index 1 to equal %d, received %d",
|
||||
dep[0].Data.Amount,
|
||||
newState.Balances()[1],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessDeposit_SkipsInvalidDeposit(t *testing.T) {
|
||||
// Same test settings as in TestProcessDeposit_AddsNewValidatorDeposit, except that we use an invalid signature
|
||||
dep, _, err := testutil.DeterministicDepositsAndKeys(1)
|
||||
require.NoError(t, err)
|
||||
dep[0].Data.Signature = make([]byte, 96)
|
||||
trie, _, err := testutil.DepositTrieFromDeposits(dep)
|
||||
require.NoError(t, err)
|
||||
root := trie.Root()
|
||||
eth1Data := ðpb.Eth1Data{
|
||||
DepositRoot: root[:],
|
||||
DepositCount: 1,
|
||||
}
|
||||
registry := []*ethpb.Validator{
|
||||
{
|
||||
PublicKey: []byte{1},
|
||||
WithdrawalCredentials: []byte{1, 2, 3},
|
||||
},
|
||||
}
|
||||
balances := []uint64{0}
|
||||
beaconState, err := stateAltair.InitializeFromProto(ðpb.BeaconStateAltair{
|
||||
Validators: registry,
|
||||
Balances: balances,
|
||||
Eth1Data: eth1Data,
|
||||
Fork: ðpb.Fork{
|
||||
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
newState, err := altair.ProcessDeposit(context.Background(), beaconState, dep[0], true)
|
||||
require.NoError(t, err, "Expected invalid block deposit to be ignored without error")
|
||||
|
||||
if newState.Eth1DepositIndex() != 1 {
|
||||
t.Errorf(
|
||||
"Expected Eth1DepositIndex to be increased by 1 after processing an invalid deposit, received change: %v",
|
||||
newState.Eth1DepositIndex(),
|
||||
)
|
||||
}
|
||||
if len(newState.Validators()) != 1 {
|
||||
t.Errorf("Expected validator list to have length 1, received: %v", len(newState.Validators()))
|
||||
}
|
||||
if len(newState.Balances()) != 1 {
|
||||
t.Errorf("Expected validator balances list to have length 1, received: %v", len(newState.Balances()))
|
||||
}
|
||||
if newState.Balances()[0] != 0 {
|
||||
t.Errorf("Expected validator balance at index 0 to stay 0, received: %v", newState.Balances()[0])
|
||||
}
|
||||
}
|
||||
291
beacon-chain/core/altair/epoch_precompute.go
Normal file
291
beacon-chain/core/altair/epoch_precompute.go
Normal file
@@ -0,0 +1,291 @@
|
||||
package altair
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/epoch/precompute"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/shared/mathutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
|
||||
// InitializeEpochValidators gets called at the beginning of process epoch cycle to return
|
||||
// pre computed instances of validators attesting records and total
|
||||
// balances attested in an epoch.
|
||||
func InitializeEpochValidators(ctx context.Context, st state.BeaconStateAltair) ([]*precompute.Validator, *precompute.Balance, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "altair.InitializeEpochValidators")
|
||||
defer span.End()
|
||||
pValidators := make([]*precompute.Validator, st.NumValidators())
|
||||
bal := &precompute.Balance{}
|
||||
prevEpoch := helpers.PrevEpoch(st)
|
||||
currentEpoch := helpers.CurrentEpoch(st)
|
||||
inactivityScores, err := st.InactivityScores()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// This shouldn't happen with a correct beacon state,
|
||||
// but rather be safe to defend against index out of bound panics.
|
||||
if st.NumValidators() > len(inactivityScores) {
|
||||
return nil, nil, errors.New("num of validators can't be greater than length of inactivity scores")
|
||||
}
|
||||
if err := st.ReadFromEveryValidator(func(idx int, val state.ReadOnlyValidator) error {
|
||||
// Was validator withdrawable or slashed
|
||||
withdrawable := currentEpoch >= val.WithdrawableEpoch()
|
||||
pVal := &precompute.Validator{
|
||||
IsSlashed: val.Slashed(),
|
||||
IsWithdrawableCurrentEpoch: withdrawable,
|
||||
CurrentEpochEffectiveBalance: val.EffectiveBalance(),
|
||||
InactivityScore: inactivityScores[idx],
|
||||
}
|
||||
// Validator active current epoch
|
||||
if helpers.IsActiveValidatorUsingTrie(val, currentEpoch) {
|
||||
pVal.IsActiveCurrentEpoch = true
|
||||
bal.ActiveCurrentEpoch += val.EffectiveBalance()
|
||||
}
|
||||
// Validator active previous epoch
|
||||
if helpers.IsActiveValidatorUsingTrie(val, prevEpoch) {
|
||||
pVal.IsActivePrevEpoch = true
|
||||
bal.ActivePrevEpoch += val.EffectiveBalance()
|
||||
}
|
||||
|
||||
pValidators[idx] = pVal
|
||||
return nil
|
||||
}); err != nil {
|
||||
return nil, nil, errors.Wrap(err, "could not initialize epoch validator")
|
||||
}
|
||||
return pValidators, bal, nil
|
||||
}
|
||||
|
||||
// ProcessInactivityScores of beacon chain. This updates inactivity scores of beacon chain and
|
||||
// updates the precompute validator struct for later processing. The inactivity scores work as following:
|
||||
// For fully inactive validators and perfect active validators, the effect is the same as before Altair.
|
||||
// For a validator is inactive and the chain fails to finalize, the inactivity score increases by a fixed number, the total loss after N epochs is proportional to N**2/2.
|
||||
// For imperfectly active validators. The inactivity score's behavior is specified by this function:
|
||||
// If a validator fails to submit an attestation with the correct target, their inactivity score goes up by 4.
|
||||
// If they successfully submit an attestation with the correct source and target, their inactivity score drops by 1
|
||||
// If the chain has recently finalized, each validator's score drops by 16.
|
||||
func ProcessInactivityScores(
|
||||
ctx context.Context,
|
||||
state state.BeaconState,
|
||||
vals []*precompute.Validator,
|
||||
) (state.BeaconState, []*precompute.Validator, error) {
|
||||
cfg := params.BeaconConfig()
|
||||
if helpers.CurrentEpoch(state) == cfg.GenesisEpoch {
|
||||
return state, vals, nil
|
||||
}
|
||||
|
||||
inactivityScores, err := state.InactivityScores()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
bias := cfg.InactivityScoreBias
|
||||
recoveryRate := cfg.InactivityScoreRecoveryRate
|
||||
for i, v := range vals {
|
||||
if !precompute.EligibleForRewards(v) {
|
||||
continue
|
||||
}
|
||||
|
||||
if v.IsPrevEpochTargetAttester && !v.IsSlashed {
|
||||
// Decrease inactivity score when validator gets target correct.
|
||||
if v.InactivityScore > 0 {
|
||||
score := uint64(1)
|
||||
// Prevents underflow below 0.
|
||||
if score > v.InactivityScore {
|
||||
score = v.InactivityScore
|
||||
}
|
||||
v.InactivityScore -= score
|
||||
}
|
||||
} else {
|
||||
v.InactivityScore += bias
|
||||
}
|
||||
|
||||
if !helpers.IsInInactivityLeak(helpers.PrevEpoch(state), state.FinalizedCheckpointEpoch()) {
|
||||
score := recoveryRate
|
||||
// Prevents underflow below 0.
|
||||
if score > v.InactivityScore {
|
||||
score = v.InactivityScore
|
||||
}
|
||||
v.InactivityScore -= score
|
||||
}
|
||||
inactivityScores[i] = v.InactivityScore
|
||||
}
|
||||
|
||||
if err := state.SetInactivityScores(inactivityScores); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return state, vals, nil
|
||||
}
|
||||
|
||||
// ProcessEpochParticipation processes the epoch participation in state and updates individual validator's pre computes,
|
||||
// it also tracks and updates epoch attesting balances.
|
||||
func ProcessEpochParticipation(
|
||||
ctx context.Context,
|
||||
state state.BeaconState,
|
||||
bal *precompute.Balance,
|
||||
vals []*precompute.Validator,
|
||||
) ([]*precompute.Validator, *precompute.Balance, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "altair.ProcessEpochParticipation")
|
||||
defer span.End()
|
||||
|
||||
cp, err := state.CurrentEpochParticipation()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
cfg := params.BeaconConfig()
|
||||
targetIdx := cfg.TimelyTargetFlagIndex
|
||||
sourceIdx := cfg.TimelySourceFlagIndex
|
||||
headIdx := cfg.TimelyHeadFlagIndex
|
||||
for i, b := range cp {
|
||||
if HasValidatorFlag(b, targetIdx) {
|
||||
vals[i].IsCurrentEpochTargetAttester = true
|
||||
}
|
||||
}
|
||||
pp, err := state.PreviousEpochParticipation()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
for i, b := range pp {
|
||||
if HasValidatorFlag(b, sourceIdx) {
|
||||
vals[i].IsPrevEpochAttester = true
|
||||
}
|
||||
if HasValidatorFlag(b, targetIdx) {
|
||||
vals[i].IsPrevEpochTargetAttester = true
|
||||
}
|
||||
if HasValidatorFlag(b, headIdx) {
|
||||
vals[i].IsPrevEpochHeadAttester = true
|
||||
}
|
||||
}
|
||||
bal = precompute.UpdateBalance(vals, bal)
|
||||
return vals, bal, nil
|
||||
}
|
||||
|
||||
// ProcessRewardsAndPenaltiesPrecompute processes the rewards and penalties of individual validator.
|
||||
// This is an optimized version by passing in precomputed validator attesting records and and total epoch balances.
|
||||
func ProcessRewardsAndPenaltiesPrecompute(
|
||||
state state.BeaconStateAltair,
|
||||
bal *precompute.Balance,
|
||||
vals []*precompute.Validator,
|
||||
) (state.BeaconStateAltair, error) {
|
||||
// Don't process rewards and penalties in genesis epoch.
|
||||
if helpers.CurrentEpoch(state) == 0 {
|
||||
return state, nil
|
||||
}
|
||||
|
||||
numOfVals := state.NumValidators()
|
||||
// Guard against an out-of-bounds using validator balance precompute.
|
||||
if len(vals) != numOfVals || len(vals) != state.BalancesLength() {
|
||||
return state, errors.New("validator registries not the same length as state's validator registries")
|
||||
}
|
||||
|
||||
attsRewards, attsPenalties, err := AttestationsDelta(state, bal, vals)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get attestation delta")
|
||||
}
|
||||
|
||||
balances := state.Balances()
|
||||
for i := 0; i < numOfVals; i++ {
|
||||
vals[i].BeforeEpochTransitionBalance = balances[i]
|
||||
|
||||
// Compute the post balance of the validator after accounting for the
|
||||
// attester and proposer rewards and penalties.
|
||||
balances[i] = helpers.IncreaseBalanceWithVal(balances[i], attsRewards[i])
|
||||
balances[i] = helpers.DecreaseBalanceWithVal(balances[i], attsPenalties[i])
|
||||
|
||||
vals[i].AfterEpochTransitionBalance = balances[i]
|
||||
}
|
||||
|
||||
if err := state.SetBalances(balances); err != nil {
|
||||
return nil, errors.Wrap(err, "could not set validator balances")
|
||||
}
|
||||
|
||||
return state, nil
|
||||
}
|
||||
|
||||
// AttestationsDelta computes and returns the rewards and penalties differences for individual validators based on the
|
||||
// voting records.
|
||||
func AttestationsDelta(state state.BeaconStateAltair, bal *precompute.Balance, vals []*precompute.Validator) (rewards, penalties []uint64, err error) {
|
||||
numOfVals := state.NumValidators()
|
||||
rewards = make([]uint64, numOfVals)
|
||||
penalties = make([]uint64, numOfVals)
|
||||
prevEpoch := helpers.PrevEpoch(state)
|
||||
finalizedEpoch := state.FinalizedCheckpointEpoch()
|
||||
|
||||
cfg := params.BeaconConfig()
|
||||
increment := cfg.EffectiveBalanceIncrement
|
||||
factor := cfg.BaseRewardFactor
|
||||
baseRewardMultiplier := increment * factor / mathutil.IntegerSquareRoot(bal.ActiveCurrentEpoch)
|
||||
leak := helpers.IsInInactivityLeak(prevEpoch, finalizedEpoch)
|
||||
inactivityDenominator := cfg.InactivityScoreBias * cfg.InactivityPenaltyQuotientAltair
|
||||
|
||||
for i, v := range vals {
|
||||
rewards[i], penalties[i] = attestationDelta(bal, v, baseRewardMultiplier, inactivityDenominator, leak)
|
||||
}
|
||||
|
||||
return rewards, penalties, nil
|
||||
}
|
||||
|
||||
func attestationDelta(
|
||||
bal *precompute.Balance,
|
||||
v *precompute.Validator,
|
||||
baseRewardMultiplier, inactivityDenominator uint64,
|
||||
inactivityLeak bool) (reward, penalty uint64) {
|
||||
eligible := v.IsActivePrevEpoch || (v.IsSlashed && !v.IsWithdrawableCurrentEpoch)
|
||||
// Per spec `ActiveCurrentEpoch` can't be 0 to process attestation delta.
|
||||
if !eligible || bal.ActiveCurrentEpoch == 0 {
|
||||
return 0, 0
|
||||
}
|
||||
|
||||
cfg := params.BeaconConfig()
|
||||
increment := cfg.EffectiveBalanceIncrement
|
||||
effectiveBalance := v.CurrentEpochEffectiveBalance
|
||||
baseReward := (effectiveBalance / increment) * baseRewardMultiplier
|
||||
activeIncrement := bal.ActiveCurrentEpoch / increment
|
||||
|
||||
weightDenominator := cfg.WeightDenominator
|
||||
srcWeight := cfg.TimelySourceWeight
|
||||
tgtWeight := cfg.TimelyTargetWeight
|
||||
headWeight := cfg.TimelyHeadWeight
|
||||
reward, penalty = uint64(0), uint64(0)
|
||||
// Process source reward / penalty
|
||||
if v.IsPrevEpochAttester && !v.IsSlashed {
|
||||
if !inactivityLeak {
|
||||
n := baseReward * srcWeight * (bal.PrevEpochAttested / increment)
|
||||
reward += n / (activeIncrement * weightDenominator)
|
||||
}
|
||||
} else {
|
||||
penalty += baseReward * srcWeight / weightDenominator
|
||||
}
|
||||
|
||||
// Process target reward / penalty
|
||||
if v.IsPrevEpochTargetAttester && !v.IsSlashed {
|
||||
if !inactivityLeak {
|
||||
n := baseReward * tgtWeight * (bal.PrevEpochTargetAttested / increment)
|
||||
reward += n / (activeIncrement * weightDenominator)
|
||||
}
|
||||
} else {
|
||||
penalty += baseReward * tgtWeight / weightDenominator
|
||||
}
|
||||
|
||||
// Process head reward / penalty
|
||||
if v.IsPrevEpochHeadAttester && !v.IsSlashed {
|
||||
if !inactivityLeak {
|
||||
n := baseReward * headWeight * (bal.PrevEpochHeadAttested / increment)
|
||||
reward += n / (activeIncrement * weightDenominator)
|
||||
}
|
||||
}
|
||||
|
||||
// Process finality delay penalty
|
||||
// Apply an additional penalty to validators that did not vote on the correct target or slashed
|
||||
if !v.IsPrevEpochTargetAttester || v.IsSlashed {
|
||||
n := effectiveBalance * v.InactivityScore
|
||||
penalty += n / inactivityDenominator
|
||||
}
|
||||
|
||||
return reward, penalty
|
||||
}
|
||||
344
beacon-chain/core/altair/epoch_precompute_test.go
Normal file
344
beacon-chain/core/altair/epoch_precompute_test.go
Normal file
@@ -0,0 +1,344 @@
|
||||
package altair
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/epoch/precompute"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
stateAltair "github.com/prysmaticlabs/prysm/beacon-chain/state/v2"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
func TestInitializeEpochValidators_Ok(t *testing.T) {
|
||||
ffe := params.BeaconConfig().FarFutureEpoch
|
||||
s, err := stateAltair.InitializeFromProto(ðpb.BeaconStateAltair{
|
||||
Slot: params.BeaconConfig().SlotsPerEpoch,
|
||||
// Validator 0 is slashed
|
||||
// Validator 1 is withdrawable
|
||||
// Validator 2 is active prev epoch and current epoch
|
||||
// Validator 3 is active prev epoch
|
||||
Validators: []*ethpb.Validator{
|
||||
{Slashed: true, WithdrawableEpoch: ffe, EffectiveBalance: 100},
|
||||
{EffectiveBalance: 100},
|
||||
{WithdrawableEpoch: ffe, ExitEpoch: ffe, EffectiveBalance: 100},
|
||||
{WithdrawableEpoch: ffe, ExitEpoch: 1, EffectiveBalance: 100},
|
||||
},
|
||||
InactivityScores: []uint64{0, 1, 2, 3},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
v, b, err := InitializeEpochValidators(context.Background(), s)
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, &precompute.Validator{
|
||||
IsSlashed: true,
|
||||
CurrentEpochEffectiveBalance: 100,
|
||||
InactivityScore: 0,
|
||||
}, v[0], "Incorrect validator 0 status")
|
||||
assert.DeepEqual(t, &precompute.Validator{
|
||||
IsWithdrawableCurrentEpoch: true,
|
||||
CurrentEpochEffectiveBalance: 100,
|
||||
InactivityScore: 1,
|
||||
}, v[1], "Incorrect validator 1 status")
|
||||
assert.DeepEqual(t, &precompute.Validator{
|
||||
IsActivePrevEpoch: true,
|
||||
IsActiveCurrentEpoch: true,
|
||||
CurrentEpochEffectiveBalance: 100,
|
||||
InactivityScore: 2,
|
||||
}, v[2], "Incorrect validator 2 status")
|
||||
assert.DeepEqual(t, &precompute.Validator{
|
||||
IsActivePrevEpoch: true,
|
||||
CurrentEpochEffectiveBalance: 100,
|
||||
InactivityScore: 3,
|
||||
}, v[3], "Incorrect validator 3 status")
|
||||
|
||||
wantedBalances := &precompute.Balance{
|
||||
ActiveCurrentEpoch: 100,
|
||||
ActivePrevEpoch: 200,
|
||||
}
|
||||
assert.DeepEqual(t, wantedBalances, b, "Incorrect wanted balance")
|
||||
}
|
||||
|
||||
func TestInitializeEpochValidators_BadState(t *testing.T) {
|
||||
s, err := stateAltair.InitializeFromProto(ðpb.BeaconStateAltair{
|
||||
Validators: []*ethpb.Validator{{}},
|
||||
InactivityScores: []uint64{},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
_, _, err = InitializeEpochValidators(context.Background(), s)
|
||||
require.ErrorContains(t, "num of validators can't be greater than length of inactivity scores", err)
|
||||
}
|
||||
|
||||
func TestProcessEpochParticipation(t *testing.T) {
|
||||
s, err := testState()
|
||||
require.NoError(t, err)
|
||||
validators, balance, err := InitializeEpochValidators(context.Background(), s)
|
||||
require.NoError(t, err)
|
||||
validators, balance, err = ProcessEpochParticipation(context.Background(), s, balance, validators)
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, &precompute.Validator{
|
||||
IsActiveCurrentEpoch: true,
|
||||
IsActivePrevEpoch: true,
|
||||
IsWithdrawableCurrentEpoch: true,
|
||||
CurrentEpochEffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
|
||||
}, validators[0])
|
||||
require.DeepEqual(t, &precompute.Validator{
|
||||
IsActiveCurrentEpoch: true,
|
||||
IsActivePrevEpoch: true,
|
||||
IsWithdrawableCurrentEpoch: true,
|
||||
CurrentEpochEffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
|
||||
IsPrevEpochAttester: true,
|
||||
}, validators[1])
|
||||
require.DeepEqual(t, &precompute.Validator{
|
||||
IsActiveCurrentEpoch: true,
|
||||
IsActivePrevEpoch: true,
|
||||
IsWithdrawableCurrentEpoch: true,
|
||||
CurrentEpochEffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
|
||||
IsPrevEpochAttester: true,
|
||||
IsCurrentEpochTargetAttester: true,
|
||||
IsPrevEpochTargetAttester: true,
|
||||
}, validators[2])
|
||||
require.DeepEqual(t, &precompute.Validator{
|
||||
IsActiveCurrentEpoch: true,
|
||||
IsActivePrevEpoch: true,
|
||||
IsWithdrawableCurrentEpoch: true,
|
||||
CurrentEpochEffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
|
||||
IsPrevEpochAttester: true,
|
||||
IsCurrentEpochTargetAttester: true,
|
||||
IsPrevEpochTargetAttester: true,
|
||||
IsPrevEpochHeadAttester: true,
|
||||
}, validators[3])
|
||||
require.Equal(t, params.BeaconConfig().MaxEffectiveBalance*3, balance.PrevEpochAttested)
|
||||
require.Equal(t, balance.CurrentEpochTargetAttested, params.BeaconConfig().MaxEffectiveBalance*2)
|
||||
require.Equal(t, balance.PrevEpochTargetAttested, params.BeaconConfig().MaxEffectiveBalance*2)
|
||||
require.Equal(t, balance.PrevEpochHeadAttested, params.BeaconConfig().MaxEffectiveBalance*1)
|
||||
}
|
||||
|
||||
func TestAttestationsDelta(t *testing.T) {
|
||||
s, err := testState()
|
||||
require.NoError(t, err)
|
||||
validators, balance, err := InitializeEpochValidators(context.Background(), s)
|
||||
require.NoError(t, err)
|
||||
validators, balance, err = ProcessEpochParticipation(context.Background(), s, balance, validators)
|
||||
require.NoError(t, err)
|
||||
rewards, penalties, err := AttestationsDelta(s, balance, validators)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Reward amount should increase as validator index increases due to setup.
|
||||
for i := 1; i < len(rewards); i++ {
|
||||
require.Equal(t, true, rewards[i] > rewards[i-1])
|
||||
}
|
||||
|
||||
// Penalty amount should decrease as validator index increases due to setup.
|
||||
for i := 1; i < len(penalties); i++ {
|
||||
require.Equal(t, true, penalties[i] <= penalties[i-1])
|
||||
}
|
||||
|
||||
// First index should have 0 reward.
|
||||
require.Equal(t, uint64(0), rewards[0])
|
||||
// Last index should have 0 penalty.
|
||||
require.Equal(t, uint64(0), penalties[len(penalties)-1])
|
||||
}
|
||||
|
||||
func TestProcessRewardsAndPenaltiesPrecompute_Ok(t *testing.T) {
|
||||
s, err := testState()
|
||||
require.NoError(t, err)
|
||||
validators, balance, err := InitializeEpochValidators(context.Background(), s)
|
||||
require.NoError(t, err)
|
||||
validators, balance, err = ProcessEpochParticipation(context.Background(), s, balance, validators)
|
||||
require.NoError(t, err)
|
||||
s, err = ProcessRewardsAndPenaltiesPrecompute(s, balance, validators)
|
||||
require.NoError(t, err)
|
||||
|
||||
balances := s.Balances()
|
||||
// Reward amount should increase as validator index increases due to setup.
|
||||
for i := 1; i < len(balances); i++ {
|
||||
require.Equal(t, true, balances[i] >= balances[i-1])
|
||||
}
|
||||
|
||||
wanted := make([]uint64, s.NumValidators())
|
||||
rewards, penalties, err := AttestationsDelta(s, balance, validators)
|
||||
require.NoError(t, err)
|
||||
for i := range rewards {
|
||||
wanted[i] += rewards[i]
|
||||
}
|
||||
for i := range penalties {
|
||||
if wanted[i] > penalties[i] {
|
||||
wanted[i] -= penalties[i]
|
||||
} else {
|
||||
wanted[i] = 0
|
||||
}
|
||||
}
|
||||
require.DeepEqual(t, wanted, balances)
|
||||
}
|
||||
|
||||
func TestProcessRewardsAndPenaltiesPrecompute_InactivityLeak(t *testing.T) {
|
||||
s, err := testState()
|
||||
require.NoError(t, err)
|
||||
validators, balance, err := InitializeEpochValidators(context.Background(), s)
|
||||
require.NoError(t, err)
|
||||
validators, balance, err = ProcessEpochParticipation(context.Background(), s, balance, validators)
|
||||
require.NoError(t, err)
|
||||
sCopy := s.Copy()
|
||||
s, err = ProcessRewardsAndPenaltiesPrecompute(s, balance, validators)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Copied state where finality happened long ago
|
||||
require.NoError(t, sCopy.SetSlot(params.BeaconConfig().SlotsPerEpoch*1000))
|
||||
sCopy, err = ProcessRewardsAndPenaltiesPrecompute(sCopy, balance, validators)
|
||||
require.NoError(t, err)
|
||||
|
||||
balances := s.Balances()
|
||||
inactivityBalances := sCopy.Balances()
|
||||
// Balances decreased to 0 due to inactivity
|
||||
require.Equal(t, uint64(2101898), balances[2])
|
||||
require.Equal(t, uint64(2414946), balances[3])
|
||||
require.Equal(t, uint64(0), inactivityBalances[2])
|
||||
require.Equal(t, uint64(0), inactivityBalances[3])
|
||||
}
|
||||
|
||||
func TestProcessInactivityScores_CanProcessInactivityLeak(t *testing.T) {
|
||||
s, err := testState()
|
||||
require.NoError(t, err)
|
||||
defaultScore := uint64(5)
|
||||
require.NoError(t, s.SetInactivityScores([]uint64{defaultScore, defaultScore, defaultScore, defaultScore}))
|
||||
require.NoError(t, s.SetSlot(params.BeaconConfig().SlotsPerEpoch*types.Slot(params.BeaconConfig().MinEpochsToInactivityPenalty+2)))
|
||||
validators, balance, err := InitializeEpochValidators(context.Background(), s)
|
||||
require.NoError(t, err)
|
||||
validators, _, err = ProcessEpochParticipation(context.Background(), s, balance, validators)
|
||||
require.NoError(t, err)
|
||||
s, _, err = ProcessInactivityScores(context.Background(), s, validators)
|
||||
require.NoError(t, err)
|
||||
inactivityScores, err := s.InactivityScores()
|
||||
require.NoError(t, err)
|
||||
// V0 and V1 didn't vote head. V2 and V3 did.
|
||||
require.Equal(t, defaultScore+params.BeaconConfig().InactivityScoreBias, inactivityScores[0])
|
||||
require.Equal(t, defaultScore+params.BeaconConfig().InactivityScoreBias, inactivityScores[1])
|
||||
require.Equal(t, defaultScore-1, inactivityScores[2])
|
||||
require.Equal(t, defaultScore-1, inactivityScores[3])
|
||||
}
|
||||
|
||||
func TestProcessInactivityScores_CanProcessNonInactivityLeak(t *testing.T) {
|
||||
s, err := testState()
|
||||
require.NoError(t, err)
|
||||
defaultScore := uint64(5)
|
||||
require.NoError(t, s.SetInactivityScores([]uint64{defaultScore, defaultScore, defaultScore, defaultScore}))
|
||||
validators, balance, err := InitializeEpochValidators(context.Background(), s)
|
||||
require.NoError(t, err)
|
||||
validators, _, err = ProcessEpochParticipation(context.Background(), s, balance, validators)
|
||||
require.NoError(t, err)
|
||||
s, _, err = ProcessInactivityScores(context.Background(), s, validators)
|
||||
require.NoError(t, err)
|
||||
inactivityScores, err := s.InactivityScores()
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, uint64(0), inactivityScores[0])
|
||||
require.Equal(t, uint64(0), inactivityScores[1])
|
||||
require.Equal(t, uint64(0), inactivityScores[2])
|
||||
require.Equal(t, uint64(0), inactivityScores[3])
|
||||
}
|
||||
|
||||
func TestProcessRewardsAndPenaltiesPrecompute_GenesisEpoch(t *testing.T) {
|
||||
s, err := testState()
|
||||
require.NoError(t, err)
|
||||
validators, balance, err := InitializeEpochValidators(context.Background(), s)
|
||||
require.NoError(t, err)
|
||||
validators, balance, err = ProcessEpochParticipation(context.Background(), s, balance, validators)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, s.SetSlot(0))
|
||||
s, err = ProcessRewardsAndPenaltiesPrecompute(s, balance, validators)
|
||||
require.NoError(t, err)
|
||||
|
||||
balances := s.Balances()
|
||||
// Nothing should happen at genesis epoch
|
||||
require.Equal(t, uint64(0), balances[0])
|
||||
for i := 1; i < len(balances); i++ {
|
||||
require.Equal(t, true, balances[i] == balances[i-1])
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessRewardsAndPenaltiesPrecompute_BadState(t *testing.T) {
|
||||
s, err := testState()
|
||||
require.NoError(t, err)
|
||||
validators, balance, err := InitializeEpochValidators(context.Background(), s)
|
||||
require.NoError(t, err)
|
||||
_, balance, err = ProcessEpochParticipation(context.Background(), s, balance, validators)
|
||||
require.NoError(t, err)
|
||||
_, err = ProcessRewardsAndPenaltiesPrecompute(s, balance, []*precompute.Validator{})
|
||||
require.ErrorContains(t, "validator registries not the same length as state's validator registries", err)
|
||||
}
|
||||
|
||||
func TestProcessInactivityScores_NonEligibleValidator(t *testing.T) {
|
||||
s, err := testState()
|
||||
require.NoError(t, err)
|
||||
defaultScore := uint64(5)
|
||||
require.NoError(t, s.SetInactivityScores([]uint64{defaultScore, defaultScore, defaultScore, defaultScore}))
|
||||
validators, balance, err := InitializeEpochValidators(context.Background(), s)
|
||||
require.NoError(t, err)
|
||||
|
||||
// v0 is eligible (not active previous epoch, slashed and not withdrawable)
|
||||
validators[0].IsActivePrevEpoch = false
|
||||
validators[0].IsSlashed = true
|
||||
validators[0].IsWithdrawableCurrentEpoch = false
|
||||
|
||||
// v1 is not eligible (not active previous epoch, not slashed and not withdrawable)
|
||||
validators[1].IsActivePrevEpoch = false
|
||||
validators[1].IsSlashed = false
|
||||
validators[1].IsWithdrawableCurrentEpoch = false
|
||||
|
||||
// v2 is not eligible (not active previous epoch, slashed and withdrawable)
|
||||
validators[2].IsActivePrevEpoch = false
|
||||
validators[2].IsSlashed = true
|
||||
validators[2].IsWithdrawableCurrentEpoch = true
|
||||
|
||||
// v3 is eligible (active previous epoch)
|
||||
validators[3].IsActivePrevEpoch = true
|
||||
|
||||
validators, _, err = ProcessEpochParticipation(context.Background(), s, balance, validators)
|
||||
require.NoError(t, err)
|
||||
s, _, err = ProcessInactivityScores(context.Background(), s, validators)
|
||||
require.NoError(t, err)
|
||||
inactivityScores, err := s.InactivityScores()
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, uint64(0), inactivityScores[0])
|
||||
require.Equal(t, defaultScore, inactivityScores[1]) // Should remain unchanged
|
||||
require.Equal(t, defaultScore, inactivityScores[2]) // Should remain unchanged
|
||||
require.Equal(t, uint64(0), inactivityScores[3])
|
||||
}
|
||||
|
||||
func testState() (state.BeaconState, error) {
|
||||
generateParticipation := func(flags ...uint8) byte {
|
||||
b := byte(0)
|
||||
for _, flag := range flags {
|
||||
b = AddValidatorFlag(b, flag)
|
||||
}
|
||||
return b
|
||||
}
|
||||
return stateAltair.InitializeFromProto(ðpb.BeaconStateAltair{
|
||||
Slot: 2 * params.BeaconConfig().SlotsPerEpoch,
|
||||
Validators: []*ethpb.Validator{
|
||||
{EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance, ExitEpoch: params.BeaconConfig().FarFutureEpoch},
|
||||
{EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance, ExitEpoch: params.BeaconConfig().FarFutureEpoch},
|
||||
{EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance, ExitEpoch: params.BeaconConfig().FarFutureEpoch},
|
||||
{EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance, ExitEpoch: params.BeaconConfig().FarFutureEpoch},
|
||||
},
|
||||
CurrentEpochParticipation: []byte{
|
||||
0,
|
||||
generateParticipation(params.BeaconConfig().TimelySourceFlagIndex),
|
||||
generateParticipation(params.BeaconConfig().TimelySourceFlagIndex, params.BeaconConfig().TimelyTargetFlagIndex),
|
||||
generateParticipation(params.BeaconConfig().TimelySourceFlagIndex, params.BeaconConfig().TimelyTargetFlagIndex, params.BeaconConfig().TimelyHeadFlagIndex),
|
||||
},
|
||||
PreviousEpochParticipation: []byte{
|
||||
0,
|
||||
generateParticipation(params.BeaconConfig().TimelySourceFlagIndex),
|
||||
generateParticipation(params.BeaconConfig().TimelySourceFlagIndex, params.BeaconConfig().TimelyTargetFlagIndex),
|
||||
generateParticipation(params.BeaconConfig().TimelySourceFlagIndex, params.BeaconConfig().TimelyTargetFlagIndex, params.BeaconConfig().TimelyHeadFlagIndex),
|
||||
},
|
||||
InactivityScores: []uint64{0, 0, 0, 0},
|
||||
Balances: []uint64{0, 0, 0, 0},
|
||||
})
|
||||
}
|
||||
116
beacon-chain/core/altair/epoch_spec.go
Normal file
116
beacon-chain/core/altair/epoch_spec.go
Normal file
@@ -0,0 +1,116 @@
|
||||
package altair
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/shared/mathutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
// ProcessSyncCommitteeUpdates processes sync client committee updates for the beacon state.
|
||||
//
|
||||
// Spec code:
|
||||
// def process_sync_committee_updates(state: BeaconState) -> None:
|
||||
// next_epoch = get_current_epoch(state) + Epoch(1)
|
||||
// if next_epoch % EPOCHS_PER_SYNC_COMMITTEE_PERIOD == 0:
|
||||
// state.current_sync_committee = state.next_sync_committee
|
||||
// state.next_sync_committee = get_next_sync_committee(state)
|
||||
func ProcessSyncCommitteeUpdates(ctx context.Context, beaconState state.BeaconStateAltair) (state.BeaconStateAltair, error) {
|
||||
nextEpoch := helpers.NextEpoch(beaconState)
|
||||
if nextEpoch%params.BeaconConfig().EpochsPerSyncCommitteePeriod == 0 {
|
||||
currentSyncCommittee, err := beaconState.NextSyncCommittee()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := beaconState.SetCurrentSyncCommittee(currentSyncCommittee); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nextCommittee, err := NextSyncCommittee(ctx, beaconState)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := beaconState.SetNextSyncCommittee(nextCommittee); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := helpers.UpdateSyncCommitteeCache(beaconState); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return beaconState, nil
|
||||
}
|
||||
|
||||
// ProcessParticipationFlagUpdates processes participation flag updates by rotating current to previous.
|
||||
//
|
||||
// Spec code:
|
||||
// def process_participation_flag_updates(state: BeaconState) -> None:
|
||||
// state.previous_epoch_participation = state.current_epoch_participation
|
||||
// state.current_epoch_participation = [ParticipationFlags(0b0000_0000) for _ in range(len(state.validators))]
|
||||
func ProcessParticipationFlagUpdates(beaconState state.BeaconStateAltair) (state.BeaconStateAltair, error) {
|
||||
c, err := beaconState.CurrentEpochParticipation()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := beaconState.SetPreviousParticipationBits(c); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := beaconState.SetCurrentParticipationBits(make([]byte, beaconState.NumValidators())); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return beaconState, nil
|
||||
}
|
||||
|
||||
// ProcessSlashings processes the slashed validators during epoch processing,
|
||||
// The function is modified to use PROPORTIONAL_SLASHING_MULTIPLIER_ALTAIR.
|
||||
//
|
||||
// Spec code:
|
||||
// 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_ALTAIR, 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 * adjusted_total_slashing_balance
|
||||
// penalty = penalty_numerator // total_balance * increment
|
||||
// decrease_balance(state, ValidatorIndex(index), penalty)
|
||||
// decrease_balance(state, ValidatorIndex(index), penalty)
|
||||
func ProcessSlashings(state state.BeaconState) (state.BeaconState, error) {
|
||||
currentEpoch := helpers.CurrentEpoch(state)
|
||||
totalBalance, err := helpers.TotalActiveBalance(state)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get total active balance")
|
||||
}
|
||||
|
||||
// Compute slashed balances in the current epoch
|
||||
exitLength := params.BeaconConfig().EpochsPerSlashingsVector
|
||||
|
||||
// Compute the sum of state slashings
|
||||
slashings := state.Slashings()
|
||||
totalSlashing := uint64(0)
|
||||
for _, slashing := range slashings {
|
||||
totalSlashing += slashing
|
||||
}
|
||||
|
||||
// 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().ProportionalSlashingMultiplierAltair, totalBalance)
|
||||
err = state.ApplyToEveryValidator(func(idx int, val *ethpb.Validator) (bool, *ethpb.Validator, error) {
|
||||
correctEpoch := (currentEpoch + exitLength/2) == val.WithdrawableEpoch
|
||||
if val.Slashed && correctEpoch {
|
||||
penaltyNumerator := val.EffectiveBalance / increment * minSlashing
|
||||
penalty := penaltyNumerator / totalBalance * increment
|
||||
if err := helpers.DecreaseBalance(state, types.ValidatorIndex(idx), penalty); err != nil {
|
||||
return false, val, err
|
||||
}
|
||||
return true, val, nil
|
||||
}
|
||||
return false, val, nil
|
||||
})
|
||||
return state, err
|
||||
}
|
||||
181
beacon-chain/core/altair/epoch_spec_test.go
Normal file
181
beacon-chain/core/altair/epoch_spec_test.go
Normal file
@@ -0,0 +1,181 @@
|
||||
package altair_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/altair"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
stateAltair "github.com/prysmaticlabs/prysm/beacon-chain/state/v2"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"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"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
func TestProcessSyncCommitteeUpdates_CanRotate(t *testing.T) {
|
||||
s, _ := testutil.DeterministicGenesisStateAltair(t, params.BeaconConfig().MaxValidatorsPerCommittee)
|
||||
h := ðpb.BeaconBlockHeader{
|
||||
StateRoot: bytesutil.PadTo([]byte{'a'}, 32),
|
||||
ParentRoot: bytesutil.PadTo([]byte{'b'}, 32),
|
||||
BodyRoot: bytesutil.PadTo([]byte{'c'}, 32),
|
||||
}
|
||||
require.NoError(t, s.SetLatestBlockHeader(h))
|
||||
postState, err := altair.ProcessSyncCommitteeUpdates(context.Background(), s)
|
||||
require.NoError(t, err)
|
||||
current, err := postState.CurrentSyncCommittee()
|
||||
require.NoError(t, err)
|
||||
next, err := postState.NextSyncCommittee()
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, current, next)
|
||||
|
||||
require.NoError(t, s.SetSlot(params.BeaconConfig().SlotsPerEpoch))
|
||||
postState, err = altair.ProcessSyncCommitteeUpdates(context.Background(), s)
|
||||
require.NoError(t, err)
|
||||
c, err := postState.CurrentSyncCommittee()
|
||||
require.NoError(t, err)
|
||||
n, err := postState.NextSyncCommittee()
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, current, c)
|
||||
require.DeepEqual(t, next, n)
|
||||
|
||||
require.NoError(t, s.SetSlot(types.Slot(params.BeaconConfig().EpochsPerSyncCommitteePeriod)*params.BeaconConfig().SlotsPerEpoch-1))
|
||||
postState, err = altair.ProcessSyncCommitteeUpdates(context.Background(), s)
|
||||
require.NoError(t, err)
|
||||
c, err = postState.CurrentSyncCommittee()
|
||||
require.NoError(t, err)
|
||||
n, err = postState.NextSyncCommittee()
|
||||
require.NoError(t, err)
|
||||
require.NotEqual(t, current, c)
|
||||
require.NotEqual(t, next, n)
|
||||
require.DeepEqual(t, next, c)
|
||||
|
||||
// Test boundary condition.
|
||||
slot := params.BeaconConfig().SlotsPerEpoch * types.Slot(helpers.CurrentEpoch(s)+params.BeaconConfig().EpochsPerSyncCommitteePeriod)
|
||||
require.NoError(t, s.SetSlot(slot))
|
||||
boundaryCommittee, err := altair.NextSyncCommittee(context.Background(), s)
|
||||
require.NoError(t, err)
|
||||
require.DeepNotEqual(t, boundaryCommittee, n)
|
||||
}
|
||||
|
||||
func TestProcessParticipationFlagUpdates_CanRotate(t *testing.T) {
|
||||
s, _ := testutil.DeterministicGenesisStateAltair(t, params.BeaconConfig().MaxValidatorsPerCommittee)
|
||||
c, err := s.CurrentEpochParticipation()
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, make([]byte, params.BeaconConfig().MaxValidatorsPerCommittee), c)
|
||||
p, err := s.PreviousEpochParticipation()
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, make([]byte, params.BeaconConfig().MaxValidatorsPerCommittee), p)
|
||||
|
||||
newC := []byte{'a'}
|
||||
newP := []byte{'b'}
|
||||
require.NoError(t, s.SetCurrentParticipationBits(newC))
|
||||
require.NoError(t, s.SetPreviousParticipationBits(newP))
|
||||
c, err = s.CurrentEpochParticipation()
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, newC, c)
|
||||
p, err = s.PreviousEpochParticipation()
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, newP, p)
|
||||
|
||||
s, err = altair.ProcessParticipationFlagUpdates(s)
|
||||
require.NoError(t, err)
|
||||
c, err = s.CurrentEpochParticipation()
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, make([]byte, params.BeaconConfig().MaxValidatorsPerCommittee), c)
|
||||
p, err = s.PreviousEpochParticipation()
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, newC, p)
|
||||
}
|
||||
|
||||
func TestProcessSlashings_NotSlashed(t *testing.T) {
|
||||
base := ðpb.BeaconStateAltair{
|
||||
Slot: 0,
|
||||
Validators: []*ethpb.Validator{{Slashed: true}},
|
||||
Balances: []uint64{params.BeaconConfig().MaxEffectiveBalance},
|
||||
Slashings: []uint64{0, 1e9},
|
||||
}
|
||||
s, err := stateAltair.InitializeFromProto(base)
|
||||
require.NoError(t, err)
|
||||
newState, err := altair.ProcessSlashings(s)
|
||||
require.NoError(t, err)
|
||||
wanted := params.BeaconConfig().MaxEffectiveBalance
|
||||
assert.Equal(t, wanted, newState.Balances()[0], "Unexpected slashed balance")
|
||||
}
|
||||
|
||||
func TestProcessSlashings_SlashedLess(t *testing.T) {
|
||||
tests := []struct {
|
||||
state *ethpb.BeaconStateAltair
|
||||
want uint64
|
||||
}{
|
||||
{
|
||||
state: ðpb.BeaconStateAltair{
|
||||
Validators: []*ethpb.Validator{
|
||||
{Slashed: true,
|
||||
WithdrawableEpoch: params.BeaconConfig().EpochsPerSlashingsVector / 2,
|
||||
EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance},
|
||||
{ExitEpoch: params.BeaconConfig().FarFutureEpoch, EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance}},
|
||||
Balances: []uint64{params.BeaconConfig().MaxEffectiveBalance, params.BeaconConfig().MaxEffectiveBalance},
|
||||
Slashings: []uint64{0, 1e9},
|
||||
},
|
||||
want: uint64(30000000000),
|
||||
},
|
||||
{
|
||||
state: ðpb.BeaconStateAltair{
|
||||
Validators: []*ethpb.Validator{
|
||||
{Slashed: true,
|
||||
WithdrawableEpoch: params.BeaconConfig().EpochsPerSlashingsVector / 2,
|
||||
EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance},
|
||||
{ExitEpoch: params.BeaconConfig().FarFutureEpoch, EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance},
|
||||
{ExitEpoch: params.BeaconConfig().FarFutureEpoch, EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance},
|
||||
},
|
||||
Balances: []uint64{params.BeaconConfig().MaxEffectiveBalance, params.BeaconConfig().MaxEffectiveBalance},
|
||||
Slashings: []uint64{0, 1e9},
|
||||
},
|
||||
want: uint64(31000000000),
|
||||
},
|
||||
{
|
||||
state: ðpb.BeaconStateAltair{
|
||||
Validators: []*ethpb.Validator{
|
||||
{Slashed: true,
|
||||
WithdrawableEpoch: params.BeaconConfig().EpochsPerSlashingsVector / 2,
|
||||
EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance},
|
||||
{ExitEpoch: params.BeaconConfig().FarFutureEpoch, EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance},
|
||||
{ExitEpoch: params.BeaconConfig().FarFutureEpoch, EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance},
|
||||
},
|
||||
Balances: []uint64{params.BeaconConfig().MaxEffectiveBalance, params.BeaconConfig().MaxEffectiveBalance},
|
||||
Slashings: []uint64{0, 2 * 1e9},
|
||||
},
|
||||
want: uint64(30000000000),
|
||||
},
|
||||
{
|
||||
state: ðpb.BeaconStateAltair{
|
||||
Validators: []*ethpb.Validator{
|
||||
{Slashed: true,
|
||||
WithdrawableEpoch: params.BeaconConfig().EpochsPerSlashingsVector / 2,
|
||||
EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance - params.BeaconConfig().EffectiveBalanceIncrement},
|
||||
{ExitEpoch: params.BeaconConfig().FarFutureEpoch, EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance - params.BeaconConfig().EffectiveBalanceIncrement}},
|
||||
Balances: []uint64{params.BeaconConfig().MaxEffectiveBalance - params.BeaconConfig().EffectiveBalanceIncrement, params.BeaconConfig().MaxEffectiveBalance - params.BeaconConfig().EffectiveBalanceIncrement},
|
||||
Slashings: []uint64{0, 1e9},
|
||||
},
|
||||
want: uint64(29000000000),
|
||||
},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
t.Run(fmt.Sprint(i), func(t *testing.T) {
|
||||
helpers.ClearCache()
|
||||
original := proto.Clone(tt.state)
|
||||
s, err := stateAltair.InitializeFromProto(tt.state)
|
||||
require.NoError(t, err)
|
||||
newState, err := altair.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])
|
||||
})
|
||||
}
|
||||
}
|
||||
60
beacon-chain/core/altair/reward.go
Normal file
60
beacon-chain/core/altair/reward.go
Normal file
@@ -0,0 +1,60 @@
|
||||
package altair
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/shared/mathutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
// BaseReward takes state and validator index and calculate
|
||||
// individual validator's base reward.
|
||||
//
|
||||
// Spec code:
|
||||
// def get_base_reward(state: BeaconState, index: ValidatorIndex) -> Gwei:
|
||||
// """
|
||||
// Return the base reward for the validator defined by ``index`` with respect to the current ``state``.
|
||||
//
|
||||
// Note: An optimally performing validator can earn one base reward per epoch over a long time horizon.
|
||||
// This takes into account both per-epoch (e.g. attestation) and intermittent duties (e.g. block proposal
|
||||
// and sync committees).
|
||||
// """
|
||||
// increments = state.validators[index].effective_balance // EFFECTIVE_BALANCE_INCREMENT
|
||||
// return Gwei(increments * get_base_reward_per_increment(state))
|
||||
func BaseReward(s state.ReadOnlyBeaconState, index types.ValidatorIndex) (uint64, error) {
|
||||
totalBalance, err := helpers.TotalActiveBalance(s)
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "could not calculate active balance")
|
||||
}
|
||||
return BaseRewardWithTotalBalance(s, index, totalBalance)
|
||||
}
|
||||
|
||||
// BaseRewardWithTotalBalance calculates the base reward with the provided total balance.
|
||||
func BaseRewardWithTotalBalance(s state.ReadOnlyBeaconState, index types.ValidatorIndex, totalBalance uint64) (uint64, error) {
|
||||
val, err := s.ValidatorAtIndexReadOnly(index)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
cfg := params.BeaconConfig()
|
||||
increments := val.EffectiveBalance() / cfg.EffectiveBalanceIncrement
|
||||
baseRewardPerInc, err := BaseRewardPerIncrement(totalBalance)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return increments * baseRewardPerInc, nil
|
||||
}
|
||||
|
||||
// BaseRewardPerIncrement of the beacon state
|
||||
//
|
||||
// Spec code:
|
||||
// def get_base_reward_per_increment(state: BeaconState) -> Gwei:
|
||||
// return Gwei(EFFECTIVE_BALANCE_INCREMENT * BASE_REWARD_FACTOR // integer_squareroot(get_total_active_balance(state)))
|
||||
func BaseRewardPerIncrement(activeBalance uint64) (uint64, error) {
|
||||
if activeBalance == 0 {
|
||||
return 0, errors.New("active balance can't be 0")
|
||||
}
|
||||
cfg := params.BeaconConfig()
|
||||
return cfg.EffectiveBalanceIncrement * cfg.BaseRewardFactor / mathutil.IntegerSquareRoot(activeBalance), nil
|
||||
}
|
||||
193
beacon-chain/core/altair/reward_test.go
Normal file
193
beacon-chain/core/altair/reward_test.go
Normal file
@@ -0,0 +1,193 @@
|
||||
package altair_test
|
||||
|
||||
import (
|
||||
"math"
|
||||
"testing"
|
||||
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/altair"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
func Test_BaseReward(t *testing.T) {
|
||||
genState := func(valCount uint64) state.ReadOnlyBeaconState {
|
||||
s, _ := testutil.DeterministicGenesisStateAltair(t, valCount)
|
||||
return s
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
valIdx types.ValidatorIndex
|
||||
st state.ReadOnlyBeaconState
|
||||
want uint64
|
||||
errString string
|
||||
}{
|
||||
{
|
||||
name: "unknown validator",
|
||||
valIdx: 2,
|
||||
st: genState(1),
|
||||
want: 0,
|
||||
errString: "index 2 out of range",
|
||||
},
|
||||
{
|
||||
name: "active balance is 32eth",
|
||||
valIdx: 0,
|
||||
st: genState(1),
|
||||
want: 11448672,
|
||||
errString: "",
|
||||
},
|
||||
{
|
||||
name: "active balance is 32eth * target committee size",
|
||||
valIdx: 0,
|
||||
st: genState(params.BeaconConfig().TargetCommitteeSize),
|
||||
want: 1011904,
|
||||
errString: "",
|
||||
},
|
||||
{
|
||||
name: "active balance is 32eth * max validator per committee size",
|
||||
valIdx: 0,
|
||||
st: genState(params.BeaconConfig().MaxValidatorsPerCommittee),
|
||||
want: 252960,
|
||||
errString: "",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := altair.BaseReward(tt.st, tt.valIdx)
|
||||
if (err != nil) && (tt.errString != "") {
|
||||
require.ErrorContains(t, tt.errString, err)
|
||||
return
|
||||
}
|
||||
require.Equal(t, tt.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_BaseRewardWithTotalBalance(t *testing.T) {
|
||||
s, _ := testutil.DeterministicGenesisStateAltair(t, 1)
|
||||
tests := []struct {
|
||||
name string
|
||||
valIdx types.ValidatorIndex
|
||||
activeBalance uint64
|
||||
want uint64
|
||||
errString string
|
||||
}{
|
||||
{
|
||||
name: "active balance is 0",
|
||||
valIdx: 0,
|
||||
activeBalance: 0,
|
||||
want: 0,
|
||||
errString: "active balance can't be 0",
|
||||
},
|
||||
{
|
||||
name: "unknown validator",
|
||||
valIdx: 2,
|
||||
activeBalance: 1,
|
||||
want: 0,
|
||||
errString: "index 2 out of range",
|
||||
},
|
||||
{
|
||||
name: "active balance is 1",
|
||||
valIdx: 0,
|
||||
activeBalance: 1,
|
||||
want: 2048000000000,
|
||||
errString: "",
|
||||
},
|
||||
{
|
||||
name: "active balance is 1eth",
|
||||
valIdx: 0,
|
||||
activeBalance: params.BeaconConfig().EffectiveBalanceIncrement,
|
||||
want: 64765024,
|
||||
errString: "",
|
||||
},
|
||||
{
|
||||
name: "active balance is 32eth",
|
||||
valIdx: 0,
|
||||
activeBalance: params.BeaconConfig().MaxEffectiveBalance,
|
||||
want: 11448672,
|
||||
errString: "",
|
||||
},
|
||||
{
|
||||
name: "active balance is 32eth * 1m validators",
|
||||
valIdx: 0,
|
||||
activeBalance: params.BeaconConfig().MaxEffectiveBalance * 1e9,
|
||||
want: 544,
|
||||
errString: "",
|
||||
},
|
||||
{
|
||||
name: "active balance is max uint64",
|
||||
valIdx: 0,
|
||||
activeBalance: math.MaxUint64,
|
||||
want: 448,
|
||||
errString: "",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := altair.BaseRewardWithTotalBalance(s, tt.valIdx, tt.activeBalance)
|
||||
if (err != nil) && (tt.errString != "") {
|
||||
require.ErrorContains(t, tt.errString, err)
|
||||
return
|
||||
}
|
||||
require.Equal(t, tt.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_BaseRewardPerIncrement(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
activeBalance uint64
|
||||
want uint64
|
||||
errString string
|
||||
}{
|
||||
{
|
||||
name: "active balance is 0",
|
||||
activeBalance: 0,
|
||||
want: 0,
|
||||
errString: "active balance can't be 0",
|
||||
},
|
||||
{
|
||||
name: "active balance is 1",
|
||||
activeBalance: 1,
|
||||
want: 64000000000,
|
||||
errString: "",
|
||||
},
|
||||
{
|
||||
name: "active balance is 1eth",
|
||||
activeBalance: params.BeaconConfig().EffectiveBalanceIncrement,
|
||||
want: 2023907,
|
||||
errString: "",
|
||||
},
|
||||
{
|
||||
name: "active balance is 32eth",
|
||||
activeBalance: params.BeaconConfig().MaxEffectiveBalance,
|
||||
want: 357771,
|
||||
errString: "",
|
||||
},
|
||||
{
|
||||
name: "active balance is 32eth * 1m validators",
|
||||
activeBalance: params.BeaconConfig().MaxEffectiveBalance * 1e9,
|
||||
want: 17,
|
||||
errString: "",
|
||||
},
|
||||
{
|
||||
name: "active balance is max uint64",
|
||||
activeBalance: math.MaxUint64,
|
||||
want: 14,
|
||||
errString: "",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := altair.BaseRewardPerIncrement(tt.activeBalance)
|
||||
if (err != nil) && (tt.errString != "") {
|
||||
require.ErrorContains(t, tt.errString, err)
|
||||
return
|
||||
}
|
||||
require.Equal(t, tt.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
221
beacon-chain/core/altair/sync_committee.go
Normal file
221
beacon-chain/core/altair/sync_committee.go
Normal file
@@ -0,0 +1,221 @@
|
||||
package altair
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/hashutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/mathutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
const maxRandomByte = uint64(1<<8 - 1)
|
||||
|
||||
// ValidateNilSyncContribution validates the following fields are not nil:
|
||||
// -the contribution and proof itself
|
||||
// -the message within contribution and proof
|
||||
// -the contribution within contribution and proof
|
||||
// -the aggregation bits within contribution
|
||||
func ValidateNilSyncContribution(s *ethpb.SignedContributionAndProof) error {
|
||||
if s == nil {
|
||||
return errors.New("signed message can't be nil")
|
||||
}
|
||||
if s.Message == nil {
|
||||
return errors.New("signed contribution's message can't be nil")
|
||||
}
|
||||
if s.Message.Contribution == nil {
|
||||
return errors.New("inner contribution can't be nil")
|
||||
}
|
||||
if s.Message.Contribution.AggregationBits == nil {
|
||||
return errors.New("contribution's bitfield can't be nil")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NextSyncCommittee returns the next sync committee for a given state.
|
||||
//
|
||||
// Spec code:
|
||||
// def get_next_sync_committee(state: BeaconState) -> SyncCommittee:
|
||||
// """
|
||||
// Return the next sync committee, with possible pubkey duplicates.
|
||||
// """
|
||||
// indices = get_next_sync_committee_indices(state)
|
||||
// pubkeys = [state.validators[index].pubkey for index in indices]
|
||||
// aggregate_pubkey = bls.AggregatePKs(pubkeys)
|
||||
// return SyncCommittee(pubkeys=pubkeys, aggregate_pubkey=aggregate_pubkey)
|
||||
func NextSyncCommittee(ctx context.Context, s state.BeaconStateAltair) (*ethpb.SyncCommittee, error) {
|
||||
indices, err := NextSyncCommitteeIndices(ctx, s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pubkeys := make([][]byte, len(indices))
|
||||
for i, index := range indices {
|
||||
p := s.PubkeyAtIndex(index)
|
||||
pubkeys[i] = p[:]
|
||||
}
|
||||
aggregated, err := bls.AggregatePublicKeys(pubkeys)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ðpb.SyncCommittee{
|
||||
Pubkeys: pubkeys,
|
||||
AggregatePubkey: aggregated.Marshal(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// NextSyncCommitteeIndices returns the next sync committee indices for a given state.
|
||||
//
|
||||
// Spec code:
|
||||
// def get_next_sync_committee_indices(state: BeaconState) -> Sequence[ValidatorIndex]:
|
||||
// """
|
||||
// Return the sync committee indices, with possible duplicates, for the next sync committee.
|
||||
// """
|
||||
// epoch = Epoch(get_current_epoch(state) + 1)
|
||||
//
|
||||
// MAX_RANDOM_BYTE = 2**8 - 1
|
||||
// active_validator_indices = get_active_validator_indices(state, epoch)
|
||||
// active_validator_count = uint64(len(active_validator_indices))
|
||||
// seed = get_seed(state, epoch, DOMAIN_SYNC_COMMITTEE)
|
||||
// i = 0
|
||||
// sync_committee_indices: List[ValidatorIndex] = []
|
||||
// while len(sync_committee_indices) < SYNC_COMMITTEE_SIZE:
|
||||
// shuffled_index = compute_shuffled_index(uint64(i % active_validator_count), active_validator_count, seed)
|
||||
// candidate_index = active_validator_indices[shuffled_index]
|
||||
// random_byte = hash(seed + uint_to_bytes(uint64(i // 32)))[i % 32]
|
||||
// effective_balance = state.validators[candidate_index].effective_balance
|
||||
// if effective_balance * MAX_RANDOM_BYTE >= MAX_EFFECTIVE_BALANCE * random_byte:
|
||||
// sync_committee_indices.append(candidate_index)
|
||||
// i += 1
|
||||
// return sync_committee_indices
|
||||
func NextSyncCommitteeIndices(ctx context.Context, s state.BeaconStateAltair) ([]types.ValidatorIndex, error) {
|
||||
epoch := helpers.NextEpoch(s)
|
||||
indices, err := helpers.ActiveValidatorIndices(s, epoch)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
seed, err := helpers.Seed(s, epoch, params.BeaconConfig().DomainSyncCommittee)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
count := uint64(len(indices))
|
||||
cfg := params.BeaconConfig()
|
||||
syncCommitteeSize := cfg.SyncCommitteeSize
|
||||
cIndices := make([]types.ValidatorIndex, 0, syncCommitteeSize)
|
||||
hashFunc := hashutil.CustomSHA256Hasher()
|
||||
|
||||
for i := types.ValidatorIndex(0); uint64(len(cIndices)) < params.BeaconConfig().SyncCommitteeSize; i++ {
|
||||
if ctx.Err() != nil {
|
||||
return nil, ctx.Err()
|
||||
}
|
||||
|
||||
sIndex, err := helpers.ComputeShuffledIndex(i.Mod(count), count, seed, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
b := append(seed[:], bytesutil.Bytes8(uint64(i.Div(32)))...)
|
||||
randomByte := hashFunc(b)[i%32]
|
||||
cIndex := indices[sIndex]
|
||||
v, err := s.ValidatorAtIndexReadOnly(cIndex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
effectiveBal := v.EffectiveBalance()
|
||||
if effectiveBal*maxRandomByte >= cfg.MaxEffectiveBalance*uint64(randomByte) {
|
||||
cIndices = append(cIndices, cIndex)
|
||||
}
|
||||
}
|
||||
|
||||
return cIndices, nil
|
||||
}
|
||||
|
||||
// SyncSubCommitteePubkeys returns the pubkeys participating in a sync subcommittee.
|
||||
//
|
||||
// def get_sync_subcommittee_pubkeys(state: BeaconState, subcommittee_index: uint64) -> Sequence[BLSPubkey]:
|
||||
// # Committees assigned to `slot` sign for `slot - 1`
|
||||
// # This creates the exceptional logic below when transitioning between sync committee periods
|
||||
// next_slot_epoch = compute_epoch_at_slot(Slot(state.slot + 1))
|
||||
// if compute_sync_committee_period(get_current_epoch(state)) == compute_sync_committee_period(next_slot_epoch):
|
||||
// sync_committee = state.current_sync_committee
|
||||
// else:
|
||||
// sync_committee = state.next_sync_committee
|
||||
//
|
||||
// # Return pubkeys for the subcommittee index
|
||||
// sync_subcommittee_size = SYNC_COMMITTEE_SIZE // SYNC_COMMITTEE_SUBNET_COUNT
|
||||
// i = subcommittee_index * sync_subcommittee_size
|
||||
// return sync_committee.pubkeys[i:i + sync_subcommittee_size]
|
||||
func SyncSubCommitteePubkeys(syncCommittee *ethpb.SyncCommittee, subComIdx types.CommitteeIndex) ([][]byte, error) {
|
||||
cfg := params.BeaconConfig()
|
||||
subCommSize := cfg.SyncCommitteeSize / cfg.SyncCommitteeSubnetCount
|
||||
i := uint64(subComIdx) * subCommSize
|
||||
endOfSubCom := i + subCommSize
|
||||
pubkeyLen := uint64(len(syncCommittee.Pubkeys))
|
||||
if endOfSubCom > pubkeyLen {
|
||||
return nil, errors.Errorf("end index is larger than array length: %d > %d", endOfSubCom, pubkeyLen)
|
||||
}
|
||||
return syncCommittee.Pubkeys[i:endOfSubCom], nil
|
||||
}
|
||||
|
||||
// IsSyncCommitteeAggregator checks whether the provided signature is for a valid
|
||||
// aggregator.
|
||||
//
|
||||
// def is_sync_committee_aggregator(signature: BLSSignature) -> bool:
|
||||
// modulo = max(1, SYNC_COMMITTEE_SIZE // SYNC_COMMITTEE_SUBNET_COUNT // TARGET_AGGREGATORS_PER_SYNC_SUBCOMMITTEE)
|
||||
// return bytes_to_uint64(hash(signature)[0:8]) % modulo == 0
|
||||
func IsSyncCommitteeAggregator(sig []byte) (bool, error) {
|
||||
if len(sig) != params.BeaconConfig().BLSSignatureLength {
|
||||
return false, errors.New("incorrect sig length")
|
||||
}
|
||||
|
||||
cfg := params.BeaconConfig()
|
||||
modulo := mathutil.Max(1, cfg.SyncCommitteeSize/cfg.SyncCommitteeSubnetCount/cfg.TargetAggregatorsPerSyncSubcommittee)
|
||||
hashedSig := hashutil.Hash(sig)
|
||||
return bytesutil.FromBytes8(hashedSig[:8])%modulo == 0, nil
|
||||
}
|
||||
|
||||
// ValidateSyncMessageTime validates sync message to ensure that the provided slot is valid.
|
||||
func ValidateSyncMessageTime(slot types.Slot, genesisTime time.Time, clockDisparity time.Duration) error {
|
||||
if err := helpers.ValidateSlotClock(slot, uint64(genesisTime.Unix())); err != nil {
|
||||
return err
|
||||
}
|
||||
messageTime, err := helpers.SlotToTime(uint64(genesisTime.Unix()), slot)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
currentSlot := helpers.SlotsSince(genesisTime)
|
||||
slotStartTime, err := helpers.SlotToTime(uint64(genesisTime.Unix()), currentSlot)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
lowestSlotBound := slotStartTime.Add(-clockDisparity)
|
||||
currentLowerBound := time.Now().Add(-clockDisparity)
|
||||
// In the event the Slot's start time, is before the
|
||||
// current allowable bound, we set the slot's start
|
||||
// time as the bound.
|
||||
if slotStartTime.Before(currentLowerBound) {
|
||||
lowestSlotBound = slotStartTime
|
||||
}
|
||||
|
||||
lowerBound := lowestSlotBound
|
||||
upperBound := time.Now().Add(clockDisparity)
|
||||
// Verify sync message slot is within the time range.
|
||||
if messageTime.Before(lowerBound) || messageTime.After(upperBound) {
|
||||
return fmt.Errorf(
|
||||
"sync message slot %d not within allowable range of %d to %d (current slot)",
|
||||
slot,
|
||||
lowerBound.Unix(),
|
||||
upperBound.Unix(),
|
||||
)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
402
beacon-chain/core/altair/sync_committee_test.go
Normal file
402
beacon-chain/core/altair/sync_committee_test.go
Normal file
@@ -0,0 +1,402 @@
|
||||
package altair_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/altair"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
stateAltair "github.com/prysmaticlabs/prysm/beacon-chain/state/v2"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
"github.com/prysmaticlabs/prysm/shared/timeutils"
|
||||
)
|
||||
|
||||
func TestSyncCommitteeIndices_CanGet(t *testing.T) {
|
||||
getState := func(t *testing.T, count uint64) *stateAltair.BeaconState {
|
||||
validators := make([]*ethpb.Validator, count)
|
||||
for i := 0; i < len(validators); i++ {
|
||||
validators[i] = ðpb.Validator{
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
EffectiveBalance: params.BeaconConfig().MinDepositAmount,
|
||||
}
|
||||
}
|
||||
state, err := stateAltair.InitializeFromProto(ðpb.BeaconStateAltair{
|
||||
Validators: validators,
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
return state
|
||||
}
|
||||
|
||||
type args struct {
|
||||
state *stateAltair.BeaconState
|
||||
epoch types.Epoch
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantErr bool
|
||||
errString string
|
||||
}{
|
||||
{
|
||||
name: "nil state",
|
||||
args: args{
|
||||
state: nil,
|
||||
},
|
||||
wantErr: true,
|
||||
errString: "nil inner state",
|
||||
},
|
||||
{
|
||||
name: "genesis validator count, epoch 0",
|
||||
args: args{
|
||||
state: getState(t, params.BeaconConfig().MinGenesisActiveValidatorCount),
|
||||
epoch: 0,
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "genesis validator count, epoch 100",
|
||||
args: args{
|
||||
state: getState(t, params.BeaconConfig().MinGenesisActiveValidatorCount),
|
||||
epoch: 100,
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "less than optimal validator count, epoch 100",
|
||||
args: args{
|
||||
state: getState(t, params.BeaconConfig().MaxValidatorsPerCommittee),
|
||||
epoch: 100,
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
helpers.ClearCache()
|
||||
got, err := altair.NextSyncCommitteeIndices(context.Background(), tt.args.state)
|
||||
if tt.wantErr {
|
||||
require.ErrorContains(t, tt.errString, err)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, int(params.BeaconConfig().SyncCommitteeSize), len(got))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSyncCommitteeIndices_DifferentPeriods(t *testing.T) {
|
||||
helpers.ClearCache()
|
||||
getState := func(t *testing.T, count uint64) *stateAltair.BeaconState {
|
||||
validators := make([]*ethpb.Validator, count)
|
||||
for i := 0; i < len(validators); i++ {
|
||||
validators[i] = ðpb.Validator{
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
EffectiveBalance: params.BeaconConfig().MinDepositAmount,
|
||||
}
|
||||
}
|
||||
state, err := stateAltair.InitializeFromProto(ðpb.BeaconStateAltair{
|
||||
Validators: validators,
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
return state
|
||||
}
|
||||
|
||||
state := getState(t, params.BeaconConfig().MaxValidatorsPerCommittee)
|
||||
got1, err := altair.NextSyncCommitteeIndices(context.Background(), state)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, state.SetSlot(params.BeaconConfig().SlotsPerEpoch))
|
||||
got2, err := altair.NextSyncCommitteeIndices(context.Background(), state)
|
||||
require.NoError(t, err)
|
||||
require.DeepNotEqual(t, got1, got2)
|
||||
require.NoError(t, state.SetSlot(params.BeaconConfig().SlotsPerEpoch*types.Slot(params.BeaconConfig().EpochsPerSyncCommitteePeriod)))
|
||||
got2, err = altair.NextSyncCommitteeIndices(context.Background(), state)
|
||||
require.NoError(t, err)
|
||||
require.DeepNotEqual(t, got1, got2)
|
||||
require.NoError(t, state.SetSlot(params.BeaconConfig().SlotsPerEpoch*types.Slot(2*params.BeaconConfig().EpochsPerSyncCommitteePeriod)))
|
||||
got2, err = altair.NextSyncCommitteeIndices(context.Background(), state)
|
||||
require.NoError(t, err)
|
||||
require.DeepNotEqual(t, got1, got2)
|
||||
}
|
||||
|
||||
func TestSyncCommittee_CanGet(t *testing.T) {
|
||||
getState := func(t *testing.T, count uint64) *stateAltair.BeaconState {
|
||||
validators := make([]*ethpb.Validator, count)
|
||||
for i := 0; i < len(validators); i++ {
|
||||
blsKey, err := bls.RandKey()
|
||||
require.NoError(t, err)
|
||||
validators[i] = ðpb.Validator{
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
EffectiveBalance: params.BeaconConfig().MinDepositAmount,
|
||||
PublicKey: blsKey.PublicKey().Marshal(),
|
||||
}
|
||||
}
|
||||
state, err := stateAltair.InitializeFromProto(ðpb.BeaconStateAltair{
|
||||
Validators: validators,
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
return state
|
||||
}
|
||||
|
||||
type args struct {
|
||||
state *stateAltair.BeaconState
|
||||
epoch types.Epoch
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantErr bool
|
||||
errString string
|
||||
}{
|
||||
{
|
||||
name: "nil state",
|
||||
args: args{
|
||||
state: nil,
|
||||
},
|
||||
wantErr: true,
|
||||
errString: "nil inner state",
|
||||
},
|
||||
{
|
||||
name: "genesis validator count, epoch 0",
|
||||
args: args{
|
||||
state: getState(t, params.BeaconConfig().MinGenesisActiveValidatorCount),
|
||||
epoch: 0,
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "genesis validator count, epoch 100",
|
||||
args: args{
|
||||
state: getState(t, params.BeaconConfig().MinGenesisActiveValidatorCount),
|
||||
epoch: 100,
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "less than optimal validator count, epoch 100",
|
||||
args: args{
|
||||
state: getState(t, params.BeaconConfig().MaxValidatorsPerCommittee),
|
||||
epoch: 100,
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
helpers.ClearCache()
|
||||
if !tt.wantErr {
|
||||
require.NoError(t, tt.args.state.SetSlot(types.Slot(tt.args.epoch)*params.BeaconConfig().SlotsPerEpoch))
|
||||
}
|
||||
got, err := altair.NextSyncCommittee(context.Background(), tt.args.state)
|
||||
if tt.wantErr {
|
||||
require.ErrorContains(t, tt.errString, err)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, int(params.BeaconConfig().SyncCommitteeSize), len(got.Pubkeys))
|
||||
require.Equal(t, params.BeaconConfig().BLSPubkeyLength, len(got.AggregatePubkey))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateNilSyncContribution(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
s *ethpb.SignedContributionAndProof
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "nil object",
|
||||
s: nil,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "nil message",
|
||||
s: ðpb.SignedContributionAndProof{},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "nil contribution",
|
||||
s: ðpb.SignedContributionAndProof{Message: ðpb.ContributionAndProof{}},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "nil bitfield",
|
||||
s: ðpb.SignedContributionAndProof{
|
||||
Message: ðpb.ContributionAndProof{
|
||||
Contribution: ðpb.SyncCommitteeContribution{},
|
||||
}},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "non nil sync contribution",
|
||||
s: ðpb.SignedContributionAndProof{
|
||||
Message: ðpb.ContributionAndProof{
|
||||
Contribution: ðpb.SyncCommitteeContribution{
|
||||
AggregationBits: []byte{},
|
||||
},
|
||||
}},
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if err := altair.ValidateNilSyncContribution(tt.s); (err != nil) != tt.wantErr {
|
||||
t.Errorf("ValidateNilSyncContribution() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSyncSubCommitteePubkeys_CanGet(t *testing.T) {
|
||||
helpers.ClearCache()
|
||||
state := getState(t, params.BeaconConfig().MaxValidatorsPerCommittee)
|
||||
com, err := altair.NextSyncCommittee(context.Background(), state)
|
||||
require.NoError(t, err)
|
||||
sub, err := altair.SyncSubCommitteePubkeys(com, 0)
|
||||
require.NoError(t, err)
|
||||
subCommSize := params.BeaconConfig().SyncCommitteeSize / params.BeaconConfig().SyncCommitteeSubnetCount
|
||||
require.Equal(t, int(subCommSize), len(sub))
|
||||
require.DeepSSZEqual(t, com.Pubkeys[0:subCommSize], sub)
|
||||
|
||||
sub, err = altair.SyncSubCommitteePubkeys(com, 1)
|
||||
require.NoError(t, err)
|
||||
require.DeepSSZEqual(t, com.Pubkeys[subCommSize:2*subCommSize], sub)
|
||||
|
||||
sub, err = altair.SyncSubCommitteePubkeys(com, 2)
|
||||
require.NoError(t, err)
|
||||
require.DeepSSZEqual(t, com.Pubkeys[2*subCommSize:3*subCommSize], sub)
|
||||
|
||||
sub, err = altair.SyncSubCommitteePubkeys(com, 3)
|
||||
require.NoError(t, err)
|
||||
require.DeepSSZEqual(t, com.Pubkeys[3*subCommSize:], sub)
|
||||
|
||||
}
|
||||
|
||||
func Test_ValidateSyncMessageTime(t *testing.T) {
|
||||
if params.BeaconNetworkConfig().MaximumGossipClockDisparity < 200*time.Millisecond {
|
||||
t.Fatal("This test expects the maximum clock disparity to be at least 200ms")
|
||||
}
|
||||
|
||||
type args struct {
|
||||
syncMessageSlot types.Slot
|
||||
genesisTime time.Time
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantedErr string
|
||||
}{
|
||||
{
|
||||
name: "sync_message.slot == current_slot",
|
||||
args: args{
|
||||
syncMessageSlot: 15,
|
||||
genesisTime: timeutils.Now().Add(-15 * time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Second),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "sync_message.slot == current_slot, received in middle of slot",
|
||||
args: args{
|
||||
syncMessageSlot: 15,
|
||||
genesisTime: timeutils.Now().Add(
|
||||
-15 * time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Second,
|
||||
).Add(-(time.Duration(params.BeaconConfig().SecondsPerSlot/2) * time.Second)),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "sync_message.slot == current_slot, received 200ms early",
|
||||
args: args{
|
||||
syncMessageSlot: 16,
|
||||
genesisTime: timeutils.Now().Add(
|
||||
-16 * time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Second,
|
||||
).Add(-200 * time.Millisecond),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "sync_message.slot > current_slot",
|
||||
args: args{
|
||||
syncMessageSlot: 16,
|
||||
genesisTime: timeutils.Now().Add(-(15 * time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Second)),
|
||||
},
|
||||
wantedErr: "sync message slot 16 not within allowable range of",
|
||||
},
|
||||
{
|
||||
name: "sync_message.slot == current_slot+CLOCK_DISPARITY",
|
||||
args: args{
|
||||
syncMessageSlot: 100,
|
||||
genesisTime: timeutils.Now().Add(-(100*time.Duration(params.BeaconConfig().SecondsPerSlot)*time.Second - params.BeaconNetworkConfig().MaximumGossipClockDisparity)),
|
||||
},
|
||||
wantedErr: "",
|
||||
},
|
||||
{
|
||||
name: "sync_message.slot == current_slot+CLOCK_DISPARITY-1000ms",
|
||||
args: args{
|
||||
syncMessageSlot: 100,
|
||||
genesisTime: timeutils.Now().Add(-(100 * time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Second) + params.BeaconNetworkConfig().MaximumGossipClockDisparity + 1000*time.Millisecond),
|
||||
},
|
||||
wantedErr: "sync message slot 100 not within allowable range of",
|
||||
},
|
||||
{
|
||||
name: "sync_message.slot == current_slot-CLOCK_DISPARITY",
|
||||
args: args{
|
||||
syncMessageSlot: 100,
|
||||
genesisTime: timeutils.Now().Add(-(100*time.Duration(params.BeaconConfig().SecondsPerSlot)*time.Second + params.BeaconNetworkConfig().MaximumGossipClockDisparity)),
|
||||
},
|
||||
wantedErr: "",
|
||||
},
|
||||
{
|
||||
name: "sync_message.slot > current_slot+CLOCK_DISPARITY",
|
||||
args: args{
|
||||
syncMessageSlot: 101,
|
||||
genesisTime: timeutils.Now().Add(-(100*time.Duration(params.BeaconConfig().SecondsPerSlot)*time.Second + params.BeaconNetworkConfig().MaximumGossipClockDisparity)),
|
||||
},
|
||||
wantedErr: "sync message slot 101 not within allowable range of",
|
||||
},
|
||||
{
|
||||
name: "sync_message.slot is well beyond current slot",
|
||||
args: args{
|
||||
syncMessageSlot: 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) {
|
||||
err := altair.ValidateSyncMessageTime(tt.args.syncMessageSlot, tt.args.genesisTime,
|
||||
params.BeaconNetworkConfig().MaximumGossipClockDisparity)
|
||||
if tt.wantedErr != "" {
|
||||
assert.ErrorContains(t, tt.wantedErr, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func getState(t *testing.T, count uint64) *stateAltair.BeaconState {
|
||||
validators := make([]*ethpb.Validator, count)
|
||||
for i := 0; i < len(validators); i++ {
|
||||
blsKey, err := bls.RandKey()
|
||||
require.NoError(t, err)
|
||||
validators[i] = ðpb.Validator{
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
EffectiveBalance: params.BeaconConfig().MinDepositAmount,
|
||||
PublicKey: blsKey.PublicKey().Marshal(),
|
||||
}
|
||||
}
|
||||
state, err := stateAltair.InitializeFromProto(ðpb.BeaconStateAltair{
|
||||
Validators: validators,
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
return state
|
||||
}
|
||||
110
beacon-chain/core/altair/transition.go
Normal file
110
beacon-chain/core/altair/transition.go
Normal file
@@ -0,0 +1,110 @@
|
||||
package altair
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
e "github.com/prysmaticlabs/prysm/beacon-chain/core/epoch"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/epoch/precompute"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
|
||||
// ProcessEpoch describes the per epoch operations that are performed on the beacon state.
|
||||
// It's optimized by pre computing validator attested info and epoch total/attested balances upfront.
|
||||
//
|
||||
// Spec code:
|
||||
// def process_epoch(state: BeaconState) -> None:
|
||||
// process_justification_and_finalization(state) # [Modified in Altair]
|
||||
// process_inactivity_updates(state) # [New in Altair]
|
||||
// process_rewards_and_penalties(state) # [Modified in Altair]
|
||||
// process_registry_updates(state)
|
||||
// process_slashings(state) # [Modified in Altair]
|
||||
// process_eth1_data_reset(state)
|
||||
// process_effective_balance_updates(state)
|
||||
// process_slashings_reset(state)
|
||||
// process_randao_mixes_reset(state)
|
||||
// process_historical_roots_update(state)
|
||||
// process_participation_flag_updates(state) # [New in Altair]
|
||||
// process_sync_committee_updates(state) # [New in Altair]
|
||||
func ProcessEpoch(ctx context.Context, state state.BeaconStateAltair) (state.BeaconStateAltair, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "altair.ProcessEpoch")
|
||||
defer span.End()
|
||||
|
||||
if state == nil || state.IsNil() {
|
||||
return nil, errors.New("nil state")
|
||||
}
|
||||
vp, bp, err := InitializeEpochValidators(ctx, state)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// New in Altair.
|
||||
vp, bp, err = ProcessEpochParticipation(ctx, state, bp, vp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
state, err = precompute.ProcessJustificationAndFinalizationPreCompute(state, bp)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not process justification")
|
||||
}
|
||||
|
||||
// New in Altair.
|
||||
state, vp, err = ProcessInactivityScores(ctx, state, vp)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not process inactivity updates")
|
||||
}
|
||||
|
||||
// New in Altair.
|
||||
state, err = ProcessRewardsAndPenaltiesPrecompute(state, bp, vp)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not process rewards and penalties")
|
||||
}
|
||||
|
||||
state, err = e.ProcessRegistryUpdates(state)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not process registry updates")
|
||||
}
|
||||
|
||||
// Modified in Altair.
|
||||
state, err = ProcessSlashings(state)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
state, err = e.ProcessEth1DataReset(state)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
state, err = e.ProcessEffectiveBalanceUpdates(state)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
state, err = e.ProcessSlashingsReset(state)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
state, err = e.ProcessRandaoMixesReset(state)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
state, err = e.ProcessHistoricalRootsUpdate(state)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// New in Altair.
|
||||
state, err = ProcessParticipationFlagUpdates(state)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// New in Altair.
|
||||
state, err = ProcessSyncCommitteeUpdates(ctx, state)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return state, nil
|
||||
}
|
||||
34
beacon-chain/core/altair/transition_test.go
Normal file
34
beacon-chain/core/altair/transition_test.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package altair_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/go-bitfield"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/altair"
|
||||
stateAltair "github.com/prysmaticlabs/prysm/beacon-chain/state/v2"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
func TestProcessEpoch_CanProcess(t *testing.T) {
|
||||
epoch := types.Epoch(1)
|
||||
slashing := make([]uint64, params.BeaconConfig().EpochsPerSlashingsVector)
|
||||
base := ðpb.BeaconStateAltair{
|
||||
Slot: params.BeaconConfig().SlotsPerEpoch.Mul(uint64(epoch)) + 1,
|
||||
BlockRoots: make([][]byte, 128),
|
||||
Slashings: slashing,
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
FinalizedCheckpoint: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
JustificationBits: bitfield.Bitvector4{0x00},
|
||||
CurrentJustifiedCheckpoint: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
}
|
||||
s, err := stateAltair.InitializeFromProto(base)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, s.SetValidators([]*ethpb.Validator{}))
|
||||
newState, err := altair.ProcessEpoch(context.Background(), s)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, uint64(0), newState.Slashings()[2], "Unexpected slashed balance")
|
||||
}
|
||||
180
beacon-chain/core/altair/upgrade.go
Normal file
180
beacon-chain/core/altair/upgrade.go
Normal file
@@ -0,0 +1,180 @@
|
||||
package altair
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
statealtair "github.com/prysmaticlabs/prysm/beacon-chain/state/v2"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/shared/attestationutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
// UpgradeToAltair updates input state to return the version Altair state.
|
||||
//
|
||||
// Spec code:
|
||||
// def upgrade_to_altair(pre: phase0.BeaconState) -> BeaconState:
|
||||
// epoch = phase0.get_current_epoch(pre)
|
||||
// post = BeaconState(
|
||||
// # Versioning
|
||||
// genesis_time=pre.genesis_time,
|
||||
// genesis_validators_root=pre.genesis_validators_root,
|
||||
// slot=pre.slot,
|
||||
// fork=Fork(
|
||||
// previous_version=pre.fork.current_version,
|
||||
// current_version=ALTAIR_FORK_VERSION,
|
||||
// epoch=epoch,
|
||||
// ),
|
||||
// # History
|
||||
// latest_block_header=pre.latest_block_header,
|
||||
// block_roots=pre.block_roots,
|
||||
// state_roots=pre.state_roots,
|
||||
// historical_roots=pre.historical_roots,
|
||||
// # Eth1
|
||||
// eth1_data=pre.eth1_data,
|
||||
// eth1_data_votes=pre.eth1_data_votes,
|
||||
// eth1_deposit_index=pre.eth1_deposit_index,
|
||||
// # Registry
|
||||
// validators=pre.validators,
|
||||
// balances=pre.balances,
|
||||
// # Randomness
|
||||
// randao_mixes=pre.randao_mixes,
|
||||
// # Slashings
|
||||
// slashings=pre.slashings,
|
||||
// # Participation
|
||||
// previous_epoch_participation=[ParticipationFlags(0b0000_0000) for _ in range(len(pre.validators))],
|
||||
// current_epoch_participation=[ParticipationFlags(0b0000_0000) for _ in range(len(pre.validators))],
|
||||
// # Finality
|
||||
// justification_bits=pre.justification_bits,
|
||||
// previous_justified_checkpoint=pre.previous_justified_checkpoint,
|
||||
// current_justified_checkpoint=pre.current_justified_checkpoint,
|
||||
// finalized_checkpoint=pre.finalized_checkpoint,
|
||||
// # Inactivity
|
||||
// inactivity_scores=[uint64(0) for _ in range(len(pre.validators))],
|
||||
// )
|
||||
// # Fill in previous epoch participation from the pre state's pending attestations
|
||||
// translate_participation(post, pre.previous_epoch_attestations)
|
||||
//
|
||||
// # Fill in sync committees
|
||||
// # Note: A duplicate committee is assigned for the current and next committee at the fork boundary
|
||||
// post.current_sync_committee = get_next_sync_committee(post)
|
||||
// post.next_sync_committee = get_next_sync_committee(post)
|
||||
// return post
|
||||
func UpgradeToAltair(ctx context.Context, state state.BeaconState) (state.BeaconStateAltair, error) {
|
||||
epoch := helpers.CurrentEpoch(state)
|
||||
|
||||
numValidators := state.NumValidators()
|
||||
s := ðpb.BeaconStateAltair{
|
||||
GenesisTime: state.GenesisTime(),
|
||||
GenesisValidatorsRoot: state.GenesisValidatorRoot(),
|
||||
Slot: state.Slot(),
|
||||
Fork: ðpb.Fork{
|
||||
PreviousVersion: state.Fork().CurrentVersion,
|
||||
CurrentVersion: params.BeaconConfig().AltairForkVersion,
|
||||
Epoch: epoch,
|
||||
},
|
||||
LatestBlockHeader: state.LatestBlockHeader(),
|
||||
BlockRoots: state.BlockRoots(),
|
||||
StateRoots: state.StateRoots(),
|
||||
HistoricalRoots: state.HistoricalRoots(),
|
||||
Eth1Data: state.Eth1Data(),
|
||||
Eth1DataVotes: state.Eth1DataVotes(),
|
||||
Eth1DepositIndex: state.Eth1DepositIndex(),
|
||||
Validators: state.Validators(),
|
||||
Balances: state.Balances(),
|
||||
RandaoMixes: state.RandaoMixes(),
|
||||
Slashings: state.Slashings(),
|
||||
PreviousEpochParticipation: make([]byte, numValidators),
|
||||
CurrentEpochParticipation: make([]byte, numValidators),
|
||||
JustificationBits: state.JustificationBits(),
|
||||
PreviousJustifiedCheckpoint: state.PreviousJustifiedCheckpoint(),
|
||||
CurrentJustifiedCheckpoint: state.CurrentJustifiedCheckpoint(),
|
||||
FinalizedCheckpoint: state.FinalizedCheckpoint(),
|
||||
InactivityScores: make([]uint64, numValidators),
|
||||
}
|
||||
|
||||
newState, err := statealtair.InitializeFromProto(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
prevEpochAtts, err := state.PreviousEpochAttestations()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
newState, err = TranslateParticipation(newState, prevEpochAtts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
committee, err := NextSyncCommittee(ctx, newState)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := newState.SetCurrentSyncCommittee(committee); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := newState.SetNextSyncCommittee(committee); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newState, nil
|
||||
}
|
||||
|
||||
// TranslateParticipation translates pending attestations into participation bits, then inserts the bits into beacon state.
|
||||
// This is helper function to convert phase 0 beacon state(pending_attestations) to Altair beacon state(participation_bits).
|
||||
//
|
||||
// Spec code:
|
||||
// def translate_participation(state: BeaconState, pending_attestations: Sequence[phase0.PendingAttestation]) -> None:
|
||||
// for attestation in pending_attestations:
|
||||
// data = attestation.data
|
||||
// inclusion_delay = attestation.inclusion_delay
|
||||
// # Translate attestation inclusion info to flag indices
|
||||
// participation_flag_indices = get_attestation_participation_flag_indices(state, data, inclusion_delay)
|
||||
//
|
||||
// # Apply flags to all attesting validators
|
||||
// epoch_participation = state.previous_epoch_participation
|
||||
// for index in get_attesting_indices(state, data, attestation.aggregation_bits):
|
||||
// for flag_index in participation_flag_indices:
|
||||
// epoch_participation[index] = add_flag(epoch_participation[index], flag_index)
|
||||
func TranslateParticipation(state *statealtair.BeaconState, atts []*ethpb.PendingAttestation) (*statealtair.BeaconState, error) {
|
||||
epochParticipation, err := state.PreviousEpochParticipation()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, att := range atts {
|
||||
participatedFlags, err := AttestationParticipationFlagIndices(state, att.Data, att.InclusionDelay)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
committee, err := helpers.BeaconCommitteeFromState(state, att.Data.Slot, att.Data.CommitteeIndex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
indices, err := attestationutil.AttestingIndices(att.AggregationBits, committee)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cfg := params.BeaconConfig()
|
||||
sourceFlagIndex := cfg.TimelySourceFlagIndex
|
||||
targetFlagIndex := cfg.TimelyTargetFlagIndex
|
||||
headFlagIndex := cfg.TimelyHeadFlagIndex
|
||||
for _, index := range indices {
|
||||
if participatedFlags[sourceFlagIndex] && !HasValidatorFlag(epochParticipation[index], sourceFlagIndex) {
|
||||
epochParticipation[index] = AddValidatorFlag(epochParticipation[index], sourceFlagIndex)
|
||||
}
|
||||
if participatedFlags[targetFlagIndex] && !HasValidatorFlag(epochParticipation[index], targetFlagIndex) {
|
||||
epochParticipation[index] = AddValidatorFlag(epochParticipation[index], targetFlagIndex)
|
||||
}
|
||||
if participatedFlags[headFlagIndex] && !HasValidatorFlag(epochParticipation[index], headFlagIndex) {
|
||||
epochParticipation[index] = AddValidatorFlag(epochParticipation[index], headFlagIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := state.SetPreviousParticipationBits(epochParticipation); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return state, nil
|
||||
}
|
||||
117
beacon-chain/core/altair/upgrade_test.go
Normal file
117
beacon-chain/core/altair/upgrade_test.go
Normal file
@@ -0,0 +1,117 @@
|
||||
package altair_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/go-bitfield"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/altair"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
stateAltair "github.com/prysmaticlabs/prysm/beacon-chain/state/v2"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/shared/attestationutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
func TestTranslateParticipation(t *testing.T) {
|
||||
s, _ := testutil.DeterministicGenesisStateAltair(t, 64)
|
||||
st, ok := s.(*stateAltair.BeaconState)
|
||||
require.Equal(t, true, ok)
|
||||
require.NoError(t, st.SetSlot(st.Slot()+params.BeaconConfig().MinAttestationInclusionDelay))
|
||||
|
||||
var err error
|
||||
newState, err := altair.TranslateParticipation(st, nil)
|
||||
require.NoError(t, err)
|
||||
participation, err := newState.PreviousEpochParticipation()
|
||||
require.NoError(t, err)
|
||||
require.DeepSSZEqual(t, make([]byte, 64), participation)
|
||||
|
||||
aggBits := bitfield.NewBitlist(2)
|
||||
aggBits.SetBitAt(0, true)
|
||||
aggBits.SetBitAt(1, true)
|
||||
r, err := helpers.BlockRootAtSlot(s, 0)
|
||||
require.NoError(t, err)
|
||||
var pendingAtts []*ethpb.PendingAttestation
|
||||
for i := 0; i < 3; i++ {
|
||||
pendingAtts = append(pendingAtts, ðpb.PendingAttestation{
|
||||
Data: ðpb.AttestationData{
|
||||
CommitteeIndex: types.CommitteeIndex(i),
|
||||
BeaconBlockRoot: r,
|
||||
Source: ðpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
|
||||
Target: ðpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
|
||||
},
|
||||
AggregationBits: aggBits,
|
||||
InclusionDelay: 1,
|
||||
})
|
||||
}
|
||||
|
||||
newState, err = altair.TranslateParticipation(newState, pendingAtts)
|
||||
require.NoError(t, err)
|
||||
participation, err = newState.PreviousEpochParticipation()
|
||||
require.NoError(t, err)
|
||||
require.DeepNotSSZEqual(t, make([]byte, 64), participation)
|
||||
|
||||
committee, err := helpers.BeaconCommitteeFromState(st, pendingAtts[0].Data.Slot, pendingAtts[0].Data.CommitteeIndex)
|
||||
require.NoError(t, err)
|
||||
indices, err := attestationutil.AttestingIndices(pendingAtts[0].AggregationBits, committee)
|
||||
require.NoError(t, err)
|
||||
for _, index := range indices {
|
||||
require.Equal(t, true, altair.HasValidatorFlag(participation[index], params.BeaconConfig().TimelyHeadFlagIndex))
|
||||
require.Equal(t, true, altair.HasValidatorFlag(participation[index], params.BeaconConfig().TimelyTargetFlagIndex))
|
||||
require.Equal(t, true, altair.HasValidatorFlag(participation[index], params.BeaconConfig().TimelySourceFlagIndex))
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpgradeToAltair(t *testing.T) {
|
||||
st, _ := testutil.DeterministicGenesisState(t, params.BeaconConfig().MaxValidatorsPerCommittee)
|
||||
preForkState := st.Copy()
|
||||
aState, err := altair.UpgradeToAltair(context.Background(), st)
|
||||
require.NoError(t, err)
|
||||
_, ok := aState.(state.BeaconStateAltair)
|
||||
require.Equal(t, true, ok)
|
||||
|
||||
require.Equal(t, preForkState.GenesisTime(), aState.GenesisTime())
|
||||
require.DeepSSZEqual(t, preForkState.GenesisValidatorRoot(), aState.GenesisValidatorRoot())
|
||||
require.Equal(t, preForkState.Slot(), aState.Slot())
|
||||
require.DeepSSZEqual(t, preForkState.LatestBlockHeader(), aState.LatestBlockHeader())
|
||||
require.DeepSSZEqual(t, preForkState.BlockRoots(), aState.BlockRoots())
|
||||
require.DeepSSZEqual(t, preForkState.StateRoots(), aState.StateRoots())
|
||||
require.DeepSSZEqual(t, preForkState.HistoricalRoots(), aState.HistoricalRoots())
|
||||
require.DeepSSZEqual(t, preForkState.Eth1Data(), aState.Eth1Data())
|
||||
require.DeepSSZEqual(t, preForkState.Eth1DataVotes(), aState.Eth1DataVotes())
|
||||
require.DeepSSZEqual(t, preForkState.Eth1DepositIndex(), aState.Eth1DepositIndex())
|
||||
require.DeepSSZEqual(t, preForkState.Validators(), aState.Validators())
|
||||
require.DeepSSZEqual(t, preForkState.Balances(), aState.Balances())
|
||||
require.DeepSSZEqual(t, preForkState.RandaoMixes(), aState.RandaoMixes())
|
||||
require.DeepSSZEqual(t, preForkState.Slashings(), aState.Slashings())
|
||||
require.DeepSSZEqual(t, preForkState.JustificationBits(), aState.JustificationBits())
|
||||
require.DeepSSZEqual(t, preForkState.PreviousJustifiedCheckpoint(), aState.PreviousJustifiedCheckpoint())
|
||||
require.DeepSSZEqual(t, preForkState.CurrentJustifiedCheckpoint(), aState.CurrentJustifiedCheckpoint())
|
||||
require.DeepSSZEqual(t, preForkState.FinalizedCheckpoint(), aState.FinalizedCheckpoint())
|
||||
numValidators := aState.NumValidators()
|
||||
p, err := aState.PreviousEpochParticipation()
|
||||
require.NoError(t, err)
|
||||
require.DeepSSZEqual(t, make([]byte, numValidators), p)
|
||||
p, err = aState.CurrentEpochParticipation()
|
||||
require.NoError(t, err)
|
||||
require.DeepSSZEqual(t, make([]byte, numValidators), p)
|
||||
s, err := aState.InactivityScores()
|
||||
require.NoError(t, err)
|
||||
require.DeepSSZEqual(t, make([]uint64, numValidators), s)
|
||||
|
||||
f := aState.Fork()
|
||||
require.DeepSSZEqual(t, ðpb.Fork{
|
||||
PreviousVersion: st.Fork().CurrentVersion,
|
||||
CurrentVersion: params.BeaconConfig().AltairForkVersion,
|
||||
Epoch: helpers.CurrentEpoch(st),
|
||||
}, f)
|
||||
csc, err := aState.CurrentSyncCommittee()
|
||||
require.NoError(t, err)
|
||||
nsc, err := aState.NextSyncCommittee()
|
||||
require.NoError(t, err)
|
||||
require.DeepSSZEqual(t, nsc, csc)
|
||||
}
|
||||
87
beacon-chain/core/altair/validator.go
Normal file
87
beacon-chain/core/altair/validator.go
Normal file
@@ -0,0 +1,87 @@
|
||||
package altair
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/validators"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
// SlashValidator with slashed index.
|
||||
// The function is modified to use MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR and use PROPOSER_WEIGHT when calculating the proposer reward.
|
||||
//
|
||||
// def slash_validator(state: BeaconState,
|
||||
// slashed_index: ValidatorIndex,
|
||||
// whistleblower_index: ValidatorIndex=None) -> None:
|
||||
// """
|
||||
// Slash the validator with index ``slashed_index``.
|
||||
// """
|
||||
// epoch = get_current_epoch(state)
|
||||
// initiate_validator_exit(state, slashed_index)
|
||||
// validator = state.validators[slashed_index]
|
||||
// validator.slashed = True
|
||||
// validator.withdrawable_epoch = max(validator.withdrawable_epoch, Epoch(epoch + EPOCHS_PER_SLASHINGS_VECTOR))
|
||||
// state.slashings[epoch % EPOCHS_PER_SLASHINGS_VECTOR] += validator.effective_balance
|
||||
// decrease_balance(state, slashed_index, validator.effective_balance // MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR)
|
||||
//
|
||||
// # Apply proposer and whistleblower rewards
|
||||
// proposer_index = get_beacon_proposer_index(state)
|
||||
// if whistleblower_index is None:
|
||||
// whistleblower_index = proposer_index
|
||||
// whistleblower_reward = Gwei(validator.effective_balance // WHISTLEBLOWER_REWARD_QUOTIENT)
|
||||
// proposer_reward = Gwei(whistleblower_reward * PROPOSER_WEIGHT // WEIGHT_DENOMINATOR)
|
||||
// increase_balance(state, proposer_index, proposer_reward)
|
||||
// increase_balance(state, whistleblower_index, Gwei(whistleblower_reward - proposer_reward))
|
||||
func SlashValidator(state state.BeaconState, slashedIdx types.ValidatorIndex, penaltyQuotient uint64,
|
||||
proposerRewardQuotient uint64) (state.BeaconState, error) {
|
||||
state, err := validators.InitiateValidatorExit(state, slashedIdx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not initiate validator %d exit", slashedIdx)
|
||||
}
|
||||
currentEpoch := helpers.SlotToEpoch(state.Slot())
|
||||
validator, err := state.ValidatorAtIndex(slashedIdx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
validator.Slashed = true
|
||||
maxWithdrawableEpoch := types.MaxEpoch(validator.WithdrawableEpoch, currentEpoch+params.BeaconConfig().EpochsPerSlashingsVector)
|
||||
validator.WithdrawableEpoch = maxWithdrawableEpoch
|
||||
|
||||
if err := state.UpdateValidatorAtIndex(slashedIdx, validator); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// The slashing amount is represented by epochs per slashing vector. The validator's effective balance is then applied to that amount.
|
||||
slashings := state.Slashings()
|
||||
currentSlashing := slashings[currentEpoch%params.BeaconConfig().EpochsPerSlashingsVector]
|
||||
if err := state.UpdateSlashingsAtIndex(
|
||||
uint64(currentEpoch%params.BeaconConfig().EpochsPerSlashingsVector),
|
||||
currentSlashing+validator.EffectiveBalance,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := helpers.DecreaseBalance(state, slashedIdx, validator.EffectiveBalance/penaltyQuotient); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
proposerIdx, err := helpers.BeaconProposerIndex(state)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get proposer idx")
|
||||
}
|
||||
|
||||
// In this implementation, proposer is the whistleblower.
|
||||
whistleBlowerIdx := proposerIdx
|
||||
whistleblowerReward := validator.EffectiveBalance / params.BeaconConfig().WhistleBlowerRewardQuotient
|
||||
proposerReward := whistleblowerReward * params.BeaconConfig().ProposerWeight / params.BeaconConfig().WeightDenominator
|
||||
err = helpers.IncreaseBalance(state, proposerIdx, proposerReward)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = helpers.IncreaseBalance(state, whistleBlowerIdx, whistleblowerReward-proposerReward)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return state, nil
|
||||
}
|
||||
69
beacon-chain/core/altair/validator_test.go
Normal file
69
beacon-chain/core/altair/validator_test.go
Normal file
@@ -0,0 +1,69 @@
|
||||
package altair_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/altair"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
stateAltair "github.com/prysmaticlabs/prysm/beacon-chain/state/v2"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
func TestSlashValidator_OK(t *testing.T) {
|
||||
validatorCount := params.BeaconConfig().MinGenesisActiveValidatorCount
|
||||
registry := make([]*ethpb.Validator, 0, validatorCount)
|
||||
balances := make([]uint64, 0, validatorCount)
|
||||
for i := uint64(0); i < validatorCount; i++ {
|
||||
registry = append(registry, ðpb.Validator{
|
||||
ActivationEpoch: 0,
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
|
||||
})
|
||||
balances = append(balances, params.BeaconConfig().MaxEffectiveBalance)
|
||||
}
|
||||
|
||||
base := ðpb.BeaconStateAltair{
|
||||
Validators: registry,
|
||||
Slashings: make([]uint64, params.BeaconConfig().EpochsPerSlashingsVector),
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
Balances: balances,
|
||||
}
|
||||
state, err := stateAltair.InitializeFromProto(base)
|
||||
require.NoError(t, err)
|
||||
|
||||
slashedIdx := types.ValidatorIndex(2)
|
||||
|
||||
proposer, err := helpers.BeaconProposerIndex(state)
|
||||
require.NoError(t, err, "Could not get proposer")
|
||||
proposerBal, err := state.BalanceAtIndex(proposer)
|
||||
require.NoError(t, err)
|
||||
cfg := params.BeaconConfig()
|
||||
slashedState, err := altair.SlashValidator(state, slashedIdx, cfg.MinSlashingPenaltyQuotientAltair, cfg.ProposerRewardQuotient)
|
||||
require.NoError(t, err, "Could not slash validator")
|
||||
state, ok := slashedState.(*stateAltair.BeaconState)
|
||||
require.Equal(t, true, ok)
|
||||
|
||||
v, err := state.ValidatorAtIndex(slashedIdx)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, true, v.Slashed, "Validator not slashed despite supposed to being slashed")
|
||||
assert.Equal(t, helpers.CurrentEpoch(state)+params.BeaconConfig().EpochsPerSlashingsVector, v.WithdrawableEpoch, "Withdrawable epoch not the expected value")
|
||||
|
||||
maxBalance := params.BeaconConfig().MaxEffectiveBalance
|
||||
slashedBalance := state.Slashings()[state.Slot().Mod(uint64(params.BeaconConfig().EpochsPerSlashingsVector))]
|
||||
assert.Equal(t, maxBalance, slashedBalance, "Slashed balance isnt the expected amount")
|
||||
|
||||
whistleblowerReward := slashedBalance / params.BeaconConfig().WhistleBlowerRewardQuotient
|
||||
bal, err := state.BalanceAtIndex(proposer)
|
||||
require.NoError(t, err)
|
||||
// The proposer is the whistleblower in phase 0.
|
||||
assert.Equal(t, proposerBal+whistleblowerReward, bal, "Did not get expected balance for proposer")
|
||||
bal, err = state.BalanceAtIndex(slashedIdx)
|
||||
require.NoError(t, err)
|
||||
v, err = state.ValidatorAtIndex(slashedIdx)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, maxBalance-(v.EffectiveBalance/params.BeaconConfig().MinSlashingPenaltyQuotientAltair), bal, "Did not get expected balance for slashed validator")
|
||||
}
|
||||
@@ -26,10 +26,9 @@ go_library(
|
||||
deps = [
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//beacon-chain/core/validators:go_default_library",
|
||||
"//beacon-chain/state/interface:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//proto/eth/v1alpha1:go_default_library",
|
||||
"//proto/interfaces:go_default_library",
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//proto/prysm/v1alpha1/block:go_default_library",
|
||||
"//shared/attestationutil:go_default_library",
|
||||
"//shared/bls:go_default_library",
|
||||
"//shared/bytesutil:go_default_library",
|
||||
@@ -37,10 +36,12 @@ go_library(
|
||||
"//shared/depositutil:go_default_library",
|
||||
"//shared/hashutil:go_default_library",
|
||||
"//shared/mathutil:go_default_library",
|
||||
"//shared/p2putils:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"//shared/slashutil:go_default_library",
|
||||
"//shared/sliceutil:go_default_library",
|
||||
"//shared/trieutil:go_default_library",
|
||||
"//shared/version:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@com_github_prysmaticlabs_eth2_types//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
@@ -66,6 +67,7 @@ go_test(
|
||||
"proposer_slashing_regression_test.go",
|
||||
"proposer_slashing_test.go",
|
||||
"randao_test.go",
|
||||
"signature_test.go",
|
||||
],
|
||||
data = glob(["testdata/**"]),
|
||||
embed = [":go_default_library"],
|
||||
@@ -74,11 +76,10 @@ go_test(
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//beacon-chain/core/validators:go_default_library",
|
||||
"//beacon-chain/p2p/types:go_default_library",
|
||||
"//beacon-chain/state/interface:go_default_library",
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//beacon-chain/state/v1:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//proto/eth/v1alpha1:go_default_library",
|
||||
"//proto/eth/v1alpha1/wrapper:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//proto/prysm/v1alpha1/wrapper:go_default_library",
|
||||
"//shared/aggregation:go_default_library",
|
||||
"//shared/aggregation/attestations:go_default_library",
|
||||
"//shared/attestationutil:go_default_library",
|
||||
|
||||
@@ -7,85 +7,22 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/interfaces"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/block"
|
||||
"github.com/prysmaticlabs/prysm/shared/attestationutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
|
||||
// ProcessAttestations applies processing operations to a block's inner attestation
|
||||
// records.
|
||||
func ProcessAttestations(
|
||||
ctx context.Context,
|
||||
beaconState iface.BeaconState,
|
||||
b interfaces.SignedBeaconBlock,
|
||||
) (iface.BeaconState, error) {
|
||||
if err := helpers.VerifyNilBeaconBlock(b); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var err error
|
||||
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)
|
||||
}
|
||||
}
|
||||
return beaconState, nil
|
||||
}
|
||||
|
||||
// ProcessAttestation verifies an input attestation can pass through processing using the given beacon state.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// def process_attestation(state: BeaconState, attestation: Attestation) -> None:
|
||||
// data = attestation.data
|
||||
// assert data.target.epoch in (get_previous_epoch(state), get_current_epoch(state))
|
||||
// assert data.target.epoch == compute_epoch_at_slot(data.slot)
|
||||
// assert data.slot + MIN_ATTESTATION_INCLUSION_DELAY <= state.slot <= data.slot + SLOTS_PER_EPOCH
|
||||
// assert data.index < get_committee_count_per_slot(state, data.target.epoch)
|
||||
//
|
||||
// committee = get_beacon_committee(state, data.slot, data.index)
|
||||
// assert len(attestation.aggregation_bits) == len(committee)
|
||||
//
|
||||
// pending_attestation = PendingAttestation(
|
||||
// data=data,
|
||||
// aggregation_bits=attestation.aggregation_bits,
|
||||
// inclusion_delay=state.slot - data.slot,
|
||||
// proposer_index=get_beacon_proposer_index(state),
|
||||
// )
|
||||
//
|
||||
// if data.target.epoch == get_current_epoch(state):
|
||||
// assert data.source == state.current_justified_checkpoint
|
||||
// state.current_epoch_attestations.append(pending_attestation)
|
||||
// else:
|
||||
// assert data.source == state.previous_justified_checkpoint
|
||||
// state.previous_epoch_attestations.append(pending_attestation)
|
||||
//
|
||||
// # Verify signature
|
||||
// assert is_valid_indexed_attestation(state, get_indexed_attestation(state, attestation))
|
||||
func ProcessAttestation(
|
||||
ctx context.Context,
|
||||
beaconState iface.BeaconState,
|
||||
att *ethpb.Attestation,
|
||||
) (iface.BeaconState, error) {
|
||||
beaconState, err := ProcessAttestationNoVerifySignature(ctx, beaconState, att)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return beaconState, VerifyAttestationSignature(ctx, beaconState, att)
|
||||
}
|
||||
|
||||
// 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 ProcessAttestationsNoVerifySignature(
|
||||
ctx context.Context,
|
||||
beaconState iface.BeaconState,
|
||||
b interfaces.SignedBeaconBlock,
|
||||
) (iface.BeaconState, error) {
|
||||
beaconState state.BeaconState,
|
||||
b block.SignedBeaconBlock,
|
||||
) (state.BeaconState, error) {
|
||||
if err := helpers.VerifyNilBeaconBlock(b); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -104,7 +41,7 @@ func ProcessAttestationsNoVerifySignature(
|
||||
// used before processing attestation with the beacon state.
|
||||
func VerifyAttestationNoVerifySignature(
|
||||
ctx context.Context,
|
||||
beaconState iface.ReadOnlyBeaconState,
|
||||
beaconState state.ReadOnlyBeaconState,
|
||||
att *ethpb.Attestation,
|
||||
) error {
|
||||
ctx, span := trace.StartSpan(ctx, "core.VerifyAttestationNoVerifySignature")
|
||||
@@ -188,9 +125,9 @@ func VerifyAttestationNoVerifySignature(
|
||||
// method is used to validate attestations whose signatures have already been verified.
|
||||
func ProcessAttestationNoVerifySignature(
|
||||
ctx context.Context,
|
||||
beaconState iface.BeaconState,
|
||||
beaconState state.BeaconState,
|
||||
att *ethpb.Attestation,
|
||||
) (iface.BeaconState, error) {
|
||||
) (state.BeaconState, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "core.ProcessAttestationNoVerifySignature")
|
||||
defer span.End()
|
||||
|
||||
@@ -205,7 +142,7 @@ func ProcessAttestationNoVerifySignature(
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pendingAtt := &pb.PendingAttestation{
|
||||
pendingAtt := ðpb.PendingAttestation{
|
||||
Data: data,
|
||||
AggregationBits: att.AggregationBits,
|
||||
InclusionDelay: beaconState.Slot() - s,
|
||||
@@ -227,7 +164,7 @@ func ProcessAttestationNoVerifySignature(
|
||||
|
||||
// VerifyAttestationSignature converts and attestation into an indexed attestation and verifies
|
||||
// the signature in that attestation.
|
||||
func VerifyAttestationSignature(ctx context.Context, beaconState iface.ReadOnlyBeaconState, att *ethpb.Attestation) error {
|
||||
func VerifyAttestationSignature(ctx context.Context, beaconState state.ReadOnlyBeaconState, att *ethpb.Attestation) error {
|
||||
if err := helpers.ValidateNilAttestation(att); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -258,7 +195,7 @@ func VerifyAttestationSignature(ctx context.Context, beaconState iface.ReadOnlyB
|
||||
// domain = get_domain(state, DOMAIN_BEACON_ATTESTER, indexed_attestation.data.target.epoch)
|
||||
// signing_root = compute_signing_root(indexed_attestation.data, domain)
|
||||
// return bls.FastAggregateVerify(pubkeys, signing_root, indexed_attestation.signature)
|
||||
func VerifyIndexedAttestation(ctx context.Context, beaconState iface.ReadOnlyBeaconState, indexedAtt *ethpb.IndexedAttestation) error {
|
||||
func VerifyIndexedAttestation(ctx context.Context, beaconState state.ReadOnlyBeaconState, indexedAtt *ethpb.IndexedAttestation) error {
|
||||
ctx, span := trace.StartSpan(ctx, "core.VerifyIndexedAttestation")
|
||||
defer span.End()
|
||||
|
||||
|
||||
@@ -7,9 +7,8 @@ import (
|
||||
|
||||
"github.com/prysmaticlabs/go-bitfield"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
||||
v1 "github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
@@ -33,7 +32,7 @@ func TestProcessAttestationNoVerifySignature_BeaconFuzzIssue78(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
spb := &pb.BeaconState{}
|
||||
spb := ðpb.BeaconState{}
|
||||
if err := spb.UnmarshalSSZ(stateData); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -73,7 +72,7 @@ func TestVerifyAttestationNoVerifySignature_IncorrectSourceEpoch(t *testing.T) {
|
||||
ckp := beaconState.CurrentJustifiedCheckpoint()
|
||||
copy(ckp.Root, "hello-world")
|
||||
require.NoError(t, beaconState.SetCurrentJustifiedCheckpoint(ckp))
|
||||
require.NoError(t, beaconState.AppendCurrentEpochAttestations(&pb.PendingAttestation{}))
|
||||
require.NoError(t, beaconState.AppendCurrentEpochAttestations(ðpb.PendingAttestation{}))
|
||||
|
||||
err = blocks.VerifyAttestationNoVerifySignature(context.TODO(), beaconState, att)
|
||||
assert.NotEqual(t, nil, err)
|
||||
|
||||
@@ -2,17 +2,14 @@ package blocks_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/go-bitfield"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/eth/v1alpha1/wrapper"
|
||||
v1 "github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/shared/aggregation"
|
||||
attaggregation "github.com/prysmaticlabs/prysm/shared/aggregation/attestations"
|
||||
"github.com/prysmaticlabs/prysm/shared/attestationutil"
|
||||
@@ -24,208 +21,6 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
func TestProcessAttestations_InclusionDelayFailure(t *testing.T) {
|
||||
attestations := []*ethpb.Attestation{
|
||||
testutil.HydrateAttestation(ðpb.Attestation{
|
||||
Data: ðpb.AttestationData{
|
||||
Target: ðpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
|
||||
Slot: 5,
|
||||
},
|
||||
}),
|
||||
}
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block = ðpb.BeaconBlock{
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
Attestations: attestations,
|
||||
},
|
||||
}
|
||||
beaconState, _ := testutil.DeterministicGenesisState(t, 100)
|
||||
|
||||
want := fmt.Sprintf(
|
||||
"attestation slot %d + inclusion delay %d > state slot %d",
|
||||
attestations[0].Data.Slot,
|
||||
params.BeaconConfig().MinAttestationInclusionDelay,
|
||||
beaconState.Slot(),
|
||||
)
|
||||
_, err := blocks.ProcessAttestations(context.Background(), beaconState, wrapper.WrappedPhase0SignedBeaconBlock(b))
|
||||
assert.ErrorContains(t, want, err)
|
||||
}
|
||||
|
||||
func TestProcessAttestations_NeitherCurrentNorPrevEpoch(t *testing.T) {
|
||||
att := testutil.HydrateAttestation(ðpb.Attestation{
|
||||
Data: ðpb.AttestationData{
|
||||
Source: ðpb.Checkpoint{Epoch: 0, Root: []byte("hello-world")},
|
||||
Target: ðpb.Checkpoint{Epoch: 0}}})
|
||||
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block = ðpb.BeaconBlock{
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
Attestations: []*ethpb.Attestation{att},
|
||||
},
|
||||
}
|
||||
beaconState, _ := testutil.DeterministicGenesisState(t, 100)
|
||||
err := beaconState.SetSlot(beaconState.Slot() + params.BeaconConfig().SlotsPerEpoch*4 + params.BeaconConfig().MinAttestationInclusionDelay)
|
||||
require.NoError(t, err)
|
||||
pfc := beaconState.PreviousJustifiedCheckpoint()
|
||||
pfc.Root = []byte("hello-world")
|
||||
require.NoError(t, beaconState.SetPreviousJustifiedCheckpoint(pfc))
|
||||
require.NoError(t, beaconState.AppendPreviousEpochAttestations(&pb.PendingAttestation{}))
|
||||
|
||||
want := fmt.Sprintf(
|
||||
"expected target epoch (%d) to be the previous epoch (%d) or the current epoch (%d)",
|
||||
att.Data.Target.Epoch,
|
||||
helpers.PrevEpoch(beaconState),
|
||||
helpers.CurrentEpoch(beaconState),
|
||||
)
|
||||
_, err = blocks.ProcessAttestations(context.Background(), beaconState, wrapper.WrappedPhase0SignedBeaconBlock(b))
|
||||
assert.ErrorContains(t, want, err)
|
||||
}
|
||||
|
||||
func TestProcessAttestations_CurrentEpochFFGDataMismatches(t *testing.T) {
|
||||
attestations := []*ethpb.Attestation{
|
||||
{
|
||||
Data: ðpb.AttestationData{
|
||||
Target: ðpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
|
||||
Source: ðpb.Checkpoint{Epoch: 1, Root: make([]byte, 32)},
|
||||
},
|
||||
AggregationBits: bitfield.Bitlist{0x09},
|
||||
},
|
||||
}
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block = ðpb.BeaconBlock{
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
Attestations: attestations,
|
||||
},
|
||||
}
|
||||
beaconState, _ := testutil.DeterministicGenesisState(t, 100)
|
||||
require.NoError(t, beaconState.SetSlot(beaconState.Slot()+params.BeaconConfig().MinAttestationInclusionDelay))
|
||||
cfc := beaconState.CurrentJustifiedCheckpoint()
|
||||
cfc.Root = []byte("hello-world")
|
||||
require.NoError(t, beaconState.SetCurrentJustifiedCheckpoint(cfc))
|
||||
require.NoError(t, beaconState.AppendCurrentEpochAttestations(&pb.PendingAttestation{}))
|
||||
|
||||
want := "source check point not equal to current justified checkpoint"
|
||||
_, err := blocks.ProcessAttestations(context.Background(), beaconState, wrapper.WrappedPhase0SignedBeaconBlock(b))
|
||||
assert.ErrorContains(t, want, err)
|
||||
b.Block.Body.Attestations[0].Data.Source.Epoch = helpers.CurrentEpoch(beaconState)
|
||||
b.Block.Body.Attestations[0].Data.Source.Root = []byte{}
|
||||
_, err = blocks.ProcessAttestations(context.Background(), beaconState, wrapper.WrappedPhase0SignedBeaconBlock(b))
|
||||
assert.ErrorContains(t, want, err)
|
||||
}
|
||||
|
||||
func TestProcessAttestations_PrevEpochFFGDataMismatches(t *testing.T) {
|
||||
beaconState, _ := testutil.DeterministicGenesisState(t, 100)
|
||||
|
||||
aggBits := bitfield.NewBitlist(3)
|
||||
aggBits.SetBitAt(0, true)
|
||||
attestations := []*ethpb.Attestation{
|
||||
{
|
||||
Data: ðpb.AttestationData{
|
||||
Source: ðpb.Checkpoint{Epoch: 1, Root: make([]byte, 32)},
|
||||
Target: ðpb.Checkpoint{Epoch: 1, Root: make([]byte, 32)},
|
||||
Slot: params.BeaconConfig().SlotsPerEpoch,
|
||||
},
|
||||
AggregationBits: aggBits,
|
||||
},
|
||||
}
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block = ðpb.BeaconBlock{
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
Attestations: attestations,
|
||||
},
|
||||
}
|
||||
|
||||
err := beaconState.SetSlot(beaconState.Slot() + 2*params.BeaconConfig().SlotsPerEpoch)
|
||||
require.NoError(t, err)
|
||||
pfc := beaconState.PreviousJustifiedCheckpoint()
|
||||
pfc.Root = []byte("hello-world")
|
||||
require.NoError(t, beaconState.SetPreviousJustifiedCheckpoint(pfc))
|
||||
require.NoError(t, beaconState.AppendPreviousEpochAttestations(&pb.PendingAttestation{}))
|
||||
|
||||
want := "source check point not equal to previous justified checkpoint"
|
||||
_, err = blocks.ProcessAttestations(context.Background(), beaconState, wrapper.WrappedPhase0SignedBeaconBlock(b))
|
||||
assert.ErrorContains(t, want, err)
|
||||
b.Block.Body.Attestations[0].Data.Source.Epoch = helpers.PrevEpoch(beaconState)
|
||||
b.Block.Body.Attestations[0].Data.Target.Epoch = helpers.PrevEpoch(beaconState)
|
||||
b.Block.Body.Attestations[0].Data.Source.Root = []byte{}
|
||||
_, err = blocks.ProcessAttestations(context.Background(), beaconState, wrapper.WrappedPhase0SignedBeaconBlock(b))
|
||||
assert.ErrorContains(t, want, err)
|
||||
}
|
||||
|
||||
func TestProcessAttestations_InvalidAggregationBitsLength(t *testing.T) {
|
||||
beaconState, _ := testutil.DeterministicGenesisState(t, 100)
|
||||
|
||||
aggBits := bitfield.NewBitlist(4)
|
||||
att := ðpb.Attestation{
|
||||
Data: ðpb.AttestationData{
|
||||
Source: ðpb.Checkpoint{Epoch: 0, Root: []byte("hello-world")},
|
||||
Target: ðpb.Checkpoint{Epoch: 0}},
|
||||
AggregationBits: aggBits,
|
||||
}
|
||||
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block = ðpb.BeaconBlock{
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
Attestations: []*ethpb.Attestation{att},
|
||||
},
|
||||
}
|
||||
|
||||
err := beaconState.SetSlot(beaconState.Slot() + params.BeaconConfig().MinAttestationInclusionDelay)
|
||||
require.NoError(t, err)
|
||||
|
||||
cfc := beaconState.CurrentJustifiedCheckpoint()
|
||||
cfc.Root = []byte("hello-world")
|
||||
require.NoError(t, beaconState.SetCurrentJustifiedCheckpoint(cfc))
|
||||
require.NoError(t, beaconState.AppendCurrentEpochAttestations(&pb.PendingAttestation{}))
|
||||
|
||||
expected := "failed to verify aggregation bitfield: wanted participants bitfield length 3, got: 4"
|
||||
_, err = blocks.ProcessAttestations(context.Background(), beaconState, wrapper.WrappedPhase0SignedBeaconBlock(b))
|
||||
assert.ErrorContains(t, expected, err)
|
||||
}
|
||||
|
||||
func TestProcessAttestations_OK(t *testing.T) {
|
||||
beaconState, privKeys := testutil.DeterministicGenesisState(t, 100)
|
||||
|
||||
aggBits := bitfield.NewBitlist(3)
|
||||
aggBits.SetBitAt(0, true)
|
||||
var mockRoot [32]byte
|
||||
copy(mockRoot[:], "hello-world")
|
||||
att := testutil.HydrateAttestation(ðpb.Attestation{
|
||||
Data: ðpb.AttestationData{
|
||||
Source: ðpb.Checkpoint{Root: mockRoot[:]},
|
||||
Target: ðpb.Checkpoint{Root: mockRoot[:]},
|
||||
},
|
||||
AggregationBits: aggBits,
|
||||
})
|
||||
|
||||
cfc := beaconState.CurrentJustifiedCheckpoint()
|
||||
cfc.Root = mockRoot[:]
|
||||
require.NoError(t, beaconState.SetCurrentJustifiedCheckpoint(cfc))
|
||||
require.NoError(t, beaconState.AppendCurrentEpochAttestations(&pb.PendingAttestation{}))
|
||||
|
||||
committee, err := helpers.BeaconCommitteeFromState(beaconState, att.Data.Slot, att.Data.CommitteeIndex)
|
||||
require.NoError(t, err)
|
||||
attestingIndices, err := attestationutil.AttestingIndices(att.AggregationBits, committee)
|
||||
require.NoError(t, err)
|
||||
sigs := make([]bls.Signature, len(attestingIndices))
|
||||
for i, indice := range attestingIndices {
|
||||
sb, err := helpers.ComputeDomainAndSign(beaconState, 0, att.Data, params.BeaconConfig().DomainBeaconAttester, privKeys[indice])
|
||||
require.NoError(t, err)
|
||||
sig, err := bls.SignatureFromBytes(sb)
|
||||
require.NoError(t, err)
|
||||
sigs[i] = sig
|
||||
}
|
||||
att.Signature = bls.AggregateSignatures(sigs).Marshal()
|
||||
|
||||
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, wrapper.WrappedPhase0SignedBeaconBlock(block))
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestProcessAggregatedAttestation_OverlappingBits(t *testing.T) {
|
||||
beaconState, privKeys := testutil.DeterministicGenesisState(t, 100)
|
||||
data := testutil.HydrateAttestationData(ðpb.AttestationData{
|
||||
@@ -243,7 +38,7 @@ func TestProcessAggregatedAttestation_OverlappingBits(t *testing.T) {
|
||||
cfc := beaconState.CurrentJustifiedCheckpoint()
|
||||
cfc.Root = bytesutil.PadTo([]byte("hello-world"), 32)
|
||||
require.NoError(t, beaconState.SetCurrentJustifiedCheckpoint(cfc))
|
||||
require.NoError(t, beaconState.AppendCurrentEpochAttestations(&pb.PendingAttestation{}))
|
||||
require.NoError(t, beaconState.AppendCurrentEpochAttestations(ðpb.PendingAttestation{}))
|
||||
|
||||
committee, err := helpers.BeaconCommitteeFromState(beaconState, att1.Data.Slot, att1.Data.CommitteeIndex)
|
||||
require.NoError(t, err)
|
||||
@@ -285,78 +80,6 @@ func TestProcessAggregatedAttestation_OverlappingBits(t *testing.T) {
|
||||
assert.ErrorContains(t, aggregation.ErrBitsOverlap.Error(), err)
|
||||
}
|
||||
|
||||
func TestProcessAggregatedAttestation_NoOverlappingBits(t *testing.T) {
|
||||
beaconState, privKeys := testutil.DeterministicGenesisState(t, 300)
|
||||
|
||||
var mockRoot [32]byte
|
||||
copy(mockRoot[:], "hello-world")
|
||||
data := testutil.HydrateAttestationData(ðpb.AttestationData{
|
||||
Source: ðpb.Checkpoint{Epoch: 0, Root: mockRoot[:]},
|
||||
Target: ðpb.Checkpoint{Epoch: 0, Root: mockRoot[:]},
|
||||
})
|
||||
aggBits1 := bitfield.NewBitlist(9)
|
||||
aggBits1.SetBitAt(0, true)
|
||||
aggBits1.SetBitAt(1, true)
|
||||
att1 := ðpb.Attestation{
|
||||
Data: data,
|
||||
AggregationBits: aggBits1,
|
||||
Signature: make([]byte, 32),
|
||||
}
|
||||
|
||||
cfc := beaconState.CurrentJustifiedCheckpoint()
|
||||
cfc.Root = mockRoot[:]
|
||||
require.NoError(t, beaconState.SetCurrentJustifiedCheckpoint(cfc))
|
||||
require.NoError(t, beaconState.AppendCurrentEpochAttestations(&pb.PendingAttestation{}))
|
||||
|
||||
committee, err := helpers.BeaconCommitteeFromState(beaconState, att1.Data.Slot, att1.Data.CommitteeIndex)
|
||||
require.NoError(t, err)
|
||||
attestingIndices1, err := attestationutil.AttestingIndices(att1.AggregationBits, committee)
|
||||
require.NoError(t, err)
|
||||
sigs := make([]bls.Signature, len(attestingIndices1))
|
||||
for i, indice := range attestingIndices1 {
|
||||
sb, err := helpers.ComputeDomainAndSign(beaconState, 0, data, params.BeaconConfig().DomainBeaconAttester, privKeys[indice])
|
||||
require.NoError(t, err)
|
||||
sig, err := bls.SignatureFromBytes(sb)
|
||||
require.NoError(t, err)
|
||||
sigs[i] = sig
|
||||
}
|
||||
att1.Signature = bls.AggregateSignatures(sigs).Marshal()
|
||||
|
||||
aggBits2 := bitfield.NewBitlist(9)
|
||||
aggBits2.SetBitAt(2, true)
|
||||
aggBits2.SetBitAt(3, true)
|
||||
att2 := ðpb.Attestation{
|
||||
Data: data,
|
||||
AggregationBits: aggBits2,
|
||||
Signature: make([]byte, 32),
|
||||
}
|
||||
|
||||
committee, err = helpers.BeaconCommitteeFromState(beaconState, att2.Data.Slot, att2.Data.CommitteeIndex)
|
||||
require.NoError(t, err)
|
||||
attestingIndices2, err := attestationutil.AttestingIndices(att2.AggregationBits, committee)
|
||||
require.NoError(t, err)
|
||||
sigs = make([]bls.Signature, len(attestingIndices2))
|
||||
for i, indice := range attestingIndices2 {
|
||||
sb, err := helpers.ComputeDomainAndSign(beaconState, 0, att2.Data, params.BeaconConfig().DomainBeaconAttester, privKeys[indice])
|
||||
require.NoError(t, err)
|
||||
sig, err := bls.SignatureFromBytes(sb)
|
||||
require.NoError(t, err)
|
||||
sigs[i] = sig
|
||||
}
|
||||
att2.Signature = bls.AggregateSignatures(sigs).Marshal()
|
||||
|
||||
aggregatedAtt, err := attaggregation.AggregatePair(att1, att2)
|
||||
require.NoError(t, err)
|
||||
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, wrapper.WrappedPhase0SignedBeaconBlock(block))
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestVerifyAttestationNoVerifySignature_IncorrectSlotTargetEpoch(t *testing.T) {
|
||||
beaconState, _ := testutil.DeterministicGenesisState(t, 1)
|
||||
|
||||
@@ -396,7 +119,7 @@ func TestProcessAttestationsNoVerify_OK(t *testing.T) {
|
||||
ckp := beaconState.CurrentJustifiedCheckpoint()
|
||||
copy(ckp.Root, "hello-world")
|
||||
require.NoError(t, beaconState.SetCurrentJustifiedCheckpoint(ckp))
|
||||
require.NoError(t, beaconState.AppendCurrentEpochAttestations(&pb.PendingAttestation{}))
|
||||
require.NoError(t, beaconState.AppendCurrentEpochAttestations(ðpb.PendingAttestation{}))
|
||||
|
||||
_, err = blocks.ProcessAttestationNoVerifySignature(context.TODO(), beaconState, att)
|
||||
assert.NoError(t, err)
|
||||
@@ -427,7 +150,7 @@ func TestVerifyAttestationNoVerifySignature_OK(t *testing.T) {
|
||||
ckp := beaconState.CurrentJustifiedCheckpoint()
|
||||
copy(ckp.Root, "hello-world")
|
||||
require.NoError(t, beaconState.SetCurrentJustifiedCheckpoint(ckp))
|
||||
require.NoError(t, beaconState.AppendCurrentEpochAttestations(&pb.PendingAttestation{}))
|
||||
require.NoError(t, beaconState.AppendCurrentEpochAttestations(ðpb.PendingAttestation{}))
|
||||
|
||||
err = blocks.VerifyAttestationNoVerifySignature(context.TODO(), beaconState, att)
|
||||
assert.NoError(t, err)
|
||||
@@ -453,7 +176,7 @@ func TestVerifyAttestationNoVerifySignature_BadAttIdx(t *testing.T) {
|
||||
ckp := beaconState.CurrentJustifiedCheckpoint()
|
||||
copy(ckp.Root, "hello-world")
|
||||
require.NoError(t, beaconState.SetCurrentJustifiedCheckpoint(ckp))
|
||||
require.NoError(t, beaconState.AppendCurrentEpochAttestations(&pb.PendingAttestation{}))
|
||||
require.NoError(t, beaconState.AppendCurrentEpochAttestations(ðpb.PendingAttestation{}))
|
||||
err := blocks.VerifyAttestationNoVerifySignature(context.TODO(), beaconState, att)
|
||||
require.ErrorContains(t, "committee index 100 >= committee count 1", err)
|
||||
}
|
||||
@@ -467,7 +190,7 @@ func TestConvertToIndexed_OK(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
state, err := v1.InitializeFromProto(&pb.BeaconState{
|
||||
state, err := v1.InitializeFromProto(ðpb.BeaconState{
|
||||
Slot: 5,
|
||||
Validators: validators,
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
@@ -525,10 +248,10 @@ func TestVerifyIndexedAttestation_OK(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
state, err := v1.InitializeFromProto(&pb.BeaconState{
|
||||
state, err := v1.InitializeFromProto(ðpb.BeaconState{
|
||||
Slot: 5,
|
||||
Validators: validators,
|
||||
Fork: &pb.Fork{
|
||||
Fork: ðpb.Fork{
|
||||
Epoch: 0,
|
||||
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
@@ -676,7 +399,7 @@ func TestVerifyAttestations_HandlesPlannedFork(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, st.SetSlot(35))
|
||||
require.NoError(t, st.SetValidators(validators))
|
||||
require.NoError(t, st.SetFork(&pb.Fork{
|
||||
require.NoError(t, st.SetFork(ðpb.Fork{
|
||||
Epoch: 1,
|
||||
CurrentVersion: []byte{0, 1, 2, 3},
|
||||
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
@@ -803,7 +526,7 @@ func TestRetrieveAttestationSignatureSet_AcrossFork(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, st.SetSlot(5))
|
||||
require.NoError(t, st.SetValidators(validators))
|
||||
require.NoError(t, st.SetFork(&pb.Fork{Epoch: 1, CurrentVersion: []byte{0, 1, 2, 3}, PreviousVersion: []byte{0, 1, 1, 1}}))
|
||||
require.NoError(t, st.SetFork(ðpb.Fork{Epoch: 1, CurrentVersion: []byte{0, 1, 2, 3}, PreviousVersion: []byte{0, 1, 1, 1}}))
|
||||
|
||||
comm1, err := helpers.BeaconCommitteeFromState(st, 1 /*slot*/, 0 /*committeeIndex*/)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -7,11 +7,13 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/shared/attestationutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/slashutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/sliceutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/version"
|
||||
)
|
||||
|
||||
// ProcessAttesterSlashings is one of the operations performed
|
||||
@@ -35,10 +37,10 @@ import (
|
||||
// assert slashed_any
|
||||
func ProcessAttesterSlashings(
|
||||
ctx context.Context,
|
||||
beaconState iface.BeaconState,
|
||||
beaconState state.BeaconState,
|
||||
slashings []*ethpb.AttesterSlashing,
|
||||
slashFunc slashValidatorFunc,
|
||||
) (iface.BeaconState, error) {
|
||||
) (state.BeaconState, error) {
|
||||
for idx, slashing := range slashings {
|
||||
if err := VerifyAttesterSlashing(ctx, beaconState, slashing); err != nil {
|
||||
return nil, errors.Wrapf(err, "could not verify attester slashing %d", idx)
|
||||
@@ -50,14 +52,19 @@ func ProcessAttesterSlashings(
|
||||
currentEpoch := helpers.SlotToEpoch(beaconState.Slot())
|
||||
var err error
|
||||
var slashedAny bool
|
||||
var val iface.ReadOnlyValidator
|
||||
var val state.ReadOnlyValidator
|
||||
for _, validatorIndex := range slashableIndices {
|
||||
val, err = beaconState.ValidatorAtIndexReadOnly(types.ValidatorIndex(validatorIndex))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if helpers.IsSlashableValidator(val.ActivationEpoch(), val.WithdrawableEpoch(), val.Slashed(), currentEpoch) {
|
||||
beaconState, err = slashFunc(beaconState, types.ValidatorIndex(validatorIndex))
|
||||
cfg := params.BeaconConfig()
|
||||
slashingQuotient := cfg.MinSlashingPenaltyQuotient
|
||||
if beaconState.Version() == version.Altair {
|
||||
slashingQuotient = cfg.MinSlashingPenaltyQuotientAltair
|
||||
}
|
||||
beaconState, err = slashFunc(beaconState, types.ValidatorIndex(validatorIndex), slashingQuotient, cfg.ProposerRewardQuotient)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not slash validator index %d",
|
||||
validatorIndex)
|
||||
@@ -73,7 +80,7 @@ func ProcessAttesterSlashings(
|
||||
}
|
||||
|
||||
// VerifyAttesterSlashing validates the attestation data in both attestations in the slashing object.
|
||||
func VerifyAttesterSlashing(ctx context.Context, beaconState iface.ReadOnlyBeaconState, slashing *ethpb.AttesterSlashing) error {
|
||||
func VerifyAttesterSlashing(ctx context.Context, beaconState state.ReadOnlyBeaconState, slashing *ethpb.AttesterSlashing) error {
|
||||
if slashing == nil {
|
||||
return errors.New("nil slashing")
|
||||
}
|
||||
|
||||
@@ -8,9 +8,8 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
v "github.com/prysmaticlabs/prysm/beacon-chain/core/validators"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
||||
v1 "github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
@@ -47,7 +46,7 @@ func TestProcessAttesterSlashings_DataNotSlashable(t *testing.T) {
|
||||
var registry []*ethpb.Validator
|
||||
currentSlot := types.Slot(0)
|
||||
|
||||
beaconState, err := v1.InitializeFromProto(&pb.BeaconState{
|
||||
beaconState, err := v1.InitializeFromProto(ðpb.BeaconState{
|
||||
Validators: registry,
|
||||
Slot: currentSlot,
|
||||
})
|
||||
@@ -66,7 +65,7 @@ func TestProcessAttesterSlashings_IndexedAttestationFailedToVerify(t *testing.T)
|
||||
var registry []*ethpb.Validator
|
||||
currentSlot := types.Slot(0)
|
||||
|
||||
beaconState, err := v1.InitializeFromProto(&pb.BeaconState{
|
||||
beaconState, err := v1.InitializeFromProto(ðpb.BeaconState{
|
||||
Validators: registry,
|
||||
Slot: currentSlot,
|
||||
})
|
||||
|
||||
@@ -7,10 +7,10 @@ import (
|
||||
fuzz "github.com/google/gofuzz"
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
v "github.com/prysmaticlabs/prysm/beacon-chain/core/validators"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
eth "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/eth/v1alpha1/wrapper"
|
||||
v1 "github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
|
||||
eth "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/wrapper"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
@@ -18,7 +18,7 @@ import (
|
||||
func TestFuzzProcessAttestationNoVerify_10000(t *testing.T) {
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
ctx := context.Background()
|
||||
state := &pb.BeaconState{}
|
||||
state := ðpb.BeaconState{}
|
||||
att := ð.Attestation{}
|
||||
|
||||
for i := 0; i < 10000; i++ {
|
||||
@@ -33,7 +33,7 @@ func TestFuzzProcessAttestationNoVerify_10000(t *testing.T) {
|
||||
|
||||
func TestFuzzProcessBlockHeader_10000(t *testing.T) {
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
state := &pb.BeaconState{}
|
||||
state := ðpb.BeaconState{}
|
||||
block := ð.SignedBeaconBlock{}
|
||||
|
||||
for i := 0; i < 10000; i++ {
|
||||
@@ -105,7 +105,7 @@ func TestFuzzEth1DataHasEnoughSupport_10000(t *testing.T) {
|
||||
for i := 0; i < 100000; i++ {
|
||||
fuzzer.Fuzz(eth1data)
|
||||
fuzzer.Fuzz(&stateVotes)
|
||||
s, err := v1.InitializeFromProto(&pb.BeaconState{
|
||||
s, err := v1.InitializeFromProto(ðpb.BeaconState{
|
||||
Eth1DataVotes: stateVotes,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
@@ -117,7 +117,7 @@ func TestFuzzEth1DataHasEnoughSupport_10000(t *testing.T) {
|
||||
|
||||
func TestFuzzProcessBlockHeaderNoVerify_10000(t *testing.T) {
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
state := &pb.BeaconState{}
|
||||
state := ðpb.BeaconState{}
|
||||
block := ð.BeaconBlock{}
|
||||
|
||||
for i := 0; i < 10000; i++ {
|
||||
@@ -132,7 +132,7 @@ func TestFuzzProcessBlockHeaderNoVerify_10000(t *testing.T) {
|
||||
|
||||
func TestFuzzProcessRandao_10000(t *testing.T) {
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
state := &pb.BeaconState{}
|
||||
state := ðpb.BeaconState{}
|
||||
b := ð.SignedBeaconBlock{}
|
||||
|
||||
for i := 0; i < 10000; i++ {
|
||||
@@ -149,7 +149,7 @@ func TestFuzzProcessRandao_10000(t *testing.T) {
|
||||
|
||||
func TestFuzzProcessRandaoNoVerify_10000(t *testing.T) {
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
state := &pb.BeaconState{}
|
||||
state := ðpb.BeaconState{}
|
||||
blockBody := ð.BeaconBlockBody{}
|
||||
|
||||
for i := 0; i < 10000; i++ {
|
||||
@@ -166,7 +166,7 @@ func TestFuzzProcessRandaoNoVerify_10000(t *testing.T) {
|
||||
|
||||
func TestFuzzProcessProposerSlashings_10000(t *testing.T) {
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
state := &pb.BeaconState{}
|
||||
state := ðpb.BeaconState{}
|
||||
p := ð.ProposerSlashing{}
|
||||
ctx := context.Background()
|
||||
for i := 0; i < 10000; i++ {
|
||||
@@ -183,7 +183,7 @@ func TestFuzzProcessProposerSlashings_10000(t *testing.T) {
|
||||
|
||||
func TestFuzzVerifyProposerSlashing_10000(t *testing.T) {
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
state := &pb.BeaconState{}
|
||||
state := ðpb.BeaconState{}
|
||||
proposerSlashing := ð.ProposerSlashing{}
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
@@ -197,7 +197,7 @@ func TestFuzzVerifyProposerSlashing_10000(t *testing.T) {
|
||||
|
||||
func TestFuzzProcessAttesterSlashings_10000(t *testing.T) {
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
state := &pb.BeaconState{}
|
||||
state := ðpb.BeaconState{}
|
||||
a := ð.AttesterSlashing{}
|
||||
ctx := context.Background()
|
||||
for i := 0; i < 10000; i++ {
|
||||
@@ -214,7 +214,7 @@ func TestFuzzProcessAttesterSlashings_10000(t *testing.T) {
|
||||
|
||||
func TestFuzzVerifyAttesterSlashing_10000(t *testing.T) {
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
state := &pb.BeaconState{}
|
||||
state := ðpb.BeaconState{}
|
||||
attesterSlashing := ð.AttesterSlashing{}
|
||||
ctx := context.Background()
|
||||
for i := 0; i < 10000; i++ {
|
||||
@@ -249,26 +249,9 @@ func TestFuzzslashableAttesterIndices_10000(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestFuzzProcessAttestations_10000(t *testing.T) {
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
state := &pb.BeaconState{}
|
||||
b := ð.SignedBeaconBlock{}
|
||||
ctx := context.Background()
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(b)
|
||||
s, err := v1.InitializeFromProtoUnsafe(state)
|
||||
require.NoError(t, err)
|
||||
r, err := ProcessAttestations(ctx, s, wrapper.WrappedPhase0SignedBeaconBlock(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, b)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFuzzProcessAttestationsNoVerify_10000(t *testing.T) {
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
state := &pb.BeaconState{}
|
||||
state := ðpb.BeaconState{}
|
||||
b := ð.SignedBeaconBlock{}
|
||||
ctx := context.Background()
|
||||
for i := 0; i < 10000; i++ {
|
||||
@@ -283,26 +266,9 @@ func TestFuzzProcessAttestationsNoVerify_10000(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestFuzzProcessAttestation_10000(t *testing.T) {
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
state := &pb.BeaconState{}
|
||||
attestation := ð.Attestation{}
|
||||
ctx := context.Background()
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(attestation)
|
||||
s, err := v1.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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFuzzVerifyIndexedAttestationn_10000(t *testing.T) {
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
state := &pb.BeaconState{}
|
||||
state := ðpb.BeaconState{}
|
||||
idxAttestation := ð.IndexedAttestation{}
|
||||
ctx := context.Background()
|
||||
for i := 0; i < 10000; i++ {
|
||||
@@ -317,7 +283,7 @@ func TestFuzzVerifyIndexedAttestationn_10000(t *testing.T) {
|
||||
|
||||
func TestFuzzVerifyAttestation_10000(t *testing.T) {
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
state := &pb.BeaconState{}
|
||||
state := ðpb.BeaconState{}
|
||||
attestation := ð.Attestation{}
|
||||
ctx := context.Background()
|
||||
for i := 0; i < 10000; i++ {
|
||||
@@ -332,7 +298,7 @@ func TestFuzzVerifyAttestation_10000(t *testing.T) {
|
||||
|
||||
func TestFuzzProcessDeposits_10000(t *testing.T) {
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
state := &pb.BeaconState{}
|
||||
state := ðpb.BeaconState{}
|
||||
deposits := make([]*eth.Deposit, 100)
|
||||
ctx := context.Background()
|
||||
for i := 0; i < 10000; i++ {
|
||||
@@ -351,7 +317,7 @@ func TestFuzzProcessDeposits_10000(t *testing.T) {
|
||||
|
||||
func TestFuzzProcessPreGenesisDeposit_10000(t *testing.T) {
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
state := &pb.BeaconState{}
|
||||
state := ðpb.BeaconState{}
|
||||
deposit := ð.Deposit{}
|
||||
ctx := context.Background()
|
||||
|
||||
@@ -369,7 +335,7 @@ func TestFuzzProcessPreGenesisDeposit_10000(t *testing.T) {
|
||||
|
||||
func TestFuzzProcessDeposit_10000(t *testing.T) {
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
state := &pb.BeaconState{}
|
||||
state := ðpb.BeaconState{}
|
||||
deposit := ð.Deposit{}
|
||||
|
||||
for i := 0; i < 10000; i++ {
|
||||
@@ -377,7 +343,7 @@ func TestFuzzProcessDeposit_10000(t *testing.T) {
|
||||
fuzzer.Fuzz(deposit)
|
||||
s, err := v1.InitializeFromProtoUnsafe(state)
|
||||
require.NoError(t, err)
|
||||
r, err := ProcessDeposit(s, deposit, true)
|
||||
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)
|
||||
}
|
||||
@@ -386,7 +352,7 @@ func TestFuzzProcessDeposit_10000(t *testing.T) {
|
||||
|
||||
func TestFuzzverifyDeposit_10000(t *testing.T) {
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
state := &pb.BeaconState{}
|
||||
state := ðpb.BeaconState{}
|
||||
deposit := ð.Deposit{}
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
@@ -400,7 +366,7 @@ func TestFuzzverifyDeposit_10000(t *testing.T) {
|
||||
|
||||
func TestFuzzProcessVoluntaryExits_10000(t *testing.T) {
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
state := &pb.BeaconState{}
|
||||
state := ðpb.BeaconState{}
|
||||
e := ð.SignedVoluntaryExit{}
|
||||
ctx := context.Background()
|
||||
for i := 0; i < 10000; i++ {
|
||||
@@ -417,7 +383,7 @@ func TestFuzzProcessVoluntaryExits_10000(t *testing.T) {
|
||||
|
||||
func TestFuzzProcessVoluntaryExitsNoVerify_10000(t *testing.T) {
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
state := &pb.BeaconState{}
|
||||
state := ðpb.BeaconState{}
|
||||
e := ð.SignedVoluntaryExit{}
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
@@ -434,13 +400,14 @@ func TestFuzzProcessVoluntaryExitsNoVerify_10000(t *testing.T) {
|
||||
func TestFuzzVerifyExit_10000(t *testing.T) {
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
ve := ð.SignedVoluntaryExit{}
|
||||
val := v1.ReadOnlyValidator{}
|
||||
fork := &pb.Fork{}
|
||||
val, err := v1.NewValidator(ðpb.Validator{})
|
||||
_ = err
|
||||
fork := ðpb.Fork{}
|
||||
var slot types.Slot
|
||||
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(ve)
|
||||
fuzzer.Fuzz(&val)
|
||||
fuzzer.Fuzz(val)
|
||||
fuzzer.Fuzz(fork)
|
||||
fuzzer.Fuzz(&slot)
|
||||
err := VerifyExitAndSignature(val, slot, fork, ve, params.BeaconConfig().ZeroHash[:])
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
v "github.com/prysmaticlabs/prysm/beacon-chain/core/validators"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
|
||||
@@ -6,9 +6,8 @@ import (
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/depositutil"
|
||||
@@ -20,9 +19,9 @@ import (
|
||||
// ProcessPreGenesisDeposits processes a deposit for the beacon state before chainstart.
|
||||
func ProcessPreGenesisDeposits(
|
||||
ctx context.Context,
|
||||
beaconState iface.BeaconState,
|
||||
beaconState state.BeaconState,
|
||||
deposits []*ethpb.Deposit,
|
||||
) (iface.BeaconState, error) {
|
||||
) (state.BeaconState, error) {
|
||||
var err error
|
||||
beaconState, err = ProcessDeposits(ctx, beaconState, deposits)
|
||||
if err != nil {
|
||||
@@ -36,7 +35,7 @@ func ProcessPreGenesisDeposits(
|
||||
}
|
||||
|
||||
// ActivateValidatorWithEffectiveBalance updates validator's effective balance, and if it's above MaxEffectiveBalance, validator becomes active in genesis.
|
||||
func ActivateValidatorWithEffectiveBalance(beaconState iface.BeaconState, deposits []*ethpb.Deposit) (iface.BeaconState, error) {
|
||||
func ActivateValidatorWithEffectiveBalance(beaconState state.BeaconState, deposits []*ethpb.Deposit) (state.BeaconState, error) {
|
||||
for _, deposit := range deposits {
|
||||
pubkey := deposit.Data.PublicKey
|
||||
index, ok := beaconState.ValidatorIndexByPubkey(bytesutil.ToBytes48(pubkey))
|
||||
@@ -75,9 +74,9 @@ func ActivateValidatorWithEffectiveBalance(beaconState iface.BeaconState, deposi
|
||||
// process_deposit(state, deposit)
|
||||
func ProcessDeposits(
|
||||
ctx context.Context,
|
||||
beaconState iface.BeaconState,
|
||||
beaconState state.BeaconState,
|
||||
deposits []*ethpb.Deposit,
|
||||
) (iface.BeaconState, error) {
|
||||
) (state.BeaconState, error) {
|
||||
// Attempt to verify all deposit signatures at once, if this fails then fall back to processing
|
||||
// individual deposits with signature verification enabled.
|
||||
batchVerified, err := BatchVerifyDepositsSignatures(ctx, deposits)
|
||||
@@ -89,7 +88,7 @@ func ProcessDeposits(
|
||||
if deposit == nil || deposit.Data == nil {
|
||||
return nil, errors.New("got a nil deposit in block")
|
||||
}
|
||||
beaconState, err = ProcessDeposit(beaconState, deposit, batchVerified)
|
||||
beaconState, _, err = ProcessDeposit(beaconState, deposit, batchVerified)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not process deposit from %#x", bytesutil.Trunc(deposit.Data.PublicKey))
|
||||
}
|
||||
@@ -115,6 +114,8 @@ func BatchVerifyDepositsSignatures(ctx context.Context, deposits []*ethpb.Deposi
|
||||
|
||||
// ProcessDeposit takes in a deposit object and inserts it
|
||||
// into the registry as a new validator or balance change.
|
||||
// Returns the resulting state, a boolean to indicate whether or not the deposit
|
||||
// resulted in a new validator entry into the beacon state, and any error.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// def process_deposit(state: BeaconState, deposit: Deposit) -> None:
|
||||
@@ -152,15 +153,16 @@ func BatchVerifyDepositsSignatures(ctx context.Context, deposits []*ethpb.Deposi
|
||||
// # Increase balance by deposit amount
|
||||
// index = ValidatorIndex(validator_pubkeys.index(pubkey))
|
||||
// increase_balance(state, index, amount)
|
||||
func ProcessDeposit(beaconState iface.BeaconState, deposit *ethpb.Deposit, verifySignature bool) (iface.BeaconState, error) {
|
||||
func ProcessDeposit(beaconState state.BeaconState, deposit *ethpb.Deposit, verifySignature bool) (state.BeaconState, bool, error) {
|
||||
var newValidator bool
|
||||
if err := verifyDeposit(beaconState, deposit); err != nil {
|
||||
if deposit == nil || deposit.Data == nil {
|
||||
return nil, err
|
||||
return nil, newValidator, err
|
||||
}
|
||||
return nil, errors.Wrapf(err, "could not verify deposit from %#x", bytesutil.Trunc(deposit.Data.PublicKey))
|
||||
return nil, newValidator, errors.Wrapf(err, "could not verify deposit from %#x", bytesutil.Trunc(deposit.Data.PublicKey))
|
||||
}
|
||||
if err := beaconState.SetEth1DepositIndex(beaconState.Eth1DepositIndex() + 1); err != nil {
|
||||
return nil, err
|
||||
return nil, newValidator, err
|
||||
}
|
||||
pubKey := deposit.Data.PublicKey
|
||||
amount := deposit.Data.Amount
|
||||
@@ -169,12 +171,12 @@ func ProcessDeposit(beaconState iface.BeaconState, deposit *ethpb.Deposit, verif
|
||||
if verifySignature {
|
||||
domain, err := helpers.ComputeDomain(params.BeaconConfig().DomainDeposit, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, newValidator, err
|
||||
}
|
||||
if err := verifyDepositDataSigningRoot(deposit.Data, domain); err != nil {
|
||||
// Ignore this error as in the spec pseudo code.
|
||||
log.Debugf("Skipping deposit: could not verify deposit data signature: %v", err)
|
||||
return beaconState, nil
|
||||
return beaconState, newValidator, nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,19 +193,20 @@ func ProcessDeposit(beaconState iface.BeaconState, deposit *ethpb.Deposit, verif
|
||||
WithdrawableEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
EffectiveBalance: effectiveBalance,
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
return nil, newValidator, err
|
||||
}
|
||||
newValidator = true
|
||||
if err := beaconState.AppendBalance(amount); err != nil {
|
||||
return nil, err
|
||||
return nil, newValidator, err
|
||||
}
|
||||
} else if err := helpers.IncreaseBalance(beaconState, index, amount); err != nil {
|
||||
return nil, err
|
||||
return nil, newValidator, err
|
||||
}
|
||||
|
||||
return beaconState, nil
|
||||
return beaconState, newValidator, nil
|
||||
}
|
||||
|
||||
func verifyDeposit(beaconState iface.ReadOnlyBeaconState, deposit *ethpb.Deposit) error {
|
||||
func verifyDeposit(beaconState state.ReadOnlyBeaconState, deposit *ethpb.Deposit) error {
|
||||
// Verify Merkle proof of deposit and deposit trie root.
|
||||
if deposit == nil || deposit.Data == nil {
|
||||
return errors.New("received nil deposit or nil deposit data")
|
||||
@@ -258,7 +261,7 @@ func verifyDepositDataWithDomain(ctx context.Context, deps []*ethpb.Deposit, dom
|
||||
}
|
||||
pks[i] = dpk
|
||||
sigs[i] = dep.Data.Signature
|
||||
depositMessage := &pb.DepositMessage{
|
||||
depositMessage := ðpb.DepositMessage{
|
||||
PublicKey: dep.Data.PublicKey,
|
||||
WithdrawalCredentials: dep.Data.WithdrawalCredentials,
|
||||
Amount: dep.Data.Amount,
|
||||
|
||||
@@ -7,9 +7,8 @@ import (
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
||||
v1 "github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
@@ -40,11 +39,11 @@ func TestProcessDeposits_SameValidatorMultipleDepositsSameBlock(t *testing.T) {
|
||||
},
|
||||
}
|
||||
balances := []uint64{0}
|
||||
beaconState, err := v1.InitializeFromProto(&pb.BeaconState{
|
||||
beaconState, err := v1.InitializeFromProto(ðpb.BeaconState{
|
||||
Validators: registry,
|
||||
Balances: balances,
|
||||
Eth1Data: eth1Data,
|
||||
Fork: &pb.Fork{
|
||||
Fork: ðpb.Fork{
|
||||
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
},
|
||||
@@ -80,7 +79,7 @@ func TestProcessDeposits_MerkleBranchFailsVerification(t *testing.T) {
|
||||
Deposits: []*ethpb.Deposit{deposit},
|
||||
},
|
||||
}
|
||||
beaconState, err := v1.InitializeFromProto(&pb.BeaconState{
|
||||
beaconState, err := v1.InitializeFromProto(ðpb.BeaconState{
|
||||
Eth1Data: ðpb.Eth1Data{
|
||||
DepositRoot: []byte{0},
|
||||
BlockHash: []byte{1},
|
||||
@@ -111,11 +110,11 @@ func TestProcessDeposits_AddsNewValidatorDeposit(t *testing.T) {
|
||||
},
|
||||
}
|
||||
balances := []uint64{0}
|
||||
beaconState, err := v1.InitializeFromProto(&pb.BeaconState{
|
||||
beaconState, err := v1.InitializeFromProto(ðpb.BeaconState{
|
||||
Validators: registry,
|
||||
Balances: balances,
|
||||
Eth1Data: eth1Data,
|
||||
Fork: &pb.Fork{
|
||||
Fork: ðpb.Fork{
|
||||
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
},
|
||||
@@ -174,7 +173,7 @@ func TestProcessDeposits_RepeatedDeposit_IncreasesValidatorBalance(t *testing.T)
|
||||
}
|
||||
balances := []uint64{0, 50}
|
||||
root := depositTrie.Root()
|
||||
beaconState, err := v1.InitializeFromProto(&pb.BeaconState{
|
||||
beaconState, err := v1.InitializeFromProto(ðpb.BeaconState{
|
||||
Validators: registry,
|
||||
Balances: balances,
|
||||
Eth1Data: ðpb.Eth1Data{
|
||||
@@ -202,18 +201,19 @@ func TestProcessDeposit_AddsNewValidatorDeposit(t *testing.T) {
|
||||
},
|
||||
}
|
||||
balances := []uint64{0}
|
||||
beaconState, err := v1.InitializeFromProto(&pb.BeaconState{
|
||||
beaconState, err := v1.InitializeFromProto(ðpb.BeaconState{
|
||||
Validators: registry,
|
||||
Balances: balances,
|
||||
Eth1Data: eth1Data,
|
||||
Fork: &pb.Fork{
|
||||
Fork: ðpb.Fork{
|
||||
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
newState, err := blocks.ProcessDeposit(beaconState, dep[0], true)
|
||||
newState, isNewValidator, err := blocks.ProcessDeposit(beaconState, dep[0], true)
|
||||
require.NoError(t, err, "Process deposit failed")
|
||||
assert.Equal(t, true, isNewValidator, "Expected isNewValidator to be true")
|
||||
assert.Equal(t, 2, len(newState.Validators()), "Expected validator list to have length 2")
|
||||
assert.Equal(t, 2, len(newState.Balances()), "Expected validator balances list to have length 2")
|
||||
if newState.Balances()[1] != dep[0].Data.Amount {
|
||||
@@ -244,18 +244,19 @@ func TestProcessDeposit_SkipsInvalidDeposit(t *testing.T) {
|
||||
},
|
||||
}
|
||||
balances := []uint64{0}
|
||||
beaconState, err := v1.InitializeFromProto(&pb.BeaconState{
|
||||
beaconState, err := v1.InitializeFromProto(ðpb.BeaconState{
|
||||
Validators: registry,
|
||||
Balances: balances,
|
||||
Eth1Data: eth1Data,
|
||||
Fork: &pb.Fork{
|
||||
Fork: ðpb.Fork{
|
||||
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
newState, err := blocks.ProcessDeposit(beaconState, dep[0], true)
|
||||
newState, isNewValidator, err := blocks.ProcessDeposit(beaconState, dep[0], true)
|
||||
require.NoError(t, err, "Expected invalid block deposit to be ignored without error")
|
||||
assert.Equal(t, false, isNewValidator, "Expected isNewValidator to be false")
|
||||
|
||||
if newState.Eth1DepositIndex() != 1 {
|
||||
t.Errorf(
|
||||
@@ -299,11 +300,11 @@ func TestPreGenesisDeposits_SkipInvalidDeposit(t *testing.T) {
|
||||
},
|
||||
}
|
||||
balances := []uint64{0}
|
||||
beaconState, err := v1.InitializeFromProto(&pb.BeaconState{
|
||||
beaconState, err := v1.InitializeFromProto(ðpb.BeaconState{
|
||||
Validators: registry,
|
||||
Balances: balances,
|
||||
Eth1Data: eth1Data,
|
||||
Fork: &pb.Fork{
|
||||
Fork: ðpb.Fork{
|
||||
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
},
|
||||
@@ -338,3 +339,54 @@ func TestPreGenesisDeposits_SkipInvalidDeposit(t *testing.T) {
|
||||
t.Errorf("Expected validator balance at index 0 to stay 0, received: %v", newState.Balances()[0])
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessDeposit_RepeatedDeposit_IncreasesValidatorBalance(t *testing.T) {
|
||||
sk, err := bls.RandKey()
|
||||
require.NoError(t, err)
|
||||
deposit := ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: sk.PublicKey().Marshal(),
|
||||
Amount: 1000,
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
}
|
||||
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 := deposit.Data.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
// We then create a merkle branch for the test.
|
||||
depositTrie, err := trieutil.GenerateTrieFromItems([][]byte{leaf[:]}, params.BeaconConfig().DepositContractTreeDepth)
|
||||
require.NoError(t, err, "Could not generate trie")
|
||||
proof, err := depositTrie.MerkleProof(0)
|
||||
require.NoError(t, err, "Could not generate proof")
|
||||
|
||||
deposit.Proof = proof
|
||||
registry := []*ethpb.Validator{
|
||||
{
|
||||
PublicKey: []byte{1, 2, 3},
|
||||
},
|
||||
{
|
||||
PublicKey: sk.PublicKey().Marshal(),
|
||||
WithdrawalCredentials: []byte{1},
|
||||
},
|
||||
}
|
||||
balances := []uint64{0, 50}
|
||||
root := depositTrie.Root()
|
||||
beaconState, err := v1.InitializeFromProto(ðpb.BeaconState{
|
||||
Validators: registry,
|
||||
Balances: balances,
|
||||
Eth1Data: ðpb.Eth1Data{
|
||||
DepositRoot: root[:],
|
||||
BlockHash: root[:],
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
newState, isNewValidator, err := blocks.ProcessDeposit(beaconState, deposit, true /*verifySignature*/)
|
||||
require.NoError(t, err, "Process deposit failed")
|
||||
assert.Equal(t, false, isNewValidator, "Expected isNewValidator to be false")
|
||||
assert.Equal(t, uint64(1000+50), newState.Balances()[1], "Expected balance at index 1 to be 1050")
|
||||
}
|
||||
|
||||
@@ -5,8 +5,8 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/shared/copyutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
@@ -20,7 +20,7 @@ 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.eth1_data = body.eth1_data
|
||||
func ProcessEth1DataInBlock(_ context.Context, beaconState iface.BeaconState, eth1Data *ethpb.Eth1Data) (iface.BeaconState, error) {
|
||||
func ProcessEth1DataInBlock(_ context.Context, beaconState state.BeaconState, eth1Data *ethpb.Eth1Data) (state.BeaconState, error) {
|
||||
if beaconState == nil || beaconState.IsNil() {
|
||||
return nil, errors.New("nil state")
|
||||
}
|
||||
@@ -56,7 +56,7 @@ func AreEth1DataEqual(a, b *ethpb.Eth1Data) bool {
|
||||
// eth1 voting period. A vote is cast by including eth1data in a block and part of state processing
|
||||
// appends eth1data to the state in the Eth1DataVotes list. Iterating through this list checks the
|
||||
// votes to see if they match the eth1data.
|
||||
func Eth1DataHasEnoughSupport(beaconState iface.ReadOnlyBeaconState, data *ethpb.Eth1Data) (bool, error) {
|
||||
func Eth1DataHasEnoughSupport(beaconState state.ReadOnlyBeaconState, data *ethpb.Eth1Data) (bool, error) {
|
||||
voteCount := uint64(0)
|
||||
data = copyutil.CopyETH1Data(data)
|
||||
|
||||
|
||||
@@ -7,9 +7,8 @@ import (
|
||||
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
||||
v1 "github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/copyutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
@@ -71,7 +70,7 @@ func TestEth1DataHasEnoughSupport(t *testing.T) {
|
||||
c.EpochsPerEth1VotingPeriod = tt.votingPeriodLength
|
||||
params.OverrideBeaconConfig(c)
|
||||
|
||||
s, err := v1.InitializeFromProto(&pb.BeaconState{
|
||||
s, err := v1.InitializeFromProto(ðpb.BeaconState{
|
||||
Eth1DataVotes: tt.stateVotes,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
@@ -161,7 +160,7 @@ func TestAreEth1DataEqual(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestProcessEth1Data_SetsCorrectly(t *testing.T) {
|
||||
beaconState, err := v1.InitializeFromProto(&pb.BeaconState{
|
||||
beaconState, err := v1.InitializeFromProto(ðpb.BeaconState{
|
||||
Eth1DataVotes: []*ethpb.Eth1Data{},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -8,9 +8,8 @@ import (
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
v "github.com/prysmaticlabs/prysm/beacon-chain/core/validators"
|
||||
iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
@@ -45,9 +44,9 @@ var ValidatorCannotExitYetMsg = "validator has not been active long enough to ex
|
||||
// initiate_validator_exit(state, voluntary_exit.validator_index)
|
||||
func ProcessVoluntaryExits(
|
||||
_ context.Context,
|
||||
beaconState iface.BeaconState,
|
||||
beaconState state.BeaconState,
|
||||
exits []*ethpb.SignedVoluntaryExit,
|
||||
) (iface.BeaconState, error) {
|
||||
) (state.BeaconState, error) {
|
||||
for idx, exit := range exits {
|
||||
if exit == nil || exit.Exit == nil {
|
||||
return nil, errors.New("nil voluntary exit in block body")
|
||||
@@ -88,9 +87,9 @@ func ProcessVoluntaryExits(
|
||||
// # Initiate exit
|
||||
// initiate_validator_exit(state, voluntary_exit.validator_index)
|
||||
func VerifyExitAndSignature(
|
||||
validator iface.ReadOnlyValidator,
|
||||
validator state.ReadOnlyValidator,
|
||||
currentSlot types.Slot,
|
||||
fork *pb.Fork,
|
||||
fork *ethpb.Fork,
|
||||
signed *ethpb.SignedVoluntaryExit,
|
||||
genesisRoot []byte,
|
||||
) error {
|
||||
@@ -133,7 +132,7 @@ func VerifyExitAndSignature(
|
||||
// assert bls.Verify(validator.pubkey, signing_root, signed_voluntary_exit.signature)
|
||||
// # Initiate exit
|
||||
// initiate_validator_exit(state, voluntary_exit.validator_index)
|
||||
func verifyExitConditions(validator iface.ReadOnlyValidator, currentSlot types.Slot, exit *ethpb.VoluntaryExit) error {
|
||||
func verifyExitConditions(validator state.ReadOnlyValidator, currentSlot types.Slot, exit *ethpb.VoluntaryExit) error {
|
||||
currentEpoch := helpers.SlotToEpoch(currentSlot)
|
||||
// Verify the validator is active.
|
||||
if !helpers.IsActiveValidatorUsingTrie(validator, currentEpoch) {
|
||||
|
||||
@@ -7,9 +7,8 @@ import (
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
||||
v1 "github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
@@ -31,7 +30,7 @@ func TestProcessVoluntaryExits_NotActiveLongEnoughToExit(t *testing.T) {
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
},
|
||||
}
|
||||
state, err := v1.InitializeFromProto(&pb.BeaconState{
|
||||
state, err := v1.InitializeFromProto(ðpb.BeaconState{
|
||||
Validators: registry,
|
||||
Slot: 10,
|
||||
})
|
||||
@@ -61,7 +60,7 @@ func TestProcessVoluntaryExits_ExitAlreadySubmitted(t *testing.T) {
|
||||
ExitEpoch: 10,
|
||||
},
|
||||
}
|
||||
state, err := v1.InitializeFromProto(&pb.BeaconState{
|
||||
state, err := v1.InitializeFromProto(ðpb.BeaconState{
|
||||
Validators: registry,
|
||||
Slot: 0,
|
||||
})
|
||||
@@ -93,9 +92,9 @@ func TestProcessVoluntaryExits_AppliesCorrectStatus(t *testing.T) {
|
||||
ActivationEpoch: 0,
|
||||
},
|
||||
}
|
||||
state, err := v1.InitializeFromProto(&pb.BeaconState{
|
||||
state, err := v1.InitializeFromProto(ðpb.BeaconState{
|
||||
Validators: registry,
|
||||
Fork: &pb.Fork{
|
||||
Fork: ðpb.Fork{
|
||||
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
},
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
package blocks
|
||||
|
||||
import (
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
@@ -7,9 +7,9 @@ import (
|
||||
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/interfaces"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/block"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
@@ -40,9 +40,9 @@ import (
|
||||
// assert not proposer.slashed
|
||||
func ProcessBlockHeader(
|
||||
_ context.Context,
|
||||
beaconState iface.BeaconState,
|
||||
block interfaces.SignedBeaconBlock,
|
||||
) (iface.BeaconState, error) {
|
||||
beaconState state.BeaconState,
|
||||
block block.SignedBeaconBlock,
|
||||
) (state.BeaconState, error) {
|
||||
if err := helpers.VerifyNilBeaconBlock(block); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -92,10 +92,10 @@ func ProcessBlockHeader(
|
||||
// proposer = state.validators[block.proposer_index]
|
||||
// assert not proposer.slashed
|
||||
func ProcessBlockHeaderNoVerify(
|
||||
beaconState iface.BeaconState,
|
||||
beaconState state.BeaconState,
|
||||
slot types.Slot, proposerIndex types.ValidatorIndex,
|
||||
parentRoot, bodyRoot []byte,
|
||||
) (iface.BeaconState, error) {
|
||||
) (state.BeaconState, error) {
|
||||
if beaconState.Slot() != slot {
|
||||
return nil, fmt.Errorf("state slot: %d is different than block slot: %d", beaconState.Slot(), slot)
|
||||
}
|
||||
|
||||
@@ -8,8 +8,8 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
p2ptypes "github.com/prysmaticlabs/prysm/beacon-chain/p2p/types"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/eth/v1alpha1/wrapper"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/wrapper"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
|
||||
@@ -7,13 +7,14 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/version"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
type slashValidatorFunc func(iface.BeaconState, types.ValidatorIndex) (iface.BeaconState, error)
|
||||
type slashValidatorFunc func(st state.BeaconState, vid types.ValidatorIndex, penaltyQuotient, proposerRewardQuotient uint64) (state.BeaconState, error)
|
||||
|
||||
// ProcessProposerSlashings is one of the operations performed
|
||||
// on each processed beacon block to slash proposers based on
|
||||
@@ -42,10 +43,10 @@ type slashValidatorFunc func(iface.BeaconState, types.ValidatorIndex) (iface.Bea
|
||||
// slash_validator(state, header_1.proposer_index)
|
||||
func ProcessProposerSlashings(
|
||||
_ context.Context,
|
||||
beaconState iface.BeaconState,
|
||||
beaconState state.BeaconState,
|
||||
slashings []*ethpb.ProposerSlashing,
|
||||
slashFunc slashValidatorFunc,
|
||||
) (iface.BeaconState, error) {
|
||||
) (state.BeaconState, error) {
|
||||
var err error
|
||||
for idx, slashing := range slashings {
|
||||
if slashing == nil {
|
||||
@@ -54,7 +55,12 @@ func ProcessProposerSlashings(
|
||||
if err = VerifyProposerSlashing(beaconState, slashing); err != nil {
|
||||
return nil, errors.Wrapf(err, "could not verify proposer slashing %d", idx)
|
||||
}
|
||||
beaconState, err = slashFunc(beaconState, slashing.Header_1.Header.ProposerIndex)
|
||||
cfg := params.BeaconConfig()
|
||||
slashingQuotient := cfg.MinSlashingPenaltyQuotient
|
||||
if beaconState.Version() == version.Altair {
|
||||
slashingQuotient = cfg.MinSlashingPenaltyQuotientAltair
|
||||
}
|
||||
beaconState, err = slashFunc(beaconState, slashing.Header_1.Header.ProposerIndex, slashingQuotient, cfg.ProposerRewardQuotient)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not slash proposer index %d", slashing.Header_1.Header.ProposerIndex)
|
||||
}
|
||||
@@ -64,7 +70,7 @@ func ProcessProposerSlashings(
|
||||
|
||||
// VerifyProposerSlashing verifies that the data provided from slashing is valid.
|
||||
func VerifyProposerSlashing(
|
||||
beaconState iface.BeaconState,
|
||||
beaconState state.BeaconState,
|
||||
slashing *ethpb.ProposerSlashing,
|
||||
) error {
|
||||
if slashing.Header_1 == nil || slashing.Header_1.Header == nil || slashing.Header_2 == nil || slashing.Header_2.Header == nil {
|
||||
|
||||
@@ -5,10 +5,8 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
|
||||
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
||||
v1 "github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
@@ -20,7 +18,7 @@ import (
|
||||
func TestVerifyProposerSlashing_BeaconFuzzIssue91(t *testing.T) {
|
||||
file, err := ioutil.ReadFile("testdata/beaconfuzz_91_beacon.ssz")
|
||||
require.NoError(t, err)
|
||||
rawState := &pb.BeaconState{}
|
||||
rawState := ðpb.BeaconState{}
|
||||
err = rawState.UnmarshalSSZ(file)
|
||||
require.NoError(t, err)
|
||||
|
||||
|
||||
@@ -9,10 +9,9 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
v "github.com/prysmaticlabs/prysm/beacon-chain/core/validators"
|
||||
iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
v1 "github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
@@ -118,7 +117,7 @@ func TestProcessProposerSlashings_ValidatorNotSlashable(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
beaconState, err := v1.InitializeFromProto(&pb.BeaconState{
|
||||
beaconState, err := v1.InitializeFromProto(ðpb.BeaconState{
|
||||
Validators: registry,
|
||||
Slot: currentSlot,
|
||||
})
|
||||
@@ -184,7 +183,7 @@ func TestProcessProposerSlashings_AppliesCorrectStatus(t *testing.T) {
|
||||
|
||||
func TestVerifyProposerSlashing(t *testing.T) {
|
||||
type args struct {
|
||||
beaconState iface.BeaconState
|
||||
beaconState state.BeaconState
|
||||
slashing *ethpb.ProposerSlashing
|
||||
}
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@ import (
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface"
|
||||
"github.com/prysmaticlabs/prysm/proto/interfaces"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/block"
|
||||
"github.com/prysmaticlabs/prysm/shared/hashutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
@@ -27,9 +27,9 @@ import (
|
||||
// state.randao_mixes[epoch % EPOCHS_PER_HISTORICAL_VECTOR] = mix
|
||||
func ProcessRandao(
|
||||
_ context.Context,
|
||||
beaconState iface.BeaconState,
|
||||
b interfaces.SignedBeaconBlock,
|
||||
) (iface.BeaconState, error) {
|
||||
beaconState state.BeaconState,
|
||||
b block.SignedBeaconBlock,
|
||||
) (state.BeaconState, error) {
|
||||
if err := helpers.VerifyNilBeaconBlock(b); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -59,9 +59,9 @@ func ProcessRandao(
|
||||
// hash(body.randao_reveal))
|
||||
// )
|
||||
func ProcessRandaoNoVerify(
|
||||
beaconState iface.BeaconState,
|
||||
beaconState state.BeaconState,
|
||||
randaoReveal []byte,
|
||||
) (iface.BeaconState, error) {
|
||||
) (state.BeaconState, error) {
|
||||
currentEpoch := helpers.SlotToEpoch(beaconState.Slot())
|
||||
// If block randao passed verification, we XOR the state's latest randao mix with the block's
|
||||
// randao and update the state's corresponding latest randao mix value.
|
||||
|
||||
@@ -8,9 +8,8 @@ import (
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"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"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/eth/v1alpha1/wrapper"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/wrapper"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
@@ -27,7 +26,7 @@ func TestProcessRandao_IncorrectProposerFailsVerification(t *testing.T) {
|
||||
binary.LittleEndian.PutUint64(buf, uint64(epoch))
|
||||
domain, err := helpers.Domain(beaconState.Fork(), epoch, params.BeaconConfig().DomainRandao, beaconState.GenesisValidatorRoot())
|
||||
require.NoError(t, err)
|
||||
root, err := (&pb.SigningData{ObjectRoot: buf, Domain: domain}).HashTreeRoot()
|
||||
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[:])
|
||||
|
||||
@@ -7,11 +7,12 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/block"
|
||||
"github.com/prysmaticlabs/prysm/shared/attestationutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/p2putils"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
@@ -21,7 +22,7 @@ func signatureSet(signedData, pub, signature, domain []byte) (*bls.SignatureSet,
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not convert bytes to public key")
|
||||
}
|
||||
signingData := &pb.SigningData{
|
||||
signingData := ðpb.SigningData{
|
||||
ObjectRoot: signedData,
|
||||
Domain: domain,
|
||||
}
|
||||
@@ -60,7 +61,7 @@ func verifySignature(signedData, pub, signature, domain []byte) error {
|
||||
}
|
||||
|
||||
// VerifyBlockSignature verifies the proposer signature of a beacon block.
|
||||
func VerifyBlockSignature(beaconState iface.ReadOnlyBeaconState,
|
||||
func VerifyBlockSignature(beaconState state.ReadOnlyBeaconState,
|
||||
proposerIndex types.ValidatorIndex,
|
||||
sig []byte,
|
||||
rootFunc func() ([32]byte, error)) error {
|
||||
@@ -77,8 +78,29 @@ func VerifyBlockSignature(beaconState iface.ReadOnlyBeaconState,
|
||||
return helpers.VerifyBlockSigningRoot(proposerPubKey, sig, domain, rootFunc)
|
||||
}
|
||||
|
||||
// VerifyBlockSignatureUsingCurrentFork verifies the proposer signature of a beacon block. This differs
|
||||
// from the above method by not using fork data from the state and instead retrieving it
|
||||
// via the respective epoch.
|
||||
func VerifyBlockSignatureUsingCurrentFork(beaconState state.ReadOnlyBeaconState, blk block.SignedBeaconBlock) error {
|
||||
currentEpoch := helpers.SlotToEpoch(blk.Block().Slot())
|
||||
fork, err := p2putils.Fork(currentEpoch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
domain, err := helpers.Domain(fork, currentEpoch, params.BeaconConfig().DomainBeaconProposer, beaconState.GenesisValidatorRoot())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
proposer, err := beaconState.ValidatorAtIndex(blk.Block().ProposerIndex())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
proposerPubKey := proposer.PublicKey
|
||||
return helpers.VerifyBlockSigningRoot(proposerPubKey, blk.Signature(), domain, blk.Block().HashTreeRoot)
|
||||
}
|
||||
|
||||
// BlockSignatureSet retrieves the block signature set from the provided block and its corresponding state.
|
||||
func BlockSignatureSet(beaconState iface.ReadOnlyBeaconState,
|
||||
func BlockSignatureSet(beaconState state.ReadOnlyBeaconState,
|
||||
proposerIndex types.ValidatorIndex,
|
||||
sig []byte,
|
||||
rootFunc func() ([32]byte, error)) (*bls.SignatureSet, error) {
|
||||
@@ -97,7 +119,7 @@ func BlockSignatureSet(beaconState iface.ReadOnlyBeaconState,
|
||||
|
||||
// RandaoSignatureSet retrieves the relevant randao specific signature set object
|
||||
// from a block and its corresponding state.
|
||||
func RandaoSignatureSet(beaconState iface.ReadOnlyBeaconState,
|
||||
func RandaoSignatureSet(beaconState state.ReadOnlyBeaconState,
|
||||
reveal []byte,
|
||||
) (*bls.SignatureSet, error) {
|
||||
buf, proposerPub, domain, err := randaoSigningData(beaconState)
|
||||
@@ -112,7 +134,7 @@ func RandaoSignatureSet(beaconState iface.ReadOnlyBeaconState,
|
||||
}
|
||||
|
||||
// retrieves the randao related signing data from the state.
|
||||
func randaoSigningData(beaconState iface.ReadOnlyBeaconState) ([]byte, []byte, []byte, error) {
|
||||
func randaoSigningData(beaconState state.ReadOnlyBeaconState) ([]byte, []byte, []byte, error) {
|
||||
proposerIdx, err := helpers.BeaconProposerIndex(beaconState)
|
||||
if err != nil {
|
||||
return nil, nil, nil, errors.Wrap(err, "could not get beacon proposer index")
|
||||
@@ -133,7 +155,7 @@ func randaoSigningData(beaconState iface.ReadOnlyBeaconState) ([]byte, []byte, [
|
||||
// Method to break down attestations of the same domain and collect them into a single signature set.
|
||||
func createAttestationSignatureSet(
|
||||
ctx context.Context,
|
||||
beaconState iface.ReadOnlyBeaconState,
|
||||
beaconState state.ReadOnlyBeaconState,
|
||||
atts []*ethpb.Attestation,
|
||||
domain []byte,
|
||||
) (*bls.SignatureSet, error) {
|
||||
@@ -184,7 +206,7 @@ func createAttestationSignatureSet(
|
||||
|
||||
// AttestationSignatureSet retrieves all the related attestation signature data such as the relevant public keys,
|
||||
// signatures and attestation signing data and collate it into a signature set object.
|
||||
func AttestationSignatureSet(ctx context.Context, beaconState iface.ReadOnlyBeaconState, atts []*ethpb.Attestation) (*bls.SignatureSet, error) {
|
||||
func AttestationSignatureSet(ctx context.Context, beaconState state.ReadOnlyBeaconState, atts []*ethpb.Attestation) (*bls.SignatureSet, error) {
|
||||
if len(atts) == 0 {
|
||||
return bls.NewSet(), nil
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user