mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-10 13:58:09 -05:00
Compare commits
549 Commits
handleCras
...
e2e-at-cap
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
317c09c40a | ||
|
|
2c2f56cc7e | ||
|
|
58acdb5136 | ||
|
|
fa8a6d9d17 | ||
|
|
fa2b64f702 | ||
|
|
6f5e35f08a | ||
|
|
743037efb5 | ||
|
|
301970cf5a | ||
|
|
01ae2fe7be | ||
|
|
1cfe5988e6 | ||
|
|
a40cadab32 | ||
|
|
79d6ce45ad | ||
|
|
73cd7df679 | ||
|
|
d084d5a979 | ||
|
|
db6b1c15c4 | ||
|
|
7c9bff489e | ||
|
|
1fca73d761 | ||
|
|
fbafbdd62c | ||
|
|
75d98cf9af | ||
|
|
9f5f807303 | ||
|
|
96401e734e | ||
|
|
5f6147ecf7 | ||
|
|
5480d607ac | ||
|
|
38f0a81526 | ||
|
|
b97d2827e9 | ||
|
|
ad680d3417 | ||
|
|
047cae5e8b | ||
|
|
179252faea | ||
|
|
f93b82ee89 | ||
|
|
508e1ad005 | ||
|
|
8f06f72eed | ||
|
|
046882401e | ||
|
|
ce339bc22b | ||
|
|
1b2d917389 | ||
|
|
eb6b811071 | ||
|
|
cf71dbdf97 | ||
|
|
1ec5d45d8d | ||
|
|
9328e9af1f | ||
|
|
4762fd71de | ||
|
|
daa4fd2b72 | ||
|
|
5bdffb82e3 | ||
|
|
aabcaac619 | ||
|
|
769daffb73 | ||
|
|
16e6e0de6c | ||
|
|
396fc3dc7e | ||
|
|
d86a452b15 | ||
|
|
7fa3ebfaa8 | ||
|
|
81b9eceb50 | ||
|
|
505ff6ea3d | ||
|
|
2b5125c7bc | ||
|
|
9f3bb623ec | ||
|
|
b10a95097e | ||
|
|
1e3a55c6a6 | ||
|
|
116f3ac265 | ||
|
|
bbe003720c | ||
|
|
e957edcb12 | ||
|
|
684022fa69 | ||
|
|
a7a64632b1 | ||
|
|
c89ab764e3 | ||
|
|
375a76d6c9 | ||
|
|
bad7c6a94e | ||
|
|
ffbb73a59b | ||
|
|
bdc3a6ef11 | ||
|
|
649974f14d | ||
|
|
9ec0bc0734 | ||
|
|
b6a32c050f | ||
|
|
055e225093 | ||
|
|
144218cb1b | ||
|
|
4c9a0bf772 | ||
|
|
13b575a609 | ||
|
|
1c27b21b5a | ||
|
|
c1f00923c1 | ||
|
|
700f5fee8c | ||
|
|
66b6177ed3 | ||
|
|
0b0373f2fd | ||
|
|
b481c91453 | ||
|
|
e1408deb40 | ||
|
|
b5a414eae9 | ||
|
|
b94b347ace | ||
|
|
f5ee225819 | ||
|
|
51601716dc | ||
|
|
0e77a89208 | ||
|
|
9cb48be14f | ||
|
|
6715f10ffc | ||
|
|
2906196786 | ||
|
|
ff82d9ee8c | ||
|
|
42450fb24e | ||
|
|
b6060d5a49 | ||
|
|
cf6617933d | ||
|
|
ffcdc26618 | ||
|
|
4e28192541 | ||
|
|
4aa075abac | ||
|
|
c1563e40bd | ||
|
|
dac555a57c | ||
|
|
96981a07b9 | ||
|
|
4d549f572c | ||
|
|
6b2721b239 | ||
|
|
83f48350b2 | ||
|
|
77a9dca9eb | ||
|
|
9f1c6b2d18 | ||
|
|
0c997ede0f | ||
|
|
2dc56878cd | ||
|
|
911048aa6d | ||
|
|
d916827fb9 | ||
|
|
255e9693ee | ||
|
|
d602c94b7b | ||
|
|
6a5ecbd68f | ||
|
|
e43152102e | ||
|
|
90d5f6097c | ||
|
|
ce125b763c | ||
|
|
29dfcab505 | ||
|
|
16e5c903cc | ||
|
|
3ff5895548 | ||
|
|
4eb4cd9756 | ||
|
|
81b049ea02 | ||
|
|
66682cb4e5 | ||
|
|
cab42a4ae3 | ||
|
|
a2fc57cb03 | ||
|
|
b63f649d89 | ||
|
|
e627d3c6a4 | ||
|
|
a5bdd42bdd | ||
|
|
a26197f919 | ||
|
|
856102cba8 | ||
|
|
8ff6f7768f | ||
|
|
295cc5e4f0 | ||
|
|
8a2c7e4269 | ||
|
|
cb02a6897d | ||
|
|
e843cafe7d | ||
|
|
080ce31395 | ||
|
|
1c5b0596c7 | ||
|
|
159228b34f | ||
|
|
d5d17e00b3 | ||
|
|
9c6a1331cf | ||
|
|
1fbb3f3e51 | ||
|
|
9c21809c50 | ||
|
|
62ffed7861 | ||
|
|
bdf063819c | ||
|
|
9efc89f993 | ||
|
|
5ed52b1e44 | ||
|
|
2e49fdb3d2 | ||
|
|
a01d08b857 | ||
|
|
fbe0672fc4 | ||
|
|
a15ec49844 | ||
|
|
a268255ab1 | ||
|
|
8629ac8417 | ||
|
|
043079dafe | ||
|
|
3fcdd58872 | ||
|
|
0798092ca8 | ||
|
|
fb981d29e8 | ||
|
|
6dcb2bbf0d | ||
|
|
deb138959a | ||
|
|
45e6f3bd00 | ||
|
|
55a9e0d51a | ||
|
|
fa01ee5eba | ||
|
|
09619c388f | ||
|
|
1531313603 | ||
|
|
3ddae600fb | ||
|
|
babfc66c5b | ||
|
|
56503110dd | ||
|
|
f67d35dffd | ||
|
|
cb9b5e8f6e | ||
|
|
145eb5a8e4 | ||
|
|
7510f584cb | ||
|
|
b05b67b264 | ||
|
|
a5c6518c20 | ||
|
|
da048395ce | ||
|
|
f31f7be310 | ||
|
|
e1a2267f86 | ||
|
|
3c9e4ee7f7 | ||
|
|
9ba32c9acd | ||
|
|
d23008452e | ||
|
|
f397cba1e0 | ||
|
|
dbeb3ee886 | ||
|
|
ca2618110f | ||
|
|
642c399b9d | ||
|
|
6eee539425 | ||
|
|
1583e93b48 | ||
|
|
bd82eb873c | ||
|
|
849457df81 | ||
|
|
903cab75ee | ||
|
|
ee108d4aff | ||
|
|
49bcc58762 | ||
|
|
a08baf4a14 | ||
|
|
8c56dfdd46 | ||
|
|
dcdd9af9db | ||
|
|
a464cf5c60 | ||
|
|
62455b7bcb | ||
|
|
2d483ab09f | ||
|
|
6e26a6f128 | ||
|
|
b512b92a8a | ||
|
|
3d6d0a12dd | ||
|
|
b0601580ef | ||
|
|
c1f29ea651 | ||
|
|
881d1d435a | ||
|
|
05148dbc8f | ||
|
|
d1aae0c941 | ||
|
|
19af1d2bb0 | ||
|
|
faf16f9e56 | ||
|
|
0a5c65e29c | ||
|
|
7dc966bb3b | ||
|
|
51d35f36f0 | ||
|
|
943a0556e9 | ||
|
|
57bdb907cc | ||
|
|
f7cecf9f8a | ||
|
|
15d683c78f | ||
|
|
bf6c8ced7d | ||
|
|
78fb685027 | ||
|
|
8be73a52b1 | ||
|
|
bebceb3bfa | ||
|
|
98c0b23350 | ||
|
|
d541010bf1 | ||
|
|
039a0fffba | ||
|
|
8cb07e0c2b | ||
|
|
90ec640e7a | ||
|
|
10acd31d25 | ||
|
|
df1e8b33d8 | ||
|
|
aa2bf0c9c4 | ||
|
|
cdb4ee42cc | ||
|
|
d29baec77e | ||
|
|
0adc54b7ff | ||
|
|
e49d8f2162 | ||
|
|
1cbd7e9888 | ||
|
|
0a9e1658dd | ||
|
|
31d4a4cd11 | ||
|
|
fbc4e73d31 | ||
|
|
c1d4eaa79d | ||
|
|
760af6428e | ||
|
|
dfa0ccf626 | ||
|
|
1a51fdbd58 | ||
|
|
c6ed4e2089 | ||
|
|
0ad902e47d | ||
|
|
368a99ec8d | ||
|
|
4f4775f9f9 | ||
|
|
1c7e734918 | ||
|
|
764d1325bf | ||
|
|
0cf30e9022 | ||
|
|
227b20f368 | ||
|
|
679e6bc54a | ||
|
|
d7d70bc25b | ||
|
|
82f6ddb693 | ||
|
|
9e4e82d2c5 | ||
|
|
c7a3cf8563 | ||
|
|
9838369fe9 | ||
|
|
6085ad1bfa | ||
|
|
d3851b27df | ||
|
|
6c3b75f908 | ||
|
|
d6100dfdcb | ||
|
|
f276c5d006 | ||
|
|
c2144dac86 | ||
|
|
a47ff569a8 | ||
|
|
f8be022ef2 | ||
|
|
4f39e6b685 | ||
|
|
29953cb734 | ||
|
|
c67b000633 | ||
|
|
02f7443586 | ||
|
|
a23a5052bc | ||
|
|
6275e7df4e | ||
|
|
1b6b52fda1 | ||
|
|
5fa1fd84b9 | ||
|
|
bd0c9f9e8d | ||
|
|
2532bb370c | ||
|
|
f9e0d4b13a | ||
|
|
0aaee51973 | ||
|
|
a0c0706224 | ||
|
|
a525fad0ea | ||
|
|
12efc6c2c1 | ||
|
|
a6cc9ac9c5 | ||
|
|
031f5845a2 | ||
|
|
b88559726c | ||
|
|
7ab5851c54 | ||
|
|
e231cfd59d | ||
|
|
0a41b957dc | ||
|
|
f2399e21e1 | ||
|
|
395e49972e | ||
|
|
62f6b07cba | ||
|
|
f956f1ed6e | ||
|
|
ee099d3f03 | ||
|
|
16b0820193 | ||
|
|
4b02267e96 | ||
|
|
746584c453 | ||
|
|
e2ffaf983a | ||
|
|
b56daaaca2 | ||
|
|
0d4b98cd0a | ||
|
|
fe1281dc1a | ||
|
|
9761bd0753 | ||
|
|
0bcddb3009 | ||
|
|
ee9da3aded | ||
|
|
d58d3f2c57 | ||
|
|
4b033f4cc7 | ||
|
|
07d0a00f88 | ||
|
|
08d63a0cd0 | ||
|
|
931e5e10c3 | ||
|
|
f02ad8a68b | ||
|
|
c172f838b1 | ||
|
|
c07ae29cd9 | ||
|
|
466fd359a2 | ||
|
|
214c9bfd8b | ||
|
|
716140d64d | ||
|
|
088cb4ef59 | ||
|
|
b5f8e69b6b | ||
|
|
d1472fc351 | ||
|
|
5c8c0c31d8 | ||
|
|
7f3c00c7a2 | ||
|
|
c180dab791 | ||
|
|
cf466702df | ||
|
|
f24acc21c7 | ||
|
|
40b637849d | ||
|
|
e7db1685df | ||
|
|
eccbfd1011 | ||
|
|
90211f6769 | ||
|
|
edc32ac18e | ||
|
|
fe68e020e3 | ||
|
|
81e1e3544d | ||
|
|
09372d5c35 | ||
|
|
078a89e4ca | ||
|
|
dbc6ae26a6 | ||
|
|
b6f429867a | ||
|
|
de73baa4a7 | ||
|
|
d4a3b74bc6 | ||
|
|
216cdd9361 | ||
|
|
68c3e939b8 | ||
|
|
09f50660ce | ||
|
|
189825b495 | ||
|
|
bf7e17db8f | ||
|
|
ead9a83d8d | ||
|
|
764b7ff610 | ||
|
|
2fef03414d | ||
|
|
7b63d5c08c | ||
|
|
d499db7f0e | ||
|
|
af6d5e9149 | ||
|
|
d0d7021c1d | ||
|
|
4db1a02763 | ||
|
|
69d7f7f6ca | ||
|
|
ed2d1c7bf9 | ||
|
|
14b73cbd47 | ||
|
|
4e342b8802 | ||
|
|
02566de74c | ||
|
|
90ecd23d41 | ||
|
|
4d68211ad4 | ||
|
|
19f6d3bef6 | ||
|
|
37108e6ed8 | ||
|
|
3124785a08 | ||
|
|
d33af46c90 | ||
|
|
60e6306107 | ||
|
|
42ccb7830a | ||
|
|
0bb03b9292 | ||
|
|
ed6fbf1480 | ||
|
|
477cec6021 | ||
|
|
924500d111 | ||
|
|
0677504ef1 | ||
|
|
ca2a7c4d9c | ||
|
|
28606629ad | ||
|
|
c817279464 | ||
|
|
009d6ed8ed | ||
|
|
5cec1282a9 | ||
|
|
340170fd29 | ||
|
|
7ed0cc139a | ||
|
|
2c822213eb | ||
|
|
53d4659654 | ||
|
|
c08bb39ffe | ||
|
|
5083d8ab34 | ||
|
|
7552a5dd07 | ||
|
|
c93d68f853 | ||
|
|
09e117370a | ||
|
|
3e8aa4023d | ||
|
|
b443875e66 | ||
|
|
8ade8afb73 | ||
|
|
872021f10d | ||
|
|
bb09295072 | ||
|
|
e4b2b1ea7d | ||
|
|
ead329e610 | ||
|
|
a0c5669511 | ||
|
|
0fd5253915 | ||
|
|
86e855d499 | ||
|
|
001ae30a59 | ||
|
|
d1f0e5dd55 | ||
|
|
2142b13a41 | ||
|
|
ffac232d89 | ||
|
|
26b46301d2 | ||
|
|
fdf913aed9 | ||
|
|
9435d10652 | ||
|
|
8fa481cb93 | ||
|
|
26087d7b2d | ||
|
|
5a3a01090a | ||
|
|
55690de685 | ||
|
|
007c776d8a | ||
|
|
a15e0797e4 | ||
|
|
1572c530b5 | ||
|
|
652303522f | ||
|
|
39a7988e9e | ||
|
|
648ab9f2c2 | ||
|
|
43a0b4bb16 | ||
|
|
57d7207554 | ||
|
|
b7b5b28c5a | ||
|
|
968dc5d1e8 | ||
|
|
c24016f006 | ||
|
|
661cbc45ae | ||
|
|
4bd4d6392d | ||
|
|
5f4c26875b | ||
|
|
6aab2b2b8d | ||
|
|
b7a878d011 | ||
|
|
2ae9f1be9e | ||
|
|
98b9c9e6c9 | ||
|
|
df694aad71 | ||
|
|
e8400a0773 | ||
|
|
dcba27ffbc | ||
|
|
cafe0bd1f8 | ||
|
|
ce7f042974 | ||
|
|
974cf51a8c | ||
|
|
eb49404a75 | ||
|
|
6bea17cb54 | ||
|
|
de8e50d8b6 | ||
|
|
8049060119 | ||
|
|
c1446a35c5 | ||
|
|
f5efde5ccc | ||
|
|
cdcb289693 | ||
|
|
5dca874530 | ||
|
|
885dd2e327 | ||
|
|
0f0d480dbc | ||
|
|
1696208318 | ||
|
|
7f686a7878 | ||
|
|
2817f8e8d6 | ||
|
|
db76be2f15 | ||
|
|
ad65c841c4 | ||
|
|
7b255f5c9d | ||
|
|
157b1e373c | ||
|
|
e3df25f443 | ||
|
|
805473cb38 | ||
|
|
a54bb19c82 | ||
|
|
14908f639e | ||
|
|
77fc45304b | ||
|
|
722c7fb034 | ||
|
|
97ef8dde4d | ||
|
|
211c5c2c5c | ||
|
|
2ea66a8467 | ||
|
|
7720d98764 | ||
|
|
20e99fd1f9 | ||
|
|
61f6b27548 | ||
|
|
e1c1d0f864 | ||
|
|
7a8d780869 | ||
|
|
588674f2fd | ||
|
|
73443208a1 | ||
|
|
9c2c665e92 | ||
|
|
0f0ab1327e | ||
|
|
a27feb4cb2 | ||
|
|
41e95cb274 | ||
|
|
3b8a3c2276 | ||
|
|
5a1d260b9a | ||
|
|
53627e9709 | ||
|
|
9fefb33cdf | ||
|
|
d860daff75 | ||
|
|
6cf4f3c260 | ||
|
|
99fbf5d3d8 | ||
|
|
d57a44b973 | ||
|
|
fbe591c363 | ||
|
|
fc509cc220 | ||
|
|
78cbe4dfe1 | ||
|
|
436fcb8682 | ||
|
|
b4d2395a38 | ||
|
|
0cee01ad55 | ||
|
|
14a6fe3f01 | ||
|
|
4d90afe944 | ||
|
|
b98e9019ce | ||
|
|
45a637a3b0 | ||
|
|
17f3d66885 | ||
|
|
29390516b0 | ||
|
|
135c30e912 | ||
|
|
50f9d2bab8 | ||
|
|
8743e6a688 | ||
|
|
08e6274c14 | ||
|
|
cca9ea6989 | ||
|
|
cbc2153664 | ||
|
|
8627fe72e8 | ||
|
|
65bf3d0fa8 | ||
|
|
a5da9aedd4 | ||
|
|
e1ab034d25 | ||
|
|
84bc8f3d64 | ||
|
|
c4deb84012 | ||
|
|
488e19e428 | ||
|
|
bcaae1c440 | ||
|
|
587ba83aca | ||
|
|
091f16b26c | ||
|
|
fb9626fdd7 | ||
|
|
c638e114db | ||
|
|
b1e08307ed | ||
|
|
cac5d0f234 | ||
|
|
52d48b328f | ||
|
|
9729b2ec77 | ||
|
|
7aa3776aa6 | ||
|
|
760c71ef77 | ||
|
|
6c209db3ca | ||
|
|
0725905797 | ||
|
|
166f8a1eb6 | ||
|
|
85896e994e | ||
|
|
4a00b295ed | ||
|
|
d2b39e9697 | ||
|
|
97dc86e742 | ||
|
|
cff3b99918 | ||
|
|
be9847f23c | ||
|
|
4796827d22 | ||
|
|
57b7e0b572 | ||
|
|
b5039e9bd9 | ||
|
|
f5d792299f | ||
|
|
9ce922304f | ||
|
|
3cbb4aace4 | ||
|
|
c94095b609 | ||
|
|
ae858bbd0a | ||
|
|
30cd158ae5 | ||
|
|
2db22adfe0 | ||
|
|
161a14d256 | ||
|
|
9dee22f7ab | ||
|
|
52271cf0ba | ||
|
|
e1f56d403c | ||
|
|
a2193ee014 | ||
|
|
762b3df491 | ||
|
|
2b3025828f | ||
|
|
436792fe38 | ||
|
|
1d07bffe11 | ||
|
|
f086535c8a | ||
|
|
3a4c599a96 | ||
|
|
1c6cbc574e | ||
|
|
2317375983 | ||
|
|
6354748b12 | ||
|
|
e910471784 | ||
|
|
ab7e97ba63 | ||
|
|
e99de7726d | ||
|
|
606fdd2299 | ||
|
|
1eb6025aaa | ||
|
|
d431ceee25 | ||
|
|
4597599196 | ||
|
|
0c32eb5c03 | ||
|
|
4b1cb6fa80 | ||
|
|
9cfb823cc6 | ||
|
|
cb502ceb8c | ||
|
|
8da4d572d9 | ||
|
|
1c6fa65f7b | ||
|
|
eaa2566e90 | ||
|
|
6957f0637f | ||
|
|
01b1f15bdf | ||
|
|
b787fd877a | ||
|
|
2c89ce810d | ||
|
|
e687fff922 | ||
|
|
5e2498be7e | ||
|
|
76f958710f | ||
|
|
1775cf89c6 | ||
|
|
8fecfaee48 | ||
|
|
f089405d2f | ||
|
|
029c81a2e4 | ||
|
|
56c48b4971 |
6
.bazelrc
6
.bazelrc
@@ -13,7 +13,6 @@ coverage --define=coverage_enabled=1
|
||||
|
||||
# Fix for rules_docker. See: https://github.com/bazelbuild/rules_docker/issues/842
|
||||
build --host_force_python=PY2
|
||||
test --host_force_python=PY2
|
||||
run --host_force_python=PY2
|
||||
|
||||
# Networking is blocked for tests by default, add "requires-network" tag to your test if networking
|
||||
@@ -22,15 +21,12 @@ build --sandbox_default_allow_network=false
|
||||
|
||||
# Stamp binaries with git information
|
||||
build --workspace_status_command=./hack/workspace_status.sh
|
||||
build --stamp
|
||||
|
||||
# Prevent PATH changes from rebuilding when switching from IDE to command line.
|
||||
build --incompatible_strict_action_env
|
||||
test --incompatible_strict_action_env
|
||||
run --incompatible_strict_action_env
|
||||
|
||||
build --define blst_disabled=false
|
||||
test --define blst_disabled=false
|
||||
run --define blst_disabled=false
|
||||
|
||||
build:blst_disabled --define blst_disabled=true
|
||||
@@ -41,7 +37,7 @@ build:minimal --@io_bazel_rules_go//go/config:tags=minimal
|
||||
|
||||
# Release flags
|
||||
build:release --compilation_mode=opt
|
||||
build:release --config=llvm
|
||||
build:release --stamp
|
||||
|
||||
# LLVM compiler for building C/C++ dependencies.
|
||||
build:llvm --define compiler=llvm
|
||||
|
||||
@@ -1 +1 @@
|
||||
5.0.0
|
||||
5.3.0
|
||||
|
||||
10
.github/CODEOWNERS
vendored
10
.github/CODEOWNERS
vendored
@@ -5,12 +5,4 @@
|
||||
*.bzl @prestonvanloon
|
||||
|
||||
# Anyone on prylabs team can approve dependency updates.
|
||||
deps.bzl @prysmaticlabs/core-team
|
||||
|
||||
# Radek and Nishant are responsible for changes that can affect the native state feature.
|
||||
# See https://www.notion.so/prysmaticlabs/Native-Beacon-State-Redesign-6cc9744b4ec1439bb34fa829b36a35c1
|
||||
/beacon-chain/state/fieldtrie/ @rkapka @nisdas @rauljordan
|
||||
/beacon-chain/state/v1/ @rkapka @nisdas @rauljordan
|
||||
/beacon-chain/state/v2/ @rkapka @nisdas @rauljordan
|
||||
/beacon-chain/state/v3/ @rkapka @nisdas @rauljordan
|
||||
/beacon-chain/state/state-native/ @rkapka @nisdas @rauljordan
|
||||
deps.bzl @prysmaticlabs/core-team
|
||||
6
.github/ISSUE_TEMPLATE/feature_request.md
vendored
6
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@@ -16,12 +16,12 @@ Existing issues often contain information about workarounds, resolution, or prog
|
||||
|
||||
### Description
|
||||
|
||||
<!-- ✍️--> A clear and concise description of the problem or missing capability...
|
||||
<!-- ✍️ A clear and concise description of the problem or missing capability... -->
|
||||
|
||||
### Describe the solution you'd like
|
||||
|
||||
<!-- ✍️--> If you have a solution in mind, please describe it.
|
||||
<!-- ✍️ If you have a solution in mind, please describe it. -->
|
||||
|
||||
### Describe alternatives you've considered
|
||||
|
||||
<!-- ✍️--> Have you considered any alternative solutions or workarounds?
|
||||
<!-- ✍️ Have you considered any alternative solutions or workarounds? -->
|
||||
|
||||
15
.github/workflows/go.yml
vendored
15
.github/workflows/go.yml
vendored
@@ -26,14 +26,14 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Set up Go 1.18
|
||||
- name: Set up Go 1.19
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: 1.18
|
||||
go-version: 1.19
|
||||
- name: Run Gosec Security Scanner
|
||||
run: | # https://github.com/securego/gosec/issues/469
|
||||
export PATH=$PATH:$(go env GOPATH)/bin
|
||||
go install github.com/securego/gosec/v2/cmd/gosec@latest
|
||||
go install github.com/securego/gosec/v2/cmd/gosec@v2.12.0
|
||||
gosec -exclude=G307 -exclude-dir=crypto/bls/herumi ./...
|
||||
|
||||
lint:
|
||||
@@ -43,16 +43,17 @@ jobs:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Set up Go 1.18
|
||||
- name: Set up Go 1.19
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: 1.18
|
||||
go-version: 1.19
|
||||
id: go
|
||||
|
||||
- name: Golangci-lint
|
||||
uses: golangci/golangci-lint-action@v3
|
||||
with:
|
||||
version: v1.47.2
|
||||
version: v1.50.1
|
||||
args: --config=.golangci.yml --out-${NO_FUTURE}format colored-line-number
|
||||
|
||||
build:
|
||||
name: Build
|
||||
@@ -61,7 +62,7 @@ jobs:
|
||||
- name: Set up Go 1.x
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.18
|
||||
go-version: 1.19
|
||||
id: go
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -38,3 +38,6 @@ metaData
|
||||
|
||||
# execution API authentication
|
||||
jwt.hex
|
||||
|
||||
# manual testing
|
||||
tmp
|
||||
|
||||
@@ -6,14 +6,14 @@ run:
|
||||
- proto
|
||||
- tools/analyzers
|
||||
timeout: 10m
|
||||
go: '1.18'
|
||||
go: '1.19'
|
||||
|
||||
linters:
|
||||
disable-all: true
|
||||
enable:
|
||||
- gofmt
|
||||
- goimports
|
||||
- deadcode
|
||||
- unused
|
||||
- errcheck
|
||||
- gosimple
|
||||
- gocognit
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Dependency Managagement in Prysm
|
||||
# Dependency Management in Prysm
|
||||
|
||||
Prysm is go project with many complicated dependencies, including some c++ based libraries. There
|
||||
are two parts to Prysm's dependency management. Go modules and bazel managed dependencies. Be sure
|
||||
@@ -28,7 +28,7 @@ including complicated c++ dependencies.
|
||||
One key advantage of Bazel over vanilla `go build` is that Bazel automatically (re)builds generated
|
||||
pb.go files at build time when file changes are present in any protobuf definition file or after
|
||||
any updates to the protobuf compiler or other relevant dependencies. Vanilla go users should run
|
||||
the following scripts often to ensure their generated files are up to date. Further more, Prysm
|
||||
the following scripts often to ensure their generated files are up to date. Furthermore, Prysm
|
||||
generates SSZ marshal related code based on defined data structures. These generated files must
|
||||
also be updated and checked in as frequently.
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
[](https://buildkite.com/prysmatic-labs/prysm)
|
||||
[](https://goreportcard.com/report/github.com/prysmaticlabs/prysm)
|
||||
[](https://github.com/ethereum/consensus-specs/tree/v1.2.0-rc.1)
|
||||
[](https://github.com/ethereum/execution-apis/tree/v1.0.0-alpha.9/src/engine)
|
||||
[](https://github.com/ethereum/consensus-specs/tree/v1.2.0)
|
||||
[](https://github.com/ethereum/execution-apis/tree/v1.0.0-beta.1/src/engine)
|
||||
[](https://discord.gg/CTYGPUJ)
|
||||
[](https://www.gitpoap.io/gh/prysmaticlabs/prysm)
|
||||
|
||||
|
||||
51
WORKSPACE
51
WORKSPACE
@@ -28,7 +28,7 @@ load("@com_grail_bazel_toolchain//toolchain:rules.bzl", "llvm_toolchain")
|
||||
|
||||
llvm_toolchain(
|
||||
name = "llvm_toolchain",
|
||||
llvm_version = "10.0.0",
|
||||
llvm_version = "13.0.1",
|
||||
)
|
||||
|
||||
load("@llvm_toolchain//:toolchains.bzl", "llvm_register_toolchains")
|
||||
@@ -88,10 +88,10 @@ http_archive(
|
||||
# Expose internals of go_test for custom build transitions.
|
||||
"//third_party:io_bazel_rules_go_test.patch",
|
||||
],
|
||||
sha256 = "16e9fca53ed6bd4ff4ad76facc9b7b651a89db1689a2877d6fd7b82aa824e366",
|
||||
sha256 = "ae013bf35bd23234d1dea46b079f1e05ba74ac0321423830119d3e787ec73483",
|
||||
urls = [
|
||||
"https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.34.0/rules_go-v0.34.0.zip",
|
||||
"https://github.com/bazelbuild/rules_go/releases/download/v0.34.0/rules_go-v0.34.0.zip",
|
||||
"https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.36.0/rules_go-v0.36.0.zip",
|
||||
"https://github.com/bazelbuild/rules_go/releases/download/v0.36.0/rules_go-v0.36.0.zip",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -110,13 +110,6 @@ git_repository(
|
||||
# gazelle args: -go_prefix github.com/gogo/protobuf -proto legacy
|
||||
)
|
||||
|
||||
http_archive(
|
||||
name = "fuzzit_linux",
|
||||
build_file_content = "exports_files([\"fuzzit\"])",
|
||||
sha256 = "9ca76ac1c22d9360936006efddf992977ebf8e4788ded8e5f9d511285c9ac774",
|
||||
urls = ["https://github.com/fuzzitdev/fuzzit/releases/download/v2.4.76/fuzzit_Linux_x86_64.zip"],
|
||||
)
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_docker//repositories:repositories.bzl",
|
||||
container_repositories = "repositories",
|
||||
@@ -164,35 +157,15 @@ container_pull(
|
||||
repository = "pinglamb/alpine-glibc",
|
||||
)
|
||||
|
||||
container_pull(
|
||||
name = "fuzzit_base",
|
||||
digest = "sha256:24a39a4360b07b8f0121eb55674a2e757ab09f0baff5569332fefd227ee4338f",
|
||||
registry = "gcr.io",
|
||||
repository = "fuzzit-public/stretch-llvm8",
|
||||
)
|
||||
|
||||
load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies")
|
||||
|
||||
go_rules_dependencies()
|
||||
|
||||
go_register_toolchains(
|
||||
go_version = "1.18.5",
|
||||
go_version = "1.19.4",
|
||||
nogo = "@//:nogo",
|
||||
)
|
||||
|
||||
http_archive(
|
||||
name = "prysm_testnet_site",
|
||||
build_file_content = """
|
||||
proto_library(
|
||||
name = "faucet_proto",
|
||||
srcs = ["src/proto/faucet.proto"],
|
||||
visibility = ["//visibility:public"],
|
||||
)""",
|
||||
sha256 = "29742136ff9faf47343073c4569a7cf21b8ed138f726929e09e3c38ab83544f7",
|
||||
strip_prefix = "prysm-testnet-site-5c711600f0a77fc553b18cf37b880eaffef4afdb",
|
||||
url = "https://github.com/prestonvanloon/prysm-testnet-site/archive/5c711600f0a77fc553b18cf37b880eaffef4afdb.tar.gz",
|
||||
)
|
||||
|
||||
http_archive(
|
||||
name = "io_kubernetes_build",
|
||||
sha256 = "b84fbd1173acee9d02a7d3698ad269fdf4f7aa081e9cecd40e012ad0ad8cfa2a",
|
||||
@@ -215,7 +188,7 @@ filegroup(
|
||||
url = "https://github.com/eth-clients/slashing-protection-interchange-tests/archive/b8413ca42dc92308019d0d4db52c87e9e125c4e9.tar.gz",
|
||||
)
|
||||
|
||||
consensus_spec_version = "v1.2.0-rc.2"
|
||||
consensus_spec_version = "v1.3.0-rc.1"
|
||||
|
||||
bls_test_version = "v0.1.1"
|
||||
|
||||
@@ -231,7 +204,7 @@ filegroup(
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
""",
|
||||
sha256 = "eff52923eebbed6e37a5282db5290abe67c68d6aa54302e3db2b0718c3edf867",
|
||||
sha256 = "3d6fadb64674eb64a84fae6c2efa9949231ea91e7cb74ada9214097323e86569",
|
||||
url = "https://github.com/ethereum/consensus-spec-tests/releases/download/%s/general.tar.gz" % consensus_spec_version,
|
||||
)
|
||||
|
||||
@@ -247,7 +220,7 @@ filegroup(
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
""",
|
||||
sha256 = "6183d39d40ae659347e8bcfa435cbbe6de8c19ab327b61d47f906bb087bc7a67",
|
||||
sha256 = "54ffbcab1e77316a280e6f5a64c6ed62351e8f5678e6fa49340e49b9b5575e8e",
|
||||
url = "https://github.com/ethereum/consensus-spec-tests/releases/download/%s/minimal.tar.gz" % consensus_spec_version,
|
||||
)
|
||||
|
||||
@@ -263,7 +236,7 @@ filegroup(
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
""",
|
||||
sha256 = "894d16608d7d37a8f6206165e6c2b6ffcc45b13152b5f411e9283b005ca9793f",
|
||||
sha256 = "bb06d30ca533dc97d45f2367916ba9ff1b5af52f08a9d8c33bb7b1a61254094e",
|
||||
url = "https://github.com/ethereum/consensus-spec-tests/releases/download/%s/mainnet.tar.gz" % consensus_spec_version,
|
||||
)
|
||||
|
||||
@@ -278,7 +251,7 @@ filegroup(
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
""",
|
||||
sha256 = "006674e5d7eee613f1155e154ab97f6b57589ec92e6e3e5f7affd2b53581e907",
|
||||
sha256 = "9d22246c00ec3907ef8dc3ddccdfe6f7153ce46df73deee0a0176fe7e4aa1126",
|
||||
strip_prefix = "consensus-specs-" + consensus_spec_version[1:],
|
||||
url = "https://github.com/ethereum/consensus-specs/archive/refs/tags/%s.tar.gz" % consensus_spec_version,
|
||||
)
|
||||
@@ -342,9 +315,9 @@ filegroup(
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
""",
|
||||
sha256 = "e0c0b5dc609b3a221e74c720f483c595441f2ad5e38bb8aa3522636039945a6f",
|
||||
sha256 = "b2226874526805d64c29e5053fa28e511b57c0860585d6d59777ee81ff4859ca",
|
||||
urls = [
|
||||
"https://github.com/prysmaticlabs/prysm-web-ui/releases/download/v2.0.1/prysm-web-ui.tar.gz",
|
||||
"https://github.com/prysmaticlabs/prysm-web-ui/releases/download/v2.0.2/prysm-web-ui.tar.gz",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -21,14 +21,13 @@ import (
|
||||
// OriginData represents the BeaconState and SignedBeaconBlock necessary to start an empty Beacon Node
|
||||
// using Checkpoint Sync.
|
||||
type OriginData struct {
|
||||
wsd *WeakSubjectivityData
|
||||
sb []byte
|
||||
bb []byte
|
||||
st state.BeaconState
|
||||
b interfaces.SignedBeaconBlock
|
||||
vu *detect.VersionedUnmarshaler
|
||||
br [32]byte
|
||||
sr [32]byte
|
||||
sb []byte
|
||||
bb []byte
|
||||
st state.BeaconState
|
||||
b interfaces.SignedBeaconBlock
|
||||
vu *detect.VersionedUnmarshaler
|
||||
br [32]byte
|
||||
sr [32]byte
|
||||
}
|
||||
|
||||
// SaveBlock saves the downloaded block to a unique file in the given path.
|
||||
@@ -75,6 +74,9 @@ func DownloadFinalizedData(ctx context.Context, client *Client) (*OriginData, er
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "error unmarshaling finalized state to correct version")
|
||||
}
|
||||
if s.Slot() != s.LatestBlockHeader().Slot {
|
||||
return nil, fmt.Errorf("finalized state slot does not match latest block header slot %d != %d", s.Slot(), s.LatestBlockHeader().Slot)
|
||||
}
|
||||
|
||||
sr, err := s.HashTreeRoot(ctx)
|
||||
if err != nil {
|
||||
|
||||
@@ -418,6 +418,7 @@ func TestDownloadFinalizedData(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
fork, err := forkForEpoch(cfg, epoch)
|
||||
require.NoError(t, st.SetFork(fork))
|
||||
require.NoError(t, st.SetSlot(slot))
|
||||
|
||||
// set up checkpoint block
|
||||
b, err := blocks.NewSignedBeaconBlock(util.NewBeaconBlock())
|
||||
|
||||
@@ -95,8 +95,6 @@ func WithTimeout(timeout time.Duration) ClientOpt {
|
||||
// Client provides a collection of helper methods for calling the Eth Beacon Node API endpoints.
|
||||
type Client struct {
|
||||
hc *http.Client
|
||||
host string
|
||||
scheme string
|
||||
baseURL *url.URL
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
/*
|
||||
Package beacon provides a client for interacting with the standard Eth Beacon Node API.
|
||||
Interactive swagger documentation for the API is available here: https://ethereum.github.io/beacon-APIs/
|
||||
|
||||
*/
|
||||
package beacon
|
||||
|
||||
@@ -13,6 +13,8 @@ go_library(
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
"//monitoring/tracing:go_default_library",
|
||||
"//network:go_default_library",
|
||||
"//network/authorization:go_default_library",
|
||||
"//proto/engine/v1:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
|
||||
|
||||
@@ -15,6 +15,8 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||
"github.com/prysmaticlabs/prysm/v3/monitoring/tracing"
|
||||
"github.com/prysmaticlabs/prysm/v3/network"
|
||||
"github.com/prysmaticlabs/prysm/v3/network/authorization"
|
||||
v1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||
log "github.com/sirupsen/logrus"
|
||||
@@ -30,17 +32,11 @@ const (
|
||||
|
||||
var errMalformedHostname = errors.New("hostname must include port, separated by one colon, like example.com:3500")
|
||||
var errMalformedRequest = errors.New("required request data are missing")
|
||||
var submitBlindedBlockTimeout = 3 * time.Second
|
||||
|
||||
// ClientOpt is a functional option for the Client type (http.Client wrapper)
|
||||
type ClientOpt func(*Client)
|
||||
|
||||
// WithTimeout sets the .Timeout attribute of the wrapped http.Client.
|
||||
func WithTimeout(timeout time.Duration) ClientOpt {
|
||||
return func(c *Client) {
|
||||
c.hc.Timeout = timeout
|
||||
}
|
||||
}
|
||||
|
||||
type observer interface {
|
||||
observe(r *http.Request) error
|
||||
}
|
||||
@@ -83,6 +79,15 @@ func (*requestLogger) observe(r *http.Request) (e error) {
|
||||
|
||||
var _ observer = &requestLogger{}
|
||||
|
||||
// BuilderClient provides a collection of helper methods for calling Builder API endpoints.
|
||||
type BuilderClient interface {
|
||||
NodeURL() string
|
||||
GetHeader(ctx context.Context, slot types.Slot, parentHash [32]byte, pubkey [48]byte) (*ethpb.SignedBuilderBid, error)
|
||||
RegisterValidator(ctx context.Context, svr []*ethpb.SignedValidatorRegistrationV1) error
|
||||
SubmitBlindedBlock(ctx context.Context, sb *ethpb.SignedBlindedBeaconBlockBellatrix) (*v1.ExecutionPayload, error)
|
||||
Status(ctx context.Context) error
|
||||
}
|
||||
|
||||
// Client provides a collection of helper methods for calling Builder API endpoints.
|
||||
type Client struct {
|
||||
hc *http.Client
|
||||
@@ -94,7 +99,8 @@ type Client struct {
|
||||
// `host` is the base host + port used to construct request urls. This value can be
|
||||
// a URL string, or NewClient will assume an http endpoint if just `host:port` is used.
|
||||
func NewClient(host string, opts ...ClientOpt) (*Client, error) {
|
||||
u, err := urlForHost(host)
|
||||
endpoint := covertEndPoint(host)
|
||||
u, err := urlForHost(endpoint.Url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -248,7 +254,11 @@ func (c *Client) SubmitBlindedBlock(ctx context.Context, sb *ethpb.SignedBlinded
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "error encoding the SignedBlindedBeaconBlockBellatrix value body in SubmitBlindedBlock")
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(ctx, submitBlindedBlockTimeout)
|
||||
defer cancel()
|
||||
rb, err := c.do(ctx, http.MethodPost, postBlindedBeaconBlockPath, bytes.NewBuffer(body))
|
||||
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "error posting the SignedBlindedBeaconBlockBellatrix to the builder api")
|
||||
}
|
||||
@@ -274,9 +284,6 @@ func non200Err(response *http.Response) error {
|
||||
if err != nil {
|
||||
body = "(Unable to read response body.)"
|
||||
} else {
|
||||
if jsonErr := json.Unmarshal(bodyBytes, &errMessage); jsonErr != nil {
|
||||
return errors.Wrap(jsonErr, "unable to read response body")
|
||||
}
|
||||
body = "response body:\n" + string(bodyBytes)
|
||||
}
|
||||
msg := fmt.Sprintf("code=%d, url=%s, body=%s", response.StatusCode, response.Request.URL, body)
|
||||
@@ -285,13 +292,34 @@ func non200Err(response *http.Response) error {
|
||||
log.WithError(ErrNoContent).Debug(msg)
|
||||
return ErrNoContent
|
||||
case 400:
|
||||
if jsonErr := json.Unmarshal(bodyBytes, &errMessage); jsonErr != nil {
|
||||
return errors.Wrap(jsonErr, "unable to read response body")
|
||||
}
|
||||
log.WithError(ErrBadRequest).Debug(msg)
|
||||
return errors.Wrap(ErrBadRequest, errMessage.Message)
|
||||
case 404:
|
||||
if jsonErr := json.Unmarshal(bodyBytes, &errMessage); jsonErr != nil {
|
||||
return errors.Wrap(jsonErr, "unable to read response body")
|
||||
}
|
||||
log.WithError(ErrNotFound).Debug(msg)
|
||||
return errors.Wrap(ErrNotFound, errMessage.Message)
|
||||
default:
|
||||
case 500:
|
||||
if jsonErr := json.Unmarshal(bodyBytes, &errMessage); jsonErr != nil {
|
||||
return errors.Wrap(jsonErr, "unable to read response body")
|
||||
}
|
||||
log.WithError(ErrNotOK).Debug(msg)
|
||||
return errors.Wrap(ErrNotOK, errMessage.Message)
|
||||
default:
|
||||
log.WithError(ErrNotOK).Debug(msg)
|
||||
return errors.Wrap(ErrNotOK, fmt.Sprintf("unsupported error code: %d", response.StatusCode))
|
||||
}
|
||||
}
|
||||
|
||||
func covertEndPoint(ep string) network.Endpoint {
|
||||
return network.Endpoint{
|
||||
Url: ep,
|
||||
Auth: network.AuthorizationData{ // Auth is not used for builder.
|
||||
Method: authorization.None,
|
||||
Value: "",
|
||||
}}
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ func TestClient_Status(t *testing.T) {
|
||||
|
||||
func TestClient_RegisterValidator(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
expectedBody := `[{"message":{"fee_recipient":"0x0000000000000000000000000000000000000000","gas_limit":"23","timestamp":"42","pubkey":"0x93247f2209abcacf57b75a51dafae777f9dd38bc7053d1af526f220a7489a6d3a2753e5f3e8b1cfe39b56f43611df74a"}}]`
|
||||
expectedBody := `[{"message":{"fee_recipient":"0x0000000000000000000000000000000000000000","gas_limit":"23","timestamp":"42","pubkey":"0x93247f2209abcacf57b75a51dafae777f9dd38bc7053d1af526f220a7489a6d3a2753e5f3e8b1cfe39b56f43611df74a"},"signature":"0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505"}]`
|
||||
expectedPath := "/eth/v1/builder/validators"
|
||||
hc := &http.Client{
|
||||
Transport: roundtrip(func(r *http.Request) (*http.Response, error) {
|
||||
@@ -111,6 +111,7 @@ func TestClient_RegisterValidator(t *testing.T) {
|
||||
Timestamp: 42,
|
||||
Pubkey: ezDecode(t, "0x93247f2209abcacf57b75a51dafae777f9dd38bc7053d1af526f220a7489a6d3a2753e5f3e8b1cfe39b56f43611df74a"),
|
||||
},
|
||||
Signature: ezDecode(t, "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505"),
|
||||
}
|
||||
require.NoError(t, c.RegisterValidator(ctx, []*eth.SignedValidatorRegistrationV1{reg}))
|
||||
}
|
||||
@@ -144,6 +145,23 @@ func TestClient_GetHeader(t *testing.T) {
|
||||
_, err := c.GetHeader(ctx, slot, bytesutil.ToBytes32(parentHash), bytesutil.ToBytes48(pubkey))
|
||||
require.ErrorIs(t, err, ErrNotOK)
|
||||
|
||||
hc = &http.Client{
|
||||
Transport: roundtrip(func(r *http.Request) (*http.Response, error) {
|
||||
require.Equal(t, expectedPath, r.URL.Path)
|
||||
return &http.Response{
|
||||
StatusCode: http.StatusNoContent,
|
||||
Body: io.NopCloser(bytes.NewBuffer([]byte("No header is available."))),
|
||||
Request: r.Clone(ctx),
|
||||
}, nil
|
||||
}),
|
||||
}
|
||||
c = &Client{
|
||||
hc: hc,
|
||||
baseURL: &url.URL{Host: "localhost:3500", Scheme: "http"},
|
||||
}
|
||||
_, err = c.GetHeader(ctx, slot, bytesutil.ToBytes32(parentHash), bytesutil.ToBytes48(pubkey))
|
||||
require.ErrorIs(t, err, ErrNoContent)
|
||||
|
||||
hc = &http.Client{
|
||||
Transport: roundtrip(func(r *http.Request) (*http.Response, error) {
|
||||
require.Equal(t, expectedPath, r.URL.Path)
|
||||
@@ -165,7 +183,8 @@ func TestClient_GetHeader(t *testing.T) {
|
||||
expectedTxRoot := ezDecode(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2")
|
||||
require.Equal(t, true, bytes.Equal(expectedTxRoot, h.Message.Header.TransactionsRoot))
|
||||
require.Equal(t, uint64(1), h.Message.Header.GasUsed)
|
||||
value := stringToUint256("652312848583266388373324160190187140051835877600158453279131187530910662656")
|
||||
value, err := stringToUint256("652312848583266388373324160190187140051835877600158453279131187530910662656")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, fmt.Sprintf("%#x", value.SSZBytes()), fmt.Sprintf("%#x", h.Message.Value))
|
||||
}
|
||||
|
||||
@@ -189,7 +208,8 @@ func TestSubmitBlindedBlock(t *testing.T) {
|
||||
ep, err := c.SubmitBlindedBlock(ctx, sbbb)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, true, bytes.Equal(ezDecode(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"), ep.ParentHash))
|
||||
bfpg := stringToUint256("452312848583266388373324160190187140051835877600158453279131187530910662656")
|
||||
bfpg, err := stringToUint256("452312848583266388373324160190187140051835877600158453279131187530910662656")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, fmt.Sprintf("%#x", bfpg.SSZBytes()), fmt.Sprintf("%#x", ep.BaseFeePerGas))
|
||||
require.Equal(t, uint64(1), ep.GasLimit)
|
||||
}
|
||||
|
||||
14
api/client/builder/testing/BUILD.bazel
Normal file
14
api/client/builder/testing/BUILD.bazel
Normal file
@@ -0,0 +1,14 @@
|
||||
load("@prysm//tools/go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["mock.go"],
|
||||
importpath = "github.com/prysmaticlabs/prysm/v3/api/client/builder/testing",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
"//proto/engine/v1:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
],
|
||||
)
|
||||
49
api/client/builder/testing/mock.go
Normal file
49
api/client/builder/testing/mock.go
Normal file
@@ -0,0 +1,49 @@
|
||||
package testing
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
||||
v1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||
)
|
||||
|
||||
// MockClient is a mock implementation of BuilderClient.
|
||||
type MockClient struct {
|
||||
RegisteredVals map[[48]byte]bool
|
||||
}
|
||||
|
||||
// NewClient creates a new, correctly initialized mock.
|
||||
func NewClient() MockClient {
|
||||
return MockClient{RegisteredVals: map[[48]byte]bool{}}
|
||||
}
|
||||
|
||||
// NodeURL --
|
||||
func (MockClient) NodeURL() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetHeader --
|
||||
func (MockClient) GetHeader(_ context.Context, _ types.Slot, _ [32]byte, _ [48]byte) (*ethpb.SignedBuilderBid, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// RegisterValidator --
|
||||
func (m MockClient) RegisterValidator(_ context.Context, svr []*ethpb.SignedValidatorRegistrationV1) error {
|
||||
for _, r := range svr {
|
||||
b := bytesutil.ToBytes48(r.Message.Pubkey)
|
||||
m.RegisteredVals[b] = true
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SubmitBlindedBlock --
|
||||
func (MockClient) SubmitBlindedBlock(_ context.Context, _ *ethpb.SignedBlindedBeaconBlockBellatrix) (*v1.ExecutionPayload, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Status --
|
||||
func (MockClient) Status(_ context.Context) error {
|
||||
return nil
|
||||
}
|
||||
@@ -23,8 +23,8 @@ type ValidatorRegistration struct {
|
||||
|
||||
func (r *SignedValidatorRegistration) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(struct {
|
||||
Message *ValidatorRegistration `json:"message,omitempty"`
|
||||
Signature hexutil.Bytes `json:"signature,omitempty"`
|
||||
Message *ValidatorRegistration `json:"message"`
|
||||
Signature hexutil.Bytes `json:"signature"`
|
||||
}{
|
||||
Message: &ValidatorRegistration{r.Message},
|
||||
Signature: r.SignedValidatorRegistrationV1.Signature,
|
||||
@@ -36,8 +36,8 @@ func (r *SignedValidatorRegistration) UnmarshalJSON(b []byte) error {
|
||||
r.SignedValidatorRegistrationV1 = ð.SignedValidatorRegistrationV1{}
|
||||
}
|
||||
o := struct {
|
||||
Message *ValidatorRegistration `json:"message,omitempty"`
|
||||
Signature hexutil.Bytes `json:"signature,omitempty"`
|
||||
Message *ValidatorRegistration `json:"message"`
|
||||
Signature hexutil.Bytes `json:"signature"`
|
||||
}{}
|
||||
if err := json.Unmarshal(b, &o); err != nil {
|
||||
return err
|
||||
@@ -49,10 +49,10 @@ func (r *SignedValidatorRegistration) UnmarshalJSON(b []byte) error {
|
||||
|
||||
func (r *ValidatorRegistration) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(struct {
|
||||
FeeRecipient hexutil.Bytes `json:"fee_recipient,omitempty"`
|
||||
GasLimit string `json:"gas_limit,omitempty"`
|
||||
Timestamp string `json:"timestamp,omitempty"`
|
||||
Pubkey hexutil.Bytes `json:"pubkey,omitempty"`
|
||||
FeeRecipient hexutil.Bytes `json:"fee_recipient"`
|
||||
GasLimit string `json:"gas_limit"`
|
||||
Timestamp string `json:"timestamp"`
|
||||
Pubkey hexutil.Bytes `json:"pubkey"`
|
||||
}{
|
||||
FeeRecipient: r.FeeRecipient,
|
||||
GasLimit: fmt.Sprintf("%d", r.GasLimit),
|
||||
@@ -66,10 +66,10 @@ func (r *ValidatorRegistration) UnmarshalJSON(b []byte) error {
|
||||
r.ValidatorRegistrationV1 = ð.ValidatorRegistrationV1{}
|
||||
}
|
||||
o := struct {
|
||||
FeeRecipient hexutil.Bytes `json:"fee_recipient,omitempty"`
|
||||
GasLimit string `json:"gas_limit,omitempty"`
|
||||
Timestamp string `json:"timestamp,omitempty"`
|
||||
Pubkey hexutil.Bytes `json:"pubkey,omitempty"`
|
||||
FeeRecipient hexutil.Bytes `json:"fee_recipient"`
|
||||
GasLimit string `json:"gas_limit"`
|
||||
Timestamp string `json:"timestamp"`
|
||||
Pubkey hexutil.Bytes `json:"pubkey"`
|
||||
}{}
|
||||
if err := json.Unmarshal(b, &o); err != nil {
|
||||
return err
|
||||
@@ -88,29 +88,43 @@ func (r *ValidatorRegistration) UnmarshalJSON(b []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
var errInvalidUint256 = errors.New("invalid Uint256")
|
||||
var errDecodeUint256 = errors.New("unable to decode into Uint256")
|
||||
|
||||
type Uint256 struct {
|
||||
*big.Int
|
||||
}
|
||||
|
||||
func stringToUint256(s string) Uint256 {
|
||||
func isValidUint256(bi *big.Int) bool {
|
||||
return bi.Cmp(big.NewInt(0)) >= 0 && bi.BitLen() <= 256
|
||||
}
|
||||
|
||||
func stringToUint256(s string) (Uint256, error) {
|
||||
bi := new(big.Int)
|
||||
bi.SetString(s, 10)
|
||||
return Uint256{Int: bi}
|
||||
_, ok := bi.SetString(s, 10)
|
||||
if !ok || !isValidUint256(bi) {
|
||||
return Uint256{}, errors.Wrapf(errDecodeUint256, "value=%s", s)
|
||||
}
|
||||
return Uint256{Int: bi}, nil
|
||||
}
|
||||
|
||||
// sszBytesToUint256 creates a Uint256 from a ssz-style (little-endian byte slice) representation.
|
||||
func sszBytesToUint256(b []byte) Uint256 {
|
||||
bi := new(big.Int)
|
||||
return Uint256{Int: bi.SetBytes(bytesutil.ReverseByteOrder(b))}
|
||||
func sszBytesToUint256(b []byte) (Uint256, error) {
|
||||
bi := bytesutil.LittleEndianBytesToBigInt(b)
|
||||
if !isValidUint256(bi) {
|
||||
return Uint256{}, errors.Wrapf(errDecodeUint256, "value=%s", b)
|
||||
}
|
||||
return Uint256{Int: bi}, nil
|
||||
}
|
||||
|
||||
// SSZBytes creates an ssz-style (little-endian byte slice) representation of the Uint256
|
||||
func (s Uint256) SSZBytes() []byte {
|
||||
if !isValidUint256(s.Int) {
|
||||
return []byte{}
|
||||
}
|
||||
return bytesutil.PadTo(bytesutil.ReverseByteOrder(s.Int.Bytes()), 32)
|
||||
}
|
||||
|
||||
var errUnmarshalUint256Failed = errors.New("unable to UnmarshalText into a Uint256 value")
|
||||
|
||||
func (s *Uint256) UnmarshalJSON(t []byte) error {
|
||||
start := 0
|
||||
end := len(t)
|
||||
@@ -129,7 +143,10 @@ func (s *Uint256) UnmarshalText(t []byte) error {
|
||||
}
|
||||
z, ok := s.SetString(string(t), 10)
|
||||
if !ok {
|
||||
return errors.Wrapf(errUnmarshalUint256Failed, "value=%s", string(t))
|
||||
return errors.Wrapf(errDecodeUint256, "value=%s", t)
|
||||
}
|
||||
if !isValidUint256(z) {
|
||||
return errors.Wrapf(errDecodeUint256, "value=%s", t)
|
||||
}
|
||||
s.Int = z
|
||||
return nil
|
||||
@@ -146,6 +163,9 @@ func (s Uint256) MarshalJSON() ([]byte, error) {
|
||||
}
|
||||
|
||||
func (s Uint256) MarshalText() ([]byte, error) {
|
||||
if !isValidUint256(s.Int) {
|
||||
return nil, errors.Wrapf(errInvalidUint256, "value=%s", s.Int)
|
||||
}
|
||||
return []byte(s.String()), nil
|
||||
}
|
||||
|
||||
@@ -162,11 +182,11 @@ func (s Uint64String) MarshalText() ([]byte, error) {
|
||||
}
|
||||
|
||||
type ExecHeaderResponse struct {
|
||||
Version string `json:"version,omitempty"`
|
||||
Version string `json:"version"`
|
||||
Data struct {
|
||||
Signature hexutil.Bytes `json:"signature,omitempty"`
|
||||
Message *BuilderBid `json:"message,omitempty"`
|
||||
} `json:"data,omitempty"`
|
||||
Signature hexutil.Bytes `json:"signature"`
|
||||
Message *BuilderBid `json:"message"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
func (ehr *ExecHeaderResponse) ToProto() (*eth.SignedBuilderBid, error) {
|
||||
@@ -212,31 +232,35 @@ func (h *ExecutionPayloadHeader) ToProto() (*v1.ExecutionPayloadHeader, error) {
|
||||
}
|
||||
|
||||
type BuilderBid struct {
|
||||
Header *ExecutionPayloadHeader `json:"header,omitempty"`
|
||||
Value Uint256 `json:"value,omitempty"`
|
||||
Pubkey hexutil.Bytes `json:"pubkey,omitempty"`
|
||||
Header *ExecutionPayloadHeader `json:"header"`
|
||||
Value Uint256 `json:"value"`
|
||||
Pubkey hexutil.Bytes `json:"pubkey"`
|
||||
}
|
||||
|
||||
type ExecutionPayloadHeader struct {
|
||||
ParentHash hexutil.Bytes `json:"parent_hash,omitempty"`
|
||||
FeeRecipient hexutil.Bytes `json:"fee_recipient,omitempty"`
|
||||
StateRoot hexutil.Bytes `json:"state_root,omitempty"`
|
||||
ReceiptsRoot hexutil.Bytes `json:"receipts_root,omitempty"`
|
||||
LogsBloom hexutil.Bytes `json:"logs_bloom,omitempty"`
|
||||
PrevRandao hexutil.Bytes `json:"prev_randao,omitempty"`
|
||||
BlockNumber Uint64String `json:"block_number,omitempty"`
|
||||
GasLimit Uint64String `json:"gas_limit,omitempty"`
|
||||
GasUsed Uint64String `json:"gas_used,omitempty"`
|
||||
Timestamp Uint64String `json:"timestamp,omitempty"`
|
||||
ExtraData hexutil.Bytes `json:"extra_data,omitempty"`
|
||||
BaseFeePerGas Uint256 `json:"base_fee_per_gas,omitempty"`
|
||||
BlockHash hexutil.Bytes `json:"block_hash,omitempty"`
|
||||
TransactionsRoot hexutil.Bytes `json:"transactions_root,omitempty"`
|
||||
ParentHash hexutil.Bytes `json:"parent_hash"`
|
||||
FeeRecipient hexutil.Bytes `json:"fee_recipient"`
|
||||
StateRoot hexutil.Bytes `json:"state_root"`
|
||||
ReceiptsRoot hexutil.Bytes `json:"receipts_root"`
|
||||
LogsBloom hexutil.Bytes `json:"logs_bloom"`
|
||||
PrevRandao hexutil.Bytes `json:"prev_randao"`
|
||||
BlockNumber Uint64String `json:"block_number"`
|
||||
GasLimit Uint64String `json:"gas_limit"`
|
||||
GasUsed Uint64String `json:"gas_used"`
|
||||
Timestamp Uint64String `json:"timestamp"`
|
||||
ExtraData hexutil.Bytes `json:"extra_data"`
|
||||
BaseFeePerGas Uint256 `json:"base_fee_per_gas"`
|
||||
BlockHash hexutil.Bytes `json:"block_hash"`
|
||||
TransactionsRoot hexutil.Bytes `json:"transactions_root"`
|
||||
*v1.ExecutionPayloadHeader
|
||||
}
|
||||
|
||||
func (h *ExecutionPayloadHeader) MarshalJSON() ([]byte, error) {
|
||||
type MarshalCaller ExecutionPayloadHeader
|
||||
baseFeePerGas, err := sszBytesToUint256(h.ExecutionPayloadHeader.BaseFeePerGas)
|
||||
if err != nil {
|
||||
return []byte{}, errors.Wrapf(err, "invalid BaseFeePerGas")
|
||||
}
|
||||
return json.Marshal(&MarshalCaller{
|
||||
ParentHash: h.ExecutionPayloadHeader.ParentHash,
|
||||
FeeRecipient: h.ExecutionPayloadHeader.FeeRecipient,
|
||||
@@ -249,7 +273,7 @@ func (h *ExecutionPayloadHeader) MarshalJSON() ([]byte, error) {
|
||||
GasUsed: Uint64String(h.ExecutionPayloadHeader.GasUsed),
|
||||
Timestamp: Uint64String(h.ExecutionPayloadHeader.Timestamp),
|
||||
ExtraData: h.ExecutionPayloadHeader.ExtraData,
|
||||
BaseFeePerGas: sszBytesToUint256(h.ExecutionPayloadHeader.BaseFeePerGas),
|
||||
BaseFeePerGas: baseFeePerGas,
|
||||
BlockHash: h.ExecutionPayloadHeader.BlockHash,
|
||||
TransactionsRoot: h.ExecutionPayloadHeader.TransactionsRoot,
|
||||
})
|
||||
@@ -269,25 +293,25 @@ func (h *ExecutionPayloadHeader) UnmarshalJSON(b []byte) error {
|
||||
}
|
||||
|
||||
type ExecPayloadResponse struct {
|
||||
Version string `json:"version,omitempty"`
|
||||
Data ExecutionPayload `json:"data,omitempty"`
|
||||
Version string `json:"version"`
|
||||
Data ExecutionPayload `json:"data"`
|
||||
}
|
||||
|
||||
type ExecutionPayload struct {
|
||||
ParentHash hexutil.Bytes `json:"parent_hash,omitempty"`
|
||||
FeeRecipient hexutil.Bytes `json:"fee_recipient,omitempty"`
|
||||
StateRoot hexutil.Bytes `json:"state_root,omitempty"`
|
||||
ReceiptsRoot hexutil.Bytes `json:"receipts_root,omitempty"`
|
||||
LogsBloom hexutil.Bytes `json:"logs_bloom,omitempty"`
|
||||
PrevRandao hexutil.Bytes `json:"prev_randao,omitempty"`
|
||||
BlockNumber Uint64String `json:"block_number,omitempty"`
|
||||
GasLimit Uint64String `json:"gas_limit,omitempty"`
|
||||
GasUsed Uint64String `json:"gas_used,omitempty"`
|
||||
Timestamp Uint64String `json:"timestamp,omitempty"`
|
||||
ExtraData hexutil.Bytes `json:"extra_data,omitempty"`
|
||||
BaseFeePerGas Uint256 `json:"base_fee_per_gas,omitempty"`
|
||||
BlockHash hexutil.Bytes `json:"block_hash,omitempty"`
|
||||
Transactions []hexutil.Bytes `json:"transactions,omitempty"`
|
||||
ParentHash hexutil.Bytes `json:"parent_hash"`
|
||||
FeeRecipient hexutil.Bytes `json:"fee_recipient"`
|
||||
StateRoot hexutil.Bytes `json:"state_root"`
|
||||
ReceiptsRoot hexutil.Bytes `json:"receipts_root"`
|
||||
LogsBloom hexutil.Bytes `json:"logs_bloom"`
|
||||
PrevRandao hexutil.Bytes `json:"prev_randao"`
|
||||
BlockNumber Uint64String `json:"block_number"`
|
||||
GasLimit Uint64String `json:"gas_limit"`
|
||||
GasUsed Uint64String `json:"gas_used"`
|
||||
Timestamp Uint64String `json:"timestamp"`
|
||||
ExtraData hexutil.Bytes `json:"extra_data"`
|
||||
BaseFeePerGas Uint256 `json:"base_fee_per_gas"`
|
||||
BlockHash hexutil.Bytes `json:"block_hash"`
|
||||
Transactions []hexutil.Bytes `json:"transactions"`
|
||||
}
|
||||
|
||||
func (r *ExecPayloadResponse) ToProto() (*v1.ExecutionPayload, error) {
|
||||
@@ -331,8 +355,8 @@ type BlindedBeaconBlockBodyBellatrix struct {
|
||||
|
||||
func (r *SignedBlindedBeaconBlockBellatrix) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(struct {
|
||||
Message *BlindedBeaconBlockBellatrix `json:"message,omitempty"`
|
||||
Signature hexutil.Bytes `json:"signature,omitempty"`
|
||||
Message *BlindedBeaconBlockBellatrix `json:"message"`
|
||||
Signature hexutil.Bytes `json:"signature"`
|
||||
}{
|
||||
Message: &BlindedBeaconBlockBellatrix{r.SignedBlindedBeaconBlockBellatrix.Block},
|
||||
Signature: r.SignedBlindedBeaconBlockBellatrix.Signature,
|
||||
@@ -342,10 +366,10 @@ func (r *SignedBlindedBeaconBlockBellatrix) MarshalJSON() ([]byte, error) {
|
||||
func (b *BlindedBeaconBlockBellatrix) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(struct {
|
||||
Slot string `json:"slot"`
|
||||
ProposerIndex string `json:"proposer_index,omitempty"`
|
||||
ParentRoot hexutil.Bytes `json:"parent_root,omitempty"`
|
||||
StateRoot hexutil.Bytes `json:"state_root,omitempty"`
|
||||
Body *BlindedBeaconBlockBodyBellatrix `json:"body,omitempty"`
|
||||
ProposerIndex string `json:"proposer_index"`
|
||||
ParentRoot hexutil.Bytes `json:"parent_root"`
|
||||
StateRoot hexutil.Bytes `json:"state_root"`
|
||||
Body *BlindedBeaconBlockBodyBellatrix `json:"body"`
|
||||
}{
|
||||
Slot: fmt.Sprintf("%d", b.Slot),
|
||||
ProposerIndex: fmt.Sprintf("%d", b.ProposerIndex),
|
||||
@@ -361,8 +385,8 @@ type ProposerSlashing struct {
|
||||
|
||||
func (s *ProposerSlashing) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(struct {
|
||||
SignedHeader1 *SignedBeaconBlockHeader `json:"signed_header_1,omitempty"`
|
||||
SignedHeader2 *SignedBeaconBlockHeader `json:"signed_header_2,omitempty"`
|
||||
SignedHeader1 *SignedBeaconBlockHeader `json:"signed_header_1"`
|
||||
SignedHeader2 *SignedBeaconBlockHeader `json:"signed_header_2"`
|
||||
}{
|
||||
SignedHeader1: &SignedBeaconBlockHeader{s.ProposerSlashing.Header_1},
|
||||
SignedHeader2: &SignedBeaconBlockHeader{s.ProposerSlashing.Header_2},
|
||||
@@ -375,8 +399,8 @@ type SignedBeaconBlockHeader struct {
|
||||
|
||||
func (h *SignedBeaconBlockHeader) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(struct {
|
||||
Header *BeaconBlockHeader `json:"message,omitempty"`
|
||||
Signature hexutil.Bytes `json:"signature,omitempty"`
|
||||
Header *BeaconBlockHeader `json:"message"`
|
||||
Signature hexutil.Bytes `json:"signature"`
|
||||
}{
|
||||
Header: &BeaconBlockHeader{h.SignedBeaconBlockHeader.Header},
|
||||
Signature: h.SignedBeaconBlockHeader.Signature,
|
||||
@@ -389,11 +413,11 @@ type BeaconBlockHeader struct {
|
||||
|
||||
func (h *BeaconBlockHeader) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(struct {
|
||||
Slot string `json:"slot,omitempty"`
|
||||
ProposerIndex string `json:"proposer_index,omitempty"`
|
||||
ParentRoot hexutil.Bytes `json:"parent_root,omitempty"`
|
||||
StateRoot hexutil.Bytes `json:"state_root,omitempty"`
|
||||
BodyRoot hexutil.Bytes `json:"body_root,omitempty"`
|
||||
Slot string `json:"slot"`
|
||||
ProposerIndex string `json:"proposer_index"`
|
||||
ParentRoot hexutil.Bytes `json:"parent_root"`
|
||||
StateRoot hexutil.Bytes `json:"state_root"`
|
||||
BodyRoot hexutil.Bytes `json:"body_root"`
|
||||
}{
|
||||
Slot: fmt.Sprintf("%d", h.BeaconBlockHeader.Slot),
|
||||
ProposerIndex: fmt.Sprintf("%d", h.BeaconBlockHeader.ProposerIndex),
|
||||
@@ -413,9 +437,9 @@ func (a *IndexedAttestation) MarshalJSON() ([]byte, error) {
|
||||
indices[i] = fmt.Sprintf("%d", a.AttestingIndices[i])
|
||||
}
|
||||
return json.Marshal(struct {
|
||||
AttestingIndices []string `json:"attesting_indices,omitempty"`
|
||||
Data *AttestationData `json:"data,omitempty"`
|
||||
Signature hexutil.Bytes `json:"signature,omitempty"`
|
||||
AttestingIndices []string `json:"attesting_indices"`
|
||||
Data *AttestationData `json:"data"`
|
||||
Signature hexutil.Bytes `json:"signature"`
|
||||
}{
|
||||
AttestingIndices: indices,
|
||||
Data: &AttestationData{a.IndexedAttestation.Data},
|
||||
@@ -429,8 +453,8 @@ type AttesterSlashing struct {
|
||||
|
||||
func (s *AttesterSlashing) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(struct {
|
||||
Attestation1 *IndexedAttestation `json:"attestation_1,omitempty"`
|
||||
Attestation2 *IndexedAttestation `json:"attestation_2,omitempty"`
|
||||
Attestation1 *IndexedAttestation `json:"attestation_1"`
|
||||
Attestation2 *IndexedAttestation `json:"attestation_2"`
|
||||
}{
|
||||
Attestation1: &IndexedAttestation{s.Attestation_1},
|
||||
Attestation2: &IndexedAttestation{s.Attestation_2},
|
||||
@@ -443,8 +467,8 @@ type Checkpoint struct {
|
||||
|
||||
func (c *Checkpoint) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(struct {
|
||||
Epoch string `json:"epoch,omitempty"`
|
||||
Root hexutil.Bytes `json:"root,omitempty"`
|
||||
Epoch string `json:"epoch"`
|
||||
Root hexutil.Bytes `json:"root"`
|
||||
}{
|
||||
Epoch: fmt.Sprintf("%d", c.Checkpoint.Epoch),
|
||||
Root: c.Checkpoint.Root,
|
||||
@@ -457,11 +481,11 @@ type AttestationData struct {
|
||||
|
||||
func (a *AttestationData) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(struct {
|
||||
Slot string `json:"slot,omitempty"`
|
||||
Index string `json:"index,omitempty"`
|
||||
BeaconBlockRoot hexutil.Bytes `json:"beacon_block_root,omitempty"`
|
||||
Source *Checkpoint `json:"source,omitempty"`
|
||||
Target *Checkpoint `json:"target,omitempty"`
|
||||
Slot string `json:"slot"`
|
||||
Index string `json:"index"`
|
||||
BeaconBlockRoot hexutil.Bytes `json:"beacon_block_root"`
|
||||
Source *Checkpoint `json:"source"`
|
||||
Target *Checkpoint `json:"target"`
|
||||
}{
|
||||
Slot: fmt.Sprintf("%d", a.AttestationData.Slot),
|
||||
Index: fmt.Sprintf("%d", a.AttestationData.CommitteeIndex),
|
||||
@@ -477,9 +501,9 @@ type Attestation struct {
|
||||
|
||||
func (a *Attestation) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(struct {
|
||||
AggregationBits hexutil.Bytes `json:"aggregation_bits,omitempty"`
|
||||
Data *AttestationData `json:"data,omitempty"`
|
||||
Signature hexutil.Bytes `json:"signature,omitempty" ssz-size:"96"`
|
||||
AggregationBits hexutil.Bytes `json:"aggregation_bits"`
|
||||
Data *AttestationData `json:"data"`
|
||||
Signature hexutil.Bytes `json:"signature" ssz-size:"96"`
|
||||
}{
|
||||
AggregationBits: hexutil.Bytes(a.Attestation.AggregationBits),
|
||||
Data: &AttestationData{a.Attestation.Data},
|
||||
@@ -493,10 +517,10 @@ type DepositData struct {
|
||||
|
||||
func (d *DepositData) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(struct {
|
||||
PublicKey hexutil.Bytes `json:"pubkey,omitempty"`
|
||||
WithdrawalCredentials hexutil.Bytes `json:"withdrawal_credentials,omitempty"`
|
||||
Amount string `json:"amount,omitempty"`
|
||||
Signature hexutil.Bytes `json:"signature,omitempty"`
|
||||
PublicKey hexutil.Bytes `json:"pubkey"`
|
||||
WithdrawalCredentials hexutil.Bytes `json:"withdrawal_credentials"`
|
||||
Amount string `json:"amount"`
|
||||
Signature hexutil.Bytes `json:"signature"`
|
||||
}{
|
||||
PublicKey: d.PublicKey,
|
||||
WithdrawalCredentials: d.WithdrawalCredentials,
|
||||
@@ -529,8 +553,8 @@ type SignedVoluntaryExit struct {
|
||||
|
||||
func (sve *SignedVoluntaryExit) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(struct {
|
||||
Message *VoluntaryExit `json:"message,omitempty"`
|
||||
Signature hexutil.Bytes `json:"signature,omitempty"`
|
||||
Message *VoluntaryExit `json:"message"`
|
||||
Signature hexutil.Bytes `json:"signature"`
|
||||
}{
|
||||
Signature: sve.SignedVoluntaryExit.Signature,
|
||||
Message: &VoluntaryExit{sve.SignedVoluntaryExit.Exit},
|
||||
@@ -543,8 +567,8 @@ type VoluntaryExit struct {
|
||||
|
||||
func (ve *VoluntaryExit) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(struct {
|
||||
Epoch string `json:"epoch,omitempty"`
|
||||
ValidatorIndex string `json:"validator_index,omitempty"`
|
||||
Epoch string `json:"epoch"`
|
||||
ValidatorIndex string `json:"validator_index"`
|
||||
}{
|
||||
Epoch: fmt.Sprintf("%d", ve.Epoch),
|
||||
ValidatorIndex: fmt.Sprintf("%d", ve.ValidatorIndex),
|
||||
@@ -557,8 +581,8 @@ type SyncAggregate struct {
|
||||
|
||||
func (s *SyncAggregate) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(struct {
|
||||
SyncCommitteeBits hexutil.Bytes `json:"sync_committee_bits,omitempty"`
|
||||
SyncCommitteeSignature hexutil.Bytes `json:"sync_committee_signature,omitempty"`
|
||||
SyncCommitteeBits hexutil.Bytes `json:"sync_committee_bits"`
|
||||
SyncCommitteeSignature hexutil.Bytes `json:"sync_committee_signature"`
|
||||
}{
|
||||
SyncCommitteeBits: hexutil.Bytes(s.SyncAggregate.SyncCommitteeBits),
|
||||
SyncCommitteeSignature: s.SyncAggregate.SyncCommitteeSignature,
|
||||
@@ -571,9 +595,9 @@ type Eth1Data struct {
|
||||
|
||||
func (e *Eth1Data) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(struct {
|
||||
DepositRoot hexutil.Bytes `json:"deposit_root,omitempty"`
|
||||
DepositCount string `json:"deposit_count,omitempty"`
|
||||
BlockHash hexutil.Bytes `json:"block_hash,omitempty"`
|
||||
DepositRoot hexutil.Bytes `json:"deposit_root"`
|
||||
DepositCount string `json:"deposit_count"`
|
||||
BlockHash hexutil.Bytes `json:"block_hash"`
|
||||
}{
|
||||
DepositRoot: e.DepositRoot,
|
||||
DepositCount: fmt.Sprintf("%d", e.DepositCount),
|
||||
@@ -603,16 +627,16 @@ func (b *BlindedBeaconBlockBodyBellatrix) MarshalJSON() ([]byte, error) {
|
||||
pros[i] = &ProposerSlashing{ProposerSlashing: b.BlindedBeaconBlockBodyBellatrix.ProposerSlashings[i]}
|
||||
}
|
||||
return json.Marshal(struct {
|
||||
RandaoReveal hexutil.Bytes `json:"randao_reveal,omitempty"`
|
||||
Eth1Data *Eth1Data `json:"eth1_data,omitempty"`
|
||||
Graffiti hexutil.Bytes `json:"graffiti,omitempty"`
|
||||
ProposerSlashings []*ProposerSlashing `json:"proposer_slashings,omitempty"`
|
||||
AttesterSlashings []*AttesterSlashing `json:"attester_slashings,omitempty"`
|
||||
Attestations []*Attestation `json:"attestations,omitempty"`
|
||||
Deposits []*Deposit `json:"deposits,omitempty"`
|
||||
VoluntaryExits []*SignedVoluntaryExit `json:"voluntary_exits,omitempty"`
|
||||
SyncAggregate *SyncAggregate `json:"sync_aggregate,omitempty"`
|
||||
ExecutionPayloadHeader *ExecutionPayloadHeader `json:"execution_payload_header,omitempty"`
|
||||
RandaoReveal hexutil.Bytes `json:"randao_reveal"`
|
||||
Eth1Data *Eth1Data `json:"eth1_data"`
|
||||
Graffiti hexutil.Bytes `json:"graffiti"`
|
||||
ProposerSlashings []*ProposerSlashing `json:"proposer_slashings"`
|
||||
AttesterSlashings []*AttesterSlashing `json:"attester_slashings"`
|
||||
Attestations []*Attestation `json:"attestations"`
|
||||
Deposits []*Deposit `json:"deposits"`
|
||||
VoluntaryExits []*SignedVoluntaryExit `json:"voluntary_exits"`
|
||||
SyncAggregate *SyncAggregate `json:"sync_aggregate"`
|
||||
ExecutionPayloadHeader *ExecutionPayloadHeader `json:"execution_payload_header"`
|
||||
}{
|
||||
RandaoReveal: b.RandaoReveal,
|
||||
Eth1Data: &Eth1Data{b.BlindedBeaconBlockBodyBellatrix.Eth1Data},
|
||||
|
||||
@@ -187,8 +187,10 @@ func TestExecutionHeaderResponseUnmarshal(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestExecutionHeaderResponseToProto(t *testing.T) {
|
||||
bfpg := stringToUint256("452312848583266388373324160190187140051835877600158453279131187530910662656")
|
||||
v := stringToUint256("652312848583266388373324160190187140051835877600158453279131187530910662656")
|
||||
bfpg, err := stringToUint256("452312848583266388373324160190187140051835877600158453279131187530910662656")
|
||||
require.NoError(t, err)
|
||||
v, err := stringToUint256("652312848583266388373324160190187140051835877600158453279131187530910662656")
|
||||
require.NoError(t, err)
|
||||
hr := &ExecHeaderResponse{}
|
||||
require.NoError(t, json.Unmarshal([]byte(testExampleHeaderResponse), hr))
|
||||
p, err := hr.ToProto()
|
||||
@@ -373,7 +375,8 @@ func TestExecutionPayloadResponseToProto(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
txList := [][]byte{tx}
|
||||
|
||||
bfpg := stringToUint256("452312848583266388373324160190187140051835877600158453279131187530910662656")
|
||||
bfpg, err := stringToUint256("452312848583266388373324160190187140051835877600158453279131187530910662656")
|
||||
require.NoError(t, err)
|
||||
expected := &v1.ExecutionPayload{
|
||||
ParentHash: parentHash,
|
||||
FeeRecipient: feeRecipient,
|
||||
@@ -581,7 +584,8 @@ func TestProposerSlashings(t *testing.T) {
|
||||
}
|
||||
|
||||
func pbExecutionPayloadHeader(t *testing.T) *v1.ExecutionPayloadHeader {
|
||||
bfpg := stringToUint256("452312848583266388373324160190187140051835877600158453279131187530910662656")
|
||||
bfpg, err := stringToUint256("452312848583266388373324160190187140051835877600158453279131187530910662656")
|
||||
require.NoError(t, err)
|
||||
return &v1.ExecutionPayloadHeader{
|
||||
ParentHash: ezDecode(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"),
|
||||
FeeRecipient: ezDecode(t, "0xabcf8e0d4e9587369b2301d0790347320302cc09"),
|
||||
@@ -661,6 +665,49 @@ func TestMathBigUnmarshal(t *testing.T) {
|
||||
require.NoError(t, u256.UnmarshalText([]byte("452312848583266388373324160190187140051835877600158453279131187530910662656")))
|
||||
}
|
||||
|
||||
func TestIsValidUint256(t *testing.T) {
|
||||
value, ok := new(big.Int), false
|
||||
|
||||
// negative uint256.max - 1
|
||||
_, ok = value.SetString("-10000000000000000000000000000000000000000000000000000000000000000", 16)
|
||||
require.Equal(t, true, ok)
|
||||
require.Equal(t, 257, value.BitLen())
|
||||
require.Equal(t, false, isValidUint256(value))
|
||||
|
||||
// negative uint256.max
|
||||
_, ok = value.SetString("-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16)
|
||||
require.Equal(t, true, ok)
|
||||
require.Equal(t, 256, value.BitLen())
|
||||
require.Equal(t, false, isValidUint256(value))
|
||||
|
||||
// negative number
|
||||
_, ok = value.SetString("-1", 16)
|
||||
require.Equal(t, true, ok)
|
||||
require.Equal(t, false, isValidUint256(value))
|
||||
|
||||
// uint256.min
|
||||
_, ok = value.SetString("0", 16)
|
||||
require.Equal(t, true, ok)
|
||||
require.Equal(t, true, isValidUint256(value))
|
||||
|
||||
// positive number
|
||||
_, ok = value.SetString("1", 16)
|
||||
require.Equal(t, true, ok)
|
||||
require.Equal(t, true, isValidUint256(value))
|
||||
|
||||
// uint256.max
|
||||
_, ok = value.SetString("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16)
|
||||
require.Equal(t, true, ok)
|
||||
require.Equal(t, 256, value.BitLen())
|
||||
require.Equal(t, true, isValidUint256(value))
|
||||
|
||||
// uint256.max + 1
|
||||
_, ok = value.SetString("10000000000000000000000000000000000000000000000000000000000000000", 16)
|
||||
require.Equal(t, true, ok)
|
||||
require.Equal(t, 257, value.BitLen())
|
||||
require.Equal(t, false, isValidUint256(value))
|
||||
}
|
||||
|
||||
func TestUint256Unmarshal(t *testing.T) {
|
||||
base10 := "452312848583266388373324160190187140051835877600158453279131187530910662656"
|
||||
bi := new(big.Int)
|
||||
@@ -677,6 +724,36 @@ func TestUint256Unmarshal(t *testing.T) {
|
||||
require.Equal(t, expected, string(m))
|
||||
}
|
||||
|
||||
func TestUint256UnmarshalNegative(t *testing.T) {
|
||||
m := "-1"
|
||||
var value Uint256
|
||||
err := value.UnmarshalText([]byte(m))
|
||||
require.ErrorContains(t, "unable to decode into Uint256", err)
|
||||
}
|
||||
|
||||
func TestUint256UnmarshalMin(t *testing.T) {
|
||||
m := "0"
|
||||
var value Uint256
|
||||
err := value.UnmarshalText([]byte(m))
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestUint256UnmarshalMax(t *testing.T) {
|
||||
// 2**256-1 (uint256.max)
|
||||
m := "115792089237316195423570985008687907853269984665640564039457584007913129639935"
|
||||
var value Uint256
|
||||
err := value.UnmarshalText([]byte(m))
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestUint256UnmarshalTooBig(t *testing.T) {
|
||||
// 2**256 (one more than uint256.max)
|
||||
m := "115792089237316195423570985008687907853269984665640564039457584007913129639936"
|
||||
var value Uint256
|
||||
err := value.UnmarshalText([]byte(m))
|
||||
require.ErrorContains(t, "unable to decode into Uint256", err)
|
||||
}
|
||||
|
||||
func TestMarshalBlindedBeaconBlockBodyBellatrix(t *testing.T) {
|
||||
expected, err := os.ReadFile("testdata/blinded-block.json")
|
||||
require.NoError(t, err)
|
||||
@@ -708,10 +785,12 @@ func TestMarshalBlindedBeaconBlockBodyBellatrix(t *testing.T) {
|
||||
|
||||
func TestRoundTripUint256(t *testing.T) {
|
||||
vs := "4523128485832663883733241601901871400518358776001584532791311875309106626"
|
||||
u := stringToUint256(vs)
|
||||
u, err := stringToUint256(vs)
|
||||
require.NoError(t, err)
|
||||
sb := u.SSZBytes()
|
||||
require.Equal(t, 32, len(sb))
|
||||
uu := sszBytesToUint256(sb)
|
||||
uu, err := sszBytesToUint256(sb)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, true, bytes.Equal(u.SSZBytes(), uu.SSZBytes()))
|
||||
require.Equal(t, vs, uu.String())
|
||||
}
|
||||
|
||||
@@ -3,7 +3,9 @@ Copyright 2017 Albert Tedja
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
@@ -3,7 +3,9 @@ Copyright 2017 Albert Tedja
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
@@ -51,9 +51,9 @@ go_library(
|
||||
"//beacon-chain/execution:go_default_library",
|
||||
"//beacon-chain/forkchoice:go_default_library",
|
||||
"//beacon-chain/forkchoice/doubly-linked-tree:go_default_library",
|
||||
"//beacon-chain/forkchoice/protoarray:go_default_library",
|
||||
"//beacon-chain/forkchoice/types:go_default_library",
|
||||
"//beacon-chain/operations/attestations:go_default_library",
|
||||
"//beacon-chain/operations/blstoexec:go_default_library",
|
||||
"//beacon-chain/operations/slashings:go_default_library",
|
||||
"//beacon-chain/operations/voluntaryexits:go_default_library",
|
||||
"//beacon-chain/p2p:go_default_library",
|
||||
@@ -64,6 +64,7 @@ go_library(
|
||||
"//config/params:go_default_library",
|
||||
"//consensus-types/blocks:go_default_library",
|
||||
"//consensus-types/interfaces:go_default_library",
|
||||
"//consensus-types/payload-attribute:go_default_library",
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
"//crypto/bls:go_default_library",
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
@@ -132,9 +133,8 @@ go_test(
|
||||
"//beacon-chain/execution/testing:go_default_library",
|
||||
"//beacon-chain/forkchoice/types:go_default_library",
|
||||
"//beacon-chain/p2p:go_default_library",
|
||||
"//beacon-chain/state/state-native:go_default_library",
|
||||
"//beacon-chain/state/stateutil:go_default_library",
|
||||
"//beacon-chain/state/v1:go_default_library",
|
||||
"//beacon-chain/state/v3:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//consensus-types/blocks:go_default_library",
|
||||
|
||||
@@ -5,10 +5,10 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/forkchoice"
|
||||
doublylinkedtree "github.com/prysmaticlabs/prysm/v3/beacon-chain/forkchoice/doubly-linked-tree"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/forkchoice/protoarray"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/v3/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||
@@ -314,7 +314,7 @@ func (s *Service) IsOptimistic(ctx context.Context) (bool, error) {
|
||||
if err == nil {
|
||||
return optimistic, nil
|
||||
}
|
||||
if err != protoarray.ErrUnknownNodeRoot && err != doublylinkedtree.ErrNilNode {
|
||||
if !errors.Is(err, doublylinkedtree.ErrNilNode) {
|
||||
return true, err
|
||||
}
|
||||
// If fockchoice does not have the headroot, then the node is considered
|
||||
@@ -328,6 +328,11 @@ func (s *Service) IsFinalized(ctx context.Context, root [32]byte) bool {
|
||||
if s.ForkChoicer().FinalizedCheckpoint().Root == root {
|
||||
return true
|
||||
}
|
||||
// If node exists in our store, then it is not
|
||||
// finalized.
|
||||
if s.ForkChoicer().HasNode(root) {
|
||||
return false
|
||||
}
|
||||
return s.cfg.BeaconDB.IsFinalizedBlock(ctx, root)
|
||||
}
|
||||
|
||||
@@ -338,7 +343,7 @@ func (s *Service) IsOptimisticForRoot(ctx context.Context, root [32]byte) (bool,
|
||||
if err == nil {
|
||||
return optimistic, nil
|
||||
}
|
||||
if err != protoarray.ErrUnknownNodeRoot && err != doublylinkedtree.ErrNilNode {
|
||||
if !errors.Is(err, doublylinkedtree.ErrNilNode) {
|
||||
return false, err
|
||||
}
|
||||
// if the requested root is the headroot and the root is not found in
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"testing"
|
||||
|
||||
testDB "github.com/prysmaticlabs/prysm/v3/beacon-chain/db/testing"
|
||||
doublylinkedtree "github.com/prysmaticlabs/prysm/v3/beacon-chain/forkchoice/doubly-linked-tree"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state/stategen"
|
||||
"github.com/prysmaticlabs/prysm/v3/consensus-types/blocks"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||
@@ -32,7 +33,7 @@ func TestHeadSlot_DataRace(t *testing.T) {
|
||||
func TestHeadRoot_DataRace(t *testing.T) {
|
||||
beaconDB := testDB.SetupDB(t)
|
||||
s := &Service{
|
||||
cfg: &config{BeaconDB: beaconDB, StateGen: stategen.New(beaconDB)},
|
||||
cfg: &config{BeaconDB: beaconDB, StateGen: stategen.New(beaconDB, doublylinkedtree.New())},
|
||||
head: &head{root: [32]byte{'A'}},
|
||||
}
|
||||
b, err := blocks.NewSignedBeaconBlock(util.NewBeaconBlock())
|
||||
@@ -54,7 +55,7 @@ func TestHeadBlock_DataRace(t *testing.T) {
|
||||
wsb, err := blocks.NewSignedBeaconBlock(ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Body: ðpb.BeaconBlockBody{}}})
|
||||
require.NoError(t, err)
|
||||
s := &Service{
|
||||
cfg: &config{BeaconDB: beaconDB, StateGen: stategen.New(beaconDB)},
|
||||
cfg: &config{BeaconDB: beaconDB, StateGen: stategen.New(beaconDB, doublylinkedtree.New())},
|
||||
head: &head{block: wsb},
|
||||
}
|
||||
b, err := blocks.NewSignedBeaconBlock(util.NewBeaconBlock())
|
||||
@@ -74,7 +75,7 @@ func TestHeadBlock_DataRace(t *testing.T) {
|
||||
func TestHeadState_DataRace(t *testing.T) {
|
||||
beaconDB := testDB.SetupDB(t)
|
||||
s := &Service{
|
||||
cfg: &config{BeaconDB: beaconDB, StateGen: stategen.New(beaconDB)},
|
||||
cfg: &config{BeaconDB: beaconDB, StateGen: stategen.New(beaconDB, doublylinkedtree.New())},
|
||||
}
|
||||
b, err := blocks.NewSignedBeaconBlock(util.NewBeaconBlock())
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -7,12 +7,10 @@ import (
|
||||
|
||||
testDB "github.com/prysmaticlabs/prysm/v3/beacon-chain/db/testing"
|
||||
doublylinkedtree "github.com/prysmaticlabs/prysm/v3/beacon-chain/forkchoice/doubly-linked-tree"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/forkchoice/protoarray"
|
||||
forkchoicetypes "github.com/prysmaticlabs/prysm/v3/beacon-chain/forkchoice/types"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state"
|
||||
state_native "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/state-native"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state/stategen"
|
||||
v1 "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/v1"
|
||||
v3 "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/v3"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/v3/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||
"github.com/prysmaticlabs/prysm/v3/consensus-types/blocks"
|
||||
@@ -61,7 +59,7 @@ func prepareForkchoiceState(
|
||||
}
|
||||
|
||||
base.BlockRoots[0] = append(base.BlockRoots[0], blockRoot[:]...)
|
||||
st, err := v3.InitializeFromProto(base)
|
||||
st, err := state_native.InitializeFromProtoBellatrix(base)
|
||||
return st, blockRoot, err
|
||||
}
|
||||
|
||||
@@ -86,7 +84,7 @@ func TestFinalizedCheckpt_GenesisRootOk(t *testing.T) {
|
||||
opts := []Option{
|
||||
WithDatabase(beaconDB),
|
||||
WithForkChoiceStore(fcs),
|
||||
WithStateGen(stategen.New(beaconDB)),
|
||||
WithStateGen(stategen.New(beaconDB, fcs)),
|
||||
}
|
||||
service, err := NewService(ctx, opts...)
|
||||
require.NoError(t, err)
|
||||
@@ -111,7 +109,7 @@ func TestCurrentJustifiedCheckpt_CanRetrieve(t *testing.T) {
|
||||
opts := []Option{
|
||||
WithDatabase(beaconDB),
|
||||
WithForkChoiceStore(fcs),
|
||||
WithStateGen(stategen.New(beaconDB)),
|
||||
WithStateGen(stategen.New(beaconDB, fcs)),
|
||||
}
|
||||
service, err := NewService(ctx, opts...)
|
||||
require.NoError(t, err)
|
||||
@@ -125,9 +123,12 @@ func TestCurrentJustifiedCheckpt_CanRetrieve(t *testing.T) {
|
||||
|
||||
func TestHeadSlot_CanRetrieve(t *testing.T) {
|
||||
c := &Service{}
|
||||
s, err := v1.InitializeFromProto(ðpb.BeaconState{})
|
||||
s, err := state_native.InitializeFromProtoPhase0(ðpb.BeaconState{})
|
||||
require.NoError(t, err)
|
||||
c.head = &head{slot: 100, state: s}
|
||||
b, err := blocks.NewSignedBeaconBlock(util.NewBeaconBlock())
|
||||
require.NoError(t, err)
|
||||
b.Block().SetSlot(100)
|
||||
c.head = &head{block: b, state: s}
|
||||
assert.Equal(t, types.Slot(100), c.HeadSlot())
|
||||
}
|
||||
|
||||
@@ -138,7 +139,7 @@ func TestHeadRoot_CanRetrieve(t *testing.T) {
|
||||
opts := []Option{
|
||||
WithDatabase(beaconDB),
|
||||
WithForkChoiceStore(fcs),
|
||||
WithStateGen(stategen.New(beaconDB)),
|
||||
WithStateGen(stategen.New(beaconDB, fcs)),
|
||||
}
|
||||
service, err := NewService(ctx, opts...)
|
||||
require.NoError(t, err)
|
||||
@@ -157,7 +158,7 @@ func TestHeadRoot_UseDB(t *testing.T) {
|
||||
opts := []Option{
|
||||
WithDatabase(beaconDB),
|
||||
WithForkChoiceStore(fcs),
|
||||
WithStateGen(stategen.New(beaconDB)),
|
||||
WithStateGen(stategen.New(beaconDB, fcs)),
|
||||
}
|
||||
service, err := NewService(ctx, opts...)
|
||||
require.NoError(t, err)
|
||||
@@ -179,7 +180,7 @@ func TestHeadRoot_UseDB(t *testing.T) {
|
||||
func TestHeadBlock_CanRetrieve(t *testing.T) {
|
||||
b := util.NewBeaconBlock()
|
||||
b.Block.Slot = 1
|
||||
s, err := v1.InitializeFromProto(ðpb.BeaconState{})
|
||||
s, err := state_native.InitializeFromProtoPhase0(ðpb.BeaconState{})
|
||||
require.NoError(t, err)
|
||||
wsb, err := blocks.NewSignedBeaconBlock(b)
|
||||
require.NoError(t, err)
|
||||
@@ -194,13 +195,13 @@ 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 := state_native.InitializeFromProtoPhase0(ðpb.BeaconState{Slot: 2, GenesisValidatorsRoot: params.BeaconConfig().ZeroHash[:]})
|
||||
require.NoError(t, err)
|
||||
c := &Service{}
|
||||
c.head = &head{state: s}
|
||||
headState, err := c.HeadState(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, headState.InnerStateUnsafe(), s.InnerStateUnsafe(), "Incorrect head state received")
|
||||
assert.DeepEqual(t, headState.ToProtoUnsafe(), s.ToProtoUnsafe(), "Incorrect head state received")
|
||||
}
|
||||
|
||||
func TestGenesisTime_CanRetrieve(t *testing.T) {
|
||||
@@ -211,7 +212,7 @@ 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})
|
||||
s, err := state_native.InitializeFromProtoPhase0(ðpb.BeaconState{Fork: f})
|
||||
require.NoError(t, err)
|
||||
c := &Service{}
|
||||
c.head = &head{state: s}
|
||||
@@ -236,7 +237,7 @@ func TestGenesisValidatorsRoot_CanRetrieve(t *testing.T) {
|
||||
c := &Service{}
|
||||
assert.Equal(t, [32]byte{}, c.GenesisValidatorsRoot(), "Did not get correct genesis validators root")
|
||||
|
||||
s, err := v1.InitializeFromProto(ðpb.BeaconState{GenesisValidatorsRoot: []byte{'a'}})
|
||||
s, err := state_native.InitializeFromProtoPhase0(ðpb.BeaconState{GenesisValidatorsRoot: []byte{'a'}})
|
||||
require.NoError(t, err)
|
||||
c.head = &head{state: s}
|
||||
assert.Equal(t, [32]byte{'a'}, c.GenesisValidatorsRoot(), "Did not get correct genesis validators root")
|
||||
@@ -250,7 +251,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 := state_native.InitializeFromProtoPhase0(ðpb.BeaconState{Eth1Data: d})
|
||||
require.NoError(t, err)
|
||||
c := &Service{}
|
||||
c.head = &head{state: s}
|
||||
@@ -306,31 +307,6 @@ func TestService_HeadGenesisValidatorsRoot(t *testing.T) {
|
||||
root = c.HeadGenesisValidatorsRoot()
|
||||
require.DeepEqual(t, root[:], s.GenesisValidatorsRoot())
|
||||
}
|
||||
func TestService_ChainHeads_ProtoArray(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
c := &Service{cfg: &config{ForkChoiceStore: protoarray.New()}}
|
||||
ojc := ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}
|
||||
ofc := ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}
|
||||
st, blkRoot, err := prepareForkchoiceState(ctx, 100, [32]byte{'a'}, [32]byte{}, params.BeaconConfig().ZeroHash, ojc, ofc)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, c.cfg.ForkChoiceStore.InsertNode(ctx, st, blkRoot))
|
||||
st, blkRoot, err = prepareForkchoiceState(ctx, 101, [32]byte{'b'}, [32]byte{'a'}, params.BeaconConfig().ZeroHash, ojc, ofc)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, c.cfg.ForkChoiceStore.InsertNode(ctx, st, blkRoot))
|
||||
st, blkRoot, err = prepareForkchoiceState(ctx, 102, [32]byte{'c'}, [32]byte{'b'}, params.BeaconConfig().ZeroHash, ojc, ofc)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, c.cfg.ForkChoiceStore.InsertNode(ctx, st, blkRoot))
|
||||
st, blkRoot, err = prepareForkchoiceState(ctx, 103, [32]byte{'d'}, [32]byte{'a'}, params.BeaconConfig().ZeroHash, ojc, ofc)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, c.cfg.ForkChoiceStore.InsertNode(ctx, st, blkRoot))
|
||||
st, blkRoot, err = prepareForkchoiceState(ctx, 104, [32]byte{'e'}, [32]byte{'b'}, params.BeaconConfig().ZeroHash, ojc, ofc)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, c.cfg.ForkChoiceStore.InsertNode(ctx, st, blkRoot))
|
||||
|
||||
roots, slots := c.ChainHeads()
|
||||
require.DeepEqual(t, [][32]byte{{'c'}, {'d'}, {'e'}}, roots)
|
||||
require.DeepEqual(t, []types.Slot{102, 103, 104}, slots)
|
||||
}
|
||||
|
||||
//
|
||||
// A <- B <- C
|
||||
@@ -338,7 +314,7 @@ func TestService_ChainHeads_ProtoArray(t *testing.T) {
|
||||
// \ ---------- E
|
||||
// ---------- D
|
||||
|
||||
func TestService_ChainHeads_DoublyLinkedTree(t *testing.T) {
|
||||
func TestService_ChainHeads(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
c := &Service{cfg: &config{ForkChoiceStore: doublylinkedtree.New()}}
|
||||
ojc := ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}
|
||||
@@ -355,7 +331,7 @@ func TestService_ChainHeads_DoublyLinkedTree(t *testing.T) {
|
||||
st, blkRoot, err = prepareForkchoiceState(ctx, 102, [32]byte{'c'}, [32]byte{'b'}, params.BeaconConfig().ZeroHash, ojc, ofc)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, c.cfg.ForkChoiceStore.InsertNode(ctx, st, blkRoot))
|
||||
st, blkRoot, err = prepareForkchoiceState(ctx, 103, [32]byte{'d'}, [32]byte{}, params.BeaconConfig().ZeroHash, ojc, ofc)
|
||||
st, blkRoot, err = prepareForkchoiceState(ctx, 103, [32]byte{'d'}, [32]byte{'a'}, params.BeaconConfig().ZeroHash, ojc, ofc)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, c.cfg.ForkChoiceStore.InsertNode(ctx, st, blkRoot))
|
||||
st, blkRoot, err = prepareForkchoiceState(ctx, 104, [32]byte{'e'}, [32]byte{'b'}, params.BeaconConfig().ZeroHash, ojc, ofc)
|
||||
@@ -430,29 +406,7 @@ func TestService_HeadValidatorIndexToPublicKeyNil(t *testing.T) {
|
||||
require.Equal(t, [fieldparams.BLSPubkeyLength]byte{}, p)
|
||||
}
|
||||
|
||||
func TestService_IsOptimistic_ProtoArray(t *testing.T) {
|
||||
params.SetupTestConfigCleanup(t)
|
||||
cfg := params.BeaconConfig()
|
||||
cfg.BellatrixForkEpoch = 0
|
||||
params.OverrideBeaconConfig(cfg)
|
||||
|
||||
ctx := context.Background()
|
||||
c := &Service{cfg: &config{ForkChoiceStore: protoarray.New()}, head: &head{slot: 101, root: [32]byte{'b'}}}
|
||||
ojc := ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}
|
||||
ofc := ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}
|
||||
st, blkRoot, err := prepareForkchoiceState(ctx, 100, [32]byte{'a'}, [32]byte{}, params.BeaconConfig().ZeroHash, ojc, ofc)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, c.cfg.ForkChoiceStore.InsertNode(ctx, st, blkRoot))
|
||||
st, blkRoot, err = prepareForkchoiceState(ctx, 101, [32]byte{'b'}, [32]byte{'a'}, params.BeaconConfig().ZeroHash, ojc, ofc)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, c.cfg.ForkChoiceStore.InsertNode(ctx, st, blkRoot))
|
||||
|
||||
opt, err := c.IsOptimistic(ctx)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, true, opt)
|
||||
}
|
||||
|
||||
func TestService_IsOptimistic_DoublyLinkedTree(t *testing.T) {
|
||||
func TestService_IsOptimistic(t *testing.T) {
|
||||
params.SetupTestConfigCleanup(t)
|
||||
cfg := params.BeaconConfig()
|
||||
cfg.BellatrixForkEpoch = 0
|
||||
@@ -461,7 +415,7 @@ func TestService_IsOptimistic_DoublyLinkedTree(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
ojc := ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}
|
||||
ofc := ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}
|
||||
c := &Service{cfg: &config{ForkChoiceStore: doublylinkedtree.New()}, head: &head{slot: 101, root: [32]byte{'b'}}}
|
||||
c := &Service{cfg: &config{ForkChoiceStore: doublylinkedtree.New()}, head: &head{root: [32]byte{'b'}}}
|
||||
st, blkRoot, err := prepareForkchoiceState(ctx, 100, [32]byte{'a'}, [32]byte{}, params.BeaconConfig().ZeroHash, ojc, ofc)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, c.cfg.ForkChoiceStore.InsertNode(ctx, st, blkRoot))
|
||||
@@ -482,9 +436,9 @@ func TestService_IsOptimisticBeforeBellatrix(t *testing.T) {
|
||||
require.Equal(t, false, opt)
|
||||
}
|
||||
|
||||
func TestService_IsOptimisticForRoot_ProtoArray(t *testing.T) {
|
||||
func TestService_IsOptimisticForRoot(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
c := &Service{cfg: &config{ForkChoiceStore: protoarray.New()}, head: &head{slot: 101, root: [32]byte{'b'}}}
|
||||
c := &Service{cfg: &config{ForkChoiceStore: doublylinkedtree.New()}, head: &head{root: [32]byte{'b'}}}
|
||||
ojc := ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}
|
||||
ofc := ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}
|
||||
st, blkRoot, err := prepareForkchoiceState(ctx, 100, [32]byte{'a'}, [32]byte{}, params.BeaconConfig().ZeroHash, ojc, ofc)
|
||||
@@ -499,86 +453,10 @@ func TestService_IsOptimisticForRoot_ProtoArray(t *testing.T) {
|
||||
require.Equal(t, true, opt)
|
||||
}
|
||||
|
||||
func TestService_IsOptimisticForRoot_DoublyLinkedTree(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
c := &Service{cfg: &config{ForkChoiceStore: doublylinkedtree.New()}, head: &head{slot: 101, root: [32]byte{'b'}}}
|
||||
ojc := ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}
|
||||
ofc := ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}
|
||||
st, blkRoot, err := prepareForkchoiceState(ctx, 100, [32]byte{'a'}, [32]byte{}, params.BeaconConfig().ZeroHash, ojc, ofc)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, c.cfg.ForkChoiceStore.InsertNode(ctx, st, blkRoot))
|
||||
st, blkRoot, err = prepareForkchoiceState(ctx, 101, [32]byte{'b'}, [32]byte{'a'}, params.BeaconConfig().ZeroHash, ojc, ofc)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, c.cfg.ForkChoiceStore.InsertNode(ctx, st, blkRoot))
|
||||
|
||||
opt, err := c.IsOptimisticForRoot(ctx, [32]byte{'a'})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, true, opt)
|
||||
}
|
||||
|
||||
func TestService_IsOptimisticForRoot_DB_ProtoArray(t *testing.T) {
|
||||
func TestService_IsOptimisticForRoot_DB(t *testing.T) {
|
||||
beaconDB := testDB.SetupDB(t)
|
||||
ctx := context.Background()
|
||||
c := &Service{cfg: &config{BeaconDB: beaconDB, ForkChoiceStore: protoarray.New()}, head: &head{slot: 101, root: [32]byte{'b'}}}
|
||||
c.head = &head{root: params.BeaconConfig().ZeroHash}
|
||||
b := util.NewBeaconBlock()
|
||||
b.Block.Slot = 10
|
||||
br, err := b.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
util.SaveBlock(t, context.Background(), beaconDB, b)
|
||||
require.NoError(t, beaconDB.SaveStateSummary(context.Background(), ðpb.StateSummary{Root: br[:], Slot: 10}))
|
||||
|
||||
optimisticBlock := util.NewBeaconBlock()
|
||||
optimisticBlock.Block.Slot = 97
|
||||
optimisticRoot, err := optimisticBlock.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
util.SaveBlock(t, context.Background(), beaconDB, optimisticBlock)
|
||||
|
||||
validatedBlock := util.NewBeaconBlock()
|
||||
validatedBlock.Block.Slot = 9
|
||||
validatedRoot, err := validatedBlock.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
util.SaveBlock(t, context.Background(), beaconDB, validatedBlock)
|
||||
|
||||
validatedCheckpoint := ðpb.Checkpoint{Root: br[:]}
|
||||
require.NoError(t, beaconDB.SaveLastValidatedCheckpoint(ctx, validatedCheckpoint))
|
||||
|
||||
_, err = c.IsOptimisticForRoot(ctx, optimisticRoot)
|
||||
require.ErrorContains(t, "nil summary returned from the DB", err)
|
||||
|
||||
require.NoError(t, beaconDB.SaveStateSummary(context.Background(), ðpb.StateSummary{Root: optimisticRoot[:], Slot: 11}))
|
||||
optimistic, err := c.IsOptimisticForRoot(ctx, optimisticRoot)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, true, optimistic)
|
||||
|
||||
require.NoError(t, beaconDB.SaveStateSummary(context.Background(), ðpb.StateSummary{Root: validatedRoot[:], Slot: 9}))
|
||||
cp := ðpb.Checkpoint{
|
||||
Epoch: 1,
|
||||
Root: validatedRoot[:],
|
||||
}
|
||||
require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, validatedRoot))
|
||||
require.NoError(t, beaconDB.SaveFinalizedCheckpoint(ctx, cp))
|
||||
|
||||
validated, err := c.IsOptimisticForRoot(ctx, validatedRoot)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, false, validated)
|
||||
|
||||
// Before the first finalized epoch, finalized root could be zeros.
|
||||
validatedCheckpoint = ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}
|
||||
require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, br))
|
||||
require.NoError(t, beaconDB.SaveStateSummary(context.Background(), ðpb.StateSummary{Root: params.BeaconConfig().ZeroHash[:], Slot: 10}))
|
||||
require.NoError(t, beaconDB.SaveLastValidatedCheckpoint(ctx, validatedCheckpoint))
|
||||
|
||||
require.NoError(t, beaconDB.SaveStateSummary(context.Background(), ðpb.StateSummary{Root: optimisticRoot[:], Slot: 11}))
|
||||
optimistic, err = c.IsOptimisticForRoot(ctx, optimisticRoot)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, true, optimistic)
|
||||
}
|
||||
|
||||
func TestService_IsOptimisticForRoot_DB_DoublyLinkedTree(t *testing.T) {
|
||||
beaconDB := testDB.SetupDB(t)
|
||||
ctx := context.Background()
|
||||
c := &Service{cfg: &config{BeaconDB: beaconDB, ForkChoiceStore: doublylinkedtree.New()}, head: &head{slot: 101, root: [32]byte{'b'}}}
|
||||
c := &Service{cfg: &config{BeaconDB: beaconDB, ForkChoiceStore: doublylinkedtree.New()}, head: &head{root: [32]byte{'b'}}}
|
||||
c.head = &head{root: params.BeaconConfig().ZeroHash}
|
||||
b := util.NewBeaconBlock()
|
||||
b.Block.Slot = 10
|
||||
@@ -636,7 +514,7 @@ func TestService_IsOptimisticForRoot_DB_DoublyLinkedTree(t *testing.T) {
|
||||
func TestService_IsOptimisticForRoot_DB_non_canonical(t *testing.T) {
|
||||
beaconDB := testDB.SetupDB(t)
|
||||
ctx := context.Background()
|
||||
c := &Service{cfg: &config{BeaconDB: beaconDB, ForkChoiceStore: doublylinkedtree.New()}, head: &head{slot: 101, root: [32]byte{'b'}}}
|
||||
c := &Service{cfg: &config{BeaconDB: beaconDB, ForkChoiceStore: doublylinkedtree.New()}, head: &head{root: [32]byte{'b'}}}
|
||||
c.head = &head{root: params.BeaconConfig().ZeroHash}
|
||||
b := util.NewBeaconBlock()
|
||||
b.Block.Slot = 10
|
||||
|
||||
@@ -8,19 +8,17 @@ var (
|
||||
// ErrInvalidBlockHashPayloadStatus is returned when the payload has invalid block hash.
|
||||
ErrInvalidBlockHashPayloadStatus = invalidBlock{error: errors.New("received an INVALID_BLOCK_HASH payload from execution engine")}
|
||||
// ErrUndefinedExecutionEngineError is returned when the execution engine returns an error that is not defined
|
||||
ErrUndefinedExecutionEngineError = errors.New("received an undefined ee error")
|
||||
ErrUndefinedExecutionEngineError = errors.New("received an undefined execution engine error")
|
||||
// errNilFinalizedInStore is returned when a nil finalized checkpt is returned from store.
|
||||
errNilFinalizedInStore = errors.New("nil finalized checkpoint returned from store")
|
||||
// errNilFinalizedCheckpoint is returned when a nil finalized checkpt is returned from a state.
|
||||
errNilFinalizedCheckpoint = errors.New("nil finalized checkpoint returned from state")
|
||||
// errNilJustifiedCheckpoint is returned when a nil justified checkpt is returned from a state.
|
||||
errNilJustifiedCheckpoint = errors.New("nil finalized checkpoint returned from state")
|
||||
errNilJustifiedCheckpoint = errors.New("nil justified checkpoint returned from state")
|
||||
// errInvalidNilSummary is returned when a nil summary is returned from the DB.
|
||||
errInvalidNilSummary = errors.New("nil summary returned from the DB")
|
||||
// errWrongBlockCount is returned when the wrong number of blocks or block roots is used
|
||||
errWrongBlockCount = errors.New("wrong number of blocks or block roots")
|
||||
// block is not a valid optimistic candidate block
|
||||
errNotOptimisticCandidate = errors.New("block is not suitable for optimistic sync")
|
||||
// errBlockNotFoundInCacheOrDB is returned when a block is not found in the cache or DB.
|
||||
errBlockNotFoundInCacheOrDB = errors.New("block not found in cache or db")
|
||||
// errNilStateFromStategen is returned when a nil state is returned from the state generator.
|
||||
|
||||
@@ -15,9 +15,11 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||
consensusblocks "github.com/prysmaticlabs/prysm/v3/consensus-types/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces"
|
||||
payloadattribute "github.com/prysmaticlabs/prysm/v3/consensus-types/payload-attribute"
|
||||
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
||||
enginev1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
|
||||
"github.com/prysmaticlabs/prysm/v3/runtime/version"
|
||||
"github.com/prysmaticlabs/prysm/v3/time/slots"
|
||||
"github.com/sirupsen/logrus"
|
||||
"go.opencensus.io/trace"
|
||||
@@ -67,11 +69,7 @@ func (s *Service) notifyForkchoiceUpdate(ctx context.Context, arg *notifyForkcho
|
||||
}
|
||||
|
||||
nextSlot := s.CurrentSlot() + 1 // Cache payload ID for next slot proposer.
|
||||
hasAttr, attr, proposerId, err := s.getPayloadAttribute(ctx, arg.headState, nextSlot)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Could not get head payload attribute")
|
||||
return nil, nil
|
||||
}
|
||||
hasAttr, attr, proposerId := s.getPayloadAttribute(ctx, arg.headState, nextSlot)
|
||||
|
||||
payloadID, lastValidHash, err := s.cfg.ExecutionEngineCaller.ForkchoiceUpdated(ctx, fcs, attr)
|
||||
if err != nil {
|
||||
@@ -83,18 +81,14 @@ func (s *Service) notifyForkchoiceUpdate(ctx context.Context, arg *notifyForkcho
|
||||
"headPayloadBlockHash": fmt.Sprintf("%#x", bytesutil.Trunc(headPayload.BlockHash())),
|
||||
"finalizedPayloadBlockHash": fmt.Sprintf("%#x", bytesutil.Trunc(finalizedHash[:])),
|
||||
}).Info("Called fork choice updated with optimistic block")
|
||||
err := s.optimisticCandidateBlock(ctx, headBlk)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Optimistic block failed to be candidate")
|
||||
}
|
||||
return payloadID, nil
|
||||
case execution.ErrInvalidPayloadStatus:
|
||||
newPayloadInvalidNodeCount.Inc()
|
||||
forkchoiceUpdatedInvalidNodeCount.Inc()
|
||||
headRoot := arg.headRoot
|
||||
if len(lastValidHash) == 0 {
|
||||
lastValidHash = defaultLatestValidHash
|
||||
}
|
||||
invalidRoots, err := s.ForkChoicer().SetOptimisticToInvalid(ctx, headRoot, bytesutil.ToBytes32(headBlk.ParentRoot()), bytesutil.ToBytes32(lastValidHash))
|
||||
invalidRoots, err := s.ForkChoicer().SetOptimisticToInvalid(ctx, headRoot, headBlk.ParentRoot(), bytesutil.ToBytes32(lastValidHash))
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Could not set head root to invalid")
|
||||
return nil, nil
|
||||
@@ -107,9 +101,9 @@ func (s *Service) notifyForkchoiceUpdate(ctx context.Context, arg *notifyForkcho
|
||||
r, err := s.cfg.ForkChoiceStore.Head(ctx, s.justifiedBalances.balances)
|
||||
if err != nil {
|
||||
log.WithFields(logrus.Fields{
|
||||
"slot": headBlk.Slot(),
|
||||
"blockRoot": fmt.Sprintf("%#x", bytesutil.Trunc(headRoot[:])),
|
||||
"invalidCount": len(invalidRoots),
|
||||
"slot": headBlk.Slot(),
|
||||
"blockRoot": fmt.Sprintf("%#x", bytesutil.Trunc(headRoot[:])),
|
||||
"invalidChildrenCount": len(invalidRoots),
|
||||
}).Warn("Pruned invalid blocks, could not update head root")
|
||||
return nil, invalidBlock{error: ErrInvalidPayload, root: arg.headRoot, invalidAncestorRoots: invalidRoots}
|
||||
}
|
||||
@@ -137,10 +131,10 @@ func (s *Service) notifyForkchoiceUpdate(ctx context.Context, arg *notifyForkcho
|
||||
}
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"slot": headBlk.Slot(),
|
||||
"blockRoot": fmt.Sprintf("%#x", bytesutil.Trunc(headRoot[:])),
|
||||
"invalidCount": len(invalidRoots),
|
||||
"newHeadRoot": fmt.Sprintf("%#x", bytesutil.Trunc(r[:])),
|
||||
"slot": headBlk.Slot(),
|
||||
"blockRoot": fmt.Sprintf("%#x", bytesutil.Trunc(headRoot[:])),
|
||||
"invalidChildrenCount": len(invalidRoots),
|
||||
"newHeadRoot": fmt.Sprintf("%#x", bytesutil.Trunc(r[:])),
|
||||
}).Warn("Pruned invalid blocks")
|
||||
return pid, invalidBlock{error: ErrInvalidPayload, root: arg.headRoot, invalidAncestorRoots: invalidRoots}
|
||||
|
||||
@@ -154,7 +148,8 @@ func (s *Service) notifyForkchoiceUpdate(ctx context.Context, arg *notifyForkcho
|
||||
log.WithError(err).Error("Could not set head root to valid")
|
||||
return nil, nil
|
||||
}
|
||||
if hasAttr && payloadID != nil { // If the forkchoice update call has an attribute, update the proposer payload ID cache.
|
||||
// If the forkchoice update call has an attribute, update the proposer payload ID cache.
|
||||
if hasAttr && payloadID != nil {
|
||||
var pId [8]byte
|
||||
copy(pId[:], payloadID[:])
|
||||
s.cfg.ProposerSlotIndexCache.SetProposerAndPayloadIDs(nextSlot, proposerId, pId, arg.headRoot)
|
||||
@@ -184,10 +179,10 @@ func (s *Service) getPayloadHash(ctx context.Context, root []byte) ([32]byte, er
|
||||
return bytesutil.ToBytes32(payload.BlockHash()), nil
|
||||
}
|
||||
|
||||
// notifyForkchoiceUpdate signals execution engine on a new payload.
|
||||
// notifyNewPayload signals execution engine on a new payload.
|
||||
// It returns true if the EL has returned VALID for the block
|
||||
func (s *Service) notifyNewPayload(ctx context.Context, postStateVersion int,
|
||||
postStateHeader *enginev1.ExecutionPayloadHeader, blk interfaces.SignedBeaconBlock) (bool, error) {
|
||||
postStateHeader interfaces.ExecutionData, blk interfaces.SignedBeaconBlock) (bool, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "blockChain.notifyNewPayload")
|
||||
defer span.End()
|
||||
|
||||
@@ -222,14 +217,14 @@ func (s *Service) notifyNewPayload(ctx context.Context, postStateVersion int,
|
||||
"slot": blk.Block().Slot(),
|
||||
"payloadBlockHash": fmt.Sprintf("%#x", bytesutil.Trunc(payload.BlockHash())),
|
||||
}).Info("Called new payload with optimistic block")
|
||||
return false, s.optimisticCandidateBlock(ctx, blk.Block())
|
||||
return false, nil
|
||||
case execution.ErrInvalidPayloadStatus:
|
||||
newPayloadInvalidNodeCount.Inc()
|
||||
root, err := blk.Block().HashTreeRoot()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
invalidRoots, err := s.ForkChoicer().SetOptimisticToInvalid(ctx, root, bytesutil.ToBytes32(blk.Block().ParentRoot()), bytesutil.ToBytes32(lastValidHash))
|
||||
invalidRoots, err := s.ForkChoicer().SetOptimisticToInvalid(ctx, root, blk.Block().ParentRoot(), bytesutil.ToBytes32(lastValidHash))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@@ -237,9 +232,9 @@ func (s *Service) notifyNewPayload(ctx context.Context, postStateVersion int,
|
||||
return false, err
|
||||
}
|
||||
log.WithFields(logrus.Fields{
|
||||
"slot": blk.Block().Slot(),
|
||||
"blockRoot": fmt.Sprintf("%#x", root),
|
||||
"invalidCount": len(invalidRoots),
|
||||
"slot": blk.Block().Slot(),
|
||||
"blockRoot": fmt.Sprintf("%#x", root),
|
||||
"invalidChildrenCount": len(invalidRoots),
|
||||
}).Warn("Pruned invalid blocks")
|
||||
return false, invalidBlock{
|
||||
invalidAncestorRoots: invalidRoots,
|
||||
@@ -253,55 +248,27 @@ func (s *Service) notifyNewPayload(ctx context.Context, postStateVersion int,
|
||||
}
|
||||
}
|
||||
|
||||
// optimisticCandidateBlock returns an error if this block can't be optimistically synced.
|
||||
// It replaces boolean in spec code with `errNotOptimisticCandidate`.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// def is_optimistic_candidate_block(opt_store: OptimisticStore, current_slot: Slot, block: BeaconBlock) -> bool:
|
||||
// if is_execution_block(opt_store.blocks[block.parent_root]):
|
||||
// return True
|
||||
//
|
||||
// if block.slot + SAFE_SLOTS_TO_IMPORT_OPTIMISTICALLY <= current_slot:
|
||||
// return True
|
||||
//
|
||||
// return False
|
||||
func (s *Service) optimisticCandidateBlock(ctx context.Context, blk interfaces.BeaconBlock) error {
|
||||
if blk.Slot()+params.BeaconConfig().SafeSlotsToImportOptimistically <= s.CurrentSlot() {
|
||||
return nil
|
||||
}
|
||||
parent, err := s.getBlock(ctx, bytesutil.ToBytes32(blk.ParentRoot()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
parentIsExecutionBlock, err := blocks.IsExecutionBlock(parent.Block().Body())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if parentIsExecutionBlock {
|
||||
return nil
|
||||
}
|
||||
|
||||
return errNotOptimisticCandidate
|
||||
}
|
||||
|
||||
// getPayloadAttributes returns the payload attributes for the given state and slot.
|
||||
// The attribute is required to initiate a payload build process in the context of an `engine_forkchoiceUpdated` call.
|
||||
func (s *Service) getPayloadAttribute(ctx context.Context, st state.BeaconState, slot types.Slot) (bool, *enginev1.PayloadAttributes, types.ValidatorIndex, error) {
|
||||
func (s *Service) getPayloadAttribute(ctx context.Context, st state.BeaconState, slot types.Slot) (bool, payloadattribute.Attributer, types.ValidatorIndex) {
|
||||
emptyAttri := payloadattribute.EmptyWithVersion(st.Version())
|
||||
// Root is `[32]byte{}` since we are retrieving proposer ID of a given slot. During insertion at assignment the root was not known.
|
||||
proposerID, _, ok := s.cfg.ProposerSlotIndexCache.GetProposerPayloadIDs(slot, [32]byte{} /* root */)
|
||||
if !ok { // There's no need to build attribute if there is no proposer for slot.
|
||||
return false, nil, 0, nil
|
||||
return false, emptyAttri, 0
|
||||
}
|
||||
|
||||
// Get previous randao.
|
||||
st = st.Copy()
|
||||
st, err := transition.ProcessSlotsIfPossible(ctx, st, slot)
|
||||
if err != nil {
|
||||
return false, nil, 0, err
|
||||
log.WithError(err).Error("Could not process slots to get payload attribute")
|
||||
return false, emptyAttri, 0
|
||||
}
|
||||
prevRando, err := helpers.RandaoMix(st, time.CurrentEpoch(st))
|
||||
if err != nil {
|
||||
return false, nil, 0, nil
|
||||
log.WithError(err).Error("Could not get randao mix to get payload attribute")
|
||||
return false, emptyAttri, 0
|
||||
}
|
||||
|
||||
// Get fee recipient.
|
||||
@@ -319,7 +286,8 @@ func (s *Service) getPayloadAttribute(ctx context.Context, st state.BeaconState,
|
||||
"Please refer to our documentation for instructions")
|
||||
}
|
||||
case err != nil:
|
||||
return false, nil, 0, errors.Wrap(err, "could not get fee recipient in db")
|
||||
log.WithError(err).Error("Could not get fee recipient to get payload attribute")
|
||||
return false, emptyAttri, 0
|
||||
default:
|
||||
feeRecipient = recipient
|
||||
}
|
||||
@@ -327,14 +295,44 @@ func (s *Service) getPayloadAttribute(ctx context.Context, st state.BeaconState,
|
||||
// Get timestamp.
|
||||
t, err := slots.ToTime(uint64(s.genesisTime.Unix()), slot)
|
||||
if err != nil {
|
||||
return false, nil, 0, err
|
||||
log.WithError(err).Error("Could not get timestamp to get payload attribute")
|
||||
return false, emptyAttri, 0
|
||||
}
|
||||
attr := &enginev1.PayloadAttributes{
|
||||
Timestamp: uint64(t.Unix()),
|
||||
PrevRandao: prevRando,
|
||||
SuggestedFeeRecipient: feeRecipient.Bytes(),
|
||||
|
||||
var attr payloadattribute.Attributer
|
||||
switch st.Version() {
|
||||
case version.Capella:
|
||||
withdrawals, err := st.ExpectedWithdrawals()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Could not get expected withdrawals to get payload attribute")
|
||||
return false, emptyAttri, 0
|
||||
}
|
||||
attr, err = payloadattribute.New(&enginev1.PayloadAttributesV2{
|
||||
Timestamp: uint64(t.Unix()),
|
||||
PrevRandao: prevRando,
|
||||
SuggestedFeeRecipient: feeRecipient.Bytes(),
|
||||
Withdrawals: withdrawals,
|
||||
})
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Could not get payload attribute")
|
||||
return false, emptyAttri, 0
|
||||
}
|
||||
case version.Bellatrix:
|
||||
attr, err = payloadattribute.New(&enginev1.PayloadAttributes{
|
||||
Timestamp: uint64(t.Unix()),
|
||||
PrevRandao: prevRando,
|
||||
SuggestedFeeRecipient: feeRecipient.Bytes(),
|
||||
})
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Could not get payload attribute")
|
||||
return false, emptyAttri, 0
|
||||
}
|
||||
default:
|
||||
log.WithField("version", st.Version()).Error("Could not get payload attribute due to unknown state version")
|
||||
return false, emptyAttri, 0
|
||||
}
|
||||
return true, attr, proposerID, nil
|
||||
|
||||
return true, attr, proposerID
|
||||
}
|
||||
|
||||
// removeInvalidBlockAndState removes the invalid block and its corresponding state from the cache and DB.
|
||||
|
||||
@@ -13,9 +13,9 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/execution"
|
||||
mockExecution "github.com/prysmaticlabs/prysm/v3/beacon-chain/execution/testing"
|
||||
doublylinkedtree "github.com/prysmaticlabs/prysm/v3/beacon-chain/forkchoice/doubly-linked-tree"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/forkchoice/protoarray"
|
||||
forkchoicetypes "github.com/prysmaticlabs/prysm/v3/beacon-chain/forkchoice/types"
|
||||
bstate "github.com/prysmaticlabs/prysm/v3/beacon-chain/state"
|
||||
state_native "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/state-native"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state/stategen"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/v3/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||
@@ -31,8 +31,7 @@ import (
|
||||
logTest "github.com/sirupsen/logrus/hooks/test"
|
||||
)
|
||||
|
||||
func Test_NotifyForkchoiceUpdate(t *testing.T) {
|
||||
params.BeaconConfig().SafeSlotsToImportOptimistically = 0
|
||||
func Test_NotifyForkchoiceUpdate_GetPayloadAttrErrorCanContinue(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
beaconDB := testDB.SetupDB(t)
|
||||
altairBlk := util.SaveBlock(t, ctx, beaconDB, util.NewBeaconBlockAltair())
|
||||
@@ -44,16 +43,80 @@ func Test_NotifyForkchoiceUpdate(t *testing.T) {
|
||||
fcs := doublylinkedtree.New()
|
||||
opts := []Option{
|
||||
WithDatabase(beaconDB),
|
||||
WithStateGen(stategen.New(beaconDB)),
|
||||
WithStateGen(stategen.New(beaconDB, fcs)),
|
||||
WithForkChoiceStore(fcs),
|
||||
WithProposerIdsCache(cache.NewProposerPayloadIDsCache()),
|
||||
}
|
||||
service, err := NewService(ctx, opts...)
|
||||
require.NoError(t, err)
|
||||
st, _ := util.DeterministicGenesisState(t, 10)
|
||||
service.head = &head{
|
||||
state: st,
|
||||
}
|
||||
|
||||
ojc := ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}
|
||||
ofc := ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}
|
||||
state, blkRoot, err := prepareForkchoiceState(ctx, 0, [32]byte{}, [32]byte{}, params.BeaconConfig().ZeroHash, ojc, ofc)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, fcs.InsertNode(ctx, state, blkRoot))
|
||||
state, blkRoot, err = prepareForkchoiceState(ctx, 1, altairBlkRoot, [32]byte{}, params.BeaconConfig().ZeroHash, ojc, ofc)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, fcs.InsertNode(ctx, state, blkRoot))
|
||||
state, blkRoot, err = prepareForkchoiceState(ctx, 2, bellatrixBlkRoot, altairBlkRoot, params.BeaconConfig().ZeroHash, ojc, ofc)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, fcs.InsertNode(ctx, state, blkRoot))
|
||||
|
||||
b, err := consensusblocks.NewBeaconBlock(ðpb.BeaconBlockBellatrix{
|
||||
Body: ðpb.BeaconBlockBodyBellatrix{
|
||||
ExecutionPayload: &v1.ExecutionPayload{},
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
pid := &v1.PayloadIDBytes{1}
|
||||
service.cfg.ExecutionEngineCaller = &mockExecution.EngineClient{PayloadIDBytes: pid}
|
||||
st, _ = util.DeterministicGenesisState(t, 1)
|
||||
require.NoError(t, beaconDB.SaveState(ctx, st, bellatrixBlkRoot))
|
||||
require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, bellatrixBlkRoot))
|
||||
|
||||
// Intentionally generate a bad state such that `hash_tree_root` fails during `process_slot`
|
||||
s, err := state_native.InitializeFromProtoPhase0(ðpb.BeaconState{})
|
||||
require.NoError(t, err)
|
||||
arg := ¬ifyForkchoiceUpdateArg{
|
||||
headState: s,
|
||||
headRoot: [32]byte{},
|
||||
headBlock: b,
|
||||
}
|
||||
|
||||
service.cfg.ProposerSlotIndexCache.SetProposerAndPayloadIDs(1, 0, [8]byte{}, [32]byte{})
|
||||
got, err := service.notifyForkchoiceUpdate(ctx, arg)
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, got, pid) // We still get a payload ID even though the state is bad. This means it returns until the end.
|
||||
}
|
||||
|
||||
func Test_NotifyForkchoiceUpdate(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
beaconDB := testDB.SetupDB(t)
|
||||
altairBlk := util.SaveBlock(t, ctx, beaconDB, util.NewBeaconBlockAltair())
|
||||
altairBlkRoot, err := altairBlk.Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
bellatrixBlk := util.SaveBlock(t, ctx, beaconDB, util.NewBeaconBlockBellatrix())
|
||||
bellatrixBlkRoot, err := bellatrixBlk.Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
fcs := doublylinkedtree.New()
|
||||
opts := []Option{
|
||||
WithDatabase(beaconDB),
|
||||
WithStateGen(stategen.New(beaconDB, fcs)),
|
||||
WithForkChoiceStore(fcs),
|
||||
WithProposerIdsCache(cache.NewProposerPayloadIDsCache()),
|
||||
}
|
||||
service, err := NewService(ctx, opts...)
|
||||
require.NoError(t, err)
|
||||
st, _ := util.DeterministicGenesisState(t, 10)
|
||||
service.head = &head{
|
||||
state: st,
|
||||
}
|
||||
|
||||
ojc := ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}
|
||||
ofc := ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}
|
||||
state, blkRoot, err := prepareForkchoiceState(ctx, 0, [32]byte{}, [32]byte{}, params.BeaconConfig().ZeroHash, ojc, ofc)
|
||||
@@ -199,151 +262,6 @@ func Test_NotifyForkchoiceUpdate(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
// A <- B <- C <- D
|
||||
// \
|
||||
// ---------- E <- F
|
||||
// \
|
||||
// ------ G
|
||||
// D is the current head, attestations for F and G come late, both are invalid.
|
||||
// We switch recursively to F then G and finally to D.
|
||||
//
|
||||
// We test:
|
||||
// 1. forkchoice removes blocks F and G from the forkchoice implementation
|
||||
// 2. forkchoice removes the weights of these blocks
|
||||
// 3. the blockchain package calls fcu to obtain heads G -> F -> D.
|
||||
|
||||
func Test_NotifyForkchoiceUpdateRecursive_Protoarray(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
beaconDB := testDB.SetupDB(t)
|
||||
|
||||
// Prepare blocks
|
||||
ba := util.NewBeaconBlockBellatrix()
|
||||
ba.Block.Body.ExecutionPayload.BlockNumber = 1
|
||||
wba := util.SaveBlock(t, ctx, beaconDB, ba)
|
||||
bra, err := wba.Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
bb := util.NewBeaconBlockBellatrix()
|
||||
bb.Block.Body.ExecutionPayload.BlockNumber = 2
|
||||
wbb := util.SaveBlock(t, ctx, beaconDB, bb)
|
||||
brb, err := wbb.Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
bc := util.NewBeaconBlockBellatrix()
|
||||
bc.Block.Body.ExecutionPayload.BlockNumber = 3
|
||||
wbc := util.SaveBlock(t, ctx, beaconDB, bc)
|
||||
brc, err := wbc.Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
bd := util.NewBeaconBlockBellatrix()
|
||||
pd := [32]byte{'D'}
|
||||
bd.Block.Body.ExecutionPayload.BlockHash = pd[:]
|
||||
bd.Block.Body.ExecutionPayload.BlockNumber = 4
|
||||
wbd := util.SaveBlock(t, ctx, beaconDB, bd)
|
||||
brd, err := wbd.Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
be := util.NewBeaconBlockBellatrix()
|
||||
pe := [32]byte{'E'}
|
||||
be.Block.Body.ExecutionPayload.BlockHash = pe[:]
|
||||
be.Block.Body.ExecutionPayload.BlockNumber = 5
|
||||
wbe := util.SaveBlock(t, ctx, beaconDB, be)
|
||||
bre, err := wbe.Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
bf := util.NewBeaconBlockBellatrix()
|
||||
pf := [32]byte{'F'}
|
||||
bf.Block.Body.ExecutionPayload.BlockHash = pf[:]
|
||||
bf.Block.Body.ExecutionPayload.BlockNumber = 6
|
||||
bf.Block.ParentRoot = bre[:]
|
||||
wbf := util.SaveBlock(t, ctx, beaconDB, bf)
|
||||
brf, err := wbf.Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
bg := util.NewBeaconBlockBellatrix()
|
||||
bg.Block.Body.ExecutionPayload.BlockNumber = 7
|
||||
pg := [32]byte{'G'}
|
||||
bg.Block.Body.ExecutionPayload.BlockHash = pg[:]
|
||||
bg.Block.ParentRoot = bre[:]
|
||||
wbg := util.SaveBlock(t, ctx, beaconDB, bg)
|
||||
brg, err := wbg.Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
// Insert blocks into forkchoice
|
||||
service := setupBeaconChain(t, beaconDB)
|
||||
fcs := protoarray.New()
|
||||
service.cfg.ForkChoiceStore = fcs
|
||||
service.cfg.ProposerSlotIndexCache = cache.NewProposerPayloadIDsCache()
|
||||
|
||||
service.justifiedBalances.balances = []uint64{50, 100, 200}
|
||||
require.NoError(t, err)
|
||||
ojc := ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}
|
||||
ofc := ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}
|
||||
state, blkRoot, err := prepareForkchoiceState(ctx, 1, bra, [32]byte{}, [32]byte{'A'}, ojc, ofc)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, fcs.InsertNode(ctx, state, blkRoot))
|
||||
state, blkRoot, err = prepareForkchoiceState(ctx, 2, brb, bra, [32]byte{'B'}, ojc, ofc)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, fcs.InsertNode(ctx, state, blkRoot))
|
||||
state, blkRoot, err = prepareForkchoiceState(ctx, 3, brc, brb, [32]byte{'C'}, ojc, ofc)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, fcs.InsertNode(ctx, state, blkRoot))
|
||||
state, blkRoot, err = prepareForkchoiceState(ctx, 4, brd, brc, [32]byte{'D'}, ojc, ofc)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, fcs.InsertNode(ctx, state, blkRoot))
|
||||
state, blkRoot, err = prepareForkchoiceState(ctx, 5, bre, brb, [32]byte{'E'}, ojc, ofc)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, fcs.InsertNode(ctx, state, blkRoot))
|
||||
state, blkRoot, err = prepareForkchoiceState(ctx, 6, brf, bre, [32]byte{'F'}, ojc, ofc)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, fcs.InsertNode(ctx, state, blkRoot))
|
||||
state, blkRoot, err = prepareForkchoiceState(ctx, 7, brg, bre, [32]byte{'G'}, ojc, ofc)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, fcs.InsertNode(ctx, state, blkRoot))
|
||||
|
||||
// Insert Attestations to D, F and G so that they have higher weight than D
|
||||
// Ensure G is head
|
||||
fcs.ProcessAttestation(ctx, []uint64{0}, brd, 1)
|
||||
fcs.ProcessAttestation(ctx, []uint64{1}, brf, 1)
|
||||
fcs.ProcessAttestation(ctx, []uint64{2}, brg, 1)
|
||||
jc := &forkchoicetypes.Checkpoint{Epoch: 0, Root: bra}
|
||||
require.NoError(t, fcs.UpdateJustifiedCheckpoint(jc))
|
||||
headRoot, err := fcs.Head(ctx, []uint64{50, 100, 200})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, brg, headRoot)
|
||||
|
||||
// Prepare Engine Mock to return invalid unless head is D, LVH = E
|
||||
service.cfg.ExecutionEngineCaller = &mockExecution.EngineClient{ErrForkchoiceUpdated: execution.ErrInvalidPayloadStatus, ForkChoiceUpdatedResp: pe[:], OverrideValidHash: [32]byte{'D'}}
|
||||
st, _ := util.DeterministicGenesisState(t, 1)
|
||||
service.head = &head{
|
||||
state: st,
|
||||
block: wba,
|
||||
}
|
||||
|
||||
require.NoError(t, beaconDB.SaveState(ctx, st, bra))
|
||||
require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, bra))
|
||||
a := ¬ifyForkchoiceUpdateArg{
|
||||
headState: st,
|
||||
headBlock: wbg.Block(),
|
||||
headRoot: brg,
|
||||
}
|
||||
_, err = service.notifyForkchoiceUpdate(ctx, a)
|
||||
require.Equal(t, true, IsInvalidBlock(err))
|
||||
require.Equal(t, brf, InvalidBlockRoot(err))
|
||||
|
||||
// Ensure Head is D
|
||||
headRoot, err = fcs.Head(ctx, service.justifiedBalances.balances)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, brd, headRoot)
|
||||
|
||||
// Ensure F and G where removed but their parent E wasn't
|
||||
require.Equal(t, false, fcs.HasNode(brf))
|
||||
require.Equal(t, false, fcs.HasNode(brg))
|
||||
require.Equal(t, true, fcs.HasNode(bre))
|
||||
}
|
||||
|
||||
func Test_NotifyForkchoiceUpdate_NIlLVH(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
beaconDB := testDB.SetupDB(t)
|
||||
@@ -578,7 +496,7 @@ func Test_NotifyNewPayload(t *testing.T) {
|
||||
fcs := doublylinkedtree.New()
|
||||
opts := []Option{
|
||||
WithDatabase(beaconDB),
|
||||
WithStateGen(stategen.New(beaconDB)),
|
||||
WithStateGen(stategen.New(beaconDB, fcs)),
|
||||
WithForkChoiceStore(fcs),
|
||||
}
|
||||
phase0State, _ := util.DeterministicGenesisState(t, 1)
|
||||
@@ -824,7 +742,7 @@ func Test_NotifyNewPayload_SetOptimisticToValid(t *testing.T) {
|
||||
fcs := doublylinkedtree.New()
|
||||
opts := []Option{
|
||||
WithDatabase(beaconDB),
|
||||
WithStateGen(stategen.New(beaconDB)),
|
||||
WithStateGen(stategen.New(beaconDB, fcs)),
|
||||
WithForkChoiceStore(fcs),
|
||||
}
|
||||
bellatrixState, _ := util.DeterministicGenesisStateBellatrix(t, 2)
|
||||
@@ -862,169 +780,20 @@ func Test_NotifyNewPayload_SetOptimisticToValid(t *testing.T) {
|
||||
require.Equal(t, true, validated)
|
||||
}
|
||||
|
||||
func Test_IsOptimisticCandidateBlock(t *testing.T) {
|
||||
params.SetupTestConfigCleanup(t)
|
||||
params.OverrideBeaconConfig(params.MainnetConfig())
|
||||
|
||||
ctx := context.Background()
|
||||
beaconDB := testDB.SetupDB(t)
|
||||
fcs := doublylinkedtree.New()
|
||||
opts := []Option{
|
||||
WithDatabase(beaconDB),
|
||||
WithStateGen(stategen.New(beaconDB)),
|
||||
WithForkChoiceStore(fcs),
|
||||
}
|
||||
|
||||
service, err := NewService(ctx, opts...)
|
||||
require.NoError(t, err)
|
||||
|
||||
params.BeaconConfig().SafeSlotsToImportOptimistically = 128
|
||||
service.genesisTime = time.Now().Add(-time.Second * 12 * 2 * 128)
|
||||
|
||||
parentBlk := util.NewBeaconBlockBellatrix()
|
||||
wrappedParentBlock, err := consensusblocks.NewSignedBeaconBlock(parentBlk)
|
||||
require.NoError(t, err)
|
||||
parentRoot, err := wrappedParentBlock.Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
blk interfaces.BeaconBlock
|
||||
justified interfaces.SignedBeaconBlock
|
||||
err error
|
||||
}{
|
||||
{
|
||||
name: "deep block",
|
||||
blk: func(tt *testing.T) interfaces.BeaconBlock {
|
||||
blk := util.NewBeaconBlockBellatrix()
|
||||
blk.Block.Slot = 1
|
||||
blk.Block.ParentRoot = parentRoot[:]
|
||||
wr, err := consensusblocks.NewBeaconBlock(blk.Block)
|
||||
require.NoError(tt, err)
|
||||
return wr
|
||||
}(t),
|
||||
justified: func(tt *testing.T) interfaces.SignedBeaconBlock {
|
||||
blk := util.NewBeaconBlockBellatrix()
|
||||
blk.Block.Slot = 32
|
||||
blk.Block.ParentRoot = parentRoot[:]
|
||||
wr, err := consensusblocks.NewSignedBeaconBlock(blk)
|
||||
require.NoError(tt, err)
|
||||
return wr
|
||||
}(t),
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
name: "shallow block, Altair justified chkpt",
|
||||
blk: func(tt *testing.T) interfaces.BeaconBlock {
|
||||
blk := util.NewBeaconBlockAltair()
|
||||
blk.Block.Slot = 200
|
||||
blk.Block.ParentRoot = parentRoot[:]
|
||||
wr, err := consensusblocks.NewBeaconBlock(blk.Block)
|
||||
require.NoError(tt, err)
|
||||
return wr
|
||||
}(t),
|
||||
justified: func(tt *testing.T) interfaces.SignedBeaconBlock {
|
||||
blk := util.NewBeaconBlockAltair()
|
||||
blk.Block.Slot = 32
|
||||
blk.Block.ParentRoot = parentRoot[:]
|
||||
wr, err := consensusblocks.NewSignedBeaconBlock(blk)
|
||||
require.NoError(tt, err)
|
||||
return wr
|
||||
}(t),
|
||||
err: errNotOptimisticCandidate,
|
||||
},
|
||||
{
|
||||
name: "shallow block, Bellatrix justified chkpt without execution",
|
||||
blk: func(tt *testing.T) interfaces.BeaconBlock {
|
||||
blk := util.NewBeaconBlockBellatrix()
|
||||
blk.Block.Slot = 200
|
||||
blk.Block.ParentRoot = parentRoot[:]
|
||||
wr, err := consensusblocks.NewBeaconBlock(blk.Block)
|
||||
require.NoError(tt, err)
|
||||
return wr
|
||||
}(t),
|
||||
justified: func(tt *testing.T) interfaces.SignedBeaconBlock {
|
||||
blk := util.NewBeaconBlockBellatrix()
|
||||
blk.Block.Slot = 32
|
||||
blk.Block.ParentRoot = parentRoot[:]
|
||||
wr, err := consensusblocks.NewSignedBeaconBlock(blk)
|
||||
require.NoError(tt, err)
|
||||
return wr
|
||||
}(t),
|
||||
err: errNotOptimisticCandidate,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveBlock(ctx, tt.justified))
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveBlock(ctx, wrappedParentBlock))
|
||||
|
||||
err = service.optimisticCandidateBlock(ctx, tt.blk)
|
||||
if tt.err != nil {
|
||||
require.Equal(t, tt.err.Error(), err.Error())
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Test_IsOptimisticShallowExecutionParent(t *testing.T) {
|
||||
params.SetupTestConfigCleanup(t)
|
||||
params.OverrideBeaconConfig(params.MainnetConfig())
|
||||
|
||||
ctx := context.Background()
|
||||
beaconDB := testDB.SetupDB(t)
|
||||
opts := []Option{
|
||||
WithDatabase(beaconDB),
|
||||
WithStateGen(stategen.New(beaconDB)),
|
||||
}
|
||||
|
||||
service, err := NewService(ctx, opts...)
|
||||
require.NoError(t, err)
|
||||
|
||||
params.BeaconConfig().SafeSlotsToImportOptimistically = 128
|
||||
service.genesisTime = time.Now().Add(-time.Second * 12 * 2 * 128)
|
||||
payload := &v1.ExecutionPayload{
|
||||
ParentHash: make([]byte, 32),
|
||||
FeeRecipient: make([]byte, 20),
|
||||
StateRoot: make([]byte, 32),
|
||||
ReceiptsRoot: make([]byte, 32),
|
||||
LogsBloom: make([]byte, 256),
|
||||
PrevRandao: make([]byte, 32),
|
||||
BaseFeePerGas: bytesutil.PadTo([]byte{1, 2, 3, 4}, fieldparams.RootLength),
|
||||
BlockHash: make([]byte, 32),
|
||||
BlockNumber: 100,
|
||||
}
|
||||
body := ðpb.BeaconBlockBodyBellatrix{ExecutionPayload: payload}
|
||||
b := ðpb.BeaconBlockBellatrix{Body: body, Slot: 200}
|
||||
rawSigned := ðpb.SignedBeaconBlockBellatrix{Block: b}
|
||||
blk := util.HydrateSignedBeaconBlockBellatrix(rawSigned)
|
||||
wr := util.SaveBlock(t, ctx, service.cfg.BeaconDB, blk)
|
||||
blkRoot, err := wr.Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
childBlock := util.NewBeaconBlockBellatrix()
|
||||
childBlock.Block.ParentRoot = blkRoot[:]
|
||||
// shallow block
|
||||
childBlock.Block.Slot = 201
|
||||
wrappedChild := util.SaveBlock(t, ctx, service.cfg.BeaconDB, childBlock)
|
||||
err = service.optimisticCandidateBlock(ctx, wrappedChild.Block())
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func Test_GetPayloadAttribute(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
beaconDB := testDB.SetupDB(t)
|
||||
opts := []Option{
|
||||
WithDatabase(beaconDB),
|
||||
WithStateGen(stategen.New(beaconDB)),
|
||||
WithStateGen(stategen.New(beaconDB, doublylinkedtree.New())),
|
||||
WithProposerIdsCache(cache.NewProposerPayloadIDsCache()),
|
||||
}
|
||||
|
||||
// Cache miss
|
||||
service, err := NewService(ctx, opts...)
|
||||
require.NoError(t, err)
|
||||
hasPayload, _, vId, err := service.getPayloadAttribute(ctx, nil, 0)
|
||||
require.NoError(t, err)
|
||||
st, _ := util.DeterministicGenesisStateBellatrix(t, 1)
|
||||
hasPayload, _, vId := service.getPayloadAttribute(ctx, st, 0)
|
||||
require.Equal(t, false, hasPayload)
|
||||
require.Equal(t, types.ValidatorIndex(0), vId)
|
||||
|
||||
@@ -1032,24 +801,65 @@ func Test_GetPayloadAttribute(t *testing.T) {
|
||||
suggestedVid := types.ValidatorIndex(1)
|
||||
slot := types.Slot(1)
|
||||
service.cfg.ProposerSlotIndexCache.SetProposerAndPayloadIDs(slot, suggestedVid, [8]byte{}, [32]byte{})
|
||||
st, _ := util.DeterministicGenesisState(t, 1)
|
||||
hook := logTest.NewGlobal()
|
||||
hasPayload, attr, vId, err := service.getPayloadAttribute(ctx, st, slot)
|
||||
require.NoError(t, err)
|
||||
hasPayload, attr, vId := service.getPayloadAttribute(ctx, st, slot)
|
||||
require.Equal(t, true, hasPayload)
|
||||
require.Equal(t, suggestedVid, vId)
|
||||
require.Equal(t, params.BeaconConfig().EthBurnAddressHex, common.BytesToAddress(attr.SuggestedFeeRecipient).String())
|
||||
require.Equal(t, params.BeaconConfig().EthBurnAddressHex, common.BytesToAddress(attr.SuggestedFeeRecipient()).String())
|
||||
require.LogsContain(t, hook, "Fee recipient is currently using the burn address")
|
||||
|
||||
// Cache hit, advance state, has fee recipient
|
||||
suggestedAddr := common.HexToAddress("123")
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveFeeRecipientsByValidatorIDs(ctx, []types.ValidatorIndex{suggestedVid}, []common.Address{suggestedAddr}))
|
||||
service.cfg.ProposerSlotIndexCache.SetProposerAndPayloadIDs(slot, suggestedVid, [8]byte{}, [32]byte{})
|
||||
hasPayload, attr, vId, err = service.getPayloadAttribute(ctx, st, slot)
|
||||
require.NoError(t, err)
|
||||
hasPayload, attr, vId = service.getPayloadAttribute(ctx, st, slot)
|
||||
require.Equal(t, true, hasPayload)
|
||||
require.Equal(t, suggestedVid, vId)
|
||||
require.Equal(t, suggestedAddr, common.BytesToAddress(attr.SuggestedFeeRecipient))
|
||||
require.Equal(t, suggestedAddr, common.BytesToAddress(attr.SuggestedFeeRecipient()))
|
||||
}
|
||||
|
||||
func Test_GetPayloadAttributeV2(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
beaconDB := testDB.SetupDB(t)
|
||||
opts := []Option{
|
||||
WithDatabase(beaconDB),
|
||||
WithStateGen(stategen.New(beaconDB, doublylinkedtree.New())),
|
||||
WithProposerIdsCache(cache.NewProposerPayloadIDsCache()),
|
||||
}
|
||||
|
||||
// Cache miss
|
||||
service, err := NewService(ctx, opts...)
|
||||
require.NoError(t, err)
|
||||
st, _ := util.DeterministicGenesisStateCapella(t, 1)
|
||||
hasPayload, _, vId := service.getPayloadAttribute(ctx, st, 0)
|
||||
require.Equal(t, false, hasPayload)
|
||||
require.Equal(t, types.ValidatorIndex(0), vId)
|
||||
|
||||
// Cache hit, advance state, no fee recipient
|
||||
suggestedVid := types.ValidatorIndex(1)
|
||||
slot := types.Slot(1)
|
||||
service.cfg.ProposerSlotIndexCache.SetProposerAndPayloadIDs(slot, suggestedVid, [8]byte{}, [32]byte{})
|
||||
hook := logTest.NewGlobal()
|
||||
hasPayload, attr, vId := service.getPayloadAttribute(ctx, st, slot)
|
||||
require.Equal(t, true, hasPayload)
|
||||
require.Equal(t, suggestedVid, vId)
|
||||
require.Equal(t, params.BeaconConfig().EthBurnAddressHex, common.BytesToAddress(attr.SuggestedFeeRecipient()).String())
|
||||
require.LogsContain(t, hook, "Fee recipient is currently using the burn address")
|
||||
a, err := attr.Withdrawals()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 0, len(a))
|
||||
|
||||
// Cache hit, advance state, has fee recipient
|
||||
suggestedAddr := common.HexToAddress("123")
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveFeeRecipientsByValidatorIDs(ctx, []types.ValidatorIndex{suggestedVid}, []common.Address{suggestedAddr}))
|
||||
service.cfg.ProposerSlotIndexCache.SetProposerAndPayloadIDs(slot, suggestedVid, [8]byte{}, [32]byte{})
|
||||
hasPayload, attr, vId = service.getPayloadAttribute(ctx, st, slot)
|
||||
require.Equal(t, true, hasPayload)
|
||||
require.Equal(t, suggestedVid, vId)
|
||||
require.Equal(t, suggestedAddr, common.BytesToAddress(attr.SuggestedFeeRecipient()))
|
||||
a, err = attr.Withdrawals()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 0, len(a))
|
||||
}
|
||||
|
||||
func Test_UpdateLastValidatedCheckpoint(t *testing.T) {
|
||||
@@ -1058,8 +868,8 @@ func Test_UpdateLastValidatedCheckpoint(t *testing.T) {
|
||||
|
||||
ctx := context.Background()
|
||||
beaconDB := testDB.SetupDB(t)
|
||||
stateGen := stategen.New(beaconDB)
|
||||
fcs := doublylinkedtree.New()
|
||||
stateGen := stategen.New(beaconDB, fcs)
|
||||
opts := []Option{
|
||||
WithDatabase(beaconDB),
|
||||
WithStateGen(stateGen),
|
||||
@@ -1067,7 +877,7 @@ func Test_UpdateLastValidatedCheckpoint(t *testing.T) {
|
||||
}
|
||||
service, err := NewService(ctx, opts...)
|
||||
require.NoError(t, err)
|
||||
genesisStateRoot := [32]byte{}
|
||||
var genesisStateRoot [32]byte
|
||||
genesisBlk := blocks.NewGenesisBlock(genesisStateRoot[:])
|
||||
util.SaveBlock(t, ctx, beaconDB, genesisBlk)
|
||||
genesisRoot, err := genesisBlk.Block.HashTreeRoot()
|
||||
@@ -1155,15 +965,28 @@ func Test_UpdateLastValidatedCheckpoint(t *testing.T) {
|
||||
require.Equal(t, false, optimistic)
|
||||
require.DeepEqual(t, validCheckpoint.Root, cp.Root)
|
||||
require.Equal(t, validCheckpoint.Epoch, cp.Epoch)
|
||||
|
||||
// Checkpoint with a lower epoch
|
||||
oldCp, err := service.cfg.BeaconDB.FinalizedCheckpoint(ctx)
|
||||
require.NoError(t, err)
|
||||
invalidCp := ðpb.Checkpoint{
|
||||
Epoch: oldCp.Epoch - 1,
|
||||
}
|
||||
// Nothing should happen as we no-op on an invalid checkpoint.
|
||||
require.NoError(t, service.updateFinalized(ctx, invalidCp))
|
||||
got, err := service.cfg.BeaconDB.FinalizedCheckpoint(ctx)
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, oldCp, got)
|
||||
}
|
||||
|
||||
func TestService_removeInvalidBlockAndState(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
beaconDB := testDB.SetupDB(t)
|
||||
fc := doublylinkedtree.New()
|
||||
opts := []Option{
|
||||
WithDatabase(beaconDB),
|
||||
WithStateGen(stategen.New(beaconDB)),
|
||||
WithForkChoiceStore(doublylinkedtree.New()),
|
||||
WithStateGen(stategen.New(beaconDB, fc)),
|
||||
WithForkChoiceStore(fc),
|
||||
}
|
||||
service, err := NewService(ctx, opts...)
|
||||
require.NoError(t, err)
|
||||
@@ -1212,10 +1035,11 @@ func TestService_removeInvalidBlockAndState(t *testing.T) {
|
||||
func TestService_getPayloadHash(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
beaconDB := testDB.SetupDB(t)
|
||||
fc := doublylinkedtree.New()
|
||||
opts := []Option{
|
||||
WithDatabase(beaconDB),
|
||||
WithStateGen(stategen.New(beaconDB)),
|
||||
WithForkChoiceStore(doublylinkedtree.New()),
|
||||
WithStateGen(stategen.New(beaconDB, fc)),
|
||||
WithForkChoiceStore(fc),
|
||||
}
|
||||
service, err := NewService(ctx, opts...)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -17,7 +17,9 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces"
|
||||
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/v3/math"
|
||||
ethpbv1 "github.com/prysmaticlabs/prysm/v3/proto/eth/v1"
|
||||
"github.com/prysmaticlabs/prysm/v3/runtime/version"
|
||||
"github.com/prysmaticlabs/prysm/v3/time/slots"
|
||||
"github.com/sirupsen/logrus"
|
||||
"go.opencensus.io/trace"
|
||||
@@ -50,7 +52,6 @@ func (s *Service) UpdateAndSaveHeadWithBalances(ctx context.Context) error {
|
||||
|
||||
// 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 state.BeaconState // current head state.
|
||||
@@ -90,6 +91,7 @@ func (s *Service) saveHead(ctx context.Context, newHeadRoot [32]byte, headBlock
|
||||
s.headLock.RLock()
|
||||
oldHeadBlock, err := s.headBlock()
|
||||
if err != nil {
|
||||
s.headLock.RUnlock()
|
||||
return errors.Wrap(err, "could not get old head block")
|
||||
}
|
||||
oldStateRoot := oldHeadBlock.Block().StateRoot()
|
||||
@@ -99,20 +101,36 @@ func (s *Service) saveHead(ctx context.Context, newHeadRoot [32]byte, headBlock
|
||||
newStateRoot := headBlock.Block().StateRoot()
|
||||
|
||||
// A chain re-org occurred, so we fire an event notifying the rest of the services.
|
||||
if bytesutil.ToBytes32(headBlock.Block().ParentRoot()) != oldHeadRoot {
|
||||
commonRoot, err := s.ForkChoicer().CommonAncestorRoot(ctx, oldHeadRoot, newHeadRoot)
|
||||
if headBlock.Block().ParentRoot() != oldHeadRoot {
|
||||
commonRoot, forkSlot, err := s.ForkChoicer().CommonAncestor(ctx, oldHeadRoot, newHeadRoot)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Could not find common ancestor root")
|
||||
commonRoot = params.BeaconConfig().ZeroHash
|
||||
}
|
||||
dis := headSlot + newHeadSlot - 2*forkSlot
|
||||
dep := math.Max(uint64(headSlot-forkSlot), uint64(newHeadSlot-forkSlot))
|
||||
oldWeight, err := s.ForkChoicer().Weight(oldHeadRoot)
|
||||
if err != nil {
|
||||
log.WithField("root", fmt.Sprintf("%#x", oldHeadRoot)).Warn("could not determine node weight")
|
||||
}
|
||||
newWeight, err := s.ForkChoicer().Weight(newHeadRoot)
|
||||
if err != nil {
|
||||
log.WithField("root", fmt.Sprintf("%#x", newHeadRoot)).Warn("could not determine node weight")
|
||||
}
|
||||
log.WithFields(logrus.Fields{
|
||||
"newSlot": fmt.Sprintf("%d", newHeadSlot),
|
||||
"newRoot": fmt.Sprintf("%#x", newHeadRoot),
|
||||
"newWeight": newWeight,
|
||||
"oldSlot": fmt.Sprintf("%d", headSlot),
|
||||
"oldRoot": fmt.Sprintf("%#x", oldHeadRoot),
|
||||
"oldWeight": oldWeight,
|
||||
"commonAncestorRoot": fmt.Sprintf("%#x", commonRoot),
|
||||
"distance": dis,
|
||||
"depth": dep,
|
||||
}).Info("Chain reorg occurred")
|
||||
absoluteSlotDifference := slots.AbsoluteValueSlotDifference(newHeadSlot, headSlot)
|
||||
reorgDistance.Observe(float64(dis))
|
||||
reorgDepth.Observe(float64(dep))
|
||||
|
||||
isOptimistic, err := s.IsOptimistic(ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not check if node is optimistically synced")
|
||||
@@ -121,17 +139,17 @@ func (s *Service) saveHead(ctx context.Context, newHeadRoot [32]byte, headBlock
|
||||
Type: statefeed.Reorg,
|
||||
Data: ðpbv1.EventChainReorg{
|
||||
Slot: newHeadSlot,
|
||||
Depth: absoluteSlotDifference,
|
||||
Depth: math.Max(uint64(headSlot-forkSlot), uint64(newHeadSlot-forkSlot)),
|
||||
OldHeadBlock: oldHeadRoot[:],
|
||||
NewHeadBlock: newHeadRoot[:],
|
||||
OldHeadState: oldStateRoot,
|
||||
NewHeadState: newStateRoot,
|
||||
OldHeadState: oldStateRoot[:],
|
||||
NewHeadState: newStateRoot[:],
|
||||
Epoch: slots.ToEpoch(newHeadSlot),
|
||||
ExecutionOptimistic: isOptimistic,
|
||||
},
|
||||
})
|
||||
|
||||
if err := s.saveOrphanedAtts(ctx, oldHeadRoot, newHeadRoot); err != nil {
|
||||
if err := s.saveOrphanedOperations(ctx, oldHeadRoot, newHeadRoot); err != nil {
|
||||
return err
|
||||
}
|
||||
reorgCount.Inc()
|
||||
@@ -150,7 +168,7 @@ func (s *Service) saveHead(ctx context.Context, newHeadRoot [32]byte, headBlock
|
||||
// Forward an event capturing a new chain head over a common event feed
|
||||
// done in a goroutine to avoid blocking the critical runtime main routine.
|
||||
go func() {
|
||||
if err := s.notifyNewHeadEvent(ctx, newHeadSlot, headState, newStateRoot, newHeadRoot[:]); err != nil {
|
||||
if err := s.notifyNewHeadEvent(ctx, newHeadSlot, headState, newStateRoot[:], newHeadRoot[:]); err != nil {
|
||||
log.WithError(err).Error("Could not notify event feed of new chain head")
|
||||
}
|
||||
}()
|
||||
@@ -194,7 +212,6 @@ func (s *Service) setHead(root [32]byte, block interfaces.SignedBeaconBlock, sta
|
||||
return err
|
||||
}
|
||||
s.head = &head{
|
||||
slot: block.Block().Slot(),
|
||||
root: root,
|
||||
block: bCp,
|
||||
state: state.Copy(),
|
||||
@@ -215,7 +232,6 @@ func (s *Service) setHeadInitialSync(root [32]byte, block interfaces.SignedBeaco
|
||||
return err
|
||||
}
|
||||
s.head = &head{
|
||||
slot: block.Block().Slot(),
|
||||
root: root,
|
||||
block: bCp,
|
||||
state: state,
|
||||
@@ -226,7 +242,10 @@ func (s *Service) setHeadInitialSync(root [32]byte, block interfaces.SignedBeaco
|
||||
// This returns the head slot.
|
||||
// This is a lock free version.
|
||||
func (s *Service) headSlot() types.Slot {
|
||||
return s.head.slot
|
||||
if s.head == nil || s.head.block == nil || s.head.block.Block() == nil {
|
||||
return 0
|
||||
}
|
||||
return s.head.block.Block().Slot()
|
||||
}
|
||||
|
||||
// This returns the head root.
|
||||
@@ -339,10 +358,10 @@ func (s *Service) notifyNewHeadEvent(
|
||||
return nil
|
||||
}
|
||||
|
||||
// This saves the attestations between `orphanedRoot` and the common ancestor root that is derived using `newHeadRoot`.
|
||||
// This saves the Attestations and BLSToExecChanges between `orphanedRoot` and the common ancestor root that is derived using `newHeadRoot`.
|
||||
// It also filters out the attestations that is one epoch older as a defense so invalid attestations don't flow into the attestation pool.
|
||||
func (s *Service) saveOrphanedAtts(ctx context.Context, orphanedRoot [32]byte, newHeadRoot [32]byte) error {
|
||||
commonAncestorRoot, err := s.ForkChoicer().CommonAncestorRoot(ctx, newHeadRoot, orphanedRoot)
|
||||
func (s *Service) saveOrphanedOperations(ctx context.Context, orphanedRoot [32]byte, newHeadRoot [32]byte) error {
|
||||
commonAncestorRoot, _, err := s.ForkChoicer().CommonAncestor(ctx, newHeadRoot, orphanedRoot)
|
||||
switch {
|
||||
// Exit early if there's no common ancestor and root doesn't exist, there would be nothing to save.
|
||||
case errors.Is(err, forkchoice.ErrUnknownCommonAncestor):
|
||||
@@ -380,7 +399,17 @@ func (s *Service) saveOrphanedAtts(ctx context.Context, orphanedRoot [32]byte, n
|
||||
}
|
||||
saveOrphanedAttCount.Inc()
|
||||
}
|
||||
orphanedRoot = bytesutil.ToBytes32(orphanedBlk.Block().ParentRoot())
|
||||
if orphanedBlk.Version() >= version.Capella {
|
||||
changes, err := orphanedBlk.Block().Body().BLSToExecutionChanges()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get BLSToExecutionChanges")
|
||||
}
|
||||
for _, c := range changes {
|
||||
s.cfg.BLSToExecPool.InsertBLSToExecChange(c)
|
||||
}
|
||||
}
|
||||
parentRoot := orphanedBlk.Block().ParentRoot()
|
||||
orphanedRoot = bytesutil.ToBytes32(parentRoot[:])
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/cache"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/signing"
|
||||
dbtest "github.com/prysmaticlabs/prysm/v3/beacon-chain/db/testing"
|
||||
doublylinkedtree "github.com/prysmaticlabs/prysm/v3/beacon-chain/forkchoice/doubly-linked-tree"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state/stategen"
|
||||
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||
@@ -19,7 +20,7 @@ func TestService_headSyncCommitteeFetcher_Errors(t *testing.T) {
|
||||
beaconDB := dbtest.SetupDB(t)
|
||||
c := &Service{
|
||||
cfg: &config{
|
||||
StateGen: stategen.New(beaconDB),
|
||||
StateGen: stategen.New(beaconDB, doublylinkedtree.New()),
|
||||
},
|
||||
}
|
||||
c.head = &head{}
|
||||
@@ -37,7 +38,7 @@ func TestService_HeadDomainFetcher_Errors(t *testing.T) {
|
||||
beaconDB := dbtest.SetupDB(t)
|
||||
c := &Service{
|
||||
cfg: &config{
|
||||
StateGen: stategen.New(beaconDB),
|
||||
StateGen: stategen.New(beaconDB, doublylinkedtree.New()),
|
||||
},
|
||||
}
|
||||
c.head = &head{}
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
mock "github.com/prysmaticlabs/prysm/v3/beacon-chain/blockchain/testing"
|
||||
testDB "github.com/prysmaticlabs/prysm/v3/beacon-chain/db/testing"
|
||||
doublylinkedtree "github.com/prysmaticlabs/prysm/v3/beacon-chain/forkchoice/doubly-linked-tree"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/forkchoice/protoarray"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/operations/blstoexec"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state/stategen"
|
||||
"github.com/prysmaticlabs/prysm/v3/config/features"
|
||||
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||
@@ -31,7 +31,7 @@ func TestSaveHead_Same(t *testing.T) {
|
||||
service := setupBeaconChain(t, beaconDB)
|
||||
|
||||
r := [32]byte{'A'}
|
||||
service.head = &head{slot: 0, root: r}
|
||||
service.head = &head{root: r}
|
||||
b, err := blocks.NewSignedBeaconBlock(util.NewBeaconBlock())
|
||||
require.NoError(t, err)
|
||||
st, _ := util.DeterministicGenesisState(t, 1)
|
||||
@@ -50,11 +50,10 @@ func TestSaveHead_Different(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
ojc := ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}
|
||||
ofc := ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}
|
||||
state, blkRoot, err := prepareForkchoiceState(ctx, oldBlock.Block().Slot(), oldRoot, bytesutil.ToBytes32(oldBlock.Block().ParentRoot()), [32]byte{}, ojc, ofc)
|
||||
state, blkRoot, err := prepareForkchoiceState(ctx, oldBlock.Block().Slot(), oldRoot, oldBlock.Block().ParentRoot(), [32]byte{}, ojc, ofc)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, service.cfg.ForkChoiceStore.InsertNode(ctx, state, blkRoot))
|
||||
service.head = &head{
|
||||
slot: 0,
|
||||
root: oldRoot,
|
||||
block: oldBlock,
|
||||
}
|
||||
@@ -66,11 +65,11 @@ func TestSaveHead_Different(t *testing.T) {
|
||||
wsb := util.SaveBlock(t, context.Background(), service.cfg.BeaconDB, newHeadSignedBlock)
|
||||
newRoot, err := newHeadBlock.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
state, blkRoot, err = prepareForkchoiceState(ctx, wsb.Block().Slot()-1, bytesutil.ToBytes32(wsb.Block().ParentRoot()), service.cfg.ForkChoiceStore.CachedHeadRoot(), [32]byte{}, ojc, ofc)
|
||||
state, blkRoot, err = prepareForkchoiceState(ctx, wsb.Block().Slot()-1, wsb.Block().ParentRoot(), service.cfg.ForkChoiceStore.CachedHeadRoot(), [32]byte{}, ojc, ofc)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, service.cfg.ForkChoiceStore.InsertNode(ctx, state, blkRoot))
|
||||
|
||||
state, blkRoot, err = prepareForkchoiceState(ctx, wsb.Block().Slot(), newRoot, bytesutil.ToBytes32(wsb.Block().ParentRoot()), [32]byte{}, ojc, ofc)
|
||||
state, blkRoot, err = prepareForkchoiceState(ctx, wsb.Block().Slot(), newRoot, wsb.Block().ParentRoot(), [32]byte{}, ojc, ofc)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, service.cfg.ForkChoiceStore.InsertNode(ctx, state, blkRoot))
|
||||
headState, err := util.NewBeaconState()
|
||||
@@ -90,7 +89,7 @@ func TestSaveHead_Different(t *testing.T) {
|
||||
pb, err := headBlock.Proto()
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, newHeadSignedBlock, pb, "Head did not change")
|
||||
assert.DeepSSZEqual(t, headState.CloneInnerState(), service.headState(ctx).CloneInnerState(), "Head did not change")
|
||||
assert.DeepSSZEqual(t, headState.ToProto(), service.headState(ctx).ToProto(), "Head did not change")
|
||||
}
|
||||
|
||||
func TestSaveHead_Different_Reorg(t *testing.T) {
|
||||
@@ -104,17 +103,16 @@ func TestSaveHead_Different_Reorg(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
ojc := ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}
|
||||
ofc := ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}
|
||||
state, blkRoot, err := prepareForkchoiceState(ctx, oldBlock.Block().Slot(), oldRoot, bytesutil.ToBytes32(oldBlock.Block().ParentRoot()), [32]byte{}, ojc, ofc)
|
||||
state, blkRoot, err := prepareForkchoiceState(ctx, oldBlock.Block().Slot(), oldRoot, oldBlock.Block().ParentRoot(), [32]byte{}, ojc, ofc)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, service.cfg.ForkChoiceStore.InsertNode(ctx, state, blkRoot))
|
||||
service.head = &head{
|
||||
slot: 0,
|
||||
root: oldRoot,
|
||||
block: oldBlock,
|
||||
}
|
||||
|
||||
reorgChainParent := [32]byte{'B'}
|
||||
state, blkRoot, err = prepareForkchoiceState(ctx, 0, reorgChainParent, oldRoot, bytesutil.ToBytes32(oldBlock.Block().ParentRoot()), ojc, ofc)
|
||||
state, blkRoot, err = prepareForkchoiceState(ctx, 0, reorgChainParent, oldRoot, oldBlock.Block().ParentRoot(), ojc, ofc)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, service.cfg.ForkChoiceStore.InsertNode(ctx, state, blkRoot))
|
||||
|
||||
@@ -126,7 +124,7 @@ func TestSaveHead_Different_Reorg(t *testing.T) {
|
||||
wsb := util.SaveBlock(t, context.Background(), service.cfg.BeaconDB, newHeadSignedBlock)
|
||||
newRoot, err := newHeadBlock.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
state, blkRoot, err = prepareForkchoiceState(ctx, wsb.Block().Slot(), newRoot, bytesutil.ToBytes32(wsb.Block().ParentRoot()), [32]byte{}, ojc, ofc)
|
||||
state, blkRoot, err = prepareForkchoiceState(ctx, wsb.Block().Slot(), newRoot, wsb.Block().ParentRoot(), [32]byte{}, ojc, ofc)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, service.cfg.ForkChoiceStore.InsertNode(ctx, state, blkRoot))
|
||||
headState, err := util.NewBeaconState()
|
||||
@@ -148,8 +146,10 @@ func TestSaveHead_Different_Reorg(t *testing.T) {
|
||||
pb, err := headBlock.Proto()
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, newHeadSignedBlock, pb, "Head did not change")
|
||||
assert.DeepSSZEqual(t, headState.CloneInnerState(), service.headState(ctx).CloneInnerState(), "Head did not change")
|
||||
assert.DeepSSZEqual(t, headState.ToProto(), service.headState(ctx).ToProto(), "Head did not change")
|
||||
require.LogsContain(t, hook, "Chain reorg occurred")
|
||||
require.LogsContain(t, hook, "distance=1")
|
||||
require.LogsContain(t, hook, "depth=1")
|
||||
}
|
||||
|
||||
func TestCacheJustifiedStateBalances_CanCache(t *testing.T) {
|
||||
@@ -232,64 +232,6 @@ func Test_notifyNewHeadEvent(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestSaveOrphanedAtts_NoCommonAncestor_Protoarray(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
beaconDB := testDB.SetupDB(t)
|
||||
service := setupBeaconChain(t, beaconDB)
|
||||
// this test does not make sense in doubly linked tree since it enforces
|
||||
// that the finalized node is a common ancestor
|
||||
service.cfg.ForkChoiceStore = protoarray.New()
|
||||
|
||||
service.genesisTime = time.Now().Add(time.Duration(-10*int64(1)*int64(params.BeaconConfig().SecondsPerSlot)) * time.Second)
|
||||
|
||||
// Chain setup
|
||||
// 0 -- 1 -- 2 -- 3
|
||||
// -4
|
||||
st, keys := util.DeterministicGenesisState(t, 64)
|
||||
blkG, err := util.GenerateFullBlock(st, keys, util.DefaultBlockGenConfig(), 0)
|
||||
assert.NoError(t, err)
|
||||
util.SaveBlock(t, ctx, service.cfg.BeaconDB, blkG)
|
||||
rG, err := blkG.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
blk1, err := util.GenerateFullBlock(st, keys, util.DefaultBlockGenConfig(), 1)
|
||||
assert.NoError(t, err)
|
||||
blk1.Block.ParentRoot = rG[:]
|
||||
r1, err := blk1.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
blk2, err := util.GenerateFullBlock(st, keys, util.DefaultBlockGenConfig(), 2)
|
||||
assert.NoError(t, err)
|
||||
blk2.Block.ParentRoot = r1[:]
|
||||
r2, err := blk2.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
blk3, err := util.GenerateFullBlock(st, keys, util.DefaultBlockGenConfig(), 3)
|
||||
assert.NoError(t, err)
|
||||
blk3.Block.ParentRoot = r2[:]
|
||||
r3, err := blk3.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
blk4 := util.NewBeaconBlock()
|
||||
blk4.Block.Slot = 4
|
||||
r4, err := blk4.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
for _, blk := range []*ethpb.SignedBeaconBlock{blkG, blk1, blk2, blk3, blk4} {
|
||||
r, err := blk.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
ojc := ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}
|
||||
ofc := ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}
|
||||
state, blkRoot, err := prepareForkchoiceState(ctx, blk.Block.Slot, r, bytesutil.ToBytes32(blk.Block.ParentRoot), [32]byte{}, ojc, ofc)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, service.ForkChoicer().InsertNode(ctx, state, blkRoot))
|
||||
util.SaveBlock(t, ctx, beaconDB, blk)
|
||||
}
|
||||
|
||||
require.NoError(t, service.saveOrphanedAtts(ctx, r3, r4))
|
||||
require.Equal(t, 0, service.cfg.AttPool.AggregatedAttestationCount())
|
||||
}
|
||||
|
||||
func TestSaveOrphanedAtts(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
beaconDB := testDB.SetupDB(t)
|
||||
@@ -342,7 +284,7 @@ func TestSaveOrphanedAtts(t *testing.T) {
|
||||
util.SaveBlock(t, ctx, beaconDB, blk)
|
||||
}
|
||||
|
||||
require.NoError(t, service.saveOrphanedAtts(ctx, r3, r4))
|
||||
require.NoError(t, service.saveOrphanedOperations(ctx, r3, r4))
|
||||
require.Equal(t, 3, service.cfg.AttPool.AggregatedAttestationCount())
|
||||
wantAtts := []*ethpb.Attestation{
|
||||
blk3.Block.Body.Attestations[0],
|
||||
@@ -360,31 +302,37 @@ func TestSaveOrphanedAtts_CanFilter(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
beaconDB := testDB.SetupDB(t)
|
||||
service := setupBeaconChain(t, beaconDB)
|
||||
service.cfg.BLSToExecPool = blstoexec.NewPool()
|
||||
service.genesisTime = time.Now().Add(time.Duration(-1*int64(params.BeaconConfig().SlotsPerEpoch+2)*int64(params.BeaconConfig().SecondsPerSlot)) * time.Second)
|
||||
|
||||
// Chain setup
|
||||
// 0 -- 1 -- 2
|
||||
// \-4
|
||||
st, keys := util.DeterministicGenesisState(t, 64)
|
||||
blkG, err := util.GenerateFullBlock(st, keys, util.DefaultBlockGenConfig(), 0)
|
||||
st, keys := util.DeterministicGenesisStateCapella(t, 64)
|
||||
blkConfig := util.DefaultBlockGenConfig()
|
||||
blkConfig.NumBLSChanges = 5
|
||||
blkG, err := util.GenerateFullBlockCapella(st, keys, blkConfig, 1)
|
||||
assert.NoError(t, err)
|
||||
util.SaveBlock(t, ctx, service.cfg.BeaconDB, blkG)
|
||||
rG, err := blkG.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
blk1, err := util.GenerateFullBlock(st, keys, util.DefaultBlockGenConfig(), 1)
|
||||
blkConfig.NumBLSChanges = 10
|
||||
blk1, err := util.GenerateFullBlockCapella(st, keys, blkConfig, 2)
|
||||
assert.NoError(t, err)
|
||||
blk1.Block.ParentRoot = rG[:]
|
||||
r1, err := blk1.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
blk2, err := util.GenerateFullBlock(st, keys, util.DefaultBlockGenConfig(), 2)
|
||||
blkConfig.NumBLSChanges = 15
|
||||
blk2, err := util.GenerateFullBlockCapella(st, keys, blkConfig, 3)
|
||||
assert.NoError(t, err)
|
||||
blk2.Block.ParentRoot = r1[:]
|
||||
r2, err := blk2.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
blk4 := util.NewBeaconBlock()
|
||||
blk4 := util.NewBeaconBlockCapella()
|
||||
blkConfig.NumBLSChanges = 0
|
||||
blk4.Block.Slot = 4
|
||||
blk4.Block.ParentRoot = rG[:]
|
||||
r4, err := blk4.Block.HashTreeRoot()
|
||||
@@ -392,7 +340,7 @@ func TestSaveOrphanedAtts_CanFilter(t *testing.T) {
|
||||
ojc := ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}
|
||||
ofc := ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}
|
||||
|
||||
for _, blk := range []*ethpb.SignedBeaconBlock{blkG, blk1, blk2, blk4} {
|
||||
for _, blk := range []*ethpb.SignedBeaconBlockCapella{blkG, blk1, blk2, blk4} {
|
||||
r, err := blk.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
state, blkRoot, err := prepareForkchoiceState(ctx, blk.Block.Slot, r, bytesutil.ToBytes32(blk.Block.ParentRoot), [32]byte{}, ojc, ofc)
|
||||
@@ -401,8 +349,11 @@ func TestSaveOrphanedAtts_CanFilter(t *testing.T) {
|
||||
util.SaveBlock(t, ctx, beaconDB, blk)
|
||||
}
|
||||
|
||||
require.NoError(t, service.saveOrphanedAtts(ctx, r2, r4))
|
||||
require.Equal(t, 0, service.cfg.AttPool.AggregatedAttestationCount())
|
||||
require.NoError(t, service.saveOrphanedOperations(ctx, r2, r4))
|
||||
require.Equal(t, 1, service.cfg.AttPool.AggregatedAttestationCount())
|
||||
pending, err := service.cfg.BLSToExecPool.PendingBLSToExecChanges()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 15, len(pending))
|
||||
}
|
||||
|
||||
func TestSaveOrphanedAtts_DoublyLinkedTrie(t *testing.T) {
|
||||
@@ -461,7 +412,7 @@ func TestSaveOrphanedAtts_DoublyLinkedTrie(t *testing.T) {
|
||||
util.SaveBlock(t, ctx, beaconDB, blk)
|
||||
}
|
||||
|
||||
require.NoError(t, service.saveOrphanedAtts(ctx, r3, r4))
|
||||
require.NoError(t, service.saveOrphanedOperations(ctx, r3, r4))
|
||||
require.Equal(t, 3, service.cfg.AttPool.AggregatedAttestationCount())
|
||||
wantAtts := []*ethpb.Attestation{
|
||||
blk3.Block.Body.Attestations[0],
|
||||
@@ -525,7 +476,7 @@ func TestSaveOrphanedAtts_CanFilter_DoublyLinkedTrie(t *testing.T) {
|
||||
util.SaveBlock(t, ctx, beaconDB, blk)
|
||||
}
|
||||
|
||||
require.NoError(t, service.saveOrphanedAtts(ctx, r2, r4))
|
||||
require.NoError(t, service.saveOrphanedOperations(ctx, r2, r4))
|
||||
require.Equal(t, 0, service.cfg.AttPool.AggregatedAttestationCount())
|
||||
}
|
||||
|
||||
@@ -536,7 +487,7 @@ func TestUpdateHead_noSavedChanges(t *testing.T) {
|
||||
fcs := doublylinkedtree.New()
|
||||
opts := []Option{
|
||||
WithDatabase(beaconDB),
|
||||
WithStateGen(stategen.New(beaconDB)),
|
||||
WithStateGen(stategen.New(beaconDB, fcs)),
|
||||
WithForkChoiceStore(fcs),
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||
consensusBlocks "github.com/prysmaticlabs/prysm/v3/consensus-types/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces"
|
||||
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||
@@ -37,24 +38,29 @@ func logStateTransitionData(b interfaces.BeaconBlock) error {
|
||||
if len(b.Body().VoluntaryExits()) > 0 {
|
||||
log = log.WithField("voluntaryExits", len(b.Body().VoluntaryExits()))
|
||||
}
|
||||
if b.Version() == version.Altair || b.Version() == version.Bellatrix {
|
||||
if b.Version() >= version.Altair {
|
||||
agg, err := b.Body().SyncAggregate()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log = log.WithField("syncBitsCount", agg.SyncCommitteeBits.Count())
|
||||
}
|
||||
if b.Version() == version.Bellatrix {
|
||||
if b.Version() >= version.Bellatrix {
|
||||
p, err := b.Body().Execution()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log = log.WithField("payloadHash", fmt.Sprintf("%#x", bytesutil.Trunc(p.BlockHash())))
|
||||
txs, err := p.Transactions()
|
||||
if err != nil {
|
||||
switch {
|
||||
case errors.Is(err, consensusBlocks.ErrUnsupportedGetter):
|
||||
case err != nil:
|
||||
return err
|
||||
default:
|
||||
log = log.WithField("txCount", len(txs))
|
||||
txsPerSlotCount.Set(float64(len(txs)))
|
||||
}
|
||||
log = log.WithField("txCount", len(txs))
|
||||
|
||||
}
|
||||
log.Info("Finished applying state transition")
|
||||
return nil
|
||||
@@ -67,6 +73,7 @@ func logBlockSyncStatus(block interfaces.BeaconBlock, blockRoot [32]byte, justif
|
||||
}
|
||||
level := log.Logger.GetLevel()
|
||||
if level >= logrus.DebugLevel {
|
||||
parentRoot := block.ParentRoot()
|
||||
log.WithFields(logrus.Fields{
|
||||
"slot": block.Slot(),
|
||||
"slotInEpoch": block.Slot() % params.BeaconConfig().SlotsPerEpoch,
|
||||
@@ -76,10 +83,11 @@ func logBlockSyncStatus(block interfaces.BeaconBlock, blockRoot [32]byte, justif
|
||||
"justifiedRoot": fmt.Sprintf("0x%s...", hex.EncodeToString(justified.Root)[:8]),
|
||||
"finalizedEpoch": finalized.Epoch,
|
||||
"finalizedRoot": fmt.Sprintf("0x%s...", hex.EncodeToString(finalized.Root)[:8]),
|
||||
"parentRoot": fmt.Sprintf("0x%s...", hex.EncodeToString(block.ParentRoot())[:8]),
|
||||
"parentRoot": fmt.Sprintf("0x%s...", hex.EncodeToString(parentRoot[:])[:8]),
|
||||
"version": version.String(block.Version()),
|
||||
"sinceSlotStartTime": prysmTime.Now().Sub(startTime),
|
||||
"chainServiceProcessedTime": prysmTime.Now().Sub(receivedTime),
|
||||
"deposits": len(block.Body().Deposits()),
|
||||
}).Debug("Synced new block")
|
||||
} else {
|
||||
log.WithFields(logrus.Fields{
|
||||
@@ -110,12 +118,24 @@ func logPayload(block interfaces.BeaconBlock) error {
|
||||
return errors.New("gas limit should not be 0")
|
||||
}
|
||||
gasUtilized := float64(payload.GasUsed()) / float64(payload.GasLimit())
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
fields := logrus.Fields{
|
||||
"blockHash": fmt.Sprintf("%#x", bytesutil.Trunc(payload.BlockHash())),
|
||||
"parentHash": fmt.Sprintf("%#x", bytesutil.Trunc(payload.ParentHash())),
|
||||
"blockNumber": payload.BlockNumber,
|
||||
"gasUtilized": fmt.Sprintf("%.2f", gasUtilized),
|
||||
}).Debug("Synced new payload")
|
||||
}
|
||||
if block.Version() >= version.Capella {
|
||||
withdrawals, err := payload.Withdrawals()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get withdrawals")
|
||||
}
|
||||
fields["withdrawals"] = len(withdrawals)
|
||||
changes, err := block.Body().BLSToExecutionChanges()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get BLSToExecutionChanges")
|
||||
}
|
||||
fields["blsToExecutionChanges"] = len(changes)
|
||||
}
|
||||
log.WithFields(fields).Debug("Synced new payload")
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -158,10 +158,61 @@ var (
|
||||
Name: "forkchoice_updated_optimistic_node_count",
|
||||
Help: "Count the number of optimistic nodes after forkchoiceUpdated EE call",
|
||||
})
|
||||
forkchoiceUpdatedInvalidNodeCount = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "forkchoice_updated_invalid_node_count",
|
||||
Help: "Count the number of invalid nodes after forkchoiceUpdated EE call",
|
||||
})
|
||||
txsPerSlotCount = promauto.NewGauge(prometheus.GaugeOpts{
|
||||
Name: "txs_per_slot_count",
|
||||
Help: "Count the number of txs per slot",
|
||||
})
|
||||
missedPayloadIDFilledCount = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "missed_payload_id_filled_count",
|
||||
Help: "",
|
||||
})
|
||||
onBlockProcessingTime = promauto.NewSummary(prometheus.SummaryOpts{
|
||||
Name: "on_block_processing_milliseconds",
|
||||
Help: "Total time in milliseconds to complete a call to onBlock()",
|
||||
})
|
||||
stateTransitionProcessingTime = promauto.NewSummary(prometheus.SummaryOpts{
|
||||
Name: "state_transition_processing_milliseconds",
|
||||
Help: "Total time to call a state transition in onBlock()",
|
||||
})
|
||||
processAttsElapsedTime = promauto.NewHistogram(
|
||||
prometheus.HistogramOpts{
|
||||
Name: "process_attestations_milliseconds",
|
||||
Help: "Captures latency for process attestations (forkchoice) in milliseconds",
|
||||
Buckets: []float64{1, 5, 20, 100, 500, 1000},
|
||||
},
|
||||
)
|
||||
newAttHeadElapsedTime = promauto.NewHistogram(
|
||||
prometheus.HistogramOpts{
|
||||
Name: "new_att_head_milliseconds",
|
||||
Help: "Captures latency for new attestation head in milliseconds",
|
||||
Buckets: []float64{1, 5, 20, 100, 500, 1000},
|
||||
},
|
||||
)
|
||||
newBlockHeadElapsedTime = promauto.NewHistogram(
|
||||
prometheus.HistogramOpts{
|
||||
Name: "new_block_head_milliseconds",
|
||||
Help: "Captures latency for new block head in milliseconds",
|
||||
Buckets: []float64{1, 5, 20, 100, 500, 1000},
|
||||
},
|
||||
)
|
||||
reorgDistance = promauto.NewHistogram(
|
||||
prometheus.HistogramOpts{
|
||||
Name: "reorg_distance",
|
||||
Help: "Captures distance of reorgs. Distance is defined as the number of blocks between the old head and the new head",
|
||||
Buckets: []float64{1, 2, 4, 8, 16, 32, 64},
|
||||
},
|
||||
)
|
||||
reorgDepth = promauto.NewHistogram(
|
||||
prometheus.HistogramOpts{
|
||||
Name: "reorg_depth",
|
||||
Help: "Captures depth of reorgs. Depth is defined as the number of blocks between the head and the common ancestor",
|
||||
Buckets: []float64{1, 2, 4, 8, 16, 32},
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
// reportSlotMetrics reports slot related metrics.
|
||||
@@ -266,9 +317,8 @@ func reportEpochMetrics(ctx context.Context, postState, headState state.BeaconSt
|
||||
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.
|
||||
|
||||
if headState.Version() == version.Phase0 {
|
||||
v, b, err = precompute.New(ctx, headState)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -277,7 +327,7 @@ func reportEpochMetrics(ctx context.Context, postState, headState state.BeaconSt
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case version.Altair, version.Bellatrix:
|
||||
} else if headState.Version() >= version.Altair {
|
||||
v, b, err = altair.InitializePrecomputeValidators(ctx, headState)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -286,9 +336,10 @@ func reportEpochMetrics(ctx context.Context, postState, headState state.BeaconSt
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
return errors.Errorf("invalid state type provided: %T", headState.InnerStateUnsafe())
|
||||
} else {
|
||||
return errors.Errorf("invalid state type provided: %T", headState.ToProtoUnsafe())
|
||||
}
|
||||
|
||||
prevEpochActiveBalances.Set(float64(b.ActivePrevEpoch))
|
||||
prevEpochSourceBalances.Set(float64(b.PrevEpochAttested))
|
||||
prevEpochTargetBalances.Set(float64(b.PrevEpochTargetAttested))
|
||||
|
||||
@@ -6,17 +6,17 @@ import (
|
||||
"testing"
|
||||
|
||||
testDB "github.com/prysmaticlabs/prysm/v3/beacon-chain/db/testing"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/forkchoice/protoarray"
|
||||
doublylinkedtree "github.com/prysmaticlabs/prysm/v3/beacon-chain/forkchoice/doubly-linked-tree"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state/stategen"
|
||||
)
|
||||
|
||||
func testServiceOptsWithDB(t *testing.T) []Option {
|
||||
beaconDB := testDB.SetupDB(t)
|
||||
fcs := protoarray.New()
|
||||
fcs := doublylinkedtree.New()
|
||||
return []Option{
|
||||
WithDatabase(beaconDB),
|
||||
WithStateGen(stategen.New(beaconDB)),
|
||||
WithStateGen(stategen.New(beaconDB, fcs)),
|
||||
WithForkChoiceStore(fcs),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/execution"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/forkchoice"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/operations/attestations"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/operations/blstoexec"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/operations/slashings"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/operations/voluntaryexits"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/p2p"
|
||||
@@ -99,6 +100,14 @@ func WithSlashingPool(p slashings.PoolManager) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// WithBLSToExecPool to keep track of BLS to Execution address changes.
|
||||
func WithBLSToExecPool(p blstoexec.PoolManager) Option {
|
||||
return func(s *Service) error {
|
||||
s.cfg.BLSToExecPool = p
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithP2PBroadcaster to broadcast messages after appropriate processing.
|
||||
func WithP2PBroadcaster(p p2p.Broadcaster) Option {
|
||||
return func(s *Service) error {
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces"
|
||||
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/v3/runtime/version"
|
||||
"github.com/prysmaticlabs/prysm/v3/time/slots"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
@@ -22,20 +23,21 @@ import (
|
||||
// validateMergeBlock validates terminal block hash in the event of manual overrides before checking for total difficulty.
|
||||
//
|
||||
// def validate_merge_block(block: BeaconBlock) -> None:
|
||||
// if TERMINAL_BLOCK_HASH != Hash32():
|
||||
// # If `TERMINAL_BLOCK_HASH` is used as an override, the activation epoch must be reached.
|
||||
// assert compute_epoch_at_slot(block.slot) >= TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH
|
||||
// assert block.body.execution_payload.parent_hash == TERMINAL_BLOCK_HASH
|
||||
// return
|
||||
//
|
||||
// pow_block = get_pow_block(block.body.execution_payload.parent_hash)
|
||||
// # Check if `pow_block` is available
|
||||
// assert pow_block is not None
|
||||
// pow_parent = get_pow_block(pow_block.parent_hash)
|
||||
// # Check if `pow_parent` is available
|
||||
// assert pow_parent is not None
|
||||
// # Check if `pow_block` is a valid terminal PoW block
|
||||
// assert is_valid_terminal_pow_block(pow_block, pow_parent)
|
||||
// if TERMINAL_BLOCK_HASH != Hash32():
|
||||
// # If `TERMINAL_BLOCK_HASH` is used as an override, the activation epoch must be reached.
|
||||
// assert compute_epoch_at_slot(block.slot) >= TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH
|
||||
// assert block.body.execution_payload.parent_hash == TERMINAL_BLOCK_HASH
|
||||
// return
|
||||
//
|
||||
// pow_block = get_pow_block(block.body.execution_payload.parent_hash)
|
||||
// # Check if `pow_block` is available
|
||||
// assert pow_block is not None
|
||||
// pow_parent = get_pow_block(pow_block.parent_hash)
|
||||
// # Check if `pow_parent` is available
|
||||
// assert pow_parent is not None
|
||||
// # Check if `pow_block` is a valid terminal PoW block
|
||||
// assert is_valid_terminal_pow_block(pow_block, pow_parent)
|
||||
func (s *Service) validateMergeBlock(ctx context.Context, b interfaces.SignedBeaconBlock) error {
|
||||
if err := blocks.BeaconBlockIsNil(b); err != nil {
|
||||
return err
|
||||
@@ -91,6 +93,7 @@ func (s *Service) getBlkParentHashAndTD(ctx context.Context, blkHash []byte) ([]
|
||||
if blk == nil {
|
||||
return nil, nil, errors.New("pow block is nil")
|
||||
}
|
||||
blk.Version = version.Bellatrix
|
||||
blkTDBig, err := hexutil.DecodeBig(blk.TotalDifficulty)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "could not decode merge block total difficulty")
|
||||
@@ -105,10 +108,11 @@ func (s *Service) getBlkParentHashAndTD(ctx context.Context, blkHash []byte) ([]
|
||||
// validateTerminalBlockHash validates if the merge block is a valid terminal PoW block.
|
||||
// spec code:
|
||||
// if TERMINAL_BLOCK_HASH != Hash32():
|
||||
// # If `TERMINAL_BLOCK_HASH` is used as an override, the activation epoch must be reached.
|
||||
// assert compute_epoch_at_slot(block.slot) >= TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH
|
||||
// assert block.body.execution_payload.parent_hash == TERMINAL_BLOCK_HASH
|
||||
// return
|
||||
//
|
||||
// # If `TERMINAL_BLOCK_HASH` is used as an override, the activation epoch must be reached.
|
||||
// assert compute_epoch_at_slot(block.slot) >= TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH
|
||||
// assert block.body.execution_payload.parent_hash == TERMINAL_BLOCK_HASH
|
||||
// return
|
||||
func validateTerminalBlockHash(blkSlot types.Slot, payload interfaces.ExecutionData) error {
|
||||
if bytesutil.ToBytes32(params.BeaconConfig().TerminalBlockHash.Bytes()) == [32]byte{} {
|
||||
return nil
|
||||
@@ -125,9 +129,10 @@ func validateTerminalBlockHash(blkSlot types.Slot, payload interfaces.ExecutionD
|
||||
// validateTerminalBlockDifficulties validates terminal pow block by comparing own total difficulty with parent's total difficulty.
|
||||
//
|
||||
// def is_valid_terminal_pow_block(block: PowBlock, parent: PowBlock) -> bool:
|
||||
// is_total_difficulty_reached = block.total_difficulty >= TERMINAL_TOTAL_DIFFICULTY
|
||||
// is_parent_total_difficulty_valid = parent.total_difficulty < TERMINAL_TOTAL_DIFFICULTY
|
||||
// return is_total_difficulty_reached and is_parent_total_difficulty_valid
|
||||
//
|
||||
// is_total_difficulty_reached = block.total_difficulty >= TERMINAL_TOTAL_DIFFICULTY
|
||||
// is_parent_total_difficulty_valid = parent.total_difficulty < TERMINAL_TOTAL_DIFFICULTY
|
||||
// return is_total_difficulty_reached and is_parent_total_difficulty_valid
|
||||
func validateTerminalBlockDifficulties(currentDifficulty *uint256.Int, parentDifficulty *uint256.Int) (bool, error) {
|
||||
b, ok := new(big.Int).SetString(params.BeaconConfig().TerminalTotalDifficulty, 10)
|
||||
if !ok {
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"github.com/holiman/uint256"
|
||||
testDB "github.com/prysmaticlabs/prysm/v3/beacon-chain/db/testing"
|
||||
mocks "github.com/prysmaticlabs/prysm/v3/beacon-chain/execution/testing"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/forkchoice/protoarray"
|
||||
doublylinkedtree "github.com/prysmaticlabs/prysm/v3/beacon-chain/forkchoice/doubly-linked-tree"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state/stategen"
|
||||
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||
"github.com/prysmaticlabs/prysm/v3/consensus-types/blocks"
|
||||
@@ -109,10 +109,10 @@ func Test_validateMergeBlock(t *testing.T) {
|
||||
|
||||
ctx := context.Background()
|
||||
beaconDB := testDB.SetupDB(t)
|
||||
fcs := protoarray.New()
|
||||
fcs := doublylinkedtree.New()
|
||||
opts := []Option{
|
||||
WithDatabase(beaconDB),
|
||||
WithStateGen(stategen.New(beaconDB)),
|
||||
WithStateGen(stategen.New(beaconDB, fcs)),
|
||||
WithForkChoiceStore(fcs),
|
||||
}
|
||||
service, err := NewService(ctx, opts...)
|
||||
@@ -159,10 +159,10 @@ func Test_validateMergeBlock(t *testing.T) {
|
||||
func Test_getBlkParentHashAndTD(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
beaconDB := testDB.SetupDB(t)
|
||||
fcs := protoarray.New()
|
||||
fcs := doublylinkedtree.New()
|
||||
opts := []Option{
|
||||
WithDatabase(beaconDB),
|
||||
WithStateGen(stategen.New(beaconDB)),
|
||||
WithStateGen(stategen.New(beaconDB, fcs)),
|
||||
WithForkChoiceStore(fcs),
|
||||
}
|
||||
service, err := NewService(ctx, opts...)
|
||||
|
||||
@@ -19,23 +19,24 @@ import (
|
||||
// The delay is handled by the caller in `processAttestations`.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// def on_attestation(store: Store, attestation: Attestation) -> None:
|
||||
// """
|
||||
// Run ``on_attestation`` upon receiving a new ``attestation`` from either within a block or directly on the wire.
|
||||
//
|
||||
// An ``attestation`` that is asserted as invalid may be valid at a later time,
|
||||
// consider scheduling it for later processing in such case.
|
||||
// """
|
||||
// validate_on_attestation(store, attestation)
|
||||
// store_target_checkpoint_state(store, attestation.data.target)
|
||||
// def on_attestation(store: Store, attestation: Attestation) -> None:
|
||||
// """
|
||||
// Run ``on_attestation`` upon receiving a new ``attestation`` from either within a block or directly on the wire.
|
||||
//
|
||||
// # Get state at the `target` to fully validate attestation
|
||||
// target_state = store.checkpoint_states[attestation.data.target]
|
||||
// indexed_attestation = get_indexed_attestation(target_state, attestation)
|
||||
// assert is_valid_indexed_attestation(target_state, indexed_attestation)
|
||||
// An ``attestation`` that is asserted as invalid may be valid at a later time,
|
||||
// consider scheduling it for later processing in such case.
|
||||
// """
|
||||
// validate_on_attestation(store, attestation)
|
||||
// store_target_checkpoint_state(store, attestation.data.target)
|
||||
//
|
||||
// # Update latest messages for attesting indices
|
||||
// update_latest_messages(store, indexed_attestation.attesting_indices, attestation)
|
||||
// # Get state at the `target` to fully validate attestation
|
||||
// target_state = store.checkpoint_states[attestation.data.target]
|
||||
// indexed_attestation = get_indexed_attestation(target_state, attestation)
|
||||
// assert is_valid_indexed_attestation(target_state, indexed_attestation)
|
||||
//
|
||||
// # Update latest messages for attesting indices
|
||||
// update_latest_messages(store, indexed_attestation.attesting_indices, attestation)
|
||||
func (s *Service) OnAttestation(ctx context.Context, a *ethpb.Attestation) error {
|
||||
ctx, span := trace.StartSpan(ctx, "blockChain.onAttestation")
|
||||
defer span.End()
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/transition"
|
||||
testDB "github.com/prysmaticlabs/prysm/v3/beacon-chain/db/testing"
|
||||
doublylinkedtree "github.com/prysmaticlabs/prysm/v3/beacon-chain/forkchoice/doubly-linked-tree"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/forkchoice/protoarray"
|
||||
forkchoicetypes "github.com/prysmaticlabs/prysm/v3/beacon-chain/forkchoice/types"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state/stategen"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/v3/config/fieldparams"
|
||||
@@ -22,14 +21,15 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v3/time/slots"
|
||||
)
|
||||
|
||||
func TestStore_OnAttestation_ErrorConditions_ProtoArray(t *testing.T) {
|
||||
func TestStore_OnAttestation_ErrorConditions(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
beaconDB := testDB.SetupDB(t)
|
||||
|
||||
fc := doublylinkedtree.New()
|
||||
opts := []Option{
|
||||
WithDatabase(beaconDB),
|
||||
WithForkChoiceStore(doublylinkedtree.New()),
|
||||
WithStateGen(stategen.New(beaconDB)),
|
||||
WithForkChoiceStore(fc),
|
||||
WithStateGen(stategen.New(beaconDB, fc)),
|
||||
}
|
||||
service, err := NewService(ctx, opts...)
|
||||
require.NoError(t, err)
|
||||
@@ -128,142 +128,6 @@ func TestStore_OnAttestation_ErrorConditions_ProtoArray(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestStore_OnAttestation_ErrorConditions_DoublyLinkedTree(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
beaconDB := testDB.SetupDB(t)
|
||||
|
||||
opts := []Option{
|
||||
WithDatabase(beaconDB),
|
||||
WithForkChoiceStore(doublylinkedtree.New()),
|
||||
WithStateGen(stategen.New(beaconDB)),
|
||||
}
|
||||
service, err := NewService(ctx, opts...)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = blockTree1(t, beaconDB, []byte{'g'})
|
||||
require.NoError(t, err)
|
||||
|
||||
blkWithoutState := util.NewBeaconBlock()
|
||||
blkWithoutState.Block.Slot = 0
|
||||
util.SaveBlock(t, ctx, beaconDB, blkWithoutState)
|
||||
BlkWithOutStateRoot, err := blkWithoutState.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
blkWithStateBadAtt := util.NewBeaconBlock()
|
||||
blkWithStateBadAtt.Block.Slot = 1
|
||||
util.SaveBlock(t, ctx, beaconDB, blkWithStateBadAtt)
|
||||
BlkWithStateBadAttRoot, err := blkWithStateBadAtt.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
s, err := util.NewBeaconState()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, s.SetSlot(100*params.BeaconConfig().SlotsPerEpoch))
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveState(ctx, s, BlkWithStateBadAttRoot))
|
||||
|
||||
blkWithValidState := util.NewBeaconBlock()
|
||||
blkWithValidState.Block.Slot = 2
|
||||
util.SaveBlock(t, ctx, beaconDB, blkWithValidState)
|
||||
|
||||
blkWithValidStateRoot, err := blkWithValidState.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
s, err = util.NewBeaconState()
|
||||
require.NoError(t, err)
|
||||
err = s.SetFork(ðpb.Fork{
|
||||
Epoch: 0,
|
||||
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveState(ctx, s, blkWithValidStateRoot))
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
a *ethpb.Attestation
|
||||
wantedErr string
|
||||
}{
|
||||
{
|
||||
name: "attestation's data slot not aligned with target vote",
|
||||
a: util.HydrateAttestation(ðpb.Attestation{Data: ðpb.AttestationData{Slot: params.BeaconConfig().SlotsPerEpoch, Target: ðpb.Checkpoint{Root: make([]byte, 32)}}}),
|
||||
wantedErr: "slot 32 does not match target epoch 0",
|
||||
},
|
||||
{
|
||||
name: "no pre state for attestations's target block",
|
||||
a: util.HydrateAttestation(ðpb.Attestation{Data: ðpb.AttestationData{Target: ðpb.Checkpoint{Root: BlkWithOutStateRoot[:]}}}),
|
||||
wantedErr: "could not get pre state for epoch 0",
|
||||
},
|
||||
{
|
||||
name: "process attestation doesn't match current epoch",
|
||||
a: util.HydrateAttestation(ðpb.Attestation{Data: ðpb.AttestationData{Slot: 100 * params.BeaconConfig().SlotsPerEpoch, Target: ðpb.Checkpoint{Epoch: 100,
|
||||
Root: BlkWithStateBadAttRoot[:]}}}),
|
||||
wantedErr: "target epoch 100 does not match current epoch",
|
||||
},
|
||||
{
|
||||
name: "process nil attestation",
|
||||
a: nil,
|
||||
wantedErr: "attestation can't be nil",
|
||||
},
|
||||
{
|
||||
name: "process nil field (a.Data) in attestation",
|
||||
a: ðpb.Attestation{},
|
||||
wantedErr: "attestation's data can't be nil",
|
||||
},
|
||||
{
|
||||
name: "process nil field (a.Target) in attestation",
|
||||
a: ðpb.Attestation{
|
||||
Data: ðpb.AttestationData{
|
||||
BeaconBlockRoot: make([]byte, fieldparams.RootLength),
|
||||
Target: nil,
|
||||
Source: ðpb.Checkpoint{Root: make([]byte, fieldparams.RootLength)},
|
||||
},
|
||||
AggregationBits: make([]byte, 1),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
wantedErr: "attestation's target can't be nil",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := service.OnAttestation(ctx, tt.a)
|
||||
if tt.wantedErr != "" {
|
||||
assert.ErrorContains(t, tt.wantedErr, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestStore_OnAttestation_Ok_ProtoArray(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
beaconDB := testDB.SetupDB(t)
|
||||
|
||||
fcs := protoarray.New()
|
||||
opts := []Option{
|
||||
WithDatabase(beaconDB),
|
||||
WithStateGen(stategen.New(beaconDB)),
|
||||
WithForkChoiceStore(fcs),
|
||||
}
|
||||
service, err := NewService(ctx, opts...)
|
||||
require.NoError(t, err)
|
||||
genesisState, pks := util.DeterministicGenesisState(t, 64)
|
||||
service.SetGenesisTime(time.Unix(time.Now().Unix()-int64(params.BeaconConfig().SecondsPerSlot), 0))
|
||||
require.NoError(t, service.saveGenesisData(ctx, genesisState))
|
||||
att, err := util.GenerateAttestations(genesisState, pks, 1, 0, false)
|
||||
require.NoError(t, err)
|
||||
tRoot := bytesutil.ToBytes32(att[0].Data.Target.Root)
|
||||
copied := genesisState.Copy()
|
||||
copied, err = transition.ProcessSlots(ctx, copied, 1)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveState(ctx, copied, tRoot))
|
||||
ojc := ðpb.Checkpoint{Epoch: 1, Root: tRoot[:]}
|
||||
ofc := ðpb.Checkpoint{Epoch: 1, Root: tRoot[:]}
|
||||
state, blkRoot, err := prepareForkchoiceState(ctx, 0, tRoot, tRoot, params.BeaconConfig().ZeroHash, ojc, ofc)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, service.cfg.ForkChoiceStore.InsertNode(ctx, state, blkRoot))
|
||||
require.NoError(t, service.OnAttestation(ctx, att[0]))
|
||||
}
|
||||
|
||||
func TestStore_OnAttestation_Ok_DoublyLinkedTree(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
beaconDB := testDB.SetupDB(t)
|
||||
@@ -271,7 +135,7 @@ func TestStore_OnAttestation_Ok_DoublyLinkedTree(t *testing.T) {
|
||||
fcs := doublylinkedtree.New()
|
||||
opts := []Option{
|
||||
WithDatabase(beaconDB),
|
||||
WithStateGen(stategen.New(beaconDB)),
|
||||
WithStateGen(stategen.New(beaconDB, fcs)),
|
||||
WithForkChoiceStore(fcs),
|
||||
}
|
||||
service, err := NewService(ctx, opts...)
|
||||
@@ -300,7 +164,7 @@ func TestStore_SaveCheckpointState(t *testing.T) {
|
||||
|
||||
opts := []Option{
|
||||
WithDatabase(beaconDB),
|
||||
WithStateGen(stategen.New(beaconDB)),
|
||||
WithStateGen(stategen.New(beaconDB, doublylinkedtree.New())),
|
||||
}
|
||||
service, err := NewService(ctx, opts...)
|
||||
require.NoError(t, err)
|
||||
@@ -362,7 +226,7 @@ func TestStore_UpdateCheckpointState(t *testing.T) {
|
||||
|
||||
opts := []Option{
|
||||
WithDatabase(beaconDB),
|
||||
WithStateGen(stategen.New(beaconDB)),
|
||||
WithStateGen(stategen.New(beaconDB, doublylinkedtree.New())),
|
||||
}
|
||||
service, err := NewService(ctx, opts...)
|
||||
require.NoError(t, err)
|
||||
@@ -392,7 +256,7 @@ func TestStore_UpdateCheckpointState(t *testing.T) {
|
||||
|
||||
cached, err = service.checkpointStateCache.StateByCheckpoint(newCheckpoint)
|
||||
require.NoError(t, err)
|
||||
require.DeepSSZEqual(t, returned.InnerStateUnsafe(), cached.InnerStateUnsafe())
|
||||
require.DeepSSZEqual(t, returned.ToProtoUnsafe(), cached.ToProtoUnsafe())
|
||||
}
|
||||
|
||||
func TestAttEpoch_MatchPrevEpoch(t *testing.T) {
|
||||
@@ -461,37 +325,6 @@ func TestVerifyBeaconBlock_OK(t *testing.T) {
|
||||
assert.NoError(t, service.verifyBeaconBlock(ctx, d), "Did not receive the wanted error")
|
||||
}
|
||||
|
||||
func TestVerifyFinalizedConsistency_InconsistentRoot_ProtoArray(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
beaconDB := testDB.SetupDB(t)
|
||||
|
||||
fcs := protoarray.New()
|
||||
opts := []Option{
|
||||
WithDatabase(beaconDB),
|
||||
WithStateGen(stategen.New(beaconDB)),
|
||||
WithForkChoiceStore(fcs),
|
||||
}
|
||||
service, err := NewService(ctx, opts...)
|
||||
require.NoError(t, err)
|
||||
|
||||
b32 := util.NewBeaconBlock()
|
||||
b32.Block.Slot = 32
|
||||
util.SaveBlock(t, ctx, service.cfg.BeaconDB, b32)
|
||||
r32, err := b32.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NoError(t, service.ForkChoicer().UpdateFinalizedCheckpoint(&forkchoicetypes.Checkpoint{Epoch: 1}))
|
||||
b33 := util.NewBeaconBlock()
|
||||
b33.Block.Slot = 33
|
||||
b33.Block.ParentRoot = r32[:]
|
||||
util.SaveBlock(t, ctx, service.cfg.BeaconDB, b33)
|
||||
r33, err := b33.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
err = service.VerifyFinalizedConsistency(context.Background(), r33[:])
|
||||
require.ErrorContains(t, "Root and finalized store are not consistent", err)
|
||||
}
|
||||
|
||||
func TestVerifyFinalizedConsistency_InconsistentRoot_DoublyLinkedTree(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
beaconDB := testDB.SetupDB(t)
|
||||
@@ -499,7 +332,7 @@ func TestVerifyFinalizedConsistency_InconsistentRoot_DoublyLinkedTree(t *testing
|
||||
fcs := doublylinkedtree.New()
|
||||
opts := []Option{
|
||||
WithDatabase(beaconDB),
|
||||
WithStateGen(stategen.New(beaconDB)),
|
||||
WithStateGen(stategen.New(beaconDB, fcs)),
|
||||
WithForkChoiceStore(fcs),
|
||||
}
|
||||
service, err := NewService(ctx, opts...)
|
||||
|
||||
@@ -23,7 +23,6 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v3/crypto/bls"
|
||||
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/v3/monitoring/tracing"
|
||||
enginev1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
|
||||
ethpbv1 "github.com/prysmaticlabs/prysm/v3/proto/eth/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1/attestation"
|
||||
@@ -46,58 +45,60 @@ var initialSyncBlockCacheSize = uint64(2 * params.BeaconConfig().SlotsPerEpoch)
|
||||
// computation in this method and methods it calls into.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// def on_block(store: Store, signed_block: SignedBeaconBlock) -> None:
|
||||
// block = signed_block.message
|
||||
// # Parent block must be known
|
||||
// assert block.parent_root in store.block_states
|
||||
// # Make a copy of the state to avoid mutability issues
|
||||
// pre_state = copy(store.block_states[block.parent_root])
|
||||
// # Blocks cannot be in the future. If they are, their consideration must be delayed until the are in the past.
|
||||
// assert get_current_slot(store) >= block.slot
|
||||
//
|
||||
// # Check that block is later than the finalized epoch slot (optimization to reduce calls to get_ancestor)
|
||||
// finalized_slot = compute_start_slot_at_epoch(store.finalized_checkpoint.epoch)
|
||||
// assert block.slot > finalized_slot
|
||||
// # Check block is a descendant of the finalized block at the checkpoint finalized slot
|
||||
// assert get_ancestor(store, block.parent_root, finalized_slot) == store.finalized_checkpoint.root
|
||||
// def on_block(store: Store, signed_block: SignedBeaconBlock) -> None:
|
||||
// block = signed_block.message
|
||||
// # Parent block must be known
|
||||
// assert block.parent_root in store.block_states
|
||||
// # Make a copy of the state to avoid mutability issues
|
||||
// pre_state = copy(store.block_states[block.parent_root])
|
||||
// # Blocks cannot be in the future. If they are, their consideration must be delayed until the are in the past.
|
||||
// assert get_current_slot(store) >= block.slot
|
||||
//
|
||||
// # Check the block is valid and compute the post-state
|
||||
// state = pre_state.copy()
|
||||
// state_transition(state, signed_block, True)
|
||||
// # Add new block to the store
|
||||
// store.blocks[hash_tree_root(block)] = block
|
||||
// # Add new state for this block to the store
|
||||
// store.block_states[hash_tree_root(block)] = state
|
||||
// # Check that block is later than the finalized epoch slot (optimization to reduce calls to get_ancestor)
|
||||
// finalized_slot = compute_start_slot_at_epoch(store.finalized_checkpoint.epoch)
|
||||
// assert block.slot > finalized_slot
|
||||
// # Check block is a descendant of the finalized block at the checkpoint finalized slot
|
||||
// assert get_ancestor(store, block.parent_root, finalized_slot) == store.finalized_checkpoint.root
|
||||
//
|
||||
// # Update justified checkpoint
|
||||
// if state.current_justified_checkpoint.epoch > store.justified_checkpoint.epoch:
|
||||
// if state.current_justified_checkpoint.epoch > store.best_justified_checkpoint.epoch:
|
||||
// store.best_justified_checkpoint = state.current_justified_checkpoint
|
||||
// if should_update_justified_checkpoint(store, state.current_justified_checkpoint):
|
||||
// store.justified_checkpoint = state.current_justified_checkpoint
|
||||
// # Check the block is valid and compute the post-state
|
||||
// state = pre_state.copy()
|
||||
// state_transition(state, signed_block, True)
|
||||
// # Add new block to the store
|
||||
// store.blocks[hash_tree_root(block)] = block
|
||||
// # Add new state for this block to the store
|
||||
// store.block_states[hash_tree_root(block)] = state
|
||||
//
|
||||
// # Update finalized checkpoint
|
||||
// if state.finalized_checkpoint.epoch > store.finalized_checkpoint.epoch:
|
||||
// store.finalized_checkpoint = state.finalized_checkpoint
|
||||
// # Update justified checkpoint
|
||||
// if state.current_justified_checkpoint.epoch > store.justified_checkpoint.epoch:
|
||||
// if state.current_justified_checkpoint.epoch > store.best_justified_checkpoint.epoch:
|
||||
// store.best_justified_checkpoint = state.current_justified_checkpoint
|
||||
// if should_update_justified_checkpoint(store, state.current_justified_checkpoint):
|
||||
// store.justified_checkpoint = state.current_justified_checkpoint
|
||||
//
|
||||
// # Potentially update justified if different from store
|
||||
// if store.justified_checkpoint != state.current_justified_checkpoint:
|
||||
// # Update justified if new justified is later than store justified
|
||||
// if state.current_justified_checkpoint.epoch > store.justified_checkpoint.epoch:
|
||||
// store.justified_checkpoint = state.current_justified_checkpoint
|
||||
// return
|
||||
// # Update finalized checkpoint
|
||||
// if state.finalized_checkpoint.epoch > store.finalized_checkpoint.epoch:
|
||||
// store.finalized_checkpoint = state.finalized_checkpoint
|
||||
//
|
||||
// # Update justified if store justified is not in chain with finalized checkpoint
|
||||
// finalized_slot = compute_start_slot_at_epoch(store.finalized_checkpoint.epoch)
|
||||
// ancestor_at_finalized_slot = get_ancestor(store, store.justified_checkpoint.root, finalized_slot)
|
||||
// if ancestor_at_finalized_slot != store.finalized_checkpoint.root:
|
||||
// store.justified_checkpoint = state.current_justified_checkpoint
|
||||
// # Potentially update justified if different from store
|
||||
// if store.justified_checkpoint != state.current_justified_checkpoint:
|
||||
// # Update justified if new justified is later than store justified
|
||||
// if state.current_justified_checkpoint.epoch > store.justified_checkpoint.epoch:
|
||||
// store.justified_checkpoint = state.current_justified_checkpoint
|
||||
// return
|
||||
//
|
||||
// # Update justified if store justified is not in chain with finalized checkpoint
|
||||
// finalized_slot = compute_start_slot_at_epoch(store.finalized_checkpoint.epoch)
|
||||
// ancestor_at_finalized_slot = get_ancestor(store, store.justified_checkpoint.root, finalized_slot)
|
||||
// if ancestor_at_finalized_slot != store.finalized_checkpoint.root:
|
||||
// store.justified_checkpoint = state.current_justified_checkpoint
|
||||
func (s *Service) onBlock(ctx context.Context, signed interfaces.SignedBeaconBlock, blockRoot [32]byte) error {
|
||||
ctx, span := trace.StartSpan(ctx, "blockChain.onBlock")
|
||||
defer span.End()
|
||||
if err := consensusblocks.BeaconBlockIsNil(signed); err != nil {
|
||||
return invalidBlock{error: err}
|
||||
}
|
||||
startTime := time.Now()
|
||||
b := signed.Block()
|
||||
|
||||
preState, err := s.getBlockPreState(ctx, b)
|
||||
@@ -115,10 +116,13 @@ func (s *Service) onBlock(ctx context.Context, signed interfaces.SignedBeaconBlo
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
stateTransitionStartTime := time.Now()
|
||||
postState, err := transition.ExecuteStateTransition(ctx, preState, signed)
|
||||
if err != nil {
|
||||
return invalidBlock{error: err}
|
||||
}
|
||||
stateTransitionProcessingTime.Observe(float64(time.Since(stateTransitionStartTime).Milliseconds()))
|
||||
|
||||
postStateVersion, postStateHeader, err := getStateVersionAndPayload(postState)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -139,6 +143,13 @@ func (s *Service) onBlock(ctx context.Context, signed interfaces.SignedBeaconBlo
|
||||
if err := s.insertBlockToForkchoiceStore(ctx, signed.Block(), blockRoot, postState); err != nil {
|
||||
return errors.Wrapf(err, "could not insert block %d to fork choice store", signed.Block().Slot())
|
||||
}
|
||||
if err := s.handleBlockAttestations(ctx, signed.Block(), postState); err != nil {
|
||||
return errors.Wrap(err, "could not handle block's attestations")
|
||||
}
|
||||
if err := s.handleBlockBLSToExecChanges(signed.Block()); err != nil {
|
||||
return errors.Wrap(err, "could not handle block's BLSToExecutionChanges")
|
||||
}
|
||||
|
||||
s.InsertSlashingsToForkChoiceStore(ctx, signed.Block().Body().AttesterSlashings())
|
||||
if isValidPayload {
|
||||
if err := s.cfg.ForkChoiceStore.SetOptimisticToValid(ctx, blockRoot); err != nil {
|
||||
@@ -179,10 +190,14 @@ func (s *Service) onBlock(ctx context.Context, signed interfaces.SignedBeaconBlo
|
||||
msg := fmt.Sprintf("could not read balances for state w/ justified checkpoint %#x", justified.Root)
|
||||
return errors.Wrap(err, msg)
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
headRoot, err := s.cfg.ForkChoiceStore.Head(ctx, balances)
|
||||
if err != nil {
|
||||
log.WithError(err).Warn("Could not update head")
|
||||
}
|
||||
newBlockHeadElapsedTime.Observe(float64(time.Since(start).Milliseconds()))
|
||||
|
||||
if err := s.notifyEngineIfChangedHead(ctx, headRoot); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -237,12 +252,13 @@ func (s *Service) onBlock(ctx context.Context, signed interfaces.SignedBeaconBlo
|
||||
}
|
||||
go func() {
|
||||
// Send an event regarding the new finalized checkpoint over a common event feed.
|
||||
stateRoot := signed.Block().StateRoot()
|
||||
s.cfg.StateNotifier.StateFeed().Send(&feed.Event{
|
||||
Type: statefeed.FinalizedCheckpoint,
|
||||
Data: ðpbv1.EventFinalizedCheckpoint{
|
||||
Epoch: postState.FinalizedCheckpoint().Epoch,
|
||||
Block: postState.FinalizedCheckpoint().Root,
|
||||
State: signed.Block().StateRoot(),
|
||||
State: stateRoot[:],
|
||||
ExecutionOptimistic: isOptimistic,
|
||||
},
|
||||
})
|
||||
@@ -259,14 +275,18 @@ func (s *Service) onBlock(ctx context.Context, signed interfaces.SignedBeaconBlo
|
||||
|
||||
}
|
||||
defer reportAttestationInclusion(b)
|
||||
return s.handleEpochBoundary(ctx, postState)
|
||||
if err := s.handleEpochBoundary(ctx, postState); err != nil {
|
||||
return err
|
||||
}
|
||||
onBlockProcessingTime.Observe(float64(time.Since(startTime).Milliseconds()))
|
||||
return nil
|
||||
}
|
||||
|
||||
func getStateVersionAndPayload(st state.BeaconState) (int, *enginev1.ExecutionPayloadHeader, error) {
|
||||
func getStateVersionAndPayload(st state.BeaconState) (int, interfaces.ExecutionData, error) {
|
||||
if st == nil {
|
||||
return 0, nil, errors.New("nil state")
|
||||
}
|
||||
var preStateHeader *enginev1.ExecutionPayloadHeader
|
||||
var preStateHeader interfaces.ExecutionData
|
||||
var err error
|
||||
preStateVersion := st.Version()
|
||||
switch preStateVersion {
|
||||
@@ -302,7 +322,7 @@ func (s *Service) onBlockBatch(ctx context.Context, blks []interfaces.SignedBeac
|
||||
if err := s.verifyBlkPreState(ctx, b); err != nil {
|
||||
return err
|
||||
}
|
||||
preState, err := s.cfg.StateGen.StateByRootInitialSync(ctx, bytesutil.ToBytes32(b.ParentRoot()))
|
||||
preState, err := s.cfg.StateGen.StateByRootInitialSync(ctx, b.ParentRoot())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -317,14 +337,10 @@ func (s *Service) onBlockBatch(ctx context.Context, blks []interfaces.SignedBeac
|
||||
|
||||
jCheckpoints := make([]*ethpb.Checkpoint, len(blks))
|
||||
fCheckpoints := make([]*ethpb.Checkpoint, len(blks))
|
||||
sigSet := &bls.SignatureBatch{
|
||||
Signatures: [][]byte{},
|
||||
PublicKeys: []bls.PublicKey{},
|
||||
Messages: [][32]byte{},
|
||||
}
|
||||
sigSet := bls.NewSet()
|
||||
type versionAndHeader struct {
|
||||
version int
|
||||
header *enginev1.ExecutionPayloadHeader
|
||||
header interfaces.ExecutionData
|
||||
}
|
||||
preVersionAndHeaders := make([]*versionAndHeader, len(blks))
|
||||
postVersionAndHeaders := make([]*versionAndHeader, len(blks))
|
||||
@@ -361,7 +377,13 @@ func (s *Service) onBlockBatch(ctx context.Context, blks []interfaces.SignedBeac
|
||||
}
|
||||
sigSet.Join(set)
|
||||
}
|
||||
verify, err := sigSet.Verify()
|
||||
|
||||
var verify bool
|
||||
if features.Get().EnableVerboseSigVerification {
|
||||
verify, err = sigSet.VerifyVerbosely()
|
||||
} else {
|
||||
verify, err = sigSet.Verify()
|
||||
}
|
||||
if err != nil {
|
||||
return invalidBlock{error: err}
|
||||
}
|
||||
@@ -501,7 +523,7 @@ func (s *Service) insertBlockToForkchoiceStore(ctx context.Context, blk interfac
|
||||
ctx, span := trace.StartSpan(ctx, "blockChain.insertBlockToForkchoiceStore")
|
||||
defer span.End()
|
||||
|
||||
if !s.cfg.ForkChoiceStore.HasNode(bytesutil.ToBytes32(blk.ParentRoot())) {
|
||||
if !s.cfg.ForkChoiceStore.HasNode(blk.ParentRoot()) {
|
||||
fCheckpoint := st.FinalizedCheckpoint()
|
||||
jCheckpoint := st.CurrentJustifiedCheckpoint()
|
||||
if err := s.fillInForkChoiceMissingBlocks(ctx, blk, fCheckpoint, jCheckpoint); err != nil {
|
||||
@@ -509,10 +531,45 @@ func (s *Service) insertBlockToForkchoiceStore(ctx context.Context, blk interfac
|
||||
}
|
||||
}
|
||||
|
||||
if err := s.cfg.ForkChoiceStore.InsertNode(ctx, st, root); err != nil {
|
||||
return err
|
||||
}
|
||||
return s.cfg.ForkChoiceStore.InsertNode(ctx, st, root)
|
||||
}
|
||||
|
||||
// This feeds in the attestations included in the block to fork choice store. It's allows fork choice store
|
||||
// to gain information on the most current chain.
|
||||
func (s *Service) handleBlockAttestations(ctx context.Context, blk interfaces.BeaconBlock, st state.BeaconState) error {
|
||||
// Feed in block's attestations to fork choice store.
|
||||
for _, a := range blk.Body().Attestations() {
|
||||
committee, err := helpers.BeaconCommitteeFromState(ctx, st, a.Data.Slot, a.Data.CommitteeIndex)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
indices, err := attestation.AttestingIndices(a.AggregationBits, committee)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r := bytesutil.ToBytes32(a.Data.BeaconBlockRoot)
|
||||
if s.cfg.ForkChoiceStore.HasNode(r) {
|
||||
s.cfg.ForkChoiceStore.ProcessAttestation(ctx, indices, r, a.Data.Target.Epoch)
|
||||
} else if err := s.cfg.AttPool.SaveBlockAttestation(a); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) handleBlockBLSToExecChanges(blk interfaces.BeaconBlock) error {
|
||||
if blk.Version() < version.Capella {
|
||||
return nil
|
||||
}
|
||||
changes, err := blk.Body().BLSToExecutionChanges()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get BLSToExecutionChanges")
|
||||
}
|
||||
for _, change := range changes {
|
||||
if err := s.cfg.BLSToExecPool.MarkIncluded(change); err != nil {
|
||||
return errors.Wrap(err, "could not mark BLSToExecutionChange as included")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -568,7 +625,7 @@ func (s *Service) pruneCanonicalAttsFromPool(ctx context.Context, r [32]byte, b
|
||||
}
|
||||
|
||||
// validateMergeTransitionBlock validates the merge transition block.
|
||||
func (s *Service) validateMergeTransitionBlock(ctx context.Context, stateVersion int, stateHeader *enginev1.ExecutionPayloadHeader, blk interfaces.SignedBeaconBlock) error {
|
||||
func (s *Service) validateMergeTransitionBlock(ctx context.Context, stateVersion int, stateHeader interfaces.ExecutionData, blk interfaces.SignedBeaconBlock) error {
|
||||
// Skip validation if block is older than Bellatrix.
|
||||
if blocks.IsPreBellatrixVersion(blk.Block().Version()) {
|
||||
return nil
|
||||
@@ -595,11 +652,7 @@ func (s *Service) validateMergeTransitionBlock(ctx context.Context, stateVersion
|
||||
|
||||
// Skip validation if the block is not a merge transition block.
|
||||
// To reach here. The payload must be non-empty. If the state header is empty then it's at transition.
|
||||
wh, err := consensusblocks.WrappedExecutionPayloadHeader(stateHeader)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
empty, err := consensusblocks.IsEmptyExecutionData(wh)
|
||||
empty, err := consensusblocks.IsEmptyExecutionData(stateHeader)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -630,25 +683,8 @@ func (s *Service) fillMissingPayloadIDRoutine(ctx context.Context, stateFeed *ev
|
||||
for {
|
||||
select {
|
||||
case ti := <-ticker.C:
|
||||
if !atHalfSlot(ti) {
|
||||
continue
|
||||
}
|
||||
_, id, has := s.cfg.ProposerSlotIndexCache.GetProposerPayloadIDs(s.CurrentSlot()+1, s.headRoot())
|
||||
// There exists proposer for next slot, but we haven't called fcu w/ payload attribute yet.
|
||||
if has && id == [8]byte{} {
|
||||
headBlock, err := s.headBlock()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Could not get head block")
|
||||
} else {
|
||||
if _, err := s.notifyForkchoiceUpdate(ctx, ¬ifyForkchoiceUpdateArg{
|
||||
headState: s.headState(ctx),
|
||||
headRoot: s.headRoot(),
|
||||
headBlock: headBlock.Block(),
|
||||
}); err != nil {
|
||||
log.WithError(err).Error("Could not prepare payload on empty ID")
|
||||
}
|
||||
}
|
||||
missedPayloadIDFilledCount.Inc()
|
||||
if err := s.fillMissingBlockPayloadId(ctx, ti); err != nil {
|
||||
log.WithError(err).Error("Could not fill missing payload ID")
|
||||
}
|
||||
case <-s.ctx.Done():
|
||||
log.Debug("Context closed, exiting routine")
|
||||
@@ -663,3 +699,31 @@ func atHalfSlot(t time.Time) bool {
|
||||
s := params.BeaconConfig().SecondsPerSlot
|
||||
return uint64(t.Second())%s == s/2
|
||||
}
|
||||
|
||||
func (s *Service) fillMissingBlockPayloadId(ctx context.Context, ti time.Time) error {
|
||||
if !atHalfSlot(ti) {
|
||||
return nil
|
||||
}
|
||||
if s.CurrentSlot() == s.cfg.ForkChoiceStore.HighestReceivedBlockSlot() {
|
||||
return nil
|
||||
}
|
||||
// Head root should be empty when retrieving proposer index for the next slot.
|
||||
_, id, has := s.cfg.ProposerSlotIndexCache.GetProposerPayloadIDs(s.CurrentSlot()+1, [32]byte{} /* head root */)
|
||||
// There exists proposer for next slot, but we haven't called fcu w/ payload attribute yet.
|
||||
if has && id == [8]byte{} {
|
||||
missedPayloadIDFilledCount.Inc()
|
||||
headBlock, err := s.headBlock()
|
||||
if err != nil {
|
||||
return err
|
||||
} else {
|
||||
if _, err := s.notifyForkchoiceUpdate(ctx, ¬ifyForkchoiceUpdateArg{
|
||||
headState: s.headState(ctx),
|
||||
headRoot: s.headRoot(),
|
||||
headBlock: headBlock.Block(),
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -6,9 +6,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/helpers"
|
||||
doublylinkedtree "github.com/prysmaticlabs/prysm/v3/beacon-chain/forkchoice/doubly-linked-tree"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/forkchoice/protoarray"
|
||||
forkchoicetypes "github.com/prysmaticlabs/prysm/v3/beacon-chain/forkchoice/types"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||
@@ -39,7 +37,7 @@ func (s *Service) getBlockPreState(ctx context.Context, b interfaces.BeaconBlock
|
||||
return nil, err
|
||||
}
|
||||
|
||||
preState, err := s.cfg.StateGen.StateByRoot(ctx, bytesutil.ToBytes32(b.ParentRoot()))
|
||||
preState, err := s.cfg.StateGen.StateByRoot(ctx, b.ParentRoot())
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not get pre state for slot %d", b.Slot())
|
||||
}
|
||||
@@ -65,15 +63,16 @@ func (s *Service) verifyBlkPreState(ctx context.Context, b interfaces.BeaconBloc
|
||||
ctx, span := trace.StartSpan(ctx, "blockChain.verifyBlkPreState")
|
||||
defer span.End()
|
||||
|
||||
parentRoot := bytesutil.ToBytes32(b.ParentRoot())
|
||||
parentRoot := b.ParentRoot()
|
||||
// Loosen the check to HasBlock because state summary gets saved in batches
|
||||
// during initial syncing. There's no risk given a state summary object is just a
|
||||
// a subset of the block object.
|
||||
if !s.cfg.BeaconDB.HasStateSummary(ctx, parentRoot) && !s.cfg.BeaconDB.HasBlock(ctx, parentRoot) {
|
||||
log.Errorf("requesting blockroot %#x", bytesutil.Trunc(parentRoot[:]))
|
||||
return errors.New("could not reconstruct parent state")
|
||||
}
|
||||
|
||||
if err := s.VerifyFinalizedBlkDescendant(ctx, bytesutil.ToBytes32(b.ParentRoot())); err != nil {
|
||||
if err := s.VerifyFinalizedBlkDescendant(ctx, parentRoot); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -135,11 +134,21 @@ func (s *Service) verifyBlkFinalizedSlot(b interfaces.BeaconBlock) error {
|
||||
}
|
||||
|
||||
// updateFinalized saves the init sync blocks, finalized checkpoint, migrates
|
||||
// to cold old states and saves the last validated checkpoint to DB
|
||||
// to cold old states and saves the last validated checkpoint to DB. It returns
|
||||
// early if the new checkpoint is older than the one on db.
|
||||
func (s *Service) updateFinalized(ctx context.Context, cp *ethpb.Checkpoint) error {
|
||||
ctx, span := trace.StartSpan(ctx, "blockChain.updateFinalized")
|
||||
defer span.End()
|
||||
|
||||
// return early if new checkpoint is not newer than the one in DB
|
||||
currentFinalized, err := s.cfg.BeaconDB.FinalizedCheckpoint(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if cp.Epoch <= currentFinalized.Epoch {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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 {
|
||||
@@ -153,7 +162,7 @@ func (s *Service) updateFinalized(ctx context.Context, cp *ethpb.Checkpoint) err
|
||||
|
||||
fRoot := bytesutil.ToBytes32(cp.Root)
|
||||
optimistic, err := s.cfg.ForkChoiceStore.IsOptimistic(fRoot)
|
||||
if err != nil && err != protoarray.ErrUnknownNodeRoot && err != doublylinkedtree.ErrNilNode {
|
||||
if err != nil && !errors.Is(err, doublylinkedtree.ErrNilNode) {
|
||||
return err
|
||||
}
|
||||
if !optimistic {
|
||||
@@ -162,24 +171,30 @@ func (s *Service) updateFinalized(ctx context.Context, cp *ethpb.Checkpoint) err
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := s.cfg.StateGen.MigrateToCold(ctx, fRoot); err != nil {
|
||||
return errors.Wrap(err, "could not migrate to cold")
|
||||
}
|
||||
go func() {
|
||||
// We do not pass in the parent context from the method as this method call
|
||||
// is meant to be asynchronous and run in the background rather than being
|
||||
// tied to the execution of a block.
|
||||
if err := s.cfg.StateGen.MigrateToCold(s.ctx, fRoot); err != nil {
|
||||
log.WithError(err).Error("could not migrate to cold")
|
||||
}
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
// ancestor returns the block root of an ancestry block from the input block root.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// def get_ancestor(store: Store, root: Root, slot: Slot) -> Root:
|
||||
// block = store.blocks[root]
|
||||
// if block.slot > slot:
|
||||
// return get_ancestor(store, block.parent_root, slot)
|
||||
// elif block.slot == slot:
|
||||
// return root
|
||||
// else:
|
||||
// # root is older than queried slot, thus a skip slot. Return most recent root prior to slot
|
||||
// return root
|
||||
//
|
||||
// def get_ancestor(store: Store, root: Root, slot: Slot) -> Root:
|
||||
// block = store.blocks[root]
|
||||
// if block.slot > slot:
|
||||
// return get_ancestor(store, block.parent_root, slot)
|
||||
// elif block.slot == slot:
|
||||
// return root
|
||||
// else:
|
||||
// # root is older than queried slot, thus a skip slot. Return most recent root prior to slot
|
||||
// return root
|
||||
func (s *Service) ancestor(ctx context.Context, root []byte, slot types.Slot) ([]byte, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "blockChain.ancestor")
|
||||
defer span.End()
|
||||
@@ -231,7 +246,7 @@ func (s *Service) ancestorByDB(ctx context.Context, r [32]byte, slot types.Slot)
|
||||
return r[:], nil
|
||||
}
|
||||
|
||||
return s.ancestorByDB(ctx, bytesutil.ToBytes32(b.ParentRoot()), slot)
|
||||
return s.ancestorByDB(ctx, b.ParentRoot(), slot)
|
||||
}
|
||||
|
||||
// This retrieves missing blocks from DB (ie. the blocks that couldn't be received over sync) and inserts them to fork choice store.
|
||||
@@ -249,7 +264,7 @@ func (s *Service) fillInForkChoiceMissingBlocks(ctx context.Context, blk interfa
|
||||
pendingNodes = append(pendingNodes, &forkchoicetypes.BlockAndCheckpoints{Block: blk,
|
||||
JustifiedCheckpoint: jCheckpoint, FinalizedCheckpoint: fCheckpoint})
|
||||
// As long as parent node is not in fork choice store, and parent node is in DB.
|
||||
root := bytesutil.ToBytes32(blk.ParentRoot())
|
||||
root := blk.ParentRoot()
|
||||
for !s.cfg.ForkChoiceStore.HasNode(root) && s.cfg.BeaconDB.HasBlock(ctx, root) {
|
||||
b, err := s.getBlock(ctx, root)
|
||||
if err != nil {
|
||||
@@ -258,7 +273,7 @@ func (s *Service) fillInForkChoiceMissingBlocks(ctx context.Context, blk interfa
|
||||
if b.Block().Slot() <= fSlot {
|
||||
break
|
||||
}
|
||||
root = bytesutil.ToBytes32(b.Block().ParentRoot())
|
||||
root = b.Block().ParentRoot()
|
||||
args := &forkchoicetypes.BlockAndCheckpoints{Block: b.Block(),
|
||||
JustifiedCheckpoint: jCheckpoint,
|
||||
FinalizedCheckpoint: fCheckpoint}
|
||||
@@ -267,7 +282,7 @@ func (s *Service) fillInForkChoiceMissingBlocks(ctx context.Context, blk interfa
|
||||
if len(pendingNodes) == 1 {
|
||||
return nil
|
||||
}
|
||||
if root != s.ensureRootNotZeros(finalized.Root) {
|
||||
if root != s.ensureRootNotZeros(finalized.Root) && !s.ForkChoicer().HasNode(root) {
|
||||
return errNotDescendantOfFinalized
|
||||
}
|
||||
return s.cfg.ForkChoiceStore.InsertOptimisticChain(ctx, pendingNodes)
|
||||
@@ -302,23 +317,6 @@ func (s *Service) insertFinalizedDeposits(ctx context.Context, fRoot [32]byte) e
|
||||
return nil
|
||||
}
|
||||
|
||||
// The deletes input attestations from the attestation pool, so proposers don't include them in a block for the future.
|
||||
func (s *Service) deletePoolAtts(atts []*ethpb.Attestation) error {
|
||||
for _, att := range atts {
|
||||
if helpers.IsAggregated(att) {
|
||||
if err := s.cfg.AttPool.DeleteAggregatedAttestation(att); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := s.cfg.AttPool.DeleteUnaggregatedAttestation(att); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// This ensures that the input root defaults to using genesis root instead of zero hashes. This is needed for handling
|
||||
// fork choice justification routine.
|
||||
func (s *Service) ensureRootNotZeros(root [32]byte) [32]byte {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -122,12 +122,10 @@ func (s *Service) spawnProcessAttestationsRoutine(stateFeed *event.Feed) {
|
||||
case <-st.C():
|
||||
if err := s.ForkChoicer().NewSlot(s.ctx, s.CurrentSlot()); err != nil {
|
||||
log.WithError(err).Error("Could not process new slot")
|
||||
return
|
||||
}
|
||||
|
||||
if err := s.UpdateHead(s.ctx); err != nil {
|
||||
log.WithError(err).Error("Could not process attestations and update head")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -137,27 +135,26 @@ func (s *Service) spawnProcessAttestationsRoutine(stateFeed *event.Feed) {
|
||||
// UpdateHead updates the canonical head of the chain based on information from fork-choice attestations and votes.
|
||||
// It requires no external inputs.
|
||||
func (s *Service) UpdateHead(ctx context.Context) error {
|
||||
// Continue when there's no fork choice attestation, there's nothing to process and update head.
|
||||
// This covers the condition when the node is still initial syncing to the head of the chain.
|
||||
if s.cfg.AttPool.ForkchoiceAttestationCount() == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Only one process can process attestations and update head at a time.
|
||||
s.processAttestationsLock.Lock()
|
||||
defer s.processAttestationsLock.Unlock()
|
||||
|
||||
start := time.Now()
|
||||
s.processAttestations(ctx)
|
||||
processAttsElapsedTime.Observe(float64(time.Since(start).Milliseconds()))
|
||||
|
||||
justified := s.ForkChoicer().JustifiedCheckpoint()
|
||||
balances, err := s.justifiedBalances.get(ctx, justified.Root)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
start = time.Now()
|
||||
newHeadRoot, err := s.cfg.ForkChoiceStore.Head(ctx, balances)
|
||||
if err != nil {
|
||||
log.WithError(err).Warn("Resolving fork due to new attestation")
|
||||
log.WithError(err).Error("Could not compute head from new attestations")
|
||||
}
|
||||
newAttHeadElapsedTime.Observe(float64(time.Since(start).Milliseconds()))
|
||||
|
||||
s.headLock.RLock()
|
||||
if s.headRoot() != newHeadRoot {
|
||||
log.WithFields(logrus.Fields{
|
||||
|
||||
@@ -159,7 +159,6 @@ func TestNotifyEngineIfChangedHead(t *testing.T) {
|
||||
require.NoError(t, service.saveInitSyncBlock(ctx, r1, wsb))
|
||||
st, _ := util.DeterministicGenesisState(t, 1)
|
||||
service.head = &head{
|
||||
slot: 1,
|
||||
root: r1,
|
||||
block: wsb,
|
||||
state: st,
|
||||
@@ -177,7 +176,6 @@ func TestNotifyEngineIfChangedHead(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
st, _ = util.DeterministicGenesisState(t, 1)
|
||||
service.head = &head{
|
||||
slot: 1,
|
||||
root: r1,
|
||||
block: wsb,
|
||||
state: st,
|
||||
@@ -226,11 +224,11 @@ func TestService_ProcessAttestationsAndUpdateHead(t *testing.T) {
|
||||
require.Equal(t, 2, fcs.NodeCount())
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveBlock(ctx, wsb))
|
||||
|
||||
// Generate attestatios for this block in Slot 1
|
||||
// Generate attestations for this block in Slot 1
|
||||
atts, err := util.GenerateAttestations(copied, pks, 1, 1, false)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, service.cfg.AttPool.SaveForkchoiceAttestations(atts))
|
||||
// Verify the target is in forchoice
|
||||
// Verify the target is in forkchoice
|
||||
require.Equal(t, true, fcs.HasNode(bytesutil.ToBytes32(atts[0].Data.BeaconBlockRoot)))
|
||||
|
||||
// Insert a new block to forkchoice
|
||||
@@ -253,3 +251,52 @@ func TestService_ProcessAttestationsAndUpdateHead(t *testing.T) {
|
||||
require.Equal(t, 0, len(service.cfg.AttPool.ForkchoiceAttestations())) // Validate att pool is empty
|
||||
require.Equal(t, tRoot, service.head.root) // Validate head is the new one
|
||||
}
|
||||
|
||||
func TestService_UpdateHead_NoAtts(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
opts := testServiceOptsWithDB(t)
|
||||
fcs := doublylinkedtree.New()
|
||||
opts = append(opts,
|
||||
WithAttestationPool(attestations.NewPool()),
|
||||
WithStateNotifier(&mockBeaconNode{}),
|
||||
WithForkChoiceStore(fcs),
|
||||
)
|
||||
|
||||
service, err := NewService(ctx, opts...)
|
||||
require.NoError(t, err)
|
||||
service.genesisTime = prysmTime.Now().Add(-2 * time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Second)
|
||||
genesisState, pks := util.DeterministicGenesisState(t, 64)
|
||||
require.NoError(t, service.saveGenesisData(ctx, genesisState))
|
||||
copied := genesisState.Copy()
|
||||
// Generate a new block
|
||||
blk, err := util.GenerateFullBlock(copied, pks, util.DefaultBlockGenConfig(), 1)
|
||||
require.NoError(t, err)
|
||||
tRoot, err := blk.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
wsb, err := blocks.NewSignedBeaconBlock(blk)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, service.onBlock(ctx, wsb, tRoot))
|
||||
require.Equal(t, 2, fcs.NodeCount())
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveBlock(ctx, wsb))
|
||||
require.Equal(t, tRoot, service.head.root)
|
||||
|
||||
// Insert a new block to forkchoice
|
||||
ojc := ðpb.Checkpoint{Epoch: 0, Root: params.BeaconConfig().ZeroHash[:]}
|
||||
b, err := util.GenerateFullBlock(genesisState, pks, util.DefaultBlockGenConfig(), 2)
|
||||
require.NoError(t, err)
|
||||
b.Block.ParentRoot = service.originBlockRoot[:]
|
||||
r, err := b.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
util.SaveBlock(t, ctx, service.cfg.BeaconDB, b)
|
||||
state, blkRoot, err := prepareForkchoiceState(ctx, 2, r, service.originBlockRoot, [32]byte{'b'}, ojc, ojc)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, service.cfg.ForkChoiceStore.InsertNode(ctx, state, blkRoot))
|
||||
require.Equal(t, 3, fcs.NodeCount())
|
||||
|
||||
require.Equal(t, 0, service.cfg.AttPool.ForkchoiceAttestationCount())
|
||||
require.NoError(t, err, service.UpdateHead(ctx))
|
||||
|
||||
require.Equal(t, 0, len(service.cfg.AttPool.ForkchoiceAttestations())) // Validate att pool is empty
|
||||
require.Equal(t, r, service.head.root) // Validate head is the new one
|
||||
|
||||
}
|
||||
|
||||
@@ -32,9 +32,9 @@ type SlashingReceiver interface {
|
||||
|
||||
// ReceiveBlock is a function that defines the operations (minus pubsub)
|
||||
// that are performed on a received block. The operations consist of:
|
||||
// 1. Validate block, apply state transition and update checkpoints
|
||||
// 2. Apply fork choice to the processed block
|
||||
// 3. Save latest head info
|
||||
// 1. Validate block, apply state transition and update checkpoints
|
||||
// 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 {
|
||||
ctx, span := trace.StartSpan(ctx, "blockChain.ReceiveBlock")
|
||||
defer span.End()
|
||||
@@ -145,16 +145,6 @@ func (s *Service) ReceiveAttesterSlashing(ctx context.Context, slashing *ethpb.A
|
||||
}
|
||||
|
||||
func (s *Service) handlePostBlockOperations(b interfaces.BeaconBlock) error {
|
||||
// Delete the processed block attestations from attestation pool.
|
||||
if err := s.deletePoolAtts(b.Body().Attestations()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Add block attestations to the fork choice pool to compute head.
|
||||
if err := s.cfg.AttPool.SaveBlockAttestations(b.Body().Attestations()); err != nil {
|
||||
log.WithError(err).Error("Could not save block attestations for fork choice")
|
||||
return nil
|
||||
}
|
||||
// Mark block exits as seen so we don't include same ones in future blocks.
|
||||
for _, e := range b.Body().VoluntaryExits() {
|
||||
s.cfg.ExitPool.MarkIncluded(e)
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
|
||||
blockchainTesting "github.com/prysmaticlabs/prysm/v3/beacon-chain/blockchain/testing"
|
||||
testDB "github.com/prysmaticlabs/prysm/v3/beacon-chain/db/testing"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/forkchoice/protoarray"
|
||||
doublylinkedtree "github.com/prysmaticlabs/prysm/v3/beacon-chain/forkchoice/doubly-linked-tree"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/operations/attestations"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/operations/voluntaryexits"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state/stategen"
|
||||
@@ -33,7 +33,7 @@ func TestService_ReceiveBlock(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
return blk
|
||||
}
|
||||
params.SetupTestConfigCleanupWithLock(t)
|
||||
//params.SetupTestConfigCleanupWithLock(t)
|
||||
bc := params.BeaconConfig().Copy()
|
||||
bc.ShardCommitteePeriod = 0 // Required for voluntary exits test in reasonable time.
|
||||
params.OverrideBeaconConfig(bc)
|
||||
@@ -76,9 +76,9 @@ func TestService_ReceiveBlock(t *testing.T) {
|
||||
),
|
||||
},
|
||||
check: func(t *testing.T, s *Service) {
|
||||
if baCount := len(s.cfg.AttPool.BlockAttestations()); baCount != 2 {
|
||||
if baCount := len(s.cfg.AttPool.BlockAttestations()); baCount != 0 {
|
||||
t.Errorf("Did not get the correct number of block attestations saved to the pool. "+
|
||||
"Got %d but wanted %d", baCount, 2)
|
||||
"Got %d but wanted %d", baCount, 0)
|
||||
}
|
||||
},
|
||||
},
|
||||
@@ -127,13 +127,14 @@ func TestService_ReceiveBlock(t *testing.T) {
|
||||
genesisBlockRoot := bytesutil.ToBytes32(nil)
|
||||
require.NoError(t, beaconDB.SaveState(ctx, genesis, genesisBlockRoot))
|
||||
|
||||
fc := doublylinkedtree.New()
|
||||
opts := []Option{
|
||||
WithDatabase(beaconDB),
|
||||
WithForkChoiceStore(protoarray.New()),
|
||||
WithForkChoiceStore(fc),
|
||||
WithAttestationPool(attestations.NewPool()),
|
||||
WithExitPool(voluntaryexits.NewPool()),
|
||||
WithStateNotifier(&blockchainTesting.MockStateNotifier{RecordEvents: true}),
|
||||
WithStateGen(stategen.New(beaconDB)),
|
||||
WithStateGen(stategen.New(beaconDB, fc)),
|
||||
WithFinalizedStateAtStartUp(genesis),
|
||||
}
|
||||
s, err := NewService(ctx, opts...)
|
||||
@@ -166,13 +167,14 @@ func TestService_ReceiveBlockUpdateHead(t *testing.T) {
|
||||
beaconDB := testDB.SetupDB(t)
|
||||
genesisBlockRoot := bytesutil.ToBytes32(nil)
|
||||
require.NoError(t, beaconDB.SaveState(ctx, genesis, genesisBlockRoot))
|
||||
fc := doublylinkedtree.New()
|
||||
opts := []Option{
|
||||
WithDatabase(beaconDB),
|
||||
WithForkChoiceStore(protoarray.New()),
|
||||
WithForkChoiceStore(fc),
|
||||
WithAttestationPool(attestations.NewPool()),
|
||||
WithExitPool(voluntaryexits.NewPool()),
|
||||
WithStateNotifier(&blockchainTesting.MockStateNotifier{RecordEvents: true}),
|
||||
WithStateGen(stategen.New(beaconDB)),
|
||||
WithStateGen(stategen.New(beaconDB, fc)),
|
||||
}
|
||||
|
||||
s, err := NewService(ctx, opts...)
|
||||
@@ -242,12 +244,13 @@ func TestService_ReceiveBlockBatch(t *testing.T) {
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
fc := doublylinkedtree.New()
|
||||
beaconDB := testDB.SetupDB(t)
|
||||
opts := []Option{
|
||||
WithDatabase(beaconDB),
|
||||
WithForkChoiceStore(protoarray.New()),
|
||||
WithForkChoiceStore(fc),
|
||||
WithStateNotifier(&blockchainTesting.MockStateNotifier{RecordEvents: true}),
|
||||
WithStateGen(stategen.New(beaconDB)),
|
||||
WithStateGen(stategen.New(beaconDB, fc)),
|
||||
}
|
||||
s, err := NewService(ctx, opts...)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -21,10 +21,9 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/db"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/execution"
|
||||
f "github.com/prysmaticlabs/prysm/v3/beacon-chain/forkchoice"
|
||||
doublylinkedtree "github.com/prysmaticlabs/prysm/v3/beacon-chain/forkchoice/doubly-linked-tree"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/forkchoice/protoarray"
|
||||
forkchoicetypes "github.com/prysmaticlabs/prysm/v3/beacon-chain/forkchoice/types"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/operations/attestations"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/operations/blstoexec"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/operations/slashings"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/operations/voluntaryexits"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/p2p"
|
||||
@@ -72,6 +71,7 @@ type config struct {
|
||||
AttPool attestations.Pool
|
||||
ExitPool voluntaryexits.PoolManager
|
||||
SlashingPool slashings.PoolManager
|
||||
BLSToExecPool blstoexec.PoolManager
|
||||
P2p p2p.Broadcaster
|
||||
MaxRoutines int
|
||||
StateNotifier statefeed.Notifier
|
||||
@@ -206,39 +206,33 @@ func (s *Service) StartFromSavedState(saved state.BeaconState) error {
|
||||
return errNilFinalizedCheckpoint
|
||||
}
|
||||
|
||||
var forkChoicer f.ForkChoicer
|
||||
fRoot := s.ensureRootNotZeros(bytesutil.ToBytes32(finalized.Root))
|
||||
if !features.Get().DisableForkchoiceDoublyLinkedTree {
|
||||
forkChoicer = doublylinkedtree.New()
|
||||
} else {
|
||||
forkChoicer = protoarray.New()
|
||||
}
|
||||
s.cfg.ForkChoiceStore = forkChoicer
|
||||
if err := forkChoicer.UpdateJustifiedCheckpoint(&forkchoicetypes.Checkpoint{Epoch: justified.Epoch,
|
||||
if err := s.cfg.ForkChoiceStore.UpdateJustifiedCheckpoint(&forkchoicetypes.Checkpoint{Epoch: justified.Epoch,
|
||||
Root: bytesutil.ToBytes32(justified.Root)}); err != nil {
|
||||
return errors.Wrap(err, "could not update forkchoice's justified checkpoint")
|
||||
}
|
||||
if err := forkChoicer.UpdateFinalizedCheckpoint(&forkchoicetypes.Checkpoint{Epoch: finalized.Epoch,
|
||||
if err := s.cfg.ForkChoiceStore.UpdateFinalizedCheckpoint(&forkchoicetypes.Checkpoint{Epoch: finalized.Epoch,
|
||||
Root: bytesutil.ToBytes32(finalized.Root)}); err != nil {
|
||||
return errors.Wrap(err, "could not update forkchoice's finalized checkpoint")
|
||||
}
|
||||
forkChoicer.SetGenesisTime(uint64(s.genesisTime.Unix()))
|
||||
s.cfg.ForkChoiceStore.SetGenesisTime(uint64(s.genesisTime.Unix()))
|
||||
|
||||
st, err := s.cfg.StateGen.StateByRoot(s.ctx, fRoot)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get finalized checkpoint state")
|
||||
}
|
||||
if err := forkChoicer.InsertNode(s.ctx, st, fRoot); err != nil {
|
||||
if err := s.cfg.ForkChoiceStore.InsertNode(s.ctx, st, fRoot); err != nil {
|
||||
return errors.Wrap(err, "could not insert finalized block to forkchoice")
|
||||
}
|
||||
|
||||
lastValidatedCheckpoint, err := s.cfg.BeaconDB.LastValidatedCheckpoint(s.ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get last validated checkpoint")
|
||||
}
|
||||
if bytes.Equal(finalized.Root, lastValidatedCheckpoint.Root) {
|
||||
if err := forkChoicer.SetOptimisticToValid(s.ctx, fRoot); err != nil {
|
||||
return errors.Wrap(err, "could not set finalized block as validated")
|
||||
if !features.Get().EnableStartOptimistic {
|
||||
lastValidatedCheckpoint, err := s.cfg.BeaconDB.LastValidatedCheckpoint(s.ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get last validated checkpoint")
|
||||
}
|
||||
if bytes.Equal(finalized.Root, lastValidatedCheckpoint.Root) {
|
||||
if err := s.cfg.ForkChoiceStore.SetOptimisticToValid(s.ctx, fRoot); err != nil {
|
||||
return errors.Wrap(err, "could not set finalized block as validated")
|
||||
}
|
||||
}
|
||||
}
|
||||
// not attempting to save initial sync blocks here, because there shouldn't be any until
|
||||
|
||||
@@ -21,11 +21,11 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/execution"
|
||||
mockExecution "github.com/prysmaticlabs/prysm/v3/beacon-chain/execution/testing"
|
||||
doublylinkedtree "github.com/prysmaticlabs/prysm/v3/beacon-chain/forkchoice/doubly-linked-tree"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/forkchoice/protoarray"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/operations/attestations"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/p2p"
|
||||
state_native "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/state-native"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state/stategen"
|
||||
v1 "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/v1"
|
||||
"github.com/prysmaticlabs/prysm/v3/config/features"
|
||||
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||
consensusblocks "github.com/prysmaticlabs/prysm/v3/consensus-types/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces"
|
||||
@@ -83,7 +83,7 @@ func setupBeaconChain(t *testing.T, beaconDB db.Database) *Service {
|
||||
srv.Stop()
|
||||
})
|
||||
bState, _ := util.DeterministicGenesisState(t, 10)
|
||||
pbState, err := v1.ProtobufBeaconState(bState.InnerStateUnsafe())
|
||||
pbState, err := state_native.ProtobufBeaconStatePhase0(bState.ToProtoUnsafe())
|
||||
require.NoError(t, err)
|
||||
mockTrie, err := trie.NewTrie(0)
|
||||
require.NoError(t, err)
|
||||
@@ -117,7 +117,8 @@ func setupBeaconChain(t *testing.T, beaconDB db.Database) *Service {
|
||||
depositCache, err := depositcache.New()
|
||||
require.NoError(t, err)
|
||||
|
||||
stateGen := stategen.New(beaconDB)
|
||||
fc := doublylinkedtree.New()
|
||||
stateGen := stategen.New(beaconDB, fc)
|
||||
// Safe a state in stategen to purposes of testing a service stop / shutdown.
|
||||
require.NoError(t, stateGen.SaveState(ctx, bytesutil.ToBytes32(bState.FinalizedCheckpoint().Root), bState))
|
||||
|
||||
@@ -128,7 +129,7 @@ func setupBeaconChain(t *testing.T, beaconDB db.Database) *Service {
|
||||
WithAttestationPool(attestations.NewPool()),
|
||||
WithP2PBroadcaster(&mockBroadcaster{}),
|
||||
WithStateNotifier(&mockBeaconNode{}),
|
||||
WithForkChoiceStore(doublylinkedtree.New()),
|
||||
WithForkChoiceStore(fc),
|
||||
WithAttestationService(attService),
|
||||
WithStateGen(stateGen),
|
||||
}
|
||||
@@ -305,8 +306,15 @@ func TestChainService_InitializeChainInfo(t *testing.T) {
|
||||
require.NoError(t, beaconDB.SaveFinalizedCheckpoint(ctx, ðpb.Checkpoint{Epoch: slots.ToEpoch(finalizedSlot), Root: headRoot[:]}))
|
||||
attSrv, err := attestations.NewService(ctx, &attestations.Config{})
|
||||
require.NoError(t, err)
|
||||
stateGen := stategen.New(beaconDB)
|
||||
c, err := NewService(ctx, WithDatabase(beaconDB), WithStateGen(stateGen), WithAttestationService(attSrv), WithStateNotifier(&mock.MockStateNotifier{}), WithFinalizedStateAtStartUp(headState))
|
||||
fc := doublylinkedtree.New()
|
||||
stateGen := stategen.New(beaconDB, fc)
|
||||
c, err := NewService(ctx,
|
||||
WithForkChoiceStore(fc),
|
||||
WithDatabase(beaconDB),
|
||||
WithStateGen(stateGen),
|
||||
WithAttestationService(attSrv),
|
||||
WithStateNotifier(&mock.MockStateNotifier{}),
|
||||
WithFinalizedStateAtStartUp(headState))
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, stateGen.SaveState(ctx, headRoot, headState))
|
||||
require.NoError(t, c.StartFromSavedState(headState))
|
||||
@@ -317,7 +325,7 @@ func TestChainService_InitializeChainInfo(t *testing.T) {
|
||||
assert.DeepEqual(t, headBlock, pb, "Head block incorrect")
|
||||
s, err := c.HeadState(ctx)
|
||||
require.NoError(t, err)
|
||||
assert.DeepSSZEqual(t, headState.InnerStateUnsafe(), s.InnerStateUnsafe(), "Head state incorrect")
|
||||
assert.DeepSSZEqual(t, headState.ToProtoUnsafe(), s.ToProtoUnsafe(), "Head state incorrect")
|
||||
assert.Equal(t, c.HeadSlot(), headBlock.Block.Slot, "Head slot incorrect")
|
||||
r, err := c.HeadRoot(context.Background())
|
||||
require.NoError(t, err)
|
||||
@@ -358,14 +366,21 @@ func TestChainService_InitializeChainInfo_SetHeadAtGenesis(t *testing.T) {
|
||||
}
|
||||
require.NoError(t, beaconDB.SaveStateSummary(ctx, ss))
|
||||
require.NoError(t, beaconDB.SaveFinalizedCheckpoint(ctx, ðpb.Checkpoint{Root: headRoot[:], Epoch: slots.ToEpoch(finalizedSlot)}))
|
||||
stateGen := stategen.New(beaconDB)
|
||||
c, err := NewService(ctx, WithDatabase(beaconDB), WithStateGen(stateGen), WithAttestationService(attSrv), WithStateNotifier(&mock.MockStateNotifier{}), WithFinalizedStateAtStartUp(headState))
|
||||
fc := doublylinkedtree.New()
|
||||
stateGen := stategen.New(beaconDB, fc)
|
||||
c, err := NewService(ctx,
|
||||
WithForkChoiceStore(fc),
|
||||
WithDatabase(beaconDB),
|
||||
WithStateGen(stateGen),
|
||||
WithAttestationService(attSrv),
|
||||
WithStateNotifier(&mock.MockStateNotifier{}),
|
||||
WithFinalizedStateAtStartUp(headState))
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NoError(t, c.StartFromSavedState(headState))
|
||||
s, err := c.HeadState(ctx)
|
||||
require.NoError(t, err)
|
||||
assert.DeepSSZEqual(t, headState.InnerStateUnsafe(), s.InnerStateUnsafe(), "Head state incorrect")
|
||||
assert.DeepSSZEqual(t, headState.ToProtoUnsafe(), s.ToProtoUnsafe(), "Head state incorrect")
|
||||
assert.Equal(t, genesisRoot, c.originBlockRoot, "Genesis block root incorrect")
|
||||
pb, err := c.head.block.Proto()
|
||||
require.NoError(t, err)
|
||||
@@ -375,8 +390,9 @@ func TestChainService_InitializeChainInfo_SetHeadAtGenesis(t *testing.T) {
|
||||
func TestChainService_SaveHeadNoDB(t *testing.T) {
|
||||
beaconDB := testDB.SetupDB(t)
|
||||
ctx := context.Background()
|
||||
fc := doublylinkedtree.New()
|
||||
s := &Service{
|
||||
cfg: &config{BeaconDB: beaconDB, StateGen: stategen.New(beaconDB), ForkChoiceStore: doublylinkedtree.New()},
|
||||
cfg: &config{BeaconDB: beaconDB, StateGen: stategen.New(beaconDB, fc), ForkChoiceStore: fc},
|
||||
}
|
||||
blk := util.NewBeaconBlock()
|
||||
blk.Block.Slot = 1
|
||||
@@ -396,25 +412,6 @@ func TestChainService_SaveHeadNoDB(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestHasBlock_ForkChoiceAndDB_ProtoArray(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
beaconDB := testDB.SetupDB(t)
|
||||
s := &Service{
|
||||
cfg: &config{ForkChoiceStore: protoarray.New(), BeaconDB: beaconDB},
|
||||
}
|
||||
b := util.NewBeaconBlock()
|
||||
r, err := b.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
beaconState, err := util.NewBeaconState()
|
||||
require.NoError(t, err)
|
||||
wsb, err := consensusblocks.NewSignedBeaconBlock(b)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, s.insertBlockToForkchoiceStore(ctx, wsb.Block(), r, beaconState))
|
||||
|
||||
assert.Equal(t, false, s.hasBlock(ctx, [32]byte{}), "Should not have block")
|
||||
assert.Equal(t, true, s.hasBlock(ctx, r), "Should have block")
|
||||
}
|
||||
|
||||
func TestHasBlock_ForkChoiceAndDB_DoublyLinkedTree(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
beaconDB := testDB.SetupDB(t)
|
||||
@@ -438,7 +435,7 @@ func TestServiceStop_SaveCachedBlocks(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
beaconDB := testDB.SetupDB(t)
|
||||
s := &Service{
|
||||
cfg: &config{BeaconDB: beaconDB, StateGen: stategen.New(beaconDB)},
|
||||
cfg: &config{BeaconDB: beaconDB, StateGen: stategen.New(beaconDB, doublylinkedtree.New())},
|
||||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
initSyncBlocks: make(map[[32]byte]interfaces.SignedBeaconBlock),
|
||||
@@ -486,27 +483,6 @@ func BenchmarkHasBlockDB(b *testing.B) {
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkHasBlockForkChoiceStore_ProtoArray(b *testing.B) {
|
||||
ctx := context.Background()
|
||||
beaconDB := testDB.SetupDB(b)
|
||||
s := &Service{
|
||||
cfg: &config{ForkChoiceStore: protoarray.New(), BeaconDB: beaconDB},
|
||||
}
|
||||
blk := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Body: ðpb.BeaconBlockBody{}}}
|
||||
r, err := blk.Block.HashTreeRoot()
|
||||
require.NoError(b, err)
|
||||
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)
|
||||
wsb, err := consensusblocks.NewSignedBeaconBlock(blk)
|
||||
require.NoError(b, err)
|
||||
require.NoError(b, s.insertBlockToForkchoiceStore(ctx, wsb.Block(), r, beaconState))
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
require.Equal(b, true, s.cfg.ForkChoiceStore.HasNode(r), "Block is not in fork choice store")
|
||||
}
|
||||
}
|
||||
func BenchmarkHasBlockForkChoiceStore_DoublyLinkedTree(b *testing.B) {
|
||||
ctx := context.Background()
|
||||
beaconDB := testDB.SetupDB(b)
|
||||
@@ -517,7 +493,7 @@ func BenchmarkHasBlockForkChoiceStore_DoublyLinkedTree(b *testing.B) {
|
||||
r, err := blk.Block.HashTreeRoot()
|
||||
require.NoError(b, err)
|
||||
bs := ðpb.BeaconState{FinalizedCheckpoint: ðpb.Checkpoint{Root: make([]byte, 32)}, CurrentJustifiedCheckpoint: ðpb.Checkpoint{Root: make([]byte, 32)}}
|
||||
beaconState, err := v1.InitializeFromProto(bs)
|
||||
beaconState, err := state_native.InitializeFromProtoPhase0(bs)
|
||||
require.NoError(b, err)
|
||||
wsb, err := consensusblocks.NewSignedBeaconBlock(blk)
|
||||
require.NoError(b, err)
|
||||
@@ -528,3 +504,52 @@ func BenchmarkHasBlockForkChoiceStore_DoublyLinkedTree(b *testing.B) {
|
||||
require.Equal(b, true, s.cfg.ForkChoiceStore.HasNode(r), "Block is not in fork choice store")
|
||||
}
|
||||
}
|
||||
|
||||
func TestChainService_EverythingOptimistic(t *testing.T) {
|
||||
resetFn := features.InitWithReset(&features.Flags{
|
||||
EnableStartOptimistic: true,
|
||||
})
|
||||
defer resetFn()
|
||||
beaconDB := testDB.SetupDB(t)
|
||||
ctx := context.Background()
|
||||
|
||||
genesis := util.NewBeaconBlock()
|
||||
genesisRoot, err := genesis.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, genesisRoot))
|
||||
util.SaveBlock(t, ctx, beaconDB, genesis)
|
||||
|
||||
finalizedSlot := params.BeaconConfig().SlotsPerEpoch*2 + 1
|
||||
headBlock := util.NewBeaconBlock()
|
||||
headBlock.Block.Slot = finalizedSlot
|
||||
headBlock.Block.ParentRoot = bytesutil.PadTo(genesisRoot[:], 32)
|
||||
headState, err := util.NewBeaconState()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, headState.SetSlot(finalizedSlot))
|
||||
require.NoError(t, headState.SetGenesisValidatorsRoot(params.BeaconConfig().ZeroHash[:]))
|
||||
headRoot, err := headBlock.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, beaconDB.SaveState(ctx, headState, headRoot))
|
||||
require.NoError(t, beaconDB.SaveState(ctx, headState, genesisRoot))
|
||||
util.SaveBlock(t, ctx, beaconDB, headBlock)
|
||||
require.NoError(t, beaconDB.SaveFinalizedCheckpoint(ctx, ðpb.Checkpoint{Epoch: slots.ToEpoch(finalizedSlot), Root: headRoot[:]}))
|
||||
attSrv, err := attestations.NewService(ctx, &attestations.Config{})
|
||||
require.NoError(t, err)
|
||||
fc := doublylinkedtree.New()
|
||||
stateGen := stategen.New(beaconDB, fc)
|
||||
c, err := NewService(ctx,
|
||||
WithForkChoiceStore(fc),
|
||||
WithDatabase(beaconDB),
|
||||
WithStateGen(stateGen),
|
||||
WithAttestationService(attSrv),
|
||||
WithStateNotifier(&mock.MockStateNotifier{}),
|
||||
WithFinalizedStateAtStartUp(headState))
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, stateGen.SaveState(ctx, headRoot, headState))
|
||||
require.NoError(t, beaconDB.SaveLastValidatedCheckpoint(ctx, ðpb.Checkpoint{Epoch: slots.ToEpoch(finalizedSlot), Root: headRoot[:]}))
|
||||
require.NoError(t, c.StartFromSavedState(headState))
|
||||
require.Equal(t, true, c.cfg.ForkChoiceStore.HasNode(headRoot))
|
||||
op, err := c.cfg.ForkChoiceStore.IsOptimistic(headRoot)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, true, op)
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state"
|
||||
v2 "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/v2"
|
||||
state_native "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/state-native"
|
||||
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||
@@ -34,7 +34,7 @@ func testStateFixture(opts ...testStateOpt) state.BeaconState {
|
||||
for _, o := range opts {
|
||||
o(a)
|
||||
}
|
||||
s, _ := v2.InitializeFromProtoUnsafe(a)
|
||||
s, _ := state_native.InitializeFromProtoUnsafeAltair(a)
|
||||
return s
|
||||
}
|
||||
|
||||
|
||||
@@ -174,7 +174,8 @@ func (s *ChainService) ReceiveBlockInitialSync(ctx context.Context, block interf
|
||||
if s.State == nil {
|
||||
return ErrNilState
|
||||
}
|
||||
if !bytes.Equal(s.Root, block.Block().ParentRoot()) {
|
||||
parentRoot := block.Block().ParentRoot()
|
||||
if !bytes.Equal(s.Root, parentRoot[:]) {
|
||||
return errors.Errorf("wanted %#x but got %#x", s.Root, block.Block().ParentRoot())
|
||||
}
|
||||
if err := s.State.SetSlot(block.Block().Slot()); err != nil {
|
||||
@@ -202,7 +203,8 @@ func (s *ChainService) ReceiveBlockBatch(ctx context.Context, blks []interfaces.
|
||||
return ErrNilState
|
||||
}
|
||||
for _, b := range blks {
|
||||
if !bytes.Equal(s.Root, b.Block().ParentRoot()) {
|
||||
parentRoot := b.Block().ParentRoot()
|
||||
if !bytes.Equal(s.Root, parentRoot[:]) {
|
||||
return errors.Errorf("wanted %#x but got %#x", s.Root, b.Block().ParentRoot())
|
||||
}
|
||||
if err := s.State.SetSlot(b.Block().Slot()); err != nil {
|
||||
@@ -233,7 +235,8 @@ func (s *ChainService) ReceiveBlock(ctx context.Context, block interfaces.Signed
|
||||
if s.State == nil {
|
||||
return ErrNilState
|
||||
}
|
||||
if !bytes.Equal(s.Root, block.Block().ParentRoot()) {
|
||||
parentRoot := block.Block().ParentRoot()
|
||||
if !bytes.Equal(s.Root, parentRoot[:]) {
|
||||
return errors.Errorf("wanted %#x but got %#x", s.Root, block.Block().ParentRoot())
|
||||
}
|
||||
if err := s.State.SetSlot(block.Block().Slot()); err != nil {
|
||||
|
||||
@@ -30,8 +30,7 @@ type WeakSubjectivityVerifier struct {
|
||||
// NewWeakSubjectivityVerifier validates a checkpoint, and if valid, uses it to initialize a weak subjectivity verifier.
|
||||
func NewWeakSubjectivityVerifier(wsc *ethpb.Checkpoint, db weakSubjectivityDB) (*WeakSubjectivityVerifier, error) {
|
||||
if wsc == nil || len(wsc.Root) == 0 || wsc.Epoch == 0 {
|
||||
log.Info("--weak-subjectivity-checkpoint not provided. Prysm recommends providing a weak subjectivity checkpoint " +
|
||||
"for nodes synced from genesis, or manual verification of block and state roots for checkpoint sync nodes.")
|
||||
log.Debug("--weak-subjectivity-checkpoint not provided")
|
||||
return &WeakSubjectivityVerifier{
|
||||
enabled: false,
|
||||
}, nil
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
|
||||
"github.com/pkg/errors"
|
||||
testDB "github.com/prysmaticlabs/prysm/v3/beacon-chain/db/testing"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/forkchoice/protoarray"
|
||||
doublylinkedtree "github.com/prysmaticlabs/prysm/v3/beacon-chain/forkchoice/doubly-linked-tree"
|
||||
forkchoicetypes "github.com/prysmaticlabs/prysm/v3/beacon-chain/forkchoice/types"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/v3/config/fieldparams"
|
||||
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||
@@ -72,7 +72,7 @@ func TestService_VerifyWeakSubjectivityRoot(t *testing.T) {
|
||||
wv, err := NewWeakSubjectivityVerifier(tt.checkpt, beaconDB)
|
||||
require.Equal(t, !tt.disabled, wv.enabled)
|
||||
require.NoError(t, err)
|
||||
fcs := protoarray.New()
|
||||
fcs := doublylinkedtree.New()
|
||||
s := &Service{
|
||||
cfg: &config{BeaconDB: beaconDB, WeakSubjectivityCheckpt: tt.checkpt, ForkChoiceStore: fcs},
|
||||
wsVerifier: wv,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
load("@prysm//tools/go:def.bzl", "go_library")
|
||||
load("@prysm//tools/go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
@@ -16,8 +16,6 @@ go_library(
|
||||
"//cmd/beacon-chain/flags:go_default_library",
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
"//network:go_default_library",
|
||||
"//network/authorization:go_default_library",
|
||||
"//proto/engine/v1:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
@@ -28,3 +26,18 @@ go_library(
|
||||
"@io_opencensus_go//trace:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["service_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//api/client/builder/testing:go_default_library",
|
||||
"//beacon-chain/blockchain/testing:go_default_library",
|
||||
"//beacon-chain/db/testing:go_default_library",
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//testing/assert:go_default_library",
|
||||
"//testing/require:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -20,13 +20,6 @@ var (
|
||||
Buckets: []float64{1, 2, 5, 10, 20, 50, 100, 200, 500, 1000},
|
||||
},
|
||||
)
|
||||
getStatusLatency = promauto.NewHistogram(
|
||||
prometheus.HistogramOpts{
|
||||
Name: "get_status_latency_milliseconds",
|
||||
Help: "Captures RPC latency for get status in milliseconds",
|
||||
Buckets: []float64{1, 2, 5, 10, 20, 50, 100, 200, 500, 1000},
|
||||
},
|
||||
)
|
||||
registerValidatorLatency = promauto.NewHistogram(
|
||||
prometheus.HistogramOpts{
|
||||
Name: "register_validator_latency_milliseconds",
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
package builder
|
||||
|
||||
import (
|
||||
"github.com/prysmaticlabs/prysm/v3/api/client/builder"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/blockchain"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/db"
|
||||
"github.com/prysmaticlabs/prysm/v3/cmd/beacon-chain/flags"
|
||||
"github.com/prysmaticlabs/prysm/v3/network"
|
||||
"github.com/prysmaticlabs/prysm/v3/network/authorization"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
@@ -14,22 +13,30 @@ type Option func(s *Service) error
|
||||
// FlagOptions for builder service flag configurations.
|
||||
func FlagOptions(c *cli.Context) ([]Option, error) {
|
||||
endpoint := c.String(flags.MevRelayEndpoint.Name)
|
||||
var client *builder.Client
|
||||
if endpoint != "" {
|
||||
var err error
|
||||
client, err = builder.NewClient(endpoint)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
opts := []Option{
|
||||
WithBuilderEndpoints(endpoint),
|
||||
WithBuilderClient(client),
|
||||
}
|
||||
return opts, nil
|
||||
}
|
||||
|
||||
// WithBuilderEndpoints sets the endpoint for the beacon chain builder service.
|
||||
func WithBuilderEndpoints(endpoint string) Option {
|
||||
// WithBuilderClient sets the builder client for the beacon chain builder service.
|
||||
func WithBuilderClient(client builder.BuilderClient) Option {
|
||||
return func(s *Service) error {
|
||||
s.cfg.builderEndpoint = covertEndPoint(endpoint)
|
||||
s.cfg.builderClient = client
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithHeadFetcher gets the head info from chain service.
|
||||
func WithHeadFetcher(svc *blockchain.Service) Option {
|
||||
func WithHeadFetcher(svc blockchain.HeadFetcher) Option {
|
||||
return func(s *Service) error {
|
||||
s.cfg.headFetcher = svc
|
||||
return nil
|
||||
@@ -43,12 +50,3 @@ func WithDatabase(beaconDB db.HeadAccessDatabase) Option {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func covertEndPoint(ep string) network.Endpoint {
|
||||
return network.Endpoint{
|
||||
Url: ep,
|
||||
Auth: network.AuthorizationData{ // Auth is not used for builder.
|
||||
Method: authorization.None,
|
||||
Value: "",
|
||||
}}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ package builder
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
@@ -11,7 +11,6 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/db"
|
||||
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/v3/network"
|
||||
v1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||
log "github.com/sirupsen/logrus"
|
||||
@@ -31,15 +30,15 @@ type BlockBuilder interface {
|
||||
|
||||
// config defines a config struct for dependencies into the service.
|
||||
type config struct {
|
||||
builderEndpoint network.Endpoint
|
||||
beaconDB db.HeadAccessDatabase
|
||||
headFetcher blockchain.HeadFetcher
|
||||
builderClient builder.BuilderClient
|
||||
beaconDB db.HeadAccessDatabase
|
||||
headFetcher blockchain.HeadFetcher
|
||||
}
|
||||
|
||||
// Service defines a service that provides a client for interacting with the beacon chain and MEV relay network.
|
||||
type Service struct {
|
||||
cfg *config
|
||||
c *builder.Client
|
||||
c builder.BuilderClient
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
}
|
||||
@@ -57,27 +56,25 @@ func NewService(ctx context.Context, opts ...Option) (*Service, error) {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if s.cfg.builderEndpoint.Url != "" {
|
||||
c, err := builder.NewClient(s.cfg.builderEndpoint.Url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.c = c
|
||||
if s.cfg.builderClient != nil && !reflect.ValueOf(s.cfg.builderClient).IsNil() {
|
||||
s.c = s.cfg.builderClient
|
||||
|
||||
// Is the builder up?
|
||||
if err := s.c.Status(ctx); err != nil {
|
||||
return nil, fmt.Errorf("could not connect to builder: %v", err)
|
||||
log.WithError(err).Error("Failed to check builder status")
|
||||
} else {
|
||||
log.WithField("endpoint", s.c.NodeURL()).Info("Builder has been configured")
|
||||
log.Warn("Outsourcing block construction to external builders adds non-trivial delay to block propagation time. " +
|
||||
"Builder-constructed blocks or fallback blocks may get orphaned. Use at your own risk!")
|
||||
}
|
||||
|
||||
log.WithField("endpoint", c.NodeURL()).Info("Builder has been configured")
|
||||
log.Warn("Outsourcing block construction to external builders adds non-trivial delay to block propagation time. " +
|
||||
"Builder-constructed blocks or fallback blocks may get orphaned. Use at your own risk!")
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// Start initializes the service.
|
||||
func (*Service) Start() {}
|
||||
func (s *Service) Start() {
|
||||
go s.pollRelayerStatus(s.ctx)
|
||||
}
|
||||
|
||||
// Stop halts the service.
|
||||
func (*Service) Stop() error {
|
||||
@@ -110,19 +107,12 @@ func (s *Service) GetHeader(ctx context.Context, slot types.Slot, parentHash [32
|
||||
|
||||
// Status retrieves the status of the builder relay network.
|
||||
func (s *Service) Status() error {
|
||||
ctx, span := trace.StartSpan(context.Background(), "builder.Status")
|
||||
defer span.End()
|
||||
start := time.Now()
|
||||
defer func() {
|
||||
getStatusLatency.Observe(float64(time.Since(start).Milliseconds()))
|
||||
}()
|
||||
|
||||
// Return early if builder isn't initialized in service.
|
||||
if s.c == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return s.c.Status(ctx)
|
||||
return nil
|
||||
}
|
||||
|
||||
// RegisterValidator registers a validator with the builder relay network.
|
||||
@@ -158,7 +148,24 @@ func (s *Service) RegisterValidator(ctx context.Context, reg []*ethpb.SignedVali
|
||||
return s.cfg.beaconDB.SaveRegistrationsByValidatorIDs(ctx, idxs, msgs)
|
||||
}
|
||||
|
||||
// Configured returns true if the user has input a builder URL.
|
||||
// Configured returns true if the user has configured a builder client.
|
||||
func (s *Service) Configured() bool {
|
||||
return s.cfg.builderEndpoint.Url != ""
|
||||
return s.c != nil && !reflect.ValueOf(s.c).IsNil()
|
||||
}
|
||||
|
||||
func (s *Service) pollRelayerStatus(ctx context.Context) {
|
||||
ticker := time.NewTicker(time.Minute)
|
||||
defer ticker.Stop()
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
if s.c != nil {
|
||||
if err := s.c.Status(ctx); err != nil {
|
||||
log.WithError(err).Error("Failed to call relayer status endpoint, perhaps mev-boost or relayers are down")
|
||||
}
|
||||
}
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
39
beacon-chain/builder/service_test.go
Normal file
39
beacon-chain/builder/service_test.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package builder
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
buildertesting "github.com/prysmaticlabs/prysm/v3/api/client/builder/testing"
|
||||
blockchainTesting "github.com/prysmaticlabs/prysm/v3/beacon-chain/blockchain/testing"
|
||||
dbtesting "github.com/prysmaticlabs/prysm/v3/beacon-chain/db/testing"
|
||||
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
||||
eth "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v3/testing/assert"
|
||||
"github.com/prysmaticlabs/prysm/v3/testing/require"
|
||||
)
|
||||
|
||||
func Test_NewServiceWithBuilder(t *testing.T) {
|
||||
s, err := NewService(context.Background(), WithBuilderClient(&buildertesting.MockClient{}))
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, true, s.Configured())
|
||||
}
|
||||
|
||||
func Test_NewServiceWithoutBuilder(t *testing.T) {
|
||||
s, err := NewService(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, false, s.Configured())
|
||||
}
|
||||
|
||||
func Test_RegisterValidator(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
db := dbtesting.SetupDB(t)
|
||||
headFetcher := &blockchainTesting.ChainService{}
|
||||
builder := buildertesting.NewClient()
|
||||
s, err := NewService(ctx, WithDatabase(db), WithHeadFetcher(headFetcher), WithBuilderClient(&builder))
|
||||
require.NoError(t, err)
|
||||
pubkey := bytesutil.ToBytes48([]byte("pubkey"))
|
||||
var feeRecipient [20]byte
|
||||
require.NoError(t, s.RegisterValidator(ctx, []*eth.SignedValidatorRegistrationV1{{Message: ð.ValidatorRegistrationV1{Pubkey: pubkey[:], FeeRecipient: feeRecipient[:]}}}))
|
||||
assert.Equal(t, true, builder.RegisteredVals[pubkey])
|
||||
}
|
||||
4
beacon-chain/cache/BUILD.bazel
vendored
4
beacon-chain/cache/BUILD.bazel
vendored
@@ -73,9 +73,7 @@ go_test(
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//beacon-chain/state/v1:go_default_library",
|
||||
"//beacon-chain/state/v2:go_default_library",
|
||||
"//beacon-chain/state/v3:go_default_library",
|
||||
"//beacon-chain/state/state-native:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
|
||||
6
beacon-chain/cache/active_balance_test.go
vendored
6
beacon-chain/cache/active_balance_test.go
vendored
@@ -7,7 +7,7 @@ import (
|
||||
"math"
|
||||
"testing"
|
||||
|
||||
state "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/v1"
|
||||
state_native "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/state-native"
|
||||
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||
@@ -24,7 +24,7 @@ func TestBalanceCache_AddGetBalance(t *testing.T) {
|
||||
raw := ðpb.BeaconState{
|
||||
BlockRoots: blockRoots,
|
||||
}
|
||||
st, err := state.InitializeFromProto(raw)
|
||||
st, err := state_native.InitializeFromProtoPhase0(raw)
|
||||
require.NoError(t, err)
|
||||
|
||||
cache := NewEffectiveBalanceCache()
|
||||
@@ -68,7 +68,7 @@ func TestBalanceCache_BalanceKey(t *testing.T) {
|
||||
raw := ðpb.BeaconState{
|
||||
BlockRoots: blockRoots,
|
||||
}
|
||||
st, err := state.InitializeFromProto(raw)
|
||||
st, err := state_native.InitializeFromProtoPhase0(raw)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, st.SetSlot(types.Slot(math.MaxUint64)))
|
||||
|
||||
|
||||
7
beacon-chain/cache/checkpoint_state.go
vendored
7
beacon-chain/cache/checkpoint_state.go
vendored
@@ -1,8 +1,6 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
lru "github.com/hashicorp/golang-lru"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
@@ -32,7 +30,6 @@ var (
|
||||
// CheckpointStateCache is a struct with 1 queue for looking up state by checkpoint.
|
||||
type CheckpointStateCache struct {
|
||||
cache *lru.Cache
|
||||
lock sync.RWMutex
|
||||
}
|
||||
|
||||
// NewCheckpointStateCache creates a new checkpoint state cache for storing/accessing processed state.
|
||||
@@ -45,8 +42,6 @@ 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) (state.BeaconState, error) {
|
||||
c.lock.RLock()
|
||||
defer c.lock.RUnlock()
|
||||
h, err := hash.HashProto(cp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -67,8 +62,6 @@ func (c *CheckpointStateCache) StateByCheckpoint(cp *ethpb.Checkpoint) (state.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 state.ReadOnlyBeaconState) error {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
h, err := hash.HashProto(cp)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
16
beacon-chain/cache/checkpoint_state_test.go
vendored
16
beacon-chain/cache/checkpoint_state_test.go
vendored
@@ -4,7 +4,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state"
|
||||
v1 "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/v1"
|
||||
state_native "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/state-native"
|
||||
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
||||
@@ -18,7 +18,7 @@ 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 := state_native.InitializeFromProtoPhase0(ðpb.BeaconState{
|
||||
GenesisValidatorsRoot: params.BeaconConfig().ZeroHash[:],
|
||||
Slot: 64,
|
||||
})
|
||||
@@ -33,16 +33,16 @@ func TestCheckpointStateCache_StateByCheckpoint(t *testing.T) {
|
||||
s, err = cache.StateByCheckpoint(cp1)
|
||||
require.NoError(t, err)
|
||||
|
||||
pbState1, err := v1.ProtobufBeaconState(s.InnerStateUnsafe())
|
||||
pbState1, err := state_native.ProtobufBeaconStatePhase0(s.ToProtoUnsafe())
|
||||
require.NoError(t, err)
|
||||
pbstate, err := v1.ProtobufBeaconState(st.InnerStateUnsafe())
|
||||
pbstate, err := state_native.ProtobufBeaconStatePhase0(st.ToProtoUnsafe())
|
||||
require.NoError(t, err)
|
||||
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 := state_native.InitializeFromProtoPhase0(ðpb.BeaconState{
|
||||
Slot: 128,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
@@ -50,16 +50,16 @@ func TestCheckpointStateCache_StateByCheckpoint(t *testing.T) {
|
||||
|
||||
s, err = cache.StateByCheckpoint(cp2)
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, st2.CloneInnerState(), s.CloneInnerState(), "incorrectly cached state")
|
||||
assert.DeepEqual(t, st2.ToProto(), s.ToProto(), "incorrectly cached state")
|
||||
|
||||
s, err = cache.StateByCheckpoint(cp1)
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, st.CloneInnerState(), s.CloneInnerState(), "incorrectly cached state")
|
||||
assert.DeepEqual(t, st.ToProto(), s.ToProto(), "incorrectly cached state")
|
||||
}
|
||||
|
||||
func TestCheckpointStateCache_MaxSize(t *testing.T) {
|
||||
c := NewCheckpointStateCache()
|
||||
st, err := v1.InitializeFromProto(ðpb.BeaconState{
|
||||
st, err := state_native.InitializeFromProtoPhase0(ðpb.BeaconState{
|
||||
Slot: 0,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -185,7 +185,21 @@ func (dc *DepositCache) AllDepositContainers(ctx context.Context) []*ethpb.Depos
|
||||
dc.depositsLock.RLock()
|
||||
defer dc.depositsLock.RUnlock()
|
||||
|
||||
return dc.deposits
|
||||
// Make a shallow copy of the deposits and return that. This way, the
|
||||
// caller can safely iterate over the returned list of deposits without
|
||||
// the possibility of new deposits showing up. If we were to return the
|
||||
// list without a copy, when a new deposit is added to the cache, it
|
||||
// would also be present in the returned value. This could result in a
|
||||
// race condition if the list is being iterated over.
|
||||
//
|
||||
// It's not necessary to make a deep copy of this list because the
|
||||
// deposits in the cache should never be modified. It is still possible
|
||||
// for the caller to modify one of the underlying deposits and modify
|
||||
// the cache, but that's not a race condition. Also, a deep copy would
|
||||
// take too long and use too much memory.
|
||||
deposits := make([]*ethpb.DepositContainer, len(dc.deposits))
|
||||
copy(deposits, dc.deposits)
|
||||
return deposits
|
||||
}
|
||||
|
||||
// AllDeposits returns a list of historical deposits until the given block number
|
||||
|
||||
@@ -55,7 +55,7 @@ func (dc *DepositCache) PendingDeposits(ctx context.Context, untilBlk *big.Int)
|
||||
|
||||
depositCntrs := dc.PendingContainers(ctx, untilBlk)
|
||||
|
||||
var deposits []*ethpb.Deposit
|
||||
deposits := make([]*ethpb.Deposit, 0, len(depositCntrs))
|
||||
for _, dep := range depositCntrs {
|
||||
deposits = append(deposits, dep.Deposit)
|
||||
}
|
||||
@@ -71,7 +71,7 @@ func (dc *DepositCache) PendingContainers(ctx context.Context, untilBlk *big.Int
|
||||
dc.depositsLock.RLock()
|
||||
defer dc.depositsLock.RUnlock()
|
||||
|
||||
var depositCntrs []*ethpb.DepositContainer
|
||||
depositCntrs := make([]*ethpb.DepositContainer, 0, len(dc.pendingDeposits))
|
||||
for _, ctnr := range dc.pendingDeposits {
|
||||
if untilBlk == nil || untilBlk.Uint64() >= ctnr.Eth1BlockHeight {
|
||||
depositCntrs = append(depositCntrs, ctnr)
|
||||
@@ -139,7 +139,7 @@ func (dc *DepositCache) PrunePendingDeposits(ctx context.Context, merkleTreeInde
|
||||
dc.depositsLock.Lock()
|
||||
defer dc.depositsLock.Unlock()
|
||||
|
||||
var cleanDeposits []*ethpb.DepositContainer
|
||||
cleanDeposits := make([]*ethpb.DepositContainer, 0, len(dc.pendingDeposits))
|
||||
for _, dp := range dc.pendingDeposits {
|
||||
if dp.Index >= merkleTreeIndex {
|
||||
cleanDeposits = append(cleanDeposits, dp)
|
||||
|
||||
8
beacon-chain/cache/depositsnapshot/BUILD.bazel
vendored
Normal file
8
beacon-chain/cache/depositsnapshot/BUILD.bazel
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
load("@prysm//tools/go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["merkle_tree.go"],
|
||||
importpath = "github.com/prysmaticlabs/prysm/v3/beacon-chain/cache/depositsnapshot",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
19
beacon-chain/cache/depositsnapshot/merkle_tree.go
vendored
Normal file
19
beacon-chain/cache/depositsnapshot/merkle_tree.go
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
package depositsnapshot
|
||||
|
||||
const (
|
||||
DepositContractDepth = 32 // Maximum tree depth as defined by EIP-4881.
|
||||
)
|
||||
|
||||
// MerkleTreeNode is the interface for a Merkle tree.
|
||||
type MerkleTreeNode interface {
|
||||
// GetRoot returns the root of the Merkle tree.
|
||||
GetRoot() [32]byte
|
||||
// IsFull returns whether there is space left for deposits.
|
||||
IsFull() bool
|
||||
// Finalize marks deposits of the Merkle tree as finalized.
|
||||
Finalize(deposits uint, depth uint) MerkleTreeNode
|
||||
// GetFinalized returns a list of hashes of all the finalized nodes and the number of deposits.
|
||||
GetFinalized(result [][32]byte) ([][32]byte, uint)
|
||||
// PushLeaf adds a new leaf node at the next available Zero node.
|
||||
PushLeaf(leaf [32]byte, deposits uint, depth uint) MerkleTreeNode
|
||||
}
|
||||
2
beacon-chain/cache/payload_id.go
vendored
2
beacon-chain/cache/payload_id.go
vendored
@@ -57,7 +57,7 @@ func (f *ProposerPayloadIDsCache) SetProposerAndPayloadIDs(slot types.Slot, vId
|
||||
ids, ok := f.slotToProposerAndPayloadIDs[k]
|
||||
// Ok to overwrite if the slot is already set but the cached payload ID is not set.
|
||||
// This combats the re-org case where payload assignment could change at the start of the epoch.
|
||||
byte8 := [vIdLength]byte{}
|
||||
var byte8 [vIdLength]byte
|
||||
if !ok || (ok && bytes.Equal(ids[vIdLength:], byte8[:])) {
|
||||
f.slotToProposerAndPayloadIDs[k] = bs
|
||||
}
|
||||
|
||||
2
beacon-chain/cache/payload_id_test.go
vendored
2
beacon-chain/cache/payload_id_test.go
vendored
@@ -9,7 +9,7 @@ import (
|
||||
|
||||
func TestValidatorPayloadIDsCache_GetAndSaveValidatorPayloadIDs(t *testing.T) {
|
||||
cache := NewProposerPayloadIDsCache()
|
||||
r := [32]byte{}
|
||||
var r [32]byte
|
||||
i, p, ok := cache.GetProposerPayloadIDs(0, r)
|
||||
require.Equal(t, false, ok)
|
||||
require.Equal(t, types.ValidatorIndex(0), i)
|
||||
|
||||
6
beacon-chain/cache/skip_slot_cache_test.go
vendored
6
beacon-chain/cache/skip_slot_cache_test.go
vendored
@@ -6,7 +6,7 @@ import (
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/cache"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state"
|
||||
v1 "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/v1"
|
||||
state_native "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/state-native"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v3/testing/assert"
|
||||
"github.com/prysmaticlabs/prysm/v3/testing/require"
|
||||
@@ -23,7 +23,7 @@ func TestSkipSlotCache_RoundTrip(t *testing.T) {
|
||||
|
||||
require.NoError(t, c.MarkInProgress(r))
|
||||
|
||||
s, err = v1.InitializeFromProto(ðpb.BeaconState{
|
||||
s, err = state_native.InitializeFromProtoPhase0(ðpb.BeaconState{
|
||||
Slot: 10,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
@@ -33,5 +33,5 @@ func TestSkipSlotCache_RoundTrip(t *testing.T) {
|
||||
|
||||
res, err := c.Get(ctx, r)
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, res.CloneInnerState(), s.CloneInnerState(), "Expected equal protos to return from cache")
|
||||
assert.DeepEqual(t, res.ToProto(), s.ToProto(), "Expected equal protos to return from cache")
|
||||
}
|
||||
|
||||
@@ -52,9 +52,8 @@ func (c *SyncCommitteeHeadStateCache) Get(slot types.Slot) (state.BeaconState, e
|
||||
if !ok {
|
||||
return nil, ErrIncorrectType
|
||||
}
|
||||
switch st.Version() {
|
||||
case version.Altair, version.Bellatrix:
|
||||
default:
|
||||
// Sync committee is not supported in phase 0.
|
||||
if st.Version() == version.Phase0 {
|
||||
return nil, ErrIncorrectType
|
||||
}
|
||||
return st, nil
|
||||
|
||||
@@ -4,9 +4,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state"
|
||||
v1 "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/v1"
|
||||
v2 "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/v2"
|
||||
v3 "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/v3"
|
||||
state_native "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/state-native"
|
||||
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||
@@ -14,21 +12,28 @@ import (
|
||||
)
|
||||
|
||||
func TestSyncCommitteeHeadState(t *testing.T) {
|
||||
beaconState, err := v2.InitializeFromProto(ðpb.BeaconStateAltair{
|
||||
beaconState, err := state_native.InitializeFromProtoAltair(ðpb.BeaconStateAltair{
|
||||
Fork: ðpb.Fork{
|
||||
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
phase0State, err := v1.InitializeFromProto(ðpb.BeaconState{
|
||||
phase0State, err := state_native.InitializeFromProtoPhase0(ðpb.BeaconState{
|
||||
Fork: ðpb.Fork{
|
||||
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
bellatrixState, err := v3.InitializeFromProto(ðpb.BeaconStateBellatrix{
|
||||
bellatrixState, err := state_native.InitializeFromProtoBellatrix(ðpb.BeaconStateBellatrix{
|
||||
Fork: ðpb.Fork{
|
||||
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
capellaState, err := state_native.InitializeFromProtoCapella(ðpb.BeaconStateCapella{
|
||||
Fork: ðpb.Fork{
|
||||
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
@@ -108,6 +113,15 @@ func TestSyncCommitteeHeadState(t *testing.T) {
|
||||
},
|
||||
want: bellatrixState,
|
||||
},
|
||||
{
|
||||
name: "found with key (capella state)",
|
||||
key: types.Slot(200),
|
||||
put: &put{
|
||||
slot: types.Slot(200),
|
||||
state: capellaState,
|
||||
},
|
||||
want: capellaState,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
||||
@@ -14,13 +14,7 @@ go_library(
|
||||
"upgrade.go",
|
||||
],
|
||||
importpath = "github.com/prysmaticlabs/prysm/v3/beacon-chain/core/altair",
|
||||
visibility = [
|
||||
"//beacon-chain:__subpackages__",
|
||||
"//testing/endtoend/evaluators:__subpackages__",
|
||||
"//testing/spectest:__subpackages__",
|
||||
"//testing/util:__pkg__",
|
||||
"//validator/client:__pkg__",
|
||||
],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//beacon-chain/core/blocks:go_default_library",
|
||||
"//beacon-chain/core/epoch:go_default_library",
|
||||
@@ -30,7 +24,7 @@ go_library(
|
||||
"//beacon-chain/core/time:go_default_library",
|
||||
"//beacon-chain/p2p/types:go_default_library",
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//beacon-chain/state/v2:go_default_library",
|
||||
"//beacon-chain/state/state-native:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//consensus-types/blocks:go_default_library",
|
||||
@@ -58,6 +52,7 @@ go_test(
|
||||
"deposit_test.go",
|
||||
"epoch_precompute_test.go",
|
||||
"epoch_spec_test.go",
|
||||
"exports_test.go",
|
||||
"reward_test.go",
|
||||
"sync_committee_test.go",
|
||||
"transition_test.go",
|
||||
@@ -72,8 +67,7 @@ go_test(
|
||||
"//beacon-chain/core/time:go_default_library",
|
||||
"//beacon-chain/p2p/types:go_default_library",
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//beacon-chain/state/v2:go_default_library",
|
||||
"//beacon-chain/state/v3:go_default_library",
|
||||
"//beacon-chain/state/state-native:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//consensus-types/blocks:go_default_library",
|
||||
|
||||
@@ -82,23 +82,24 @@ func ProcessAttestationNoVerifySignature(
|
||||
// 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
|
||||
// # 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
|
||||
//
|
||||
// # 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)
|
||||
// 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(
|
||||
ctx context.Context,
|
||||
beaconState state.BeaconState,
|
||||
@@ -157,12 +158,13 @@ func AddValidatorFlag(flag, flagPosition uint8) (uint8, error) {
|
||||
// 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
|
||||
//
|
||||
// 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, totalBalance uint64) (uint64, []byte, error) {
|
||||
cfg := params.BeaconConfig()
|
||||
sourceFlagIndex := cfg.TimelySourceFlagIndex
|
||||
@@ -218,9 +220,10 @@ func EpochParticipation(beaconState state.BeaconState, indices []uint64, epochPa
|
||||
// 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)
|
||||
//
|
||||
// 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(ctx context.Context, beaconState state.BeaconState, proposerRewardNumerator uint64) error {
|
||||
cfg := params.BeaconConfig()
|
||||
d := (cfg.WeightDenominator - cfg.ProposerWeight) * cfg.WeightDenominator / cfg.ProposerWeight
|
||||
@@ -238,31 +241,32 @@ func RewardProposer(ctx context.Context, beaconState state.BeaconState, proposer
|
||||
//
|
||||
// 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
|
||||
// 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
|
||||
//
|
||||
// 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)
|
||||
// # 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
|
||||
//
|
||||
// return participation_flag_indices
|
||||
// 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.BeaconState, data *ethpb.AttestationData, delay types.Slot) (map[uint8]bool, error) {
|
||||
currEpoch := time.CurrentEpoch(beaconState)
|
||||
var justifiedCheckpt *ethpb.Checkpoint
|
||||
@@ -304,9 +308,10 @@ func AttestationParticipationFlagIndices(beaconState state.BeaconState, data *et
|
||||
// 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)
|
||||
//
|
||||
// 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, matchedTgt, matchedHead bool, err error) {
|
||||
matchedSrc = attestation.CheckPointIsEqual(data.Source, cp)
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/signing"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/time"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state"
|
||||
stateAltair "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/v2"
|
||||
state_native "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/state-native"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/v3/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||
"github.com/prysmaticlabs/prysm/v3/consensus-types/blocks"
|
||||
@@ -256,7 +256,7 @@ func TestProcessAttestationNoVerify_SourceTargetHead(t *testing.T) {
|
||||
},
|
||||
AggregationBits: aggBits,
|
||||
}
|
||||
zeroSig := [96]byte{}
|
||||
var zeroSig [96]byte
|
||||
att.Signature = zeroSig[:]
|
||||
|
||||
ckp := beaconState.CurrentJustifiedCheckpoint()
|
||||
@@ -419,7 +419,7 @@ func TestFuzzProcessAttestationsNoVerify_10000(t *testing.T) {
|
||||
if b.Block == nil {
|
||||
b.Block = ðpb.BeaconBlockAltair{}
|
||||
}
|
||||
s, err := stateAltair.InitializeFromProtoUnsafe(st)
|
||||
s, err := state_native.InitializeFromProtoUnsafeAltair(st)
|
||||
require.NoError(t, err)
|
||||
if b.Block == nil || b.Block.Body == nil {
|
||||
continue
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
p2pType "github.com/prysmaticlabs/prysm/v3/beacon-chain/p2p/types"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||
"github.com/prysmaticlabs/prysm/v3/crypto/bls"
|
||||
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||
@@ -20,32 +19,33 @@ import (
|
||||
//
|
||||
// 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))
|
||||
// # 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)
|
||||
//
|
||||
// # 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)
|
||||
// # 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(ctx context.Context, s state.BeaconState, sync *ethpb.SyncAggregate) (state.BeaconState, error) {
|
||||
votedKeys, votedIndices, didntVoteIndices, err := FilterSyncCommitteeVotes(s, sync)
|
||||
s, votedKeys, err := processSyncAggregate(ctx, s, sync)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not filter sync committee votes")
|
||||
}
|
||||
@@ -53,50 +53,70 @@ func ProcessSyncAggregate(ctx context.Context, s state.BeaconState, sync *ethpb.
|
||||
if err := VerifySyncCommitteeSig(s, votedKeys, sync.SyncCommitteeSignature); err != nil {
|
||||
return nil, errors.Wrap(err, "could not verify sync committee signature")
|
||||
}
|
||||
|
||||
return ApplySyncRewardsPenalties(ctx, s, votedIndices, didntVoteIndices)
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// FilterSyncCommitteeVotes filters the validator public keys and indices for the ones that voted and didn't vote.
|
||||
func FilterSyncCommitteeVotes(s state.BeaconState, sync *ethpb.SyncAggregate) (
|
||||
votedKeys []bls.PublicKey,
|
||||
votedIndices []types.ValidatorIndex,
|
||||
didntVoteIndices []types.ValidatorIndex,
|
||||
err error) {
|
||||
// processSyncAggregate applies all the logic in the spec function `process_sync_aggregate` except
|
||||
// verifying the BLS signatures. It returns the modified beacons state and the list of validators'
|
||||
// public keys that voted, for future signature verification.
|
||||
func processSyncAggregate(ctx context.Context, s state.BeaconState, sync *ethpb.SyncAggregate) (
|
||||
state.BeaconState,
|
||||
[]bls.PublicKey,
|
||||
error) {
|
||||
currentSyncCommittee, err := s.CurrentSyncCommittee()
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
if currentSyncCommittee == nil {
|
||||
return nil, nil, nil, errors.New("nil current sync committee in state")
|
||||
return 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")
|
||||
return 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.
|
||||
votedKeys := make([]bls.PublicKey, 0, len(committeeKeys))
|
||||
|
||||
activeBalance, err := helpers.TotalActiveBalance(s)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
proposerReward, participantReward, err := SyncRewards(activeBalance)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
proposerIndex, err := helpers.BeaconProposerIndex(ctx, s)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
earnedProposerReward := uint64(0)
|
||||
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")
|
||||
return 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
|
||||
return nil, nil, err
|
||||
}
|
||||
votedKeys = append(votedKeys, pubKey)
|
||||
votedIndices = append(votedIndices, vIdx)
|
||||
if err := helpers.IncreaseBalance(s, vIdx, participantReward); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
earnedProposerReward += proposerReward
|
||||
} else {
|
||||
didntVoteIndices = append(didntVoteIndices, vIdx)
|
||||
if err := helpers.DecreaseBalance(s, vIdx, participantReward); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
if err := helpers.IncreaseBalance(s, proposerIndex, earnedProposerReward); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return s, votedKeys, err
|
||||
}
|
||||
|
||||
// VerifySyncCommitteeSig verifies sync committee signature `syncSig` is valid with respect to public keys `syncKeys`.
|
||||
@@ -125,43 +145,6 @@ func VerifySyncCommitteeSig(s state.BeaconState, syncKeys []bls.PublicKey, syncS
|
||||
return nil
|
||||
}
|
||||
|
||||
// ApplySyncRewardsPenalties applies rewards and penalties for proposer and sync committee participants.
|
||||
func ApplySyncRewardsPenalties(ctx context.Context, s state.BeaconState, votedIndices, didntVoteIndices []types.ValidatorIndex) (state.BeaconState, 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(ctx, 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, participantReward uint64, err error) {
|
||||
cfg := params.BeaconConfig()
|
||||
|
||||
@@ -168,7 +168,36 @@ func TestProcessSyncCommittee_MixParticipation_GoodSignature(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestProcessSyncCommittee_FilterSyncCommitteeVotes(t *testing.T) {
|
||||
// This is a regression test #11696
|
||||
func TestProcessSyncCommittee_DontPrecompute(t *testing.T) {
|
||||
beaconState, _ := util.DeterministicGenesisStateAltair(t, params.BeaconConfig().MaxValidatorsPerCommittee)
|
||||
require.NoError(t, beaconState.SetSlot(1))
|
||||
committee, err := altair.NextSyncCommittee(context.Background(), beaconState)
|
||||
require.NoError(t, err)
|
||||
committeeKeys := committee.Pubkeys
|
||||
committeeKeys[1] = committeeKeys[0]
|
||||
require.NoError(t, beaconState.SetCurrentSyncCommittee(committee))
|
||||
idx, ok := beaconState.ValidatorIndexByPubkey(bytesutil.ToBytes48(committeeKeys[0]))
|
||||
require.Equal(t, true, ok)
|
||||
|
||||
syncBits := bitfield.NewBitvector512()
|
||||
for i := range syncBits {
|
||||
syncBits[i] = 0xFF
|
||||
}
|
||||
syncBits.SetBitAt(0, false)
|
||||
syncAggregate := ðpb.SyncAggregate{
|
||||
SyncCommitteeBits: syncBits,
|
||||
}
|
||||
require.NoError(t, beaconState.UpdateBalancesAtIndex(idx, 0))
|
||||
st, votedKeys, err := altair.ProcessSyncAggregateEported(context.Background(), beaconState, syncAggregate)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 511, len(votedKeys))
|
||||
require.DeepEqual(t, committeeKeys[0], votedKeys[0].Marshal())
|
||||
balances := st.Balances()
|
||||
require.Equal(t, uint64(988), balances[idx])
|
||||
}
|
||||
|
||||
func TestProcessSyncCommittee_processSyncAggregate(t *testing.T) {
|
||||
beaconState, _ := util.DeterministicGenesisStateAltair(t, params.BeaconConfig().MaxValidatorsPerCommittee)
|
||||
require.NoError(t, beaconState.SetSlot(1))
|
||||
committee, err := altair.NextSyncCommittee(context.Background(), beaconState)
|
||||
@@ -183,25 +212,40 @@ func TestProcessSyncCommittee_FilterSyncCommitteeVotes(t *testing.T) {
|
||||
SyncCommitteeBits: syncBits,
|
||||
}
|
||||
|
||||
votedKeys, votedIndices, didntVoteIndices, err := altair.FilterSyncCommitteeVotes(beaconState, syncAggregate)
|
||||
st, votedKeys, err := altair.ProcessSyncAggregateEported(context.Background(), beaconState, syncAggregate)
|
||||
require.NoError(t, err)
|
||||
votedMap := make(map[[fieldparams.BLSPubkeyLength]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))
|
||||
|
||||
currentSyncCommittee, err := st.CurrentSyncCommittee()
|
||||
require.NoError(t, err)
|
||||
committeeKeys := currentSyncCommittee.Pubkeys
|
||||
balances := st.Balances()
|
||||
|
||||
proposerIndex, err := helpers.BeaconProposerIndex(context.Background(), beaconState)
|
||||
require.NoError(t, err)
|
||||
|
||||
for i := 0; i < len(syncBits); i++ {
|
||||
if syncBits.BitAt(uint64(i)) {
|
||||
pk := beaconState.PubkeyAtIndex(votedIndices[i])
|
||||
pk := bytesutil.ToBytes48(committeeKeys[i])
|
||||
require.DeepEqual(t, true, votedMap[pk])
|
||||
idx, ok := st.ValidatorIndexByPubkey(pk)
|
||||
require.Equal(t, true, ok)
|
||||
require.Equal(t, uint64(32000000988), balances[idx])
|
||||
} else {
|
||||
pk := beaconState.PubkeyAtIndex(didntVoteIndices[i])
|
||||
pk := bytesutil.ToBytes48(committeeKeys[i])
|
||||
require.DeepEqual(t, false, votedMap[pk])
|
||||
idx, ok := st.ValidatorIndexByPubkey(pk)
|
||||
require.Equal(t, true, ok)
|
||||
if idx != proposerIndex {
|
||||
require.Equal(t, uint64(31999999012), balances[idx])
|
||||
}
|
||||
}
|
||||
}
|
||||
require.Equal(t, uint64(32000035108), balances[proposerIndex])
|
||||
}
|
||||
|
||||
func Test_VerifySyncCommitteeSig(t *testing.T) {
|
||||
@@ -240,22 +284,6 @@ func Test_VerifySyncCommitteeSig(t *testing.T) {
|
||||
require.NoError(t, altair.VerifySyncCommitteeSig(beaconState, pks, aggregatedSig))
|
||||
}
|
||||
|
||||
func Test_ApplySyncRewardsPenalties(t *testing.T) {
|
||||
beaconState, _ := util.DeterministicGenesisStateAltair(t, params.BeaconConfig().MaxValidatorsPerCommittee)
|
||||
beaconState, err := altair.ApplySyncRewardsPenalties(context.Background(), 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(context.Background(), beaconState)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, uint64(32000000282), balances[proposerIndex])
|
||||
}
|
||||
|
||||
func Test_SyncRewards(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
|
||||
fuzz "github.com/google/gofuzz"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/altair"
|
||||
stateAltair "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/v2"
|
||||
state_native "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/state-native"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v3/testing/require"
|
||||
)
|
||||
@@ -21,7 +21,7 @@ func TestFuzzProcessDeposits_10000(t *testing.T) {
|
||||
for i := range deposits {
|
||||
fuzzer.Fuzz(deposits[i])
|
||||
}
|
||||
s, err := stateAltair.InitializeFromProtoUnsafe(state)
|
||||
s, err := state_native.InitializeFromProtoUnsafeAltair(state)
|
||||
require.NoError(t, err)
|
||||
r, err := altair.ProcessDeposits(ctx, s, deposits)
|
||||
if err != nil && r != nil {
|
||||
@@ -38,7 +38,7 @@ func TestFuzzProcessDeposit_10000(t *testing.T) {
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(deposit)
|
||||
s, err := stateAltair.InitializeFromProtoUnsafe(state)
|
||||
s, err := state_native.InitializeFromProtoUnsafeAltair(state)
|
||||
require.NoError(t, err)
|
||||
r, err := altair.ProcessDeposit(s, deposit, true)
|
||||
if err != nil && r != nil {
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/altair"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/signing"
|
||||
stateAltair "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/v2"
|
||||
state_native "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/state-native"
|
||||
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||
"github.com/prysmaticlabs/prysm/v3/container/trie"
|
||||
"github.com/prysmaticlabs/prysm/v3/crypto/bls"
|
||||
@@ -29,7 +29,7 @@ func TestProcessDeposits_SameValidatorMultipleDepositsSameBlock(t *testing.T) {
|
||||
},
|
||||
}
|
||||
balances := []uint64{0}
|
||||
beaconState, err := stateAltair.InitializeFromProto(ðpb.BeaconStateAltair{
|
||||
beaconState, err := state_native.InitializeFromProtoAltair(ðpb.BeaconStateAltair{
|
||||
Validators: registry,
|
||||
Balances: balances,
|
||||
Eth1Data: eth1Data,
|
||||
@@ -62,7 +62,7 @@ func TestProcessDeposits_MerkleBranchFailsVerification(t *testing.T) {
|
||||
require.NoError(t, err, "Could not generate proof")
|
||||
|
||||
deposit.Proof = proof
|
||||
beaconState, err := stateAltair.InitializeFromProto(ðpb.BeaconStateAltair{
|
||||
beaconState, err := state_native.InitializeFromProtoAltair(ðpb.BeaconStateAltair{
|
||||
Eth1Data: ðpb.Eth1Data{
|
||||
DepositRoot: []byte{0},
|
||||
BlockHash: []byte{1},
|
||||
@@ -87,7 +87,7 @@ func TestProcessDeposits_AddsNewValidatorDeposit(t *testing.T) {
|
||||
},
|
||||
}
|
||||
balances := []uint64{0}
|
||||
beaconState, err := stateAltair.InitializeFromProto(ðpb.BeaconStateAltair{
|
||||
beaconState, err := state_native.InitializeFromProtoAltair(ðpb.BeaconStateAltair{
|
||||
Validators: registry,
|
||||
Balances: balances,
|
||||
Eth1Data: eth1Data,
|
||||
@@ -145,7 +145,7 @@ func TestProcessDeposits_RepeatedDeposit_IncreasesValidatorBalance(t *testing.T)
|
||||
balances := []uint64{0, 50}
|
||||
root, err := depositTrie.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
beaconState, err := stateAltair.InitializeFromProto(ðpb.BeaconStateAltair{
|
||||
beaconState, err := state_native.InitializeFromProtoAltair(ðpb.BeaconStateAltair{
|
||||
Validators: registry,
|
||||
Balances: balances,
|
||||
Eth1Data: ðpb.Eth1Data{
|
||||
@@ -173,7 +173,7 @@ func TestProcessDeposit_AddsNewValidatorDeposit(t *testing.T) {
|
||||
},
|
||||
}
|
||||
balances := []uint64{0}
|
||||
beaconState, err := stateAltair.InitializeFromProto(ðpb.BeaconStateAltair{
|
||||
beaconState, err := state_native.InitializeFromProtoAltair(ðpb.BeaconStateAltair{
|
||||
Validators: registry,
|
||||
Balances: balances,
|
||||
Eth1Data: eth1Data,
|
||||
@@ -216,7 +216,7 @@ func TestProcessDeposit_SkipsInvalidDeposit(t *testing.T) {
|
||||
},
|
||||
}
|
||||
balances := []uint64{0}
|
||||
beaconState, err := stateAltair.InitializeFromProto(ðpb.BeaconStateAltair{
|
||||
beaconState, err := state_native.InitializeFromProtoAltair(ðpb.BeaconStateAltair{
|
||||
Validators: registry,
|
||||
Balances: balances,
|
||||
Eth1Data: eth1Data,
|
||||
|
||||
@@ -68,9 +68,10 @@ func InitializePrecomputeValidators(ctx context.Context, beaconState state.Beaco
|
||||
// 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.
|
||||
//
|
||||
// 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,
|
||||
beaconState state.BeaconState,
|
||||
@@ -132,12 +133,13 @@ func ProcessInactivityScores(
|
||||
// it also tracks and updates epoch attesting balances.
|
||||
// Spec code:
|
||||
// if epoch == get_current_epoch(state):
|
||||
// epoch_participation = state.current_epoch_participation
|
||||
// else:
|
||||
// epoch_participation = state.previous_epoch_participation
|
||||
// active_validator_indices = get_active_validator_indices(state, epoch)
|
||||
// participating_indices = [i for i in active_validator_indices if has_flag(epoch_participation[i], flag_index)]
|
||||
// return set(filter(lambda index: not state.validators[index].slashed, participating_indices))
|
||||
//
|
||||
// epoch_participation = state.current_epoch_participation
|
||||
// else:
|
||||
// epoch_participation = state.previous_epoch_participation
|
||||
// active_validator_indices = get_active_validator_indices(state, epoch)
|
||||
// participating_indices = [i for i in active_validator_indices if has_flag(epoch_participation[i], flag_index)]
|
||||
// return set(filter(lambda index: not state.validators[index].slashed, participating_indices))
|
||||
func ProcessEpochParticipation(
|
||||
ctx context.Context,
|
||||
beaconState state.BeaconState,
|
||||
|
||||
@@ -7,8 +7,7 @@ import (
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/epoch/precompute"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state"
|
||||
stateAltair "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/v2"
|
||||
v3 "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/v3"
|
||||
state_native "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/state-native"
|
||||
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||
@@ -18,7 +17,7 @@ import (
|
||||
|
||||
func TestInitializeEpochValidators_Ok(t *testing.T) {
|
||||
ffe := params.BeaconConfig().FarFutureEpoch
|
||||
s, err := stateAltair.InitializeFromProto(ðpb.BeaconStateAltair{
|
||||
s, err := state_native.InitializeFromProtoAltair(ðpb.BeaconStateAltair{
|
||||
Slot: params.BeaconConfig().SlotsPerEpoch,
|
||||
// Validator 0 is slashed
|
||||
// Validator 1 is withdrawable
|
||||
@@ -66,7 +65,7 @@ func TestInitializeEpochValidators_Ok(t *testing.T) {
|
||||
|
||||
func TestInitializeEpochValidators_Overflow(t *testing.T) {
|
||||
ffe := params.BeaconConfig().FarFutureEpoch
|
||||
s, err := stateAltair.InitializeFromProto(ðpb.BeaconStateAltair{
|
||||
s, err := state_native.InitializeFromProtoAltair(ðpb.BeaconStateAltair{
|
||||
Slot: params.BeaconConfig().SlotsPerEpoch,
|
||||
Validators: []*ethpb.Validator{
|
||||
{WithdrawableEpoch: ffe, ExitEpoch: ffe, EffectiveBalance: math.MaxUint64},
|
||||
@@ -80,7 +79,7 @@ func TestInitializeEpochValidators_Overflow(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestInitializeEpochValidators_BadState(t *testing.T) {
|
||||
s, err := stateAltair.InitializeFromProto(ðpb.BeaconStateAltair{
|
||||
s, err := state_native.InitializeFromProtoAltair(ðpb.BeaconStateAltair{
|
||||
Validators: []*ethpb.Validator{{}},
|
||||
InactivityScores: []uint64{},
|
||||
})
|
||||
@@ -150,7 +149,7 @@ func TestProcessEpochParticipation_InactiveValidator(t *testing.T) {
|
||||
}
|
||||
return b
|
||||
}
|
||||
st, err := stateAltair.InitializeFromProto(ðpb.BeaconStateAltair{
|
||||
st, err := state_native.InitializeFromProtoAltair(ðpb.BeaconStateAltair{
|
||||
Slot: 2 * params.BeaconConfig().SlotsPerEpoch,
|
||||
Validators: []*ethpb.Validator{
|
||||
{EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance}, // Inactive
|
||||
@@ -468,7 +467,7 @@ func testState() (state.BeaconState, error) {
|
||||
}
|
||||
return b
|
||||
}
|
||||
return stateAltair.InitializeFromProto(ðpb.BeaconStateAltair{
|
||||
return state_native.InitializeFromProtoAltair(ðpb.BeaconStateAltair{
|
||||
Slot: 2 * params.BeaconConfig().SlotsPerEpoch,
|
||||
Validators: []*ethpb.Validator{
|
||||
{EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance, ExitEpoch: params.BeaconConfig().FarFutureEpoch},
|
||||
@@ -505,7 +504,7 @@ func testStateBellatrix() (state.BeaconState, error) {
|
||||
}
|
||||
return b
|
||||
}
|
||||
return v3.InitializeFromProto(ðpb.BeaconStateBellatrix{
|
||||
return state_native.InitializeFromProtoBellatrix(ðpb.BeaconStateBellatrix{
|
||||
Slot: 2 * params.BeaconConfig().SlotsPerEpoch,
|
||||
Validators: []*ethpb.Validator{
|
||||
{EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance, ExitEpoch: params.BeaconConfig().FarFutureEpoch},
|
||||
|
||||
@@ -14,10 +14,11 @@ import (
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
// 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.BeaconState) (state.BeaconState, error) {
|
||||
nextEpoch := time.NextEpoch(beaconState)
|
||||
if nextEpoch%params.BeaconConfig().EpochsPerSyncCommitteePeriod == 0 {
|
||||
@@ -46,8 +47,9 @@ func ProcessSyncCommitteeUpdates(ctx context.Context, beaconState state.BeaconSt
|
||||
//
|
||||
// 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))]
|
||||
//
|
||||
// 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.BeaconState) (state.BeaconState, error) {
|
||||
c, err := beaconState.CurrentEpochParticipation()
|
||||
if err != nil {
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/epoch"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/time"
|
||||
stateAltair "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/v2"
|
||||
state_native "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/state-native"
|
||||
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
||||
@@ -103,7 +103,7 @@ func TestProcessSlashings_NotSlashed(t *testing.T) {
|
||||
Balances: []uint64{params.BeaconConfig().MaxEffectiveBalance},
|
||||
Slashings: []uint64{0, 1e9},
|
||||
}
|
||||
s, err := stateAltair.InitializeFromProto(base)
|
||||
s, err := state_native.InitializeFromProtoAltair(base)
|
||||
require.NoError(t, err)
|
||||
newState, err := epoch.ProcessSlashings(s, params.BeaconConfig().ProportionalSlashingMultiplierAltair)
|
||||
require.NoError(t, err)
|
||||
@@ -174,7 +174,7 @@ func TestProcessSlashings_SlashedLess(t *testing.T) {
|
||||
t.Run(fmt.Sprint(i), func(t *testing.T) {
|
||||
helpers.ClearCache()
|
||||
original := proto.Clone(tt.state)
|
||||
s, err := stateAltair.InitializeFromProto(tt.state)
|
||||
s, err := state_native.InitializeFromProtoAltair(tt.state)
|
||||
require.NoError(t, err)
|
||||
newState, err := epoch.ProcessSlashings(s, params.BeaconConfig().ProportionalSlashingMultiplierAltair)
|
||||
require.NoError(t, err)
|
||||
@@ -190,7 +190,7 @@ func TestProcessSlashings_BadValue(t *testing.T) {
|
||||
Balances: []uint64{params.BeaconConfig().MaxEffectiveBalance},
|
||||
Slashings: []uint64{math.MaxUint64, 1e9},
|
||||
}
|
||||
s, err := stateAltair.InitializeFromProto(base)
|
||||
s, err := state_native.InitializeFromProtoAltair(base)
|
||||
require.NoError(t, err)
|
||||
_, err = epoch.ProcessSlashings(s, params.BeaconConfig().ProportionalSlashingMultiplierAltair)
|
||||
require.ErrorContains(t, "addition overflows", err)
|
||||
|
||||
3
beacon-chain/core/altair/exports_test.go
Normal file
3
beacon-chain/core/altair/exports_test.go
Normal file
@@ -0,0 +1,3 @@
|
||||
package altair
|
||||
|
||||
var ProcessSyncAggregateEported = processSyncAggregate
|
||||
@@ -13,16 +13,17 @@ import (
|
||||
// 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))
|
||||
// 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 {
|
||||
@@ -50,7 +51,8 @@ func BaseRewardWithTotalBalance(s state.ReadOnlyBeaconState, index types.Validat
|
||||
//
|
||||
// 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)))
|
||||
//
|
||||
// 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")
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/altair"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||
@@ -13,6 +14,7 @@ import (
|
||||
)
|
||||
|
||||
func Test_BaseReward(t *testing.T) {
|
||||
helpers.ClearCache()
|
||||
genState := func(valCount uint64) state.ReadOnlyBeaconState {
|
||||
s, _ := util.DeterministicGenesisStateAltair(t, valCount)
|
||||
return s
|
||||
@@ -66,6 +68,7 @@ func Test_BaseReward(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_BaseRewardWithTotalBalance(t *testing.T) {
|
||||
helpers.ClearCache()
|
||||
s, _ := util.DeterministicGenesisStateAltair(t, 1)
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -137,6 +140,7 @@ func Test_BaseRewardWithTotalBalance(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_BaseRewardPerIncrement(t *testing.T) {
|
||||
helpers.ClearCache()
|
||||
tests := []struct {
|
||||
name string
|
||||
activeBalance uint64
|
||||
|
||||
@@ -47,13 +47,14 @@ func ValidateNilSyncContribution(s *ethpb.SignedContributionAndProof) error {
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
// """
|
||||
// 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.BeaconState) (*ethpb.SyncCommittee, error) {
|
||||
indices, err := NextSyncCommitteeIndices(ctx, s)
|
||||
if err != nil {
|
||||
@@ -78,26 +79,27 @@ func NextSyncCommittee(ctx context.Context, s state.BeaconState) (*ethpb.SyncCom
|
||||
//
|
||||
// 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
|
||||
// """
|
||||
// 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.BeaconState) ([]types.ValidatorIndex, error) {
|
||||
epoch := coreTime.NextEpoch(s)
|
||||
indices, err := helpers.ActiveValidatorIndices(ctx, s, epoch)
|
||||
@@ -144,18 +146,19 @@ func NextSyncCommitteeIndices(ctx context.Context, s state.BeaconState) ([]types
|
||||
// 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]
|
||||
// # 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
|
||||
@@ -172,8 +175,9 @@ func SyncSubCommitteePubkeys(syncCommittee *ethpb.SyncCommittee, subComIdx types
|
||||
// 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
|
||||
//
|
||||
// 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) != fieldparams.BLSSignatureLength {
|
||||
return false, errors.New("incorrect sig length")
|
||||
|
||||
@@ -8,8 +8,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/altair"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state"
|
||||
stateAltair "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/v2"
|
||||
v2 "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/v2"
|
||||
state_native "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/state-native"
|
||||
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||
"github.com/prysmaticlabs/prysm/v3/crypto/bls"
|
||||
@@ -28,7 +27,7 @@ func TestSyncCommitteeIndices_CanGet(t *testing.T) {
|
||||
EffectiveBalance: params.BeaconConfig().MinDepositAmount,
|
||||
}
|
||||
}
|
||||
st, err := stateAltair.InitializeFromProto(ðpb.BeaconStateAltair{
|
||||
st, err := state_native.InitializeFromProtoAltair(ðpb.BeaconStateAltair{
|
||||
Validators: validators,
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
})
|
||||
@@ -46,14 +45,6 @@ func TestSyncCommitteeIndices_CanGet(t *testing.T) {
|
||||
wantErr bool
|
||||
errString string
|
||||
}{
|
||||
{
|
||||
name: "nil inner state",
|
||||
args: args{
|
||||
state: &v2.BeaconState{},
|
||||
},
|
||||
wantErr: true,
|
||||
errString: "nil inner state",
|
||||
},
|
||||
{
|
||||
name: "genesis validator count, epoch 0",
|
||||
args: args{
|
||||
@@ -103,7 +94,7 @@ func TestSyncCommitteeIndices_DifferentPeriods(t *testing.T) {
|
||||
EffectiveBalance: params.BeaconConfig().MinDepositAmount,
|
||||
}
|
||||
}
|
||||
st, err := stateAltair.InitializeFromProto(ðpb.BeaconStateAltair{
|
||||
st, err := state_native.InitializeFromProtoAltair(ðpb.BeaconStateAltair{
|
||||
Validators: validators,
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
})
|
||||
@@ -140,7 +131,7 @@ func TestSyncCommittee_CanGet(t *testing.T) {
|
||||
PublicKey: blsKey.PublicKey().Marshal(),
|
||||
}
|
||||
}
|
||||
st, err := stateAltair.InitializeFromProto(ðpb.BeaconStateAltair{
|
||||
st, err := state_native.InitializeFromProtoAltair(ðpb.BeaconStateAltair{
|
||||
Validators: validators,
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
})
|
||||
@@ -158,14 +149,6 @@ func TestSyncCommittee_CanGet(t *testing.T) {
|
||||
wantErr bool
|
||||
errString string
|
||||
}{
|
||||
{
|
||||
name: "nil inner state",
|
||||
args: args{
|
||||
state: &v2.BeaconState{},
|
||||
},
|
||||
wantErr: true,
|
||||
errString: "nil inner state",
|
||||
},
|
||||
{
|
||||
name: "genesis validator count, epoch 0",
|
||||
args: args{
|
||||
@@ -395,7 +378,7 @@ func getState(t *testing.T, count uint64) state.BeaconState {
|
||||
PublicKey: blsKey.PublicKey().Marshal(),
|
||||
}
|
||||
}
|
||||
st, err := stateAltair.InitializeFromProto(ðpb.BeaconStateAltair{
|
||||
st, err := state_native.InitializeFromProtoAltair(ðpb.BeaconStateAltair{
|
||||
Validators: validators,
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
})
|
||||
|
||||
@@ -15,18 +15,19 @@ import (
|
||||
//
|
||||
// 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]
|
||||
//
|
||||
// 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.BeaconState) (state.BeaconState, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "altair.ProcessEpoch")
|
||||
defer span.End()
|
||||
@@ -92,7 +93,7 @@ func ProcessEpoch(ctx context.Context, state state.BeaconState) (state.BeaconSta
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
state, err = e.ProcessHistoricalRootsUpdate(state)
|
||||
state, err = e.ProcessHistoricalDataUpdate(state)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/time"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state"
|
||||
statealtair "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/v2"
|
||||
state_native "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/state-native"
|
||||
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1/attestation"
|
||||
@@ -16,56 +16,61 @@ import (
|
||||
//
|
||||
// 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
|
||||
// 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.BeaconState, error) {
|
||||
epoch := time.CurrentEpoch(state)
|
||||
|
||||
numValidators := state.NumValidators()
|
||||
hrs, err := state.HistoricalRoots()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s := ðpb.BeaconStateAltair{
|
||||
GenesisTime: state.GenesisTime(),
|
||||
GenesisValidatorsRoot: state.GenesisValidatorsRoot(),
|
||||
@@ -78,7 +83,7 @@ func UpgradeToAltair(ctx context.Context, state state.BeaconState) (state.Beacon
|
||||
LatestBlockHeader: state.LatestBlockHeader(),
|
||||
BlockRoots: state.BlockRoots(),
|
||||
StateRoots: state.StateRoots(),
|
||||
HistoricalRoots: state.HistoricalRoots(),
|
||||
HistoricalRoots: hrs,
|
||||
Eth1Data: state.Eth1Data(),
|
||||
Eth1DataVotes: state.Eth1DataVotes(),
|
||||
Eth1DepositIndex: state.Eth1DepositIndex(),
|
||||
@@ -95,7 +100,7 @@ func UpgradeToAltair(ctx context.Context, state state.BeaconState) (state.Beacon
|
||||
InactivityScores: make([]uint64, numValidators),
|
||||
}
|
||||
|
||||
newState, err := statealtair.InitializeFromProtoUnsafe(s)
|
||||
newState, err := state_native.InitializeFromProtoUnsafeAltair(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -126,17 +131,18 @@ func UpgradeToAltair(ctx context.Context, state state.BeaconState) (state.Beacon
|
||||
//
|
||||
// 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)
|
||||
// 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(ctx context.Context, state state.BeaconState, atts []*ethpb.PendingAttestation) (state.BeaconState, error) {
|
||||
epochParticipation, err := state.PreviousEpochParticipation()
|
||||
if err != nil {
|
||||
|
||||
@@ -82,7 +82,11 @@ func TestUpgradeToAltair(t *testing.T) {
|
||||
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())
|
||||
r1, err := preForkState.HistoricalRoots()
|
||||
require.NoError(t, err)
|
||||
r2, err := aState.HistoricalRoots()
|
||||
require.NoError(t, err)
|
||||
require.DeepSSZEqual(t, r1, r2)
|
||||
require.DeepSSZEqual(t, preForkState.Eth1Data(), aState.Eth1Data())
|
||||
require.DeepSSZEqual(t, preForkState.Eth1DataVotes(), aState.Eth1DataVotes())
|
||||
require.DeepSSZEqual(t, preForkState.Eth1DepositIndex(), aState.Eth1DepositIndex())
|
||||
|
||||
@@ -19,12 +19,7 @@ go_library(
|
||||
"withdrawals.go",
|
||||
],
|
||||
importpath = "github.com/prysmaticlabs/prysm/v3/beacon-chain/core/blocks",
|
||||
visibility = [
|
||||
"//beacon-chain:__subpackages__",
|
||||
"//testing/spectest:__subpackages__",
|
||||
"//testing/util:__pkg__",
|
||||
"//validator:__subpackages__",
|
||||
],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//beacon-chain/core/signing:go_default_library",
|
||||
@@ -41,11 +36,12 @@ go_library(
|
||||
"//contracts/deposit:go_default_library",
|
||||
"//crypto/bls:go_default_library",
|
||||
"//crypto/hash:go_default_library",
|
||||
"//crypto/hash/htr:go_default_library",
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
"//encoding/ssz:go_default_library",
|
||||
"//math:go_default_library",
|
||||
"//network/forks:go_default_library",
|
||||
"//proto/engine/v1:go_default_library",
|
||||
"//proto/eth/v2:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//proto/prysm/v1alpha1/attestation:go_default_library",
|
||||
"//proto/prysm/v1alpha1/slashings:go_default_library",
|
||||
@@ -70,6 +66,7 @@ go_test(
|
||||
"deposit_test.go",
|
||||
"eth1_data_test.go",
|
||||
"exit_test.go",
|
||||
"exports_test.go",
|
||||
"genesis_test.go",
|
||||
"header_test.go",
|
||||
"payload_test.go",
|
||||
@@ -89,17 +86,20 @@ go_test(
|
||||
"//beacon-chain/core/validators:go_default_library",
|
||||
"//beacon-chain/p2p/types:go_default_library",
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//beacon-chain/state/v1:go_default_library",
|
||||
"//beacon-chain/state/state-native:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//consensus-types/blocks:go_default_library",
|
||||
"//consensus-types/interfaces:go_default_library",
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
"//container/trie:go_default_library",
|
||||
"//crypto/bls:go_default_library",
|
||||
"//crypto/hash/htr:go_default_library",
|
||||
"//crypto/bls/common:go_default_library",
|
||||
"//crypto/hash:go_default_library",
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
"//encoding/ssz:go_default_library",
|
||||
"//proto/engine/v1:go_default_library",
|
||||
"//proto/migration:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//proto/prysm/v1alpha1/attestation:go_default_library",
|
||||
"//proto/prysm/v1alpha1/attestation/aggregation:go_default_library",
|
||||
|
||||
@@ -185,19 +185,20 @@ func VerifyAttestationSignature(ctx context.Context, beaconState state.ReadOnlyB
|
||||
// VerifyIndexedAttestation determines the validity of an indexed attestation.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// def is_valid_indexed_attestation(state: BeaconState, indexed_attestation: IndexedAttestation) -> bool:
|
||||
// """
|
||||
// Check if ``indexed_attestation`` is not empty, has sorted and unique indices and has a valid aggregate signature.
|
||||
// """
|
||||
// # Verify indices are sorted and unique
|
||||
// indices = indexed_attestation.attesting_indices
|
||||
// if len(indices) == 0 or not indices == sorted(set(indices)):
|
||||
// return False
|
||||
// # Verify aggregate signature
|
||||
// pubkeys = [state.validators[i].pubkey for i in indices]
|
||||
// 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)
|
||||
//
|
||||
// def is_valid_indexed_attestation(state: BeaconState, indexed_attestation: IndexedAttestation) -> bool:
|
||||
// """
|
||||
// Check if ``indexed_attestation`` is not empty, has sorted and unique indices and has a valid aggregate signature.
|
||||
// """
|
||||
// # Verify indices are sorted and unique
|
||||
// indices = indexed_attestation.attesting_indices
|
||||
// if len(indices) == 0 or not indices == sorted(set(indices)):
|
||||
// return False
|
||||
// # Verify aggregate signature
|
||||
// pubkeys = [state.validators[i].pubkey for i in indices]
|
||||
// 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 state.ReadOnlyBeaconState, indexedAtt *ethpb.IndexedAttestation) error {
|
||||
ctx, span := trace.StartSpan(ctx, "core.VerifyIndexedAttestation")
|
||||
defer span.End()
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
|
||||
"github.com/prysmaticlabs/go-bitfield"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/blocks"
|
||||
v1 "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/v1"
|
||||
state_native "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/state-native"
|
||||
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v3/testing/assert"
|
||||
@@ -36,7 +36,7 @@ func TestProcessAttestationNoVerifySignature_BeaconFuzzIssue78(t *testing.T) {
|
||||
if err := spb.UnmarshalSSZ(stateData); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
st, err := v1.InitializeFromProtoUnsafe(spb)
|
||||
st, err := state_native.InitializeFromProtoUnsafePhase0(spb)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -64,7 +64,7 @@ func TestVerifyAttestationNoVerifySignature_IncorrectSourceEpoch(t *testing.T) {
|
||||
AggregationBits: aggBits,
|
||||
}
|
||||
|
||||
zeroSig := [96]byte{}
|
||||
var zeroSig [96]byte
|
||||
att.Signature = zeroSig[:]
|
||||
|
||||
err := beaconState.SetSlot(beaconState.Slot() + params.BeaconConfig().MinAttestationInclusionDelay)
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/signing"
|
||||
v1 "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/v1"
|
||||
state_native "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/state-native"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/v3/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||
@@ -113,7 +113,7 @@ func TestProcessAttestationsNoVerify_OK(t *testing.T) {
|
||||
AggregationBits: aggBits,
|
||||
}
|
||||
|
||||
zeroSig := [fieldparams.BLSSignatureLength]byte{}
|
||||
var zeroSig [fieldparams.BLSSignatureLength]byte
|
||||
att.Signature = zeroSig[:]
|
||||
|
||||
err := beaconState.SetSlot(beaconState.Slot() + params.BeaconConfig().MinAttestationInclusionDelay)
|
||||
@@ -144,7 +144,7 @@ func TestVerifyAttestationNoVerifySignature_OK(t *testing.T) {
|
||||
AggregationBits: aggBits,
|
||||
}
|
||||
|
||||
zeroSig := [fieldparams.BLSSignatureLength]byte{}
|
||||
var zeroSig [fieldparams.BLSSignatureLength]byte
|
||||
att.Signature = zeroSig[:]
|
||||
|
||||
err := beaconState.SetSlot(beaconState.Slot() + params.BeaconConfig().MinAttestationInclusionDelay)
|
||||
@@ -172,7 +172,7 @@ func TestVerifyAttestationNoVerifySignature_BadAttIdx(t *testing.T) {
|
||||
},
|
||||
AggregationBits: aggBits,
|
||||
}
|
||||
zeroSig := [fieldparams.BLSSignatureLength]byte{}
|
||||
var zeroSig [fieldparams.BLSSignatureLength]byte
|
||||
att.Signature = zeroSig[:]
|
||||
require.NoError(t, beaconState.SetSlot(beaconState.Slot()+params.BeaconConfig().MinAttestationInclusionDelay))
|
||||
ckp := beaconState.CurrentJustifiedCheckpoint()
|
||||
@@ -192,7 +192,7 @@ func TestConvertToIndexed_OK(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
state, err := v1.InitializeFromProto(ðpb.BeaconState{
|
||||
state, err := state_native.InitializeFromProtoPhase0(ðpb.BeaconState{
|
||||
Slot: 5,
|
||||
Validators: validators,
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
@@ -250,7 +250,7 @@ func TestVerifyIndexedAttestation_OK(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
state, err := v1.InitializeFromProto(ðpb.BeaconState{
|
||||
state, err := state_native.InitializeFromProtoPhase0(ðpb.BeaconState{
|
||||
Slot: 5,
|
||||
Validators: validators,
|
||||
Fork: ðpb.Fork{
|
||||
@@ -337,7 +337,7 @@ func TestValidateIndexedAttestation_AboveMaxLength(t *testing.T) {
|
||||
}
|
||||
|
||||
want := "validator indices count exceeds MAX_VALIDATORS_PER_COMMITTEE"
|
||||
st, err := v1.InitializeFromProtoUnsafe(ðpb.BeaconState{})
|
||||
st, err := state_native.InitializeFromProtoUnsafePhase0(ðpb.BeaconState{})
|
||||
require.NoError(t, err)
|
||||
err = blocks.VerifyIndexedAttestation(context.Background(), st, indexedAtt1)
|
||||
assert.ErrorContains(t, want, err)
|
||||
|
||||
@@ -22,20 +22,21 @@ import (
|
||||
// Casper FFG slashing conditions if any slashable events occurred.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// def process_attester_slashing(state: BeaconState, attester_slashing: AttesterSlashing) -> None:
|
||||
// attestation_1 = attester_slashing.attestation_1
|
||||
// attestation_2 = attester_slashing.attestation_2
|
||||
// assert is_slashable_attestation_data(attestation_1.data, attestation_2.data)
|
||||
// assert is_valid_indexed_attestation(state, attestation_1)
|
||||
// assert is_valid_indexed_attestation(state, attestation_2)
|
||||
//
|
||||
// slashed_any = False
|
||||
// indices = set(attestation_1.attesting_indices).intersection(attestation_2.attesting_indices)
|
||||
// for index in sorted(indices):
|
||||
// if is_slashable_validator(state.validators[index], get_current_epoch(state)):
|
||||
// slash_validator(state, index)
|
||||
// slashed_any = True
|
||||
// assert slashed_any
|
||||
// def process_attester_slashing(state: BeaconState, attester_slashing: AttesterSlashing) -> None:
|
||||
// attestation_1 = attester_slashing.attestation_1
|
||||
// attestation_2 = attester_slashing.attestation_2
|
||||
// assert is_slashable_attestation_data(attestation_1.data, attestation_2.data)
|
||||
// assert is_valid_indexed_attestation(state, attestation_1)
|
||||
// assert is_valid_indexed_attestation(state, attestation_2)
|
||||
//
|
||||
// slashed_any = False
|
||||
// indices = set(attestation_1.attesting_indices).intersection(attestation_2.attesting_indices)
|
||||
// for index in sorted(indices):
|
||||
// if is_slashable_validator(state.validators[index], get_current_epoch(state)):
|
||||
// slash_validator(state, index)
|
||||
// slashed_any = True
|
||||
// assert slashed_any
|
||||
func ProcessAttesterSlashings(
|
||||
ctx context.Context,
|
||||
beaconState state.BeaconState,
|
||||
@@ -83,7 +84,7 @@ func ProcessAttesterSlashing(
|
||||
slashingQuotient = cfg.MinSlashingPenaltyQuotient
|
||||
case beaconState.Version() == version.Altair:
|
||||
slashingQuotient = cfg.MinSlashingPenaltyQuotientAltair
|
||||
case beaconState.Version() == version.Bellatrix:
|
||||
case beaconState.Version() >= version.Bellatrix:
|
||||
slashingQuotient = cfg.MinSlashingPenaltyQuotientBellatrix
|
||||
default:
|
||||
return nil, errors.New("unknown state version")
|
||||
@@ -132,16 +133,17 @@ func VerifyAttesterSlashing(ctx context.Context, beaconState state.ReadOnlyBeaco
|
||||
// IsSlashableAttestationData verifies a slashing against the Casper Proof of Stake FFG rules.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// def is_slashable_attestation_data(data_1: AttestationData, data_2: AttestationData) -> bool:
|
||||
// """
|
||||
// Check if ``data_1`` and ``data_2`` are slashable according to Casper FFG rules.
|
||||
// """
|
||||
// return (
|
||||
// # Double vote
|
||||
// (data_1 != data_2 and data_1.target.epoch == data_2.target.epoch) or
|
||||
// # Surround vote
|
||||
// (data_1.source.epoch < data_2.source.epoch and data_2.target.epoch < data_1.target.epoch)
|
||||
// )
|
||||
//
|
||||
// def is_slashable_attestation_data(data_1: AttestationData, data_2: AttestationData) -> bool:
|
||||
// """
|
||||
// Check if ``data_1`` and ``data_2`` are slashable according to Casper FFG rules.
|
||||
// """
|
||||
// return (
|
||||
// # Double vote
|
||||
// (data_1 != data_2 and data_1.target.epoch == data_2.target.epoch) or
|
||||
// # Surround vote
|
||||
// (data_1.source.epoch < data_2.source.epoch and data_2.target.epoch < data_1.target.epoch)
|
||||
// )
|
||||
func IsSlashableAttestationData(data1, data2 *ethpb.AttestationData) bool {
|
||||
if data1 == nil || data2 == nil || data1.Target == nil || data2.Target == nil || data1.Source == nil || data2.Source == nil {
|
||||
return false
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/signing"
|
||||
v "github.com/prysmaticlabs/prysm/v3/beacon-chain/core/validators"
|
||||
v1 "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/v1"
|
||||
state_native "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/state-native"
|
||||
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||
"github.com/prysmaticlabs/prysm/v3/crypto/bls"
|
||||
@@ -46,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 := state_native.InitializeFromProtoPhase0(ðpb.BeaconState{
|
||||
Validators: registry,
|
||||
Slot: currentSlot,
|
||||
})
|
||||
@@ -65,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 := state_native.InitializeFromProtoPhase0(ðpb.BeaconState{
|
||||
Validators: registry,
|
||||
Slot: currentSlot,
|
||||
})
|
||||
@@ -302,3 +302,72 @@ func TestProcessAttesterSlashings_AppliesCorrectStatusBellatrix(t *testing.T) {
|
||||
require.Equal(t, uint64(31000000000), newState.Balances()[1])
|
||||
require.Equal(t, uint64(32000000000), newState.Balances()[2])
|
||||
}
|
||||
|
||||
func TestProcessAttesterSlashings_AppliesCorrectStatusCapella(t *testing.T) {
|
||||
beaconState, privKeys := util.DeterministicGenesisStateCapella(t, 100)
|
||||
for _, vv := range beaconState.Validators() {
|
||||
vv.WithdrawableEpoch = types.Epoch(params.BeaconConfig().SlotsPerEpoch)
|
||||
}
|
||||
|
||||
att1 := util.HydrateIndexedAttestation(ðpb.IndexedAttestation{
|
||||
Data: ðpb.AttestationData{
|
||||
Source: ðpb.Checkpoint{Epoch: 1},
|
||||
},
|
||||
AttestingIndices: []uint64{0, 1},
|
||||
})
|
||||
domain, err := signing.Domain(beaconState.Fork(), 0, params.BeaconConfig().DomainBeaconAttester, beaconState.GenesisValidatorsRoot())
|
||||
require.NoError(t, err)
|
||||
signingRoot, err := signing.ComputeSigningRoot(att1.Data, domain)
|
||||
assert.NoError(t, err, "Could not get signing root of beacon block header")
|
||||
sig0 := privKeys[0].Sign(signingRoot[:])
|
||||
sig1 := privKeys[1].Sign(signingRoot[:])
|
||||
aggregateSig := bls.AggregateSignatures([]bls.Signature{sig0, sig1})
|
||||
att1.Signature = aggregateSig.Marshal()
|
||||
|
||||
att2 := util.HydrateIndexedAttestation(ðpb.IndexedAttestation{
|
||||
AttestingIndices: []uint64{0, 1},
|
||||
})
|
||||
signingRoot, err = signing.ComputeSigningRoot(att2.Data, domain)
|
||||
assert.NoError(t, err, "Could not get signing root of beacon block header")
|
||||
sig0 = privKeys[0].Sign(signingRoot[:])
|
||||
sig1 = privKeys[1].Sign(signingRoot[:])
|
||||
aggregateSig = bls.AggregateSignatures([]bls.Signature{sig0, sig1})
|
||||
att2.Signature = aggregateSig.Marshal()
|
||||
|
||||
slashings := []*ethpb.AttesterSlashing{
|
||||
{
|
||||
Attestation_1: att1,
|
||||
Attestation_2: att2,
|
||||
},
|
||||
}
|
||||
|
||||
currentSlot := 2 * params.BeaconConfig().SlotsPerEpoch
|
||||
require.NoError(t, beaconState.SetSlot(currentSlot))
|
||||
|
||||
b := util.NewBeaconBlock()
|
||||
b.Block = ðpb.BeaconBlock{
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
AttesterSlashings: slashings,
|
||||
},
|
||||
}
|
||||
|
||||
newState, err := blocks.ProcessAttesterSlashings(context.Background(), beaconState, b.Block.Body.AttesterSlashings, v.SlashValidator)
|
||||
require.NoError(t, err)
|
||||
newRegistry := newState.Validators()
|
||||
|
||||
// Given the intersection of slashable indices is [1], only validator
|
||||
// at index 1 should be slashed and exited. We confirm this below.
|
||||
if newRegistry[1].ExitEpoch != beaconState.Validators()[1].ExitEpoch {
|
||||
t.Errorf(
|
||||
`
|
||||
Expected validator at index 1's exit epoch to match
|
||||
%d, received %d instead
|
||||
`,
|
||||
beaconState.Validators()[1].ExitEpoch,
|
||||
newRegistry[1].ExitEpoch,
|
||||
)
|
||||
}
|
||||
|
||||
require.Equal(t, uint64(31000000000), newState.Balances()[1])
|
||||
require.Equal(t, uint64(32000000000), newState.Balances()[2])
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
|
||||
fuzz "github.com/google/gofuzz"
|
||||
v "github.com/prysmaticlabs/prysm/v3/beacon-chain/core/validators"
|
||||
v1 "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/v1"
|
||||
state_native "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/state-native"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/v3/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||
"github.com/prysmaticlabs/prysm/v3/consensus-types/blocks"
|
||||
@@ -24,7 +24,7 @@ func TestFuzzProcessAttestationNoVerify_10000(t *testing.T) {
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(att)
|
||||
s, err := v1.InitializeFromProtoUnsafe(state)
|
||||
s, err := state_native.InitializeFromProtoUnsafePhase0(state)
|
||||
require.NoError(t, err)
|
||||
_, err = ProcessAttestationNoVerifySignature(ctx, s, att)
|
||||
_ = err
|
||||
@@ -40,9 +40,9 @@ func TestFuzzProcessBlockHeader_10000(t *testing.T) {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(block)
|
||||
|
||||
s, err := v1.InitializeFromProtoUnsafe(state)
|
||||
s, err := state_native.InitializeFromProtoUnsafePhase0(state)
|
||||
require.NoError(t, err)
|
||||
if block.Block == nil || block.Block.Body == nil {
|
||||
if block.Block == nil || block.Block.Body == nil || block.Block.Body.Eth1Data == nil {
|
||||
continue
|
||||
}
|
||||
wsb, err := blocks.NewSignedBeaconBlock(block)
|
||||
@@ -55,9 +55,9 @@ func TestFuzzProcessBlockHeader_10000(t *testing.T) {
|
||||
func TestFuzzverifyDepositDataSigningRoot_10000(_ *testing.T) {
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
var ba []byte
|
||||
pubkey := [fieldparams.BLSPubkeyLength]byte{}
|
||||
sig := [96]byte{}
|
||||
domain := [4]byte{}
|
||||
var pubkey [fieldparams.BLSPubkeyLength]byte
|
||||
var sig [96]byte
|
||||
var domain [4]byte
|
||||
var p []byte
|
||||
var s []byte
|
||||
var d []byte
|
||||
@@ -79,7 +79,7 @@ func TestFuzzverifyDepositDataSigningRoot_10000(_ *testing.T) {
|
||||
func TestFuzzProcessEth1DataInBlock_10000(t *testing.T) {
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
e := ðpb.Eth1Data{}
|
||||
state, err := v1.InitializeFromProtoUnsafe(ðpb.BeaconState{})
|
||||
state, err := state_native.InitializeFromProtoUnsafePhase0(ðpb.BeaconState{})
|
||||
require.NoError(t, err)
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
@@ -111,7 +111,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 := state_native.InitializeFromProtoPhase0(ðpb.BeaconState{
|
||||
Eth1DataVotes: stateVotes,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
@@ -129,7 +129,7 @@ func TestFuzzProcessBlockHeaderNoVerify_10000(t *testing.T) {
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(block)
|
||||
s, err := v1.InitializeFromProtoUnsafe(state)
|
||||
s, err := state_native.InitializeFromProtoUnsafePhase0(state)
|
||||
require.NoError(t, err)
|
||||
_, err = ProcessBlockHeaderNoVerify(context.Background(), s, block.Slot, block.ProposerIndex, block.ParentRoot, []byte{})
|
||||
_ = err
|
||||
@@ -144,7 +144,7 @@ func TestFuzzProcessRandao_10000(t *testing.T) {
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(b)
|
||||
s, err := v1.InitializeFromProtoUnsafe(state)
|
||||
s, err := state_native.InitializeFromProtoUnsafePhase0(state)
|
||||
require.NoError(t, err)
|
||||
if b.Block == nil || b.Block.Body == nil {
|
||||
continue
|
||||
@@ -166,7 +166,7 @@ func TestFuzzProcessRandaoNoVerify_10000(t *testing.T) {
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(blockBody)
|
||||
s, err := v1.InitializeFromProtoUnsafe(state)
|
||||
s, err := state_native.InitializeFromProtoUnsafePhase0(state)
|
||||
require.NoError(t, err)
|
||||
r, err := ProcessRandaoNoVerify(s, blockBody.RandaoReveal)
|
||||
if err != nil && r != nil {
|
||||
@@ -183,7 +183,7 @@ func TestFuzzProcessProposerSlashings_10000(t *testing.T) {
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(p)
|
||||
s, err := v1.InitializeFromProtoUnsafe(state)
|
||||
s, err := state_native.InitializeFromProtoUnsafePhase0(state)
|
||||
require.NoError(t, err)
|
||||
r, err := ProcessProposerSlashings(ctx, s, []*ethpb.ProposerSlashing{p}, v.SlashValidator)
|
||||
if err != nil && r != nil {
|
||||
@@ -199,7 +199,7 @@ func TestFuzzVerifyProposerSlashing_10000(t *testing.T) {
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(proposerSlashing)
|
||||
s, err := v1.InitializeFromProtoUnsafe(state)
|
||||
s, err := state_native.InitializeFromProtoUnsafePhase0(state)
|
||||
require.NoError(t, err)
|
||||
err = VerifyProposerSlashing(s, proposerSlashing)
|
||||
_ = err
|
||||
@@ -214,7 +214,7 @@ func TestFuzzProcessAttesterSlashings_10000(t *testing.T) {
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(a)
|
||||
s, err := v1.InitializeFromProtoUnsafe(state)
|
||||
s, err := state_native.InitializeFromProtoUnsafePhase0(state)
|
||||
require.NoError(t, err)
|
||||
r, err := ProcessAttesterSlashings(ctx, s, []*ethpb.AttesterSlashing{a}, v.SlashValidator)
|
||||
if err != nil && r != nil {
|
||||
@@ -231,7 +231,7 @@ func TestFuzzVerifyAttesterSlashing_10000(t *testing.T) {
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(attesterSlashing)
|
||||
s, err := v1.InitializeFromProtoUnsafe(state)
|
||||
s, err := state_native.InitializeFromProtoUnsafePhase0(state)
|
||||
require.NoError(t, err)
|
||||
err = VerifyAttesterSlashing(ctx, s, attesterSlashing)
|
||||
_ = err
|
||||
@@ -268,7 +268,7 @@ func TestFuzzProcessAttestationsNoVerify_10000(t *testing.T) {
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(b)
|
||||
s, err := v1.InitializeFromProtoUnsafe(state)
|
||||
s, err := state_native.InitializeFromProtoUnsafePhase0(state)
|
||||
require.NoError(t, err)
|
||||
if b.Block == nil || b.Block.Body == nil {
|
||||
continue
|
||||
@@ -290,7 +290,7 @@ func TestFuzzVerifyIndexedAttestationn_10000(t *testing.T) {
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(idxAttestation)
|
||||
s, err := v1.InitializeFromProtoUnsafe(state)
|
||||
s, err := state_native.InitializeFromProtoUnsafePhase0(state)
|
||||
require.NoError(t, err)
|
||||
err = VerifyIndexedAttestation(ctx, s, idxAttestation)
|
||||
_ = err
|
||||
@@ -305,7 +305,7 @@ func TestFuzzVerifyAttestation_10000(t *testing.T) {
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(attestation)
|
||||
s, err := v1.InitializeFromProtoUnsafe(state)
|
||||
s, err := state_native.InitializeFromProtoUnsafePhase0(state)
|
||||
require.NoError(t, err)
|
||||
err = VerifyAttestationSignature(ctx, s, attestation)
|
||||
_ = err
|
||||
@@ -322,7 +322,7 @@ func TestFuzzProcessDeposits_10000(t *testing.T) {
|
||||
for i := range deposits {
|
||||
fuzzer.Fuzz(deposits[i])
|
||||
}
|
||||
s, err := v1.InitializeFromProtoUnsafe(state)
|
||||
s, err := state_native.InitializeFromProtoUnsafePhase0(state)
|
||||
require.NoError(t, err)
|
||||
r, err := ProcessDeposits(ctx, s, deposits)
|
||||
if err != nil && r != nil {
|
||||
@@ -340,7 +340,7 @@ func TestFuzzProcessPreGenesisDeposit_10000(t *testing.T) {
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(deposit)
|
||||
s, err := v1.InitializeFromProtoUnsafe(state)
|
||||
s, err := state_native.InitializeFromProtoUnsafePhase0(state)
|
||||
require.NoError(t, err)
|
||||
r, err := ProcessPreGenesisDeposits(ctx, s, []*ethpb.Deposit{deposit})
|
||||
if err != nil && r != nil {
|
||||
@@ -357,7 +357,7 @@ func TestFuzzProcessDeposit_10000(t *testing.T) {
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(deposit)
|
||||
s, err := v1.InitializeFromProtoUnsafe(state)
|
||||
s, err := state_native.InitializeFromProtoUnsafePhase0(state)
|
||||
require.NoError(t, err)
|
||||
r, _, err := ProcessDeposit(s, deposit, true)
|
||||
if err != nil && r != nil {
|
||||
@@ -373,7 +373,7 @@ func TestFuzzverifyDeposit_10000(t *testing.T) {
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(deposit)
|
||||
s, err := v1.InitializeFromProtoUnsafe(state)
|
||||
s, err := state_native.InitializeFromProtoUnsafePhase0(state)
|
||||
require.NoError(t, err)
|
||||
err = verifyDeposit(s, deposit)
|
||||
_ = err
|
||||
@@ -388,7 +388,7 @@ func TestFuzzProcessVoluntaryExits_10000(t *testing.T) {
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(e)
|
||||
s, err := v1.InitializeFromProtoUnsafe(state)
|
||||
s, err := state_native.InitializeFromProtoUnsafePhase0(state)
|
||||
require.NoError(t, err)
|
||||
r, err := ProcessVoluntaryExits(ctx, s, []*ethpb.SignedVoluntaryExit{e})
|
||||
if err != nil && r != nil {
|
||||
@@ -404,7 +404,7 @@ func TestFuzzProcessVoluntaryExitsNoVerify_10000(t *testing.T) {
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(e)
|
||||
s, err := v1.InitializeFromProtoUnsafe(state)
|
||||
s, err := state_native.InitializeFromProtoUnsafePhase0(state)
|
||||
require.NoError(t, err)
|
||||
r, err := ProcessVoluntaryExits(context.Background(), s, []*ethpb.SignedVoluntaryExit{e})
|
||||
if err != nil && r != nil {
|
||||
@@ -425,7 +425,7 @@ func TestFuzzVerifyExit_10000(_ *testing.T) {
|
||||
fuzzer.Fuzz(rawVal)
|
||||
fuzzer.Fuzz(fork)
|
||||
fuzzer.Fuzz(&slot)
|
||||
val, err := v1.NewValidator(ðpb.Validator{})
|
||||
val, err := state_native.NewValidator(ðpb.Validator{})
|
||||
_ = err
|
||||
err = VerifyExitAndSignature(val, slot, fork, ve, params.BeaconConfig().ZeroHash[:])
|
||||
_ = err
|
||||
|
||||
@@ -71,8 +71,9 @@ func ActivateValidatorWithEffectiveBalance(beaconState state.BeaconState, deposi
|
||||
// into the beacon chain.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// For each deposit in block.body.deposits:
|
||||
// process_deposit(state, deposit)
|
||||
//
|
||||
// For each deposit in block.body.deposits:
|
||||
// process_deposit(state, deposit)
|
||||
func ProcessDeposits(
|
||||
ctx context.Context,
|
||||
beaconState state.BeaconState,
|
||||
@@ -120,40 +121,41 @@ func BatchVerifyDepositsSignatures(ctx context.Context, deposits []*ethpb.Deposi
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// def process_deposit(state: BeaconState, deposit: Deposit) -> None:
|
||||
// # Verify the Merkle branch
|
||||
// assert is_valid_merkle_branch(
|
||||
// leaf=hash_tree_root(deposit.data),
|
||||
// branch=deposit.proof,
|
||||
// depth=DEPOSIT_CONTRACT_TREE_DEPTH + 1, # Add 1 for the List length mix-in
|
||||
// index=state.eth1_deposit_index,
|
||||
// root=state.eth1_data.deposit_root,
|
||||
// )
|
||||
//
|
||||
// # Deposits must be processed in order
|
||||
// state.eth1_deposit_index += 1
|
||||
// # Verify the Merkle branch
|
||||
// assert is_valid_merkle_branch(
|
||||
// leaf=hash_tree_root(deposit.data),
|
||||
// branch=deposit.proof,
|
||||
// depth=DEPOSIT_CONTRACT_TREE_DEPTH + 1, # Add 1 for the List length mix-in
|
||||
// index=state.eth1_deposit_index,
|
||||
// root=state.eth1_data.deposit_root,
|
||||
// )
|
||||
//
|
||||
// pubkey = deposit.data.pubkey
|
||||
// amount = deposit.data.amount
|
||||
// validator_pubkeys = [v.pubkey for v in state.validators]
|
||||
// if pubkey not in validator_pubkeys:
|
||||
// # Verify the deposit signature (proof of possession) which is not checked by the deposit contract
|
||||
// deposit_message = DepositMessage(
|
||||
// pubkey=deposit.data.pubkey,
|
||||
// withdrawal_credentials=deposit.data.withdrawal_credentials,
|
||||
// amount=deposit.data.amount,
|
||||
// )
|
||||
// domain = compute_domain(DOMAIN_DEPOSIT) # Fork-agnostic domain since deposits are valid across forks
|
||||
// signing_root = compute_signing_root(deposit_message, domain)
|
||||
// if not bls.Verify(pubkey, signing_root, deposit.data.signature):
|
||||
// return
|
||||
// # Deposits must be processed in order
|
||||
// state.eth1_deposit_index += 1
|
||||
//
|
||||
// # Add validator and balance entries
|
||||
// state.validators.append(get_validator_from_deposit(state, deposit))
|
||||
// state.balances.append(amount)
|
||||
// else:
|
||||
// # Increase balance by deposit amount
|
||||
// index = ValidatorIndex(validator_pubkeys.index(pubkey))
|
||||
// increase_balance(state, index, amount)
|
||||
// pubkey = deposit.data.pubkey
|
||||
// amount = deposit.data.amount
|
||||
// validator_pubkeys = [v.pubkey for v in state.validators]
|
||||
// if pubkey not in validator_pubkeys:
|
||||
// # Verify the deposit signature (proof of possession) which is not checked by the deposit contract
|
||||
// deposit_message = DepositMessage(
|
||||
// pubkey=deposit.data.pubkey,
|
||||
// withdrawal_credentials=deposit.data.withdrawal_credentials,
|
||||
// amount=deposit.data.amount,
|
||||
// )
|
||||
// domain = compute_domain(DOMAIN_DEPOSIT) # Fork-agnostic domain since deposits are valid across forks
|
||||
// signing_root = compute_signing_root(deposit_message, domain)
|
||||
// if not bls.Verify(pubkey, signing_root, deposit.data.signature):
|
||||
// return
|
||||
//
|
||||
// # Add validator and balance entries
|
||||
// state.validators.append(get_validator_from_deposit(state, deposit))
|
||||
// state.balances.append(amount)
|
||||
// else:
|
||||
// # Increase balance by deposit amount
|
||||
// index = ValidatorIndex(validator_pubkeys.index(pubkey))
|
||||
// increase_balance(state, index, amount)
|
||||
func ProcessDeposit(beaconState state.BeaconState, deposit *ethpb.Deposit, verifySignature bool) (state.BeaconState, bool, error) {
|
||||
var newValidator bool
|
||||
if err := verifyDeposit(beaconState, deposit); err != nil {
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/signing"
|
||||
v1 "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/v1"
|
||||
state_native "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/state-native"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/v3/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||
@@ -40,7 +40,7 @@ func TestProcessDeposits_SameValidatorMultipleDepositsSameBlock(t *testing.T) {
|
||||
},
|
||||
}
|
||||
balances := []uint64{0}
|
||||
beaconState, err := v1.InitializeFromProto(ðpb.BeaconState{
|
||||
beaconState, err := state_native.InitializeFromProtoPhase0(ðpb.BeaconState{
|
||||
Validators: registry,
|
||||
Balances: balances,
|
||||
Eth1Data: eth1Data,
|
||||
@@ -80,7 +80,7 @@ func TestProcessDeposits_MerkleBranchFailsVerification(t *testing.T) {
|
||||
Deposits: []*ethpb.Deposit{deposit},
|
||||
},
|
||||
}
|
||||
beaconState, err := v1.InitializeFromProto(ðpb.BeaconState{
|
||||
beaconState, err := state_native.InitializeFromProtoPhase0(ðpb.BeaconState{
|
||||
Eth1Data: ðpb.Eth1Data{
|
||||
DepositRoot: []byte{0},
|
||||
BlockHash: []byte{1},
|
||||
@@ -111,7 +111,7 @@ func TestProcessDeposits_AddsNewValidatorDeposit(t *testing.T) {
|
||||
},
|
||||
}
|
||||
balances := []uint64{0}
|
||||
beaconState, err := v1.InitializeFromProto(ðpb.BeaconState{
|
||||
beaconState, err := state_native.InitializeFromProtoPhase0(ðpb.BeaconState{
|
||||
Validators: registry,
|
||||
Balances: balances,
|
||||
Eth1Data: eth1Data,
|
||||
@@ -175,7 +175,7 @@ func TestProcessDeposits_RepeatedDeposit_IncreasesValidatorBalance(t *testing.T)
|
||||
balances := []uint64{0, 50}
|
||||
root, err := depositTrie.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
beaconState, err := v1.InitializeFromProto(ðpb.BeaconState{
|
||||
beaconState, err := state_native.InitializeFromProtoPhase0(ðpb.BeaconState{
|
||||
Validators: registry,
|
||||
Balances: balances,
|
||||
Eth1Data: ðpb.Eth1Data{
|
||||
@@ -203,7 +203,7 @@ func TestProcessDeposit_AddsNewValidatorDeposit(t *testing.T) {
|
||||
},
|
||||
}
|
||||
balances := []uint64{0}
|
||||
beaconState, err := v1.InitializeFromProto(ðpb.BeaconState{
|
||||
beaconState, err := state_native.InitializeFromProtoPhase0(ðpb.BeaconState{
|
||||
Validators: registry,
|
||||
Balances: balances,
|
||||
Eth1Data: eth1Data,
|
||||
@@ -247,7 +247,7 @@ func TestProcessDeposit_SkipsInvalidDeposit(t *testing.T) {
|
||||
},
|
||||
}
|
||||
balances := []uint64{0}
|
||||
beaconState, err := v1.InitializeFromProto(ðpb.BeaconState{
|
||||
beaconState, err := state_native.InitializeFromProtoPhase0(ðpb.BeaconState{
|
||||
Validators: registry,
|
||||
Balances: balances,
|
||||
Eth1Data: eth1Data,
|
||||
@@ -305,7 +305,7 @@ func TestPreGenesisDeposits_SkipInvalidDeposit(t *testing.T) {
|
||||
},
|
||||
}
|
||||
balances := []uint64{0}
|
||||
beaconState, err := v1.InitializeFromProto(ðpb.BeaconState{
|
||||
beaconState, err := state_native.InitializeFromProtoPhase0(ðpb.BeaconState{
|
||||
Validators: registry,
|
||||
Balances: balances,
|
||||
Eth1Data: eth1Data,
|
||||
@@ -383,7 +383,7 @@ func TestProcessDeposit_RepeatedDeposit_IncreasesValidatorBalance(t *testing.T)
|
||||
root, err := depositTrie.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
beaconState, err := v1.InitializeFromProto(ðpb.BeaconState{
|
||||
beaconState, err := state_native.InitializeFromProtoPhase0(ðpb.BeaconState{
|
||||
Validators: registry,
|
||||
Balances: balances,
|
||||
Eth1Data: ðpb.Eth1Data{
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user