mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-10 13:58:09 -05:00
Compare commits
544 Commits
v1.0.0-alp
...
v1.0.0-alp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
551b03d6e6 | ||
|
|
c4e64afd07 | ||
|
|
d98a6dda8f | ||
|
|
8aaa5b6ad0 | ||
|
|
f92244d497 | ||
|
|
e91165b0b4 | ||
|
|
e15a0b08aa | ||
|
|
a3a77ab5a8 | ||
|
|
650ec797da | ||
|
|
f629c72107 | ||
|
|
98a20766c9 | ||
|
|
1f707842d2 | ||
|
|
c944f29c7c | ||
|
|
6b5265d2d4 | ||
|
|
8f64eb622e | ||
|
|
4ddacd57c6 | ||
|
|
a66f434236 | ||
|
|
796c336a29 | ||
|
|
48fcb08ebc | ||
|
|
1315a15d9d | ||
|
|
25ebed9a70 | ||
|
|
703907bd99 | ||
|
|
d4e6ce6998 | ||
|
|
390a589afb | ||
|
|
d34156bfe6 | ||
|
|
7c8492e83f | ||
|
|
668163d740 | ||
|
|
7ad2929f0f | ||
|
|
9ce64e2428 | ||
|
|
ae78546323 | ||
|
|
23bce8d0c5 | ||
|
|
29137f7b39 | ||
|
|
bf4a8dcee9 | ||
|
|
7b5f71229e | ||
|
|
4d7797827e | ||
|
|
c0ed43d920 | ||
|
|
842c15856b | ||
|
|
20ac925ee4 | ||
|
|
6e8ff10003 | ||
|
|
419fad07cd | ||
|
|
cf1c346beb | ||
|
|
3e0b20529b | ||
|
|
d9ae2073e2 | ||
|
|
7b3efcf62b | ||
|
|
c7d01fd73c | ||
|
|
2916d183e8 | ||
|
|
c24fb792cb | ||
|
|
70f3fcdbd9 | ||
|
|
ecfdb354a7 | ||
|
|
690fa12f1a | ||
|
|
63c1057ae6 | ||
|
|
1eee1948bb | ||
|
|
e36e9250f1 | ||
|
|
b589ddd774 | ||
|
|
ba01abbc8f | ||
|
|
fa82b09cec | ||
|
|
7d9a706cfa | ||
|
|
437bab7df0 | ||
|
|
ee747ca6d4 | ||
|
|
de93551332 | ||
|
|
0839f10dbc | ||
|
|
d169b490fa | ||
|
|
490cf9b7ba | ||
|
|
95a5b4945b | ||
|
|
4aea039324 | ||
|
|
23181c8629 | ||
|
|
d23b247a82 | ||
|
|
5178474280 | ||
|
|
d5caee35fa | ||
|
|
558ee2678b | ||
|
|
e1f8a37710 | ||
|
|
e07b71b81d | ||
|
|
db92d90309 | ||
|
|
e2eb2fb0d8 | ||
|
|
953960c860 | ||
|
|
7664eab32d | ||
|
|
16cdcf5dec | ||
|
|
3b5ef50733 | ||
|
|
529554f3f9 | ||
|
|
fe9921457c | ||
|
|
bedb16cfb0 | ||
|
|
0921c00094 | ||
|
|
6ef4995329 | ||
|
|
1e0b4e150e | ||
|
|
951c139cff | ||
|
|
eb3e4944e9 | ||
|
|
bb98046608 | ||
|
|
4ac0bbca19 | ||
|
|
c0c34f3d3a | ||
|
|
77c95f3051 | ||
|
|
68d0c09daf | ||
|
|
282f3eec01 | ||
|
|
4a549ffe2b | ||
|
|
d138c608bc | ||
|
|
c7ff3a4f22 | ||
|
|
7a96412ef2 | ||
|
|
5821454ac7 | ||
|
|
90978cd22e | ||
|
|
76a3070fd7 | ||
|
|
1bc0cc7049 | ||
|
|
ff69375fbd | ||
|
|
5b814009fa | ||
|
|
99164761f5 | ||
|
|
e1cd9143e0 | ||
|
|
4d232feda8 | ||
|
|
d687270a89 | ||
|
|
6d8207801c | ||
|
|
6ad117b175 | ||
|
|
f9e062407f | ||
|
|
dca93ce641 | ||
|
|
347aa14a28 | ||
|
|
3621b2ff25 | ||
|
|
49ae42c249 | ||
|
|
1ce7cd5f50 | ||
|
|
305fdd2e1b | ||
|
|
984cb38680 | ||
|
|
bbdd20e898 | ||
|
|
568cd3c9ec | ||
|
|
b09b1f3fa5 | ||
|
|
22bcfd2c34 | ||
|
|
ba440abe2d | ||
|
|
09640ae22d | ||
|
|
719e99ffd9 | ||
|
|
1a4129f5a6 | ||
|
|
de3f112a05 | ||
|
|
3734bfacce | ||
|
|
d5e2b51d66 | ||
|
|
cdd28abc4b | ||
|
|
8c8f59e242 | ||
|
|
b1f9f97062 | ||
|
|
7545d3f2b3 | ||
|
|
bdf8bf7be2 | ||
|
|
b928e9531c | ||
|
|
1f6afa8547 | ||
|
|
303edbde58 | ||
|
|
208ea56a9c | ||
|
|
c8b91ba7b0 | ||
|
|
268df90ddd | ||
|
|
749aba8d09 | ||
|
|
7920afb12e | ||
|
|
cc147c7097 | ||
|
|
852082cdb4 | ||
|
|
e927a3d170 | ||
|
|
7c2096f209 | ||
|
|
dcdf5d0eac | ||
|
|
3db6784990 | ||
|
|
d51ead76eb | ||
|
|
a2cf235687 | ||
|
|
e1e233a6d0 | ||
|
|
76bac74562 | ||
|
|
a335bbbb61 | ||
|
|
913e4aa538 | ||
|
|
4b4641bae3 | ||
|
|
6bfb2b1e46 | ||
|
|
a97de0d474 | ||
|
|
f6d3c28ae1 | ||
|
|
3197748240 | ||
|
|
14dbc2b74d | ||
|
|
b0917db4c7 | ||
|
|
ee4ebe4c38 | ||
|
|
56d6e05196 | ||
|
|
bb374362e4 | ||
|
|
c1114fa6be | ||
|
|
36c921c601 | ||
|
|
f31f49582b | ||
|
|
cebb62997d | ||
|
|
e477df321c | ||
|
|
828156b9d4 | ||
|
|
aaa3abf630 | ||
|
|
e1aa920fc6 | ||
|
|
fcfd828725 | ||
|
|
3374a06f63 | ||
|
|
0b497e57e4 | ||
|
|
af46fc7707 | ||
|
|
b1e2238df9 | ||
|
|
acddb6035a | ||
|
|
3147a5ee01 | ||
|
|
572227d25e | ||
|
|
84273e9a34 | ||
|
|
114fac5149 | ||
|
|
2d9fe5f2cf | ||
|
|
6daf45cb8f | ||
|
|
c8e93f8789 | ||
|
|
94fa046ce1 | ||
|
|
a74cf5de90 | ||
|
|
6d83770534 | ||
|
|
593442a0fa | ||
|
|
bd46abc71d | ||
|
|
cb1f44872d | ||
|
|
8baa22f065 | ||
|
|
f4848e46d4 | ||
|
|
f04fffb5fe | ||
|
|
51f2cc18e5 | ||
|
|
3de626f0d0 | ||
|
|
a81214219d | ||
|
|
245c18784e | ||
|
|
9219dc77ff | ||
|
|
1de230110d | ||
|
|
b6607fac25 | ||
|
|
e6277ec536 | ||
|
|
0961fef727 | ||
|
|
366b98ac83 | ||
|
|
c2425e81d7 | ||
|
|
8f2950d374 | ||
|
|
f4a6864343 | ||
|
|
c1a7c65e05 | ||
|
|
7fd2536d54 | ||
|
|
0e6797d80d | ||
|
|
b2b4c2660d | ||
|
|
787857c38b | ||
|
|
1cc21ed3c4 | ||
|
|
7588e491ab | ||
|
|
afce363e00 | ||
|
|
7de3ce0b31 | ||
|
|
6e6b871cc1 | ||
|
|
2349012bd0 | ||
|
|
b4c0a89d49 | ||
|
|
d368156a08 | ||
|
|
63149a3dc3 | ||
|
|
fbe088625a | ||
|
|
ecbab20bad | ||
|
|
381b5be0fc | ||
|
|
6803f3308a | ||
|
|
60558b7970 | ||
|
|
7854b91ae0 | ||
|
|
c9c7cc7b93 | ||
|
|
b538f5073d | ||
|
|
3ed7b23ed7 | ||
|
|
c2b94d04ed | ||
|
|
3316516d22 | ||
|
|
12c1daaf2b | ||
|
|
f09620c9f6 | ||
|
|
e47e7067c4 | ||
|
|
4edcf92140 | ||
|
|
7463f2cffd | ||
|
|
fea2cc9e2f | ||
|
|
bd489e345a | ||
|
|
b98b9b740b | ||
|
|
b7175b3482 | ||
|
|
7d28146e1e | ||
|
|
5bfc457904 | ||
|
|
13324674ba | ||
|
|
c78bfab69d | ||
|
|
2ee025ee88 | ||
|
|
0410b14260 | ||
|
|
2c3558e449 | ||
|
|
e95393f671 | ||
|
|
73cb6daf46 | ||
|
|
8a8edf3743 | ||
|
|
900e7114da | ||
|
|
ba00c55f95 | ||
|
|
8240eb0416 | ||
|
|
ba07ccb484 | ||
|
|
3d9cde3e1c | ||
|
|
b291eb7953 | ||
|
|
f61f02e59b | ||
|
|
48fd40e35b | ||
|
|
d8ea41ce35 | ||
|
|
e556ac348a | ||
|
|
c764099231 | ||
|
|
b954db9704 | ||
|
|
c9c4cd9f87 | ||
|
|
880298d844 | ||
|
|
21a56d5419 | ||
|
|
5c9830f0c3 | ||
|
|
5d0f6c5b16 | ||
|
|
5cee10f28e | ||
|
|
78a25f99c3 | ||
|
|
706f375aed | ||
|
|
5977343a0d | ||
|
|
f2afeed9da | ||
|
|
e69ed7c778 | ||
|
|
c9caf5dfc5 | ||
|
|
b4c7a14759 | ||
|
|
92e1a996cc | ||
|
|
6228b3cd9f | ||
|
|
8686a81304 | ||
|
|
05d6dc7a10 | ||
|
|
ec1dd85c44 | ||
|
|
7b0b8ee126 | ||
|
|
55074bcc6c | ||
|
|
89e279f9c8 | ||
|
|
40db6cb0cf | ||
|
|
45e4ed25a3 | ||
|
|
e93d31c60e | ||
|
|
8bdf9db147 | ||
|
|
2bf1332e5c | ||
|
|
7744c3ae47 | ||
|
|
ba5da21026 | ||
|
|
395ea76f44 | ||
|
|
3aa95b9c16 | ||
|
|
bc20591b72 | ||
|
|
85a040bfd2 | ||
|
|
399dc85737 | ||
|
|
9bf80219c9 | ||
|
|
14cd25f9dc | ||
|
|
d81c9ffcfc | ||
|
|
27c8402ae0 | ||
|
|
0a5ec502b0 | ||
|
|
4d463c4a85 | ||
|
|
9caa92cae4 | ||
|
|
dbd1e8c247 | ||
|
|
bde3073bd6 | ||
|
|
f193dc2f54 | ||
|
|
a2f781522f | ||
|
|
d66f72939e | ||
|
|
c3725d11f2 | ||
|
|
715cd40f56 | ||
|
|
a4bbd82a45 | ||
|
|
0be1957c28 | ||
|
|
9ebd90c324 | ||
|
|
03c3f06288 | ||
|
|
c47d18aa0b | ||
|
|
17b810f24e | ||
|
|
ee2ba721ab | ||
|
|
d24f99d66d | ||
|
|
3c776f4e76 | ||
|
|
b981442022 | ||
|
|
6db448a81d | ||
|
|
f5a1a8b4ed | ||
|
|
3df2980cba | ||
|
|
16c34b627f | ||
|
|
6ed0539723 | ||
|
|
4de0b9fe69 | ||
|
|
282398fd13 | ||
|
|
74101612ce | ||
|
|
308dbc4272 | ||
|
|
5705a9a1f9 | ||
|
|
72bbc33a65 | ||
|
|
dc752fb945 | ||
|
|
0c94298847 | ||
|
|
7611f6d84a | ||
|
|
49549f4687 | ||
|
|
0d7ea33298 | ||
|
|
2400536a8e | ||
|
|
da4e96047b | ||
|
|
f4d808a542 | ||
|
|
86b2bd5edd | ||
|
|
682401c6b0 | ||
|
|
4499fb2ed0 | ||
|
|
46cb3abe2e | ||
|
|
11c9699129 | ||
|
|
c24666e02e | ||
|
|
a279f374bc | ||
|
|
a5f0fd29fc | ||
|
|
b32ccce23d | ||
|
|
3893ee43f9 | ||
|
|
ea9bb88d13 | ||
|
|
537fe3f721 | ||
|
|
8b9138a76a | ||
|
|
ceb11f432e | ||
|
|
cbc27e0f2e | ||
|
|
a7f4293eb3 | ||
|
|
335d31688f | ||
|
|
95fd399dbe | ||
|
|
1f21e196b6 | ||
|
|
18b3203f31 | ||
|
|
33105f1bbc | ||
|
|
44f9d07434 | ||
|
|
649bfb58e5 | ||
|
|
6d5b7b0439 | ||
|
|
b241fafd13 | ||
|
|
b1946ead23 | ||
|
|
7591240366 | ||
|
|
f575a81afd | ||
|
|
fecbec2342 | ||
|
|
9a59c4baff | ||
|
|
cca439847d | ||
|
|
10f38662e5 | ||
|
|
3275a86ece | ||
|
|
43b646a9dd | ||
|
|
1d9374d5c9 | ||
|
|
8100261e70 | ||
|
|
78ec783604 | ||
|
|
6351d187ef | ||
|
|
2502b812fc | ||
|
|
ceee7489dd | ||
|
|
6b4e4bcf96 | ||
|
|
96fcb3a927 | ||
|
|
f0de09d2ad | ||
|
|
ac82308e03 | ||
|
|
5a216de6d2 | ||
|
|
dc0f2140b3 | ||
|
|
1d679c9533 | ||
|
|
5b75f4e6be | ||
|
|
40b68da486 | ||
|
|
ec21316efd | ||
|
|
89bd5f3a5a | ||
|
|
64ba3c076b | ||
|
|
440d3288d5 | ||
|
|
446bfca4f3 | ||
|
|
492944db01 | ||
|
|
0d118df034 | ||
|
|
e492343ffd | ||
|
|
de8d3ec612 | ||
|
|
016b95385a | ||
|
|
ac0237e9cf | ||
|
|
c860553306 | ||
|
|
1f9d155f0e | ||
|
|
bc883aab9e | ||
|
|
859e59b6f7 | ||
|
|
0d6fb72496 | ||
|
|
ef69ac4496 | ||
|
|
daedb7411c | ||
|
|
6af950f001 | ||
|
|
700d82236b | ||
|
|
ee7da0d451 | ||
|
|
69e0e302b3 | ||
|
|
d06dcd2eec | ||
|
|
593d3daf84 | ||
|
|
6582014b80 | ||
|
|
e5dde1c6ef | ||
|
|
d3a9b47643 | ||
|
|
7903ec0b12 | ||
|
|
22e2278812 | ||
|
|
eef0d058ec | ||
|
|
37343930dd | ||
|
|
002bbf53d0 | ||
|
|
bf59530d93 | ||
|
|
0e1fb65476 | ||
|
|
c7c1c660ab | ||
|
|
eb0ad0669f | ||
|
|
4dfe02d919 | ||
|
|
821f2ec029 | ||
|
|
dbd2d9a0bb | ||
|
|
3f983e2a96 | ||
|
|
7a1e5b1dd9 | ||
|
|
bf82683d4f | ||
|
|
323bf70b85 | ||
|
|
f414cf36b9 | ||
|
|
f7c8ae5aa6 | ||
|
|
0cced6e41d | ||
|
|
18f8578d73 | ||
|
|
b2ae4243fd | ||
|
|
0b77f4f84c | ||
|
|
a116502c76 | ||
|
|
2011896005 | ||
|
|
bd7046c790 | ||
|
|
ec4de10001 | ||
|
|
edc9fcd0d6 | ||
|
|
dec779dc1e | ||
|
|
b56f473800 | ||
|
|
fd0383d17e | ||
|
|
48bfffbb3e | ||
|
|
bcea2c1b22 | ||
|
|
187cae8290 | ||
|
|
353bec600f | ||
|
|
bde18f0329 | ||
|
|
62c92af247 | ||
|
|
f9a08dd5d2 | ||
|
|
ecf197c11e | ||
|
|
84697a0a59 | ||
|
|
e5f3a30226 | ||
|
|
e94e62b98f | ||
|
|
d6eb6d3f41 | ||
|
|
fac5e19a17 | ||
|
|
cbd731152e | ||
|
|
fc0585f724 | ||
|
|
9d08ba49de | ||
|
|
1a1c1bb813 | ||
|
|
3a609f44b9 | ||
|
|
c0d6a231bf | ||
|
|
becb0b19e2 | ||
|
|
ee1adddd24 | ||
|
|
06ee5695fb | ||
|
|
027ee4c18c | ||
|
|
8a69d34b96 | ||
|
|
7861005990 | ||
|
|
607d5fdf4e | ||
|
|
0cd80bb970 | ||
|
|
a867f6175b | ||
|
|
905a57cbd7 | ||
|
|
7fff4ec411 | ||
|
|
664349e553 | ||
|
|
3a852bc032 | ||
|
|
630cbfb1b6 | ||
|
|
ca04621849 | ||
|
|
c8761ffb18 | ||
|
|
2cd359bde5 | ||
|
|
7a12fc6d75 | ||
|
|
ada351d087 | ||
|
|
d114c6c6b7 | ||
|
|
01f3a6e6db | ||
|
|
efc24f6aab | ||
|
|
715a33532d | ||
|
|
366e53c416 | ||
|
|
e1f33b196d | ||
|
|
55009bfa66 | ||
|
|
0b9212c685 | ||
|
|
403dab43f5 | ||
|
|
dfdff37a3e | ||
|
|
3974104a20 | ||
|
|
a5b408769a | ||
|
|
cc773a1641 | ||
|
|
415cb9ff8d | ||
|
|
2c11fcb242 | ||
|
|
c72db6f96a | ||
|
|
7c52ef8c2b | ||
|
|
0006377aec | ||
|
|
208659d7f5 | ||
|
|
cf57db910c | ||
|
|
73a9429f1e | ||
|
|
cab89c37f1 | ||
|
|
7d80415089 | ||
|
|
f19770a393 | ||
|
|
95efcb6410 | ||
|
|
6270347fdb | ||
|
|
e5b7c3f3e6 | ||
|
|
6c408d31df | ||
|
|
4400321081 | ||
|
|
17f845dcb0 | ||
|
|
62ae22e3f9 | ||
|
|
647599e87f | ||
|
|
4017743f7f | ||
|
|
28096a846e | ||
|
|
e0d11ff1d2 | ||
|
|
8a65af168d | ||
|
|
d1a828ad87 | ||
|
|
f1cfb6a222 | ||
|
|
3023f5dbd3 | ||
|
|
c41e382255 | ||
|
|
784f4169ef | ||
|
|
367738e83b | ||
|
|
ca54c1d480 | ||
|
|
e97d310453 | ||
|
|
bc16fa9f50 | ||
|
|
9deeb592e6 | ||
|
|
93bbb86a30 | ||
|
|
d54663a553 | ||
|
|
0488c9869e | ||
|
|
f0ffd5af03 | ||
|
|
22141db319 | ||
|
|
10d3275638 | ||
|
|
1d0fe105fc | ||
|
|
0544dd1f8e | ||
|
|
b60a965981 | ||
|
|
38c8393e52 | ||
|
|
568238009e | ||
|
|
c419e4ed8f | ||
|
|
d53539499c | ||
|
|
d535cb95d8 | ||
|
|
7ba500c417 | ||
|
|
c573306621 | ||
|
|
5336a167af |
17
.bazelrc
17
.bazelrc
@@ -33,9 +33,17 @@ build --define kafka_enabled=false
|
||||
test --define kafka_enabled=false
|
||||
run --define kafka_enabled=false
|
||||
|
||||
# Enable blst by default, we use a config so that our fuzzer stops complaining.
|
||||
build --config=blst_enabled
|
||||
test --config=blst_enabled
|
||||
run --config=blst_enabled
|
||||
|
||||
build:kafka_enabled --define kafka_enabled=true
|
||||
build:kafka_enabled --define gotags=kafka_enabled
|
||||
|
||||
build:blst_enabled --define blst_enabled=true
|
||||
build:blst_enabled --define gotags=blst_enabled
|
||||
|
||||
# Release flags
|
||||
build:release --workspace_status_command=./scripts/workspace_status.sh
|
||||
build:release --stamp
|
||||
@@ -69,18 +77,13 @@ build:fuzz --copt=-fno-omit-frame-pointer
|
||||
build:fuzz --define=FUZZING_ENGINE=libfuzzer
|
||||
build:fuzz --copt=-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
||||
build:fuzz --linkopt -Wl,--no-as-needed
|
||||
build:fuzz --define=gc_goopts=-d=libfuzzer
|
||||
build:fuzz --define=gc_goopts=-d=libfuzzer,checkptr
|
||||
build:fuzz --run_under=//tools:fuzz_wrapper
|
||||
build:fuzz --compilation_mode=opt
|
||||
build:fuzz --define=blst_enabled=false
|
||||
|
||||
test:fuzz --local_test_jobs="HOST_CPUS*.5"
|
||||
|
||||
test:fuzzit --config=fuzz
|
||||
test:fuzzit --test_env=FUZZIT_API_KEY
|
||||
test:fuzzit --test_env=PRYSM_BUILD_IMAGE=gcr.io/prysmaticlabs/prysm-fuzzit:v0.11.0
|
||||
test:fuzzit --test_timeout=1200
|
||||
test:fuzzit --run_under=//tools:fuzzit_wrapper
|
||||
|
||||
# Build binary with cgo symbolizer for debugging / profiling.
|
||||
build:cgo_symbolizer --config=llvm
|
||||
build:cgo_symbolizer --copt=-g
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
#
|
||||
# This config is loaded from https://github.com/bazelbuild/bazel-toolchains/blob/master/bazelrc/latest.bazelrc
|
||||
build:remote-cache --remote_timeout=3600
|
||||
build:remote-cache --spawn_strategy=standalone
|
||||
build:remote-cache --strategy=Javac=standalone
|
||||
build:remote-cache --strategy=Closure=standalone
|
||||
build:remote-cache --strategy=Genrule=standalone
|
||||
#build:remote-cache --spawn_strategy=standalone
|
||||
#build:remote-cache --strategy=Javac=standalone
|
||||
#build:remote-cache --strategy=Closure=standalone
|
||||
#build:remote-cache --strategy=Genrule=standalone
|
||||
|
||||
# Prysm specific remote-cache properties.
|
||||
#build:remote-cache --disk_cache=
|
||||
@@ -34,16 +34,5 @@ build --flaky_test_attempts=5
|
||||
# Disabled race detection due to unstable test results under constrained environment build kite
|
||||
# build --features=race
|
||||
|
||||
# Enable kafka for CI tests only.
|
||||
test --config=kafka_enabled
|
||||
|
||||
build --bes_backend=grpcs://builds.prylabs.net:1985
|
||||
build --bes_results_url=https://builds.prylabs.net/invocation/
|
||||
|
||||
# Disable flaky test detection for fuzzing.
|
||||
test:fuzz --flaky_test_attempts=1
|
||||
|
||||
# Expose test environment variables in CI
|
||||
test:fuzzit --test_env=GITHUB_REF
|
||||
test:fuzzit --test_env=GITHUB_SHA
|
||||
test:fuzzit --test_env=DOCKER_HOST
|
||||
|
||||
12
.deepsource.toml
Normal file
12
.deepsource.toml
Normal file
@@ -0,0 +1,12 @@
|
||||
version = 1
|
||||
|
||||
[[analyzers]]
|
||||
name = "go"
|
||||
enabled = true
|
||||
|
||||
[analyzers.meta]
|
||||
import_paths = ["github.com/prysmaticlabs/prysm"]
|
||||
|
||||
[[analyzers]]
|
||||
name = "test-coverage"
|
||||
enabled = true
|
||||
3
.github/workflows/go.yml
vendored
3
.github/workflows/go.yml
vendored
@@ -43,7 +43,8 @@ jobs:
|
||||
go get -v -t -d ./...
|
||||
|
||||
- name: Build
|
||||
run: go build -v ./...
|
||||
# Use blst tag to allow go and bazel builds for blst.
|
||||
run: go build -v --tags=blst_enabled ./...
|
||||
|
||||
# Tests run via Bazel for now...
|
||||
# - name: Test
|
||||
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -29,3 +29,7 @@ password.txt
|
||||
|
||||
# Dist files
|
||||
dist
|
||||
|
||||
# libfuzzer
|
||||
oom-*
|
||||
crash-*
|
||||
|
||||
@@ -104,10 +104,14 @@ nogo(
|
||||
"@org_golang_x_tools//go/analysis/passes/inspect:go_tool_library",
|
||||
"@org_golang_x_tools//go/analysis/passes/asmdecl:go_tool_library",
|
||||
"//tools/analyzers/maligned:go_tool_library",
|
||||
"//tools/analyzers/roughtime:go_tool_library",
|
||||
"//tools/analyzers/cryptorand:go_tool_library",
|
||||
"//tools/analyzers/errcheck:go_tool_library",
|
||||
"//tools/analyzers/featureconfig:go_tool_library",
|
||||
"//tools/analyzers/comparesame:go_tool_library",
|
||||
"//tools/analyzers/shadowpredecl:go_tool_library",
|
||||
"//tools/analyzers/nop:go_tool_library",
|
||||
"//tools/analyzers/slicedirect:go_tool_library",
|
||||
"//tools/analyzers/ineffassign:go_tool_library",
|
||||
] + select({
|
||||
# nogo checks that fail with coverage enabled.
|
||||
":coverage_enabled": [],
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
# Prysm: An Ethereum 2.0 Client Written in Go
|
||||
|
||||
[](https://buildkite.com/prysmatic-labs/prysm)
|
||||
[](https://app.fuzzit.dev/orgs/prysmaticlabs-gh/dashboard)
|
||||
[](https://github.com/ethereum/eth2.0-specs/tree/v0.12.1)
|
||||
[](https://github.com/ethereum/eth2.0-specs/tree/v0.12.3)
|
||||
[](https://discord.gg/KSA7rPr)
|
||||
[](https://gitter.im/prysmaticlabs/geth-sharding?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
||||
|
||||
|
||||
63
WORKSPACE
63
WORKSPACE
@@ -5,11 +5,11 @@ load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
|
||||
|
||||
http_archive(
|
||||
name = "bazel_toolchains",
|
||||
sha256 = "144290c4166bd67e76a54f96cd504ed86416ca3ca82030282760f0823c10be48",
|
||||
strip_prefix = "bazel-toolchains-3.1.1",
|
||||
sha256 = "db48eed61552e25d36fe051a65d2a329cc0fb08442627e8f13960c5ab087a44e",
|
||||
strip_prefix = "bazel-toolchains-3.2.0",
|
||||
urls = [
|
||||
"https://github.com/bazelbuild/bazel-toolchains/releases/download/3.1.1/bazel-toolchains-3.1.1.tar.gz",
|
||||
"https://mirror.bazel.build/github.com/bazelbuild/bazel-toolchains/archive/3.1.1.tar.gz",
|
||||
"https://mirror.bazel.build/github.com/bazelbuild/bazel-toolchains/releases/download/3.2.0/bazel-toolchains-3.2.0.tar.gz",
|
||||
"https://github.com/bazelbuild/bazel-toolchains/releases/download/3.2.0/bazel-toolchains-3.2.0.tar.gz",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -157,10 +157,14 @@ go_rules_dependencies()
|
||||
|
||||
go_register_toolchains(nogo = "@//:nogo")
|
||||
|
||||
load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies", "go_repository")
|
||||
load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies")
|
||||
|
||||
gazelle_dependencies()
|
||||
|
||||
load("@io_bazel_rules_go//extras:embed_data_deps.bzl", "go_embed_data_dependencies")
|
||||
|
||||
go_embed_data_dependencies()
|
||||
|
||||
load("@com_github_atlassian_bazel_tools//gometalinter:deps.bzl", "gometalinter_dependencies")
|
||||
|
||||
gometalinter_dependencies()
|
||||
@@ -215,8 +219,8 @@ filegroup(
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
""",
|
||||
sha256 = "678c50336ce39bef19b2a0dc69e20a7bda37a673ae07dc0577386e9876e0a525",
|
||||
url = "https://github.com/ethereum/eth2.0-spec-tests/releases/download/v0.12.1/general.tar.gz",
|
||||
sha256 = "7e5f838e0f9110471ef8be9401ea687a8ed4d499664dc0eac34ecfdfd03c2ac3",
|
||||
url = "https://github.com/ethereum/eth2.0-spec-tests/releases/download/v0.12.3/general.tar.gz",
|
||||
)
|
||||
|
||||
http_archive(
|
||||
@@ -231,8 +235,8 @@ filegroup(
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
""",
|
||||
sha256 = "d0ce95a3ca0d30df24f96a1b5cfad1f7e6fcc07ad84ca221d92480add051af3e",
|
||||
url = "https://github.com/ethereum/eth2.0-spec-tests/releases/download/v0.12.1/minimal.tar.gz",
|
||||
sha256 = "72c2f561db879ddcdf729fef93d10e0f9162b4cf3a697c513ef8935b93f6165a",
|
||||
url = "https://github.com/ethereum/eth2.0-spec-tests/releases/download/v0.12.3/minimal.tar.gz",
|
||||
)
|
||||
|
||||
http_archive(
|
||||
@@ -247,8 +251,8 @@ filegroup(
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
""",
|
||||
sha256 = "1dfa1ae6822912508dbf6d1fe7608169372daa3ad1e53a3ed0867cb2d6e0ccb0",
|
||||
url = "https://github.com/ethereum/eth2.0-spec-tests/releases/download/v0.12.1/mainnet.tar.gz",
|
||||
sha256 = "63eca02503692a0b6a2d7b70118e0dd62dff094153a3a542af6dbea721841b0d",
|
||||
url = "https://github.com/ethereum/eth2.0-spec-tests/releases/download/v0.12.3/mainnet.tar.gz",
|
||||
)
|
||||
|
||||
http_archive(
|
||||
@@ -336,6 +340,22 @@ go_binary(
|
||||
urls = ["https://github.com/ferranbt/fastssz/archive/06015a5d84f9e4eefe2c21377ca678fa8f1a1b09.tar.gz"],
|
||||
)
|
||||
|
||||
http_archive(
|
||||
name = "prysm_web_ui",
|
||||
build_file_content = """
|
||||
filegroup(
|
||||
name = "site",
|
||||
srcs = glob(["**/*"]),
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
""",
|
||||
sha256 = "507d574be56a63d5a30a28b4426b9ece89cf70bbb29739e982e0a8fdf1285e3a",
|
||||
urls = [
|
||||
"https://prysmaticlabs.com/uploads/prysm-web-ui.0.0.1-alpha.tar.gz",
|
||||
"https://github.com/prysmaticlabs/prysm-web-ui/releases/download/0.0.1-alpha/prysm-web-ui.tar.gz",
|
||||
],
|
||||
)
|
||||
|
||||
load("//:deps.bzl", "prysm_deps")
|
||||
|
||||
# gazelle:repository_macro deps.bzl%prysm_deps
|
||||
@@ -354,24 +374,3 @@ load("@com_github_ethereum_go_ethereum//:deps.bzl", "geth_dependencies")
|
||||
geth_dependencies()
|
||||
|
||||
# Do NOT add new go dependencies here! Refer to DEPENDENCIES.md!
|
||||
|
||||
go_repository(
|
||||
name = "com_github_nbutton23_zxcvbn_go",
|
||||
importpath = "github.com/nbutton23/zxcvbn-go",
|
||||
sum = "h1:AREM5mwr4u1ORQBMvzfzBgpsctsbQikCVpvC+tX285E=",
|
||||
version = "v0.0.0-20180912185939-ae427f1e4c1d",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "com_github_brianium_mnemonic",
|
||||
importpath = "github.com/brianium/mnemonic",
|
||||
sum = "h1:futFTqrUAf1IanFLU+jK4D1NpgE/+gCbnCG7Fl0rHs0=",
|
||||
version = "v0.0.0-20180124190051-72af92c51f88",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "com_github_logrusorgru_aurora",
|
||||
importpath = "github.com/logrusorgru/aurora",
|
||||
sum = "h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8=",
|
||||
version = "v2.0.3+incompatible",
|
||||
)
|
||||
|
||||
@@ -5,6 +5,7 @@ go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"chain_info.go",
|
||||
"checkpoint_info_cache.go",
|
||||
"head.go",
|
||||
"info.go",
|
||||
"init_sync_process_block.go",
|
||||
@@ -17,9 +18,13 @@ go_library(
|
||||
"receive_attestation.go",
|
||||
"receive_block.go",
|
||||
"service.go",
|
||||
"weak_subjectivity_checks.go",
|
||||
],
|
||||
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/blockchain",
|
||||
visibility = ["//beacon-chain:__subpackages__"],
|
||||
visibility = [
|
||||
"//beacon-chain:__subpackages__",
|
||||
"//fuzz:__pkg__",
|
||||
],
|
||||
deps = [
|
||||
"//beacon-chain/cache:go_default_library",
|
||||
"//beacon-chain/cache/depositcache:go_default_library",
|
||||
@@ -30,6 +35,7 @@ go_library(
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//beacon-chain/core/state:go_default_library",
|
||||
"//beacon-chain/db:go_default_library",
|
||||
"//beacon-chain/db/filters:go_default_library",
|
||||
"//beacon-chain/flags:go_default_library",
|
||||
"//beacon-chain/forkchoice:go_default_library",
|
||||
"//beacon-chain/forkchoice/protoarray:go_default_library",
|
||||
@@ -40,17 +46,18 @@ go_library(
|
||||
"//beacon-chain/powchain:go_default_library",
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//beacon-chain/state/stategen:go_default_library",
|
||||
"//beacon-chain/state/stateutil:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//shared/attestationutil:go_default_library",
|
||||
"//shared/bls:go_default_library",
|
||||
"//shared/bytesutil:go_default_library",
|
||||
"//shared/featureconfig:go_default_library",
|
||||
"//shared/hashutil:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"//shared/roughtime:go_default_library",
|
||||
"//shared/slotutil:go_default_library",
|
||||
"//shared/timeutils:go_default_library",
|
||||
"//shared/traceutil:go_default_library",
|
||||
"@com_github_emicklei_dot//:go_default_library",
|
||||
"@com_github_hashicorp_golang_lru//:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@com_github_prometheus_client_golang//prometheus:go_default_library",
|
||||
"@com_github_prometheus_client_golang//prometheus/promauto:go_default_library",
|
||||
@@ -73,6 +80,7 @@ go_test(
|
||||
size = "medium",
|
||||
srcs = [
|
||||
"chain_info_test.go",
|
||||
"checkpoint_info_cache_test.go",
|
||||
"head_test.go",
|
||||
"info_test.go",
|
||||
"process_attestation_test.go",
|
||||
@@ -80,6 +88,7 @@ go_test(
|
||||
"receive_attestation_test.go",
|
||||
"receive_block_test.go",
|
||||
"service_test.go",
|
||||
"weak_subjectivity_checks_test.go",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
|
||||
@@ -5,14 +5,14 @@ import (
|
||||
"time"
|
||||
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"go.opencensus.io/trace"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/protoarray"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
|
||||
// ChainInfoFetcher defines a common interface for methods in blockchain service which
|
||||
@@ -97,6 +97,9 @@ func (s *Service) PreviousJustifiedCheckpt() *ethpb.Checkpoint {
|
||||
|
||||
// HeadSlot returns the slot of the head of the chain.
|
||||
func (s *Service) HeadSlot() uint64 {
|
||||
s.headLock.RLock()
|
||||
defer s.headLock.RUnlock()
|
||||
|
||||
if !s.hasHeadState() {
|
||||
return 0
|
||||
}
|
||||
@@ -106,6 +109,9 @@ func (s *Service) HeadSlot() uint64 {
|
||||
|
||||
// HeadRoot returns the root of the head of the chain.
|
||||
func (s *Service) HeadRoot(ctx context.Context) ([]byte, error) {
|
||||
s.headLock.RLock()
|
||||
defer s.headLock.RUnlock()
|
||||
|
||||
if s.headRoot() != params.BeaconConfig().ZeroHash {
|
||||
r := s.headRoot()
|
||||
return r[:], nil
|
||||
@@ -119,7 +125,7 @@ func (s *Service) HeadRoot(ctx context.Context) ([]byte, error) {
|
||||
return params.BeaconConfig().ZeroHash[:], nil
|
||||
}
|
||||
|
||||
r, err := stateutil.BlockRoot(b.Block)
|
||||
r, err := b.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -131,6 +137,9 @@ func (s *Service) HeadRoot(ctx context.Context) ([]byte, error) {
|
||||
// If the head is nil from service struct,
|
||||
// it will attempt to get the head block from DB.
|
||||
func (s *Service) HeadBlock(ctx context.Context) (*ethpb.SignedBeaconBlock, error) {
|
||||
s.headLock.RLock()
|
||||
defer s.headLock.RUnlock()
|
||||
|
||||
if s.hasHeadState() {
|
||||
return s.headBlock(), nil
|
||||
}
|
||||
@@ -144,6 +153,8 @@ func (s *Service) HeadBlock(ctx context.Context) (*ethpb.SignedBeaconBlock, erro
|
||||
func (s *Service) HeadState(ctx context.Context) (*state.BeaconState, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "blockChain.HeadState")
|
||||
defer span.End()
|
||||
s.headLock.RLock()
|
||||
defer s.headLock.RUnlock()
|
||||
|
||||
ok := s.hasHeadState()
|
||||
span.AddAttributes(trace.BoolAttribute("cache_hit", ok))
|
||||
@@ -157,6 +168,9 @@ func (s *Service) HeadState(ctx context.Context) (*state.BeaconState, error) {
|
||||
|
||||
// HeadValidatorsIndices returns a list of active validator indices from the head view of a given epoch.
|
||||
func (s *Service) HeadValidatorsIndices(ctx context.Context, epoch uint64) ([]uint64, error) {
|
||||
s.headLock.RLock()
|
||||
defer s.headLock.RUnlock()
|
||||
|
||||
if !s.hasHeadState() {
|
||||
return []uint64{}, nil
|
||||
}
|
||||
@@ -165,6 +179,9 @@ func (s *Service) HeadValidatorsIndices(ctx context.Context, epoch uint64) ([]ui
|
||||
|
||||
// HeadSeed returns the seed from the head view of a given epoch.
|
||||
func (s *Service) HeadSeed(ctx context.Context, epoch uint64) ([32]byte, error) {
|
||||
s.headLock.RLock()
|
||||
defer s.headLock.RUnlock()
|
||||
|
||||
if !s.hasHeadState() {
|
||||
return [32]byte{}, nil
|
||||
}
|
||||
@@ -174,6 +191,9 @@ func (s *Service) HeadSeed(ctx context.Context, epoch uint64) ([32]byte, error)
|
||||
|
||||
// HeadGenesisValidatorRoot returns genesis validator root of the head state.
|
||||
func (s *Service) HeadGenesisValidatorRoot() [32]byte {
|
||||
s.headLock.RLock()
|
||||
defer s.headLock.RUnlock()
|
||||
|
||||
if !s.hasHeadState() {
|
||||
return [32]byte{}
|
||||
}
|
||||
@@ -183,6 +203,9 @@ func (s *Service) HeadGenesisValidatorRoot() [32]byte {
|
||||
|
||||
// HeadETH1Data returns the eth1data of the current head state.
|
||||
func (s *Service) HeadETH1Data() *ethpb.Eth1Data {
|
||||
s.headLock.RLock()
|
||||
defer s.headLock.RUnlock()
|
||||
|
||||
if !s.hasHeadState() {
|
||||
return ðpb.Eth1Data{}
|
||||
}
|
||||
@@ -202,6 +225,9 @@ func (s *Service) GenesisTime() time.Time {
|
||||
// GenesisValidatorRoot returns the genesis validator
|
||||
// root of the chain.
|
||||
func (s *Service) GenesisValidatorRoot() [32]byte {
|
||||
s.headLock.RLock()
|
||||
defer s.headLock.RUnlock()
|
||||
|
||||
if !s.hasHeadState() {
|
||||
return [32]byte{}
|
||||
}
|
||||
@@ -210,6 +236,9 @@ func (s *Service) GenesisValidatorRoot() [32]byte {
|
||||
|
||||
// CurrentFork retrieves the latest fork information of the beacon chain.
|
||||
func (s *Service) CurrentFork() *pb.Fork {
|
||||
s.headLock.RLock()
|
||||
defer s.headLock.RUnlock()
|
||||
|
||||
if !s.hasHeadState() {
|
||||
return &pb.Fork{
|
||||
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package blockchain
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -11,22 +10,22 @@ import (
|
||||
testDB "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
// Ensure Service implements chain info interface.
|
||||
var _ = ChainInfoFetcher(&Service{})
|
||||
var _ = TimeFetcher(&Service{})
|
||||
var _ = ForkFetcher(&Service{})
|
||||
var _ ChainInfoFetcher = (*Service)(nil)
|
||||
var _ TimeFetcher = (*Service)(nil)
|
||||
var _ ForkFetcher = (*Service)(nil)
|
||||
|
||||
func TestFinalizedCheckpt_Nil(t *testing.T) {
|
||||
db, sc := testDB.SetupDB(t)
|
||||
c := setupBeaconChain(t, db, sc)
|
||||
if !bytes.Equal(c.FinalizedCheckpt().Root, params.BeaconConfig().ZeroHash[:]) {
|
||||
t.Error("Incorrect pre chain start value")
|
||||
}
|
||||
assert.DeepEqual(t, params.BeaconConfig().ZeroHash[:], c.FinalizedCheckpt().Root, "Incorrect pre chain start value")
|
||||
}
|
||||
|
||||
func TestHeadRoot_Nil(t *testing.T) {
|
||||
@@ -34,15 +33,13 @@ func TestHeadRoot_Nil(t *testing.T) {
|
||||
c := setupBeaconChain(t, db, sc)
|
||||
headRoot, err := c.HeadRoot(context.Background())
|
||||
require.NoError(t, err)
|
||||
if !bytes.Equal(headRoot, params.BeaconConfig().ZeroHash[:]) {
|
||||
t.Error("Incorrect pre chain start value")
|
||||
}
|
||||
assert.DeepEqual(t, params.BeaconConfig().ZeroHash[:], headRoot, "Incorrect pre chain start value")
|
||||
}
|
||||
|
||||
func TestFinalizedCheckpt_CanRetrieve(t *testing.T) {
|
||||
db, sc := testDB.SetupDB(t)
|
||||
|
||||
cp := ðpb.Checkpoint{Epoch: 5, Root: []byte("foo")}
|
||||
cp := ðpb.Checkpoint{Epoch: 5, Root: bytesutil.PadTo([]byte("foo"), 32)}
|
||||
c := setupBeaconChain(t, db, sc)
|
||||
c.finalizedCheckpt = cp
|
||||
|
||||
@@ -57,16 +54,13 @@ func TestFinalizedCheckpt_GenesisRootOk(t *testing.T) {
|
||||
c := setupBeaconChain(t, db, sc)
|
||||
c.finalizedCheckpt = cp
|
||||
c.genesisRoot = genesisRoot
|
||||
|
||||
if !bytes.Equal(c.FinalizedCheckpt().Root, c.genesisRoot[:]) {
|
||||
t.Errorf("Got: %v, wanted: %v", c.FinalizedCheckpt().Root, c.genesisRoot[:])
|
||||
}
|
||||
assert.DeepEqual(t, c.genesisRoot[:], c.FinalizedCheckpt().Root)
|
||||
}
|
||||
|
||||
func TestCurrentJustifiedCheckpt_CanRetrieve(t *testing.T) {
|
||||
db, sc := testDB.SetupDB(t)
|
||||
|
||||
cp := ðpb.Checkpoint{Epoch: 6, Root: []byte("foo")}
|
||||
cp := ðpb.Checkpoint{Epoch: 6, Root: bytesutil.PadTo([]byte("foo"), 32)}
|
||||
c := setupBeaconChain(t, db, sc)
|
||||
c.justifiedCheckpt = cp
|
||||
|
||||
@@ -81,19 +75,15 @@ func TestJustifiedCheckpt_GenesisRootOk(t *testing.T) {
|
||||
c := setupBeaconChain(t, db, sc)
|
||||
c.justifiedCheckpt = cp
|
||||
c.genesisRoot = genesisRoot
|
||||
|
||||
if !bytes.Equal(c.CurrentJustifiedCheckpt().Root, c.genesisRoot[:]) {
|
||||
t.Errorf("Got: %v, wanted: %v", c.CurrentJustifiedCheckpt().Root, c.genesisRoot[:])
|
||||
}
|
||||
assert.DeepEqual(t, c.genesisRoot[:], c.CurrentJustifiedCheckpt().Root)
|
||||
}
|
||||
|
||||
func TestPreviousJustifiedCheckpt_CanRetrieve(t *testing.T) {
|
||||
db, sc := testDB.SetupDB(t)
|
||||
|
||||
cp := ðpb.Checkpoint{Epoch: 7, Root: []byte("foo")}
|
||||
cp := ðpb.Checkpoint{Epoch: 7, Root: bytesutil.PadTo([]byte("foo"), 32)}
|
||||
c := setupBeaconChain(t, db, sc)
|
||||
c.prevJustifiedCheckpt = cp
|
||||
|
||||
assert.Equal(t, cp.Epoch, c.PreviousJustifiedCheckpt().Epoch, "Unexpected previous justified epoch")
|
||||
}
|
||||
|
||||
@@ -105,30 +95,28 @@ func TestPrevJustifiedCheckpt_GenesisRootOk(t *testing.T) {
|
||||
c := setupBeaconChain(t, db, sc)
|
||||
c.prevJustifiedCheckpt = cp
|
||||
c.genesisRoot = genesisRoot
|
||||
|
||||
if !bytes.Equal(c.PreviousJustifiedCheckpt().Root, c.genesisRoot[:]) {
|
||||
t.Errorf("Got: %v, wanted: %v", c.PreviousJustifiedCheckpt().Root, c.genesisRoot[:])
|
||||
}
|
||||
assert.DeepEqual(t, c.genesisRoot[:], c.PreviousJustifiedCheckpt().Root)
|
||||
}
|
||||
|
||||
func TestHeadSlot_CanRetrieve(t *testing.T) {
|
||||
c := &Service{}
|
||||
s, err := state.InitializeFromProto(&pb.BeaconState{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
c.head = &head{slot: 100, state: s}
|
||||
assert.Equal(t, uint64(100), c.headSlot())
|
||||
assert.Equal(t, uint64(100), c.HeadSlot())
|
||||
}
|
||||
|
||||
func TestHeadRoot_CanRetrieve(t *testing.T) {
|
||||
c := &Service{}
|
||||
c.head = &head{root: [32]byte{'A'}}
|
||||
assert.Equal(t, [32]byte{'A'}, c.headRoot())
|
||||
r, err := c.HeadRoot(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, [32]byte{'A'}, bytesutil.ToBytes32(r))
|
||||
}
|
||||
|
||||
func TestHeadBlock_CanRetrieve(t *testing.T) {
|
||||
b := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Slot: 1}}
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block.Slot = 1
|
||||
s, err := state.InitializeFromProto(&pb.BeaconState{})
|
||||
require.NoError(t, err)
|
||||
c := &Service{}
|
||||
@@ -146,9 +134,7 @@ func TestHeadState_CanRetrieve(t *testing.T) {
|
||||
c.head = &head{state: s}
|
||||
headState, err := c.HeadState(context.Background())
|
||||
require.NoError(t, err)
|
||||
if !proto.Equal(s.InnerStateUnsafe(), headState.InnerStateUnsafe()) {
|
||||
t.Error("incorrect head state received")
|
||||
}
|
||||
assert.DeepEqual(t, headState.InnerStateUnsafe(), s.InnerStateUnsafe(), "Incorrect head state received")
|
||||
}
|
||||
|
||||
func TestGenesisTime_CanRetrieve(t *testing.T) {
|
||||
|
||||
83
beacon-chain/blockchain/checkpoint_info_cache.go
Normal file
83
beacon-chain/blockchain/checkpoint_info_cache.go
Normal file
@@ -0,0 +1,83 @@
|
||||
package blockchain
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
lru "github.com/hashicorp/golang-lru"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/hashutil"
|
||||
)
|
||||
|
||||
var (
|
||||
// This defines the max number of checkpoint info this cache can store.
|
||||
// Each cache is calculated at 3MB(30K validators), the total cache size is around 100MB.
|
||||
// Due to reorgs and long finality, it's good to keep the old cache around for quickly switch over.
|
||||
maxInfoSize = 32
|
||||
|
||||
// This tracks the number of check point info requests that aren't present in the cache.
|
||||
infoMiss = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "check_point_info_cache_miss",
|
||||
Help: "The number of check point info requests that aren't present in the cache.",
|
||||
})
|
||||
// This tracks the number of check point info requests that are in the cache.
|
||||
infoHit = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "check_point_info_cache_hit",
|
||||
Help: "The number of check point info requests that are present in the cache.",
|
||||
})
|
||||
)
|
||||
|
||||
// checkPtInfoCache is a struct with 1 LRU cache for looking up check point info by checkpoint.
|
||||
type checkPtInfoCache struct {
|
||||
cache *lru.Cache
|
||||
lock sync.RWMutex
|
||||
}
|
||||
|
||||
// newCheckPointInfoCache creates a new checkpoint info cache for storing/accessing processed check point info object.
|
||||
func newCheckPointInfoCache() *checkPtInfoCache {
|
||||
cache, err := lru.New(maxInfoSize)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return &checkPtInfoCache{
|
||||
cache: cache,
|
||||
}
|
||||
}
|
||||
|
||||
// get fetches check point info by check point. Returns the reference of the CheckPtInfo, nil if doesn't exist.
|
||||
func (c *checkPtInfoCache) get(cp *ethpb.Checkpoint) (*pb.CheckPtInfo, error) {
|
||||
c.lock.RLock()
|
||||
defer c.lock.RUnlock()
|
||||
h, err := hashutil.HashProto(cp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
item, exists := c.cache.Get(h)
|
||||
|
||||
if exists && item != nil {
|
||||
infoHit.Inc()
|
||||
// Copy here is unnecessary since the returned check point info object
|
||||
// will only be used to verify attestation signature.
|
||||
return item.(*pb.CheckPtInfo), nil
|
||||
}
|
||||
|
||||
infoMiss.Inc()
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// put adds CheckPtInfo object to the cache. This method also trims the least
|
||||
// recently added CheckPtInfo object if the cache size has ready the max cache size limit.
|
||||
func (c *checkPtInfoCache) put(cp *ethpb.Checkpoint, info *pb.CheckPtInfo) error {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
h, err := hashutil.HashProto(cp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.cache.Add(h, info)
|
||||
return nil
|
||||
}
|
||||
41
beacon-chain/blockchain/checkpoint_info_cache_test.go
Normal file
41
beacon-chain/blockchain/checkpoint_info_cache_test.go
Normal file
@@ -0,0 +1,41 @@
|
||||
package blockchain
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
func TestHotStateCache_RoundTrip(t *testing.T) {
|
||||
c := newCheckPointInfoCache()
|
||||
cp := ðpb.Checkpoint{
|
||||
Epoch: 1,
|
||||
Root: bytesutil.PadTo([]byte{'a'}, 32),
|
||||
}
|
||||
info, err := c.get(cp)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, (*pb.CheckPtInfo)(nil), info)
|
||||
|
||||
i := &pb.CheckPtInfo{
|
||||
Seed: bytesutil.PadTo([]byte{'c'}, 32),
|
||||
GenesisRoot: bytesutil.PadTo([]byte{'d'}, 32),
|
||||
ActiveIndices: []uint64{0, 1, 2, 3},
|
||||
}
|
||||
|
||||
require.NoError(t, c.put(cp, i))
|
||||
info, err = c.get(cp)
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, info, i)
|
||||
}
|
||||
|
||||
func TestHotStateCache_CanPrune(t *testing.T) {
|
||||
c := newCheckPointInfoCache()
|
||||
for i := 0; i < maxInfoSize+1; i++ {
|
||||
cp := ðpb.Checkpoint{Epoch: uint64(i), Root: make([]byte, 32)}
|
||||
require.NoError(t, c.put(cp, &pb.CheckPtInfo{}))
|
||||
}
|
||||
require.Equal(t, len(c.cache.Keys()), maxInfoSize)
|
||||
}
|
||||
@@ -72,7 +72,11 @@ func (s *Service) saveHead(ctx context.Context, headRoot [32]byte) error {
|
||||
defer span.End()
|
||||
|
||||
// Do nothing if head hasn't changed.
|
||||
if headRoot == s.headRoot() {
|
||||
r, err := s.HeadRoot(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if headRoot == bytesutil.ToBytes32(r) {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -101,16 +105,17 @@ func (s *Service) saveHead(ctx context.Context, headRoot [32]byte) error {
|
||||
}
|
||||
|
||||
// A chain re-org occurred, so we fire an event notifying the rest of the services.
|
||||
if bytesutil.ToBytes32(newHeadBlock.Block.ParentRoot) != s.headRoot() {
|
||||
headSlot := s.HeadSlot()
|
||||
if bytesutil.ToBytes32(newHeadBlock.Block.ParentRoot) != bytesutil.ToBytes32(r) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"newSlot": fmt.Sprintf("%d", newHeadBlock.Block.Slot),
|
||||
"oldSlot": fmt.Sprintf("%d", s.headSlot()),
|
||||
"oldSlot": fmt.Sprintf("%d", headSlot),
|
||||
}).Debug("Chain reorg occurred")
|
||||
s.stateNotifier.StateFeed().Send(&feed.Event{
|
||||
Type: statefeed.Reorg,
|
||||
Data: &statefeed.ReorgData{
|
||||
NewSlot: newHeadBlock.Block.Slot,
|
||||
OldSlot: s.headSlot(),
|
||||
OldSlot: headSlot,
|
||||
},
|
||||
})
|
||||
|
||||
@@ -131,7 +136,7 @@ func (s *Service) saveHead(ctx context.Context, headRoot [32]byte) error {
|
||||
// This gets called to update canonical root mapping. It does not save head block
|
||||
// root in DB. With the inception of initial-sync-cache-state flag, it uses finalized
|
||||
// check point as anchors to resume sync therefore head is no longer needed to be saved on per slot basis.
|
||||
func (s *Service) saveHeadNoDB(ctx context.Context, b *ethpb.SignedBeaconBlock, r [32]byte) error {
|
||||
func (s *Service) saveHeadNoDB(ctx context.Context, b *ethpb.SignedBeaconBlock, r [32]byte, hs *state.BeaconState) error {
|
||||
cachedHeadRoot, err := s.HeadRoot(ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get head root from cache")
|
||||
@@ -144,16 +149,7 @@ func (s *Service) saveHeadNoDB(ctx context.Context, b *ethpb.SignedBeaconBlock,
|
||||
return errors.New("cannot save nil head block")
|
||||
}
|
||||
|
||||
headState, err := s.stateGen.StateByRootInitialSync(ctx, r)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not retrieve head state in DB")
|
||||
}
|
||||
if headState == nil {
|
||||
return errors.New("nil head state")
|
||||
}
|
||||
|
||||
s.setHeadInitialSync(r, stateTrie.CopySignedBeaconBlock(b), headState)
|
||||
|
||||
s.setHeadInitialSync(r, stateTrie.CopySignedBeaconBlock(b), hs)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -188,60 +184,56 @@ func (s *Service) setHeadInitialSync(root [32]byte, block *ethpb.SignedBeaconBlo
|
||||
}
|
||||
|
||||
// This returns the head slot.
|
||||
// This is a lock free version.
|
||||
func (s *Service) headSlot() uint64 {
|
||||
s.headLock.RLock()
|
||||
defer s.headLock.RUnlock()
|
||||
|
||||
return s.head.slot
|
||||
}
|
||||
|
||||
// This returns the head root.
|
||||
// It does a full copy on head root for immutability.
|
||||
// This is a lock free version.
|
||||
func (s *Service) headRoot() [32]byte {
|
||||
if s.head == nil {
|
||||
return params.BeaconConfig().ZeroHash
|
||||
}
|
||||
|
||||
s.headLock.RLock()
|
||||
defer s.headLock.RUnlock()
|
||||
|
||||
return s.head.root
|
||||
}
|
||||
|
||||
// This returns the head block.
|
||||
// It does a full copy on head block for immutability.
|
||||
// This is a lock free version.
|
||||
func (s *Service) headBlock() *ethpb.SignedBeaconBlock {
|
||||
s.headLock.RLock()
|
||||
defer s.headLock.RUnlock()
|
||||
|
||||
return stateTrie.CopySignedBeaconBlock(s.head.block)
|
||||
}
|
||||
|
||||
// This returns the head state.
|
||||
// It does a full copy on head state for immutability.
|
||||
// This is a lock free version.
|
||||
func (s *Service) headState(ctx context.Context) *stateTrie.BeaconState {
|
||||
ctx, span := trace.StartSpan(ctx, "blockChain.headState")
|
||||
defer span.End()
|
||||
|
||||
s.headLock.RLock()
|
||||
defer s.headLock.RUnlock()
|
||||
|
||||
return s.head.state.Copy()
|
||||
}
|
||||
|
||||
// This returns the genesis validator root of the head state.
|
||||
// This is a lock free version.
|
||||
func (s *Service) headGenesisValidatorRoot() [32]byte {
|
||||
s.headLock.RLock()
|
||||
defer s.headLock.RUnlock()
|
||||
|
||||
return bytesutil.ToBytes32(s.head.state.GenesisValidatorRoot())
|
||||
}
|
||||
|
||||
// Returns true if head state exists.
|
||||
func (s *Service) hasHeadState() bool {
|
||||
// HasHeadState returns true if head state exists.
|
||||
func (s *Service) HasHeadState() bool {
|
||||
s.headLock.RLock()
|
||||
defer s.headLock.RUnlock()
|
||||
|
||||
return s.hasHeadState()
|
||||
}
|
||||
|
||||
// Returns true if head state exists.
|
||||
// This is the lock free version.
|
||||
func (s *Service) hasHeadState() bool {
|
||||
return s.head != nil && s.head.state != nil
|
||||
}
|
||||
|
||||
@@ -262,12 +254,12 @@ func (s *Service) updateRecentCanonicalBlocks(ctx context.Context, headRoot [32]
|
||||
return nil
|
||||
}
|
||||
|
||||
for node.Parent != protoarray.NonExistentNode {
|
||||
for node.Parent() != protoarray.NonExistentNode {
|
||||
if ctx.Err() != nil {
|
||||
return ctx.Err()
|
||||
}
|
||||
node = nodes[node.Parent]
|
||||
s.recentCanonicalBlocks[node.Root] = true
|
||||
node = nodes[node.Parent()]
|
||||
s.recentCanonicalBlocks[node.Root()] = true
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -5,9 +5,7 @@ import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
testDB "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
@@ -35,11 +33,12 @@ func TestSaveHead_Different(t *testing.T) {
|
||||
oldRoot := [32]byte{'A'}
|
||||
service.head = &head{slot: 0, root: oldRoot}
|
||||
|
||||
newHeadBlock := ðpb.BeaconBlock{Slot: 1}
|
||||
newHeadSignedBlock := ðpb.SignedBeaconBlock{Block: newHeadBlock}
|
||||
newHeadSignedBlock := testutil.NewBeaconBlock()
|
||||
newHeadSignedBlock.Block.Slot = 1
|
||||
newHeadBlock := newHeadSignedBlock.Block
|
||||
|
||||
require.NoError(t, service.beaconDB.SaveBlock(context.Background(), newHeadSignedBlock))
|
||||
newRoot, err := stateutil.BlockRoot(newHeadBlock)
|
||||
newRoot, err := newHeadBlock.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
headState := testutil.NewBeaconState()
|
||||
require.NoError(t, headState.SetSlot(1))
|
||||
@@ -68,14 +67,13 @@ func TestSaveHead_Different_Reorg(t *testing.T) {
|
||||
service.head = &head{slot: 0, root: oldRoot}
|
||||
|
||||
reorgChainParent := [32]byte{'B'}
|
||||
newHeadBlock := ðpb.BeaconBlock{
|
||||
Slot: 1,
|
||||
ParentRoot: reorgChainParent[:],
|
||||
}
|
||||
newHeadSignedBlock := ðpb.SignedBeaconBlock{Block: newHeadBlock}
|
||||
newHeadSignedBlock := testutil.NewBeaconBlock()
|
||||
newHeadSignedBlock.Block.Slot = 1
|
||||
newHeadSignedBlock.Block.ParentRoot = reorgChainParent[:]
|
||||
newHeadBlock := newHeadSignedBlock.Block
|
||||
|
||||
require.NoError(t, service.beaconDB.SaveBlock(context.Background(), newHeadSignedBlock))
|
||||
newRoot, err := stateutil.BlockRoot(newHeadBlock)
|
||||
newRoot, err := newHeadBlock.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
headState := testutil.NewBeaconState()
|
||||
require.NoError(t, headState.SetSlot(1))
|
||||
@@ -92,7 +90,7 @@ func TestSaveHead_Different_Reorg(t *testing.T) {
|
||||
}
|
||||
assert.DeepEqual(t, newHeadSignedBlock, service.headBlock(), "Head did not change")
|
||||
assert.DeepEqual(t, headState.CloneInnerState(), service.headState(ctx).CloneInnerState(), "Head did not change")
|
||||
testutil.AssertLogsContain(t, hook, "Chain reorg occurred")
|
||||
require.LogsContain(t, hook, "Chain reorg occurred")
|
||||
}
|
||||
|
||||
func TestUpdateRecentCanonicalBlocks_CanUpdateWithoutParent(t *testing.T) {
|
||||
|
||||
@@ -34,7 +34,12 @@ const template = `<html>
|
||||
|
||||
// TreeHandler is a handler to serve /tree page in metrics.
|
||||
func (s *Service) TreeHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if s.headState(r.Context()) == nil {
|
||||
headState, err := s.HeadState(r.Context())
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Could not get head state")
|
||||
return
|
||||
}
|
||||
if headState == nil {
|
||||
if _, err := w.Write([]byte("Unavailable during initial syncing")); err != nil {
|
||||
log.WithError(err).Error("Failed to render p2p info page")
|
||||
}
|
||||
@@ -47,25 +52,25 @@ func (s *Service) TreeHandler(w http.ResponseWriter, r *http.Request) {
|
||||
graph.Attr("labeljust", "l")
|
||||
|
||||
dotNodes := make([]*dot.Node, len(nodes))
|
||||
avgBalance := uint64(averageBalance(s.headState(r.Context()).Balances()))
|
||||
avgBalance := uint64(averageBalance(headState.Balances()))
|
||||
|
||||
for i := len(nodes) - 1; i >= 0; i-- {
|
||||
// Construct label for each node.
|
||||
slot := fmt.Sprintf("%d", nodes[i].Slot)
|
||||
weight := fmt.Sprintf("%d", nodes[i].Weight/1e9) // Convert unit Gwei to unit ETH.
|
||||
votes := fmt.Sprintf("%d", nodes[i].Weight/1e9/avgBalance)
|
||||
slot := fmt.Sprintf("%d", nodes[i].Slot())
|
||||
weight := fmt.Sprintf("%d", nodes[i].Weight()/1e9) // Convert unit Gwei to unit ETH.
|
||||
votes := fmt.Sprintf("%d", nodes[i].Weight()/1e9/avgBalance)
|
||||
index := fmt.Sprintf("%d", i)
|
||||
g := nodes[i].Graffiti[:]
|
||||
g := nodes[i].Graffiti()
|
||||
graffiti := hex.EncodeToString(g[:8])
|
||||
label := "slot: " + slot + "\n votes: " + votes + "\n weight: " + weight + "\n graffiti: " + graffiti
|
||||
var dotN dot.Node
|
||||
if nodes[i].Parent != ^uint64(0) {
|
||||
if nodes[i].Parent() != ^uint64(0) {
|
||||
dotN = graph.Node(index).Box().Attr("label", label)
|
||||
}
|
||||
|
||||
if nodes[i].Slot == s.headSlot() &&
|
||||
nodes[i].BestDescendant == ^uint64(0) &&
|
||||
nodes[i].Parent != ^uint64(0) {
|
||||
if nodes[i].Slot() == s.HeadSlot() &&
|
||||
nodes[i].BestDescendant() == ^uint64(0) &&
|
||||
nodes[i].Parent() != ^uint64(0) {
|
||||
dotN = dotN.Attr("color", "green")
|
||||
}
|
||||
|
||||
@@ -73,8 +78,8 @@ func (s *Service) TreeHandler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
for i := len(nodes) - 1; i >= 0; i-- {
|
||||
if nodes[i].Parent != ^uint64(0) && nodes[i].Parent < uint64(len(dotNodes)) {
|
||||
graph.Edge(*dotNodes[i], *dotNodes[nodes[i].Parent])
|
||||
if nodes[i].Parent() != ^uint64(0) && nodes[i].Parent() < uint64(len(dotNodes)) {
|
||||
graph.Edge(*dotNodes[i], *dotNodes[nodes[i].Parent()])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ func TestService_TreeHandler(t *testing.T) {
|
||||
StateGen: stategen.New(db, sCache),
|
||||
}
|
||||
s, err := NewService(ctx, cfg)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, s.forkChoiceStore.ProcessBlock(ctx, 0, [32]byte{'a'}, [32]byte{'g'}, [32]byte{'c'}, 0, 0))
|
||||
require.NoError(t, s.forkChoiceStore.ProcessBlock(ctx, 1, [32]byte{'b'}, [32]byte{'a'}, [32]byte{'c'}, 0, 0))
|
||||
s.setHead([32]byte{'a'}, testutil.NewBeaconBlock(), headState)
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
@@ -25,9 +26,10 @@ func logStateTransitionData(b *ethpb.BeaconBlock) {
|
||||
func logBlockSyncStatus(block *ethpb.BeaconBlock, blockRoot [32]byte, finalized *ethpb.Checkpoint) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"slot": block.Slot,
|
||||
"slotInEpoch": block.Slot % params.BeaconConfig().SlotsPerEpoch,
|
||||
"block": fmt.Sprintf("0x%s...", hex.EncodeToString(blockRoot[:])[:8]),
|
||||
"epoch": helpers.SlotToEpoch(block.Slot),
|
||||
"finalizedEpoch": finalized.Epoch,
|
||||
"finalizedRoot": fmt.Sprintf("0x%s...", hex.EncodeToString(finalized.Root[:])[:8]),
|
||||
"finalizedRoot": fmt.Sprintf("0x%s...", hex.EncodeToString(finalized.Root)[:8]),
|
||||
}).Info("Synced new block")
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/roughtime"
|
||||
"github.com/prysmaticlabs/prysm/shared/timeutils"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -76,14 +76,26 @@ var (
|
||||
Name: "current_eth1_data_deposit_count",
|
||||
Help: "The current eth1 deposit count in the last processed state eth1data field.",
|
||||
})
|
||||
totalEligibleBalances = promauto.NewGauge(prometheus.GaugeOpts{
|
||||
Name: "total_eligible_balances",
|
||||
Help: "The total amount of ether, in gwei, that is eligible for voting of previous epoch",
|
||||
stateTrieReferences = promauto.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Name: "field_references",
|
||||
Help: "The number of states a particular field is shared with.",
|
||||
}, []string{"state"})
|
||||
prevEpochActiveBalances = promauto.NewGauge(prometheus.GaugeOpts{
|
||||
Name: "beacon_prev_epoch_active_gwei",
|
||||
Help: "The total amount of ether, in gwei, that was active for voting of previous epoch",
|
||||
})
|
||||
totalVotedTargetBalances = promauto.NewGauge(prometheus.GaugeOpts{
|
||||
Name: "total_voted_target_balances",
|
||||
prevEpochSourceBalances = promauto.NewGauge(prometheus.GaugeOpts{
|
||||
Name: "beacon_prev_epoch_source_gwei",
|
||||
Help: "The total amount of ether, in gwei, that has been used in voting attestation source of previous epoch",
|
||||
})
|
||||
prevEpochTargetBalances = promauto.NewGauge(prometheus.GaugeOpts{
|
||||
Name: "beacon_prev_epoch_target_gwei",
|
||||
Help: "The total amount of ether, in gwei, that has been used in voting attestation target of previous epoch",
|
||||
})
|
||||
prevEpochHeadBalances = promauto.NewGauge(prometheus.GaugeOpts{
|
||||
Name: "beacon_prev_epoch_head_gwei",
|
||||
Help: "The total amount of ether, in gwei, that has been used in voting attestation head of previous epoch",
|
||||
})
|
||||
reorgCount = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "beacon_reorg_total",
|
||||
Help: "Count the number of times beacon chain has a reorg",
|
||||
@@ -102,6 +114,15 @@ var (
|
||||
Buckets: []float64{1, 2, 3, 4, 6, 32, 64},
|
||||
},
|
||||
)
|
||||
// TODO(7141): Remove deprecated metrics below.
|
||||
totalEligibleBalances = promauto.NewGauge(prometheus.GaugeOpts{
|
||||
Name: "total_eligible_balances",
|
||||
Help: "The total amount of ether, in gwei, that is eligible for voting of previous epoch",
|
||||
})
|
||||
totalVotedTargetBalances = promauto.NewGauge(prometheus.GaugeOpts{
|
||||
Name: "total_voted_target_balances",
|
||||
Help: "The total amount of ether, in gwei, that has been used in voting attestation target of previous epoch",
|
||||
})
|
||||
)
|
||||
|
||||
// reportSlotMetrics reports slot related metrics.
|
||||
@@ -201,6 +222,14 @@ func reportEpochMetrics(state *stateTrie.BeaconState) {
|
||||
if precompute.Balances != nil {
|
||||
totalEligibleBalances.Set(float64(precompute.Balances.ActivePrevEpoch))
|
||||
totalVotedTargetBalances.Set(float64(precompute.Balances.PrevEpochTargetAttested))
|
||||
prevEpochActiveBalances.Set(float64(precompute.Balances.ActivePrevEpoch))
|
||||
prevEpochSourceBalances.Set(float64(precompute.Balances.PrevEpochAttested))
|
||||
prevEpochTargetBalances.Set(float64(precompute.Balances.PrevEpochTargetAttested))
|
||||
prevEpochHeadBalances.Set(float64(precompute.Balances.PrevEpochHeadAttested))
|
||||
}
|
||||
refMap := state.FieldReferencesCount()
|
||||
for name, val := range refMap {
|
||||
stateTrieReferences.WithLabelValues(name).Set(float64(val))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,7 +239,7 @@ func captureSentTimeMetric(genesisTime uint64, currentSlot uint64) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
diffMs := roughtime.Now().Sub(startTime) / time.Millisecond
|
||||
diffMs := timeutils.Now().Sub(startTime) / time.Millisecond
|
||||
sentBlockPropagationHistogram.Observe(float64(diffMs))
|
||||
|
||||
return nil
|
||||
|
||||
@@ -8,9 +8,12 @@ import (
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/shared/attestationutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/roughtime"
|
||||
"github.com/prysmaticlabs/prysm/shared/timeutils"
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
|
||||
@@ -23,49 +26,23 @@ var ErrTargetRootNotInDB = errors.New("target root does not exist in db")
|
||||
// The delay is handled by the caller in `processAttestation`.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// def on_attestation(store: Service, attestation: Attestation) -> None:
|
||||
// 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.
|
||||
// """
|
||||
// target = attestation.data.target
|
||||
// validate_on_attestation(store, attestation)
|
||||
// store_target_checkpoint_state(store, attestation.data.target)
|
||||
//
|
||||
// # Attestations must be from the current or previous epoch
|
||||
// current_epoch = compute_epoch_at_slot(get_current_slot(store))
|
||||
// # Use GENESIS_EPOCH for previous when genesis to avoid underflow
|
||||
// previous_epoch = current_epoch - 1 if current_epoch > GENESIS_EPOCH else GENESIS_EPOCH
|
||||
// # If attestation target is from a future epoch, delay consideration until the epoch arrives
|
||||
// assert target.epoch in [current_epoch, previous_epoch]
|
||||
// assert target.epoch == compute_epoch_at_slot(attestation.data.slot)
|
||||
//
|
||||
// # Attestations target be for a known block. If target block is unknown, delay consideration until the block is found
|
||||
// assert target.root in store.blocks
|
||||
//
|
||||
// # Attestations must be for a known block. If block is unknown, delay consideration until the block is found
|
||||
// assert attestation.data.beacon_block_root in store.blocks
|
||||
// # Attestations must not be for blocks in the future. If not, the attestation should not be considered
|
||||
// assert store.blocks[attestation.data.beacon_block_root].slot <= attestation.data.slot
|
||||
//
|
||||
// # Service target checkpoint state if not yet seen
|
||||
// if target not in store.checkpoint_states:
|
||||
// process_slots(base_state, compute_start_slot_at_epoch(target.epoch))
|
||||
// store.checkpoint_states[target] = base_state
|
||||
// target_state = store.checkpoint_states[target]
|
||||
//
|
||||
// # Attestations can only affect the fork choice of subsequent slots.
|
||||
// # Delay consideration in the fork choice until their slot is in the past.
|
||||
// assert store.time >= (attestation.data.slot + 1) * SECONDS_PER_SLOT
|
||||
//
|
||||
// # Get state at the `target` to validate attestation and calculate the committees
|
||||
// # 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 i in indexed_attestation.attesting_indices:
|
||||
// if i not in store.latest_messages or target.epoch > store.latest_messages[i].epoch:
|
||||
// store.latest_messages[i] = LatestMessage(epoch=target.epoch, root=attestation.data.beacon_block_root)
|
||||
// # Update latest messages for attesting indices
|
||||
// update_latest_messages(store, indexed_attestation.attesting_indices, attestation)
|
||||
// TODO(#6072): This code path is highly untested. Requires comprehensive tests and simpler refactoring.
|
||||
func (s *Service) onAttestation(ctx context.Context, a *ethpb.Attestation) ([]uint64, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "blockChain.onAttestation")
|
||||
@@ -92,6 +69,53 @@ func (s *Service) onAttestation(ctx context.Context, a *ethpb.Attestation) ([]ui
|
||||
return nil, ErrTargetRootNotInDB
|
||||
}
|
||||
|
||||
if featureconfig.Get().UseCheckPointInfoCache {
|
||||
c, err := s.AttestationCheckPtInfo(ctx, a)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := s.verifyAttTargetEpoch(ctx, uint64(s.genesisTime.Unix()), uint64(timeutils.Now().Unix()), tgt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := s.verifyBeaconBlock(ctx, a.Data); err != nil {
|
||||
return nil, errors.Wrap(err, "could not verify attestation beacon block")
|
||||
}
|
||||
if err := s.verifyLMDFFGConsistent(ctx, a.Data.Target.Epoch, a.Data.Target.Root, a.Data.BeaconBlockRoot); err != nil {
|
||||
return nil, errors.Wrap(err, "could not verify attestation beacon block")
|
||||
}
|
||||
if err := helpers.VerifySlotTime(uint64(s.genesisTime.Unix()), a.Data.Slot+1, params.BeaconNetworkConfig().MaximumGossipClockDisparity); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
committee, err := helpers.BeaconCommittee(c.ActiveIndices, bytesutil.ToBytes32(c.Seed), a.Data.Slot, a.Data.CommitteeIndex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
indexedAtt := attestationutil.ConvertToIndexed(ctx, a, committee)
|
||||
if err := attestationutil.IsValidAttestationIndices(ctx, indexedAtt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
domain, err := helpers.Domain(c.Fork, indexedAtt.Data.Target.Epoch, params.BeaconConfig().DomainBeaconAttester, c.GenesisRoot)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
indices := indexedAtt.AttestingIndices
|
||||
pubkeys := []bls.PublicKey{}
|
||||
for i := 0; i < len(indices); i++ {
|
||||
pubkeyAtIdx := c.PubKeys[indices[i]]
|
||||
pk, err := bls.PublicKeyFromBytes(pubkeyAtIdx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pubkeys = append(pubkeys, pk)
|
||||
}
|
||||
if err := attestationutil.VerifyIndexedAttestationSig(ctx, indexedAtt, pubkeys, domain); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.forkChoiceStore.ProcessAttestation(ctx, indexedAtt.AttestingIndices, bytesutil.ToBytes32(a.Data.BeaconBlockRoot), a.Data.Target.Epoch)
|
||||
|
||||
return indexedAtt.AttestingIndices, nil
|
||||
}
|
||||
|
||||
// Retrieve attestation's data beacon block pre state. Advance pre state to latest epoch if necessary and
|
||||
// save it to the cache.
|
||||
baseState, err := s.getAttPreState(ctx, tgt)
|
||||
@@ -102,7 +126,7 @@ func (s *Service) onAttestation(ctx context.Context, a *ethpb.Attestation) ([]ui
|
||||
genesisTime := baseState.GenesisTime()
|
||||
|
||||
// Verify attestation target is from current epoch or previous epoch.
|
||||
if err := s.verifyAttTargetEpoch(ctx, genesisTime, uint64(roughtime.Now().Unix()), tgt); err != nil {
|
||||
if err := s.verifyAttTargetEpoch(ctx, genesisTime, uint64(timeutils.Now().Unix()), tgt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
@@ -7,11 +7,11 @@ import (
|
||||
|
||||
"github.com/pkg/errors"
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/cache"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/state"
|
||||
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/attestationutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
func (s *Service) getAttPreState(ctx context.Context, c *ethpb.Checkpoint) (*stateTrie.BeaconState, error) {
|
||||
s.checkpointStateLock.Lock()
|
||||
defer s.checkpointStateLock.Unlock()
|
||||
|
||||
cachedState, err := s.checkpointState.StateByCheckpoint(c)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get cached checkpoint state")
|
||||
@@ -31,28 +32,99 @@ func (s *Service) getAttPreState(ctx context.Context, c *ethpb.Checkpoint) (*sta
|
||||
|
||||
baseState, err := s.stateGen.StateByRoot(ctx, bytesutil.ToBytes32(c.Root))
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not get pre state for slot %d", helpers.StartSlot(c.Epoch))
|
||||
return nil, errors.Wrapf(err, "could not get pre state for epoch %d", c.Epoch)
|
||||
}
|
||||
|
||||
if helpers.StartSlot(c.Epoch) > baseState.Slot() {
|
||||
epochStartSlot, err := helpers.StartSlot(c.Epoch)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if epochStartSlot > baseState.Slot() {
|
||||
baseState = baseState.Copy()
|
||||
baseState, err = state.ProcessSlots(ctx, baseState, helpers.StartSlot(c.Epoch))
|
||||
baseState, err = state.ProcessSlots(ctx, baseState, epochStartSlot)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not process slots up to %d", helpers.StartSlot(c.Epoch))
|
||||
return nil, errors.Wrapf(err, "could not process slots up to epoch %d", c.Epoch)
|
||||
}
|
||||
if err := s.checkpointState.AddCheckpointState(c, baseState); err != nil {
|
||||
return nil, errors.Wrap(err, "could not saved checkpoint state to cache")
|
||||
}
|
||||
return baseState, nil
|
||||
}
|
||||
|
||||
has, err := s.stateGen.HasState(ctx, bytesutil.ToBytes32(c.Root))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !has {
|
||||
if err := s.checkpointState.AddCheckpointState(c, baseState); err != nil {
|
||||
return nil, errors.Wrap(err, "could not saved checkpoint state to cache")
|
||||
}
|
||||
}
|
||||
|
||||
if err := s.checkpointState.AddCheckpointState(&cache.CheckpointState{
|
||||
Checkpoint: c,
|
||||
State: baseState,
|
||||
}); err != nil {
|
||||
return nil, errors.Wrap(err, "could not saved checkpoint state to cache")
|
||||
}
|
||||
|
||||
return baseState, nil
|
||||
|
||||
}
|
||||
|
||||
// getAttCheckPtInfo retrieves the check point info given a check point. Check point info enables the node
|
||||
// to efficiently verify attestation signature without using beacon state. This function utilizes
|
||||
// the checkpoint info cache and will update the check point info cache on miss.
|
||||
func (s *Service) getAttCheckPtInfo(ctx context.Context, c *ethpb.Checkpoint, e uint64) (*pb.CheckPtInfo, error) {
|
||||
// Return checkpoint info if exists in cache.
|
||||
info, err := s.checkPtInfoCache.get(c)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get cached checkpoint state")
|
||||
}
|
||||
if info != nil {
|
||||
return info, nil
|
||||
}
|
||||
|
||||
// Retrieve checkpoint state to compute checkpoint info.
|
||||
baseState, err := s.stateGen.StateByRoot(ctx, bytesutil.ToBytes32(c.Root))
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not get pre state for epoch %d", c.Epoch)
|
||||
}
|
||||
epochStartSlot, err := helpers.StartSlot(c.Epoch)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if epochStartSlot > baseState.Slot() {
|
||||
baseState = baseState.Copy()
|
||||
baseState, err = state.ProcessSlots(ctx, baseState, epochStartSlot)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not process slots up to epoch %d", c.Epoch)
|
||||
}
|
||||
}
|
||||
f := baseState.Fork()
|
||||
g := bytesutil.ToBytes32(baseState.GenesisValidatorRoot())
|
||||
seed, err := helpers.Seed(baseState, e, params.BeaconConfig().DomainBeaconAttester)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
indices, err := helpers.ActiveValidatorIndices(baseState, e)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
validators := baseState.ValidatorsReadOnly()
|
||||
pks := make([][]byte, len(validators))
|
||||
for i := 0; i < len(pks); i++ {
|
||||
pk := validators[i].PublicKey()
|
||||
pks[i] = pk[:]
|
||||
}
|
||||
|
||||
// Cache and return the checkpoint info.
|
||||
info = &pb.CheckPtInfo{
|
||||
Fork: f,
|
||||
GenesisRoot: g[:],
|
||||
Seed: seed[:],
|
||||
ActiveIndices: indices,
|
||||
PubKeys: pks,
|
||||
}
|
||||
if err := s.checkPtInfoCache.put(c, info); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return info, nil
|
||||
}
|
||||
|
||||
// verifyAttTargetEpoch validates attestation is from the current or previous epoch.
|
||||
func (s *Service) verifyAttTargetEpoch(ctx context.Context, genesisTime uint64, nowTime uint64, c *ethpb.Checkpoint) error {
|
||||
currentSlot := (nowTime - genesisTime) / params.BeaconConfig().SecondsPerSlot
|
||||
@@ -91,7 +163,10 @@ func (s *Service) verifyBeaconBlock(ctx context.Context, data *ethpb.Attestation
|
||||
|
||||
// verifyLMDFFGConsistent verifies LMD GHOST and FFG votes are consistent with each other.
|
||||
func (s *Service) verifyLMDFFGConsistent(ctx context.Context, ffgEpoch uint64, ffgRoot []byte, lmdRoot []byte) error {
|
||||
ffgSlot := helpers.StartSlot(ffgEpoch)
|
||||
ffgSlot, err := helpers.StartSlot(ffgEpoch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r, err := s.ancestor(ctx, lmdRoot, ffgSlot)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -2,20 +2,19 @@ package blockchain
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/cache"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/state"
|
||||
testDB "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/protoarray"
|
||||
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stategen"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
@@ -37,103 +36,207 @@ func TestStore_OnAttestation(t *testing.T) {
|
||||
_, err = blockTree1(db, []byte{'g'})
|
||||
require.NoError(t, err)
|
||||
|
||||
BlkWithOutState := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Slot: 0}}
|
||||
BlkWithOutState := testutil.NewBeaconBlock()
|
||||
BlkWithOutState.Block.Slot = 0
|
||||
require.NoError(t, db.SaveBlock(ctx, BlkWithOutState))
|
||||
BlkWithOutStateRoot, err := stateutil.BlockRoot(BlkWithOutState.Block)
|
||||
BlkWithOutStateRoot, err := BlkWithOutState.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
BlkWithStateBadAtt := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Slot: 1}}
|
||||
BlkWithStateBadAtt := testutil.NewBeaconBlock()
|
||||
BlkWithStateBadAtt.Block.Slot = 1
|
||||
require.NoError(t, db.SaveBlock(ctx, BlkWithStateBadAtt))
|
||||
BlkWithStateBadAttRoot, err := stateutil.BlockRoot(BlkWithStateBadAtt.Block)
|
||||
BlkWithStateBadAttRoot, err := BlkWithStateBadAtt.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
s := testutil.NewBeaconState()
|
||||
require.NoError(t, s.SetSlot(100*params.BeaconConfig().SlotsPerEpoch))
|
||||
require.NoError(t, service.beaconDB.SaveState(ctx, s, BlkWithStateBadAttRoot))
|
||||
|
||||
BlkWithValidState := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Slot: 2}}
|
||||
BlkWithValidState := testutil.NewBeaconBlock()
|
||||
BlkWithValidState.Block.Slot = 2
|
||||
require.NoError(t, db.SaveBlock(ctx, BlkWithValidState))
|
||||
|
||||
BlkWithValidStateRoot, err := stateutil.BlockRoot(BlkWithValidState.Block)
|
||||
BlkWithValidStateRoot, err := BlkWithValidState.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
s = testutil.NewBeaconState()
|
||||
if err := s.SetFork(&pb.Fork{
|
||||
err = s.SetFork(&pb.Fork{
|
||||
Epoch: 0,
|
||||
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, service.beaconDB.SaveState(ctx, s, BlkWithValidStateRoot))
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
a *ethpb.Attestation
|
||||
s *pb.BeaconState
|
||||
wantErr bool
|
||||
wantErrString string
|
||||
name string
|
||||
a *ethpb.Attestation
|
||||
wantedErr string
|
||||
}{
|
||||
{
|
||||
name: "attestation's data slot not aligned with target vote",
|
||||
a: ðpb.Attestation{Data: ðpb.AttestationData{Slot: params.BeaconConfig().SlotsPerEpoch, Target: ðpb.Checkpoint{}}},
|
||||
s: &pb.BeaconState{},
|
||||
wantErr: true,
|
||||
wantErrString: "data slot is not in the same epoch as target 1 != 0",
|
||||
name: "attestation's data slot not aligned with target vote",
|
||||
a: ðpb.Attestation{Data: ðpb.AttestationData{Slot: params.BeaconConfig().SlotsPerEpoch, Target: ðpb.Checkpoint{Root: make([]byte, 32)}}},
|
||||
wantedErr: "data slot is not in the same epoch as target 1 != 0",
|
||||
},
|
||||
{
|
||||
name: "attestation's target root not in db",
|
||||
a: ðpb.Attestation{Data: ðpb.AttestationData{Target: ðpb.Checkpoint{Root: []byte{'A'}}}},
|
||||
s: &pb.BeaconState{},
|
||||
wantErr: true,
|
||||
wantErrString: "target root does not exist in db",
|
||||
name: "attestation's target root not in db",
|
||||
a: ðpb.Attestation{Data: ðpb.AttestationData{Target: ðpb.Checkpoint{Root: bytesutil.PadTo([]byte{'A'}, 32)}}},
|
||||
wantedErr: "target root does not exist in db",
|
||||
},
|
||||
{
|
||||
name: "no pre state for attestations's target block",
|
||||
a: ðpb.Attestation{Data: ðpb.AttestationData{Target: ðpb.Checkpoint{Root: BlkWithOutStateRoot[:]}}},
|
||||
s: &pb.BeaconState{},
|
||||
wantErr: true,
|
||||
wantErrString: "could not get pre state for slot 0",
|
||||
name: "no pre state for attestations's target block",
|
||||
a: ðpb.Attestation{Data: ðpb.AttestationData{Target: ðpb.Checkpoint{Root: BlkWithOutStateRoot[:]}}},
|
||||
wantedErr: "could not get pre state for epoch 0",
|
||||
},
|
||||
{
|
||||
name: "process attestation doesn't match current epoch",
|
||||
a: ðpb.Attestation{Data: ðpb.AttestationData{Slot: 100 * params.BeaconConfig().SlotsPerEpoch, Target: ðpb.Checkpoint{Epoch: 100,
|
||||
Root: BlkWithStateBadAttRoot[:]}}},
|
||||
s: &pb.BeaconState{Slot: 100 * params.BeaconConfig().SlotsPerEpoch},
|
||||
wantErr: true,
|
||||
wantErrString: "target epoch 100 does not match current epoch",
|
||||
wantedErr: "target epoch 100 does not match current epoch",
|
||||
},
|
||||
{
|
||||
name: "process nil field (a.Target) in attestation",
|
||||
a: nil,
|
||||
s: &pb.BeaconState{},
|
||||
wantErr: true,
|
||||
wantErrString: "nil attestation",
|
||||
name: "process nil attestation",
|
||||
a: nil,
|
||||
wantedErr: "nil attestation",
|
||||
},
|
||||
{
|
||||
name: "process nil field (a.Data) in attestation",
|
||||
a: ðpb.Attestation{},
|
||||
s: &pb.BeaconState{},
|
||||
wantErr: true,
|
||||
wantErrString: "nil attestation.Data field",
|
||||
name: "process nil field (a.Data) in attestation",
|
||||
a: ðpb.Attestation{},
|
||||
wantedErr: "nil attestation.Data field",
|
||||
},
|
||||
{
|
||||
name: "process nil field (a.Target) in attestation",
|
||||
a: ðpb.Attestation{Data: ðpb.AttestationData{}},
|
||||
s: &pb.BeaconState{},
|
||||
wantErr: true,
|
||||
wantErrString: "nil attestation.Data.Target field",
|
||||
name: "process nil field (a.Target) in attestation",
|
||||
a: ðpb.Attestation{
|
||||
Data: ðpb.AttestationData{
|
||||
BeaconBlockRoot: make([]byte, 32),
|
||||
Target: nil,
|
||||
Source: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
},
|
||||
AggregationBits: make([]byte, 1),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
wantedErr: "nil attestation.Data.Target field",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
_, err := service.onAttestation(ctx, tt.a)
|
||||
if tt.wantErr {
|
||||
if err == nil || !strings.Contains(err.Error(), tt.wantErrString) {
|
||||
t.Errorf("Store.onAttestation() error = %v, wantErr = %v", err, tt.wantErrString)
|
||||
}
|
||||
if tt.wantedErr != "" {
|
||||
assert.ErrorContains(t, tt.wantedErr, err)
|
||||
} else {
|
||||
t.Error(err)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestStore_OnAttestationUsingCheckptCache(t *testing.T) {
|
||||
resetCfg := featureconfig.InitWithReset(&featureconfig.Flags{UseCheckPointInfoCache: true})
|
||||
defer resetCfg()
|
||||
|
||||
ctx := context.Background()
|
||||
db, sc := testDB.SetupDB(t)
|
||||
|
||||
cfg := &Config{
|
||||
BeaconDB: db,
|
||||
ForkChoiceStore: protoarray.New(0, 0, [32]byte{}),
|
||||
StateGen: stategen.New(db, sc),
|
||||
}
|
||||
service, err := NewService(ctx, cfg)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = blockTree1(db, []byte{'g'})
|
||||
require.NoError(t, err)
|
||||
|
||||
BlkWithOutState := testutil.NewBeaconBlock()
|
||||
BlkWithOutState.Block.Slot = 0
|
||||
require.NoError(t, db.SaveBlock(ctx, BlkWithOutState))
|
||||
BlkWithOutStateRoot, err := BlkWithOutState.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
BlkWithStateBadAtt := testutil.NewBeaconBlock()
|
||||
BlkWithStateBadAtt.Block.Slot = 1
|
||||
require.NoError(t, db.SaveBlock(ctx, BlkWithStateBadAtt))
|
||||
BlkWithStateBadAttRoot, err := BlkWithStateBadAtt.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
s := testutil.NewBeaconState()
|
||||
require.NoError(t, s.SetSlot(100*params.BeaconConfig().SlotsPerEpoch))
|
||||
require.NoError(t, service.beaconDB.SaveState(ctx, s, BlkWithStateBadAttRoot))
|
||||
|
||||
BlkWithValidState := testutil.NewBeaconBlock()
|
||||
BlkWithValidState.Block.Slot = 2
|
||||
require.NoError(t, db.SaveBlock(ctx, BlkWithValidState))
|
||||
|
||||
BlkWithValidStateRoot, err := BlkWithValidState.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
s = testutil.NewBeaconState()
|
||||
err = s.SetFork(&pb.Fork{
|
||||
Epoch: 0,
|
||||
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, service.beaconDB.SaveState(ctx, s, BlkWithValidStateRoot))
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
a *ethpb.Attestation
|
||||
wantedErr string
|
||||
}{
|
||||
{
|
||||
name: "attestation's data slot not aligned with target vote",
|
||||
a: ðpb.Attestation{Data: ðpb.AttestationData{Slot: params.BeaconConfig().SlotsPerEpoch, Target: ðpb.Checkpoint{Root: make([]byte, 32)}}},
|
||||
wantedErr: "data slot is not in the same epoch as target 1 != 0",
|
||||
},
|
||||
{
|
||||
name: "attestation's target root not in db",
|
||||
a: ðpb.Attestation{Data: ðpb.AttestationData{Target: ðpb.Checkpoint{Root: bytesutil.PadTo([]byte{'A'}, 32)}}},
|
||||
wantedErr: "target root does not exist in db",
|
||||
},
|
||||
{
|
||||
name: "no pre state for attestations's target block",
|
||||
a: ðpb.Attestation{Data: ðpb.AttestationData{Target: ðpb.Checkpoint{Root: BlkWithOutStateRoot[:]}}},
|
||||
wantedErr: "could not get pre state for epoch 0",
|
||||
},
|
||||
{
|
||||
name: "process attestation doesn't match current epoch",
|
||||
a: ðpb.Attestation{Data: ðpb.AttestationData{Slot: 100 * params.BeaconConfig().SlotsPerEpoch, Target: ðpb.Checkpoint{Epoch: 100,
|
||||
Root: BlkWithStateBadAttRoot[:]}}},
|
||||
wantedErr: "target epoch 100 does not match current epoch",
|
||||
},
|
||||
{
|
||||
name: "process nil attestation",
|
||||
a: nil,
|
||||
wantedErr: "nil attestation",
|
||||
},
|
||||
{
|
||||
name: "process nil field (a.Data) in attestation",
|
||||
a: ðpb.Attestation{},
|
||||
wantedErr: "nil attestation.Data field",
|
||||
},
|
||||
{
|
||||
name: "process nil field (a.Target) in attestation",
|
||||
a: ðpb.Attestation{
|
||||
Data: ðpb.AttestationData{
|
||||
BeaconBlockRoot: make([]byte, 32),
|
||||
Target: nil,
|
||||
Source: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
},
|
||||
AggregationBits: make([]byte, 1),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
wantedErr: "nil attestation.Data.Target field",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
_, err := service.onAttestation(ctx, tt.a)
|
||||
if tt.wantedErr != "" {
|
||||
assert.ErrorContains(t, tt.wantedErr, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -150,22 +253,16 @@ func TestStore_SaveCheckpointState(t *testing.T) {
|
||||
service, err := NewService(ctx, cfg)
|
||||
require.NoError(t, err)
|
||||
|
||||
s, err := stateTrie.InitializeFromProto(&pb.BeaconState{
|
||||
Fork: &pb.Fork{
|
||||
Epoch: 0,
|
||||
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
},
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
StateRoots: make([][]byte, params.BeaconConfig().SlotsPerHistoricalRoot),
|
||||
BlockRoots: make([][]byte, params.BeaconConfig().SlotsPerHistoricalRoot),
|
||||
LatestBlockHeader: ðpb.BeaconBlockHeader{},
|
||||
JustificationBits: []byte{0},
|
||||
Slashings: make([]uint64, params.BeaconConfig().EpochsPerSlashingsVector),
|
||||
FinalizedCheckpoint: ðpb.Checkpoint{Root: bytesutil.PadTo([]byte{'A'}, 32)},
|
||||
Validators: []*ethpb.Validator{{PublicKey: bytesutil.PadTo([]byte("foo"), 48)}},
|
||||
Balances: []uint64{0},
|
||||
})
|
||||
s := testutil.NewBeaconState()
|
||||
err = s.SetFinalizedCheckpoint(ðpb.Checkpoint{Root: bytesutil.PadTo([]byte{'A'}, 32)})
|
||||
require.NoError(t, err)
|
||||
val := ðpb.Validator{
|
||||
PublicKey: bytesutil.PadTo([]byte("foo"), 48),
|
||||
WithdrawalCredentials: bytesutil.PadTo([]byte("bar"), 32),
|
||||
}
|
||||
err = s.SetValidators([]*ethpb.Validator{val})
|
||||
require.NoError(t, err)
|
||||
err = s.SetBalances([]uint64{0})
|
||||
require.NoError(t, err)
|
||||
r := [32]byte{'g'}
|
||||
require.NoError(t, service.beaconDB.SaveState(ctx, s, r))
|
||||
@@ -229,23 +326,24 @@ func TestStore_UpdateCheckpointState(t *testing.T) {
|
||||
|
||||
epoch := uint64(1)
|
||||
baseState, _ := testutil.DeterministicGenesisState(t, 1)
|
||||
require.NoError(t, baseState.SetSlot(epoch*params.BeaconConfig().SlotsPerEpoch))
|
||||
checkpoint := ðpb.Checkpoint{Epoch: epoch}
|
||||
checkpoint := ðpb.Checkpoint{Epoch: epoch, Root: bytesutil.PadTo([]byte("hi"), 32)}
|
||||
require.NoError(t, service.beaconDB.SaveState(ctx, baseState, bytesutil.ToBytes32(checkpoint.Root)))
|
||||
returned, err := service.getAttPreState(ctx, checkpoint)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, returned.Slot(), baseState.Slot(), "Incorrectly returned base state")
|
||||
assert.Equal(t, returned.Slot(), checkpoint.Epoch*params.BeaconConfig().SlotsPerEpoch, "Incorrectly returned base state")
|
||||
|
||||
cached, err := service.checkpointState.StateByCheckpoint(checkpoint)
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, cached, "State should have been cached")
|
||||
assert.Equal(t, returned.Slot(), cached.Slot(), "State should have been cached")
|
||||
|
||||
epoch = uint64(2)
|
||||
newCheckpoint := ðpb.Checkpoint{Epoch: epoch}
|
||||
newCheckpoint := ðpb.Checkpoint{Epoch: epoch, Root: bytesutil.PadTo([]byte("bye"), 32)}
|
||||
require.NoError(t, service.beaconDB.SaveState(ctx, baseState, bytesutil.ToBytes32(newCheckpoint.Root)))
|
||||
returned, err = service.getAttPreState(ctx, newCheckpoint)
|
||||
require.NoError(t, err)
|
||||
baseState, err = state.ProcessSlots(ctx, baseState, helpers.StartSlot(newCheckpoint.Epoch))
|
||||
s, err := helpers.StartSlot(newCheckpoint.Epoch)
|
||||
require.NoError(t, err)
|
||||
baseState, err = state.ProcessSlots(ctx, baseState, s)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, returned.Slot(), baseState.Slot(), "Incorrectly returned base state")
|
||||
|
||||
@@ -264,13 +362,8 @@ func TestAttEpoch_MatchPrevEpoch(t *testing.T) {
|
||||
service, err := NewService(ctx, cfg)
|
||||
require.NoError(t, err)
|
||||
|
||||
if err := service.verifyAttTargetEpoch(
|
||||
ctx,
|
||||
0,
|
||||
params.BeaconConfig().SlotsPerEpoch*params.BeaconConfig().SecondsPerSlot,
|
||||
ðpb.Checkpoint{}); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
nowTime := params.BeaconConfig().SlotsPerEpoch * params.BeaconConfig().SecondsPerSlot
|
||||
require.NoError(t, service.verifyAttTargetEpoch(ctx, 0, nowTime, ðpb.Checkpoint{Root: make([]byte, 32)}))
|
||||
}
|
||||
|
||||
func TestAttEpoch_MatchCurrentEpoch(t *testing.T) {
|
||||
@@ -281,13 +374,8 @@ func TestAttEpoch_MatchCurrentEpoch(t *testing.T) {
|
||||
service, err := NewService(ctx, cfg)
|
||||
require.NoError(t, err)
|
||||
|
||||
if err := service.verifyAttTargetEpoch(
|
||||
ctx,
|
||||
0,
|
||||
params.BeaconConfig().SlotsPerEpoch*params.BeaconConfig().SecondsPerSlot,
|
||||
ðpb.Checkpoint{Epoch: 1}); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
nowTime := params.BeaconConfig().SlotsPerEpoch * params.BeaconConfig().SecondsPerSlot
|
||||
require.NoError(t, service.verifyAttTargetEpoch(ctx, 0, nowTime, ðpb.Checkpoint{Epoch: 1}))
|
||||
}
|
||||
|
||||
func TestAttEpoch_NotMatch(t *testing.T) {
|
||||
@@ -298,14 +386,9 @@ func TestAttEpoch_NotMatch(t *testing.T) {
|
||||
service, err := NewService(ctx, cfg)
|
||||
require.NoError(t, err)
|
||||
|
||||
if err := service.verifyAttTargetEpoch(
|
||||
ctx,
|
||||
0,
|
||||
2*params.BeaconConfig().SlotsPerEpoch*params.BeaconConfig().SecondsPerSlot,
|
||||
ðpb.Checkpoint{}); !strings.Contains(err.Error(),
|
||||
"target epoch 0 does not match current epoch 2 or prev epoch 1") {
|
||||
t.Error("Did not receive wanted error")
|
||||
}
|
||||
nowTime := 2 * params.BeaconConfig().SlotsPerEpoch * params.BeaconConfig().SecondsPerSlot
|
||||
err = service.verifyAttTargetEpoch(ctx, 0, nowTime, ðpb.Checkpoint{Root: make([]byte, 32)})
|
||||
assert.ErrorContains(t, "target epoch 0 does not match current epoch 2 or prev epoch 1", err)
|
||||
}
|
||||
|
||||
func TestVerifyBeaconBlock_NoBlock(t *testing.T) {
|
||||
@@ -316,8 +399,12 @@ func TestVerifyBeaconBlock_NoBlock(t *testing.T) {
|
||||
service, err := NewService(ctx, cfg)
|
||||
require.NoError(t, err)
|
||||
|
||||
d := ðpb.AttestationData{}
|
||||
assert.ErrorContains(t, "beacon block does not exist", service.verifyBeaconBlock(ctx, d))
|
||||
d := ðpb.AttestationData{
|
||||
BeaconBlockRoot: make([]byte, 32),
|
||||
Target: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
Source: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
}
|
||||
assert.ErrorContains(t, "beacon block 0x000000000000 does not exist", service.verifyBeaconBlock(ctx, d))
|
||||
}
|
||||
|
||||
func TestVerifyBeaconBlock_futureBlock(t *testing.T) {
|
||||
@@ -328,9 +415,10 @@ func TestVerifyBeaconBlock_futureBlock(t *testing.T) {
|
||||
service, err := NewService(ctx, cfg)
|
||||
require.NoError(t, err)
|
||||
|
||||
b := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Slot: 2}}
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block.Slot = 2
|
||||
require.NoError(t, service.beaconDB.SaveBlock(ctx, b))
|
||||
r, err := stateutil.BlockRoot(b.Block)
|
||||
r, err := b.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
d := ðpb.AttestationData{Slot: 1, BeaconBlockRoot: r[:]}
|
||||
|
||||
@@ -345,9 +433,10 @@ func TestVerifyBeaconBlock_OK(t *testing.T) {
|
||||
service, err := NewService(ctx, cfg)
|
||||
require.NoError(t, err)
|
||||
|
||||
b := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Slot: 2}}
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block.Slot = 2
|
||||
require.NoError(t, service.beaconDB.SaveBlock(ctx, b))
|
||||
r, err := stateutil.BlockRoot(b.Block)
|
||||
r, err := b.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
d := ðpb.AttestationData{Slot: 2, BeaconBlockRoot: r[:]}
|
||||
|
||||
@@ -358,17 +447,20 @@ func TestVerifyLMDFFGConsistent_NotOK(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
db, _ := testDB.SetupDB(t)
|
||||
|
||||
cfg := &Config{BeaconDB: db}
|
||||
cfg := &Config{BeaconDB: db, ForkChoiceStore: protoarray.New(0, 0, [32]byte{})}
|
||||
service, err := NewService(ctx, cfg)
|
||||
require.NoError(t, err)
|
||||
|
||||
b32 := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Slot: 32}}
|
||||
b32 := testutil.NewBeaconBlock()
|
||||
b32.Block.Slot = 32
|
||||
require.NoError(t, service.beaconDB.SaveBlock(ctx, b32))
|
||||
r32, err := stateutil.BlockRoot(b32.Block)
|
||||
r32, err := b32.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
b33 := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Slot: 33, ParentRoot: r32[:]}}
|
||||
b33 := testutil.NewBeaconBlock()
|
||||
b33.Block.Slot = 33
|
||||
b33.Block.ParentRoot = r32[:]
|
||||
require.NoError(t, service.beaconDB.SaveBlock(ctx, b33))
|
||||
r33, err := stateutil.BlockRoot(b33.Block)
|
||||
r33, err := b33.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
wanted := "FFG and LMD votes are not consistent"
|
||||
@@ -379,19 +471,66 @@ func TestVerifyLMDFFGConsistent_OK(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
db, _ := testDB.SetupDB(t)
|
||||
|
||||
cfg := &Config{BeaconDB: db}
|
||||
cfg := &Config{BeaconDB: db, ForkChoiceStore: protoarray.New(0, 0, [32]byte{})}
|
||||
service, err := NewService(ctx, cfg)
|
||||
require.NoError(t, err)
|
||||
|
||||
b32 := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Slot: 32}}
|
||||
b32 := testutil.NewBeaconBlock()
|
||||
b32.Block.Slot = 32
|
||||
require.NoError(t, service.beaconDB.SaveBlock(ctx, b32))
|
||||
r32, err := stateutil.BlockRoot(b32.Block)
|
||||
r32, err := b32.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
b33 := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Slot: 33, ParentRoot: r32[:]}}
|
||||
b33 := testutil.NewBeaconBlock()
|
||||
b33.Block.Slot = 33
|
||||
b33.Block.ParentRoot = r32[:]
|
||||
require.NoError(t, service.beaconDB.SaveBlock(ctx, b33))
|
||||
r33, err := stateutil.BlockRoot(b33.Block)
|
||||
r33, err := b33.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
err = service.verifyLMDFFGConsistent(context.Background(), 1, r32[:], r33[:])
|
||||
assert.NoError(t, err, "Could not verify LMD and FFG votes to be consistent")
|
||||
}
|
||||
|
||||
func TestGetAttCheckptInfo(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
db, _ := testDB.SetupDB(t)
|
||||
cfg := &Config{BeaconDB: db, StateGen: stategen.New(db, cache.NewStateSummaryCache())}
|
||||
service, err := NewService(ctx, cfg)
|
||||
require.NoError(t, err)
|
||||
|
||||
baseState, _ := testutil.DeterministicGenesisState(t, 128)
|
||||
b := testutil.NewBeaconBlock()
|
||||
r, err := b.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, service.beaconDB.SaveState(ctx, baseState, r))
|
||||
require.NoError(t, service.beaconDB.SaveBlock(ctx, b))
|
||||
require.NoError(t, service.beaconDB.SaveGenesisBlockRoot(ctx, r))
|
||||
checkpoint := ðpb.Checkpoint{Root: r[:]}
|
||||
|
||||
returned, err := service.getAttCheckPtInfo(ctx, checkpoint, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
seed, err := helpers.Seed(baseState, 0, params.BeaconConfig().DomainBeaconAttester)
|
||||
require.NoError(t, err)
|
||||
indices, err := helpers.ActiveValidatorIndices(baseState, 0)
|
||||
require.NoError(t, err)
|
||||
validators := baseState.ValidatorsReadOnly()
|
||||
pks := make([][]byte, len(validators))
|
||||
for i := 0; i < len(pks); i++ {
|
||||
pk := validators[i].PublicKey()
|
||||
pks[i] = pk[:]
|
||||
}
|
||||
|
||||
wanted := &pb.CheckPtInfo{
|
||||
Fork: baseState.Fork(),
|
||||
GenesisRoot: baseState.GenesisValidatorRoot(),
|
||||
Seed: seed[:],
|
||||
ActiveIndices: indices,
|
||||
PubKeys: pks,
|
||||
}
|
||||
require.DeepEqual(t, wanted, returned)
|
||||
|
||||
cached, err := service.checkPtInfoCache.get(checkpoint)
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, wanted, cached)
|
||||
}
|
||||
|
||||
@@ -25,34 +25,51 @@ var initialSyncBlockCacheSize = 2 * params.BeaconConfig().SlotsPerEpoch
|
||||
// computation in this method and methods it calls into.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// def on_block(store: Store, block: BeaconBlock) -> None:
|
||||
// # Make a copy of the state to avoid mutability issues
|
||||
// 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
|
||||
// pre_state = store.block_states[block.parent_root].copy()
|
||||
// # 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 store.time >= pre_state.genesis_time + block.slot * SECONDS_PER_SLOT
|
||||
// # Add new block to the store
|
||||
// store.blocks[signing_root(block)] = block
|
||||
// # Check block is a descendant of the finalized block
|
||||
// assert (
|
||||
// get_ancestor(store, signing_root(block), store.blocks[store.finalized_checkpoint.root].slot) ==
|
||||
// store.finalized_checkpoint.root
|
||||
// )
|
||||
// # Check that block is later than the finalized epoch slot
|
||||
// assert block.slot > compute_start_slot_at_epoch(store.finalized_checkpoint.epoch)
|
||||
// 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
|
||||
//
|
||||
// # Check the block is valid and compute the post-state
|
||||
// state = state_transition(pre_state, block)
|
||||
// state = state_transition(pre_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[signing_root(block)] = state
|
||||
// store.block_states[hash_tree_root(block)] = state
|
||||
//
|
||||
// # 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
|
||||
//
|
||||
// # Update finalized checkpoint
|
||||
// if state.finalized_checkpoint.epoch > store.finalized_checkpoint.epoch:
|
||||
// store.finalized_checkpoint = state.finalized_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 *ethpb.SignedBeaconBlock, blockRoot [32]byte) error {
|
||||
ctx, span := trace.StartSpan(ctx, "blockChain.onBlock")
|
||||
defer span.End()
|
||||
@@ -104,7 +121,11 @@ func (s *Service) onBlock(ctx context.Context, signed *ethpb.SignedBeaconBlock,
|
||||
}
|
||||
|
||||
// Update deposit cache.
|
||||
s.depositCache.InsertFinalizedDeposits(ctx, int64(postState.Eth1DepositIndex()))
|
||||
finalizedState, err := s.stateGen.StateByRoot(ctx, fRoot)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not fetch finalized state")
|
||||
}
|
||||
s.depositCache.InsertFinalizedDeposits(ctx, int64(finalizedState.Eth1Data().DepositCount-1))
|
||||
}
|
||||
|
||||
defer reportAttestationInclusion(b)
|
||||
@@ -157,6 +178,10 @@ func (s *Service) onBlockInitialSyncStateTransition(ctx context.Context, signed
|
||||
if err := s.savePostStateInfo(ctx, blockRoot, signed, postState, true /* init sync */); err != nil {
|
||||
return err
|
||||
}
|
||||
// Save the latest block as head in cache.
|
||||
if err := s.saveHeadNoDB(ctx, signed, blockRoot, postState); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Rate limit how many blocks (2 epochs worth of blocks) a node keeps in the memory.
|
||||
if uint64(len(s.getInitSyncBlocks())) > initialSyncBlockCacheSize {
|
||||
@@ -183,65 +208,77 @@ func (s *Service) onBlockInitialSyncStateTransition(ctx context.Context, signed
|
||||
}
|
||||
|
||||
func (s *Service) onBlockBatch(ctx context.Context, blks []*ethpb.SignedBeaconBlock,
|
||||
blockRoots [][32]byte) (*stateTrie.BeaconState, []*ethpb.Checkpoint, []*ethpb.Checkpoint, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "blockChain.onBlock")
|
||||
blockRoots [][32]byte) ([]*ethpb.Checkpoint, []*ethpb.Checkpoint, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "blockChain.onBlockBatch")
|
||||
defer span.End()
|
||||
|
||||
if len(blks) == 0 || len(blockRoots) == 0 {
|
||||
return nil, nil, nil, errors.New("no blocks provided")
|
||||
return nil, nil, errors.New("no blocks provided")
|
||||
}
|
||||
if blks[0] == nil || blks[0].Block == nil {
|
||||
return nil, nil, nil, errors.New("nil block")
|
||||
return nil, nil, errors.New("nil block")
|
||||
}
|
||||
b := blks[0].Block
|
||||
|
||||
// Retrieve incoming block's pre state.
|
||||
if err := s.verifyBlkPreState(ctx, b); err != nil {
|
||||
return nil, nil, nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
preState, err := s.stateGen.StateByRootInitialSync(ctx, bytesutil.ToBytes32(b.ParentRoot))
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
if preState == nil {
|
||||
return nil, nil, nil, fmt.Errorf("nil pre state for slot %d", b.Slot)
|
||||
return nil, nil, fmt.Errorf("nil pre state for slot %d", b.Slot)
|
||||
}
|
||||
|
||||
jCheckpoints := make([]*ethpb.Checkpoint, len(blks))
|
||||
fCheckpoints := make([]*ethpb.Checkpoint, len(blks))
|
||||
sigSet := &bls.SignatureSet{
|
||||
Signatures: []bls.Signature{},
|
||||
Signatures: [][]byte{},
|
||||
PublicKeys: []bls.PublicKey{},
|
||||
Messages: [][32]byte{},
|
||||
}
|
||||
set := new(bls.SignatureSet)
|
||||
var set *bls.SignatureSet
|
||||
boundaries := make(map[[32]byte]*stateTrie.BeaconState)
|
||||
for i, b := range blks {
|
||||
set, preState, err = state.ExecuteStateTransitionNoVerifyAnySig(ctx, preState, b)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
// Save potential boundary states.
|
||||
if helpers.IsEpochStart(preState.Slot()) {
|
||||
boundaries[blockRoots[i]] = preState.Copy()
|
||||
if err := s.handleEpochBoundary(preState); err != nil {
|
||||
return nil, nil, errors.Wrap(err, "could not handle epoch boundary state")
|
||||
}
|
||||
}
|
||||
jCheckpoints[i] = preState.CurrentJustifiedCheckpoint()
|
||||
fCheckpoints[i] = preState.FinalizedCheckpoint()
|
||||
sigSet.Join(set)
|
||||
}
|
||||
verify, err := bls.VerifyMultipleSignatures(sigSet.Signatures, sigSet.Messages, sigSet.PublicKeys)
|
||||
verify, err := sigSet.Verify()
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
if !verify {
|
||||
return nil, nil, nil, errors.New("batch block signature verification failed")
|
||||
return nil, nil, errors.New("batch block signature verification failed")
|
||||
}
|
||||
for r, st := range boundaries {
|
||||
if err := s.stateGen.SaveState(ctx, r, st); err != nil {
|
||||
return nil, nil, nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
return preState, fCheckpoints, jCheckpoints, nil
|
||||
// Also saves the last post state which to be used as pre state for the next batch.
|
||||
lastB := blks[len(blks)-1]
|
||||
lastBR := blockRoots[len(blockRoots)-1]
|
||||
if err := s.stateGen.SaveState(ctx, lastBR, preState); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if err := s.saveHeadNoDB(ctx, lastB, lastBR, preState); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return fCheckpoints, jCheckpoints, nil
|
||||
}
|
||||
|
||||
// handles a block after the block's batch has been verified, where we can save blocks
|
||||
@@ -272,10 +309,6 @@ func (s *Service) handleBlockAfterBatchVerify(ctx context.Context, signed *ethpb
|
||||
|
||||
// Update finalized check point. Prune the block cache and helper caches on every new finalized epoch.
|
||||
if fCheckpoint.Epoch > s.finalizedCheckpt.Epoch {
|
||||
if err := s.beaconDB.SaveBlocks(ctx, s.getInitSyncBlocks()); err != nil {
|
||||
return err
|
||||
}
|
||||
s.clearInitSyncBlocks()
|
||||
if err := s.updateFinalized(ctx, fCheckpoint); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -287,8 +320,11 @@ func (s *Service) handleBlockAfterBatchVerify(ctx context.Context, signed *ethpb
|
||||
func (s *Service) handleEpochBoundary(postState *stateTrie.BeaconState) error {
|
||||
if postState.Slot() >= s.nextEpochBoundarySlot {
|
||||
reportEpochMetrics(postState)
|
||||
s.nextEpochBoundarySlot = helpers.StartSlot(helpers.NextEpoch(postState))
|
||||
|
||||
var err error
|
||||
s.nextEpochBoundarySlot, err = helpers.StartSlot(helpers.NextEpoch(postState))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Update committees cache at epoch boundary slot.
|
||||
if err := helpers.UpdateCommitteeCache(postState, helpers.CurrentEpoch(postState)); err != nil {
|
||||
return err
|
||||
@@ -343,10 +379,8 @@ func (s *Service) savePostStateInfo(ctx context.Context, r [32]byte, b *ethpb.Si
|
||||
defer span.End()
|
||||
if initSync {
|
||||
s.saveInitSyncBlock(r, b)
|
||||
} else {
|
||||
if err := s.beaconDB.SaveBlock(ctx, b); err != nil {
|
||||
return errors.Wrapf(err, "could not save block from slot %d", b.Block.Slot)
|
||||
}
|
||||
} else if err := s.beaconDB.SaveBlock(ctx, b); err != nil {
|
||||
return errors.Wrapf(err, "could not save block from slot %d", b.Block.Slot)
|
||||
}
|
||||
if err := s.stateGen.SaveState(ctx, r, state); err != nil {
|
||||
return errors.Wrap(err, "could not save state")
|
||||
|
||||
@@ -9,23 +9,16 @@ import (
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/attestationutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/roughtime"
|
||||
"github.com/prysmaticlabs/prysm/shared/traceutil"
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
|
||||
// CurrentSlot returns the current slot based on time.
|
||||
func (s *Service) CurrentSlot() uint64 {
|
||||
now := roughtime.Now().Unix()
|
||||
genesis := s.genesisTime.Unix()
|
||||
if now < genesis {
|
||||
return 0
|
||||
}
|
||||
return uint64(now-genesis) / params.BeaconConfig().SecondsPerSlot
|
||||
return helpers.CurrentSlot(uint64(s.genesisTime.Unix()))
|
||||
}
|
||||
|
||||
// getBlockPreState returns the pre state of an incoming block. It uses the parent root of the block
|
||||
@@ -53,11 +46,6 @@ func (s *Service) getBlockPreState(ctx context.Context, b *ethpb.BeaconBlock) (*
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Verify block is a descendent of a finalized block.
|
||||
if err := s.VerifyBlkDescendant(ctx, bytesutil.ToBytes32(b.ParentRoot)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Verify block is later than the finalized epoch slot.
|
||||
if err := s.verifyBlkFinalizedSlot(b); err != nil {
|
||||
return nil, err
|
||||
@@ -78,7 +66,16 @@ func (s *Service) verifyBlkPreState(ctx context.Context, b *ethpb.BeaconBlock) e
|
||||
if !s.stateGen.StateSummaryExists(ctx, parentRoot) && !s.beaconDB.HasBlock(ctx, parentRoot) {
|
||||
return errors.New("could not reconstruct parent state")
|
||||
}
|
||||
if !s.stateGen.HasState(ctx, parentRoot) {
|
||||
|
||||
if err := s.VerifyBlkDescendant(ctx, bytesutil.ToBytes32(b.ParentRoot)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
has, err := s.stateGen.HasState(ctx, parentRoot)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !has {
|
||||
if err := s.beaconDB.SaveBlocks(ctx, s.getInitSyncBlocks()); err != nil {
|
||||
return errors.Wrap(err, "could not save initial sync blocks")
|
||||
}
|
||||
@@ -122,7 +119,10 @@ func (s *Service) VerifyBlkDescendant(ctx context.Context, root [32]byte) error
|
||||
// verifyBlkFinalizedSlot validates input block is not less than or equal
|
||||
// to current finalized slot.
|
||||
func (s *Service) verifyBlkFinalizedSlot(b *ethpb.BeaconBlock) error {
|
||||
finalizedSlot := helpers.StartSlot(s.finalizedCheckpt.Epoch)
|
||||
finalizedSlot, err := helpers.StartSlot(s.finalizedCheckpt.Epoch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if finalizedSlot >= b.Slot {
|
||||
return fmt.Errorf("block is equal or earlier than finalized block, slot %d < slot %d", b.Slot, finalizedSlot)
|
||||
}
|
||||
@@ -153,7 +153,11 @@ func (s *Service) shouldUpdateCurrentJustified(ctx context.Context, newJustified
|
||||
}
|
||||
|
||||
newJustifiedBlock := newJustifiedBlockSigned.Block
|
||||
if newJustifiedBlock.Slot <= helpers.StartSlot(s.justifiedCheckpt.Epoch) {
|
||||
jSlot, err := helpers.StartSlot(s.justifiedCheckpt.Epoch)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if newJustifiedBlock.Slot <= jSlot {
|
||||
return false, nil
|
||||
}
|
||||
var justifiedBlockSigned *ethpb.SignedBeaconBlock
|
||||
@@ -223,6 +227,10 @@ func (s *Service) updateFinalized(ctx context.Context, cp *ethpb.Checkpoint) err
|
||||
}
|
||||
s.clearInitSyncBlocks()
|
||||
|
||||
if err := s.beaconDB.SaveFinalizedCheckpoint(ctx, cp); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.prevFinalizedCheckpt = s.finalizedCheckpt
|
||||
s.finalizedCheckpt = cp
|
||||
|
||||
@@ -231,7 +239,7 @@ func (s *Service) updateFinalized(ctx context.Context, cp *ethpb.Checkpoint) err
|
||||
return errors.Wrap(err, "could not migrate to cold")
|
||||
}
|
||||
|
||||
return s.beaconDB.SaveFinalizedCheckpoint(ctx, cp)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ancestor returns the block root of an ancestry block from the input block root.
|
||||
@@ -250,18 +258,44 @@ func (s *Service) ancestor(ctx context.Context, root []byte, slot uint64) ([]byt
|
||||
ctx, span := trace.StartSpan(ctx, "forkChoice.ancestor")
|
||||
defer span.End()
|
||||
|
||||
r := bytesutil.ToBytes32(root)
|
||||
// Get ancestor root from fork choice store instead of recursively looking up blocks in DB.
|
||||
// This is most optimal outcome.
|
||||
ar, err := s.ancestorByForkChoiceStore(ctx, r, slot)
|
||||
if err != nil {
|
||||
// Try getting ancestor root from DB when failed to retrieve from fork choice store.
|
||||
// This is the second line of defense for retrieving ancestor root.
|
||||
ar, err = s.ancestorByDB(ctx, r, slot)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return ar, nil
|
||||
}
|
||||
|
||||
// This retrieves an ancestor root using fork choice store. The look up is looping through the a flat array structure.
|
||||
func (s *Service) ancestorByForkChoiceStore(ctx context.Context, r [32]byte, slot uint64) ([]byte, error) {
|
||||
if !s.forkChoiceStore.HasParent(r) {
|
||||
return nil, errors.New("could not find root in fork choice store")
|
||||
}
|
||||
return s.forkChoiceStore.AncestorRoot(ctx, r, slot)
|
||||
}
|
||||
|
||||
// This retrieves an ancestor root using DB. The look up is recursively looking up DB. Slower than `ancestorByForkChoiceStore`.
|
||||
func (s *Service) ancestorByDB(ctx context.Context, r [32]byte, slot uint64) ([]byte, error) {
|
||||
// Stop recursive ancestry lookup if context is cancelled.
|
||||
if ctx.Err() != nil {
|
||||
return nil, ctx.Err()
|
||||
}
|
||||
|
||||
signed, err := s.beaconDB.Block(ctx, bytesutil.ToBytes32(root))
|
||||
signed, err := s.beaconDB.Block(ctx, r)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get ancestor block")
|
||||
}
|
||||
|
||||
if s.hasInitSyncBlock(bytesutil.ToBytes32(root)) {
|
||||
signed = s.getInitSyncBlock(bytesutil.ToBytes32(root))
|
||||
if s.hasInitSyncBlock(r) {
|
||||
signed = s.getInitSyncBlock(r)
|
||||
}
|
||||
|
||||
if signed == nil || signed.Block == nil {
|
||||
@@ -269,10 +303,10 @@ func (s *Service) ancestor(ctx context.Context, root []byte, slot uint64) ([]byt
|
||||
}
|
||||
b := signed.Block
|
||||
if b.Slot == slot || b.Slot < slot {
|
||||
return root, nil
|
||||
return r[:], nil
|
||||
}
|
||||
|
||||
return s.ancestor(ctx, b.ParentRoot, slot)
|
||||
return s.ancestorByDB(ctx, bytesutil.ToBytes32(b.ParentRoot), slot)
|
||||
}
|
||||
|
||||
// This updates justified check point in store, if the new justified is later than stored justified or
|
||||
@@ -295,14 +329,14 @@ func (s *Service) finalizedImpliesNewJustified(ctx context.Context, state *state
|
||||
if !attestationutil.CheckPointIsEqual(s.justifiedCheckpt, state.CurrentJustifiedCheckpoint()) {
|
||||
if state.CurrentJustifiedCheckpoint().Epoch > s.justifiedCheckpt.Epoch {
|
||||
s.justifiedCheckpt = state.CurrentJustifiedCheckpoint()
|
||||
if err := s.cacheJustifiedStateBalances(ctx, bytesutil.ToBytes32(s.justifiedCheckpt.Root)); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
return s.cacheJustifiedStateBalances(ctx, bytesutil.ToBytes32(s.justifiedCheckpt.Root))
|
||||
}
|
||||
|
||||
// Update justified if store justified is not in chain with finalized check point.
|
||||
finalizedSlot := helpers.StartSlot(s.finalizedCheckpt.Epoch)
|
||||
finalizedSlot, err := helpers.StartSlot(s.finalizedCheckpt.Epoch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
justifiedRoot := s.ensureRootNotZeros(bytesutil.ToBytes32(s.justifiedCheckpt.Root))
|
||||
anc, err := s.ancestor(ctx, justifiedRoot[:], finalizedSlot)
|
||||
if err != nil {
|
||||
@@ -327,7 +361,11 @@ func (s *Service) fillInForkChoiceMissingBlocks(ctx context.Context, blk *ethpb.
|
||||
parentRoot := bytesutil.ToBytes32(blk.ParentRoot)
|
||||
slot := blk.Slot
|
||||
// Fork choice only matters from last finalized slot.
|
||||
higherThanFinalized := slot > helpers.StartSlot(s.finalizedCheckpt.Epoch)
|
||||
fSlot, err := helpers.StartSlot(s.finalizedCheckpt.Epoch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
higherThanFinalized := slot > fSlot
|
||||
// As long as parent node is not in fork choice store, and parent node is in DB.
|
||||
for !s.forkChoiceStore.HasNode(parentRoot) && s.beaconDB.HasBlock(ctx, parentRoot) && higherThanFinalized {
|
||||
b, err := s.beaconDB.Block(ctx, parentRoot)
|
||||
@@ -338,14 +376,14 @@ func (s *Service) fillInForkChoiceMissingBlocks(ctx context.Context, blk *ethpb.
|
||||
pendingNodes = append(pendingNodes, b.Block)
|
||||
parentRoot = bytesutil.ToBytes32(b.Block.ParentRoot)
|
||||
slot = b.Block.Slot
|
||||
higherThanFinalized = slot > helpers.StartSlot(s.finalizedCheckpt.Epoch)
|
||||
higherThanFinalized = slot > fSlot
|
||||
}
|
||||
|
||||
// Insert parent nodes to fork choice store in reverse order.
|
||||
// Lower slots should be at the end of the list.
|
||||
for i := len(pendingNodes) - 1; i >= 0; i-- {
|
||||
b := pendingNodes[i]
|
||||
r, err := stateutil.BlockRoot(b)
|
||||
r, err := b.HashTreeRoot()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -2,12 +2,11 @@ package blockchain
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/go-ssz"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/cache"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/state"
|
||||
@@ -16,16 +15,14 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/protoarray"
|
||||
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stategen"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/attestationutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/roughtime"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
"github.com/prysmaticlabs/prysm/shared/timeutils"
|
||||
)
|
||||
|
||||
func TestStore_OnBlock(t *testing.T) {
|
||||
@@ -33,58 +30,75 @@ func TestStore_OnBlock(t *testing.T) {
|
||||
db, sc := testDB.SetupDB(t)
|
||||
|
||||
cfg := &Config{
|
||||
BeaconDB: db,
|
||||
StateGen: stategen.New(db, sc),
|
||||
BeaconDB: db,
|
||||
StateGen: stategen.New(db, sc),
|
||||
ForkChoiceStore: protoarray.New(0, 0, [32]byte{}),
|
||||
}
|
||||
service, err := NewService(ctx, cfg)
|
||||
require.NoError(t, err)
|
||||
genesisStateRoot := [32]byte{}
|
||||
genesis := blocks.NewGenesisBlock(genesisStateRoot[:])
|
||||
assert.NoError(t, db.SaveBlock(ctx, genesis))
|
||||
validGenesisRoot, err := stateutil.BlockRoot(genesis.Block)
|
||||
validGenesisRoot, err := genesis.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
st := testutil.NewBeaconState()
|
||||
require.NoError(t, service.beaconDB.SaveState(ctx, st.Copy(), validGenesisRoot))
|
||||
roots, err := blockTree1(db, validGenesisRoot[:])
|
||||
require.NoError(t, err)
|
||||
random := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Slot: 1, ParentRoot: validGenesisRoot[:]}}
|
||||
random := testutil.NewBeaconBlock()
|
||||
random.Block.Slot = 1
|
||||
random.Block.ParentRoot = validGenesisRoot[:]
|
||||
assert.NoError(t, db.SaveBlock(ctx, random))
|
||||
randomParentRoot, err := stateutil.BlockRoot(random.Block)
|
||||
randomParentRoot, err := random.Block.HashTreeRoot()
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, service.beaconDB.SaveStateSummary(ctx, &pb.StateSummary{Slot: st.Slot(), Root: randomParentRoot[:]}))
|
||||
require.NoError(t, service.beaconDB.SaveState(ctx, st.Copy(), randomParentRoot))
|
||||
randomParentRoot2 := roots[1]
|
||||
require.NoError(t, service.beaconDB.SaveStateSummary(ctx, &pb.StateSummary{Slot: st.Slot(), Root: randomParentRoot2[:]}))
|
||||
require.NoError(t, service.beaconDB.SaveStateSummary(ctx, &pb.StateSummary{Slot: st.Slot(), Root: randomParentRoot2}))
|
||||
require.NoError(t, service.beaconDB.SaveState(ctx, st.Copy(), bytesutil.ToBytes32(randomParentRoot2)))
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
blk *ethpb.BeaconBlock
|
||||
blk *ethpb.SignedBeaconBlock
|
||||
s *stateTrie.BeaconState
|
||||
time uint64
|
||||
wantErrString string
|
||||
}{
|
||||
{
|
||||
name: "parent block root does not have a state",
|
||||
blk: ðpb.BeaconBlock{},
|
||||
blk: testutil.NewBeaconBlock(),
|
||||
s: st.Copy(),
|
||||
wantErrString: "could not reconstruct parent state",
|
||||
},
|
||||
{
|
||||
name: "block is from the future",
|
||||
blk: ðpb.BeaconBlock{ParentRoot: randomParentRoot[:], Slot: params.BeaconConfig().FarFutureEpoch},
|
||||
name: "block is from the future",
|
||||
blk: func() *ethpb.SignedBeaconBlock {
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block.ParentRoot = randomParentRoot2
|
||||
b.Block.Slot = params.BeaconConfig().FarFutureEpoch
|
||||
return b
|
||||
}(),
|
||||
s: st.Copy(),
|
||||
wantErrString: "far distant future",
|
||||
wantErrString: "is in the far distant future",
|
||||
},
|
||||
{
|
||||
name: "could not get finalized block",
|
||||
blk: ðpb.BeaconBlock{ParentRoot: randomParentRoot[:]},
|
||||
name: "could not get finalized block",
|
||||
blk: func() *ethpb.SignedBeaconBlock {
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block.ParentRoot = randomParentRoot[:]
|
||||
return b
|
||||
}(),
|
||||
s: st.Copy(),
|
||||
wantErrString: "is not a descendent of the current finalized block",
|
||||
},
|
||||
{
|
||||
name: "same slot as finalized block",
|
||||
blk: ðpb.BeaconBlock{Slot: 0, ParentRoot: randomParentRoot2},
|
||||
name: "same slot as finalized block",
|
||||
blk: func() *ethpb.SignedBeaconBlock {
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block.Slot = 0
|
||||
b.Block.ParentRoot = randomParentRoot2
|
||||
return b
|
||||
}(),
|
||||
s: st.Copy(),
|
||||
wantErrString: "block is equal or earlier than finalized block, slot 0 < slot 0",
|
||||
},
|
||||
@@ -98,9 +112,9 @@ func TestStore_OnBlock(t *testing.T) {
|
||||
service.prevFinalizedCheckpt = ðpb.Checkpoint{Root: validGenesisRoot[:]}
|
||||
service.finalizedCheckpt.Root = roots[0]
|
||||
|
||||
root, err := stateutil.BlockRoot(tt.blk)
|
||||
root, err := tt.blk.Block.HashTreeRoot()
|
||||
assert.NoError(t, err)
|
||||
err = service.onBlock(ctx, ðpb.SignedBeaconBlock{Block: tt.blk}, root)
|
||||
err = service.onBlock(ctx, tt.blk, root)
|
||||
assert.ErrorContains(t, tt.wantErrString, err)
|
||||
})
|
||||
}
|
||||
@@ -120,6 +134,13 @@ func TestStore_OnBlockBatch(t *testing.T) {
|
||||
genesisStateRoot := [32]byte{}
|
||||
genesis := blocks.NewGenesisBlock(genesisStateRoot[:])
|
||||
assert.NoError(t, db.SaveBlock(ctx, genesis))
|
||||
gRoot, err := genesis.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
service.finalizedCheckpt = ðpb.Checkpoint{
|
||||
Root: gRoot[:],
|
||||
}
|
||||
service.forkChoiceStore = protoarray.New(0, 0, [32]byte{})
|
||||
service.saveInitSyncBlock(gRoot, genesis)
|
||||
|
||||
st, keys := testutil.DeterministicGenesisState(t, 64)
|
||||
|
||||
@@ -136,14 +157,17 @@ func TestStore_OnBlockBatch(t *testing.T) {
|
||||
if i == 1 {
|
||||
firstState = bState.Copy()
|
||||
}
|
||||
root, err := stateutil.BlockRoot(b.Block)
|
||||
root, err := b.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
service.saveInitSyncBlock(root, b)
|
||||
blks = append(blks, b)
|
||||
blkRoots = append(blkRoots, root)
|
||||
}
|
||||
|
||||
blks[0].Block.ParentRoot = gRoot[:]
|
||||
require.NoError(t, db.SaveBlock(context.Background(), blks[0]))
|
||||
require.NoError(t, service.stateGen.SaveState(ctx, blkRoots[0], firstState))
|
||||
_, _, _, err = service.onBlockBatch(ctx, blks[1:], blkRoots[1:])
|
||||
_, _, err = service.onBlockBatch(ctx, blks[1:], blkRoots[1:])
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
@@ -153,22 +177,22 @@ func TestRemoveStateSinceLastFinalized_EmptyStartSlot(t *testing.T) {
|
||||
params.UseMinimalConfig()
|
||||
defer params.UseMainnetConfig()
|
||||
|
||||
cfg := &Config{BeaconDB: db}
|
||||
cfg := &Config{BeaconDB: db, ForkChoiceStore: protoarray.New(0, 0, [32]byte{})}
|
||||
service, err := NewService(ctx, cfg)
|
||||
require.NoError(t, err)
|
||||
service.genesisTime = time.Now()
|
||||
|
||||
update, err := service.shouldUpdateCurrentJustified(ctx, ðpb.Checkpoint{})
|
||||
update, err := service.shouldUpdateCurrentJustified(ctx, ðpb.Checkpoint{Root: make([]byte, 32)})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, true, update, "Should be able to update justified")
|
||||
lastJustifiedBlk := testutil.NewBeaconBlock()
|
||||
lastJustifiedBlk.Block.ParentRoot = bytesutil.PadTo([]byte{'G'}, 32)
|
||||
lastJustifiedRoot, err := stateutil.BlockRoot(lastJustifiedBlk.Block)
|
||||
lastJustifiedRoot, err := lastJustifiedBlk.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
newJustifiedBlk := testutil.NewBeaconBlock()
|
||||
newJustifiedBlk.Block.Slot = 1
|
||||
newJustifiedBlk.Block.ParentRoot = bytesutil.PadTo(lastJustifiedRoot[:], 32)
|
||||
newJustifiedRoot, err := stateutil.BlockRoot(newJustifiedBlk.Block)
|
||||
newJustifiedRoot, err := newJustifiedBlk.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, service.beaconDB.SaveBlock(ctx, newJustifiedBlk))
|
||||
require.NoError(t, service.beaconDB.SaveBlock(ctx, lastJustifiedBlk))
|
||||
@@ -192,11 +216,11 @@ func TestShouldUpdateJustified_ReturnFalse(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
lastJustifiedBlk := testutil.NewBeaconBlock()
|
||||
lastJustifiedBlk.Block.ParentRoot = bytesutil.PadTo([]byte{'G'}, 32)
|
||||
lastJustifiedRoot, err := stateutil.BlockRoot(lastJustifiedBlk.Block)
|
||||
lastJustifiedRoot, err := lastJustifiedBlk.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
newJustifiedBlk := testutil.NewBeaconBlock()
|
||||
newJustifiedBlk.Block.ParentRoot = bytesutil.PadTo(lastJustifiedRoot[:], 32)
|
||||
newJustifiedRoot, err := stateutil.BlockRoot(newJustifiedBlk.Block)
|
||||
newJustifiedRoot, err := newJustifiedBlk.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, service.beaconDB.SaveBlock(ctx, newJustifiedBlk))
|
||||
require.NoError(t, service.beaconDB.SaveBlock(ctx, lastJustifiedBlk))
|
||||
@@ -211,9 +235,6 @@ func TestShouldUpdateJustified_ReturnFalse(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCachedPreState_CanGetFromStateSummary(t *testing.T) {
|
||||
resetCfg := featureconfig.InitWithReset(&featureconfig.Flags{NewStateMgmt: true})
|
||||
defer resetCfg()
|
||||
|
||||
ctx := context.Background()
|
||||
db, sc := testDB.SetupDB(t)
|
||||
|
||||
@@ -226,17 +247,27 @@ func TestCachedPreState_CanGetFromStateSummary(t *testing.T) {
|
||||
|
||||
s, err := stateTrie.InitializeFromProto(&pb.BeaconState{Slot: 1, GenesisValidatorsRoot: params.BeaconConfig().ZeroHash[:]})
|
||||
require.NoError(t, err)
|
||||
r := [32]byte{'A'}
|
||||
b := ðpb.BeaconBlock{Slot: 1, ParentRoot: r[:]}
|
||||
require.NoError(t, service.beaconDB.SaveStateSummary(ctx, &pb.StateSummary{Slot: 1, Root: r[:]}))
|
||||
require.NoError(t, service.stateGen.SaveState(ctx, r, s))
|
||||
require.NoError(t, service.verifyBlkPreState(ctx, b))
|
||||
|
||||
genesisStateRoot := [32]byte{}
|
||||
genesis := blocks.NewGenesisBlock(genesisStateRoot[:])
|
||||
assert.NoError(t, db.SaveBlock(ctx, genesis))
|
||||
gRoot, err := genesis.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
service.finalizedCheckpt = ðpb.Checkpoint{
|
||||
Root: gRoot[:],
|
||||
}
|
||||
service.forkChoiceStore = protoarray.New(0, 0, [32]byte{})
|
||||
service.saveInitSyncBlock(gRoot, genesis)
|
||||
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block.Slot = 1
|
||||
b.Block.ParentRoot = gRoot[:]
|
||||
require.NoError(t, service.beaconDB.SaveStateSummary(ctx, &pb.StateSummary{Slot: 1, Root: gRoot[:]}))
|
||||
require.NoError(t, service.stateGen.SaveState(ctx, gRoot, s))
|
||||
require.NoError(t, service.verifyBlkPreState(ctx, b.Block))
|
||||
}
|
||||
|
||||
func TestCachedPreState_CanGetFromDB(t *testing.T) {
|
||||
resetCfg := featureconfig.InitWithReset(&featureconfig.Flags{NewStateMgmt: true})
|
||||
defer resetCfg()
|
||||
|
||||
ctx := context.Background()
|
||||
db, sc := testDB.SetupDB(t)
|
||||
|
||||
@@ -247,19 +278,30 @@ func TestCachedPreState_CanGetFromDB(t *testing.T) {
|
||||
service, err := NewService(ctx, cfg)
|
||||
require.NoError(t, err)
|
||||
|
||||
r := [32]byte{'A'}
|
||||
b := ðpb.BeaconBlock{Slot: 1, ParentRoot: r[:]}
|
||||
genesisStateRoot := [32]byte{}
|
||||
genesis := blocks.NewGenesisBlock(genesisStateRoot[:])
|
||||
assert.NoError(t, db.SaveBlock(ctx, genesis))
|
||||
gRoot, err := genesis.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
service.finalizedCheckpt = ðpb.Checkpoint{
|
||||
Root: gRoot[:],
|
||||
}
|
||||
service.forkChoiceStore = protoarray.New(0, 0, [32]byte{})
|
||||
service.saveInitSyncBlock(gRoot, genesis)
|
||||
|
||||
service.finalizedCheckpt = ðpb.Checkpoint{Root: r[:]}
|
||||
err = service.verifyBlkPreState(ctx, b)
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block.Slot = 1
|
||||
service.finalizedCheckpt = ðpb.Checkpoint{Root: gRoot[:]}
|
||||
err = service.verifyBlkPreState(ctx, b.Block)
|
||||
wanted := "could not reconstruct parent state"
|
||||
assert.ErrorContains(t, wanted, err)
|
||||
|
||||
b.Block.ParentRoot = gRoot[:]
|
||||
s, err := stateTrie.InitializeFromProto(&pb.BeaconState{Slot: 1})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, service.beaconDB.SaveStateSummary(ctx, &pb.StateSummary{Slot: 1, Root: r[:]}))
|
||||
require.NoError(t, service.stateGen.SaveState(ctx, r, s))
|
||||
require.NoError(t, service.verifyBlkPreState(ctx, b))
|
||||
require.NoError(t, service.beaconDB.SaveStateSummary(ctx, &pb.StateSummary{Slot: 1, Root: gRoot[:]}))
|
||||
require.NoError(t, service.stateGen.SaveState(ctx, gRoot, s))
|
||||
require.NoError(t, service.verifyBlkPreState(ctx, b.Block))
|
||||
}
|
||||
|
||||
func TestUpdateJustified_CouldUpdateBest(t *testing.T) {
|
||||
@@ -270,9 +312,9 @@ func TestUpdateJustified_CouldUpdateBest(t *testing.T) {
|
||||
service, err := NewService(ctx, cfg)
|
||||
require.NoError(t, err)
|
||||
|
||||
signedBlock := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{}}
|
||||
signedBlock := testutil.NewBeaconBlock()
|
||||
require.NoError(t, db.SaveBlock(ctx, signedBlock))
|
||||
r, err := stateutil.BlockRoot(signedBlock.Block)
|
||||
r, err := signedBlock.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
service.justifiedCheckpt = ðpb.Checkpoint{Root: []byte{'A'}}
|
||||
service.bestJustifiedCheckpt = ðpb.Checkpoint{Root: []byte{'A'}}
|
||||
@@ -302,12 +344,12 @@ func TestFillForkChoiceMissingBlocks_CanSave(t *testing.T) {
|
||||
service, err := NewService(ctx, cfg)
|
||||
require.NoError(t, err)
|
||||
service.forkChoiceStore = protoarray.New(0, 0, [32]byte{'A'})
|
||||
service.finalizedCheckpt = ðpb.Checkpoint{}
|
||||
service.finalizedCheckpt = ðpb.Checkpoint{Root: make([]byte, 32)}
|
||||
|
||||
genesisStateRoot := [32]byte{}
|
||||
genesis := blocks.NewGenesisBlock(genesisStateRoot[:])
|
||||
require.NoError(t, db.SaveBlock(ctx, genesis))
|
||||
validGenesisRoot, err := stateutil.BlockRoot(genesis.Block)
|
||||
validGenesisRoot, err := genesis.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
st := testutil.NewBeaconState()
|
||||
|
||||
@@ -316,10 +358,12 @@ func TestFillForkChoiceMissingBlocks_CanSave(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
beaconState, _ := testutil.DeterministicGenesisState(t, 32)
|
||||
block := ðpb.BeaconBlock{Slot: 9, ParentRoot: roots[8], Body: ðpb.BeaconBlockBody{Graffiti: []byte{}}}
|
||||
block := testutil.NewBeaconBlock()
|
||||
block.Block.Slot = 9
|
||||
block.Block.ParentRoot = roots[8]
|
||||
|
||||
err = service.fillInForkChoiceMissingBlocks(
|
||||
context.Background(), block, beaconState.FinalizedCheckpoint(), beaconState.CurrentJustifiedCheckpoint())
|
||||
context.Background(), block.Block, beaconState.FinalizedCheckpoint(), beaconState.CurrentJustifiedCheckpoint())
|
||||
require.NoError(t, err)
|
||||
|
||||
// 5 nodes from the block tree 1. B0 - B3 - B4 - B6 - B8
|
||||
@@ -343,22 +387,27 @@ func TestFillForkChoiceMissingBlocks_FilterFinalized(t *testing.T) {
|
||||
genesisStateRoot := [32]byte{}
|
||||
genesis := blocks.NewGenesisBlock(genesisStateRoot[:])
|
||||
assert.NoError(t, db.SaveBlock(ctx, genesis))
|
||||
validGenesisRoot, err := stateutil.BlockRoot(genesis.Block)
|
||||
validGenesisRoot, err := genesis.Block.HashTreeRoot()
|
||||
assert.NoError(t, err)
|
||||
st := testutil.NewBeaconState()
|
||||
|
||||
require.NoError(t, service.beaconDB.SaveState(ctx, st.Copy(), validGenesisRoot))
|
||||
|
||||
// Define a tree branch, slot 63 <- 64 <- 65
|
||||
b63 := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Slot: 63, Body: ðpb.BeaconBlockBody{}}}
|
||||
b63 := testutil.NewBeaconBlock()
|
||||
b63.Block.Slot = 63
|
||||
require.NoError(t, service.beaconDB.SaveBlock(ctx, b63))
|
||||
r63, err := stateutil.BlockRoot(b63.Block)
|
||||
r63, err := b63.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
b64 := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Slot: 64, ParentRoot: r63[:], Body: ðpb.BeaconBlockBody{}}}
|
||||
b64 := testutil.NewBeaconBlock()
|
||||
b64.Block.Slot = 64
|
||||
b64.Block.ParentRoot = r63[:]
|
||||
require.NoError(t, service.beaconDB.SaveBlock(ctx, b64))
|
||||
r64, err := stateutil.BlockRoot(b64.Block)
|
||||
r64, err := b64.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
b65 := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Slot: 65, ParentRoot: r64[:], Body: ðpb.BeaconBlockBody{}}}
|
||||
b65 := testutil.NewBeaconBlock()
|
||||
b65.Block.Slot = 65
|
||||
b65.Block.ParentRoot = r64[:]
|
||||
require.NoError(t, service.beaconDB.SaveBlock(ctx, b65))
|
||||
|
||||
beaconState, _ := testutil.DeterministicGenesisState(t, 32)
|
||||
@@ -379,58 +428,74 @@ func TestFillForkChoiceMissingBlocks_FilterFinalized(t *testing.T) {
|
||||
// \- B3 - B4 - B6 - B8
|
||||
// (B1, and B3 are all from the same slots)
|
||||
func blockTree1(db db.Database, genesisRoot []byte) ([][]byte, error) {
|
||||
b0 := ðpb.BeaconBlock{Slot: 0, ParentRoot: genesisRoot}
|
||||
r0, err := ssz.HashTreeRoot(b0)
|
||||
genesisRoot = bytesutil.PadTo(genesisRoot, 32)
|
||||
b0 := testutil.NewBeaconBlock()
|
||||
b0.Block.Slot = 0
|
||||
b0.Block.ParentRoot = genesisRoot
|
||||
r0, err := b0.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b1 := ðpb.BeaconBlock{Slot: 1, ParentRoot: r0[:]}
|
||||
r1, err := ssz.HashTreeRoot(b1)
|
||||
b1 := testutil.NewBeaconBlock()
|
||||
b1.Block.Slot = 1
|
||||
b1.Block.ParentRoot = r0[:]
|
||||
r1, err := b1.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b3 := ðpb.BeaconBlock{Slot: 3, ParentRoot: r0[:]}
|
||||
r3, err := ssz.HashTreeRoot(b3)
|
||||
b3 := testutil.NewBeaconBlock()
|
||||
b3.Block.Slot = 3
|
||||
b3.Block.ParentRoot = r0[:]
|
||||
r3, err := b3.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b4 := ðpb.BeaconBlock{Slot: 4, ParentRoot: r3[:]}
|
||||
r4, err := ssz.HashTreeRoot(b4)
|
||||
b4 := testutil.NewBeaconBlock()
|
||||
b4.Block.Slot = 4
|
||||
b4.Block.ParentRoot = r3[:]
|
||||
r4, err := b4.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b5 := ðpb.BeaconBlock{Slot: 5, ParentRoot: r4[:]}
|
||||
r5, err := ssz.HashTreeRoot(b5)
|
||||
b5 := testutil.NewBeaconBlock()
|
||||
b5.Block.Slot = 5
|
||||
b5.Block.ParentRoot = r4[:]
|
||||
r5, err := b5.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b6 := ðpb.BeaconBlock{Slot: 6, ParentRoot: r4[:]}
|
||||
r6, err := ssz.HashTreeRoot(b6)
|
||||
b6 := testutil.NewBeaconBlock()
|
||||
b6.Block.Slot = 6
|
||||
b6.Block.ParentRoot = r4[:]
|
||||
r6, err := b6.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b7 := ðpb.BeaconBlock{Slot: 7, ParentRoot: r5[:]}
|
||||
r7, err := ssz.HashTreeRoot(b7)
|
||||
b7 := testutil.NewBeaconBlock()
|
||||
b7.Block.Slot = 7
|
||||
b7.Block.ParentRoot = r5[:]
|
||||
r7, err := b7.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b8 := ðpb.BeaconBlock{Slot: 8, ParentRoot: r6[:]}
|
||||
r8, err := ssz.HashTreeRoot(b8)
|
||||
b8 := testutil.NewBeaconBlock()
|
||||
b8.Block.Slot = 8
|
||||
b8.Block.ParentRoot = r6[:]
|
||||
r8, err := b8.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
st := testutil.NewBeaconState()
|
||||
|
||||
for _, b := range []*ethpb.BeaconBlock{b0, b1, b3, b4, b5, b6, b7, b8} {
|
||||
for _, b := range []*ethpb.SignedBeaconBlock{b0, b1, b3, b4, b5, b6, b7, b8} {
|
||||
beaconBlock := testutil.NewBeaconBlock()
|
||||
beaconBlock.Block.Slot = b.Slot
|
||||
beaconBlock.Block.ParentRoot = bytesutil.PadTo(b.ParentRoot, 32)
|
||||
beaconBlock.Block.Body = ðpb.BeaconBlockBody{}
|
||||
beaconBlock.Block.Slot = b.Block.Slot
|
||||
beaconBlock.Block.ParentRoot = bytesutil.PadTo(b.Block.ParentRoot, 32)
|
||||
if err := db.SaveBlock(context.Background(), beaconBlock); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := db.SaveState(context.Background(), st.Copy(), bytesutil.ToBytes32(beaconBlock.Block.ParentRoot)); err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "could not save state")
|
||||
}
|
||||
}
|
||||
if err := db.SaveState(context.Background(), st.Copy(), r1); err != nil {
|
||||
@@ -446,34 +511,48 @@ func blockTree1(db db.Database, genesisRoot []byte) ([][]byte, error) {
|
||||
}
|
||||
|
||||
func TestCurrentSlot_HandlesOverflow(t *testing.T) {
|
||||
svc := Service{genesisTime: roughtime.Now().Add(1 * time.Hour)}
|
||||
svc := Service{genesisTime: timeutils.Now().Add(1 * time.Hour)}
|
||||
|
||||
slot := svc.CurrentSlot()
|
||||
require.Equal(t, uint64(0), slot, "Unexpected slot")
|
||||
}
|
||||
func TestAncestorByDB_CtxErr(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
service, err := NewService(ctx, &Config{})
|
||||
require.NoError(t, err)
|
||||
|
||||
cancel()
|
||||
_, err = service.ancestorByDB(ctx, [32]byte{}, 0)
|
||||
require.ErrorContains(t, "context canceled", err)
|
||||
}
|
||||
|
||||
func TestAncestor_HandleSkipSlot(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
db, _ := testDB.SetupDB(t)
|
||||
|
||||
cfg := &Config{BeaconDB: db}
|
||||
cfg := &Config{BeaconDB: db, ForkChoiceStore: protoarray.New(0, 0, [32]byte{})}
|
||||
service, err := NewService(ctx, cfg)
|
||||
require.NoError(t, err)
|
||||
|
||||
b1 := ðpb.BeaconBlock{Slot: 1, ParentRoot: []byte{'a'}}
|
||||
r1, err := ssz.HashTreeRoot(b1)
|
||||
b1 := testutil.NewBeaconBlock()
|
||||
b1.Block.Slot = 1
|
||||
b1.Block.ParentRoot = bytesutil.PadTo([]byte{'a'}, 32)
|
||||
r1, err := b1.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
b100 := ðpb.BeaconBlock{Slot: 100, ParentRoot: r1[:]}
|
||||
r100, err := ssz.HashTreeRoot(b100)
|
||||
b100 := testutil.NewBeaconBlock()
|
||||
b100.Block.Slot = 100
|
||||
b100.Block.ParentRoot = r1[:]
|
||||
r100, err := b100.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
b200 := ðpb.BeaconBlock{Slot: 200, ParentRoot: r100[:]}
|
||||
r200, err := ssz.HashTreeRoot(b200)
|
||||
b200 := testutil.NewBeaconBlock()
|
||||
b200.Block.Slot = 200
|
||||
b200.Block.ParentRoot = r100[:]
|
||||
r200, err := b200.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
for _, b := range []*ethpb.BeaconBlock{b1, b100, b200} {
|
||||
for _, b := range []*ethpb.SignedBeaconBlock{b1, b100, b200} {
|
||||
beaconBlock := testutil.NewBeaconBlock()
|
||||
beaconBlock.Block.Slot = b.Slot
|
||||
beaconBlock.Block.ParentRoot = bytesutil.PadTo(b.ParentRoot, 32)
|
||||
beaconBlock.Block.Body = ðpb.BeaconBlockBody{}
|
||||
beaconBlock.Block.Slot = b.Block.Slot
|
||||
beaconBlock.Block.ParentRoot = bytesutil.PadTo(b.Block.ParentRoot, 32)
|
||||
require.NoError(t, db.SaveBlock(context.Background(), beaconBlock))
|
||||
}
|
||||
|
||||
@@ -492,6 +571,82 @@ func TestAncestor_HandleSkipSlot(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestAncestor_CanUseForkchoice(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
cfg := &Config{ForkChoiceStore: protoarray.New(0, 0, [32]byte{})}
|
||||
service, err := NewService(ctx, cfg)
|
||||
require.NoError(t, err)
|
||||
|
||||
b1 := testutil.NewBeaconBlock()
|
||||
b1.Block.Slot = 1
|
||||
b1.Block.ParentRoot = bytesutil.PadTo([]byte{'a'}, 32)
|
||||
r1, err := b1.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
b100 := testutil.NewBeaconBlock()
|
||||
b100.Block.Slot = 100
|
||||
b100.Block.ParentRoot = r1[:]
|
||||
r100, err := b100.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
b200 := testutil.NewBeaconBlock()
|
||||
b200.Block.Slot = 200
|
||||
b200.Block.ParentRoot = r100[:]
|
||||
r200, err := b200.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
for _, b := range []*ethpb.SignedBeaconBlock{b1, b100, b200} {
|
||||
beaconBlock := testutil.NewBeaconBlock()
|
||||
beaconBlock.Block.Slot = b.Block.Slot
|
||||
beaconBlock.Block.ParentRoot = bytesutil.PadTo(b.Block.ParentRoot, 32)
|
||||
r, err := b.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, service.forkChoiceStore.ProcessBlock(context.Background(), b.Block.Slot, r, bytesutil.ToBytes32(b.Block.ParentRoot), [32]byte{}, 0, 0)) // Saves blocks to fork choice store.
|
||||
}
|
||||
|
||||
r, err := service.ancestor(context.Background(), r200[:], 150)
|
||||
require.NoError(t, err)
|
||||
if bytesutil.ToBytes32(r) != r100 {
|
||||
t.Error("Did not get correct root")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAncestor_CanUseDB(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
db, _ := testDB.SetupDB(t)
|
||||
|
||||
cfg := &Config{BeaconDB: db, ForkChoiceStore: protoarray.New(0, 0, [32]byte{})}
|
||||
service, err := NewService(ctx, cfg)
|
||||
require.NoError(t, err)
|
||||
|
||||
b1 := testutil.NewBeaconBlock()
|
||||
b1.Block.Slot = 1
|
||||
b1.Block.ParentRoot = bytesutil.PadTo([]byte{'a'}, 32)
|
||||
r1, err := b1.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
b100 := testutil.NewBeaconBlock()
|
||||
b100.Block.Slot = 100
|
||||
b100.Block.ParentRoot = r1[:]
|
||||
r100, err := b100.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
b200 := testutil.NewBeaconBlock()
|
||||
b200.Block.Slot = 200
|
||||
b200.Block.ParentRoot = r100[:]
|
||||
r200, err := b200.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
for _, b := range []*ethpb.SignedBeaconBlock{b1, b100, b200} {
|
||||
beaconBlock := testutil.NewBeaconBlock()
|
||||
beaconBlock.Block.Slot = b.Block.Slot
|
||||
beaconBlock.Block.ParentRoot = bytesutil.PadTo(b.Block.ParentRoot, 32)
|
||||
require.NoError(t, db.SaveBlock(context.Background(), beaconBlock)) // Saves blocks to DB.
|
||||
}
|
||||
|
||||
require.NoError(t, service.forkChoiceStore.ProcessBlock(context.Background(), 200, r200, r200, [32]byte{}, 0, 0))
|
||||
|
||||
r, err := service.ancestor(context.Background(), r200[:], 150)
|
||||
require.NoError(t, err)
|
||||
if bytesutil.ToBytes32(r) != r100 {
|
||||
t.Error("Did not get correct root")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnsureRootNotZeroHashes(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
cfg := &Config{}
|
||||
@@ -548,7 +703,7 @@ func TestFinalizedImpliesNewJustified(t *testing.T) {
|
||||
for _, test := range tests {
|
||||
beaconState := testutil.NewBeaconState()
|
||||
require.NoError(t, beaconState.SetCurrentJustifiedCheckpoint(test.args.stateCheckPoint))
|
||||
service, err := NewService(ctx, &Config{BeaconDB: db, StateGen: stategen.New(db, sc)})
|
||||
service, err := NewService(ctx, &Config{BeaconDB: db, StateGen: stategen.New(db, sc), ForkChoiceStore: protoarray.New(0, 0, [32]byte{})})
|
||||
require.NoError(t, err)
|
||||
service.justifiedCheckpt = test.args.cachedCheckPoint
|
||||
require.NoError(t, service.beaconDB.SaveStateSummary(ctx, &pb.StateSummary{Root: bytesutil.PadTo(test.want.Root, 32)}))
|
||||
@@ -556,16 +711,20 @@ func TestFinalizedImpliesNewJustified(t *testing.T) {
|
||||
require.NoError(t, service.beaconDB.SaveState(ctx, genesisState, bytesutil.ToBytes32(test.want.Root)))
|
||||
|
||||
if test.args.diffFinalizedCheckPoint {
|
||||
b1 := ðpb.BeaconBlock{Slot: 1, ParentRoot: []byte{'a'}}
|
||||
r1, err := ssz.HashTreeRoot(b1)
|
||||
b1 := testutil.NewBeaconBlock()
|
||||
b1.Block.Slot = 1
|
||||
b1.Block.ParentRoot = bytesutil.PadTo([]byte{'a'}, 32)
|
||||
r1, err := b1.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
b100 := ðpb.BeaconBlock{Slot: 100, ParentRoot: r1[:]}
|
||||
r100, err := ssz.HashTreeRoot(b100)
|
||||
b100 := testutil.NewBeaconBlock()
|
||||
b100.Block.Slot = 100
|
||||
b100.Block.ParentRoot = r1[:]
|
||||
r100, err := b100.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
for _, b := range []*ethpb.BeaconBlock{b1, b100} {
|
||||
for _, b := range []*ethpb.SignedBeaconBlock{b1, b100} {
|
||||
beaconBlock := testutil.NewBeaconBlock()
|
||||
beaconBlock.Block.Slot = b.Slot
|
||||
beaconBlock.Block.ParentRoot = bytesutil.PadTo(b.ParentRoot, 32)
|
||||
beaconBlock.Block.Slot = b.Block.Slot
|
||||
beaconBlock.Block.ParentRoot = bytesutil.PadTo(b.Block.ParentRoot, 32)
|
||||
require.NoError(t, service.beaconDB.SaveBlock(context.Background(), beaconBlock))
|
||||
}
|
||||
service.finalizedCheckpt = ðpb.Checkpoint{Root: []byte{'c'}, Epoch: 1}
|
||||
@@ -583,14 +742,14 @@ func TestVerifyBlkDescendant(t *testing.T) {
|
||||
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block.Slot = 1
|
||||
r, err := stateutil.BlockRoot(b.Block)
|
||||
r, err := b.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, db.SaveBlock(ctx, b))
|
||||
|
||||
b1 := testutil.NewBeaconBlock()
|
||||
b1.Block.Slot = 1
|
||||
b1.Block.Body.Graffiti = bytesutil.PadTo([]byte{'a'}, 32)
|
||||
r1, err := stateutil.BlockRoot(b1.Block)
|
||||
r1, err := b1.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, db.SaveBlock(ctx, b1))
|
||||
|
||||
@@ -600,18 +759,16 @@ func TestVerifyBlkDescendant(t *testing.T) {
|
||||
finalizedSlot uint64
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
shouldError bool
|
||||
err string
|
||||
name string
|
||||
args args
|
||||
wantedErr string
|
||||
}{
|
||||
{
|
||||
name: "could not get finalized block in block service cache",
|
||||
args: args{
|
||||
finalizedRoot: [32]byte{'a'},
|
||||
},
|
||||
shouldError: true,
|
||||
err: "nil finalized block",
|
||||
wantedErr: "nil finalized block",
|
||||
},
|
||||
{
|
||||
name: "could not get finalized block root in DB",
|
||||
@@ -619,8 +776,7 @@ func TestVerifyBlkDescendant(t *testing.T) {
|
||||
finalizedRoot: r,
|
||||
parentRoot: [32]byte{'a'},
|
||||
},
|
||||
shouldError: true,
|
||||
err: "could not get finalized block root",
|
||||
wantedErr: "could not get finalized block root",
|
||||
},
|
||||
{
|
||||
name: "is not descendant",
|
||||
@@ -628,8 +784,7 @@ func TestVerifyBlkDescendant(t *testing.T) {
|
||||
finalizedRoot: r1,
|
||||
parentRoot: r,
|
||||
},
|
||||
shouldError: true,
|
||||
err: "is not a descendent of the current finalized block slot",
|
||||
wantedErr: "is not a descendent of the current finalized block slot",
|
||||
},
|
||||
{
|
||||
name: "is descendant",
|
||||
@@ -637,22 +792,19 @@ func TestVerifyBlkDescendant(t *testing.T) {
|
||||
finalizedRoot: r,
|
||||
parentRoot: r,
|
||||
},
|
||||
shouldError: false,
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
service, err := NewService(ctx, &Config{BeaconDB: db, StateGen: stategen.New(db, sc)})
|
||||
for _, tt := range tests {
|
||||
service, err := NewService(ctx, &Config{BeaconDB: db, StateGen: stategen.New(db, sc), ForkChoiceStore: protoarray.New(0, 0, [32]byte{})})
|
||||
require.NoError(t, err)
|
||||
service.finalizedCheckpt = ðpb.Checkpoint{
|
||||
Root: test.args.finalizedRoot[:],
|
||||
Root: tt.args.finalizedRoot[:],
|
||||
}
|
||||
err = service.VerifyBlkDescendant(ctx, test.args.parentRoot)
|
||||
if test.shouldError {
|
||||
if err == nil || !strings.Contains(err.Error(), test.err) {
|
||||
t.Error("Did not get wanted error")
|
||||
}
|
||||
err = service.VerifyBlkDescendant(ctx, tt.args.parentRoot)
|
||||
if tt.wantedErr != "" {
|
||||
assert.ErrorContains(t, tt.wantedErr, err)
|
||||
} else if err != nil {
|
||||
t.Error(err)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -664,8 +816,8 @@ func TestUpdateJustifiedInitSync(t *testing.T) {
|
||||
service, err := NewService(ctx, cfg)
|
||||
require.NoError(t, err)
|
||||
|
||||
gBlk := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{}}
|
||||
gRoot, err := stateutil.BlockRoot(gBlk.Block)
|
||||
gBlk := testutil.NewBeaconBlock()
|
||||
gRoot, err := gBlk.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, service.beaconDB.SaveBlock(ctx, gBlk))
|
||||
require.NoError(t, service.beaconDB.SaveGenesisBlockRoot(ctx, gRoot))
|
||||
@@ -682,8 +834,6 @@ func TestUpdateJustifiedInitSync(t *testing.T) {
|
||||
assert.DeepEqual(t, currentCp, service.prevJustifiedCheckpt, "Incorrect previous justified checkpoint")
|
||||
assert.DeepEqual(t, newCp, service.CurrentJustifiedCheckpt(), "Incorrect current justified checkpoint in cache")
|
||||
cp, err := service.beaconDB.JustifiedCheckpoint(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, newCp, cp, "Incorrect current justified checkpoint in db")
|
||||
}
|
||||
|
||||
@@ -10,11 +10,12 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/feed"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/roughtime"
|
||||
"github.com/prysmaticlabs/prysm/shared/slotutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/timeutils"
|
||||
"github.com/sirupsen/logrus"
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
@@ -24,6 +25,8 @@ type AttestationReceiver interface {
|
||||
ReceiveAttestationNoPubsub(ctx context.Context, att *ethpb.Attestation) error
|
||||
IsValidAttestation(ctx context.Context, att *ethpb.Attestation) bool
|
||||
AttestationPreState(ctx context.Context, att *ethpb.Attestation) (*state.BeaconState, error)
|
||||
AttestationCheckPtInfo(ctx context.Context, att *ethpb.Attestation) (*pb.CheckPtInfo, error)
|
||||
VerifyLmdFfgConsistency(ctx context.Context, att *ethpb.Attestation) error
|
||||
}
|
||||
|
||||
// ReceiveAttestationNoPubsub is a function that defines the operations that are performed on
|
||||
@@ -61,7 +64,7 @@ func (s *Service) IsValidAttestation(ctx context.Context, att *ethpb.Attestation
|
||||
return false
|
||||
}
|
||||
|
||||
if err := blocks.VerifyAttestation(ctx, baseState, att); err != nil {
|
||||
if err := blocks.VerifyAttestationSignature(ctx, baseState, att); err != nil {
|
||||
log.WithError(err).Error("Failed to validate attestation")
|
||||
return false
|
||||
}
|
||||
@@ -71,9 +74,34 @@ func (s *Service) IsValidAttestation(ctx context.Context, att *ethpb.Attestation
|
||||
|
||||
// AttestationPreState returns the pre state of attestation.
|
||||
func (s *Service) AttestationPreState(ctx context.Context, att *ethpb.Attestation) (*state.BeaconState, error) {
|
||||
ss, err := helpers.StartSlot(att.Data.Target.Epoch)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := helpers.ValidateSlotClock(ss, uint64(s.genesisTime.Unix())); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s.getAttPreState(ctx, att.Data.Target)
|
||||
}
|
||||
|
||||
// AttestationCheckPtInfo returns the check point info of attestation that can be used to verify the attestation
|
||||
// contents and signatures.
|
||||
func (s *Service) AttestationCheckPtInfo(ctx context.Context, att *ethpb.Attestation) (*pb.CheckPtInfo, error) {
|
||||
ss, err := helpers.StartSlot(att.Data.Target.Epoch)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := helpers.ValidateSlotClock(ss, uint64(s.genesisTime.Unix())); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s.getAttCheckPtInfo(ctx, att.Data.Target, helpers.SlotToEpoch(att.Data.Slot))
|
||||
}
|
||||
|
||||
// VerifyLmdFfgConsistency verifies that attestation's LMD and FFG votes are consistency to each other.
|
||||
func (s *Service) VerifyLmdFfgConsistency(ctx context.Context, a *ethpb.Attestation) error {
|
||||
return s.verifyLMDFFGConsistent(ctx, a.Data.Target.Epoch, a.Data.Target.Root, a.Data.BeaconBlockRoot)
|
||||
}
|
||||
|
||||
// This processes attestations from the attestation pool to account for validator votes and fork choice.
|
||||
func (s *Service) processAttestation(subscribedToStateEvents chan struct{}) {
|
||||
// Wait for state to be initialized.
|
||||
@@ -89,7 +117,7 @@ func (s *Service) processAttestation(subscribedToStateEvents chan struct{}) {
|
||||
case <-s.ctx.Done():
|
||||
return
|
||||
case <-st.C():
|
||||
ctx := context.Background()
|
||||
ctx := s.ctx
|
||||
atts := s.attPool.ForkchoiceAttestations()
|
||||
for _, a := range atts {
|
||||
// Based on the spec, don't process the attestation until the subsequent slot.
|
||||
@@ -131,7 +159,7 @@ func (s *Service) processAttestation(subscribedToStateEvents chan struct{}) {
|
||||
// This verifies the epoch of input checkpoint is within current epoch and previous epoch
|
||||
// with respect to current time. Returns true if it's within, false if it's not.
|
||||
func (s *Service) verifyCheckpointEpoch(c *ethpb.Checkpoint) bool {
|
||||
now := uint64(roughtime.Now().Unix())
|
||||
now := uint64(timeutils.Now().Unix())
|
||||
genesisTime := uint64(s.genesisTime.Unix())
|
||||
currentSlot := (now - genesisTime) / params.BeaconConfig().SecondsPerSlot
|
||||
currentEpoch := helpers.SlotToEpoch(currentSlot)
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
package blockchain
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
testDB "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
func TestVerifyCheckpointEpoch_Ok(t *testing.T) {
|
||||
@@ -17,6 +20,30 @@ func TestVerifyCheckpointEpoch_Ok(t *testing.T) {
|
||||
chainService := setupBeaconChain(t, db, sc)
|
||||
chainService.genesisTime = time.Now()
|
||||
|
||||
assert.Equal(t, true, chainService.verifyCheckpointEpoch(ðpb.Checkpoint{}))
|
||||
assert.Equal(t, true, chainService.verifyCheckpointEpoch(ðpb.Checkpoint{Root: make([]byte, 32)}))
|
||||
assert.Equal(t, false, chainService.verifyCheckpointEpoch(ðpb.Checkpoint{Epoch: 1}))
|
||||
}
|
||||
|
||||
func TestAttestationPreState_FarFutureSlot(t *testing.T) {
|
||||
helpers.ClearCache()
|
||||
db, sc := testDB.SetupDB(t)
|
||||
|
||||
chainService := setupBeaconChain(t, db, sc)
|
||||
chainService.genesisTime = time.Now()
|
||||
|
||||
e := helpers.MaxSlotBuffer/params.BeaconConfig().SlotsPerEpoch + 1
|
||||
_, err := chainService.AttestationCheckPtInfo(context.Background(), ðpb.Attestation{Data: ðpb.AttestationData{Target: ðpb.Checkpoint{Epoch: e}}})
|
||||
require.ErrorContains(t, "exceeds max allowed value relative to the local clock", err)
|
||||
}
|
||||
|
||||
func TestAttestationCheckPtInfo_FarFutureSlot(t *testing.T) {
|
||||
helpers.ClearCache()
|
||||
db, sc := testDB.SetupDB(t)
|
||||
|
||||
chainService := setupBeaconChain(t, db, sc)
|
||||
chainService.genesisTime = time.Now()
|
||||
|
||||
e := helpers.MaxSlotBuffer/params.BeaconConfig().SlotsPerEpoch + 1
|
||||
_, err := chainService.AttestationPreState(context.Background(), ðpb.Attestation{Data: ðpb.AttestationData{Target: ðpb.Checkpoint{Epoch: e}}})
|
||||
require.ErrorContains(t, "exceeds max allowed value relative to the local clock", err)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package blockchain
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
@@ -39,6 +38,11 @@ func (s *Service) ReceiveBlock(ctx context.Context, block *ethpb.SignedBeaconBlo
|
||||
return err
|
||||
}
|
||||
|
||||
// Update and save head block after fork choice.
|
||||
if err := s.updateHead(ctx, s.getJustifiedBalances()); err != nil {
|
||||
log.WithError(err).Warn("Could not update head")
|
||||
}
|
||||
|
||||
// Send notification of the processed block to the state feed.
|
||||
s.stateNotifier.StateFeed().Send(&feed.Event{
|
||||
Type: statefeed.BlockProcessed,
|
||||
@@ -54,13 +58,8 @@ func (s *Service) ReceiveBlock(ctx context.Context, block *ethpb.SignedBeaconBlo
|
||||
return err
|
||||
}
|
||||
|
||||
// Update and save head block after fork choice.
|
||||
if err := s.updateHead(ctx, s.getJustifiedBalances()); err != nil {
|
||||
return errors.Wrap(err, "could not update head")
|
||||
}
|
||||
|
||||
// Reports on block and fork choice metrics.
|
||||
reportSlotMetrics(blockCopy.Block.Slot, s.headSlot(), s.CurrentSlot(), s.finalizedCheckpt)
|
||||
reportSlotMetrics(blockCopy.Block.Slot, s.HeadSlot(), s.CurrentSlot(), s.finalizedCheckpt)
|
||||
|
||||
// Log block sync status.
|
||||
logBlockSyncStatus(blockCopy.Block, blockRoot, s.finalizedCheckpt)
|
||||
@@ -85,13 +84,6 @@ func (s *Service) ReceiveBlockInitialSync(ctx context.Context, block *ethpb.Sign
|
||||
return err
|
||||
}
|
||||
|
||||
// Save the latest block as head in cache.
|
||||
if err := s.saveHeadNoDB(ctx, blockCopy, blockRoot); err != nil {
|
||||
err := errors.Wrap(err, "could not save head")
|
||||
traceutil.AnnotateError(span, err)
|
||||
return err
|
||||
}
|
||||
|
||||
// Send notification of the processed block to the state feed.
|
||||
s.stateNotifier.StateFeed().Send(&feed.Event{
|
||||
Type: statefeed.BlockProcessed,
|
||||
@@ -103,7 +95,7 @@ func (s *Service) ReceiveBlockInitialSync(ctx context.Context, block *ethpb.Sign
|
||||
})
|
||||
|
||||
// Reports on blockCopy and fork choice metrics.
|
||||
reportSlotMetrics(blockCopy.Block.Slot, s.headSlot(), s.CurrentSlot(), s.finalizedCheckpt)
|
||||
reportSlotMetrics(blockCopy.Block.Slot, s.HeadSlot(), s.CurrentSlot(), s.finalizedCheckpt)
|
||||
|
||||
// Log state transition data.
|
||||
log.WithFields(logrus.Fields{
|
||||
@@ -123,9 +115,9 @@ func (s *Service) ReceiveBlockBatch(ctx context.Context, blocks []*ethpb.SignedB
|
||||
defer span.End()
|
||||
|
||||
// Apply state transition on the incoming newly received blockCopy without verifying its BLS contents.
|
||||
postState, fCheckpoints, jCheckpoints, err := s.onBlockBatch(ctx, blocks, blkRoots)
|
||||
fCheckpoints, jCheckpoints, err := s.onBlockBatch(ctx, blocks, blkRoots)
|
||||
if err != nil {
|
||||
err := errors.Wrap(err, "could not process block")
|
||||
err := errors.Wrap(err, "could not process block in batch")
|
||||
traceutil.AnnotateError(span, err)
|
||||
return err
|
||||
}
|
||||
@@ -147,29 +139,17 @@ func (s *Service) ReceiveBlockBatch(ctx context.Context, blocks []*ethpb.SignedB
|
||||
})
|
||||
|
||||
// Reports on blockCopy and fork choice metrics.
|
||||
reportSlotMetrics(blockCopy.Block.Slot, s.headSlot(), s.CurrentSlot(), s.finalizedCheckpt)
|
||||
}
|
||||
lastBlk := blocks[len(blocks)-1]
|
||||
lastRoot := blkRoots[len(blkRoots)-1]
|
||||
|
||||
if err := s.stateGen.SaveState(ctx, lastRoot, postState); err != nil {
|
||||
return errors.Wrap(err, "could not save state")
|
||||
reportSlotMetrics(blockCopy.Block.Slot, s.HeadSlot(), s.CurrentSlot(), s.finalizedCheckpt)
|
||||
}
|
||||
|
||||
cachedHeadRoot, err := s.HeadRoot(ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get head root from cache")
|
||||
if err := s.VerifyWeakSubjectivityRoot(s.ctx); err != nil {
|
||||
// log.Fatalf will prevent defer from being called
|
||||
span.End()
|
||||
// Exit run time if the node failed to verify weak subjectivity checkpoint.
|
||||
log.Fatalf("Could not verify weak subjectivity checkpoint: %v", err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(lastRoot[:], cachedHeadRoot) {
|
||||
if err := s.saveHeadNoDB(ctx, lastBlk, lastRoot); err != nil {
|
||||
err := errors.Wrap(err, "could not save head")
|
||||
traceutil.AnnotateError(span, err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return s.handleEpochBoundary(postState)
|
||||
return nil
|
||||
}
|
||||
|
||||
// HasInitSyncBlock returns true if the block of the input root exists in initial sync blocks cache.
|
||||
|
||||
@@ -2,6 +2,7 @@ package blockchain
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
@@ -11,7 +12,6 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/operations/attestations"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/operations/voluntaryexits"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stategen"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
@@ -36,10 +36,10 @@ func TestService_ReceiveBlock(t *testing.T) {
|
||||
block *ethpb.SignedBeaconBlock
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantErr bool
|
||||
check func(*testing.T, *Service)
|
||||
name string
|
||||
args args
|
||||
wantedErr string
|
||||
check func(*testing.T, *Service)
|
||||
}{
|
||||
{
|
||||
name: "applies block with state transition",
|
||||
@@ -138,28 +138,73 @@ func TestService_ReceiveBlock(t *testing.T) {
|
||||
require.NoError(t, s.saveGenesisData(ctx, genesis))
|
||||
gBlk, err := s.beaconDB.GenesisBlock(ctx)
|
||||
require.NoError(t, err)
|
||||
gRoot, err := stateutil.BlockRoot(gBlk.Block)
|
||||
s.finalizedCheckpt = ðpb.Checkpoint{Root: gRoot[:]}
|
||||
root, err := stateutil.BlockRoot(tt.args.block.Block)
|
||||
gRoot, err := gBlk.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
if err := s.ReceiveBlock(ctx, tt.args.block, root); (err != nil) != tt.wantErr {
|
||||
t.Errorf("ReceiveBlock() error = %v, wantErr %v", err, tt.wantErr)
|
||||
s.finalizedCheckpt = ðpb.Checkpoint{Root: gRoot[:]}
|
||||
root, err := tt.args.block.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
err = s.ReceiveBlock(ctx, tt.args.block, root)
|
||||
if tt.wantedErr != "" {
|
||||
assert.ErrorContains(t, tt.wantedErr, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
tt.check(t, s)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestService_ReceiveBlockUpdateHead(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
genesis, keys := testutil.DeterministicGenesisState(t, 64)
|
||||
b, err := testutil.GenerateFullBlock(genesis, keys, testutil.DefaultBlockGenConfig(), 1)
|
||||
assert.NoError(t, err)
|
||||
db, stateSummaryCache := testDB.SetupDB(t)
|
||||
genesisBlockRoot := bytesutil.ToBytes32(nil)
|
||||
require.NoError(t, db.SaveState(ctx, genesis, genesisBlockRoot))
|
||||
cfg := &Config{
|
||||
BeaconDB: db,
|
||||
ForkChoiceStore: protoarray.New(
|
||||
0, // justifiedEpoch
|
||||
0, // finalizedEpoch
|
||||
genesisBlockRoot,
|
||||
),
|
||||
AttPool: attestations.NewPool(),
|
||||
ExitPool: voluntaryexits.NewPool(),
|
||||
StateNotifier: &blockchainTesting.MockStateNotifier{RecordEvents: true},
|
||||
StateGen: stategen.New(db, stateSummaryCache),
|
||||
}
|
||||
s, err := NewService(ctx, cfg)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, s.saveGenesisData(ctx, genesis))
|
||||
gBlk, err := s.beaconDB.GenesisBlock(ctx)
|
||||
require.NoError(t, err)
|
||||
gRoot, err := gBlk.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
s.finalizedCheckpt = ðpb.Checkpoint{Root: gRoot[:]}
|
||||
root, err := b.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
wg := sync.WaitGroup{}
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
require.NoError(t, s.ReceiveBlock(ctx, b, root))
|
||||
wg.Done()
|
||||
}()
|
||||
wg.Wait()
|
||||
if recvd := len(s.stateNotifier.(*blockchainTesting.MockStateNotifier).ReceivedEvents()); recvd < 1 {
|
||||
t.Errorf("Received %d state notifications, expected at least 1", recvd)
|
||||
}
|
||||
// Verify fork choice has processed the block. (Genesis block and the new block)
|
||||
assert.Equal(t, 2, len(s.forkChoiceStore.Nodes()))
|
||||
}
|
||||
|
||||
func TestService_ReceiveBlockInitialSync(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
genesis, keys := testutil.DeterministicGenesisState(t, 64)
|
||||
genFullBlock := func(t *testing.T, conf *testutil.BlockGenConfig, slot uint64) *ethpb.SignedBeaconBlock {
|
||||
blk, err := testutil.GenerateFullBlock(genesis, keys, conf, slot)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
return blk
|
||||
}
|
||||
|
||||
@@ -167,10 +212,10 @@ func TestService_ReceiveBlockInitialSync(t *testing.T) {
|
||||
block *ethpb.SignedBeaconBlock
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantErr bool
|
||||
check func(*testing.T, *Service)
|
||||
name string
|
||||
args args
|
||||
wantedErr string
|
||||
check func(*testing.T, *Service)
|
||||
}{
|
||||
{
|
||||
name: "applies block with state transition",
|
||||
@@ -217,14 +262,17 @@ func TestService_ReceiveBlockInitialSync(t *testing.T) {
|
||||
gBlk, err := s.beaconDB.GenesisBlock(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
gRoot, err := stateutil.BlockRoot(gBlk.Block)
|
||||
gRoot, err := gBlk.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
s.finalizedCheckpt = ðpb.Checkpoint{Root: gRoot[:]}
|
||||
root, err := stateutil.BlockRoot(tt.args.block.Block)
|
||||
root, err := tt.args.block.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
if err := s.ReceiveBlockInitialSync(ctx, tt.args.block, root); (err != nil) != tt.wantErr {
|
||||
t.Errorf("ReceiveBlockInitialSync() error = %v, wantErr %v", err, tt.wantErr)
|
||||
err = s.ReceiveBlockInitialSync(ctx, tt.args.block, root)
|
||||
if tt.wantedErr != "" {
|
||||
assert.ErrorContains(t, tt.wantedErr, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
tt.check(t, s)
|
||||
}
|
||||
})
|
||||
@@ -237,9 +285,7 @@ func TestService_ReceiveBlockBatch(t *testing.T) {
|
||||
genesis, keys := testutil.DeterministicGenesisState(t, 64)
|
||||
genFullBlock := func(t *testing.T, conf *testutil.BlockGenConfig, slot uint64) *ethpb.SignedBeaconBlock {
|
||||
blk, err := testutil.GenerateFullBlock(genesis, keys, conf, slot)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
return blk
|
||||
}
|
||||
|
||||
@@ -247,10 +293,10 @@ func TestService_ReceiveBlockBatch(t *testing.T) {
|
||||
block *ethpb.SignedBeaconBlock
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantErr bool
|
||||
check func(*testing.T, *Service)
|
||||
name string
|
||||
args args
|
||||
wantedErr string
|
||||
check func(*testing.T, *Service)
|
||||
}{
|
||||
{
|
||||
name: "applies block with state transition",
|
||||
@@ -278,8 +324,8 @@ func TestService_ReceiveBlockBatch(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
db, stateSummaryCache := testDB.SetupDB(t)
|
||||
genesisBlockRoot := bytesutil.ToBytes32(nil)
|
||||
|
||||
genesisBlockRoot, err := genesis.HashTreeRoot(ctx)
|
||||
require.NoError(t, err)
|
||||
cfg := &Config{
|
||||
BeaconDB: db,
|
||||
ForkChoiceStore: protoarray.New(
|
||||
@@ -297,15 +343,18 @@ func TestService_ReceiveBlockBatch(t *testing.T) {
|
||||
gBlk, err := s.beaconDB.GenesisBlock(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
gRoot, err := stateutil.BlockRoot(gBlk.Block)
|
||||
gRoot, err := gBlk.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
s.finalizedCheckpt = ðpb.Checkpoint{Root: gRoot[:]}
|
||||
root, err := stateutil.BlockRoot(tt.args.block.Block)
|
||||
root, err := tt.args.block.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
blks := []*ethpb.SignedBeaconBlock{tt.args.block}
|
||||
roots := [][32]byte{root}
|
||||
if err := s.ReceiveBlockBatch(ctx, blks, roots); (err != nil) != tt.wantErr {
|
||||
t.Errorf("ReceiveBlockBatch() error = %v, wantErr %v", err, tt.wantErr)
|
||||
err = s.ReceiveBlockBatch(ctx, blks, roots)
|
||||
if tt.wantedErr != "" {
|
||||
assert.ErrorContains(t, tt.wantedErr, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
tt.check(t, s)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -30,7 +30,6 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/powchain"
|
||||
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stategen"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
@@ -63,10 +62,8 @@ type Service struct {
|
||||
finalizedCheckpt *ethpb.Checkpoint
|
||||
prevFinalizedCheckpt *ethpb.Checkpoint
|
||||
nextEpochBoundarySlot uint64
|
||||
voteLock sync.RWMutex
|
||||
initSyncState map[[32]byte]*stateTrie.BeaconState
|
||||
boundaryRoots [][32]byte
|
||||
initSyncStateLock sync.RWMutex
|
||||
checkpointState *cache.CheckpointStateCache
|
||||
checkpointStateLock sync.Mutex
|
||||
stateGen *stategen.State
|
||||
@@ -77,6 +74,10 @@ type Service struct {
|
||||
recentCanonicalBlocksLock sync.RWMutex
|
||||
justifiedBalances []uint64
|
||||
justifiedBalancesLock sync.RWMutex
|
||||
checkPtInfoCache *checkPtInfoCache
|
||||
wsEpoch uint64
|
||||
wsRoot []byte
|
||||
wsVerified bool
|
||||
}
|
||||
|
||||
// Config options for the service.
|
||||
@@ -94,6 +95,8 @@ type Config struct {
|
||||
ForkChoiceStore f.ForkChoicer
|
||||
OpsService *attestations.Service
|
||||
StateGen *stategen.State
|
||||
WspBlockRoot []byte
|
||||
WspEpoch uint64
|
||||
}
|
||||
|
||||
// NewService instantiates a new block service instance that will
|
||||
@@ -121,13 +124,15 @@ func NewService(ctx context.Context, cfg *Config) (*Service, error) {
|
||||
initSyncBlocks: make(map[[32]byte]*ethpb.SignedBeaconBlock),
|
||||
recentCanonicalBlocks: make(map[[32]byte]bool),
|
||||
justifiedBalances: make([]uint64, 0),
|
||||
checkPtInfoCache: newCheckPointInfoCache(),
|
||||
wsEpoch: cfg.WspEpoch,
|
||||
wsRoot: cfg.WspBlockRoot,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Start a blockchain service's main event loop.
|
||||
func (s *Service) Start() {
|
||||
ctx := context.TODO()
|
||||
beaconState, err := s.beaconDB.HeadState(ctx)
|
||||
beaconState, err := s.beaconDB.HeadState(s.ctx)
|
||||
if err != nil {
|
||||
log.Fatalf("Could not fetch beacon state: %v", err)
|
||||
}
|
||||
@@ -135,13 +140,29 @@ func (s *Service) Start() {
|
||||
// For running initial sync with state cache, in an event of restart, we use
|
||||
// last finalized check point as start point to sync instead of head
|
||||
// state. This is because we no longer save state every slot during sync.
|
||||
cp, err := s.beaconDB.FinalizedCheckpoint(ctx)
|
||||
cp, err := s.beaconDB.FinalizedCheckpoint(s.ctx)
|
||||
if err != nil {
|
||||
log.Fatalf("Could not fetch finalized cp: %v", err)
|
||||
}
|
||||
|
||||
if beaconState == nil {
|
||||
beaconState, err = s.stateGen.StateByRoot(ctx, bytesutil.ToBytes32(cp.Root))
|
||||
r := bytesutil.ToBytes32(cp.Root)
|
||||
// Before the first finalized epoch, in the current epoch,
|
||||
// the finalized root is defined as zero hashes instead of genesis root hash.
|
||||
// We want to use genesis root to retrieve for state.
|
||||
if r == params.BeaconConfig().ZeroHash {
|
||||
genesisBlock, err := s.beaconDB.GenesisBlock(s.ctx)
|
||||
if err != nil {
|
||||
log.Fatalf("Could not fetch finalized cp: %v", err)
|
||||
}
|
||||
if genesisBlock != nil {
|
||||
r, err = genesisBlock.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
log.Fatalf("Could not tree hash genesis block: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
beaconState, err = s.stateGen.StateByRoot(s.ctx, r)
|
||||
if err != nil {
|
||||
log.Fatalf("Could not fetch beacon state by root: %v", err)
|
||||
}
|
||||
@@ -155,29 +176,29 @@ func (s *Service) Start() {
|
||||
log.Info("Blockchain data already exists in DB, initializing...")
|
||||
s.genesisTime = time.Unix(int64(beaconState.GenesisTime()), 0)
|
||||
s.opsService.SetGenesisTime(beaconState.GenesisTime())
|
||||
if err := s.initializeChainInfo(ctx); err != nil {
|
||||
if err := s.initializeChainInfo(s.ctx); err != nil {
|
||||
log.Fatalf("Could not set up chain info: %v", err)
|
||||
}
|
||||
|
||||
// We start a counter to genesis, if needed.
|
||||
gState, err := s.beaconDB.GenesisState(ctx)
|
||||
gState, err := s.beaconDB.GenesisState(s.ctx)
|
||||
if err != nil {
|
||||
log.Fatalf("Could not retrieve genesis state: %v", err)
|
||||
}
|
||||
go slotutil.CountdownToGenesis(ctx, s.genesisTime, uint64(gState.NumValidators()))
|
||||
go slotutil.CountdownToGenesis(s.ctx, s.genesisTime, uint64(gState.NumValidators()))
|
||||
|
||||
justifiedCheckpoint, err := s.beaconDB.JustifiedCheckpoint(ctx)
|
||||
justifiedCheckpoint, err := s.beaconDB.JustifiedCheckpoint(s.ctx)
|
||||
if err != nil {
|
||||
log.Fatalf("Could not get justified checkpoint: %v", err)
|
||||
}
|
||||
finalizedCheckpoint, err := s.beaconDB.FinalizedCheckpoint(ctx)
|
||||
finalizedCheckpoint, err := s.beaconDB.FinalizedCheckpoint(s.ctx)
|
||||
if err != nil {
|
||||
log.Fatalf("Could not get finalized checkpoint: %v", err)
|
||||
}
|
||||
|
||||
// Resume fork choice.
|
||||
s.justifiedCheckpt = stateTrie.CopyCheckpoint(justifiedCheckpoint)
|
||||
if err := s.cacheJustifiedStateBalances(ctx, bytesutil.ToBytes32(s.justifiedCheckpt.Root)); err != nil {
|
||||
if err := s.cacheJustifiedStateBalances(s.ctx, s.ensureRootNotZeros(bytesutil.ToBytes32(s.justifiedCheckpt.Root))); err != nil {
|
||||
log.Fatalf("Could not cache justified state balances: %v", err)
|
||||
}
|
||||
s.prevJustifiedCheckpt = stateTrie.CopyCheckpoint(justifiedCheckpoint)
|
||||
@@ -186,6 +207,11 @@ func (s *Service) Start() {
|
||||
s.prevFinalizedCheckpt = stateTrie.CopyCheckpoint(finalizedCheckpoint)
|
||||
s.resumeForkChoice(justifiedCheckpoint, finalizedCheckpoint)
|
||||
|
||||
if err := s.VerifyWeakSubjectivityRoot(s.ctx); err != nil {
|
||||
// Exit run time if the node failed to verify weak subjectivity checkpoint.
|
||||
log.Fatalf("Could not verify weak subjectivity checkpoint: %v", err)
|
||||
}
|
||||
|
||||
s.stateNotifier.StateFeed().Send(&feed.Event{
|
||||
Type: statefeed.Initialized,
|
||||
Data: &statefeed.InitializedData{
|
||||
@@ -214,7 +240,7 @@ func (s *Service) Start() {
|
||||
return
|
||||
}
|
||||
log.WithField("starttime", data.StartTime).Debug("Received chain start event")
|
||||
s.processChainStartTime(ctx, data.StartTime)
|
||||
s.processChainStartTime(s.ctx, data.StartTime)
|
||||
return
|
||||
}
|
||||
case <-s.ctx.Done():
|
||||
@@ -261,7 +287,7 @@ func (s *Service) initializeBeaconChain(
|
||||
genesisTime time.Time,
|
||||
preGenesisState *stateTrie.BeaconState,
|
||||
eth1data *ethpb.Eth1Data) (*stateTrie.BeaconState, error) {
|
||||
_, span := trace.StartSpan(context.Background(), "beacon-chain.Service.initializeBeaconChain")
|
||||
ctx, span := trace.StartSpan(ctx, "beacon-chain.Service.initializeBeaconChain")
|
||||
defer span.End()
|
||||
s.genesisTime = genesisTime
|
||||
unixTime := uint64(genesisTime.Unix())
|
||||
@@ -296,7 +322,15 @@ func (s *Service) initializeBeaconChain(
|
||||
// Stop the blockchain service's main event loop and associated goroutines.
|
||||
func (s *Service) Stop() error {
|
||||
defer s.cancel()
|
||||
return nil
|
||||
|
||||
if s.stateGen != nil && s.head != nil && s.head.state != nil {
|
||||
if err := s.stateGen.ForceCheckpoint(s.ctx, s.head.state.FinalizedCheckpoint().Root); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Save initial sync cached blocks to the DB before stop.
|
||||
return s.beaconDB.SaveBlocks(s.ctx, s.getInitSyncBlocks())
|
||||
}
|
||||
|
||||
// Status always returns nil unless there is an error condition that causes
|
||||
@@ -321,7 +355,7 @@ func (s *Service) saveGenesisData(ctx context.Context, genesisState *stateTrie.B
|
||||
return err
|
||||
}
|
||||
genesisBlk := blocks.NewGenesisBlock(stateRoot[:])
|
||||
genesisBlkRoot, err := stateutil.BlockRoot(genesisBlk.Block)
|
||||
genesisBlkRoot, err := genesisBlk.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get genesis block root")
|
||||
}
|
||||
@@ -385,7 +419,7 @@ func (s *Service) initializeChainInfo(ctx context.Context) error {
|
||||
if genesisBlock == nil {
|
||||
return errors.New("no genesis block in db")
|
||||
}
|
||||
genesisBlkRoot, err := stateutil.BlockRoot(genesisBlock.Block)
|
||||
genesisBlkRoot, err := genesisBlock.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get signing root of genesis block")
|
||||
}
|
||||
@@ -396,7 +430,7 @@ func (s *Service) initializeChainInfo(ctx context.Context) error {
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not retrieve head block")
|
||||
}
|
||||
headRoot, err := stateutil.BlockRoot(headBlock.Block)
|
||||
headRoot, err := headBlock.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not hash head block")
|
||||
}
|
||||
@@ -417,17 +451,13 @@ func (s *Service) initializeChainInfo(ctx context.Context) error {
|
||||
// would be the genesis state and block.
|
||||
return errors.New("no finalized epoch in the database")
|
||||
}
|
||||
finalizedRoot := bytesutil.ToBytes32(finalized.Root)
|
||||
finalizedRoot := s.ensureRootNotZeros(bytesutil.ToBytes32(finalized.Root))
|
||||
var finalizedState *stateTrie.BeaconState
|
||||
|
||||
finalizedState, err = s.stateGen.Resume(ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get finalized state from db")
|
||||
}
|
||||
finalizedRoot = s.beaconDB.LastArchivedIndexRoot(ctx)
|
||||
if finalizedRoot == params.BeaconConfig().ZeroHash {
|
||||
finalizedRoot = bytesutil.ToBytes32(finalized.Root)
|
||||
}
|
||||
|
||||
finalizedBlock, err := s.beaconDB.Block(ctx, finalizedRoot)
|
||||
if err != nil {
|
||||
|
||||
@@ -11,12 +11,9 @@ import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/go-ssz"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/cache"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/cache/depositcache"
|
||||
b "github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/feed"
|
||||
statefeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/db"
|
||||
@@ -27,7 +24,6 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/powchain"
|
||||
beaconstate "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stategen"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
|
||||
protodb "github.com/prysmaticlabs/prysm/proto/beacon/db"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
@@ -71,7 +67,7 @@ func (mb *mockBroadcaster) BroadcastAttestation(_ context.Context, _ uint64, _ *
|
||||
return nil
|
||||
}
|
||||
|
||||
var _ = p2p.Broadcaster(&mockBroadcaster{})
|
||||
var _ p2p.Broadcaster = (*mockBroadcaster)(nil)
|
||||
|
||||
func setupBeaconChain(t *testing.T, beaconDB db.Database, sc *cache.StateSummaryCache) *Service {
|
||||
endpoint := "http://127.0.0.1"
|
||||
@@ -105,7 +101,7 @@ func setupBeaconChain(t *testing.T, beaconDB db.Database, sc *cache.StateSummary
|
||||
opsService, err := attestations.NewService(ctx, &attestations.Config{Pool: attestations.NewPool()})
|
||||
require.NoError(t, err)
|
||||
|
||||
depositCache, err := depositcache.NewDepositCache()
|
||||
depositCache, err := depositcache.New()
|
||||
require.NoError(t, err)
|
||||
|
||||
cfg := &Config{
|
||||
@@ -121,6 +117,9 @@ func setupBeaconChain(t *testing.T, beaconDB db.Database, sc *cache.StateSummary
|
||||
OpsService: opsService,
|
||||
}
|
||||
|
||||
// Safe a state in stategen to purposes of testing a service stop / shutdown.
|
||||
require.NoError(t, cfg.StateGen.SaveState(ctx, bytesutil.ToBytes32(bState.FinalizedCheckpoint().Root), bState))
|
||||
|
||||
chainService, err := NewService(ctx, cfg)
|
||||
require.NoError(t, err, "Unable to setup chain service")
|
||||
chainService.genesisTime = time.Unix(1, 0) // non-zero time
|
||||
@@ -128,54 +127,6 @@ func setupBeaconChain(t *testing.T, beaconDB db.Database, sc *cache.StateSummary
|
||||
return chainService
|
||||
}
|
||||
|
||||
func TestChainStartStop_Uninitialized(t *testing.T) {
|
||||
hook := logTest.NewGlobal()
|
||||
db, sc := testDB.SetupDB(t)
|
||||
chainService := setupBeaconChain(t, db, sc)
|
||||
|
||||
// Listen for state events.
|
||||
stateSubChannel := make(chan *feed.Event, 1)
|
||||
stateSub := chainService.stateNotifier.StateFeed().Subscribe(stateSubChannel)
|
||||
|
||||
// Test the chain start state notifier.
|
||||
genesisTime := time.Unix(1, 0)
|
||||
chainService.Start()
|
||||
event := &feed.Event{
|
||||
Type: statefeed.ChainStarted,
|
||||
Data: &statefeed.ChainStartedData{
|
||||
StartTime: genesisTime,
|
||||
},
|
||||
}
|
||||
// Send in a loop to ensure it is delivered (busy wait for the service to subscribe to the state feed).
|
||||
for sent := 1; sent == 1; {
|
||||
sent = chainService.stateNotifier.StateFeed().Send(event)
|
||||
if sent == 1 {
|
||||
// Flush our local subscriber.
|
||||
<-stateSubChannel
|
||||
}
|
||||
}
|
||||
|
||||
// Now wait for notification the state is ready.
|
||||
for stateInitialized := false; stateInitialized == false; {
|
||||
recv := <-stateSubChannel
|
||||
if recv.Type == statefeed.Initialized {
|
||||
stateInitialized = true
|
||||
}
|
||||
}
|
||||
stateSub.Unsubscribe()
|
||||
|
||||
beaconState, err := db.HeadState(context.Background())
|
||||
require.NoError(t, err)
|
||||
if beaconState == nil || beaconState.Slot() != 0 {
|
||||
t.Error("Expected canonical state feed to send a state with genesis block")
|
||||
}
|
||||
require.NoError(t, chainService.Stop(), "Unable to stop chain service")
|
||||
// The context should have been canceled.
|
||||
assert.Equal(t, context.Canceled, chainService.ctx.Err(), "Context was not canceled")
|
||||
testutil.AssertLogsContain(t, hook, "Waiting")
|
||||
testutil.AssertLogsContain(t, hook, "Initialized beacon chain genesis state")
|
||||
}
|
||||
|
||||
func TestChainStartStop_Initialized(t *testing.T) {
|
||||
hook := logTest.NewGlobal()
|
||||
ctx := context.Background()
|
||||
@@ -184,7 +135,7 @@ func TestChainStartStop_Initialized(t *testing.T) {
|
||||
chainService := setupBeaconChain(t, db, sc)
|
||||
|
||||
genesisBlk := testutil.NewBeaconBlock()
|
||||
blkRoot, err := stateutil.BlockRoot(genesisBlk.Block)
|
||||
blkRoot, err := genesisBlk.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, db.SaveBlock(ctx, genesisBlk))
|
||||
s := testutil.NewBeaconState()
|
||||
@@ -193,6 +144,7 @@ func TestChainStartStop_Initialized(t *testing.T) {
|
||||
require.NoError(t, db.SaveHeadBlockRoot(ctx, blkRoot))
|
||||
require.NoError(t, db.SaveGenesisBlockRoot(ctx, blkRoot))
|
||||
require.NoError(t, db.SaveJustifiedCheckpoint(ctx, ðpb.Checkpoint{Root: blkRoot[:]}))
|
||||
require.NoError(t, db.SaveFinalizedCheckpoint(ctx, ðpb.Checkpoint{Root: blkRoot[:]}))
|
||||
|
||||
// Test the start function.
|
||||
chainService.Start()
|
||||
@@ -201,7 +153,33 @@ func TestChainStartStop_Initialized(t *testing.T) {
|
||||
|
||||
// The context should have been canceled.
|
||||
assert.Equal(t, context.Canceled, chainService.ctx.Err(), "Context was not canceled")
|
||||
testutil.AssertLogsContain(t, hook, "data already exists")
|
||||
require.LogsContain(t, hook, "data already exists")
|
||||
}
|
||||
|
||||
func TestChainStartStop_GenesisZeroHashes(t *testing.T) {
|
||||
hook := logTest.NewGlobal()
|
||||
ctx := context.Background()
|
||||
db, sc := testDB.SetupDB(t)
|
||||
|
||||
chainService := setupBeaconChain(t, db, sc)
|
||||
|
||||
genesisBlk := testutil.NewBeaconBlock()
|
||||
blkRoot, err := genesisBlk.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, db.SaveBlock(ctx, genesisBlk))
|
||||
s := testutil.NewBeaconState()
|
||||
require.NoError(t, db.SaveState(ctx, s, blkRoot))
|
||||
require.NoError(t, db.SaveGenesisBlockRoot(ctx, blkRoot))
|
||||
require.NoError(t, db.SaveJustifiedCheckpoint(ctx, ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}))
|
||||
|
||||
// Test the start function.
|
||||
chainService.Start()
|
||||
|
||||
require.NoError(t, chainService.Stop(), "Unable to stop chain service")
|
||||
|
||||
// The context should have been canceled.
|
||||
assert.Equal(t, context.Canceled, chainService.ctx.Err(), "Context was not canceled")
|
||||
require.LogsContain(t, hook, "data already exists")
|
||||
}
|
||||
|
||||
func TestChainService_InitializeBeaconChain(t *testing.T) {
|
||||
@@ -224,11 +202,13 @@ func TestChainService_InitializeBeaconChain(t *testing.T) {
|
||||
err = genState.SetEth1Data(ðpb.Eth1Data{
|
||||
DepositRoot: hashTreeRoot[:],
|
||||
DepositCount: uint64(len(deposits)),
|
||||
BlockHash: make([]byte, 32),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
genState, err = b.ProcessPreGenesisDeposits(ctx, genState, deposits)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = bc.initializeBeaconChain(ctx, time.Unix(0, 0), genState, ðpb.Eth1Data{DepositRoot: hashTreeRoot[:]})
|
||||
_, err = bc.initializeBeaconChain(ctx, time.Unix(0, 0), genState, ðpb.Eth1Data{DepositRoot: hashTreeRoot[:], BlockHash: make([]byte, 32)})
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = bc.HeadState(ctx)
|
||||
@@ -238,17 +218,46 @@ func TestChainService_InitializeBeaconChain(t *testing.T) {
|
||||
if headBlk == nil {
|
||||
t.Error("Head state can't be nil after initialize beacon chain")
|
||||
}
|
||||
if bc.headRoot() == params.BeaconConfig().ZeroHash {
|
||||
r, err := bc.HeadRoot(ctx)
|
||||
require.NoError(t, err)
|
||||
if bytesutil.ToBytes32(r) == params.BeaconConfig().ZeroHash {
|
||||
t.Error("Canonical root for slot 0 can't be zeros after initialize beacon chain")
|
||||
}
|
||||
}
|
||||
|
||||
func TestChainService_CorrectGenesisRoots(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
db, sc := testDB.SetupDB(t)
|
||||
|
||||
chainService := setupBeaconChain(t, db, sc)
|
||||
|
||||
genesisBlk := testutil.NewBeaconBlock()
|
||||
blkRoot, err := genesisBlk.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, db.SaveBlock(ctx, genesisBlk))
|
||||
s := testutil.NewBeaconState()
|
||||
require.NoError(t, s.SetSlot(0))
|
||||
require.NoError(t, db.SaveState(ctx, s, blkRoot))
|
||||
require.NoError(t, db.SaveHeadBlockRoot(ctx, blkRoot))
|
||||
require.NoError(t, db.SaveGenesisBlockRoot(ctx, blkRoot))
|
||||
require.NoError(t, db.SaveFinalizedCheckpoint(ctx, ðpb.Checkpoint{Root: blkRoot[:]}))
|
||||
|
||||
// Test the start function.
|
||||
chainService.Start()
|
||||
|
||||
require.DeepEqual(t, blkRoot[:], chainService.finalizedCheckpt.Root, "Finalize Checkpoint root is incorrect")
|
||||
require.DeepEqual(t, params.BeaconConfig().ZeroHash[:], chainService.justifiedCheckpt.Root, "Justified Checkpoint root is incorrect")
|
||||
|
||||
require.NoError(t, chainService.Stop(), "Unable to stop chain service")
|
||||
|
||||
}
|
||||
|
||||
func TestChainService_InitializeChainInfo(t *testing.T) {
|
||||
db, sc := testDB.SetupDB(t)
|
||||
ctx := context.Background()
|
||||
|
||||
genesis := testutil.NewBeaconBlock()
|
||||
genesisRoot, err := stateutil.BlockRoot(genesis.Block)
|
||||
genesisRoot, err := genesis.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, db.SaveGenesisBlockRoot(ctx, genesisRoot))
|
||||
require.NoError(t, db.SaveBlock(ctx, genesis))
|
||||
@@ -260,17 +269,12 @@ func TestChainService_InitializeChainInfo(t *testing.T) {
|
||||
headState := testutil.NewBeaconState()
|
||||
require.NoError(t, headState.SetSlot(finalizedSlot))
|
||||
require.NoError(t, headState.SetGenesisValidatorRoot(params.BeaconConfig().ZeroHash[:]))
|
||||
headRoot, err := stateutil.BlockRoot(headBlock.Block)
|
||||
headRoot, err := headBlock.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, db.SaveState(ctx, headState, headRoot))
|
||||
require.NoError(t, db.SaveState(ctx, headState, genesisRoot))
|
||||
require.NoError(t, db.SaveBlock(ctx, headBlock))
|
||||
if err := db.SaveFinalizedCheckpoint(ctx, ðpb.Checkpoint{
|
||||
Epoch: helpers.SlotToEpoch(finalizedSlot),
|
||||
Root: headRoot[:],
|
||||
}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, db.SaveFinalizedCheckpoint(ctx, ðpb.Checkpoint{Epoch: helpers.SlotToEpoch(finalizedSlot), Root: headRoot[:]}))
|
||||
c := &Service{beaconDB: db, stateGen: stategen.New(db, sc)}
|
||||
require.NoError(t, c.initializeChainInfo(ctx))
|
||||
headBlk, err := c.HeadBlock(ctx)
|
||||
@@ -288,6 +292,37 @@ func TestChainService_InitializeChainInfo(t *testing.T) {
|
||||
assert.Equal(t, genesisRoot, c.genesisRoot, "Genesis block root incorrect")
|
||||
}
|
||||
|
||||
func TestChainService_InitializeChainInfo_SetHeadAtGenesis(t *testing.T) {
|
||||
db, sc := testDB.SetupDB(t)
|
||||
ctx := context.Background()
|
||||
|
||||
genesis := testutil.NewBeaconBlock()
|
||||
genesisRoot, err := genesis.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, db.SaveGenesisBlockRoot(ctx, genesisRoot))
|
||||
require.NoError(t, db.SaveBlock(ctx, genesis))
|
||||
|
||||
finalizedSlot := params.BeaconConfig().SlotsPerEpoch*2 + 1
|
||||
headBlock := testutil.NewBeaconBlock()
|
||||
headBlock.Block.Slot = finalizedSlot
|
||||
headBlock.Block.ParentRoot = bytesutil.PadTo(genesisRoot[:], 32)
|
||||
headState := testutil.NewBeaconState()
|
||||
require.NoError(t, headState.SetSlot(finalizedSlot))
|
||||
require.NoError(t, headState.SetGenesisValidatorRoot(params.BeaconConfig().ZeroHash[:]))
|
||||
headRoot, err := headBlock.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, db.SaveState(ctx, headState, headRoot))
|
||||
require.NoError(t, db.SaveState(ctx, headState, genesisRoot))
|
||||
require.NoError(t, db.SaveBlock(ctx, headBlock))
|
||||
c := &Service{beaconDB: db, stateGen: stategen.New(db, sc)}
|
||||
require.NoError(t, c.initializeChainInfo(ctx))
|
||||
s, err := c.HeadState(ctx)
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, headState.InnerStateUnsafe(), s.InnerStateUnsafe(), "Head state incorrect")
|
||||
assert.Equal(t, genesisRoot, c.genesisRoot, "Genesis block root incorrect")
|
||||
assert.DeepEqual(t, genesis, c.head.block)
|
||||
}
|
||||
|
||||
func TestChainService_SaveHeadNoDB(t *testing.T) {
|
||||
db, sc := testDB.SetupDB(t)
|
||||
ctx := context.Background()
|
||||
@@ -295,12 +330,13 @@ func TestChainService_SaveHeadNoDB(t *testing.T) {
|
||||
beaconDB: db,
|
||||
stateGen: stategen.New(db, sc),
|
||||
}
|
||||
b := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Slot: 1}}
|
||||
r, err := ssz.HashTreeRoot(b)
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block.Slot = 1
|
||||
r, err := b.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
newState := testutil.NewBeaconState()
|
||||
require.NoError(t, s.stateGen.SaveState(ctx, r, newState))
|
||||
require.NoError(t, s.saveHeadNoDB(ctx, b, r))
|
||||
require.NoError(t, s.saveHeadNoDB(ctx, b, r, newState))
|
||||
|
||||
newB, err := s.beaconDB.HeadBlock(ctx)
|
||||
require.NoError(t, err)
|
||||
@@ -314,30 +350,45 @@ func TestHasBlock_ForkChoiceAndDB(t *testing.T) {
|
||||
db, _ := testDB.SetupDB(t)
|
||||
s := &Service{
|
||||
forkChoiceStore: protoarray.New(0, 0, [32]byte{}),
|
||||
finalizedCheckpt: ðpb.Checkpoint{},
|
||||
finalizedCheckpt: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
beaconDB: db,
|
||||
}
|
||||
block := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Body: ðpb.BeaconBlockBody{}}}
|
||||
r, err := stateutil.BlockRoot(block.Block)
|
||||
require.NoError(t, err)
|
||||
bs := &pb.BeaconState{FinalizedCheckpoint: ðpb.Checkpoint{}, CurrentJustifiedCheckpoint: ðpb.Checkpoint{}}
|
||||
state, err := beaconstate.InitializeFromProto(bs)
|
||||
block := testutil.NewBeaconBlock()
|
||||
r, err := block.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
state := testutil.NewBeaconState()
|
||||
require.NoError(t, s.insertBlockAndAttestationsToForkChoiceStore(ctx, block.Block, r, state))
|
||||
|
||||
assert.Equal(t, false, s.hasBlock(ctx, [32]byte{}), "Should not have block")
|
||||
assert.Equal(t, true, s.hasBlock(ctx, r), "Should have block")
|
||||
}
|
||||
|
||||
func TestServiceStop_SaveCachedBlocks(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
db, _ := testDB.SetupDB(t)
|
||||
s := &Service{
|
||||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
beaconDB: db,
|
||||
initSyncBlocks: make(map[[32]byte]*ethpb.SignedBeaconBlock),
|
||||
}
|
||||
b := testutil.NewBeaconBlock()
|
||||
r, err := b.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
s.saveInitSyncBlock(r, b)
|
||||
require.NoError(t, s.Stop())
|
||||
require.Equal(t, true, s.beaconDB.HasBlock(ctx, r))
|
||||
}
|
||||
|
||||
func BenchmarkHasBlockDB(b *testing.B) {
|
||||
db, _ := testDB.SetupDB(b)
|
||||
ctx := context.Background()
|
||||
s := &Service{
|
||||
beaconDB: db,
|
||||
}
|
||||
block := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{}}
|
||||
block := testutil.NewBeaconBlock()
|
||||
require.NoError(b, s.beaconDB.SaveBlock(ctx, block))
|
||||
r, err := stateutil.BlockRoot(block.Block)
|
||||
r, err := block.Block.HashTreeRoot()
|
||||
require.NoError(b, err)
|
||||
|
||||
b.ResetTimer()
|
||||
@@ -351,13 +402,13 @@ func BenchmarkHasBlockForkChoiceStore(b *testing.B) {
|
||||
db, _ := testDB.SetupDB(b)
|
||||
s := &Service{
|
||||
forkChoiceStore: protoarray.New(0, 0, [32]byte{}),
|
||||
finalizedCheckpt: ðpb.Checkpoint{},
|
||||
finalizedCheckpt: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
beaconDB: db,
|
||||
}
|
||||
block := ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Body: ðpb.BeaconBlockBody{}}}
|
||||
r, err := stateutil.BlockRoot(block.Block)
|
||||
r, err := block.Block.HashTreeRoot()
|
||||
require.NoError(b, err)
|
||||
bs := &pb.BeaconState{FinalizedCheckpoint: ðpb.Checkpoint{}, CurrentJustifiedCheckpoint: ðpb.Checkpoint{}}
|
||||
bs := &pb.BeaconState{FinalizedCheckpoint: ðpb.Checkpoint{Root: make([]byte, 32)}, CurrentJustifiedCheckpoint: ðpb.Checkpoint{Root: make([]byte, 32)}}
|
||||
state, err := beaconstate.InitializeFromProto(bs)
|
||||
require.NoError(b, err)
|
||||
require.NoError(b, s.insertBlockAndAttestationsToForkChoiceStore(ctx, block.Block, r, state))
|
||||
|
||||
@@ -19,8 +19,8 @@ go_library(
|
||||
"//beacon-chain/db:go_default_library",
|
||||
"//beacon-chain/forkchoice/protoarray:go_default_library",
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//beacon-chain/state/stateutil:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//shared/bytesutil:go_default_library",
|
||||
"//shared/event:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
|
||||
@@ -19,8 +19,8 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/db"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/protoarray"
|
||||
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/event"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/sirupsen/logrus"
|
||||
@@ -152,7 +152,7 @@ func (ms *ChainService) ReceiveBlockInitialSync(ctx context.Context, block *ethp
|
||||
return err
|
||||
}
|
||||
ms.BlocksReceived = append(ms.BlocksReceived, block)
|
||||
signingRoot, err := stateutil.BlockRoot(block.Block)
|
||||
signingRoot, err := block.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -180,7 +180,7 @@ func (ms *ChainService) ReceiveBlockBatch(ctx context.Context, blks []*ethpb.Sig
|
||||
return err
|
||||
}
|
||||
ms.BlocksReceived = append(ms.BlocksReceived, block)
|
||||
signingRoot, err := stateutil.BlockRoot(block.Block)
|
||||
signingRoot, err := block.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -208,7 +208,7 @@ func (ms *ChainService) ReceiveBlock(ctx context.Context, block *ethpb.SignedBea
|
||||
return err
|
||||
}
|
||||
ms.BlocksReceived = append(ms.BlocksReceived, block)
|
||||
signingRoot, err := stateutil.BlockRoot(block.Block)
|
||||
signingRoot, err := block.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -233,8 +233,10 @@ func (ms *ChainService) HeadSlot() uint64 {
|
||||
|
||||
// HeadRoot mocks HeadRoot method in chain service.
|
||||
func (ms *ChainService) HeadRoot(ctx context.Context) ([]byte, error) {
|
||||
return ms.Root, nil
|
||||
|
||||
if len(ms.Root) > 0 {
|
||||
return ms.Root, nil
|
||||
}
|
||||
return make([]byte, 32), nil
|
||||
}
|
||||
|
||||
// HeadBlock mocks HeadBlock method in chain service.
|
||||
@@ -353,3 +355,38 @@ func (ms *ChainService) HeadGenesisValidatorRoot() [32]byte {
|
||||
func (ms *ChainService) VerifyBlkDescendant(ctx context.Context, root [32]byte) error {
|
||||
return ms.VerifyBlkDescendantErr
|
||||
}
|
||||
|
||||
// VerifyLmdFfgConsistency mocks VerifyLmdFfgConsistency and always returns nil.
|
||||
func (ms *ChainService) VerifyLmdFfgConsistency(ctx context.Context, att *ethpb.Attestation) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// AttestationCheckPtInfo mocks AttestationCheckPtInfo and always returns nil.
|
||||
func (ms *ChainService) AttestationCheckPtInfo(ctx context.Context, att *ethpb.Attestation) (*pb.CheckPtInfo, error) {
|
||||
f := ms.State.Fork()
|
||||
g := bytesutil.ToBytes32(ms.State.GenesisValidatorRoot())
|
||||
seed, err := helpers.Seed(ms.State, helpers.SlotToEpoch(att.Data.Slot), params.BeaconConfig().DomainBeaconAttester)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
indices, err := helpers.ActiveValidatorIndices(ms.State, helpers.SlotToEpoch(att.Data.Slot))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
validators := ms.State.ValidatorsReadOnly()
|
||||
pks := make([][]byte, len(validators))
|
||||
for i := 0; i < len(pks); i++ {
|
||||
pk := validators[i].PublicKey()
|
||||
pks[i] = pk[:]
|
||||
}
|
||||
|
||||
info := &pb.CheckPtInfo{
|
||||
Fork: f,
|
||||
GenesisRoot: g[:],
|
||||
Seed: seed[:],
|
||||
ActiveIndices: indices,
|
||||
PubKeys: pks,
|
||||
}
|
||||
|
||||
return info, nil
|
||||
}
|
||||
|
||||
60
beacon-chain/blockchain/weak_subjectivity_checks.go
Normal file
60
beacon-chain/blockchain/weak_subjectivity_checks.go
Normal file
@@ -0,0 +1,60 @@
|
||||
package blockchain
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/db/filters"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
// VerifyWeakSubjectivityRoot verifies the weak subjectivity root in the service struct.
|
||||
// Reference design: https://github.com/ethereum/eth2.0-specs/blob/master/specs/phase0/weak-subjectivity.md#weak-subjectivity-sync-procedure
|
||||
func (s *Service) VerifyWeakSubjectivityRoot(ctx context.Context) error {
|
||||
// TODO(7342): Remove the following to fully use weak subjectivity in production.
|
||||
if len(s.wsRoot) == 0 || s.wsEpoch == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Do nothing if the weak subjectivity has previously been verified,
|
||||
// or weak subjectivity epoch is higher than last finalized epoch.
|
||||
if s.wsVerified {
|
||||
return nil
|
||||
}
|
||||
if s.wsEpoch > s.finalizedCheckpt.Epoch {
|
||||
return nil
|
||||
}
|
||||
|
||||
r := bytesutil.ToBytes32(s.wsRoot)
|
||||
log.Infof("Performing weak subjectivity check for root %#x in epoch %d", r, s.wsEpoch)
|
||||
// Save initial sync cached blocks to DB.
|
||||
if err := s.beaconDB.SaveBlocks(ctx, s.getInitSyncBlocks()); err != nil {
|
||||
return err
|
||||
}
|
||||
// A node should have the weak subjectivity block in the DB.
|
||||
if !s.beaconDB.HasBlock(ctx, r) {
|
||||
return fmt.Errorf("node does not have root in DB: %#x", r)
|
||||
}
|
||||
|
||||
startSlot, err := helpers.StartSlot(s.wsEpoch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// A node should have the weak subjectivity block corresponds to the correct epoch in the DB.
|
||||
filter := filters.NewFilter().SetStartSlot(startSlot).SetEndSlot(startSlot + params.BeaconConfig().SlotsPerEpoch)
|
||||
roots, err := s.beaconDB.BlockRoots(ctx, filter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, root := range roots {
|
||||
if r == root {
|
||||
log.Info("Weak subjectivity check has passed")
|
||||
s.wsVerified = true
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Errorf("node does not have root in db corresponding to epoch: %#x %d", r, s.wsEpoch)
|
||||
}
|
||||
85
beacon-chain/blockchain/weak_subjectivity_checks_test.go
Normal file
85
beacon-chain/blockchain/weak_subjectivity_checks_test.go
Normal file
@@ -0,0 +1,85 @@
|
||||
package blockchain
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
testDB "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
func TestService_VerifyWeakSubjectivityRoot(t *testing.T) {
|
||||
db, _ := testDB.SetupDB(t)
|
||||
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block.Slot = 32
|
||||
require.NoError(t, db.SaveBlock(context.Background(), b))
|
||||
r, err := b.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
tests := []struct {
|
||||
wsVerified bool
|
||||
wantErr bool
|
||||
wsRoot [32]byte
|
||||
wsEpoch uint64
|
||||
finalizedEpoch uint64
|
||||
errString string
|
||||
name string
|
||||
}{
|
||||
{
|
||||
name: "nil root and epoch",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "already verified",
|
||||
wsEpoch: 2,
|
||||
finalizedEpoch: 2,
|
||||
wsVerified: true,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "not yet to verify, ws epoch higher than finalized epoch",
|
||||
wsEpoch: 2,
|
||||
finalizedEpoch: 1,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "can't find the block in DB",
|
||||
wsEpoch: 1,
|
||||
wsRoot: [32]byte{'a'},
|
||||
finalizedEpoch: 3,
|
||||
wantErr: true,
|
||||
errString: "node does not have root in DB",
|
||||
},
|
||||
{
|
||||
name: "can't find the block corresponds to ws epoch in DB",
|
||||
wsEpoch: 2,
|
||||
wsRoot: r, // Root belongs in epoch 1.
|
||||
finalizedEpoch: 3,
|
||||
wantErr: true,
|
||||
errString: "node does not have root in db corresponding to epoch",
|
||||
},
|
||||
{
|
||||
name: "can verify and pass",
|
||||
wsEpoch: 1,
|
||||
wsRoot: r,
|
||||
finalizedEpoch: 3,
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
s := &Service{
|
||||
beaconDB: db,
|
||||
wsRoot: tt.wsRoot[:],
|
||||
wsEpoch: tt.wsEpoch,
|
||||
wsVerified: tt.wsVerified,
|
||||
finalizedCheckpt: ðpb.Checkpoint{Epoch: tt.finalizedEpoch},
|
||||
}
|
||||
if err := s.VerifyWeakSubjectivityRoot(context.Background()); (err != nil) != tt.wantErr {
|
||||
require.ErrorContains(t, tt.errString, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
18
beacon-chain/cache/BUILD.bazel
vendored
18
beacon-chain/cache/BUILD.bazel
vendored
@@ -1,19 +1,31 @@
|
||||
load("@prysm//tools/go:def.bzl", "go_library")
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_test")
|
||||
|
||||
# gazelle:ignore committee_disabled.go
|
||||
# gazelle:ignore proposer_indices_disabled.go
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"attestation_data.go",
|
||||
"checkpoint_state.go",
|
||||
"committee.go",
|
||||
"committees.go",
|
||||
"common.go",
|
||||
"doc.go",
|
||||
"hot_state_cache.go",
|
||||
"skip_slot_cache.go",
|
||||
"state_summary.go",
|
||||
"subnet_ids.go",
|
||||
],
|
||||
"proposer_indices_type.go",
|
||||
] + select({
|
||||
"//fuzz:fuzzing_enabled": [
|
||||
"committee_disabled.go",
|
||||
"proposer_indices_disabled.go"
|
||||
],
|
||||
"//conditions:default": [
|
||||
"committee.go",
|
||||
"proposer_indices.go",
|
||||
],
|
||||
}),
|
||||
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/cache",
|
||||
visibility = [
|
||||
"//beacon-chain:__subpackages__",
|
||||
@@ -49,6 +61,7 @@ go_test(
|
||||
"hot_state_cache_test.go",
|
||||
"skip_slot_cache_test.go",
|
||||
"subnet_ids_test.go",
|
||||
"proposer_indices_test.go"
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
@@ -56,7 +69,6 @@ go_test(
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//shared/bytesutil:go_default_library",
|
||||
"//shared/featureconfig:go_default_library",
|
||||
"//shared/hashutil:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"//shared/testutil/assert:go_default_library",
|
||||
"//shared/testutil/require:go_default_library",
|
||||
|
||||
2
beacon-chain/cache/attestation_data_test.go
vendored
2
beacon-chain/cache/attestation_data_test.go
vendored
@@ -26,7 +26,7 @@ func TestAttestationCache_RoundTrip(t *testing.T) {
|
||||
assert.NoError(t, c.MarkInProgress(req))
|
||||
|
||||
res := ðpb.AttestationData{
|
||||
Target: ðpb.Checkpoint{Epoch: 5},
|
||||
Target: ðpb.Checkpoint{Epoch: 5, Root: make([]byte, 32)},
|
||||
}
|
||||
|
||||
assert.NoError(t, c.Put(ctx, req, res))
|
||||
|
||||
71
beacon-chain/cache/checkpoint_state.go
vendored
71
beacon-chain/cache/checkpoint_state.go
vendored
@@ -4,12 +4,12 @@ import (
|
||||
"errors"
|
||||
"sync"
|
||||
|
||||
lru "github.com/hashicorp/golang-lru"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/shared/hashutil"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -20,11 +20,11 @@ var (
|
||||
// maxCheckpointStateSize defines the max number of entries check point to state cache can contain.
|
||||
// Choosing 10 to account for multiple forks, this allows 5 forks per epoch boundary with 2 epochs
|
||||
// window to accept attestation based on latest spec.
|
||||
maxCheckpointStateSize = uint64(10)
|
||||
maxCheckpointStateSize = 10
|
||||
|
||||
// Metrics.
|
||||
checkpointStateMiss = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "check_point_statecache_miss",
|
||||
Name: "check_point_state_cache_miss",
|
||||
Help: "The number of check point state requests that aren't present in the cache.",
|
||||
})
|
||||
checkpointStateHit = promauto.NewCounter(prometheus.CounterOpts{
|
||||
@@ -33,36 +33,20 @@ var (
|
||||
})
|
||||
)
|
||||
|
||||
// CheckpointState defines the active validator indices per epoch.
|
||||
type CheckpointState struct {
|
||||
Checkpoint *ethpb.Checkpoint
|
||||
State *stateTrie.BeaconState
|
||||
}
|
||||
|
||||
// CheckpointStateCache is a struct with 1 queue for looking up state by checkpoint.
|
||||
type CheckpointStateCache struct {
|
||||
cache *cache.FIFO
|
||||
cache *lru.Cache
|
||||
lock sync.RWMutex
|
||||
}
|
||||
|
||||
// checkpointState takes the checkpoint as the key of the resulting state.
|
||||
func checkpointState(obj interface{}) (string, error) {
|
||||
info, ok := obj.(*CheckpointState)
|
||||
if !ok {
|
||||
return "", ErrNotCheckpointState
|
||||
}
|
||||
|
||||
h, err := hashutil.HashProto(info.Checkpoint)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(h[:]), nil
|
||||
}
|
||||
|
||||
// NewCheckpointStateCache creates a new checkpoint state cache for storing/accessing processed state.
|
||||
func NewCheckpointStateCache() *CheckpointStateCache {
|
||||
cache, err := lru.New(maxCheckpointStateSize)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return &CheckpointStateCache{
|
||||
cache: cache.NewFIFO(checkpointState),
|
||||
cache: cache,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,44 +60,27 @@ func (c *CheckpointStateCache) StateByCheckpoint(cp *ethpb.Checkpoint) (*stateTr
|
||||
return nil, err
|
||||
}
|
||||
|
||||
obj, exists, err := c.cache.GetByKey(string(h[:]))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
item, exists := c.cache.Get(h)
|
||||
|
||||
if exists {
|
||||
if exists && item != nil {
|
||||
checkpointStateHit.Inc()
|
||||
} else {
|
||||
checkpointStateMiss.Inc()
|
||||
return nil, nil
|
||||
// Copy here is unnecessary since the return will only be used to verify attestation signature.
|
||||
return item.(*stateTrie.BeaconState), nil
|
||||
}
|
||||
|
||||
info, ok := obj.(*CheckpointState)
|
||||
if !ok {
|
||||
return nil, ErrNotCheckpointState
|
||||
}
|
||||
|
||||
// Copy here is unnecessary since the return will only be used to verify attestation signature.
|
||||
return info.State, nil
|
||||
checkpointStateMiss.Inc()
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// 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 *CheckpointState) error {
|
||||
func (c *CheckpointStateCache) AddCheckpointState(cp *ethpb.Checkpoint, s *stateTrie.BeaconState) error {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
if err := c.cache.AddIfNotPresent(&CheckpointState{
|
||||
Checkpoint: stateTrie.CopyCheckpoint(cp.Checkpoint),
|
||||
State: cp.State.Copy(),
|
||||
}); err != nil {
|
||||
h, err := hashutil.HashProto(cp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
trim(c.cache, maxCheckpointStateSize)
|
||||
c.cache.Add(h, s)
|
||||
return nil
|
||||
}
|
||||
|
||||
// CheckpointStateKeys returns the keys of the state in cache.
|
||||
func (c *CheckpointStateCache) CheckpointStateKeys() []string {
|
||||
return c.cache.ListKeys()
|
||||
}
|
||||
|
||||
55
beacon-chain/cache/checkpoint_state_test.go
vendored
55
beacon-chain/cache/checkpoint_state_test.go
vendored
@@ -8,36 +8,11 @@ import (
|
||||
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/hashutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
func TestCheckpointStateCacheKeyFn_OK(t *testing.T) {
|
||||
cp := ðpb.Checkpoint{Epoch: 1, Root: bytesutil.PadTo([]byte{'A'}, 32)}
|
||||
st, err := stateTrie.InitializeFromProto(&pb.BeaconState{
|
||||
Slot: 64,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
info := &CheckpointState{
|
||||
Checkpoint: cp,
|
||||
State: st,
|
||||
}
|
||||
key, err := checkpointState(info)
|
||||
require.NoError(t, err)
|
||||
|
||||
wantedKey, err := hashutil.HashProto(cp)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, string(wantedKey[:]), key)
|
||||
}
|
||||
|
||||
func TestCheckpointStateCacheKeyFn_InvalidObj(t *testing.T) {
|
||||
_, err := checkpointState("bad")
|
||||
assert.Equal(t, ErrNotCheckpointState, err)
|
||||
}
|
||||
|
||||
func TestCheckpointStateCache_StateByCheckpoint(t *testing.T) {
|
||||
cache := NewCheckpointStateCache()
|
||||
|
||||
@@ -48,20 +23,16 @@ func TestCheckpointStateCache_StateByCheckpoint(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
info1 := &CheckpointState{
|
||||
Checkpoint: cp1,
|
||||
State: st,
|
||||
}
|
||||
state, err := cache.StateByCheckpoint(cp1)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, (*stateTrie.BeaconState)(nil), state, "Expected state not to exist in empty cache")
|
||||
|
||||
require.NoError(t, cache.AddCheckpointState(info1))
|
||||
require.NoError(t, cache.AddCheckpointState(cp1, st))
|
||||
|
||||
state, err = cache.StateByCheckpoint(cp1)
|
||||
require.NoError(t, err)
|
||||
|
||||
if !proto.Equal(state.InnerStateUnsafe(), info1.State.InnerStateUnsafe()) {
|
||||
if !proto.Equal(state.InnerStateUnsafe(), st.InnerStateUnsafe()) {
|
||||
t.Error("incorrectly cached state")
|
||||
}
|
||||
|
||||
@@ -70,20 +41,15 @@ func TestCheckpointStateCache_StateByCheckpoint(t *testing.T) {
|
||||
Slot: 128,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
info2 := &CheckpointState{
|
||||
Checkpoint: cp2,
|
||||
State: st2,
|
||||
}
|
||||
require.NoError(t, cache.AddCheckpointState(info2))
|
||||
require.NoError(t, cache.AddCheckpointState(cp2, st2))
|
||||
|
||||
state, err = cache.StateByCheckpoint(cp2)
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, info2.State.CloneInnerState(), state.CloneInnerState(), "incorrectly cached state")
|
||||
assert.DeepEqual(t, st2.CloneInnerState(), state.CloneInnerState(), "incorrectly cached state")
|
||||
|
||||
state, err = cache.StateByCheckpoint(cp1)
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, info1.State.CloneInnerState(), state.CloneInnerState(), "incorrectly cached state")
|
||||
assert.DeepEqual(t, st.CloneInnerState(), state.CloneInnerState(), "incorrectly cached state")
|
||||
}
|
||||
|
||||
func TestCheckpointStateCache_MaxSize(t *testing.T) {
|
||||
@@ -93,15 +59,10 @@ func TestCheckpointStateCache_MaxSize(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
for i := uint64(0); i < maxCheckpointStateSize+100; i++ {
|
||||
for i := uint64(0); i < uint64(maxCheckpointStateSize+100); i++ {
|
||||
require.NoError(t, st.SetSlot(i))
|
||||
|
||||
info := &CheckpointState{
|
||||
Checkpoint: ðpb.Checkpoint{Epoch: i},
|
||||
State: st,
|
||||
}
|
||||
require.NoError(t, c.AddCheckpointState(info))
|
||||
require.NoError(t, c.AddCheckpointState(ðpb.Checkpoint{Epoch: i, Root: make([]byte, 32)}, st))
|
||||
}
|
||||
|
||||
assert.Equal(t, maxCheckpointStateSize, uint64(len(c.cache.ListKeys())))
|
||||
assert.Equal(t, maxCheckpointStateSize, len(c.cache.Keys()))
|
||||
}
|
||||
|
||||
75
beacon-chain/cache/committee.go
vendored
75
beacon-chain/cache/committee.go
vendored
@@ -1,3 +1,5 @@
|
||||
// +build !libfuzzer
|
||||
|
||||
package cache
|
||||
|
||||
import (
|
||||
@@ -12,14 +14,9 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrNotCommittee will be returned when a cache object is not a pointer to
|
||||
// a Committee struct.
|
||||
ErrNotCommittee = errors.New("object is not a committee struct")
|
||||
|
||||
// maxCommitteesCacheSize defines the max number of shuffled committees on per randao basis can cache.
|
||||
// Due to reorgs, it's good to keep the old cache around for quickly switch over. 10 is a generous
|
||||
// cache size as it considers 3 concurrent branches over 3 epochs.
|
||||
maxCommitteesCacheSize = uint64(10)
|
||||
// Due to reorgs and long finality, it's good to keep the old cache around for quickly switch over.
|
||||
maxCommitteesCacheSize = uint64(32)
|
||||
|
||||
// CommitteeCacheMiss tracks the number of committee requests that aren't present in the cache.
|
||||
CommitteeCacheMiss = promauto.NewCounter(prometheus.CounterOpts{
|
||||
@@ -33,15 +30,6 @@ var (
|
||||
})
|
||||
)
|
||||
|
||||
// Committees defines the shuffled committees seed.
|
||||
type Committees struct {
|
||||
CommitteeCount uint64
|
||||
Seed [32]byte
|
||||
ShuffledIndices []uint64
|
||||
SortedIndices []uint64
|
||||
ProposerIndices []uint64
|
||||
}
|
||||
|
||||
// CommitteeCache is a struct with 1 queue for looking up shuffled indices list by seed.
|
||||
type CommitteeCache struct {
|
||||
CommitteeCache *cache.FIFO
|
||||
@@ -116,35 +104,6 @@ func (c *CommitteeCache) AddCommitteeShuffledList(committees *Committees) error
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddProposerIndicesList updates the committee shuffled list with proposer indices.
|
||||
func (c *CommitteeCache) AddProposerIndicesList(seed [32]byte, indices []uint64) error {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
|
||||
obj, exists, err := c.CommitteeCache.GetByKey(key(seed))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !exists {
|
||||
committees := &Committees{ProposerIndices: indices}
|
||||
if err := c.CommitteeCache.Add(committees); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
committees, ok := obj.(*Committees)
|
||||
if !ok {
|
||||
return ErrNotCommittee
|
||||
}
|
||||
committees.ProposerIndices = indices
|
||||
if err := c.CommitteeCache.Add(committees); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
trim(c.CommitteeCache, maxCommitteesCacheSize)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ActiveIndices returns the active indices of a given seed stored in cache.
|
||||
func (c *CommitteeCache) ActiveIndices(seed [32]byte) ([]uint64, error) {
|
||||
c.lock.RLock()
|
||||
@@ -193,28 +152,10 @@ func (c *CommitteeCache) ActiveIndicesCount(seed [32]byte) (int, error) {
|
||||
return len(item.SortedIndices), nil
|
||||
}
|
||||
|
||||
// ProposerIndices returns the proposer indices of a given seed.
|
||||
func (c *CommitteeCache) ProposerIndices(seed [32]byte) ([]uint64, error) {
|
||||
c.lock.RLock()
|
||||
defer c.lock.RUnlock()
|
||||
obj, exists, err := c.CommitteeCache.GetByKey(key(seed))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if exists {
|
||||
CommitteeCacheHit.Inc()
|
||||
} else {
|
||||
CommitteeCacheMiss.Inc()
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
item, ok := obj.(*Committees)
|
||||
if !ok {
|
||||
return nil, ErrNotCommittee
|
||||
}
|
||||
|
||||
return item.ProposerIndices, nil
|
||||
// HasEntry returns true if the committee cache has a value.
|
||||
func (c *CommitteeCache) HasEntry(seed string) bool {
|
||||
_, ok, err := c.CommitteeCache.GetByKey(seed)
|
||||
return err == nil && ok
|
||||
}
|
||||
|
||||
func startEndIndices(c *Committees, index uint64) (uint64, uint64) {
|
||||
|
||||
50
beacon-chain/cache/committee_disabled.go
vendored
Normal file
50
beacon-chain/cache/committee_disabled.go
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
// +build libfuzzer
|
||||
|
||||
// This file is used in fuzzer builds to bypass global committee caches.
|
||||
package cache
|
||||
|
||||
// FakeCommitteeCache is a struct with 1 queue for looking up shuffled indices list by seed.
|
||||
type FakeCommitteeCache struct {
|
||||
}
|
||||
|
||||
// NewCommitteesCache creates a new committee cache for storing/accessing shuffled indices of a committee.
|
||||
func NewCommitteesCache() *FakeCommitteeCache {
|
||||
return &FakeCommitteeCache{}
|
||||
}
|
||||
|
||||
// Committee fetches the shuffled indices by slot and committee index. Every list of indices
|
||||
// represent one committee. Returns true if the list exists with slot and committee index. Otherwise returns false, nil.
|
||||
func (c *FakeCommitteeCache) Committee(slot uint64, seed [32]byte, index uint64) ([]uint64, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// AddCommitteeShuffledList adds Committee shuffled list object to the cache. T
|
||||
// his method also trims the least recently list if the cache size has ready the max cache size limit.
|
||||
func (c *FakeCommitteeCache) AddCommitteeShuffledList(committees *Committees) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddProposerIndicesList updates the committee shuffled list with proposer indices.
|
||||
func (c *FakeCommitteeCache) AddProposerIndicesList(seed [32]byte, indices []uint64) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ActiveIndices returns the active indices of a given seed stored in cache.
|
||||
func (c *FakeCommitteeCache) ActiveIndices(seed [32]byte) ([]uint64, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// ActiveIndicesCount returns the active indices count of a given seed stored in cache.
|
||||
func (c *FakeCommitteeCache) ActiveIndicesCount(seed [32]byte) (int, error) {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// ProposerIndices returns the proposer indices of a given seed.
|
||||
func (c *FakeCommitteeCache) ProposerIndices(seed [32]byte) ([]uint64, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// HasEntry returns true if the committee cache has a value.
|
||||
func (c *FakeCommitteeCache) HasEntry(string) bool {
|
||||
return false
|
||||
}
|
||||
39
beacon-chain/cache/committee_test.go
vendored
39
beacon-chain/cache/committee_test.go
vendored
@@ -87,42 +87,13 @@ func TestCommitteeCache_ActiveCount(t *testing.T) {
|
||||
assert.Equal(t, len(item.SortedIndices), count)
|
||||
}
|
||||
|
||||
func TestCommitteeCache_AddProposerIndicesList(t *testing.T) {
|
||||
cache := NewCommitteesCache()
|
||||
|
||||
seed := [32]byte{'A'}
|
||||
indices := []uint64{1, 2, 3, 4, 5}
|
||||
indices, err := cache.ProposerIndices(seed)
|
||||
require.NoError(t, err)
|
||||
if indices != nil {
|
||||
t.Error("Expected committee count not to exist in empty cache")
|
||||
}
|
||||
require.NoError(t, cache.AddProposerIndicesList(seed, indices))
|
||||
|
||||
received, err := cache.ProposerIndices(seed)
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, received, indices)
|
||||
|
||||
item := &Committees{Seed: [32]byte{'B'}, SortedIndices: []uint64{1, 2, 3, 4, 5, 6}}
|
||||
require.NoError(t, cache.AddCommitteeShuffledList(item))
|
||||
|
||||
indices, err = cache.ProposerIndices(item.Seed)
|
||||
require.NoError(t, err)
|
||||
if indices != nil {
|
||||
t.Error("Expected committee count not to exist in empty cache")
|
||||
}
|
||||
require.NoError(t, cache.AddProposerIndicesList(item.Seed, indices))
|
||||
|
||||
received, err = cache.ProposerIndices(item.Seed)
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, received, indices)
|
||||
}
|
||||
|
||||
func TestCommitteeCache_CanRotate(t *testing.T) {
|
||||
cache := NewCommitteesCache()
|
||||
|
||||
// Should rotate out all the epochs except 190 through 199.
|
||||
for i := 100; i < 200; i++ {
|
||||
start := 100
|
||||
end := 200
|
||||
for i := start; i < end; i++ {
|
||||
s := []byte(strconv.Itoa(i))
|
||||
item := &Committees{Seed: bytesutil.ToBytes32(s)}
|
||||
require.NoError(t, cache.AddCommitteeShuffledList(item))
|
||||
@@ -134,7 +105,8 @@ func TestCommitteeCache_CanRotate(t *testing.T) {
|
||||
sort.Slice(k, func(i, j int) bool {
|
||||
return k[i] < k[j]
|
||||
})
|
||||
s := bytesutil.ToBytes32([]byte(strconv.Itoa(190)))
|
||||
wanted := end - int(maxCommitteesCacheSize)
|
||||
s := bytesutil.ToBytes32([]byte(strconv.Itoa(wanted)))
|
||||
assert.Equal(t, key(s), k[0], "incorrect key received for slot 190")
|
||||
|
||||
s = bytesutil.ToBytes32([]byte(strconv.Itoa(199)))
|
||||
@@ -149,7 +121,6 @@ func TestCommitteeCacheOutOfRange(t *testing.T) {
|
||||
Seed: seed,
|
||||
ShuffledIndices: []uint64{0},
|
||||
SortedIndices: []uint64{},
|
||||
ProposerIndices: []uint64{},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
|
||||
15
beacon-chain/cache/committees.go
vendored
Normal file
15
beacon-chain/cache/committees.go
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
package cache
|
||||
|
||||
import "errors"
|
||||
|
||||
// ErrNotCommittee will be returned when a cache object is not a pointer to
|
||||
// a Committee struct.
|
||||
var ErrNotCommittee = errors.New("object is not a committee struct")
|
||||
|
||||
// Committees defines the shuffled committees seed.
|
||||
type Committees struct {
|
||||
CommitteeCount uint64
|
||||
Seed [32]byte
|
||||
ShuffledIndices []uint64
|
||||
SortedIndices []uint64
|
||||
}
|
||||
2
beacon-chain/cache/depositcache/BUILD.bazel
vendored
2
beacon-chain/cache/depositcache/BUILD.bazel
vendored
@@ -18,7 +18,6 @@ go_library(
|
||||
"@com_github_prometheus_client_golang//prometheus:go_default_library",
|
||||
"@com_github_prometheus_client_golang//prometheus/promauto:go_default_library",
|
||||
"@com_github_prysmaticlabs_ethereumapis//eth/v1alpha1:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_ssz//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
"@io_opencensus_go//trace:go_default_library",
|
||||
],
|
||||
@@ -40,7 +39,6 @@ go_test(
|
||||
"//shared/trieutil:go_default_library",
|
||||
"@com_github_gogo_protobuf//proto:go_default_library",
|
||||
"@com_github_prysmaticlabs_ethereumapis//eth/v1alpha1:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_ssz//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//hooks/test:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -15,7 +15,6 @@ import (
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/go-ssz"
|
||||
dbpb "github.com/prysmaticlabs/prysm/proto/beacon/db"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
@@ -59,8 +58,8 @@ type DepositCache struct {
|
||||
chainStartPubkeys map[string]bool
|
||||
}
|
||||
|
||||
// NewDepositCache instantiates a new deposit cache
|
||||
func NewDepositCache() (*DepositCache, error) {
|
||||
// New instantiates a new deposit cache
|
||||
func New() (*DepositCache, error) {
|
||||
finalizedDepositsTrie, err := trieutil.NewTrie(int(params.BeaconConfig().DepositContractTreeDepth))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -128,7 +127,7 @@ func (dc *DepositCache) InsertFinalizedDeposits(ctx context.Context, eth1Deposit
|
||||
if d.Index > eth1DepositIndex {
|
||||
break
|
||||
}
|
||||
depHash, err := ssz.HashTreeRoot(d.Deposit.Data)
|
||||
depHash, err := d.Deposit.Data.HashTreeRoot()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Could not hash deposit data. Finalized deposit cache not updated.")
|
||||
return
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"testing"
|
||||
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/go-ssz"
|
||||
dbpb "github.com/prysmaticlabs/prysm/proto/beacon/db"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
@@ -20,11 +19,11 @@ import (
|
||||
|
||||
const nilDepositErr = "Ignoring nil deposit insertion"
|
||||
|
||||
var _ = DepositFetcher(&DepositCache{})
|
||||
var _ DepositFetcher = (*DepositCache)(nil)
|
||||
|
||||
func TestInsertDeposit_LogsOnNilDepositInsertion(t *testing.T) {
|
||||
hook := logTest.NewGlobal()
|
||||
dc, err := NewDepositCache()
|
||||
dc, err := New()
|
||||
require.NoError(t, err)
|
||||
|
||||
dc.InsertDeposit(context.Background(), nil, 1, 0, [32]byte{})
|
||||
@@ -34,7 +33,7 @@ func TestInsertDeposit_LogsOnNilDepositInsertion(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestInsertDeposit_MaintainsSortedOrderByIndex(t *testing.T) {
|
||||
dc, err := NewDepositCache()
|
||||
dc, err := New()
|
||||
require.NoError(t, err)
|
||||
|
||||
insertions := []struct {
|
||||
@@ -76,7 +75,7 @@ func TestInsertDeposit_MaintainsSortedOrderByIndex(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestAllDeposits_ReturnsAllDeposits(t *testing.T) {
|
||||
dc, err := NewDepositCache()
|
||||
dc, err := New()
|
||||
require.NoError(t, err)
|
||||
|
||||
deposits := []*dbpb.DepositContainer{
|
||||
@@ -116,7 +115,7 @@ func TestAllDeposits_ReturnsAllDeposits(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestAllDeposits_FiltersDepositUpToAndIncludingBlockNumber(t *testing.T) {
|
||||
dc, err := NewDepositCache()
|
||||
dc, err := New()
|
||||
require.NoError(t, err)
|
||||
|
||||
deposits := []*dbpb.DepositContainer{
|
||||
@@ -156,38 +155,80 @@ func TestAllDeposits_FiltersDepositUpToAndIncludingBlockNumber(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDepositsNumberAndRootAtHeight_ReturnsAppropriateCountAndRoot(t *testing.T) {
|
||||
dc, err := NewDepositCache()
|
||||
dc, err := New()
|
||||
require.NoError(t, err)
|
||||
|
||||
dc.deposits = []*dbpb.DepositContainer{
|
||||
{
|
||||
Eth1BlockHeight: 10,
|
||||
Deposit: ðpb.Deposit{},
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: make([]byte, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Eth1BlockHeight: 10,
|
||||
Deposit: ðpb.Deposit{},
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: make([]byte, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Eth1BlockHeight: 10,
|
||||
Deposit: ðpb.Deposit{},
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: make([]byte, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Eth1BlockHeight: 10,
|
||||
Deposit: ðpb.Deposit{},
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: make([]byte, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Eth1BlockHeight: 11,
|
||||
Deposit: ðpb.Deposit{},
|
||||
DepositRoot: []byte("root"),
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: make([]byte, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
DepositRoot: bytesutil.PadTo([]byte("root"), 32),
|
||||
},
|
||||
{
|
||||
Eth1BlockHeight: 12,
|
||||
Deposit: ðpb.Deposit{},
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: make([]byte, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Eth1BlockHeight: 12,
|
||||
Deposit: ðpb.Deposit{},
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: make([]byte, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -197,19 +238,31 @@ func TestDepositsNumberAndRootAtHeight_ReturnsAppropriateCountAndRoot(t *testing
|
||||
}
|
||||
|
||||
func TestDepositsNumberAndRootAtHeight_ReturnsEmptyTrieIfBlockHeightLessThanOldestDeposit(t *testing.T) {
|
||||
dc, err := NewDepositCache()
|
||||
dc, err := New()
|
||||
require.NoError(t, err)
|
||||
|
||||
dc.deposits = []*dbpb.DepositContainer{
|
||||
{
|
||||
Eth1BlockHeight: 10,
|
||||
Deposit: ðpb.Deposit{},
|
||||
DepositRoot: []byte("root"),
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: make([]byte, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
DepositRoot: bytesutil.PadTo([]byte("root"), 32),
|
||||
},
|
||||
{
|
||||
Eth1BlockHeight: 11,
|
||||
Deposit: ðpb.Deposit{},
|
||||
DepositRoot: []byte("root"),
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: make([]byte, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
DepositRoot: bytesutil.PadTo([]byte("root"), 32),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -219,7 +272,7 @@ func TestDepositsNumberAndRootAtHeight_ReturnsEmptyTrieIfBlockHeightLessThanOlde
|
||||
}
|
||||
|
||||
func TestDepositByPubkey_ReturnsFirstMatchingDeposit(t *testing.T) {
|
||||
dc, err := NewDepositCache()
|
||||
dc, err := New()
|
||||
require.NoError(t, err)
|
||||
|
||||
dc.deposits = []*dbpb.DepositContainer{
|
||||
@@ -227,7 +280,9 @@ func TestDepositByPubkey_ReturnsFirstMatchingDeposit(t *testing.T) {
|
||||
Eth1BlockHeight: 9,
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: []byte("pk0"),
|
||||
PublicKey: bytesutil.PadTo([]byte("pk0"), 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -235,7 +290,9 @@ func TestDepositByPubkey_ReturnsFirstMatchingDeposit(t *testing.T) {
|
||||
Eth1BlockHeight: 10,
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: []byte("pk1"),
|
||||
PublicKey: bytesutil.PadTo([]byte("pk1"), 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -243,7 +300,9 @@ func TestDepositByPubkey_ReturnsFirstMatchingDeposit(t *testing.T) {
|
||||
Eth1BlockHeight: 11,
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: []byte("pk1"),
|
||||
PublicKey: bytesutil.PadTo([]byte("pk1"), 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -251,15 +310,18 @@ func TestDepositByPubkey_ReturnsFirstMatchingDeposit(t *testing.T) {
|
||||
Eth1BlockHeight: 12,
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: []byte("pk2"),
|
||||
PublicKey: bytesutil.PadTo([]byte("pk2"), 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
dep, blkNum := dc.DepositByPubkey(context.Background(), []byte("pk1"))
|
||||
pk1 := bytesutil.PadTo([]byte("pk1"), 48)
|
||||
dep, blkNum := dc.DepositByPubkey(context.Background(), pk1)
|
||||
|
||||
if !bytes.Equal(dep.Data.PublicKey, []byte("pk1")) {
|
||||
if dep == nil || !bytes.Equal(dep.Data.PublicKey, pk1) {
|
||||
t.Error("Returned wrong deposit")
|
||||
}
|
||||
assert.Equal(t, 0, blkNum.Cmp(big.NewInt(10)),
|
||||
@@ -267,14 +329,16 @@ func TestDepositByPubkey_ReturnsFirstMatchingDeposit(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFinalizedDeposits_DepositsCachedCorrectly(t *testing.T) {
|
||||
dc, err := NewDepositCache()
|
||||
dc, err := New()
|
||||
require.NoError(t, err)
|
||||
|
||||
finalizedDeposits := []*dbpb.DepositContainer{
|
||||
{
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: []byte{0},
|
||||
PublicKey: bytesutil.PadTo([]byte{0}, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
Index: 0,
|
||||
@@ -282,7 +346,9 @@ func TestFinalizedDeposits_DepositsCachedCorrectly(t *testing.T) {
|
||||
{
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: []byte{1},
|
||||
PublicKey: bytesutil.PadTo([]byte{1}, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
Index: 1,
|
||||
@@ -290,7 +356,9 @@ func TestFinalizedDeposits_DepositsCachedCorrectly(t *testing.T) {
|
||||
{
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: []byte{2},
|
||||
PublicKey: bytesutil.PadTo([]byte{2}, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
Index: 2,
|
||||
@@ -299,7 +367,9 @@ func TestFinalizedDeposits_DepositsCachedCorrectly(t *testing.T) {
|
||||
dc.deposits = append(finalizedDeposits, &dbpb.DepositContainer{
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: []byte{3},
|
||||
PublicKey: bytesutil.PadTo([]byte{3}, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
Index: 3,
|
||||
@@ -313,7 +383,7 @@ func TestFinalizedDeposits_DepositsCachedCorrectly(t *testing.T) {
|
||||
|
||||
var deps [][]byte
|
||||
for _, d := range finalizedDeposits {
|
||||
hash, err := ssz.HashTreeRoot(d.Deposit.Data)
|
||||
hash, err := d.Deposit.Data.HashTreeRoot()
|
||||
require.NoError(t, err, "Could not hash deposit data")
|
||||
deps = append(deps, hash[:])
|
||||
}
|
||||
@@ -323,14 +393,16 @@ func TestFinalizedDeposits_DepositsCachedCorrectly(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFinalizedDeposits_UtilizesPreviouslyCachedDeposits(t *testing.T) {
|
||||
dc, err := NewDepositCache()
|
||||
dc, err := New()
|
||||
require.NoError(t, err)
|
||||
|
||||
oldFinalizedDeposits := []*dbpb.DepositContainer{
|
||||
{
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: []byte{0},
|
||||
PublicKey: bytesutil.PadTo([]byte{0}, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
Index: 0,
|
||||
@@ -338,7 +410,9 @@ func TestFinalizedDeposits_UtilizesPreviouslyCachedDeposits(t *testing.T) {
|
||||
{
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: []byte{1},
|
||||
PublicKey: bytesutil.PadTo([]byte{1}, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
Index: 1,
|
||||
@@ -347,7 +421,9 @@ func TestFinalizedDeposits_UtilizesPreviouslyCachedDeposits(t *testing.T) {
|
||||
newFinalizedDeposit := dbpb.DepositContainer{
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: []byte{2},
|
||||
PublicKey: bytesutil.PadTo([]byte{2}, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
Index: 2,
|
||||
@@ -365,7 +441,7 @@ func TestFinalizedDeposits_UtilizesPreviouslyCachedDeposits(t *testing.T) {
|
||||
|
||||
var deps [][]byte
|
||||
for _, d := range append(oldFinalizedDeposits, &newFinalizedDeposit) {
|
||||
hash, err := ssz.HashTreeRoot(d.Deposit.Data)
|
||||
hash, err := d.Deposit.Data.HashTreeRoot()
|
||||
require.NoError(t, err, "Could not hash deposit data")
|
||||
deps = append(deps, hash[:])
|
||||
}
|
||||
@@ -375,7 +451,7 @@ func TestFinalizedDeposits_UtilizesPreviouslyCachedDeposits(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFinalizedDeposits_InitializedCorrectly(t *testing.T) {
|
||||
dc, err := NewDepositCache()
|
||||
dc, err := New()
|
||||
require.NoError(t, err)
|
||||
|
||||
finalizedDeposits := dc.finalizedDeposits
|
||||
@@ -385,7 +461,7 @@ func TestFinalizedDeposits_InitializedCorrectly(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestNonFinalizedDeposits_ReturnsAllNonFinalizedDeposits(t *testing.T) {
|
||||
dc, err := NewDepositCache()
|
||||
dc, err := New()
|
||||
require.NoError(t, err)
|
||||
|
||||
finalizedDeposits := []*dbpb.DepositContainer{
|
||||
@@ -393,7 +469,9 @@ func TestNonFinalizedDeposits_ReturnsAllNonFinalizedDeposits(t *testing.T) {
|
||||
Eth1BlockHeight: 10,
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: []byte{0},
|
||||
PublicKey: bytesutil.PadTo([]byte{0}, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
Index: 0,
|
||||
@@ -402,7 +480,9 @@ func TestNonFinalizedDeposits_ReturnsAllNonFinalizedDeposits(t *testing.T) {
|
||||
Eth1BlockHeight: 10,
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: []byte{1},
|
||||
PublicKey: bytesutil.PadTo([]byte{1}, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
Index: 1,
|
||||
@@ -413,7 +493,9 @@ func TestNonFinalizedDeposits_ReturnsAllNonFinalizedDeposits(t *testing.T) {
|
||||
Eth1BlockHeight: 10,
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: []byte{2},
|
||||
PublicKey: bytesutil.PadTo([]byte{2}, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
Index: 2,
|
||||
@@ -422,7 +504,9 @@ func TestNonFinalizedDeposits_ReturnsAllNonFinalizedDeposits(t *testing.T) {
|
||||
Eth1BlockHeight: 11,
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: []byte{3},
|
||||
PublicKey: bytesutil.PadTo([]byte{3}, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
Index: 3,
|
||||
@@ -434,7 +518,7 @@ func TestNonFinalizedDeposits_ReturnsAllNonFinalizedDeposits(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestNonFinalizedDeposits_ReturnsNonFinalizedDepositsUpToBlockNumber(t *testing.T) {
|
||||
dc, err := NewDepositCache()
|
||||
dc, err := New()
|
||||
require.NoError(t, err)
|
||||
|
||||
finalizedDeposits := []*dbpb.DepositContainer{
|
||||
@@ -442,7 +526,9 @@ func TestNonFinalizedDeposits_ReturnsNonFinalizedDepositsUpToBlockNumber(t *test
|
||||
Eth1BlockHeight: 10,
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: []byte{0},
|
||||
PublicKey: bytesutil.PadTo([]byte{0}, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
Index: 0,
|
||||
@@ -451,7 +537,9 @@ func TestNonFinalizedDeposits_ReturnsNonFinalizedDepositsUpToBlockNumber(t *test
|
||||
Eth1BlockHeight: 10,
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: []byte{1},
|
||||
PublicKey: bytesutil.PadTo([]byte{1}, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
Index: 1,
|
||||
@@ -462,7 +550,9 @@ func TestNonFinalizedDeposits_ReturnsNonFinalizedDepositsUpToBlockNumber(t *test
|
||||
Eth1BlockHeight: 10,
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: []byte{2},
|
||||
PublicKey: bytesutil.PadTo([]byte{2}, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
Index: 2,
|
||||
@@ -471,7 +561,9 @@ func TestNonFinalizedDeposits_ReturnsNonFinalizedDepositsUpToBlockNumber(t *test
|
||||
Eth1BlockHeight: 11,
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: []byte{3},
|
||||
PublicKey: bytesutil.PadTo([]byte{3}, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
Index: 3,
|
||||
|
||||
@@ -9,10 +9,11 @@ import (
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
dbpb "github.com/prysmaticlabs/prysm/proto/beacon/db"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
)
|
||||
|
||||
var _ = PendingDepositsFetcher(&DepositCache{})
|
||||
var _ PendingDepositsFetcher = (*DepositCache)(nil)
|
||||
|
||||
func TestInsertPendingDeposit_OK(t *testing.T) {
|
||||
dc := DepositCache{}
|
||||
@@ -28,14 +29,28 @@ func TestInsertPendingDeposit_ignoresNilDeposit(t *testing.T) {
|
||||
assert.Equal(t, 0, len(dc.pendingDeposits))
|
||||
}
|
||||
|
||||
func makeDepositProof() [][]byte {
|
||||
proof := make([][]byte, int(params.BeaconConfig().DepositContractTreeDepth)+1)
|
||||
for i := range proof {
|
||||
proof[i] = make([]byte, 32)
|
||||
}
|
||||
return proof
|
||||
}
|
||||
|
||||
func TestRemovePendingDeposit_OK(t *testing.T) {
|
||||
db := DepositCache{}
|
||||
proof1 := make([][]byte, 33)
|
||||
proof1 := makeDepositProof()
|
||||
proof1[0] = bytesutil.PadTo([]byte{'A'}, 32)
|
||||
proof2 := make([][]byte, 33)
|
||||
proof2 := makeDepositProof()
|
||||
proof2[0] = bytesutil.PadTo([]byte{'A'}, 32)
|
||||
depToRemove := ðpb.Deposit{Proof: proof1}
|
||||
otherDep := ðpb.Deposit{Proof: proof2}
|
||||
data := ðpb.Deposit_Data{
|
||||
PublicKey: make([]byte, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Amount: 0,
|
||||
Signature: make([]byte, 96),
|
||||
}
|
||||
depToRemove := ðpb.Deposit{Proof: proof1, Data: data}
|
||||
otherDep := ðpb.Deposit{Proof: proof2, Data: data}
|
||||
db.pendingDeposits = []*dbpb.DepositContainer{
|
||||
{Deposit: depToRemove, Index: 1},
|
||||
{Deposit: otherDep, Index: 5},
|
||||
@@ -56,9 +71,15 @@ func TestRemovePendingDeposit_IgnoresNilDeposit(t *testing.T) {
|
||||
|
||||
func TestPendingDeposit_RoundTrip(t *testing.T) {
|
||||
dc := DepositCache{}
|
||||
proof := make([][]byte, 33)
|
||||
proof := makeDepositProof()
|
||||
proof[0] = bytesutil.PadTo([]byte{'A'}, 32)
|
||||
dep := ðpb.Deposit{Proof: proof}
|
||||
data := ðpb.Deposit_Data{
|
||||
PublicKey: make([]byte, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Amount: 0,
|
||||
Signature: make([]byte, 96),
|
||||
}
|
||||
dep := ðpb.Deposit{Proof: proof, Data: data}
|
||||
dc.InsertPendingDeposit(context.Background(), dep, 111, 100, [32]byte{})
|
||||
dc.RemovePendingDeposit(context.Background(), dep)
|
||||
assert.Equal(t, 0, len(dc.pendingDeposits), "Failed to insert & delete a pending deposit")
|
||||
|
||||
5
beacon-chain/cache/feature_flag_test.go
vendored
5
beacon-chain/cache/feature_flag_test.go
vendored
@@ -10,5 +10,8 @@ import (
|
||||
func TestMain(m *testing.M) {
|
||||
resetCfg := featureconfig.InitWithReset(&featureconfig.Flags{EnableEth1DataVoteCache: true})
|
||||
defer resetCfg()
|
||||
os.Exit(m.Run())
|
||||
code := m.Run()
|
||||
// os.Exit will prevent defer from being called
|
||||
resetCfg()
|
||||
os.Exit(code)
|
||||
}
|
||||
|
||||
88
beacon-chain/cache/proposer_indices.go
vendored
Normal file
88
beacon-chain/cache/proposer_indices.go
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
// +build !libfuzzer
|
||||
|
||||
package cache
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
var (
|
||||
// maxProposerIndicesCacheSize defines the max number of proposer indices on per block root basis can cache.
|
||||
// Due to reorgs and long finality, it's good to keep the old cache around for quickly switch over.
|
||||
maxProposerIndicesCacheSize = uint64(8)
|
||||
|
||||
// ProposerIndicesCacheMiss tracks the number of proposerIndices requests that aren't present in the cache.
|
||||
ProposerIndicesCacheMiss = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "proposer_indices_cache_miss",
|
||||
Help: "The number of proposer indices requests that aren't present in the cache.",
|
||||
})
|
||||
// ProposerIndicesCacheHit tracks the number of proposerIndices requests that are in the cache.
|
||||
ProposerIndicesCacheHit = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "proposer_indices_cache_hit",
|
||||
Help: "The number of proposer indices requests that are present in the cache.",
|
||||
})
|
||||
)
|
||||
|
||||
// ProposerIndicesCache is a struct with 1 queue for looking up proposer indices by root.
|
||||
type ProposerIndicesCache struct {
|
||||
ProposerIndicesCache *cache.FIFO
|
||||
lock sync.RWMutex
|
||||
}
|
||||
|
||||
// proposerIndicesKeyFn takes the block root as the key to retrieve proposer indices in a given epoch.
|
||||
func proposerIndicesKeyFn(obj interface{}) (string, error) {
|
||||
info, ok := obj.(*ProposerIndices)
|
||||
if !ok {
|
||||
return "", ErrNotProposerIndices
|
||||
}
|
||||
|
||||
return key(info.BlockRoot), nil
|
||||
}
|
||||
|
||||
// NewProposerIndicesCache creates a new proposer indices cache for storing/accessing proposer index assignments of an epoch.
|
||||
func NewProposerIndicesCache() *ProposerIndicesCache {
|
||||
return &ProposerIndicesCache{
|
||||
ProposerIndicesCache: cache.NewFIFO(proposerIndicesKeyFn),
|
||||
}
|
||||
}
|
||||
|
||||
// AddProposerIndices adds ProposerIndices object to the cache.
|
||||
// This method also trims the least recently list if the cache size has ready the max cache size limit.
|
||||
func (c *ProposerIndicesCache) AddProposerIndices(p *ProposerIndices) error {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
|
||||
if err := c.ProposerIndicesCache.AddIfNotPresent(p); err != nil {
|
||||
return err
|
||||
}
|
||||
trim(c.ProposerIndicesCache, maxProposerIndicesCacheSize)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ProposerIndices returns the proposer indices of a block root seed.
|
||||
func (c *ProposerIndicesCache) ProposerIndices(r [32]byte) ([]uint64, error) {
|
||||
c.lock.RLock()
|
||||
defer c.lock.RUnlock()
|
||||
obj, exists, err := c.ProposerIndicesCache.GetByKey(key(r))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if exists {
|
||||
ProposerIndicesCacheHit.Inc()
|
||||
} else {
|
||||
ProposerIndicesCacheMiss.Inc()
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
item, ok := obj.(*ProposerIndices)
|
||||
if !ok {
|
||||
return nil, ErrNotProposerIndices
|
||||
}
|
||||
|
||||
return item.ProposerIndices, nil
|
||||
}
|
||||
24
beacon-chain/cache/proposer_indices_disabled.go
vendored
Normal file
24
beacon-chain/cache/proposer_indices_disabled.go
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
// +build libfuzzer
|
||||
|
||||
// This file is used in fuzzer builds to bypass proposer indices caches.
|
||||
package cache
|
||||
|
||||
// FakeProposerIndicesCache is a struct with 1 queue for looking up proposer indices by root.
|
||||
type FakeProposerIndicesCache struct {
|
||||
}
|
||||
|
||||
// NewProposerIndicesCache creates a new proposer indices cache for storing/accessing proposer index assignments of an epoch.
|
||||
func NewProposerIndicesCache() *FakeProposerIndicesCache {
|
||||
return &FakeProposerIndicesCache{}
|
||||
}
|
||||
|
||||
// AddProposerIndices adds ProposerIndices object to the cache.
|
||||
// This method also trims the least recently list if the cache size has ready the max cache size limit.
|
||||
func (c *FakeProposerIndicesCache) AddProposerIndices(p *ProposerIndices) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ProposerIndices returns the proposer indices of a block root seed.
|
||||
func (c *FakeProposerIndicesCache) ProposerIndices(r [32]byte) ([]uint64, error) {
|
||||
return nil, nil
|
||||
}
|
||||
63
beacon-chain/cache/proposer_indices_test.go
vendored
Normal file
63
beacon-chain/cache/proposer_indices_test.go
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
func TestProposerKeyFn_OK(t *testing.T) {
|
||||
item := &ProposerIndices{
|
||||
BlockRoot: [32]byte{'A'},
|
||||
ProposerIndices: []uint64{1, 2, 3, 4, 5},
|
||||
}
|
||||
|
||||
k, err := proposerIndicesKeyFn(item)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, key(item.BlockRoot), k)
|
||||
}
|
||||
|
||||
func TestProposerKeyFn_InvalidObj(t *testing.T) {
|
||||
_, err := proposerIndicesKeyFn("bad")
|
||||
assert.Equal(t, ErrNotProposerIndices, err)
|
||||
}
|
||||
|
||||
func TestProposerCache_AddProposerIndicesList(t *testing.T) {
|
||||
cache := NewProposerIndicesCache()
|
||||
bRoot := [32]byte{'A'}
|
||||
indices, err := cache.ProposerIndices(bRoot)
|
||||
require.NoError(t, err)
|
||||
if indices != nil {
|
||||
t.Error("Expected committee count not to exist in empty cache")
|
||||
}
|
||||
require.NoError(t, cache.AddProposerIndices(&ProposerIndices{
|
||||
ProposerIndices: indices,
|
||||
BlockRoot: bRoot,
|
||||
}))
|
||||
|
||||
received, err := cache.ProposerIndices(bRoot)
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, received, indices)
|
||||
|
||||
item := &ProposerIndices{BlockRoot: [32]byte{'B'}, ProposerIndices: []uint64{1, 2, 3, 4, 5, 6}}
|
||||
require.NoError(t, cache.AddProposerIndices(item))
|
||||
|
||||
received, err = cache.ProposerIndices(item.BlockRoot)
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, item.ProposerIndices, received)
|
||||
}
|
||||
|
||||
func TestProposerCache_CanRotate(t *testing.T) {
|
||||
cache := NewProposerIndicesCache()
|
||||
for i := 0; i < int(maxProposerIndicesCacheSize)+1; i++ {
|
||||
s := []byte(strconv.Itoa(i))
|
||||
item := &ProposerIndices{BlockRoot: bytesutil.ToBytes32(s)}
|
||||
require.NoError(t, cache.AddProposerIndices(item))
|
||||
}
|
||||
|
||||
k := cache.ProposerIndicesCache.ListKeys()
|
||||
assert.Equal(t, maxProposerIndicesCacheSize, uint64(len(k)))
|
||||
}
|
||||
13
beacon-chain/cache/proposer_indices_type.go
vendored
Normal file
13
beacon-chain/cache/proposer_indices_type.go
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
package cache
|
||||
|
||||
import "errors"
|
||||
|
||||
// ErrNotProposerIndices will be returned when a cache object is not a pointer to
|
||||
// a ProposerIndices struct.
|
||||
var ErrNotProposerIndices = errors.New("object is not a proposer indices struct")
|
||||
|
||||
// ProposerIndices defines the cached struct for proposer indices.
|
||||
type ProposerIndices struct {
|
||||
BlockRoot [32]byte
|
||||
ProposerIndices []uint64
|
||||
}
|
||||
2
beacon-chain/cache/subnet_ids_test.go
vendored
2
beacon-chain/cache/subnet_ids_test.go
vendored
@@ -42,12 +42,10 @@ func TestSubnetIDsCache_RoundTrip(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSubnetIDsCache_PersistentCommitteeRoundtrip(t *testing.T) {
|
||||
pubkeySet := [][48]byte{}
|
||||
c := newSubnetIDs()
|
||||
|
||||
for i := 0; i < 20; i++ {
|
||||
pubkey := [48]byte{byte(i)}
|
||||
pubkeySet = append(pubkeySet, pubkey)
|
||||
c.AddPersistentCommittee(pubkey[:], []uint64{uint64(i)}, 0)
|
||||
}
|
||||
|
||||
|
||||
@@ -26,11 +26,11 @@ go_library(
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//beacon-chain/core/validators:go_default_library",
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//beacon-chain/state/stateutil:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//shared/attestationutil:go_default_library",
|
||||
"//shared/bls:go_default_library",
|
||||
"//shared/bytesutil:go_default_library",
|
||||
"//shared/depositutil:go_default_library",
|
||||
"//shared/hashutil:go_default_library",
|
||||
"//shared/mathutil:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
@@ -62,10 +62,10 @@ go_test(
|
||||
"randao_test.go",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
shard_count = 2,
|
||||
deps = [
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//beacon-chain/state/stateutil:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//shared/aggregation:go_default_library",
|
||||
"//shared/aggregation/attestations:go_default_library",
|
||||
@@ -74,12 +74,13 @@ go_test(
|
||||
"//shared/bytesutil:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"//shared/testutil:go_default_library",
|
||||
"//shared/testutil/assert:go_default_library",
|
||||
"//shared/testutil/require:go_default_library",
|
||||
"//shared/trieutil:go_default_library",
|
||||
"@com_github_gogo_protobuf//proto:go_default_library",
|
||||
"@com_github_google_gofuzz//:go_default_library",
|
||||
"@com_github_prysmaticlabs_ethereumapis//eth/v1alpha1:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_ssz//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/attestationutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
@@ -21,10 +22,14 @@ import (
|
||||
func ProcessAttestations(
|
||||
ctx context.Context,
|
||||
beaconState *stateTrie.BeaconState,
|
||||
body *ethpb.BeaconBlockBody,
|
||||
b *ethpb.SignedBeaconBlock,
|
||||
) (*stateTrie.BeaconState, error) {
|
||||
if b.Block == nil || b.Block.Body == nil {
|
||||
return nil, errors.New("block and block body can't be nil")
|
||||
}
|
||||
|
||||
var err error
|
||||
for idx, attestation := range body.Attestations {
|
||||
for idx, attestation := range b.Block.Body.Attestations {
|
||||
beaconState, err = ProcessAttestation(ctx, beaconState, attestation)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not verify attestation at index %d in block", idx)
|
||||
@@ -38,10 +43,10 @@ func ProcessAttestations(
|
||||
// Spec pseudocode definition:
|
||||
// def process_attestation(state: BeaconState, attestation: Attestation) -> None:
|
||||
// data = attestation.data
|
||||
// assert data.index < get_committee_count_at_slot(state, data.slot)
|
||||
// assert data.target.epoch in (get_previous_epoch(state), get_current_epoch(state))
|
||||
// assert data.target.epoch == compute_epoch_at_slot(data.slot)
|
||||
// assert data.slot + MIN_ATTESTATION_INCLUSION_DELAY <= state.slot <= data.slot + SLOTS_PER_EPOCH
|
||||
// assert data.index < get_committee_count_per_slot(state, data.target.epoch)
|
||||
//
|
||||
// committee = get_beacon_committee(state, data.slot, data.index)
|
||||
// assert len(attestation.aggregation_bits) == len(committee)
|
||||
@@ -67,23 +72,27 @@ func ProcessAttestation(
|
||||
beaconState *stateTrie.BeaconState,
|
||||
att *ethpb.Attestation,
|
||||
) (*stateTrie.BeaconState, error) {
|
||||
beaconState, err := ProcessAttestationNoVerify(ctx, beaconState, att)
|
||||
beaconState, err := ProcessAttestationNoVerifySignature(ctx, beaconState, att)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return beaconState, VerifyAttestation(ctx, beaconState, att)
|
||||
return beaconState, VerifyAttestationSignature(ctx, beaconState, att)
|
||||
}
|
||||
|
||||
// ProcessAttestationsNoVerify applies processing operations to a block's inner attestation
|
||||
// ProcessAttestationsNoVerifySignature applies processing operations to a block's inner attestation
|
||||
// records. The only difference would be that the attestation signature would not be verified.
|
||||
func ProcessAttestationsNoVerify(
|
||||
func ProcessAttestationsNoVerifySignature(
|
||||
ctx context.Context,
|
||||
beaconState *stateTrie.BeaconState,
|
||||
body *ethpb.BeaconBlockBody,
|
||||
b *ethpb.SignedBeaconBlock,
|
||||
) (*stateTrie.BeaconState, error) {
|
||||
if b.Block == nil || b.Block.Body == nil {
|
||||
return nil, errors.New("block and block body can't be nil")
|
||||
}
|
||||
body := b.Block.Body
|
||||
var err error
|
||||
for idx, attestation := range body.Attestations {
|
||||
beaconState, err = ProcessAttestationNoVerify(ctx, beaconState, attestation)
|
||||
beaconState, err = ProcessAttestationNoVerifySignature(ctx, beaconState, attestation)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not verify attestation at index %d in block", idx)
|
||||
}
|
||||
@@ -91,14 +100,14 @@ func ProcessAttestationsNoVerify(
|
||||
return beaconState, nil
|
||||
}
|
||||
|
||||
// ProcessAttestationNoVerify processes the attestation without verifying the attestation signature. This
|
||||
// ProcessAttestationNoVerifySignature processes the attestation without verifying the attestation signature. This
|
||||
// method is used to validate attestations whose signatures have already been verified.
|
||||
func ProcessAttestationNoVerify(
|
||||
func ProcessAttestationNoVerifySignature(
|
||||
ctx context.Context,
|
||||
beaconState *stateTrie.BeaconState,
|
||||
att *ethpb.Attestation,
|
||||
) (*stateTrie.BeaconState, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "core.ProcessAttestationNoVerify")
|
||||
ctx, span := trace.StartSpan(ctx, "core.ProcessAttestationNoVerifySignature")
|
||||
defer span.End()
|
||||
|
||||
if att == nil || att.Data == nil || att.Data.Target == nil {
|
||||
@@ -144,6 +153,14 @@ func ProcessAttestationNoVerify(
|
||||
params.BeaconConfig().SlotsPerEpoch,
|
||||
)
|
||||
}
|
||||
activeValidatorCount, err := helpers.ActiveValidatorCount(beaconState, att.Data.Target.Epoch)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c := helpers.SlotCommitteeCount(activeValidatorCount)
|
||||
if att.Data.CommitteeIndex > c {
|
||||
return nil, fmt.Errorf("committee index %d >= committee count %d", att.Data.CommitteeIndex, c)
|
||||
}
|
||||
|
||||
if err := helpers.VerifyAttestationBitfieldLengths(beaconState, att); err != nil {
|
||||
return nil, errors.Wrap(err, "could not verify attestation bitfields")
|
||||
@@ -188,9 +205,87 @@ func ProcessAttestationNoVerify(
|
||||
return nil, fmt.Errorf("expected target epoch %d, received %d", ffgTargetEpoch, data.Target.Epoch)
|
||||
}
|
||||
|
||||
// Verify attesting indices are correct.
|
||||
committee, err := helpers.BeaconCommitteeFromState(beaconState, att.Data.Slot, att.Data.CommitteeIndex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
indexedAtt := attestationutil.ConvertToIndexed(ctx, att, committee)
|
||||
if err := attestationutil.IsValidAttestationIndices(ctx, indexedAtt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return beaconState, nil
|
||||
}
|
||||
|
||||
// VerifyAttestationsSignatures will verify the signatures of the provided attestations. This method performs
|
||||
// a single BLS verification call to verify the signatures of all of the provided attestations. All
|
||||
// of the provided attestations must have valid signatures or this method will return an error.
|
||||
// This method does not determine which attestation signature is invalid, only that one or more
|
||||
// attestation signatures were not valid.
|
||||
func VerifyAttestationsSignatures(ctx context.Context, beaconState *stateTrie.BeaconState, b *ethpb.SignedBeaconBlock) error {
|
||||
ctx, span := trace.StartSpan(ctx, "core.VerifyAttestationsSignatures")
|
||||
defer span.End()
|
||||
atts := b.Block.Body.Attestations
|
||||
span.AddAttributes(trace.Int64Attribute("attestations", int64(len(atts))))
|
||||
|
||||
if len(atts) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
fork := beaconState.Fork()
|
||||
gvr := beaconState.GenesisValidatorRoot()
|
||||
dt := params.BeaconConfig().DomainBeaconAttester
|
||||
|
||||
// Split attestations by fork. Note: the signature domain will differ based on the fork.
|
||||
var preForkAtts []*ethpb.Attestation
|
||||
var postForkAtts []*ethpb.Attestation
|
||||
for _, a := range atts {
|
||||
if helpers.SlotToEpoch(a.Data.Slot) < fork.Epoch {
|
||||
preForkAtts = append(preForkAtts, a)
|
||||
} else {
|
||||
postForkAtts = append(postForkAtts, a)
|
||||
}
|
||||
}
|
||||
|
||||
// Check attestations from before the fork.
|
||||
if fork.Epoch > 0 { // Check to prevent underflow.
|
||||
prevDomain, err := helpers.Domain(fork, fork.Epoch-1, dt, gvr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := verifyAttestationsSigWithDomain(ctx, beaconState, preForkAtts, prevDomain); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if len(preForkAtts) > 0 {
|
||||
// This is a sanity check that preForkAtts were not ignored when fork.Epoch == 0. This
|
||||
// condition is not possible, but it doesn't hurt to check anyway.
|
||||
return errors.New("some attestations were not verified from previous fork before genesis")
|
||||
}
|
||||
|
||||
// Then check attestations from after the fork.
|
||||
currDomain, err := helpers.Domain(fork, fork.Epoch, dt, gvr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return verifyAttestationsSigWithDomain(ctx, beaconState, postForkAtts, currDomain)
|
||||
}
|
||||
|
||||
// VerifyAttestationSignature converts and attestation into an indexed attestation and verifies
|
||||
// the signature in that attestation.
|
||||
func VerifyAttestationSignature(ctx context.Context, beaconState *stateTrie.BeaconState, att *ethpb.Attestation) error {
|
||||
if att == nil || att.Data == nil || att.AggregationBits.Count() == 0 {
|
||||
return fmt.Errorf("nil or missing attestation data: %v", att)
|
||||
}
|
||||
committee, err := helpers.BeaconCommitteeFromState(beaconState, att.Data.Slot, att.Data.CommitteeIndex)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
indexedAtt := attestationutil.ConvertToIndexed(ctx, att, committee)
|
||||
return VerifyIndexedAttestation(ctx, beaconState, indexedAtt)
|
||||
}
|
||||
|
||||
// VerifyIndexedAttestation determines the validity of an indexed attestation.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
@@ -231,76 +326,9 @@ func VerifyIndexedAttestation(ctx context.Context, beaconState *stateTrie.Beacon
|
||||
return attestationutil.VerifyIndexedAttestationSig(ctx, indexedAtt, pubkeys, domain)
|
||||
}
|
||||
|
||||
// VerifyAttestation converts and attestation into an indexed attestation and verifies
|
||||
// the signature in that attestation.
|
||||
func VerifyAttestation(ctx context.Context, beaconState *stateTrie.BeaconState, att *ethpb.Attestation) error {
|
||||
if att == nil || att.Data == nil {
|
||||
return fmt.Errorf("nil or missing attestation data: %v", att)
|
||||
}
|
||||
committee, err := helpers.BeaconCommitteeFromState(beaconState, att.Data.Slot, att.Data.CommitteeIndex)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
indexedAtt := attestationutil.ConvertToIndexed(ctx, att, committee)
|
||||
return VerifyIndexedAttestation(ctx, beaconState, indexedAtt)
|
||||
}
|
||||
|
||||
// VerifyAttestations will verify the signatures of the provided attestations. This method performs
|
||||
// a single BLS verification call to verify the signatures of all of the provided attestations. All
|
||||
// of the provided attestations must have valid signatures or this method will return an error.
|
||||
// This method does not determine which attestation signature is invalid, only that one or more
|
||||
// attestation signatures were not valid.
|
||||
func VerifyAttestations(ctx context.Context, beaconState *stateTrie.BeaconState, atts []*ethpb.Attestation) error {
|
||||
ctx, span := trace.StartSpan(ctx, "core.VerifyAttestations")
|
||||
defer span.End()
|
||||
span.AddAttributes(trace.Int64Attribute("attestations", int64(len(atts))))
|
||||
|
||||
if len(atts) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
fork := beaconState.Fork()
|
||||
gvr := beaconState.GenesisValidatorRoot()
|
||||
dt := params.BeaconConfig().DomainBeaconAttester
|
||||
|
||||
// Split attestations by fork. Note: the signature domain will differ based on the fork.
|
||||
var preForkAtts []*ethpb.Attestation
|
||||
var postForkAtts []*ethpb.Attestation
|
||||
for _, a := range atts {
|
||||
if helpers.SlotToEpoch(a.Data.Slot) < fork.Epoch {
|
||||
preForkAtts = append(preForkAtts, a)
|
||||
} else {
|
||||
postForkAtts = append(postForkAtts, a)
|
||||
}
|
||||
}
|
||||
|
||||
// Check attestations from before the fork.
|
||||
if fork.Epoch > 0 { // Check to prevent underflow.
|
||||
prevDomain, err := helpers.Domain(fork, fork.Epoch-1, dt, gvr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := verifyAttestationsWithDomain(ctx, beaconState, preForkAtts, prevDomain); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if len(preForkAtts) > 0 {
|
||||
// This is a sanity check that preForkAtts were not ignored when fork.Epoch == 0. This
|
||||
// condition is not possible, but it doesn't hurt to check anyway.
|
||||
return errors.New("some attestations were not verified from previous fork before genesis")
|
||||
}
|
||||
|
||||
// Then check attestations from after the fork.
|
||||
currDomain, err := helpers.Domain(fork, fork.Epoch, dt, gvr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return verifyAttestationsWithDomain(ctx, beaconState, postForkAtts, currDomain)
|
||||
}
|
||||
|
||||
// Inner method to verify attestations. This abstraction allows for the domain to be provided as an
|
||||
// argument.
|
||||
func verifyAttestationsWithDomain(ctx context.Context, beaconState *stateTrie.BeaconState, atts []*ethpb.Attestation, domain []byte) error {
|
||||
func verifyAttestationsSigWithDomain(ctx context.Context, beaconState *stateTrie.BeaconState, atts []*ethpb.Attestation, domain []byte) error {
|
||||
if len(atts) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -308,7 +336,7 @@ func verifyAttestationsWithDomain(ctx context.Context, beaconState *stateTrie.Be
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
verify, err := bls.VerifyMultipleSignatures(set.Signatures, set.Messages, set.PublicKeys)
|
||||
verify, err := set.Verify()
|
||||
if err != nil {
|
||||
return errors.Errorf("got error in multiple verification: %v", err)
|
||||
}
|
||||
@@ -317,3 +345,35 @@ func verifyAttestationsWithDomain(ctx context.Context, beaconState *stateTrie.Be
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// VerifyAttSigUseCheckPt uses the checkpoint info object to verify attestation signature.
|
||||
func VerifyAttSigUseCheckPt(ctx context.Context, c *pb.CheckPtInfo, att *ethpb.Attestation) error {
|
||||
if att == nil || att.Data == nil || att.AggregationBits.Count() == 0 {
|
||||
return fmt.Errorf("nil or missing attestation data: %v", att)
|
||||
}
|
||||
seed := bytesutil.ToBytes32(c.Seed)
|
||||
committee, err := helpers.BeaconCommittee(c.ActiveIndices, seed, att.Data.Slot, att.Data.CommitteeIndex)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
indexedAtt := attestationutil.ConvertToIndexed(ctx, att, committee)
|
||||
if err := attestationutil.IsValidAttestationIndices(ctx, indexedAtt); err != nil {
|
||||
return err
|
||||
}
|
||||
domain, err := helpers.Domain(c.Fork, indexedAtt.Data.Target.Epoch, params.BeaconConfig().DomainBeaconAttester, c.GenesisRoot)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
indices := indexedAtt.AttestingIndices
|
||||
pubkeys := []bls.PublicKey{}
|
||||
for i := 0; i < len(indices); i++ {
|
||||
pubkeyAtIdx := c.PubKeys[indices[i]]
|
||||
pk, err := bls.PublicKeyFromBytes(pubkeyAtIdx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not deserialize validator public key")
|
||||
}
|
||||
pubkeys = append(pubkeys, pk)
|
||||
}
|
||||
|
||||
return attestationutil.VerifyIndexedAttestationSig(ctx, indexedAtt, pubkeys, domain)
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -35,8 +35,13 @@ import (
|
||||
func ProcessAttesterSlashings(
|
||||
ctx context.Context,
|
||||
beaconState *stateTrie.BeaconState,
|
||||
body *ethpb.BeaconBlockBody,
|
||||
b *ethpb.SignedBeaconBlock,
|
||||
) (*stateTrie.BeaconState, error) {
|
||||
if b.Block == nil || b.Block.Body == nil {
|
||||
return nil, errors.New("block and block body can't be nil")
|
||||
}
|
||||
|
||||
body := b.Block.Body
|
||||
for idx, slashing := range body.AttesterSlashings {
|
||||
if err := VerifyAttesterSlashing(ctx, beaconState, slashing); err != nil {
|
||||
return nil, errors.Wrapf(err, "could not verify attester slashing %d", idx)
|
||||
@@ -48,13 +53,13 @@ func ProcessAttesterSlashings(
|
||||
currentEpoch := helpers.SlotToEpoch(beaconState.Slot())
|
||||
var err error
|
||||
var slashedAny bool
|
||||
var val *ethpb.Validator
|
||||
var val *stateTrie.ReadOnlyValidator
|
||||
for _, validatorIndex := range slashableIndices {
|
||||
val, err = beaconState.ValidatorAtIndex(validatorIndex)
|
||||
val, err = beaconState.ValidatorAtIndexReadOnly(validatorIndex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if helpers.IsSlashableValidator(val, currentEpoch) {
|
||||
if helpers.IsSlashableValidator(val.ActivationEpoch(), val.WithdrawableEpoch(), val.Slashed(), currentEpoch) {
|
||||
beaconState, err = v.SlashValidator(beaconState, validatorIndex)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not slash validator index %d",
|
||||
|
||||
@@ -3,7 +3,6 @@ package blocks_test
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
@@ -12,28 +11,29 @@ import (
|
||||
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
func TestSlashableAttestationData_CanSlash(t *testing.T) {
|
||||
att1 := ðpb.AttestationData{
|
||||
Target: ðpb.Checkpoint{Epoch: 1},
|
||||
Source: ðpb.Checkpoint{Root: []byte{'A'}},
|
||||
Target: ðpb.Checkpoint{Epoch: 1, Root: make([]byte, 32)},
|
||||
Source: ðpb.Checkpoint{Root: bytesutil.PadTo([]byte{'A'}, 32)},
|
||||
BeaconBlockRoot: make([]byte, 32),
|
||||
}
|
||||
att2 := ðpb.AttestationData{
|
||||
Target: ðpb.Checkpoint{Epoch: 1},
|
||||
Source: ðpb.Checkpoint{Root: []byte{'B'}},
|
||||
}
|
||||
if !blocks.IsSlashableAttestationData(att1, att2) {
|
||||
t.Error("atts should have been slashable")
|
||||
Target: ðpb.Checkpoint{Epoch: 1, Root: make([]byte, 32)},
|
||||
Source: ðpb.Checkpoint{Root: bytesutil.PadTo([]byte{'B'}, 32)},
|
||||
BeaconBlockRoot: make([]byte, 32),
|
||||
}
|
||||
assert.Equal(t, true, blocks.IsSlashableAttestationData(att1, att2), "Atts should have been slashable")
|
||||
att1.Target.Epoch = 4
|
||||
att1.Source.Epoch = 2
|
||||
att2.Source.Epoch = 3
|
||||
if !blocks.IsSlashableAttestationData(att1, att2) {
|
||||
t.Error("atts should have been slashable")
|
||||
}
|
||||
assert.Equal(t, true, blocks.IsSlashableAttestationData(att1, att2), "Atts should have been slashable")
|
||||
}
|
||||
|
||||
func TestProcessAttesterSlashings_DataNotSlashable(t *testing.T) {
|
||||
@@ -41,15 +41,19 @@ func TestProcessAttesterSlashings_DataNotSlashable(t *testing.T) {
|
||||
{
|
||||
Attestation_1: ðpb.IndexedAttestation{
|
||||
Data: ðpb.AttestationData{
|
||||
Source: ðpb.Checkpoint{Epoch: 0},
|
||||
Target: ðpb.Checkpoint{Epoch: 0},
|
||||
Source: ðpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
|
||||
Target: ðpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
|
||||
BeaconBlockRoot: make([]byte, 32),
|
||||
},
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
Attestation_2: ðpb.IndexedAttestation{
|
||||
Data: ðpb.AttestationData{
|
||||
Source: ðpb.Checkpoint{Epoch: 1},
|
||||
Target: ðpb.Checkpoint{Epoch: 1},
|
||||
Source: ðpb.Checkpoint{Epoch: 1, Root: make([]byte, 32)},
|
||||
Target: ðpb.Checkpoint{Epoch: 1, Root: make([]byte, 32)},
|
||||
BeaconBlockRoot: make([]byte, 32),
|
||||
},
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -60,20 +64,16 @@ func TestProcessAttesterSlashings_DataNotSlashable(t *testing.T) {
|
||||
Validators: registry,
|
||||
Slot: currentSlot,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
block := ðpb.BeaconBlock{
|
||||
require.NoError(t, err)
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block = ðpb.BeaconBlock{
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
AttesterSlashings: slashings,
|
||||
},
|
||||
}
|
||||
want := fmt.Sprint("attestations are not slashable")
|
||||
|
||||
_, err = blocks.ProcessAttesterSlashings(context.Background(), beaconState, block.Body)
|
||||
if err == nil || !strings.Contains(err.Error(), want) {
|
||||
t.Errorf("Expected %s, received %v", want, err)
|
||||
}
|
||||
_, err = blocks.ProcessAttesterSlashings(context.Background(), beaconState, b)
|
||||
assert.ErrorContains(t, want, err)
|
||||
}
|
||||
|
||||
func TestProcessAttesterSlashings_IndexedAttestationFailedToVerify(t *testing.T) {
|
||||
@@ -84,40 +84,41 @@ func TestProcessAttesterSlashings_IndexedAttestationFailedToVerify(t *testing.T)
|
||||
Validators: registry,
|
||||
Slot: currentSlot,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
slashings := []*ethpb.AttesterSlashing{
|
||||
{
|
||||
Attestation_1: ðpb.IndexedAttestation{
|
||||
Data: ðpb.AttestationData{
|
||||
Source: ðpb.Checkpoint{Epoch: 1},
|
||||
Target: ðpb.Checkpoint{Epoch: 0},
|
||||
Source: ðpb.Checkpoint{Epoch: 1, Root: make([]byte, 32)},
|
||||
Target: ðpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
|
||||
BeaconBlockRoot: make([]byte, 32),
|
||||
},
|
||||
AttestingIndices: make([]uint64, params.BeaconConfig().MaxValidatorsPerCommittee+1),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
Attestation_2: ðpb.IndexedAttestation{
|
||||
Data: ðpb.AttestationData{
|
||||
Source: ðpb.Checkpoint{Epoch: 0},
|
||||
Target: ðpb.Checkpoint{Epoch: 0},
|
||||
Source: ðpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
|
||||
Target: ðpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
|
||||
BeaconBlockRoot: make([]byte, 32),
|
||||
},
|
||||
AttestingIndices: make([]uint64, params.BeaconConfig().MaxValidatorsPerCommittee+1),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
block := ðpb.BeaconBlock{
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block = ðpb.BeaconBlock{
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
AttesterSlashings: slashings,
|
||||
},
|
||||
}
|
||||
|
||||
want := fmt.Sprint("validator indices count exceeds MAX_VALIDATORS_PER_COMMITTEE")
|
||||
_, err = blocks.ProcessAttesterSlashings(context.Background(), beaconState, block.Body)
|
||||
if err == nil || !strings.Contains(err.Error(), want) {
|
||||
t.Errorf("Expected %s, received %v", want, err)
|
||||
}
|
||||
_, err = blocks.ProcessAttesterSlashings(context.Background(), beaconState, b)
|
||||
assert.ErrorContains(t, want, err)
|
||||
}
|
||||
|
||||
func TestProcessAttesterSlashings_AppliesCorrectStatus(t *testing.T) {
|
||||
@@ -128,39 +129,35 @@ func TestProcessAttesterSlashings_AppliesCorrectStatus(t *testing.T) {
|
||||
|
||||
att1 := ðpb.IndexedAttestation{
|
||||
Data: ðpb.AttestationData{
|
||||
Source: ðpb.Checkpoint{Epoch: 1},
|
||||
Target: ðpb.Checkpoint{Epoch: 0},
|
||||
Source: ðpb.Checkpoint{Epoch: 1, Root: make([]byte, 32)},
|
||||
Target: ðpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
|
||||
BeaconBlockRoot: make([]byte, 32),
|
||||
},
|
||||
AttestingIndices: []uint64{0, 1},
|
||||
}
|
||||
domain, err := helpers.Domain(beaconState.Fork(), 0, params.BeaconConfig().DomainBeaconAttester, beaconState.GenesisValidatorRoot())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
signingRoot, err := helpers.ComputeSigningRoot(att1.Data, domain)
|
||||
if err != nil {
|
||||
t.Errorf("Could not get signing root of beacon block header: %v", err)
|
||||
}
|
||||
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()[:]
|
||||
att1.Signature = aggregateSig.Marshal()
|
||||
|
||||
att2 := ðpb.IndexedAttestation{
|
||||
Data: ðpb.AttestationData{
|
||||
Source: ðpb.Checkpoint{Epoch: 0},
|
||||
Target: ðpb.Checkpoint{Epoch: 0},
|
||||
Source: ðpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
|
||||
Target: ðpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
|
||||
BeaconBlockRoot: make([]byte, 32),
|
||||
},
|
||||
AttestingIndices: []uint64{0, 1},
|
||||
}
|
||||
signingRoot, err = helpers.ComputeSigningRoot(att2.Data, domain)
|
||||
if err != nil {
|
||||
t.Errorf("Could not get signing root of beacon block header: %v", err)
|
||||
}
|
||||
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()[:]
|
||||
att2.Signature = aggregateSig.Marshal()
|
||||
|
||||
slashings := []*ethpb.AttesterSlashing{
|
||||
{
|
||||
@@ -170,20 +167,17 @@ func TestProcessAttesterSlashings_AppliesCorrectStatus(t *testing.T) {
|
||||
}
|
||||
|
||||
currentSlot := 2 * params.BeaconConfig().SlotsPerEpoch
|
||||
if err := beaconState.SetSlot(currentSlot); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, beaconState.SetSlot(currentSlot))
|
||||
|
||||
block := ðpb.BeaconBlock{
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block = ðpb.BeaconBlock{
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
AttesterSlashings: slashings,
|
||||
},
|
||||
}
|
||||
|
||||
newState, err := blocks.ProcessAttesterSlashings(context.Background(), beaconState, block.Body)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
newState, err := blocks.ProcessAttesterSlashings(context.Background(), beaconState, b)
|
||||
require.NoError(t, err)
|
||||
newRegistry := newState.Validators()
|
||||
|
||||
// Given the intersection of slashable indices is [1], only validator
|
||||
|
||||
@@ -6,13 +6,12 @@ import (
|
||||
|
||||
fuzz "github.com/google/gofuzz"
|
||||
eth "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
beaconstate "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
ethereum_beacon_p2p_v1 "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
|
||||
//"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
beaconstate "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
ethereum_beacon_p2p_v1 "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
func TestFuzzProcessAttestationNoVerify_10000(t *testing.T) {
|
||||
@@ -25,7 +24,8 @@ func TestFuzzProcessAttestationNoVerify_10000(t *testing.T) {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(att)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
_, err = ProcessAttestationNoVerify(ctx, s, att)
|
||||
require.NoError(t, err)
|
||||
_, err = ProcessAttestationNoVerifySignature(ctx, s, att)
|
||||
_ = err
|
||||
}
|
||||
}
|
||||
@@ -40,7 +40,8 @@ func TestFuzzProcessBlockHeader_10000(t *testing.T) {
|
||||
fuzzer.Fuzz(block)
|
||||
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
_, err = ProcessBlockHeader(s, block)
|
||||
require.NoError(t, err)
|
||||
_, err = ProcessBlockHeader(context.Background(), s, block)
|
||||
_ = err
|
||||
}
|
||||
}
|
||||
@@ -63,6 +64,7 @@ func TestFuzzverifyDepositDataSigningRoot_10000(t *testing.T) {
|
||||
fuzzer.Fuzz(&s)
|
||||
fuzzer.Fuzz(&d)
|
||||
err := verifySignature(ba, pubkey[:], sig[:], domain[:])
|
||||
_ = err
|
||||
err = verifySignature(ba, p, s, d)
|
||||
_ = err
|
||||
}
|
||||
@@ -70,14 +72,14 @@ func TestFuzzverifyDepositDataSigningRoot_10000(t *testing.T) {
|
||||
|
||||
func TestFuzzProcessEth1DataInBlock_10000(t *testing.T) {
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
block := ð.BeaconBlock{}
|
||||
b := ð.SignedBeaconBlock{}
|
||||
state := &stateTrie.BeaconState{}
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(block)
|
||||
s, err := ProcessEth1DataInBlock(state, block)
|
||||
fuzzer.Fuzz(b)
|
||||
s, err := ProcessEth1DataInBlock(context.Background(), state, b)
|
||||
if err != nil && s != nil {
|
||||
t.Fatalf("state should be nil on err. found: %v on error: %v for state: %v and block: %v", s, err, state, block)
|
||||
t.Fatalf("state should be nil on err. found: %v on error: %v for state: %v and block: %v", s, err, state, b)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -105,6 +107,7 @@ func TestFuzzEth1DataHasEnoughSupport_10000(t *testing.T) {
|
||||
s, err := beaconstate.InitializeFromProto(ðereum_beacon_p2p_v1.BeaconState{
|
||||
Eth1DataVotes: stateVotes,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
_, err = Eth1DataHasEnoughSupport(s, eth1data)
|
||||
_ = err
|
||||
}
|
||||
@@ -120,6 +123,7 @@ func TestFuzzProcessBlockHeaderNoVerify_10000(t *testing.T) {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(block)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
require.NoError(t, err)
|
||||
_, err = ProcessBlockHeaderNoVerify(s, block)
|
||||
_ = err
|
||||
}
|
||||
@@ -128,15 +132,16 @@ func TestFuzzProcessBlockHeaderNoVerify_10000(t *testing.T) {
|
||||
func TestFuzzProcessRandao_10000(t *testing.T) {
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
state := ðereum_beacon_p2p_v1.BeaconState{}
|
||||
blockBody := ð.BeaconBlockBody{}
|
||||
b := ð.SignedBeaconBlock{}
|
||||
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(blockBody)
|
||||
fuzzer.Fuzz(b)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
r, err := ProcessRandao(s, blockBody)
|
||||
require.NoError(t, err)
|
||||
r, err := ProcessRandao(context.Background(), s, b)
|
||||
if err != nil && r != nil {
|
||||
t.Fatalf("return value should be nil on err. found: %v on error: %v for state: %v and block: %v", r, err, state, blockBody)
|
||||
t.Fatalf("return value should be nil on err. found: %v on error: %v for state: %v and block: %v", r, err, state, b)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -150,6 +155,7 @@ func TestFuzzProcessRandaoNoVerify_10000(t *testing.T) {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(blockBody)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
require.NoError(t, err)
|
||||
r, err := ProcessRandaoNoVerify(s, blockBody)
|
||||
if err != nil && r != nil {
|
||||
t.Fatalf("return value should be nil on err. found: %v on error: %v for state: %v and block: %v", r, err, state, blockBody)
|
||||
@@ -160,15 +166,16 @@ func TestFuzzProcessRandaoNoVerify_10000(t *testing.T) {
|
||||
func TestFuzzProcessProposerSlashings_10000(t *testing.T) {
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
state := ðereum_beacon_p2p_v1.BeaconState{}
|
||||
blockBody := ð.BeaconBlockBody{}
|
||||
b := ð.SignedBeaconBlock{}
|
||||
ctx := context.Background()
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(blockBody)
|
||||
fuzzer.Fuzz(b)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
r, err := ProcessProposerSlashings(ctx, s, blockBody)
|
||||
require.NoError(t, err)
|
||||
r, err := ProcessProposerSlashings(ctx, s, b)
|
||||
if err != nil && r != nil {
|
||||
t.Fatalf("return value should be nil on err. found: %v on error: %v for state: %v and block: %v", r, err, state, blockBody)
|
||||
t.Fatalf("return value should be nil on err. found: %v on error: %v for state: %v and block: %v", r, err, state, b)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -181,6 +188,7 @@ func TestFuzzVerifyProposerSlashing_10000(t *testing.T) {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(proposerSlashing)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
require.NoError(t, err)
|
||||
err = VerifyProposerSlashing(s, proposerSlashing)
|
||||
_ = err
|
||||
}
|
||||
@@ -189,15 +197,16 @@ func TestFuzzVerifyProposerSlashing_10000(t *testing.T) {
|
||||
func TestFuzzProcessAttesterSlashings_10000(t *testing.T) {
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
state := ðereum_beacon_p2p_v1.BeaconState{}
|
||||
blockBody := ð.BeaconBlockBody{}
|
||||
b := ð.SignedBeaconBlock{}
|
||||
ctx := context.Background()
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(blockBody)
|
||||
fuzzer.Fuzz(b)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
r, err := ProcessAttesterSlashings(ctx, s, blockBody)
|
||||
require.NoError(t, err)
|
||||
r, err := ProcessAttesterSlashings(ctx, s, b)
|
||||
if err != nil && r != nil {
|
||||
t.Fatalf("return value should be nil on err. found: %v on error: %v for state: %v and block: %v", r, err, state, blockBody)
|
||||
t.Fatalf("return value should be nil on err. found: %v on error: %v for state: %v and block: %v", r, err, state, b)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -211,6 +220,7 @@ func TestFuzzVerifyAttesterSlashing_10000(t *testing.T) {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(attesterSlashing)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
require.NoError(t, err)
|
||||
err = VerifyAttesterSlashing(ctx, s, attesterSlashing)
|
||||
_ = err
|
||||
}
|
||||
@@ -241,15 +251,16 @@ func TestFuzzslashableAttesterIndices_10000(t *testing.T) {
|
||||
func TestFuzzProcessAttestations_10000(t *testing.T) {
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
state := ðereum_beacon_p2p_v1.BeaconState{}
|
||||
blockBody := ð.BeaconBlockBody{}
|
||||
b := ð.SignedBeaconBlock{}
|
||||
ctx := context.Background()
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(blockBody)
|
||||
fuzzer.Fuzz(b)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
r, err := ProcessAttestations(ctx, s, blockBody)
|
||||
require.NoError(t, err)
|
||||
r, err := ProcessAttestations(ctx, s, b)
|
||||
if err != nil && r != nil {
|
||||
t.Fatalf("return value should be nil on err. found: %v on error: %v for state: %v and block: %v", r, err, state, blockBody)
|
||||
t.Fatalf("return value should be nil on err. found: %v on error: %v for state: %v and block: %v", r, err, state, b)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -257,15 +268,16 @@ func TestFuzzProcessAttestations_10000(t *testing.T) {
|
||||
func TestFuzzProcessAttestationsNoVerify_10000(t *testing.T) {
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
state := ðereum_beacon_p2p_v1.BeaconState{}
|
||||
blockBody := ð.BeaconBlockBody{}
|
||||
b := ð.SignedBeaconBlock{}
|
||||
ctx := context.Background()
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(blockBody)
|
||||
fuzzer.Fuzz(b)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
r, err := ProcessAttestationsNoVerify(ctx, s, blockBody)
|
||||
require.NoError(t, err)
|
||||
r, err := ProcessAttestationsNoVerifySignature(ctx, s, b)
|
||||
if err != nil && r != nil {
|
||||
t.Fatalf("return value should be nil on err. found: %v on error: %v for state: %v and block: %v", r, err, state, blockBody)
|
||||
t.Fatalf("return value should be nil on err. found: %v on error: %v for state: %v and block: %v", r, err, state, b)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -279,6 +291,7 @@ func TestFuzzProcessAttestation_10000(t *testing.T) {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(attestation)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
require.NoError(t, err)
|
||||
r, err := ProcessAttestation(ctx, s, attestation)
|
||||
if err != nil && r != nil {
|
||||
t.Fatalf("return value should be nil on err. found: %v on error: %v for state: %v and block: %v", r, err, state, attestation)
|
||||
@@ -295,6 +308,7 @@ func TestFuzzVerifyIndexedAttestationn_10000(t *testing.T) {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(idxAttestation)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
require.NoError(t, err)
|
||||
err = VerifyIndexedAttestation(ctx, s, idxAttestation)
|
||||
_ = err
|
||||
}
|
||||
@@ -309,7 +323,8 @@ func TestFuzzVerifyAttestation_10000(t *testing.T) {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(attestation)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
err = VerifyAttestation(ctx, s, attestation)
|
||||
require.NoError(t, err)
|
||||
err = VerifyAttestationSignature(ctx, s, attestation)
|
||||
_ = err
|
||||
}
|
||||
}
|
||||
@@ -317,15 +332,16 @@ func TestFuzzVerifyAttestation_10000(t *testing.T) {
|
||||
func TestFuzzProcessDeposits_10000(t *testing.T) {
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
state := ðereum_beacon_p2p_v1.BeaconState{}
|
||||
blockBody := ð.BeaconBlockBody{}
|
||||
b := ð.SignedBeaconBlock{}
|
||||
ctx := context.Background()
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(blockBody)
|
||||
fuzzer.Fuzz(b)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
r, err := ProcessDeposits(ctx, s, blockBody.Deposits)
|
||||
require.NoError(t, err)
|
||||
r, err := ProcessDeposits(ctx, s, b)
|
||||
if err != nil && r != nil {
|
||||
t.Fatalf("return value should be nil on err. found: %v on error: %v for state: %v and block: %v", r, err, state, blockBody)
|
||||
t.Fatalf("return value should be nil on err. found: %v on error: %v for state: %v and block: %v", r, err, state, b)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -340,6 +356,7 @@ func TestFuzzProcessPreGenesisDeposit_10000(t *testing.T) {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(deposit)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
require.NoError(t, err)
|
||||
r, err := ProcessPreGenesisDeposits(ctx, s, []*eth.Deposit{deposit})
|
||||
if err != nil && r != nil {
|
||||
t.Fatalf("return value should be nil on err. found: %v on error: %v for state: %v and block: %v", r, err, state, deposit)
|
||||
@@ -356,6 +373,7 @@ func TestFuzzProcessDeposit_10000(t *testing.T) {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(deposit)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
require.NoError(t, err)
|
||||
r, err := ProcessDeposit(s, deposit, true)
|
||||
if err != nil && r != nil {
|
||||
t.Fatalf("return value should be nil on err. found: %v on error: %v for state: %v and block: %v", r, err, state, deposit)
|
||||
@@ -371,6 +389,7 @@ func TestFuzzverifyDeposit_10000(t *testing.T) {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(deposit)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
require.NoError(t, err)
|
||||
err = verifyDeposit(s, deposit)
|
||||
_ = err
|
||||
}
|
||||
@@ -379,15 +398,16 @@ func TestFuzzverifyDeposit_10000(t *testing.T) {
|
||||
func TestFuzzProcessVoluntaryExits_10000(t *testing.T) {
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
state := ðereum_beacon_p2p_v1.BeaconState{}
|
||||
blockBody := ð.BeaconBlockBody{}
|
||||
b := ð.SignedBeaconBlock{}
|
||||
ctx := context.Background()
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(blockBody)
|
||||
fuzzer.Fuzz(b)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
r, err := ProcessVoluntaryExits(ctx, s, blockBody)
|
||||
require.NoError(t, err)
|
||||
r, err := ProcessVoluntaryExits(ctx, s, b)
|
||||
if err != nil && r != nil {
|
||||
t.Fatalf("return value should be nil on err. found: %v on error: %v for state: %v and block: %v", r, err, state, blockBody)
|
||||
t.Fatalf("return value should be nil on err. found: %v on error: %v for state: %v and block: %v", r, err, state, b)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -395,14 +415,15 @@ func TestFuzzProcessVoluntaryExits_10000(t *testing.T) {
|
||||
func TestFuzzProcessVoluntaryExitsNoVerify_10000(t *testing.T) {
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
state := ðereum_beacon_p2p_v1.BeaconState{}
|
||||
blockBody := ð.BeaconBlockBody{}
|
||||
b := ð.SignedBeaconBlock{}
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(blockBody)
|
||||
fuzzer.Fuzz(b)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(state)
|
||||
r, err := ProcessVoluntaryExitsNoVerify(s, blockBody)
|
||||
require.NoError(t, err)
|
||||
r, err := ProcessVoluntaryExits(context.Background(), s, b)
|
||||
if err != nil && r != nil {
|
||||
t.Fatalf("return value should be nil on err. found: %v on error: %v for state: %v and block: %v", r, err, state, blockBody)
|
||||
t.Fatalf("return value should be nil on err. found: %v on error: %v for state: %v and block: %v", r, err, state, b)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -419,7 +440,7 @@ func TestFuzzVerifyExit_10000(t *testing.T) {
|
||||
fuzzer.Fuzz(val)
|
||||
fuzzer.Fuzz(fork)
|
||||
fuzzer.Fuzz(&slot)
|
||||
err := VerifyExit(val, slot, fork, ve, params.BeaconConfig().ZeroHash[:])
|
||||
err := VerifyExitAndSignature(val, slot, fork, ve, params.BeaconConfig().ZeroHash[:])
|
||||
_ = err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
func TestProcessAttesterSlashings_RegressionSlashableIndices(t *testing.T) {
|
||||
@@ -37,46 +39,44 @@ func TestProcessAttesterSlashings_RegressionSlashableIndices(t *testing.T) {
|
||||
root1 := [32]byte{'d', 'o', 'u', 'b', 'l', 'e', '1'}
|
||||
att1 := ðpb.IndexedAttestation{
|
||||
Data: ðpb.AttestationData{
|
||||
Source: ðpb.Checkpoint{Epoch: 0},
|
||||
Target: ðpb.Checkpoint{Epoch: 0, Root: root1[:]},
|
||||
Source: ðpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
|
||||
Target: ðpb.Checkpoint{Epoch: 0, Root: root1[:]},
|
||||
BeaconBlockRoot: make([]byte, 32),
|
||||
},
|
||||
AttestingIndices: setA,
|
||||
Signature: make([]byte, 96),
|
||||
}
|
||||
domain, err := helpers.Domain(beaconState.Fork(), 0, params.BeaconConfig().DomainBeaconAttester, beaconState.GenesisValidatorRoot())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
signingRoot, err := helpers.ComputeSigningRoot(att1.Data, domain)
|
||||
if err != nil {
|
||||
t.Errorf("Could not get signing root of beacon block header: %v", err)
|
||||
}
|
||||
require.NoError(t, err, "Could not get signing root of beacon block header")
|
||||
aggSigs := []bls.Signature{}
|
||||
for _, index := range setA {
|
||||
sig := privKeys[index].Sign(signingRoot[:])
|
||||
aggSigs = append(aggSigs, sig)
|
||||
}
|
||||
aggregateSig := bls.AggregateSignatures(aggSigs)
|
||||
att1.Signature = aggregateSig.Marshal()[:]
|
||||
att1.Signature = aggregateSig.Marshal()
|
||||
|
||||
root2 := [32]byte{'d', 'o', 'u', 'b', 'l', 'e', '2'}
|
||||
att2 := ðpb.IndexedAttestation{
|
||||
Data: ðpb.AttestationData{
|
||||
Source: ðpb.Checkpoint{Epoch: 0},
|
||||
Target: ðpb.Checkpoint{Epoch: 0, Root: root2[:]},
|
||||
Source: ðpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
|
||||
Target: ðpb.Checkpoint{Epoch: 0, Root: root2[:]},
|
||||
BeaconBlockRoot: make([]byte, 32),
|
||||
},
|
||||
AttestingIndices: setB,
|
||||
Signature: make([]byte, 96),
|
||||
}
|
||||
signingRoot, err = helpers.ComputeSigningRoot(att2.Data, domain)
|
||||
if err != nil {
|
||||
t.Errorf("Could not get signing root of beacon block header: %v", err)
|
||||
}
|
||||
assert.NoError(t, err, "Could not get signing root of beacon block header")
|
||||
aggSigs = []bls.Signature{}
|
||||
for _, index := range setB {
|
||||
sig := privKeys[index].Sign(signingRoot[:])
|
||||
aggSigs = append(aggSigs, sig)
|
||||
}
|
||||
aggregateSig = bls.AggregateSignatures(aggSigs)
|
||||
att2.Signature = aggregateSig.Marshal()[:]
|
||||
att2.Signature = aggregateSig.Marshal()
|
||||
|
||||
slashings := []*ethpb.AttesterSlashing{
|
||||
{
|
||||
@@ -86,20 +86,17 @@ func TestProcessAttesterSlashings_RegressionSlashableIndices(t *testing.T) {
|
||||
}
|
||||
|
||||
currentSlot := 2 * params.BeaconConfig().SlotsPerEpoch
|
||||
if err := beaconState.SetSlot(currentSlot); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, beaconState.SetSlot(currentSlot))
|
||||
|
||||
block := ðpb.BeaconBlock{
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block = ðpb.BeaconBlock{
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
AttesterSlashings: slashings,
|
||||
},
|
||||
}
|
||||
|
||||
newState, err := blocks.ProcessAttesterSlashings(context.Background(), beaconState, block.Body)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
newState, err := blocks.ProcessAttesterSlashings(context.Background(), beaconState, b)
|
||||
require.NoError(t, err)
|
||||
newRegistry := newState.Validators()
|
||||
if !newRegistry[expectedSlashedVal].Slashed {
|
||||
t.Errorf("Validator with index %d was not slashed despite performing a double vote", expectedSlashedVal)
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/depositutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/mathutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/trieutil"
|
||||
@@ -24,7 +25,8 @@ func ProcessPreGenesisDeposits(
|
||||
deposits []*ethpb.Deposit,
|
||||
) (*stateTrie.BeaconState, error) {
|
||||
var err error
|
||||
beaconState, err = ProcessDeposits(ctx, beaconState, deposits)
|
||||
beaconState, err = ProcessDeposits(ctx, beaconState, ðpb.SignedBeaconBlock{
|
||||
Block: ðpb.BeaconBlock{Body: ðpb.BeaconBlockBody{Deposits: deposits}}})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not process deposit")
|
||||
}
|
||||
@@ -65,10 +67,14 @@ func ProcessPreGenesisDeposits(
|
||||
func ProcessDeposits(
|
||||
ctx context.Context,
|
||||
beaconState *stateTrie.BeaconState,
|
||||
deposits []*ethpb.Deposit,
|
||||
b *ethpb.SignedBeaconBlock,
|
||||
) (*stateTrie.BeaconState, error) {
|
||||
var err error
|
||||
if b.Block == nil || b.Block.Body == nil {
|
||||
return nil, errors.New("block and block body can't be nil")
|
||||
}
|
||||
|
||||
deposits := b.Block.Body.Deposits
|
||||
var err error
|
||||
domain, err := helpers.ComputeDomain(params.BeaconConfig().DomainDeposit, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -178,10 +184,8 @@ func ProcessDeposit(beaconState *stateTrie.BeaconState, deposit *ethpb.Deposit,
|
||||
if err := beaconState.AppendBalance(amount); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
if err := helpers.IncreaseBalance(beaconState, index, amount); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else if err := helpers.IncreaseBalance(beaconState, index, amount); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return beaconState, nil
|
||||
@@ -198,7 +202,7 @@ func verifyDeposit(beaconState *stateTrie.BeaconState, deposit *ethpb.Deposit) e
|
||||
}
|
||||
|
||||
receiptRoot := eth1Data.DepositRoot
|
||||
leaf, err := ssz.HashTreeRoot(deposit.Data)
|
||||
leaf, err := deposit.Data.HashTreeRoot()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not tree hash deposit data")
|
||||
}
|
||||
@@ -207,41 +211,20 @@ func verifyDeposit(beaconState *stateTrie.BeaconState, deposit *ethpb.Deposit) e
|
||||
leaf[:],
|
||||
int(beaconState.Eth1DepositIndex()),
|
||||
deposit.Proof,
|
||||
params.BeaconConfig().DepositContractTreeDepth,
|
||||
); !ok {
|
||||
return fmt.Errorf(
|
||||
"deposit merkle branch of deposit root did not verify for root: %#x",
|
||||
receiptRoot,
|
||||
)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Deprecated: This method uses deprecated ssz.SigningRoot.
|
||||
func verifyDepositDataSigningRoot(obj *ethpb.Deposit_Data, pub []byte, signature []byte, domain []byte) error {
|
||||
publicKey, err := bls.PublicKeyFromBytes(pub)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not convert bytes to public key")
|
||||
}
|
||||
sig, err := bls.SignatureFromBytes(signature)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not convert bytes to signature")
|
||||
}
|
||||
root, err := ssz.SigningRoot(obj)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get signing root")
|
||||
}
|
||||
signingData := &pb.SigningData{
|
||||
ObjectRoot: root[:],
|
||||
Domain: domain,
|
||||
}
|
||||
ctrRoot, err := ssz.HashTreeRoot(signingData)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get container root")
|
||||
}
|
||||
if !sig.Verify(publicKey, ctrRoot[:]) {
|
||||
return helpers.ErrSigFailedToVerify
|
||||
}
|
||||
return nil
|
||||
return depositutil.VerifyDepositSignature(obj, domain)
|
||||
}
|
||||
|
||||
func verifyDepositDataWithDomain(ctx context.Context, deps []*ethpb.Deposit, domain []byte) error {
|
||||
@@ -249,7 +232,7 @@ func verifyDepositDataWithDomain(ctx context.Context, deps []*ethpb.Deposit, dom
|
||||
return nil
|
||||
}
|
||||
pks := make([]bls.PublicKey, len(deps))
|
||||
sigs := make([]bls.Signature, len(deps))
|
||||
sigs := make([][]byte, len(deps))
|
||||
msgs := make([][32]byte, len(deps))
|
||||
for i, dep := range deps {
|
||||
if ctx.Err() != nil {
|
||||
@@ -258,17 +241,12 @@ func verifyDepositDataWithDomain(ctx context.Context, deps []*ethpb.Deposit, dom
|
||||
if dep == nil || dep.Data == nil {
|
||||
return errors.New("nil deposit")
|
||||
}
|
||||
|
||||
dpk, err := bls.PublicKeyFromBytes(dep.Data.PublicKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pks[i] = dpk
|
||||
dsig, err := bls.SignatureFromBytes(dep.Data.Signature)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sigs[i] = dsig
|
||||
sigs[i] = dep.Data.Signature
|
||||
root, err := ssz.SigningRoot(dep.Data)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get signing root")
|
||||
@@ -277,7 +255,7 @@ func verifyDepositDataWithDomain(ctx context.Context, deps []*ethpb.Deposit, dom
|
||||
ObjectRoot: root[:],
|
||||
Domain: domain,
|
||||
}
|
||||
ctrRoot, err := ssz.HashTreeRoot(signingData)
|
||||
ctrRoot, err := signingData.HashTreeRoot()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get container root")
|
||||
}
|
||||
|
||||
@@ -2,11 +2,9 @@ package blocks_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/go-ssz"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
@@ -15,6 +13,8 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
"github.com/prysmaticlabs/prysm/shared/trieutil"
|
||||
)
|
||||
|
||||
@@ -22,14 +22,11 @@ func TestProcessDeposits_SameValidatorMultipleDepositsSameBlock(t *testing.T) {
|
||||
// Same validator created 3 valid deposits within the same block
|
||||
testutil.ResetCache()
|
||||
dep, _, err := testutil.DeterministicDepositsAndKeysSameValidator(3)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
eth1Data, err := testutil.DeterministicEth1Data(len(dep))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
block := ðpb.BeaconBlock{
|
||||
require.NoError(t, err)
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block = ðpb.BeaconBlock{
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
// 3 deposits from the same validator
|
||||
Deposits: []*ethpb.Deposit{dep[0], dep[1], dep[2]},
|
||||
@@ -51,43 +48,33 @@ func TestProcessDeposits_SameValidatorMultipleDepositsSameBlock(t *testing.T) {
|
||||
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
newState, err := blocks.ProcessDeposits(context.Background(), beaconState, block.Body.Deposits)
|
||||
if err != nil {
|
||||
t.Fatalf("Expected block deposits to process correctly, received: %v", err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
newState, err := blocks.ProcessDeposits(context.Background(), beaconState, b)
|
||||
require.NoError(t, err, "Expected block deposits to process correctly")
|
||||
|
||||
if len(newState.Validators()) != 2 {
|
||||
t.Errorf("Incorrect validator count. Wanted %d, got %d", 2, len(newState.Validators()))
|
||||
}
|
||||
assert.Equal(t, 2, len(newState.Validators()), "Incorrect validator count")
|
||||
}
|
||||
|
||||
func TestProcessDeposits_MerkleBranchFailsVerification(t *testing.T) {
|
||||
deposit := ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: []byte{1, 2, 3},
|
||||
Signature: make([]byte, 96),
|
||||
PublicKey: bytesutil.PadTo([]byte{1, 2, 3}, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
}
|
||||
leaf, err := ssz.HashTreeRoot(deposit.Data)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
leaf, err := deposit.Data.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
// We then create a merkle branch for the test.
|
||||
depositTrie, err := trieutil.GenerateTrieFromItems([][]byte{leaf[:]}, int(params.BeaconConfig().DepositContractTreeDepth))
|
||||
if err != nil {
|
||||
t.Fatalf("Could not generate trie: %v", err)
|
||||
}
|
||||
require.NoError(t, err, "Could not generate trie")
|
||||
proof, err := depositTrie.MerkleProof(0)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not generate proof: %v", err)
|
||||
}
|
||||
require.NoError(t, err, "Could not generate proof")
|
||||
|
||||
deposit.Proof = proof
|
||||
block := ðpb.BeaconBlock{
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block = ðpb.BeaconBlock{
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
Deposits: []*ethpb.Deposit{deposit},
|
||||
},
|
||||
@@ -98,27 +85,20 @@ func TestProcessDeposits_MerkleBranchFailsVerification(t *testing.T) {
|
||||
BlockHash: []byte{1},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
want := "deposit root did not verify"
|
||||
_, err = blocks.ProcessDeposits(context.Background(), beaconState, block.Body.Deposits)
|
||||
if err == nil || !strings.Contains(err.Error(), want) {
|
||||
t.Errorf("Expected error: %s, received %v", want, err)
|
||||
}
|
||||
_, err = blocks.ProcessDeposits(context.Background(), beaconState, b)
|
||||
assert.ErrorContains(t, want, err)
|
||||
}
|
||||
|
||||
func TestProcessDeposits_AddsNewValidatorDeposit(t *testing.T) {
|
||||
dep, _, err := testutil.DeterministicDepositsAndKeys(1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
eth1Data, err := testutil.DeterministicEth1Data(len(dep))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
block := ðpb.BeaconBlock{
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block = ðpb.BeaconBlock{
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
Deposits: []*ethpb.Deposit{dep[0]},
|
||||
},
|
||||
@@ -139,13 +119,9 @@ func TestProcessDeposits_AddsNewValidatorDeposit(t *testing.T) {
|
||||
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
newState, err := blocks.ProcessDeposits(context.Background(), beaconState, block.Body.Deposits)
|
||||
if err != nil {
|
||||
t.Fatalf("Expected block deposits to process correctly, received: %v", err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
newState, err := blocks.ProcessDeposits(context.Background(), beaconState, b)
|
||||
require.NoError(t, err, "Expected block deposits to process correctly")
|
||||
if newState.Balances()[1] != dep[0].Data.Amount {
|
||||
t.Errorf(
|
||||
"Expected state validator balances index 0 to equal %d, received %d",
|
||||
@@ -159,33 +135,28 @@ func TestProcessDeposits_RepeatedDeposit_IncreasesValidatorBalance(t *testing.T)
|
||||
sk := bls.RandKey()
|
||||
deposit := ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: sk.PublicKey().Marshal(),
|
||||
Amount: 1000,
|
||||
PublicKey: sk.PublicKey().Marshal(),
|
||||
Amount: 1000,
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
}
|
||||
sr, err := helpers.ComputeSigningRoot(deposit.Data, bytesutil.ToBytes(3, 8))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sr, err := helpers.ComputeSigningRoot(deposit.Data, bytesutil.ToBytes(3, 32))
|
||||
require.NoError(t, err)
|
||||
sig := sk.Sign(sr[:])
|
||||
deposit.Data.Signature = sig.Marshal()
|
||||
leaf, err := ssz.HashTreeRoot(deposit.Data)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
leaf, err := deposit.Data.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
// We then create a merkle branch for the test.
|
||||
depositTrie, err := trieutil.GenerateTrieFromItems([][]byte{leaf[:]}, int(params.BeaconConfig().DepositContractTreeDepth))
|
||||
if err != nil {
|
||||
t.Fatalf("Could not generate trie: %v", err)
|
||||
}
|
||||
require.NoError(t, err, "Could not generate trie")
|
||||
proof, err := depositTrie.MerkleProof(0)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not generate proof: %v", err)
|
||||
}
|
||||
require.NoError(t, err, "Could not generate proof")
|
||||
|
||||
deposit.Proof = proof
|
||||
block := ðpb.BeaconBlock{
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block = ðpb.BeaconBlock{
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
Deposits: []*ethpb.Deposit{deposit},
|
||||
},
|
||||
@@ -209,28 +180,18 @@ func TestProcessDeposits_RepeatedDeposit_IncreasesValidatorBalance(t *testing.T)
|
||||
BlockHash: root[:],
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
newState, err := blocks.ProcessDeposits(context.Background(), beaconState, block.Body.Deposits)
|
||||
if err != nil {
|
||||
t.Fatalf("Process deposit failed: %v", err)
|
||||
}
|
||||
if newState.Balances()[1] != 1000+50 {
|
||||
t.Errorf("Expected balance at index 1 to be 1050, received %d", newState.Balances()[1])
|
||||
}
|
||||
require.NoError(t, err)
|
||||
newState, err := blocks.ProcessDeposits(context.Background(), beaconState, b)
|
||||
require.NoError(t, err, "Process deposit failed")
|
||||
assert.Equal(t, uint64(1000+50), newState.Balances()[1], "Expected balance at index 1 to be 1050")
|
||||
}
|
||||
|
||||
func TestProcessDeposit_AddsNewValidatorDeposit(t *testing.T) {
|
||||
//Similar to TestProcessDeposits_AddsNewValidatorDeposit except that this test directly calls ProcessDeposit
|
||||
dep, _, err := testutil.DeterministicDepositsAndKeys(1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
eth1Data, err := testutil.DeterministicEth1Data(len(dep))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
registry := []*ethpb.Validator{
|
||||
{
|
||||
@@ -248,19 +209,11 @@ func TestProcessDeposit_AddsNewValidatorDeposit(t *testing.T) {
|
||||
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
newState, err := blocks.ProcessDeposit(beaconState, dep[0], true)
|
||||
if err != nil {
|
||||
t.Fatalf("Process deposit failed: %v", err)
|
||||
}
|
||||
if len(newState.Validators()) != 2 {
|
||||
t.Errorf("Expected validator list to have length 2, received: %v", len(newState.Validators()))
|
||||
}
|
||||
if len(newState.Balances()) != 2 {
|
||||
t.Fatalf("Expected validator balances list to have length 2, received: %v", len(newState.Balances()))
|
||||
}
|
||||
require.NoError(t, err, "Process deposit failed")
|
||||
assert.Equal(t, 2, len(newState.Validators()), "Expected validator list to have length 2")
|
||||
assert.Equal(t, 2, len(newState.Balances()), "Expected validator balances list to have length 2")
|
||||
if newState.Balances()[1] != dep[0].Data.Amount {
|
||||
t.Errorf(
|
||||
"Expected state validator balances index 1 to equal %d, received %d",
|
||||
@@ -273,14 +226,10 @@ func TestProcessDeposit_AddsNewValidatorDeposit(t *testing.T) {
|
||||
func TestProcessDeposit_SkipsInvalidDeposit(t *testing.T) {
|
||||
// Same test settings as in TestProcessDeposit_AddsNewValidatorDeposit, except that we use an invalid signature
|
||||
dep, _, err := testutil.DeterministicDepositsAndKeys(1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
dep[0].Data.Signature = make([]byte, 96)
|
||||
trie, _, err := testutil.DepositTrieFromDeposits(dep)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
root := trie.Root()
|
||||
eth1Data := ðpb.Eth1Data{
|
||||
DepositRoot: root[:],
|
||||
@@ -302,13 +251,9 @@ func TestProcessDeposit_SkipsInvalidDeposit(t *testing.T) {
|
||||
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
newState, err := blocks.ProcessDeposit(beaconState, dep[0], true)
|
||||
if err != nil {
|
||||
t.Fatalf("Expected invalid block deposit to be ignored without error, received: %v", err)
|
||||
}
|
||||
require.NoError(t, err, "Expected invalid block deposit to be ignored without error")
|
||||
|
||||
if newState.Eth1DepositIndex() != 1 {
|
||||
t.Errorf(
|
||||
|
||||
@@ -2,6 +2,7 @@ package blocks
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
@@ -18,7 +19,8 @@ import (
|
||||
// state.eth1_data_votes.append(body.eth1_data)
|
||||
// if state.eth1_data_votes.count(body.eth1_data) * 2 > EPOCHS_PER_ETH1_VOTING_PERIOD * SLOTS_PER_EPOCH:
|
||||
// state.latest_eth1_data = body.eth1_data
|
||||
func ProcessEth1DataInBlock(beaconState *stateTrie.BeaconState, block *ethpb.BeaconBlock) (*stateTrie.BeaconState, error) {
|
||||
func ProcessEth1DataInBlock(ctx context.Context, beaconState *stateTrie.BeaconState, b *ethpb.SignedBeaconBlock) (*stateTrie.BeaconState, error) {
|
||||
block := b.Block
|
||||
if beaconState == nil {
|
||||
return nil, errors.New("nil state")
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package blocks_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
@@ -9,7 +10,11 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
beaconstate "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
func FakeDeposits(n uint64) []*ethpb.Eth1Data {
|
||||
@@ -17,7 +22,7 @@ func FakeDeposits(n uint64) []*ethpb.Eth1Data {
|
||||
for i := uint64(0); i < n; i++ {
|
||||
deposits[i] = ðpb.Eth1Data{
|
||||
DepositCount: 1,
|
||||
DepositRoot: []byte("root"),
|
||||
DepositRoot: bytesutil.PadTo([]byte("root"), 32),
|
||||
}
|
||||
}
|
||||
return deposits
|
||||
@@ -34,7 +39,7 @@ func TestEth1DataHasEnoughSupport(t *testing.T) {
|
||||
stateVotes: FakeDeposits(4 * params.BeaconConfig().SlotsPerEpoch),
|
||||
data: ðpb.Eth1Data{
|
||||
DepositCount: 1,
|
||||
DepositRoot: []byte("root"),
|
||||
DepositRoot: bytesutil.PadTo([]byte("root"), 32),
|
||||
},
|
||||
hasSupport: true,
|
||||
votingPeriodLength: 7,
|
||||
@@ -42,7 +47,7 @@ func TestEth1DataHasEnoughSupport(t *testing.T) {
|
||||
stateVotes: FakeDeposits(4 * params.BeaconConfig().SlotsPerEpoch),
|
||||
data: ðpb.Eth1Data{
|
||||
DepositCount: 1,
|
||||
DepositRoot: []byte("root"),
|
||||
DepositRoot: bytesutil.PadTo([]byte("root"), 32),
|
||||
},
|
||||
hasSupport: false,
|
||||
votingPeriodLength: 8,
|
||||
@@ -50,7 +55,7 @@ func TestEth1DataHasEnoughSupport(t *testing.T) {
|
||||
stateVotes: FakeDeposits(4 * params.BeaconConfig().SlotsPerEpoch),
|
||||
data: ðpb.Eth1Data{
|
||||
DepositCount: 1,
|
||||
DepositRoot: []byte("root"),
|
||||
DepositRoot: bytesutil.PadTo([]byte("root"), 32),
|
||||
},
|
||||
hasSupport: false,
|
||||
votingPeriodLength: 10,
|
||||
@@ -67,13 +72,9 @@ func TestEth1DataHasEnoughSupport(t *testing.T) {
|
||||
s, err := beaconstate.InitializeFromProto(&pb.BeaconState{
|
||||
Eth1DataVotes: tt.stateVotes,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
result, err := blocks.Eth1DataHasEnoughSupport(s, tt.data)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
if result != tt.hasSupport {
|
||||
t.Errorf(
|
||||
@@ -152,9 +153,7 @@ func TestAreEth1DataEqual(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := blocks.AreEth1DataEqual(tt.args.a, tt.args.b); got != tt.want {
|
||||
t.Errorf("AreEth1DataEqual() = %v, want %v", got, tt.want)
|
||||
}
|
||||
assert.Equal(t, tt.want, blocks.AreEth1DataEqual(tt.args.a, tt.args.b))
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -163,11 +162,10 @@ func TestProcessEth1Data_SetsCorrectly(t *testing.T) {
|
||||
beaconState, err := beaconstate.InitializeFromProto(&pb.BeaconState{
|
||||
Eth1DataVotes: []*ethpb.Eth1Data{},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
block := ðpb.BeaconBlock{
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block = ðpb.BeaconBlock{
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
Eth1Data: ðpb.Eth1Data{
|
||||
DepositRoot: []byte{2},
|
||||
@@ -178,20 +176,18 @@ func TestProcessEth1Data_SetsCorrectly(t *testing.T) {
|
||||
|
||||
period := params.BeaconConfig().EpochsPerEth1VotingPeriod * params.BeaconConfig().SlotsPerEpoch
|
||||
for i := uint64(0); i < period; i++ {
|
||||
beaconState, err = blocks.ProcessEth1DataInBlock(beaconState, block)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
beaconState, err = blocks.ProcessEth1DataInBlock(context.Background(), beaconState, b)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
newETH1DataVotes := beaconState.Eth1DataVotes()
|
||||
if len(newETH1DataVotes) <= 1 {
|
||||
t.Error("Expected new ETH1 data votes to have length > 1")
|
||||
}
|
||||
if !proto.Equal(beaconState.Eth1Data(), beaconstate.CopyETH1Data(block.Body.Eth1Data)) {
|
||||
if !proto.Equal(beaconState.Eth1Data(), beaconstate.CopyETH1Data(b.Block.Body.Eth1Data)) {
|
||||
t.Errorf(
|
||||
"Expected latest eth1 data to have been set to %v, received %v",
|
||||
block.Body.Eth1Data,
|
||||
b.Block.Body.Eth1Data,
|
||||
beaconState.Eth1Data(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -39,8 +39,13 @@ import (
|
||||
func ProcessVoluntaryExits(
|
||||
ctx context.Context,
|
||||
beaconState *stateTrie.BeaconState,
|
||||
body *ethpb.BeaconBlockBody,
|
||||
b *ethpb.SignedBeaconBlock,
|
||||
) (*stateTrie.BeaconState, error) {
|
||||
if b.Block == nil || b.Block.Body == nil {
|
||||
return nil, errors.New("block and block body can't be nil")
|
||||
}
|
||||
|
||||
body := b.Block.Body
|
||||
exits := body.VoluntaryExits
|
||||
for idx, exit := range exits {
|
||||
if exit == nil || exit.Exit == nil {
|
||||
@@ -50,7 +55,7 @@ func ProcessVoluntaryExits(
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := VerifyExit(val, beaconState.Slot(), beaconState.Fork(), exit, beaconState.GenesisValidatorRoot()); err != nil {
|
||||
if err := VerifyExitAndSignature(val, beaconState.Slot(), beaconState.Fork(), exit, beaconState.GenesisValidatorRoot()); err != nil {
|
||||
return nil, errors.Wrapf(err, "could not verify exit %d", idx)
|
||||
}
|
||||
beaconState, err = v.InitiateValidatorExit(beaconState, exit.Exit.ValidatorIndex)
|
||||
@@ -61,19 +66,31 @@ func ProcessVoluntaryExits(
|
||||
return beaconState, nil
|
||||
}
|
||||
|
||||
// ProcessVoluntaryExitsNoVerify processes all the voluntary exits in
|
||||
// ProcessVoluntaryExitsNoVerifySignature processes all the voluntary exits in
|
||||
// a block body, without verifying their BLS signatures.
|
||||
func ProcessVoluntaryExitsNoVerify(
|
||||
// This function is here to satisfy fuzz tests.
|
||||
func ProcessVoluntaryExitsNoVerifySignature(
|
||||
beaconState *stateTrie.BeaconState,
|
||||
body *ethpb.BeaconBlockBody,
|
||||
) (*stateTrie.BeaconState, error) {
|
||||
var err error
|
||||
exits := body.VoluntaryExits
|
||||
|
||||
for idx, exit := range exits {
|
||||
if exit == nil || exit.Exit == nil {
|
||||
return nil, errors.New("nil exit")
|
||||
}
|
||||
val, err := beaconState.ValidatorAtIndexReadOnly(exit.Exit.ValidatorIndex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := verifyExitConditions(val, beaconState.Slot(), exit.Exit); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Validate that fork and genesis root are valid.
|
||||
_, err = helpers.Domain(beaconState.Fork(), exit.Exit.Epoch, params.BeaconConfig().DomainVoluntaryExit, beaconState.GenesisValidatorRoot())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
beaconState, err = v.InitiateValidatorExit(beaconState, exit.Exit.ValidatorIndex)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to process voluntary exit at index %d", idx)
|
||||
@@ -82,7 +99,7 @@ func ProcessVoluntaryExitsNoVerify(
|
||||
return beaconState, nil
|
||||
}
|
||||
|
||||
// VerifyExit implements the spec defined validation for voluntary exits.
|
||||
// VerifyExitAndSignature implements the spec defined validation for voluntary exits.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// def process_voluntary_exit(state: BeaconState, exit: VoluntaryExit) -> None:
|
||||
@@ -101,32 +118,14 @@ func ProcessVoluntaryExitsNoVerify(
|
||||
// # Verify signature
|
||||
// domain = get_domain(state, DOMAIN_VOLUNTARY_EXIT, exit.epoch)
|
||||
// assert bls_verify(validator.pubkey, signing_root(exit), exit.signature, domain)
|
||||
func VerifyExit(validator *stateTrie.ReadOnlyValidator, currentSlot uint64, fork *pb.Fork, signed *ethpb.SignedVoluntaryExit, genesisRoot []byte) error {
|
||||
func VerifyExitAndSignature(validator *stateTrie.ReadOnlyValidator, currentSlot uint64, fork *pb.Fork, signed *ethpb.SignedVoluntaryExit, genesisRoot []byte) error {
|
||||
if signed == nil || signed.Exit == nil {
|
||||
return errors.New("nil exit")
|
||||
}
|
||||
|
||||
exit := signed.Exit
|
||||
currentEpoch := helpers.SlotToEpoch(currentSlot)
|
||||
// Verify the validator is active.
|
||||
if !helpers.IsActiveValidatorUsingTrie(validator, currentEpoch) {
|
||||
return errors.New("non-active validator cannot exit")
|
||||
}
|
||||
// Verify the validator has not yet exited.
|
||||
if validator.ExitEpoch() != params.BeaconConfig().FarFutureEpoch {
|
||||
return fmt.Errorf("validator has already exited at epoch: %v", validator.ExitEpoch())
|
||||
}
|
||||
// Exits must specify an epoch when they become valid; they are not valid before then.
|
||||
if currentEpoch < exit.Epoch {
|
||||
return fmt.Errorf("expected current epoch >= exit epoch, received %d < %d", currentEpoch, exit.Epoch)
|
||||
}
|
||||
// Verify the validator has been active long enough.
|
||||
if currentEpoch < validator.ActivationEpoch()+params.BeaconConfig().ShardCommitteePeriod {
|
||||
return fmt.Errorf(
|
||||
"validator has not been active long enough to exit, wanted epoch %d >= %d",
|
||||
currentEpoch,
|
||||
validator.ActivationEpoch()+params.BeaconConfig().ShardCommitteePeriod,
|
||||
)
|
||||
if err := verifyExitConditions(validator, currentSlot, exit); err != nil {
|
||||
return err
|
||||
}
|
||||
domain, err := helpers.Domain(fork, exit.Epoch, params.BeaconConfig().DomainVoluntaryExit, genesisRoot)
|
||||
if err != nil {
|
||||
@@ -138,3 +137,46 @@ func VerifyExit(validator *stateTrie.ReadOnlyValidator, currentSlot uint64, fork
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// verifyExitConditions implements the spec defined validation for voluntary exits(excluding signatures).
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// def process_voluntary_exit(state: BeaconState, exit: VoluntaryExit) -> None:
|
||||
// """
|
||||
// Process ``VoluntaryExit`` operation.
|
||||
// """
|
||||
// validator = state.validator_registry[exit.validator_index]
|
||||
// # Verify the validator is active
|
||||
// assert is_active_validator(validator, get_current_epoch(state))
|
||||
// # Verify the validator has not yet exited
|
||||
// assert validator.exit_epoch == FAR_FUTURE_EPOCH
|
||||
// # Exits must specify an epoch when they become valid; they are not valid before then
|
||||
// assert get_current_epoch(state) >= exit.epoch
|
||||
// # Verify the validator has been active long enough
|
||||
// assert get_current_epoch(state) >= validator.activation_epoch + SHARD_COMMITTEE_PERIOD
|
||||
func verifyExitConditions(validator *stateTrie.ReadOnlyValidator, currentSlot uint64, exit *ethpb.VoluntaryExit) error {
|
||||
currentEpoch := helpers.SlotToEpoch(currentSlot)
|
||||
// Verify the validator is active.
|
||||
if !helpers.IsActiveValidatorUsingTrie(validator, currentEpoch) {
|
||||
return errors.New("non-active validator cannot exit")
|
||||
}
|
||||
// Verify the validator has not yet submitted an exit.
|
||||
if validator.ExitEpoch() != params.BeaconConfig().FarFutureEpoch {
|
||||
return fmt.Errorf(
|
||||
"validator has already submitted an exit, which will take place at epoch: %v",
|
||||
validator.ExitEpoch())
|
||||
}
|
||||
// Exits must specify an epoch when they become valid; they are not valid before then.
|
||||
if currentEpoch < exit.Epoch {
|
||||
return fmt.Errorf("expected current epoch >= exit epoch, received %d < %d", currentEpoch, exit.Epoch)
|
||||
}
|
||||
// Verify the validator has been active long enough.
|
||||
if currentEpoch < validator.ActivationEpoch()+params.BeaconConfig().ShardCommitteePeriod {
|
||||
return fmt.Errorf(
|
||||
"validator has not been active long enough to exit: %d epochs vs required %d epochs",
|
||||
currentEpoch,
|
||||
validator.ActivationEpoch()+params.BeaconConfig().ShardCommitteePeriod,
|
||||
)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package blocks_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
@@ -12,6 +11,9 @@ import (
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
func TestProcessVoluntaryExits_ValidatorNotActive(t *testing.T) {
|
||||
@@ -30,21 +32,21 @@ func TestProcessVoluntaryExits_ValidatorNotActive(t *testing.T) {
|
||||
state, err := stateTrie.InitializeFromProto(&pb.BeaconState{
|
||||
Validators: registry,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
block := ðpb.BeaconBlock{
|
||||
require.NoError(t, err)
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block = ðpb.BeaconBlock{
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
VoluntaryExits: exits,
|
||||
},
|
||||
}
|
||||
|
||||
want := "non-active validator cannot exit"
|
||||
_, err = blocks.ProcessVoluntaryExits(context.Background(), state, b)
|
||||
assert.ErrorContains(t, want, err)
|
||||
|
||||
_, err = blocks.ProcessVoluntaryExits(context.Background(), state, block.Body)
|
||||
if err == nil || !strings.Contains(err.Error(), want) {
|
||||
t.Errorf("Expected %s, received %v", want, err)
|
||||
}
|
||||
// Check conformance of no verify method.
|
||||
_, err = blocks.ProcessVoluntaryExitsNoVerifySignature(state, b.Block.Body)
|
||||
assert.ErrorContains(t, want, err)
|
||||
}
|
||||
|
||||
func TestProcessVoluntaryExits_InvalidExitEpoch(t *testing.T) {
|
||||
@@ -64,21 +66,21 @@ func TestProcessVoluntaryExits_InvalidExitEpoch(t *testing.T) {
|
||||
Validators: registry,
|
||||
Slot: 0,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
block := ðpb.BeaconBlock{
|
||||
require.NoError(t, err)
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block = ðpb.BeaconBlock{
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
VoluntaryExits: exits,
|
||||
},
|
||||
}
|
||||
|
||||
want := "expected current epoch >= exit epoch"
|
||||
_, err = blocks.ProcessVoluntaryExits(context.Background(), state, b)
|
||||
assert.ErrorContains(t, want, err)
|
||||
|
||||
_, err = blocks.ProcessVoluntaryExits(context.Background(), state, block.Body)
|
||||
if err == nil || !strings.Contains(err.Error(), want) {
|
||||
t.Errorf("Expected %s, received %v", want, err)
|
||||
}
|
||||
// Check conformance of no verify method.
|
||||
_, err = blocks.ProcessVoluntaryExitsNoVerifySignature(state, b.Block.Body)
|
||||
assert.ErrorContains(t, want, err)
|
||||
}
|
||||
|
||||
func TestProcessVoluntaryExits_NotActiveLongEnoughToExit(t *testing.T) {
|
||||
@@ -99,20 +101,47 @@ func TestProcessVoluntaryExits_NotActiveLongEnoughToExit(t *testing.T) {
|
||||
Validators: registry,
|
||||
Slot: 10,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
block := ðpb.BeaconBlock{
|
||||
require.NoError(t, err)
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block = ðpb.BeaconBlock{
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
VoluntaryExits: exits,
|
||||
},
|
||||
}
|
||||
|
||||
want := "validator has not been active long enough to exit"
|
||||
_, err = blocks.ProcessVoluntaryExits(context.Background(), state, block.Body)
|
||||
if err == nil || !strings.Contains(err.Error(), want) {
|
||||
t.Errorf("Expected %s, received %v", want, err)
|
||||
_, err = blocks.ProcessVoluntaryExits(context.Background(), state, b)
|
||||
assert.ErrorContains(t, want, err)
|
||||
}
|
||||
|
||||
func TestProcessVoluntaryExits_ExitAlreadySubmitted(t *testing.T) {
|
||||
exits := []*ethpb.SignedVoluntaryExit{
|
||||
{
|
||||
Exit: ðpb.VoluntaryExit{
|
||||
Epoch: 10,
|
||||
},
|
||||
},
|
||||
}
|
||||
registry := []*ethpb.Validator{
|
||||
{
|
||||
ExitEpoch: 10,
|
||||
},
|
||||
}
|
||||
state, err := stateTrie.InitializeFromProto(&pb.BeaconState{
|
||||
Validators: registry,
|
||||
Slot: 0,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block = ðpb.BeaconBlock{
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
VoluntaryExits: exits,
|
||||
},
|
||||
}
|
||||
|
||||
want := "validator has already submitted an exit, which will take place at epoch: 10"
|
||||
_, err = blocks.ProcessVoluntaryExits(context.Background(), state, b)
|
||||
assert.ErrorContains(t, want, err)
|
||||
}
|
||||
|
||||
func TestProcessVoluntaryExits_AppliesCorrectStatus(t *testing.T) {
|
||||
@@ -138,46 +167,40 @@ func TestProcessVoluntaryExits_AppliesCorrectStatus(t *testing.T) {
|
||||
},
|
||||
Slot: params.BeaconConfig().SlotsPerEpoch * 5,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
err = state.SetSlot(state.Slot() + (params.BeaconConfig().ShardCommitteePeriod * params.BeaconConfig().SlotsPerEpoch))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
priv := bls.RandKey()
|
||||
val, err := state.ValidatorAtIndex(0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
val.PublicKey = priv.PublicKey().Marshal()[:]
|
||||
if err := state.UpdateValidatorAtIndex(0, val); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
domain, err := helpers.Domain(state.Fork(), helpers.CurrentEpoch(state), params.BeaconConfig().DomainVoluntaryExit, state.GenesisValidatorRoot())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
signingRoot, err := helpers.ComputeSigningRoot(exits[0].Exit, domain)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
sig := priv.Sign(signingRoot[:])
|
||||
exits[0].Signature = sig.Marshal()
|
||||
block := ðpb.BeaconBlock{
|
||||
require.NoError(t, err)
|
||||
val.PublicKey = priv.PublicKey().Marshal()
|
||||
require.NoError(t, state.UpdateValidatorAtIndex(0, val))
|
||||
exits[0].Signature, err = helpers.ComputeDomainAndSign(state, helpers.CurrentEpoch(state), exits[0].Exit, params.BeaconConfig().DomainVoluntaryExit, priv)
|
||||
require.NoError(t, err)
|
||||
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block = ðpb.BeaconBlock{
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
VoluntaryExits: exits,
|
||||
},
|
||||
}
|
||||
|
||||
newState, err := blocks.ProcessVoluntaryExits(context.Background(), state, block.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not process exits: %v", err)
|
||||
}
|
||||
stateCopy := state.Copy()
|
||||
newState, err := blocks.ProcessVoluntaryExits(context.Background(), state, b)
|
||||
require.NoError(t, err, "Could not process exits")
|
||||
newRegistry := newState.Validators()
|
||||
if newRegistry[0].ExitEpoch != helpers.ActivationExitEpoch(state.Slot()/params.BeaconConfig().SlotsPerEpoch) {
|
||||
t.Errorf("Expected validator exit epoch to be %d, got %d",
|
||||
helpers.ActivationExitEpoch(state.Slot()/params.BeaconConfig().SlotsPerEpoch), newRegistry[0].ExitEpoch)
|
||||
}
|
||||
|
||||
// Check conformance with NoVerify Exit Method.
|
||||
newState, err = blocks.ProcessVoluntaryExitsNoVerifySignature(stateCopy, b.Block.Body)
|
||||
require.NoError(t, err, "Could not process exits")
|
||||
newRegistry = newState.Validators()
|
||||
if newRegistry[0].ExitEpoch != helpers.ActivationExitEpoch(stateCopy.Slot()/params.BeaconConfig().SlotsPerEpoch) {
|
||||
t.Errorf("Expected validator exit epoch to be %d, got %d",
|
||||
helpers.ActivationExitEpoch(stateCopy.Slot()/params.BeaconConfig().SlotsPerEpoch), newRegistry[0].ExitEpoch)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,19 +4,27 @@ package blocks
|
||||
|
||||
import (
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
// NewGenesisBlock returns the canonical, genesis block for the beacon chain protocol.
|
||||
func NewGenesisBlock(stateRoot []byte) *ethpb.SignedBeaconBlock {
|
||||
zeroHash := params.BeaconConfig().ZeroHash[:]
|
||||
genBlock := ðpb.BeaconBlock{
|
||||
ParentRoot: zeroHash,
|
||||
StateRoot: stateRoot,
|
||||
Body: ðpb.BeaconBlockBody{},
|
||||
}
|
||||
return ðpb.SignedBeaconBlock{
|
||||
Block: genBlock,
|
||||
block := ðpb.SignedBeaconBlock{
|
||||
Block: ðpb.BeaconBlock{
|
||||
ParentRoot: zeroHash,
|
||||
StateRoot: bytesutil.PadTo(stateRoot, 32),
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
RandaoReveal: make([]byte, 96),
|
||||
Eth1Data: ðpb.Eth1Data{
|
||||
DepositRoot: make([]byte, 32),
|
||||
BlockHash: make([]byte, 32),
|
||||
},
|
||||
Graffiti: make([]byte, 32),
|
||||
},
|
||||
},
|
||||
Signature: params.BeaconConfig().EmptySignature[:],
|
||||
}
|
||||
return block
|
||||
}
|
||||
|
||||
@@ -1,21 +1,17 @@
|
||||
package blocks_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
)
|
||||
|
||||
func TestGenesisBlock_InitializedCorrectly(t *testing.T) {
|
||||
stateHash := []byte{0}
|
||||
stateHash := bytesutil.PadTo([]byte{0}, 32)
|
||||
b1 := blocks.NewGenesisBlock(stateHash)
|
||||
|
||||
if b1.Block.ParentRoot == nil {
|
||||
t.Error("genesis block missing ParentHash field")
|
||||
}
|
||||
|
||||
if !bytes.Equal(b1.Block.StateRoot, stateHash) {
|
||||
t.Error("genesis block StateRootHash32 isn't initialized correctly")
|
||||
}
|
||||
assert.NotNil(t, b1.Block.ParentRoot, "Genesis block missing ParentHash field")
|
||||
assert.DeepEqual(t, b1.Block.StateRoot, stateHash, "Genesis block StateRootHash32 isn't initialized correctly")
|
||||
}
|
||||
|
||||
@@ -2,13 +2,13 @@ package blocks
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
@@ -37,6 +37,7 @@ import (
|
||||
// # Verify proposer signature
|
||||
// assert bls_verify(proposer.pubkey, signing_root(block), block.signature, get_domain(state, DOMAIN_BEACON_PROPOSER))
|
||||
func ProcessBlockHeader(
|
||||
ctx context.Context,
|
||||
beaconState *stateTrie.BeaconState,
|
||||
block *ethpb.SignedBeaconBlock,
|
||||
) (*stateTrie.BeaconState, error) {
|
||||
@@ -99,7 +100,7 @@ func ProcessBlockHeaderNoVerify(
|
||||
if parentHeader.Slot >= block.Slot {
|
||||
return nil, fmt.Errorf("block.Slot %d must be greater than state.LatestBlockHeader.Slot %d", block.Slot, parentHeader.Slot)
|
||||
}
|
||||
parentRoot, err := stateutil.BlockHeaderRoot(parentHeader)
|
||||
parentRoot, err := parentHeader.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -118,7 +119,7 @@ func ProcessBlockHeaderNoVerify(
|
||||
return nil, fmt.Errorf("proposer at index %d was previously slashed", idx)
|
||||
}
|
||||
|
||||
bodyRoot, err := stateutil.BlockBodyRoot(block.Body)
|
||||
bodyRoot, err := block.Body.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
package blocks_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/go-ssz"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -27,160 +27,108 @@ func TestProcessBlockHeader_ImproperBlockSlot(t *testing.T) {
|
||||
validators := make([]*ethpb.Validator, params.BeaconConfig().MinGenesisActiveValidatorCount)
|
||||
for i := 0; i < len(validators); i++ {
|
||||
validators[i] = ðpb.Validator{
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
Slashed: true,
|
||||
PublicKey: make([]byte, 32),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
Slashed: true,
|
||||
}
|
||||
}
|
||||
|
||||
state, err := stateTrie.InitializeFromProto(&pb.BeaconState{
|
||||
Validators: validators,
|
||||
Slot: 10,
|
||||
LatestBlockHeader: ðpb.BeaconBlockHeader{Slot: 10}, // Must be less than block.Slot
|
||||
Fork: &pb.Fork{
|
||||
PreviousVersion: []byte{0, 0, 0, 0},
|
||||
CurrentVersion: []byte{0, 0, 0, 0},
|
||||
},
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
state := testutil.NewBeaconState()
|
||||
require.NoError(t, state.SetSlot(10))
|
||||
require.NoError(t, state.SetValidators(validators))
|
||||
require.NoError(t, state.SetLatestBlockHeader(ðpb.BeaconBlockHeader{
|
||||
Slot: 10, // Must be less than block.Slot
|
||||
ParentRoot: make([]byte, 32),
|
||||
StateRoot: make([]byte, 32),
|
||||
BodyRoot: make([]byte, 32),
|
||||
}))
|
||||
|
||||
latestBlockSignedRoot, err := stateutil.BlockHeaderRoot(state.LatestBlockHeader())
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
latestBlockSignedRoot, err := state.LatestBlockHeader().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
currentEpoch := helpers.CurrentEpoch(state)
|
||||
dt, err := helpers.Domain(state.Fork(), currentEpoch, params.BeaconConfig().DomainBeaconProposer, state.GenesisValidatorRoot())
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to get domain form state: %v", err)
|
||||
}
|
||||
priv := bls.RandKey()
|
||||
pID, err := helpers.BeaconProposerIndex(state)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
block := ðpb.SignedBeaconBlock{
|
||||
Block: ðpb.BeaconBlock{
|
||||
ProposerIndex: pID,
|
||||
Slot: 10,
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
RandaoReveal: []byte{'A', 'B', 'C'},
|
||||
},
|
||||
ParentRoot: latestBlockSignedRoot[:],
|
||||
},
|
||||
}
|
||||
signingRoot, err := helpers.ComputeSigningRoot(block.Block, dt)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to get signing root of block: %v", err)
|
||||
}
|
||||
blockSig := priv.Sign(signingRoot[:])
|
||||
block.Signature = blockSig.Marshal()[:]
|
||||
require.NoError(t, err)
|
||||
block := testutil.NewBeaconBlock()
|
||||
block.Block.ProposerIndex = pID
|
||||
block.Block.Slot = 10
|
||||
block.Block.Body.RandaoReveal = bytesutil.PadTo([]byte{'A', 'B', 'C'}, 96)
|
||||
block.Block.ParentRoot = latestBlockSignedRoot[:]
|
||||
block.Signature, err = helpers.ComputeDomainAndSign(state, currentEpoch, block.Block, params.BeaconConfig().DomainBeaconProposer, priv)
|
||||
require.NoError(t, err)
|
||||
|
||||
proposerIdx, err := helpers.BeaconProposerIndex(state)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
validators[proposerIdx].Slashed = false
|
||||
validators[proposerIdx].PublicKey = priv.PublicKey().Marshal()
|
||||
err = state.UpdateValidatorAtIndex(proposerIdx, validators[proposerIdx])
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = blocks.ProcessBlockHeader(state, block)
|
||||
if err == nil || err.Error() != "block.Slot 10 must be greater than state.LatestBlockHeader.Slot 10" {
|
||||
t.Fatalf("did not get expected error, got %v", err)
|
||||
}
|
||||
_, err = blocks.ProcessBlockHeader(context.Background(), state, block)
|
||||
assert.ErrorContains(t, "block.Slot 10 must be greater than state.LatestBlockHeader.Slot 10", err)
|
||||
}
|
||||
|
||||
func TestProcessBlockHeader_WrongProposerSig(t *testing.T) {
|
||||
testutil.ResetCache()
|
||||
beaconState, privKeys := testutil.DeterministicGenesisState(t, 100)
|
||||
if err := beaconState.SetLatestBlockHeader(ðpb.BeaconBlockHeader{Slot: 9}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := beaconState.SetSlot(10); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.NoError(t, beaconState.SetLatestBlockHeader(ðpb.BeaconBlockHeader{
|
||||
Slot: 9,
|
||||
ParentRoot: make([]byte, 32),
|
||||
StateRoot: make([]byte, 32),
|
||||
BodyRoot: make([]byte, 32),
|
||||
}))
|
||||
require.NoError(t, beaconState.SetSlot(10))
|
||||
|
||||
lbhdr, err := stateutil.BlockHeaderRoot(beaconState.LatestBlockHeader())
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
lbhdr, err := beaconState.LatestBlockHeader().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
proposerIdx, err := helpers.BeaconProposerIndex(beaconState)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
block := ðpb.SignedBeaconBlock{
|
||||
Block: ðpb.BeaconBlock{
|
||||
ProposerIndex: proposerIdx,
|
||||
Slot: 10,
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
RandaoReveal: []byte{'A', 'B', 'C'},
|
||||
},
|
||||
ParentRoot: lbhdr[:],
|
||||
},
|
||||
}
|
||||
dt, err := helpers.Domain(beaconState.Fork(), 0, params.BeaconConfig().DomainBeaconProposer, beaconState.GenesisValidatorRoot())
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to get domain form state: %v", err)
|
||||
}
|
||||
signingRoot, err := helpers.ComputeSigningRoot(block.Block, dt)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to get signing root of block: %v", err)
|
||||
}
|
||||
blockSig := privKeys[proposerIdx+1].Sign(signingRoot[:])
|
||||
block.Signature = blockSig.Marshal()[:]
|
||||
block := testutil.NewBeaconBlock()
|
||||
block.Block.ProposerIndex = proposerIdx
|
||||
block.Block.Slot = 10
|
||||
block.Block.Body.RandaoReveal = bytesutil.PadTo([]byte{'A', 'B', 'C'}, 96)
|
||||
block.Block.ParentRoot = lbhdr[:]
|
||||
block.Signature, err = helpers.ComputeDomainAndSign(beaconState, 0, block.Block, params.BeaconConfig().DomainBeaconProposer, privKeys[proposerIdx+1])
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = blocks.ProcessBlockHeader(beaconState, block)
|
||||
_, err = blocks.ProcessBlockHeader(context.Background(), beaconState, block)
|
||||
want := "signature did not verify"
|
||||
if err == nil || !strings.Contains(err.Error(), want) {
|
||||
t.Errorf("Expected %v, received %v", want, err)
|
||||
}
|
||||
assert.ErrorContains(t, want, err)
|
||||
}
|
||||
|
||||
func TestProcessBlockHeader_DifferentSlots(t *testing.T) {
|
||||
validators := make([]*ethpb.Validator, params.BeaconConfig().MinGenesisActiveValidatorCount)
|
||||
for i := 0; i < len(validators); i++ {
|
||||
validators[i] = ðpb.Validator{
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
Slashed: true,
|
||||
PublicKey: make([]byte, 32),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
Slashed: true,
|
||||
}
|
||||
}
|
||||
|
||||
state, err := stateTrie.InitializeFromProto(&pb.BeaconState{
|
||||
Validators: validators,
|
||||
Slot: 10,
|
||||
LatestBlockHeader: ðpb.BeaconBlockHeader{Slot: 9},
|
||||
Fork: &pb.Fork{
|
||||
PreviousVersion: []byte{0, 0, 0, 0},
|
||||
CurrentVersion: []byte{0, 0, 0, 0},
|
||||
},
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
state := testutil.NewBeaconState()
|
||||
require.NoError(t, state.SetValidators(validators))
|
||||
require.NoError(t, state.SetSlot(10))
|
||||
require.NoError(t, state.SetLatestBlockHeader(ðpb.BeaconBlockHeader{
|
||||
Slot: 9,
|
||||
ProposerIndex: 0,
|
||||
ParentRoot: make([]byte, 32),
|
||||
StateRoot: make([]byte, 32),
|
||||
BodyRoot: make([]byte, 32),
|
||||
}))
|
||||
|
||||
lbhsr, err := ssz.HashTreeRoot(state.LatestBlockHeader())
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
lbhsr, err := state.LatestBlockHeader().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
currentEpoch := helpers.CurrentEpoch(state)
|
||||
dt, err := helpers.Domain(state.Fork(), currentEpoch, params.BeaconConfig().DomainBeaconProposer, state.GenesisValidatorRoot())
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to get domain form state: %v", err)
|
||||
}
|
||||
|
||||
priv := bls.RandKey()
|
||||
root, err := helpers.ComputeSigningRoot([]byte("hello"), dt)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
blockSig := priv.Sign(root[:])
|
||||
blockSig, err := helpers.ComputeDomainAndSign(state, currentEpoch, []byte("hello"), params.BeaconConfig().DomainBeaconProposer, priv)
|
||||
require.NoError(t, err)
|
||||
validators[5896].PublicKey = priv.PublicKey().Marshal()
|
||||
block := ðpb.SignedBeaconBlock{
|
||||
Block: ðpb.BeaconBlock{
|
||||
@@ -190,211 +138,137 @@ func TestProcessBlockHeader_DifferentSlots(t *testing.T) {
|
||||
},
|
||||
ParentRoot: lbhsr[:],
|
||||
},
|
||||
Signature: blockSig.Marshal(),
|
||||
Signature: blockSig,
|
||||
}
|
||||
|
||||
_, err = blocks.ProcessBlockHeader(state, block)
|
||||
_, err = blocks.ProcessBlockHeader(context.Background(), state, block)
|
||||
want := "is different than block slot"
|
||||
if err == nil || !strings.Contains(err.Error(), want) {
|
||||
t.Errorf("Expected %v, received %v", want, err)
|
||||
}
|
||||
assert.ErrorContains(t, want, err)
|
||||
}
|
||||
|
||||
func TestProcessBlockHeader_PreviousBlockRootNotSignedRoot(t *testing.T) {
|
||||
validators := make([]*ethpb.Validator, params.BeaconConfig().MinGenesisActiveValidatorCount)
|
||||
for i := 0; i < len(validators); i++ {
|
||||
validators[i] = ðpb.Validator{
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
Slashed: true,
|
||||
PublicKey: make([]byte, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
Slashed: true,
|
||||
}
|
||||
}
|
||||
|
||||
state, err := stateTrie.InitializeFromProto(&pb.BeaconState{
|
||||
Validators: validators,
|
||||
Slot: 10,
|
||||
LatestBlockHeader: ðpb.BeaconBlockHeader{Slot: 9},
|
||||
Fork: &pb.Fork{
|
||||
PreviousVersion: []byte{0, 0, 0, 0},
|
||||
CurrentVersion: []byte{0, 0, 0, 0},
|
||||
},
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
state := testutil.NewBeaconState()
|
||||
require.NoError(t, state.SetValidators(validators))
|
||||
require.NoError(t, state.SetSlot(10))
|
||||
bh := state.LatestBlockHeader()
|
||||
bh.Slot = 9
|
||||
require.NoError(t, state.SetLatestBlockHeader(bh))
|
||||
currentEpoch := helpers.CurrentEpoch(state)
|
||||
dt, err := helpers.Domain(state.Fork(), currentEpoch, params.BeaconConfig().DomainBeaconProposer, state.GenesisValidatorRoot())
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to get domain form state: %v", err)
|
||||
}
|
||||
priv := bls.RandKey()
|
||||
root, err := helpers.ComputeSigningRoot([]byte("hello"), dt)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
blockSig := priv.Sign(root[:])
|
||||
blockSig, err := helpers.ComputeDomainAndSign(state, currentEpoch, []byte("hello"), params.BeaconConfig().DomainBeaconProposer, priv)
|
||||
require.NoError(t, err)
|
||||
validators[5896].PublicKey = priv.PublicKey().Marshal()
|
||||
pID, err := helpers.BeaconProposerIndex(state)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
block := ðpb.SignedBeaconBlock{
|
||||
Block: ðpb.BeaconBlock{
|
||||
ProposerIndex: pID,
|
||||
Slot: 10,
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
RandaoReveal: []byte{'A', 'B', 'C'},
|
||||
},
|
||||
ParentRoot: []byte{'A'},
|
||||
},
|
||||
Signature: blockSig.Marshal(),
|
||||
}
|
||||
require.NoError(t, err)
|
||||
block := testutil.NewBeaconBlock()
|
||||
block.Block.Slot = 10
|
||||
block.Block.ProposerIndex = pID
|
||||
block.Block.Body.RandaoReveal = bytesutil.PadTo([]byte{'A', 'B', 'C'}, 96)
|
||||
block.Block.ParentRoot = bytesutil.PadTo([]byte{'A'}, 32)
|
||||
block.Signature = blockSig
|
||||
|
||||
_, err = blocks.ProcessBlockHeader(state, block)
|
||||
_, err = blocks.ProcessBlockHeader(context.Background(), state, block)
|
||||
want := "does not match"
|
||||
if err == nil || !strings.Contains(err.Error(), want) {
|
||||
t.Errorf("Expected %v, received %v", want, err)
|
||||
}
|
||||
assert.ErrorContains(t, want, err)
|
||||
}
|
||||
|
||||
func TestProcessBlockHeader_SlashedProposer(t *testing.T) {
|
||||
validators := make([]*ethpb.Validator, params.BeaconConfig().MinGenesisActiveValidatorCount)
|
||||
for i := 0; i < len(validators); i++ {
|
||||
validators[i] = ðpb.Validator{
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
Slashed: true,
|
||||
PublicKey: make([]byte, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
Slashed: true,
|
||||
}
|
||||
}
|
||||
|
||||
state, err := stateTrie.InitializeFromProto(&pb.BeaconState{
|
||||
Validators: validators,
|
||||
Slot: 10,
|
||||
LatestBlockHeader: ðpb.BeaconBlockHeader{Slot: 9},
|
||||
Fork: &pb.Fork{
|
||||
PreviousVersion: []byte{0, 0, 0, 0},
|
||||
CurrentVersion: []byte{0, 0, 0, 0},
|
||||
},
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
parentRoot, err := stateutil.BlockHeaderRoot(state.LatestBlockHeader())
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
state := testutil.NewBeaconState()
|
||||
require.NoError(t, state.SetValidators(validators))
|
||||
require.NoError(t, state.SetSlot(10))
|
||||
bh := state.LatestBlockHeader()
|
||||
bh.Slot = 9
|
||||
require.NoError(t, state.SetLatestBlockHeader(bh))
|
||||
parentRoot, err := state.LatestBlockHeader().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
currentEpoch := helpers.CurrentEpoch(state)
|
||||
dt, err := helpers.Domain(state.Fork(), currentEpoch, params.BeaconConfig().DomainBeaconProposer, state.GenesisValidatorRoot())
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to get domain form state: %v", err)
|
||||
}
|
||||
priv := bls.RandKey()
|
||||
root, err := helpers.ComputeSigningRoot([]byte("hello"), dt)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
blockSig := priv.Sign(root[:])
|
||||
blockSig, err := helpers.ComputeDomainAndSign(state, currentEpoch, []byte("hello"), params.BeaconConfig().DomainBeaconProposer, priv)
|
||||
require.NoError(t, err)
|
||||
|
||||
validators[12683].PublicKey = priv.PublicKey().Marshal()
|
||||
pID, err := helpers.BeaconProposerIndex(state)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
block := ðpb.SignedBeaconBlock{
|
||||
Block: ðpb.BeaconBlock{
|
||||
ProposerIndex: pID,
|
||||
Slot: 10,
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
RandaoReveal: []byte{'A', 'B', 'C'},
|
||||
},
|
||||
ParentRoot: parentRoot[:],
|
||||
},
|
||||
Signature: blockSig.Marshal(),
|
||||
}
|
||||
require.NoError(t, err)
|
||||
block := testutil.NewBeaconBlock()
|
||||
block.Block.Slot = 10
|
||||
block.Block.ProposerIndex = pID
|
||||
block.Block.Body.RandaoReveal = bytesutil.PadTo([]byte{'A', 'B', 'C'}, 96)
|
||||
block.Block.ParentRoot = parentRoot[:]
|
||||
block.Signature = blockSig
|
||||
|
||||
_, err = blocks.ProcessBlockHeader(state, block)
|
||||
_, err = blocks.ProcessBlockHeader(context.Background(), state, block)
|
||||
want := "was previously slashed"
|
||||
if err == nil || !strings.Contains(err.Error(), want) {
|
||||
t.Errorf("Expected %v, received %v", want, err)
|
||||
}
|
||||
assert.ErrorContains(t, want, err)
|
||||
}
|
||||
|
||||
func TestProcessBlockHeader_OK(t *testing.T) {
|
||||
validators := make([]*ethpb.Validator, params.BeaconConfig().MinGenesisActiveValidatorCount)
|
||||
for i := 0; i < len(validators); i++ {
|
||||
validators[i] = ðpb.Validator{
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
Slashed: true,
|
||||
PublicKey: make([]byte, 32),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
Slashed: true,
|
||||
}
|
||||
}
|
||||
|
||||
state, err := stateTrie.InitializeFromProto(&pb.BeaconState{
|
||||
Validators: validators,
|
||||
Slot: 10,
|
||||
LatestBlockHeader: ðpb.BeaconBlockHeader{Slot: 9},
|
||||
Fork: &pb.Fork{
|
||||
PreviousVersion: []byte{0, 0, 0, 0},
|
||||
CurrentVersion: []byte{0, 0, 0, 0},
|
||||
},
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
state := testutil.NewBeaconState()
|
||||
require.NoError(t, state.SetValidators(validators))
|
||||
require.NoError(t, state.SetSlot(10))
|
||||
require.NoError(t, state.SetLatestBlockHeader(ðpb.BeaconBlockHeader{
|
||||
Slot: 9,
|
||||
ProposerIndex: 0,
|
||||
ParentRoot: make([]byte, 32),
|
||||
StateRoot: make([]byte, 32),
|
||||
BodyRoot: make([]byte, 32),
|
||||
}))
|
||||
|
||||
latestBlockSignedRoot, err := stateutil.BlockHeaderRoot(state.LatestBlockHeader())
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
latestBlockSignedRoot, err := state.LatestBlockHeader().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
currentEpoch := helpers.CurrentEpoch(state)
|
||||
dt, err := helpers.Domain(state.Fork(), currentEpoch, params.BeaconConfig().DomainBeaconProposer, state.GenesisValidatorRoot())
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to get domain form state: %v", err)
|
||||
}
|
||||
priv := bls.RandKey()
|
||||
pID, err := helpers.BeaconProposerIndex(state)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
block := ðpb.SignedBeaconBlock{
|
||||
Block: ðpb.BeaconBlock{
|
||||
ProposerIndex: pID,
|
||||
Slot: 10,
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
RandaoReveal: []byte{'A', 'B', 'C'},
|
||||
},
|
||||
ParentRoot: latestBlockSignedRoot[:],
|
||||
},
|
||||
}
|
||||
signingRoot, err := helpers.ComputeSigningRoot(block.Block, dt)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to get signing root of block: %v", err)
|
||||
}
|
||||
blockSig := priv.Sign(signingRoot[:])
|
||||
block.Signature = blockSig.Marshal()[:]
|
||||
bodyRoot, err := stateutil.BlockBodyRoot(block.Block.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to hash block bytes got: %v", err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
block := testutil.NewBeaconBlock()
|
||||
block.Block.ProposerIndex = pID
|
||||
block.Block.Slot = 10
|
||||
block.Block.Body.RandaoReveal = bytesutil.PadTo([]byte{'A', 'B', 'C'}, 96)
|
||||
block.Block.ParentRoot = latestBlockSignedRoot[:]
|
||||
block.Signature, err = helpers.ComputeDomainAndSign(state, currentEpoch, block.Block, params.BeaconConfig().DomainBeaconProposer, priv)
|
||||
require.NoError(t, err)
|
||||
bodyRoot, err := block.Block.Body.HashTreeRoot()
|
||||
require.NoError(t, err, "Failed to hash block bytes got")
|
||||
|
||||
proposerIdx, err := helpers.BeaconProposerIndex(state)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
validators[proposerIdx].Slashed = false
|
||||
validators[proposerIdx].PublicKey = priv.PublicKey().Marshal()
|
||||
err = state.UpdateValidatorAtIndex(proposerIdx, validators[proposerIdx])
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
newState, err := blocks.ProcessBlockHeader(state, block)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to process block header got: %v", err)
|
||||
}
|
||||
newState, err := blocks.ProcessBlockHeader(context.Background(), state, block)
|
||||
require.NoError(t, err, "Failed to process block header got")
|
||||
var zeroHash [32]byte
|
||||
nsh := newState.LatestBlockHeader()
|
||||
expected := ðpb.BeaconBlockHeader{
|
||||
@@ -404,86 +278,55 @@ func TestProcessBlockHeader_OK(t *testing.T) {
|
||||
BodyRoot: bodyRoot[:],
|
||||
StateRoot: zeroHash[:],
|
||||
}
|
||||
if !proto.Equal(nsh, expected) {
|
||||
t.Errorf("Expected %v, received %v", expected, nsh)
|
||||
}
|
||||
assert.Equal(t, true, proto.Equal(nsh, expected), "Expected %v, received %v", expected, nsh)
|
||||
}
|
||||
|
||||
func TestBlockSignatureSet_OK(t *testing.T) {
|
||||
validators := make([]*ethpb.Validator, params.BeaconConfig().MinGenesisActiveValidatorCount)
|
||||
for i := 0; i < len(validators); i++ {
|
||||
validators[i] = ðpb.Validator{
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
Slashed: true,
|
||||
PublicKey: make([]byte, 32),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
Slashed: true,
|
||||
}
|
||||
}
|
||||
|
||||
state, err := stateTrie.InitializeFromProto(&pb.BeaconState{
|
||||
Validators: validators,
|
||||
Slot: 10,
|
||||
LatestBlockHeader: ðpb.BeaconBlockHeader{Slot: 9},
|
||||
Fork: &pb.Fork{
|
||||
PreviousVersion: []byte{0, 0, 0, 0},
|
||||
CurrentVersion: []byte{0, 0, 0, 0},
|
||||
},
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
state := testutil.NewBeaconState()
|
||||
require.NoError(t, state.SetValidators(validators))
|
||||
require.NoError(t, state.SetSlot(10))
|
||||
require.NoError(t, state.SetLatestBlockHeader(ðpb.BeaconBlockHeader{
|
||||
Slot: 9,
|
||||
ProposerIndex: 0,
|
||||
ParentRoot: make([]byte, 32),
|
||||
StateRoot: make([]byte, 32),
|
||||
BodyRoot: make([]byte, 32),
|
||||
}))
|
||||
|
||||
latestBlockSignedRoot, err := stateutil.BlockHeaderRoot(state.LatestBlockHeader())
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
latestBlockSignedRoot, err := state.LatestBlockHeader().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
currentEpoch := helpers.CurrentEpoch(state)
|
||||
dt, err := helpers.Domain(state.Fork(), currentEpoch, params.BeaconConfig().DomainBeaconProposer, state.GenesisValidatorRoot())
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to get domain form state: %v", err)
|
||||
}
|
||||
priv := bls.RandKey()
|
||||
pID, err := helpers.BeaconProposerIndex(state)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
block := ðpb.SignedBeaconBlock{
|
||||
Block: ðpb.BeaconBlock{
|
||||
ProposerIndex: pID,
|
||||
Slot: 10,
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
RandaoReveal: []byte{'A', 'B', 'C'},
|
||||
},
|
||||
ParentRoot: latestBlockSignedRoot[:],
|
||||
},
|
||||
}
|
||||
signingRoot, err := helpers.ComputeSigningRoot(block.Block, dt)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to get signing root of block: %v", err)
|
||||
}
|
||||
blockSig := priv.Sign(signingRoot[:])
|
||||
block.Signature = blockSig.Marshal()[:]
|
||||
|
||||
require.NoError(t, err)
|
||||
block := testutil.NewBeaconBlock()
|
||||
block.Block.Slot = 10
|
||||
block.Block.ProposerIndex = pID
|
||||
block.Block.Body.RandaoReveal = bytesutil.PadTo([]byte{'A', 'B', 'C'}, 96)
|
||||
block.Block.ParentRoot = latestBlockSignedRoot[:]
|
||||
block.Signature, err = helpers.ComputeDomainAndSign(state, currentEpoch, block.Block, params.BeaconConfig().DomainBeaconProposer, priv)
|
||||
require.NoError(t, err)
|
||||
proposerIdx, err := helpers.BeaconProposerIndex(state)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
validators[proposerIdx].Slashed = false
|
||||
validators[proposerIdx].PublicKey = priv.PublicKey().Marshal()
|
||||
err = state.UpdateValidatorAtIndex(proposerIdx, validators[proposerIdx])
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
set, err := blocks.BlockSignatureSet(state, block)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
verified, err := set.Verify()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !verified {
|
||||
t.Error("Block signature set returned a set which was unable to be verified")
|
||||
}
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, true, verified, "Block signature set returned a set which was unable to be verified")
|
||||
}
|
||||
|
||||
@@ -38,8 +38,13 @@ import (
|
||||
func ProcessProposerSlashings(
|
||||
ctx context.Context,
|
||||
beaconState *stateTrie.BeaconState,
|
||||
body *ethpb.BeaconBlockBody,
|
||||
b *ethpb.SignedBeaconBlock,
|
||||
) (*stateTrie.BeaconState, error) {
|
||||
if b.Block == nil || b.Block.Body == nil {
|
||||
return nil, errors.New("block and block body can't be nil")
|
||||
}
|
||||
|
||||
body := b.Block.Body
|
||||
var err error
|
||||
for idx, slashing := range body.ProposerSlashings {
|
||||
if slashing == nil {
|
||||
@@ -66,33 +71,31 @@ func VerifyProposerSlashing(
|
||||
if slashing.Header_1 == nil || slashing.Header_1.Header == nil || slashing.Header_2 == nil || slashing.Header_2.Header == nil {
|
||||
return errors.New("nil header cannot be verified")
|
||||
}
|
||||
if slashing.Header_1.Header.Slot != slashing.Header_2.Header.Slot {
|
||||
hSlot := slashing.Header_1.Header.Slot
|
||||
if hSlot != slashing.Header_2.Header.Slot {
|
||||
return fmt.Errorf("mismatched header slots, received %d == %d", slashing.Header_1.Header.Slot, slashing.Header_2.Header.Slot)
|
||||
}
|
||||
if slashing.Header_1.Header.ProposerIndex != slashing.Header_2.Header.ProposerIndex {
|
||||
pIdx := slashing.Header_1.Header.ProposerIndex
|
||||
if pIdx != slashing.Header_2.Header.ProposerIndex {
|
||||
return fmt.Errorf("mismatched indices, received %d == %d", slashing.Header_1.Header.ProposerIndex, slashing.Header_2.Header.ProposerIndex)
|
||||
}
|
||||
if proto.Equal(slashing.Header_1, slashing.Header_2) {
|
||||
if proto.Equal(slashing.Header_1.Header, slashing.Header_2.Header) {
|
||||
return errors.New("expected slashing headers to differ")
|
||||
}
|
||||
proposer, err := beaconState.ValidatorAtIndexReadOnly(slashing.Header_1.Header.ProposerIndex)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !helpers.IsSlashableValidatorUsingTrie(proposer, helpers.SlotToEpoch(beaconState.Slot())) {
|
||||
if !helpers.IsSlashableValidatorUsingTrie(proposer, helpers.SlotToEpoch(hSlot)) {
|
||||
return fmt.Errorf("validator with key %#x is not slashable", proposer.PublicKey())
|
||||
}
|
||||
// Using headerEpoch1 here because both of the headers should have the same epoch.
|
||||
domain, err := helpers.Domain(beaconState.Fork(), helpers.SlotToEpoch(slashing.Header_1.Header.Slot), params.BeaconConfig().DomainBeaconProposer, beaconState.GenesisValidatorRoot())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
headers := []*ethpb.SignedBeaconBlockHeader{slashing.Header_1, slashing.Header_2}
|
||||
for _, header := range headers {
|
||||
proposerPubKey := proposer.PublicKey()
|
||||
if err := helpers.VerifySigningRoot(header.Header, proposerPubKey[:], header.Signature, domain); err != nil {
|
||||
if err := helpers.ComputeDomainVerifySigningRoot(beaconState, pIdx, helpers.SlotToEpoch(hSlot),
|
||||
header.Header, params.BeaconConfig().DomainBeaconProposer, header.Signature); err != nil {
|
||||
return errors.Wrap(err, "could not verify beacon block header")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package blocks_test
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
@@ -11,9 +10,12 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
func TestProcessProposerSlashings_UnmatchedHeaderSlots(t *testing.T) {
|
||||
@@ -36,20 +38,17 @@ func TestProcessProposerSlashings_UnmatchedHeaderSlots(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}
|
||||
if err := beaconState.SetSlot(currentSlot); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, beaconState.SetSlot(currentSlot))
|
||||
|
||||
block := ðpb.BeaconBlock{
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block = ðpb.BeaconBlock{
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
ProposerSlashings: slashings,
|
||||
},
|
||||
}
|
||||
want := "mismatched header slots"
|
||||
_, err := blocks.ProcessProposerSlashings(context.Background(), beaconState, block.Body)
|
||||
if err == nil || !strings.Contains(err.Error(), want) {
|
||||
t.Errorf("Expected %s, received %v", want, err)
|
||||
}
|
||||
_, err := blocks.ProcessProposerSlashings(context.Background(), beaconState, b)
|
||||
assert.ErrorContains(t, want, err)
|
||||
}
|
||||
|
||||
func TestProcessProposerSlashings_SameHeaders(t *testing.T) {
|
||||
@@ -73,19 +72,16 @@ func TestProcessProposerSlashings_SameHeaders(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
if err := beaconState.SetSlot(currentSlot); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
block := ðpb.BeaconBlock{
|
||||
require.NoError(t, beaconState.SetSlot(currentSlot))
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block = ðpb.BeaconBlock{
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
ProposerSlashings: slashings,
|
||||
},
|
||||
}
|
||||
want := "expected slashing headers to differ"
|
||||
_, err := blocks.ProcessProposerSlashings(context.Background(), beaconState, block.Body)
|
||||
if err == nil || !strings.Contains(err.Error(), want) {
|
||||
t.Errorf("Expected %s, received %v", want, err)
|
||||
}
|
||||
_, err := blocks.ProcessProposerSlashings(context.Background(), beaconState, b)
|
||||
assert.ErrorContains(t, want, err)
|
||||
}
|
||||
|
||||
func TestProcessProposerSlashings_ValidatorNotSlashable(t *testing.T) {
|
||||
@@ -104,15 +100,17 @@ func TestProcessProposerSlashings_ValidatorNotSlashable(t *testing.T) {
|
||||
Header: ðpb.BeaconBlockHeader{
|
||||
ProposerIndex: 0,
|
||||
Slot: 0,
|
||||
BodyRoot: []byte("foo"),
|
||||
},
|
||||
Signature: []byte("A"),
|
||||
Signature: bytesutil.PadTo([]byte("A"), 96),
|
||||
},
|
||||
Header_2: ðpb.SignedBeaconBlockHeader{
|
||||
Header: ðpb.BeaconBlockHeader{
|
||||
ProposerIndex: 0,
|
||||
Slot: 0,
|
||||
BodyRoot: []byte("bar"),
|
||||
},
|
||||
Signature: []byte("B"),
|
||||
Signature: bytesutil.PadTo([]byte("B"), 96),
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -121,10 +119,9 @@ func TestProcessProposerSlashings_ValidatorNotSlashable(t *testing.T) {
|
||||
Validators: registry,
|
||||
Slot: currentSlot,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
block := ðpb.BeaconBlock{
|
||||
require.NoError(t, err)
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block = ðpb.BeaconBlock{
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
ProposerSlashings: slashings,
|
||||
},
|
||||
@@ -133,11 +130,8 @@ func TestProcessProposerSlashings_ValidatorNotSlashable(t *testing.T) {
|
||||
"validator with key %#x is not slashable",
|
||||
bytesutil.ToBytes48(beaconState.Validators()[0].PublicKey),
|
||||
)
|
||||
|
||||
_, err = blocks.ProcessProposerSlashings(context.Background(), beaconState, block.Body)
|
||||
if err == nil || !strings.Contains(err.Error(), want) {
|
||||
t.Errorf("Expected %s, received %v", want, err)
|
||||
}
|
||||
_, err = blocks.ProcessProposerSlashings(context.Background(), beaconState, b)
|
||||
assert.ErrorContains(t, want, err)
|
||||
}
|
||||
|
||||
func TestProcessProposerSlashings_AppliesCorrectStatus(t *testing.T) {
|
||||
@@ -146,35 +140,30 @@ func TestProcessProposerSlashings_AppliesCorrectStatus(t *testing.T) {
|
||||
beaconState, privKeys := testutil.DeterministicGenesisState(t, 100)
|
||||
proposerIdx := uint64(1)
|
||||
|
||||
domain, err := helpers.Domain(beaconState.Fork(), 0, params.BeaconConfig().DomainBeaconProposer, beaconState.GenesisValidatorRoot())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
header1 := ðpb.SignedBeaconBlockHeader{
|
||||
Header: ðpb.BeaconBlockHeader{
|
||||
ProposerIndex: proposerIdx,
|
||||
Slot: 0,
|
||||
StateRoot: []byte("A"),
|
||||
ParentRoot: make([]byte, 32),
|
||||
BodyRoot: make([]byte, 32),
|
||||
StateRoot: bytesutil.PadTo([]byte("A"), 32),
|
||||
},
|
||||
}
|
||||
signingRoot, err := helpers.ComputeSigningRoot(header1.Header, domain)
|
||||
if err != nil {
|
||||
t.Errorf("Could not get signing root of beacon block header: %v", err)
|
||||
}
|
||||
header1.Signature = privKeys[proposerIdx].Sign(signingRoot[:]).Marshal()[:]
|
||||
var err error
|
||||
header1.Signature, err = helpers.ComputeDomainAndSign(beaconState, 0, header1.Header, params.BeaconConfig().DomainBeaconProposer, privKeys[proposerIdx])
|
||||
require.NoError(t, err)
|
||||
|
||||
header2 := ðpb.SignedBeaconBlockHeader{
|
||||
Header: ðpb.BeaconBlockHeader{
|
||||
ProposerIndex: proposerIdx,
|
||||
Slot: 0,
|
||||
StateRoot: []byte("B"),
|
||||
ParentRoot: make([]byte, 32),
|
||||
BodyRoot: make([]byte, 32),
|
||||
StateRoot: bytesutil.PadTo([]byte("B"), 32),
|
||||
},
|
||||
}
|
||||
signingRoot, err = helpers.ComputeSigningRoot(header2.Header, domain)
|
||||
if err != nil {
|
||||
t.Errorf("Could not get signing root of beacon block header: %v", err)
|
||||
}
|
||||
header2.Signature = privKeys[proposerIdx].Sign(signingRoot[:]).Marshal()[:]
|
||||
header2.Signature, err = helpers.ComputeDomainAndSign(beaconState, 0, header2.Header, params.BeaconConfig().DomainBeaconProposer, privKeys[proposerIdx])
|
||||
require.NoError(t, err)
|
||||
|
||||
slashings := []*ethpb.ProposerSlashing{
|
||||
{
|
||||
@@ -183,16 +172,11 @@ func TestProcessProposerSlashings_AppliesCorrectStatus(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
block := ðpb.BeaconBlock{
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
ProposerSlashings: slashings,
|
||||
},
|
||||
}
|
||||
block := testutil.NewBeaconBlock()
|
||||
block.Block.Body.ProposerSlashings = slashings
|
||||
|
||||
newState, err := blocks.ProcessProposerSlashings(context.Background(), beaconState, block.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %s", err)
|
||||
}
|
||||
newState, err := blocks.ProcessProposerSlashings(context.Background(), beaconState, block)
|
||||
require.NoError(t, err)
|
||||
|
||||
newStateVals := newState.Validators()
|
||||
if newStateVals[1].ExitEpoch != beaconState.Validators()[1].ExitEpoch {
|
||||
@@ -200,3 +184,125 @@ func TestProcessProposerSlashings_AppliesCorrectStatus(t *testing.T) {
|
||||
newStateVals[1].ExitEpoch, beaconState.Validators()[1].ExitEpoch)
|
||||
}
|
||||
}
|
||||
|
||||
func TestVerifyProposerSlashing(t *testing.T) {
|
||||
type args struct {
|
||||
beaconState *stateTrie.BeaconState
|
||||
slashing *ethpb.ProposerSlashing
|
||||
}
|
||||
|
||||
beaconState, sks := testutil.DeterministicGenesisState(t, 2)
|
||||
currentSlot := uint64(0)
|
||||
require.NoError(t, beaconState.SetSlot(currentSlot))
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "same header, same slot as state",
|
||||
args: args{
|
||||
slashing: ðpb.ProposerSlashing{
|
||||
Header_1: ðpb.SignedBeaconBlockHeader{
|
||||
Header: ðpb.BeaconBlockHeader{
|
||||
ProposerIndex: 1,
|
||||
Slot: currentSlot,
|
||||
StateRoot: bytesutil.PadTo([]byte{}, 32),
|
||||
BodyRoot: bytesutil.PadTo([]byte{}, 32),
|
||||
ParentRoot: bytesutil.PadTo([]byte{}, 32),
|
||||
},
|
||||
},
|
||||
Header_2: ðpb.SignedBeaconBlockHeader{
|
||||
Header: ðpb.BeaconBlockHeader{
|
||||
ProposerIndex: 1,
|
||||
Slot: currentSlot,
|
||||
StateRoot: bytesutil.PadTo([]byte{}, 32),
|
||||
BodyRoot: bytesutil.PadTo([]byte{}, 32),
|
||||
ParentRoot: bytesutil.PadTo([]byte{}, 32),
|
||||
},
|
||||
},
|
||||
},
|
||||
beaconState: beaconState,
|
||||
},
|
||||
wantErr: "expected slashing headers to differ",
|
||||
},
|
||||
{ // Regression test for https://github.com/sigp/beacon-fuzz/issues/74
|
||||
name: "same header, different signatures",
|
||||
args: args{
|
||||
slashing: ðpb.ProposerSlashing{
|
||||
Header_1: ðpb.SignedBeaconBlockHeader{
|
||||
Header: ðpb.BeaconBlockHeader{
|
||||
ProposerIndex: 1,
|
||||
Slot: 0,
|
||||
StateRoot: bytesutil.PadTo([]byte{}, 32),
|
||||
BodyRoot: bytesutil.PadTo([]byte{}, 32),
|
||||
ParentRoot: bytesutil.PadTo([]byte{}, 32),
|
||||
},
|
||||
Signature: bls.RandKey().Sign([]byte("foo")).Marshal(),
|
||||
},
|
||||
Header_2: ðpb.SignedBeaconBlockHeader{
|
||||
Header: ðpb.BeaconBlockHeader{
|
||||
ProposerIndex: 1,
|
||||
Slot: 0,
|
||||
StateRoot: bytesutil.PadTo([]byte{}, 32),
|
||||
BodyRoot: bytesutil.PadTo([]byte{}, 32),
|
||||
ParentRoot: bytesutil.PadTo([]byte{}, 32),
|
||||
},
|
||||
Signature: bls.RandKey().Sign([]byte("bar")).Marshal(),
|
||||
},
|
||||
},
|
||||
beaconState: beaconState,
|
||||
},
|
||||
wantErr: "expected slashing headers to differ",
|
||||
},
|
||||
{
|
||||
name: "slashing in future epoch",
|
||||
args: args{
|
||||
slashing: ðpb.ProposerSlashing{
|
||||
Header_1: ðpb.SignedBeaconBlockHeader{
|
||||
Header: ðpb.BeaconBlockHeader{
|
||||
ProposerIndex: 1,
|
||||
Slot: 65,
|
||||
StateRoot: bytesutil.PadTo([]byte{}, 32),
|
||||
BodyRoot: bytesutil.PadTo([]byte{}, 32),
|
||||
ParentRoot: bytesutil.PadTo([]byte("foo"), 32),
|
||||
},
|
||||
},
|
||||
Header_2: ðpb.SignedBeaconBlockHeader{
|
||||
Header: ðpb.BeaconBlockHeader{
|
||||
ProposerIndex: 1,
|
||||
Slot: 65,
|
||||
StateRoot: bytesutil.PadTo([]byte{}, 32),
|
||||
BodyRoot: bytesutil.PadTo([]byte{}, 32),
|
||||
ParentRoot: bytesutil.PadTo([]byte("bar"), 32),
|
||||
},
|
||||
},
|
||||
},
|
||||
beaconState: beaconState,
|
||||
},
|
||||
wantErr: "",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
testutil.ResetCache()
|
||||
sk := sks[tt.args.slashing.Header_1.Header.ProposerIndex]
|
||||
d, err := helpers.Domain(tt.args.beaconState.Fork(), helpers.SlotToEpoch(tt.args.slashing.Header_1.Header.Slot), params.BeaconConfig().DomainBeaconProposer, tt.args.beaconState.GenesisValidatorRoot())
|
||||
require.NoError(t, err)
|
||||
if tt.args.slashing.Header_1.Signature == nil {
|
||||
sr, err := helpers.ComputeSigningRoot(tt.args.slashing.Header_1.Header, d)
|
||||
require.NoError(t, err)
|
||||
tt.args.slashing.Header_1.Signature = sk.Sign(sr[:]).Marshal()
|
||||
}
|
||||
if tt.args.slashing.Header_2.Signature == nil {
|
||||
sr, err := helpers.ComputeSigningRoot(tt.args.slashing.Header_2.Header, d)
|
||||
require.NoError(t, err)
|
||||
tt.args.slashing.Header_2.Signature = sk.Sign(sr[:]).Marshal()
|
||||
}
|
||||
if err := blocks.VerifyProposerSlashing(tt.args.beaconState, tt.args.slashing); (err != nil || tt.wantErr != "") && err.Error() != tt.wantErr {
|
||||
t.Errorf("VerifyProposerSlashing() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package blocks
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
@@ -24,14 +26,20 @@ import (
|
||||
// mix = xor(get_randao_mix(state, epoch), hash(body.randao_reveal))
|
||||
// state.randao_mixes[epoch % EPOCHS_PER_HISTORICAL_VECTOR] = mix
|
||||
func ProcessRandao(
|
||||
ctx context.Context,
|
||||
beaconState *stateTrie.BeaconState,
|
||||
body *ethpb.BeaconBlockBody,
|
||||
b *ethpb.SignedBeaconBlock,
|
||||
) (*stateTrie.BeaconState, error) {
|
||||
if b.Block == nil || b.Block.Body == nil {
|
||||
return nil, errors.New("block and block body can't be nil")
|
||||
}
|
||||
|
||||
body := b.Block.Body
|
||||
buf, proposerPub, domain, err := randaoSigningData(beaconState)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := verifySignature(buf, proposerPub[:], body.RandaoReveal, domain); err != nil {
|
||||
if err := verifySignature(buf, proposerPub, body.RandaoReveal, domain); err != nil {
|
||||
return nil, errors.Wrap(err, "could not verify block randao")
|
||||
}
|
||||
|
||||
|
||||
@@ -2,52 +2,44 @@ package blocks_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/go-ssz"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
func TestProcessRandao_IncorrectProposerFailsVerification(t *testing.T) {
|
||||
beaconState, privKeys := testutil.DeterministicGenesisState(t, 100)
|
||||
// We fetch the proposer's index as that is whom the RANDAO will be verified against.
|
||||
proposerIdx, err := helpers.BeaconProposerIndex(beaconState)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
epoch := uint64(0)
|
||||
buf := make([]byte, 32)
|
||||
binary.LittleEndian.PutUint64(buf, epoch)
|
||||
domain, err := helpers.Domain(beaconState.Fork(), epoch, params.BeaconConfig().DomainRandao, beaconState.GenesisValidatorRoot())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
root, err := ssz.HashTreeRoot(&pb.SigningData{ObjectRoot: buf, Domain: domain})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
root, err := (&pb.SigningData{ObjectRoot: buf, Domain: domain}).HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
// We make the previous validator's index sign the message instead of the proposer.
|
||||
epochSignature := privKeys[proposerIdx-1].Sign(root[:])
|
||||
block := ðpb.BeaconBlock{
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block = ðpb.BeaconBlock{
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
RandaoReveal: epochSignature.Marshal(),
|
||||
},
|
||||
}
|
||||
|
||||
want := "block randao: signature did not verify"
|
||||
if _, err := blocks.ProcessRandao(
|
||||
beaconState,
|
||||
block.Body,
|
||||
); err == nil || !strings.Contains(err.Error(), want) {
|
||||
t.Errorf("Expected %v, received %v", want, err)
|
||||
}
|
||||
_, err = blocks.ProcessRandao(context.Background(), beaconState, b)
|
||||
assert.ErrorContains(t, want, err)
|
||||
}
|
||||
|
||||
func TestProcessRandao_SignatureVerifiesAndUpdatesLatestStateMixes(t *testing.T) {
|
||||
@@ -55,23 +47,21 @@ func TestProcessRandao_SignatureVerifiesAndUpdatesLatestStateMixes(t *testing.T)
|
||||
|
||||
epoch := helpers.CurrentEpoch(beaconState)
|
||||
epochSignature, err := testutil.RandaoReveal(beaconState, epoch, privKeys)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
block := ðpb.BeaconBlock{
|
||||
b := testutil.NewBeaconBlock()
|
||||
b.Block = ðpb.BeaconBlock{
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
RandaoReveal: epochSignature,
|
||||
},
|
||||
}
|
||||
|
||||
newState, err := blocks.ProcessRandao(
|
||||
context.Background(),
|
||||
beaconState,
|
||||
block.Body,
|
||||
b,
|
||||
)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error processing block randao: %v", err)
|
||||
}
|
||||
require.NoError(t, err, "Unexpected error processing block randao")
|
||||
currentEpoch := helpers.CurrentEpoch(beaconState)
|
||||
mix := newState.RandaoMixes()[currentEpoch%params.BeaconConfig().EpochsPerHistoricalVector]
|
||||
|
||||
@@ -88,9 +78,7 @@ func TestRandaoSignatureSet_OK(t *testing.T) {
|
||||
|
||||
epoch := helpers.CurrentEpoch(beaconState)
|
||||
epochSignature, err := testutil.RandaoReveal(beaconState, epoch, privKeys)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
block := ðpb.BeaconBlock{
|
||||
Body: ðpb.BeaconBlockBody{
|
||||
@@ -99,14 +87,8 @@ func TestRandaoSignatureSet_OK(t *testing.T) {
|
||||
}
|
||||
|
||||
set, _, err := blocks.RandaoSignatureSet(beaconState, block.Body)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
verified, err := set.Verify()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !verified {
|
||||
t.Error("Unable to verify randao signature set")
|
||||
}
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, true, verified, "Unable to verify randao signature set")
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
|
||||
"github.com/pkg/errors"
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/go-ssz"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
@@ -21,20 +20,16 @@ func retrieveSignatureSet(signedData []byte, pub []byte, signature []byte, domai
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not convert bytes to public key")
|
||||
}
|
||||
sig, err := bls.SignatureFromBytes(signature)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not convert bytes to signature")
|
||||
}
|
||||
signingData := &pb.SigningData{
|
||||
ObjectRoot: signedData,
|
||||
Domain: domain,
|
||||
}
|
||||
root, err := ssz.HashTreeRoot(signingData)
|
||||
root, err := signingData.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not hash container")
|
||||
}
|
||||
return &bls.SignatureSet{
|
||||
Signatures: []bls.Signature{sig},
|
||||
Signatures: [][]byte{signature},
|
||||
PublicKeys: []bls.PublicKey{publicKey},
|
||||
Messages: [][32]byte{root},
|
||||
}, nil
|
||||
@@ -53,7 +48,11 @@ func verifySignature(signedData []byte, pub []byte, signature []byte, domain []b
|
||||
sig := set.Signatures[0]
|
||||
publicKey := set.PublicKeys[0]
|
||||
root := set.Messages[0]
|
||||
if !sig.Verify(publicKey, root[:]) {
|
||||
rSig, err := bls.SignatureFromBytes(sig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !rSig.Verify(publicKey, root[:]) {
|
||||
return helpers.ErrSigFailedToVerify
|
||||
}
|
||||
return nil
|
||||
@@ -71,7 +70,7 @@ func VerifyBlockSignature(beaconState *stateTrie.BeaconState, block *ethpb.Signe
|
||||
return err
|
||||
}
|
||||
proposerPubKey := proposer.PublicKey
|
||||
return helpers.VerifyBlockSigningRoot(block.Block, proposerPubKey[:], block.Signature, domain)
|
||||
return helpers.VerifyBlockSigningRoot(block.Block, proposerPubKey, block.Signature, domain)
|
||||
}
|
||||
|
||||
// BlockSignatureSet retrieves the block signature set from the provided block and its corresponding state.
|
||||
@@ -98,7 +97,7 @@ func RandaoSignatureSet(beaconState *stateTrie.BeaconState,
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
set, err := retrieveSignatureSet(buf, proposerPub[:], body.RandaoReveal, domain)
|
||||
set, err := retrieveSignatureSet(buf, proposerPub, body.RandaoReveal, domain)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@@ -130,35 +129,30 @@ func createAttestationSignatureSet(ctx context.Context, beaconState *stateTrie.B
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
sigs := make([]bls.Signature, len(atts))
|
||||
sigs := make([][]byte, len(atts))
|
||||
pks := make([]bls.PublicKey, len(atts))
|
||||
msgs := make([][32]byte, len(atts))
|
||||
for i, a := range atts {
|
||||
sig, err := bls.SignatureFromBytes(a.Signature)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sigs[i] = sig
|
||||
sigs[i] = a.Signature
|
||||
c, err := helpers.BeaconCommitteeFromState(beaconState, a.Data.Slot, a.Data.CommitteeIndex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ia := attestationutil.ConvertToIndexed(ctx, a, c)
|
||||
if err := attestationutil.IsValidAttestationIndices(ctx, ia); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
indices := ia.AttestingIndices
|
||||
var pk bls.PublicKey
|
||||
pubkeys := make([][]byte, len(indices))
|
||||
for i := 0; i < len(indices); i++ {
|
||||
pubkeyAtIdx := beaconState.PubkeyAtIndex(indices[i])
|
||||
p, err := bls.PublicKeyFromBytes(pubkeyAtIdx[:])
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not deserialize validator public key")
|
||||
}
|
||||
if pk == nil {
|
||||
pk = p
|
||||
} else {
|
||||
pk.Aggregate(p)
|
||||
}
|
||||
pubkeys[i] = pubkeyAtIdx[:]
|
||||
}
|
||||
pks[i] = pk
|
||||
aggP, err := bls.AggregatePublicKeys(pubkeys)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pks[i] = aggP
|
||||
|
||||
root, err := helpers.ComputeSigningRoot(ia.Data, domain)
|
||||
if err != nil {
|
||||
|
||||
@@ -38,8 +38,10 @@ go_test(
|
||||
"//beacon-chain/core/state/stateutils:go_default_library",
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"//shared/params/spectest:go_default_library",
|
||||
"//shared/testutil:go_default_library",
|
||||
"//shared/testutil/require:go_default_library",
|
||||
"@com_github_gogo_protobuf//proto:go_default_library",
|
||||
"@com_github_prysmaticlabs_ethereumapis//eth/v1alpha1:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_ssz//:go_default_library",
|
||||
@@ -72,8 +74,10 @@ go_test(
|
||||
"//beacon-chain/core/state/stateutils:go_default_library",
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"//shared/params/spectest:go_default_library",
|
||||
"//shared/testutil:go_default_library",
|
||||
"//shared/testutil/require:go_default_library",
|
||||
"@com_github_gogo_protobuf//proto:go_default_library",
|
||||
"@com_github_prysmaticlabs_ethereumapis//eth/v1alpha1:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_ssz//:go_default_library",
|
||||
|
||||
@@ -8,25 +8,20 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/shared/params/spectest"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
func runAttestationTest(t *testing.T, config string) {
|
||||
if err := spectest.SetConfig(t, config); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, spectest.SetConfig(t, config))
|
||||
|
||||
testFolders, testsFolderPath := testutil.TestFolders(t, config, "operations/attestation/pyspec_tests")
|
||||
for _, folder := range testFolders {
|
||||
t.Run(folder.Name(), func(t *testing.T) {
|
||||
folderPath := path.Join(testsFolderPath, folder.Name())
|
||||
attestationFile, err := testutil.BazelFileBytes(folderPath, "attestation.ssz")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
att := ðpb.Attestation{}
|
||||
if err := att.UnmarshalSSZ(attestationFile); err != nil {
|
||||
t.Fatalf("Failed to unmarshal: %v", err)
|
||||
}
|
||||
require.NoError(t, att.UnmarshalSSZ(attestationFile), "Failed to unmarshal")
|
||||
|
||||
body := ðpb.BeaconBlockBody{Attestations: []*ethpb.Attestation{att}}
|
||||
testutil.RunBlockOperationTest(t, folderPath, body, blocks.ProcessAttestations)
|
||||
|
||||
@@ -8,25 +8,20 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/shared/params/spectest"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
func runAttesterSlashingTest(t *testing.T, config string) {
|
||||
if err := spectest.SetConfig(t, config); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, spectest.SetConfig(t, config))
|
||||
|
||||
testFolders, testsFolderPath := testutil.TestFolders(t, config, "operations/attester_slashing/pyspec_tests")
|
||||
for _, folder := range testFolders {
|
||||
t.Run(folder.Name(), func(t *testing.T) {
|
||||
folderPath := path.Join(testsFolderPath, folder.Name())
|
||||
attSlashingFile, err := testutil.BazelFileBytes(folderPath, "attester_slashing.ssz")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
attSlashing := ðpb.AttesterSlashing{}
|
||||
if err := attSlashing.UnmarshalSSZ(attSlashingFile); err != nil {
|
||||
t.Fatalf("Failed to unmarshal: %v", err)
|
||||
}
|
||||
require.NoError(t, attSlashing.UnmarshalSSZ(attSlashingFile), "Failed to unmarshal")
|
||||
|
||||
body := ðpb.BeaconBlockBody{AttesterSlashings: []*ethpb.AttesterSlashing{attSlashing}}
|
||||
testutil.RunBlockOperationTest(t, folderPath, body, blocks.ProcessAttesterSlashings)
|
||||
|
||||
@@ -14,64 +14,47 @@ import (
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/params/spectest"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
"gopkg.in/d4l3k/messagediff.v1"
|
||||
)
|
||||
|
||||
func runBlockHeaderTest(t *testing.T, config string) {
|
||||
if err := spectest.SetConfig(t, config); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, spectest.SetConfig(t, config))
|
||||
|
||||
testFolders, testsFolderPath := testutil.TestFolders(t, config, "operations/block_header/pyspec_tests")
|
||||
for _, folder := range testFolders {
|
||||
t.Run(folder.Name(), func(t *testing.T) {
|
||||
blockFile, err := testutil.BazelFileBytes(testsFolderPath, folder.Name(), "block.ssz")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
block := ðpb.BeaconBlock{}
|
||||
if err := block.UnmarshalSSZ(blockFile); err != nil {
|
||||
t.Fatalf("Failed to unmarshal: %v", err)
|
||||
}
|
||||
require.NoError(t, block.UnmarshalSSZ(blockFile), "Failed to unmarshal")
|
||||
|
||||
preBeaconStateFile, err := testutil.BazelFileBytes(testsFolderPath, folder.Name(), "pre.ssz")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
preBeaconStateBase := &pb.BeaconState{}
|
||||
if err := preBeaconStateBase.UnmarshalSSZ(preBeaconStateFile); err != nil {
|
||||
t.Fatalf("Failed to unmarshal: %v", err)
|
||||
}
|
||||
require.NoError(t, preBeaconStateBase.UnmarshalSSZ(preBeaconStateFile), "Failed to unmarshal")
|
||||
preBeaconState, err := stateTrie.InitializeFromProto(preBeaconStateBase)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// If the post.ssz is not present, it means the test should fail on our end.
|
||||
postSSZFilepath, err := bazel.Runfile(path.Join(testsFolderPath, folder.Name(), "post.ssz"))
|
||||
postSSZExists := true
|
||||
if err != nil && strings.Contains(err.Error(), "could not locate file") {
|
||||
postSSZExists = false
|
||||
} else if err != nil {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
// Spectest blocks are not signed, so we'll call NoVerify to skip sig verification.
|
||||
beaconState, err := blocks.ProcessBlockHeaderNoVerify(preBeaconState, block)
|
||||
if postSSZExists {
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
postBeaconStateFile, err := ioutil.ReadFile(postSSZFilepath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
postBeaconState := &pb.BeaconState{}
|
||||
if err := postBeaconState.UnmarshalSSZ(postBeaconStateFile); err != nil {
|
||||
t.Fatalf("Failed to unmarshal: %v", err)
|
||||
}
|
||||
require.NoError(t, postBeaconState.UnmarshalSSZ(postBeaconStateFile), "Failed to unmarshal")
|
||||
if !proto.Equal(beaconState.CloneInnerState(), postBeaconState) {
|
||||
diff, _ := messagediff.PrettyDiff(beaconState.CloneInnerState(), postBeaconState)
|
||||
t.Log(diff)
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/params/spectest"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
"gopkg.in/d4l3k/messagediff.v1"
|
||||
)
|
||||
|
||||
@@ -27,48 +28,32 @@ func init() {
|
||||
}
|
||||
|
||||
func runBlockProcessingTest(t *testing.T, config string) {
|
||||
if err := spectest.SetConfig(t, config); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, spectest.SetConfig(t, config))
|
||||
|
||||
testFolders, testsFolderPath := testutil.TestFolders(t, config, "sanity/blocks/pyspec_tests")
|
||||
for _, folder := range testFolders {
|
||||
t.Run(folder.Name(), func(t *testing.T) {
|
||||
helpers.ClearCache()
|
||||
preBeaconStateFile, err := testutil.BazelFileBytes(testsFolderPath, folder.Name(), "pre.ssz")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
beaconStateBase := &pb.BeaconState{}
|
||||
if err := beaconStateBase.UnmarshalSSZ(preBeaconStateFile); err != nil {
|
||||
t.Fatalf("Failed to unmarshal: %v", err)
|
||||
}
|
||||
require.NoError(t, beaconStateBase.UnmarshalSSZ(preBeaconStateFile), "Failed to unmarshal")
|
||||
beaconState, err := stateTrie.InitializeFromProto(beaconStateBase)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
file, err := testutil.BazelFileBytes(testsFolderPath, folder.Name(), "meta.yaml")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
metaYaml := &SanityConfig{}
|
||||
if err := testutil.UnmarshalYaml(file, metaYaml); err != nil {
|
||||
t.Fatalf("Failed to Unmarshal: %v", err)
|
||||
}
|
||||
require.NoError(t, testutil.UnmarshalYaml(file, metaYaml), "Failed to Unmarshal")
|
||||
|
||||
var transitionError error
|
||||
for i := 0; i < metaYaml.BlocksCount; i++ {
|
||||
filename := fmt.Sprintf("blocks_%d.ssz", i)
|
||||
blockFile, err := testutil.BazelFileBytes(testsFolderPath, folder.Name(), filename)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
block := ðpb.SignedBeaconBlock{}
|
||||
if err := block.UnmarshalSSZ(blockFile); err != nil {
|
||||
t.Fatalf("Failed to unmarshal: %v", err)
|
||||
}
|
||||
require.NoError(t, block.UnmarshalSSZ(blockFile), "Failed to unmarshal")
|
||||
beaconState, transitionError = state.ExecuteStateTransition(context.Background(), beaconState, block)
|
||||
if transitionError != nil {
|
||||
break
|
||||
@@ -90,14 +75,10 @@ func runBlockProcessingTest(t *testing.T, config string) {
|
||||
}
|
||||
|
||||
postBeaconStateFile, err := ioutil.ReadFile(postSSZFilepath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
postBeaconState := &pb.BeaconState{}
|
||||
if err := postBeaconState.UnmarshalSSZ(postBeaconStateFile); err != nil {
|
||||
t.Fatalf("Failed to unmarshal: %v", err)
|
||||
}
|
||||
require.NoError(t, postBeaconState.UnmarshalSSZ(postBeaconStateFile), "Failed to unmarshal")
|
||||
|
||||
if !proto.Equal(beaconState.InnerStateUnsafe(), postBeaconState) {
|
||||
diff, _ := messagediff.PrettyDiff(beaconState.InnerStateUnsafe(), postBeaconState)
|
||||
|
||||
@@ -1,39 +1,30 @@
|
||||
package spectest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/shared/params/spectest"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
func runDepositTest(t *testing.T, config string) {
|
||||
if err := spectest.SetConfig(t, config); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, spectest.SetConfig(t, config))
|
||||
|
||||
testFolders, testsFolderPath := testutil.TestFolders(t, config, "operations/deposit/pyspec_tests")
|
||||
for _, folder := range testFolders {
|
||||
t.Run(folder.Name(), func(t *testing.T) {
|
||||
folderPath := path.Join(testsFolderPath, folder.Name())
|
||||
depositFile, err := testutil.BazelFileBytes(folderPath, "deposit.ssz")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
deposit := ðpb.Deposit{}
|
||||
if err := deposit.UnmarshalSSZ(depositFile); err != nil {
|
||||
t.Fatalf("Failed to unmarshal: %v", err)
|
||||
}
|
||||
require.NoError(t, deposit.UnmarshalSSZ(depositFile), "Failed to unmarshal")
|
||||
|
||||
body := ðpb.BeaconBlockBody{Deposits: []*ethpb.Deposit{deposit}}
|
||||
testutil.RunBlockOperationTest(t, folderPath, body, func(ctx context.Context, state *state.BeaconState, body *ethpb.BeaconBlockBody) (*state.BeaconState, error) {
|
||||
return blocks.ProcessDeposits(ctx, state, body.Deposits)
|
||||
})
|
||||
testutil.RunBlockOperationTest(t, folderPath, body, blocks.ProcessDeposits)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,25 +8,20 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/shared/params/spectest"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
func runProposerSlashingTest(t *testing.T, config string) {
|
||||
if err := spectest.SetConfig(t, config); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, spectest.SetConfig(t, config))
|
||||
|
||||
testFolders, testsFolderPath := testutil.TestFolders(t, config, "operations/proposer_slashing/pyspec_tests")
|
||||
for _, folder := range testFolders {
|
||||
t.Run(folder.Name(), func(t *testing.T) {
|
||||
folderPath := path.Join(testsFolderPath, folder.Name())
|
||||
proposerSlashingFile, err := testutil.BazelFileBytes(folderPath, "proposer_slashing.ssz")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
proposerSlashing := ðpb.ProposerSlashing{}
|
||||
if err := proposerSlashing.UnmarshalSSZ(proposerSlashingFile); err != nil {
|
||||
t.Fatalf("Failed to unmarshal: %v", err)
|
||||
}
|
||||
require.NoError(t, proposerSlashing.UnmarshalSSZ(proposerSlashingFile), "Failed to unmarshal")
|
||||
|
||||
body := ðpb.BeaconBlockBody{ProposerSlashings: []*ethpb.ProposerSlashing{proposerSlashing}}
|
||||
testutil.RunBlockOperationTest(t, folderPath, body, blocks.ProcessProposerSlashings)
|
||||
|
||||
@@ -8,25 +8,20 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/shared/params/spectest"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
func runVoluntaryExitTest(t *testing.T, config string) {
|
||||
if err := spectest.SetConfig(t, config); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, spectest.SetConfig(t, config))
|
||||
|
||||
testFolders, testsFolderPath := testutil.TestFolders(t, config, "operations/voluntary_exit/pyspec_tests")
|
||||
for _, folder := range testFolders {
|
||||
t.Run(folder.Name(), func(t *testing.T) {
|
||||
folderPath := path.Join(testsFolderPath, folder.Name())
|
||||
exitFile, err := testutil.BazelFileBytes(folderPath, "voluntary_exit.ssz")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
voluntaryExit := ðpb.SignedVoluntaryExit{}
|
||||
if err := voluntaryExit.UnmarshalSSZ(exitFile); err != nil {
|
||||
t.Fatalf("Failed to unmarshal: %v", err)
|
||||
}
|
||||
require.NoError(t, voluntaryExit.UnmarshalSSZ(exitFile), "Failed to unmarshal")
|
||||
|
||||
body := ðpb.BeaconBlockBody{VoluntaryExits: []*ethpb.SignedVoluntaryExit{voluntaryExit}}
|
||||
testutil.RunBlockOperationTest(t, folderPath, body, blocks.ProcessVoluntaryExits)
|
||||
|
||||
@@ -16,7 +16,6 @@ go_library(
|
||||
"//shared/params:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@com_github_prysmaticlabs_ethereumapis//eth/v1alpha1:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_ssz//:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -33,6 +32,9 @@ go_test(
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"//shared/testutil:go_default_library",
|
||||
"//shared/testutil/assert:go_default_library",
|
||||
"//shared/testutil/require:go_default_library",
|
||||
"@com_github_gogo_protobuf//proto:go_default_library",
|
||||
"@com_github_google_gofuzz//:go_default_library",
|
||||
"@com_github_prysmaticlabs_ethereumapis//eth/v1alpha1:go_default_library",
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
|
||||
"github.com/pkg/errors"
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/go-ssz"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/validators"
|
||||
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
@@ -46,7 +45,7 @@ func (s sortableIndices) Less(i, j int) bool {
|
||||
// def get_attesting_balance(state: BeaconState, attestations: List[PendingAttestation]) -> Gwei:
|
||||
// return get_total_balance(state, get_unslashed_attesting_indices(state, attestations))
|
||||
func AttestingBalance(state *stateTrie.BeaconState, atts []*pb.PendingAttestation) (uint64, error) {
|
||||
indices, err := unslashedAttestingIndices(state, atts)
|
||||
indices, err := UnslashedAttestingIndices(state, atts)
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "could not get attesting indices")
|
||||
}
|
||||
@@ -148,10 +147,11 @@ func ProcessRegistryUpdates(state *stateTrie.BeaconState) (*stateTrie.BeaconStat
|
||||
// def process_slashings(state: BeaconState) -> None:
|
||||
// epoch = get_current_epoch(state)
|
||||
// total_balance = get_total_active_balance(state)
|
||||
// adjusted_total_slashing_balance = min(sum(state.slashings) * PROPORTIONAL_SLASHING_MULTIPLIER, total_balance)
|
||||
// for index, validator in enumerate(state.validators):
|
||||
// if validator.slashed and epoch + EPOCHS_PER_SLASHINGS_VECTOR // 2 == validator.withdrawable_epoch:
|
||||
// increment = EFFECTIVE_BALANCE_INCREMENT # Factored out from penalty numerator to avoid uint64 overflow
|
||||
// penalty_numerator = validator.effective_balance // increment * min(sum(state.slashings) * 3, total_balance)
|
||||
// penalty_numerator = validator.effective_balance // increment * adjusted_total_slashing_balance
|
||||
// penalty = penalty_numerator // total_balance * increment
|
||||
// decrease_balance(state, ValidatorIndex(index), penalty)
|
||||
func ProcessSlashings(state *stateTrie.BeaconState) (*stateTrie.BeaconState, error) {
|
||||
@@ -174,10 +174,10 @@ func ProcessSlashings(state *stateTrie.BeaconState) (*stateTrie.BeaconState, err
|
||||
// a callback is used here to apply the following actions to all validators
|
||||
// below equally.
|
||||
increment := params.BeaconConfig().EffectiveBalanceIncrement
|
||||
minSlashing := mathutil.Min(totalSlashing*params.BeaconConfig().ProportionalSlashingMultiplier, totalBalance)
|
||||
err = state.ApplyToEveryValidator(func(idx int, val *ethpb.Validator) (bool, error) {
|
||||
correctEpoch := (currentEpoch + exitLength/2) == val.WithdrawableEpoch
|
||||
if val.Slashed && correctEpoch {
|
||||
minSlashing := mathutil.Min(totalSlashing*3, totalBalance)
|
||||
penaltyNumerator := val.EffectiveBalance / increment * minSlashing
|
||||
penalty := penaltyNumerator / totalBalance * increment
|
||||
if err := helpers.DecreaseBalance(state, uint64(idx), penalty); err != nil {
|
||||
@@ -311,7 +311,7 @@ func ProcessFinalUpdates(state *stateTrie.BeaconState) (*stateTrie.BeaconState,
|
||||
BlockRoots: state.BlockRoots(),
|
||||
StateRoots: state.StateRoots(),
|
||||
}
|
||||
batchRoot, err := ssz.HashTreeRoot(historicalBatch)
|
||||
batchRoot, err := historicalBatch.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not hash historical batch")
|
||||
}
|
||||
@@ -330,7 +330,7 @@ func ProcessFinalUpdates(state *stateTrie.BeaconState) (*stateTrie.BeaconState,
|
||||
return state, nil
|
||||
}
|
||||
|
||||
// unslashedAttestingIndices returns all the attesting indices from a list of attestations,
|
||||
// UnslashedAttestingIndices returns all the attesting indices from a list of attestations,
|
||||
// it sorts the indices and filters out the slashed ones.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
@@ -340,7 +340,7 @@ func ProcessFinalUpdates(state *stateTrie.BeaconState) (*stateTrie.BeaconState,
|
||||
// for a in attestations:
|
||||
// output = output.union(get_attesting_indices(state, a.data, a.aggregation_bits))
|
||||
// return set(filter(lambda index: not state.validators[index].slashed, output))
|
||||
func unslashedAttestingIndices(state *stateTrie.BeaconState, atts []*pb.PendingAttestation) ([]uint64, error) {
|
||||
func UnslashedAttestingIndices(state *stateTrie.BeaconState, atts []*pb.PendingAttestation) ([]uint64, error) {
|
||||
var setIndices []uint64
|
||||
seen := make(map[uint64]bool)
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
fuzz "github.com/google/gofuzz"
|
||||
beaconstate "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
ethereum_beacon_p2p_v1 "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
func TestFuzzFinalUpdates_10000(t *testing.T) {
|
||||
@@ -15,9 +16,8 @@ func TestFuzzFinalUpdates_10000(t *testing.T) {
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(base)
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(base)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
_, err = ProcessFinalUpdates(s)
|
||||
_ = err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
package epoch
|
||||
package epoch_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/go-bitfield"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/epoch"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
func TestUnslashedAttestingIndices_CanSortAndFilter(t *testing.T) {
|
||||
@@ -18,8 +21,8 @@ func TestUnslashedAttestingIndices_CanSortAndFilter(t *testing.T) {
|
||||
atts := make([]*pb.PendingAttestation, 2)
|
||||
for i := 0; i < len(atts); i++ {
|
||||
atts[i] = &pb.PendingAttestation{
|
||||
Data: ðpb.AttestationData{Source: ðpb.Checkpoint{},
|
||||
Target: ðpb.Checkpoint{Epoch: 0},
|
||||
Data: ðpb.AttestationData{Source: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
Target: ðpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
|
||||
},
|
||||
AggregationBits: bitfield.Bitlist{0xFF, 0xFF, 0xFF},
|
||||
}
|
||||
@@ -38,14 +41,10 @@ func TestUnslashedAttestingIndices_CanSortAndFilter(t *testing.T) {
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
}
|
||||
state, err := state.InitializeFromProto(base)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
indices, err := unslashedAttestingIndices(state, atts)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
indices, err := epoch.UnslashedAttestingIndices(state, atts)
|
||||
require.NoError(t, err)
|
||||
for i := 0; i < len(indices)-1; i++ {
|
||||
if indices[i] >= indices[i+1] {
|
||||
t.Error("sorted indices not sorted or duplicated")
|
||||
@@ -56,17 +55,11 @@ func TestUnslashedAttestingIndices_CanSortAndFilter(t *testing.T) {
|
||||
slashedValidator := indices[0]
|
||||
validators = state.Validators()
|
||||
validators[slashedValidator].Slashed = true
|
||||
if err = state.SetValidators(validators); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
indices, err = unslashedAttestingIndices(state, atts)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, state.SetValidators(validators))
|
||||
indices, err = epoch.UnslashedAttestingIndices(state, atts)
|
||||
require.NoError(t, err)
|
||||
for i := 0; i < len(indices); i++ {
|
||||
if indices[i] == slashedValidator {
|
||||
t.Errorf("Slashed validator %d is not filtered", slashedValidator)
|
||||
}
|
||||
assert.NotEqual(t, slashedValidator, indices[i], "Slashed validator %d is not filtered", slashedValidator)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,7 +68,7 @@ func TestUnslashedAttestingIndices_DuplicatedAttestations(t *testing.T) {
|
||||
atts := make([]*pb.PendingAttestation, 5)
|
||||
for i := 0; i < len(atts); i++ {
|
||||
atts[i] = &pb.PendingAttestation{
|
||||
Data: ðpb.AttestationData{Source: ðpb.Checkpoint{},
|
||||
Data: ðpb.AttestationData{Source: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
Target: ðpb.Checkpoint{Epoch: 0}},
|
||||
AggregationBits: bitfield.Bitlist{0xFF, 0xFF, 0xFF},
|
||||
}
|
||||
@@ -94,14 +87,10 @@ func TestUnslashedAttestingIndices_DuplicatedAttestations(t *testing.T) {
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
}
|
||||
state, err := state.InitializeFromProto(base)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
indices, err := unslashedAttestingIndices(state, atts)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
indices, err := epoch.UnslashedAttestingIndices(state, atts)
|
||||
require.NoError(t, err)
|
||||
|
||||
for i := 0; i < len(indices)-1; i++ {
|
||||
if indices[i] >= indices[i+1] {
|
||||
@@ -117,8 +106,8 @@ func TestAttestingBalance_CorrectBalance(t *testing.T) {
|
||||
for i := 0; i < len(atts); i++ {
|
||||
atts[i] = &pb.PendingAttestation{
|
||||
Data: ðpb.AttestationData{
|
||||
Target: ðpb.Checkpoint{},
|
||||
Source: ðpb.Checkpoint{},
|
||||
Target: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
Source: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
Slot: uint64(i),
|
||||
},
|
||||
AggregationBits: bitfield.Bitlist{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
@@ -144,18 +133,12 @@ func TestAttestingBalance_CorrectBalance(t *testing.T) {
|
||||
Balances: balances,
|
||||
}
|
||||
state, err := state.InitializeFromProto(base)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
balance, err := AttestingBalance(state, atts)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
balance, err := epoch.AttestingBalance(state, atts)
|
||||
require.NoError(t, err)
|
||||
wanted := 256 * params.BeaconConfig().MaxEffectiveBalance
|
||||
if balance != wanted {
|
||||
t.Errorf("wanted balance: %d, got: %d", wanted, balance)
|
||||
}
|
||||
assert.Equal(t, wanted, balance)
|
||||
}
|
||||
|
||||
func TestBaseReward_AccurateRewards(t *testing.T) {
|
||||
@@ -176,17 +159,10 @@ func TestBaseReward_AccurateRewards(t *testing.T) {
|
||||
Balances: []uint64{tt.a},
|
||||
}
|
||||
state, err := state.InitializeFromProto(base)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
c, err := BaseReward(state, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if c != tt.c {
|
||||
t.Errorf("BaseReward(%d) = %d, want = %d",
|
||||
tt.a, c, tt.c)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
c, err := epoch.BaseReward(state, 0)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tt.c, c, "epoch.BaseReward(%d)", tt.a)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,17 +174,11 @@ func TestProcessSlashings_NotSlashed(t *testing.T) {
|
||||
Slashings: []uint64{0, 1e9},
|
||||
}
|
||||
s, err := state.InitializeFromProto(base)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
newState, err := ProcessSlashings(s)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
newState, err := epoch.ProcessSlashings(s)
|
||||
require.NoError(t, err)
|
||||
wanted := params.BeaconConfig().MaxEffectiveBalance
|
||||
if newState.Balances()[0] != wanted {
|
||||
t.Errorf("Wanted slashed balance: %d, got: %d", wanted, newState.Balances()[0])
|
||||
}
|
||||
assert.Equal(t, wanted, newState.Balances()[0], "Unexpected slashed balance")
|
||||
}
|
||||
|
||||
func TestProcessSlashings_SlashedLess(t *testing.T) {
|
||||
@@ -282,83 +252,48 @@ func TestProcessSlashings_SlashedLess(t *testing.T) {
|
||||
t.Run(string(i), func(t *testing.T) {
|
||||
original := proto.Clone(tt.state)
|
||||
s, err := state.InitializeFromProto(tt.state)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
newState, err := ProcessSlashings(s)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if newState.Balances()[0] != tt.want {
|
||||
t.Errorf(
|
||||
"ProcessSlashings({%v}) = newState; newState.Balances[0] = %d; wanted %d",
|
||||
original,
|
||||
newState.Balances()[0],
|
||||
tt.want,
|
||||
)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
newState, err := epoch.ProcessSlashings(s)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tt.want, newState.Balances()[0], "ProcessSlashings({%v}) = newState; newState.Balances[0] = %d", original, newState.Balances()[0])
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessFinalUpdates_CanProcess(t *testing.T) {
|
||||
s := buildState(params.BeaconConfig().SlotsPerHistoricalRoot-1, params.BeaconConfig().SlotsPerEpoch)
|
||||
s := buildState(t, params.BeaconConfig().SlotsPerHistoricalRoot-1, params.BeaconConfig().SlotsPerEpoch)
|
||||
ce := helpers.CurrentEpoch(s)
|
||||
ne := ce + 1
|
||||
if err := s.SetEth1DataVotes([]*ethpb.Eth1Data{}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, s.SetEth1DataVotes([]*ethpb.Eth1Data{}))
|
||||
balances := s.Balances()
|
||||
balances[0] = 31.75 * 1e9
|
||||
balances[1] = 31.74 * 1e9
|
||||
if err := s.SetBalances(balances); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, s.SetBalances(balances))
|
||||
|
||||
slashings := s.Slashings()
|
||||
slashings[ce] = 0
|
||||
if err := s.SetSlashings(slashings); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, s.SetSlashings(slashings))
|
||||
mixes := s.RandaoMixes()
|
||||
mixes[ce] = []byte{'A'}
|
||||
if err := s.SetRandaoMixes(mixes); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
newS, err := ProcessFinalUpdates(s)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, s.SetRandaoMixes(mixes))
|
||||
newS, err := epoch.ProcessFinalUpdates(s)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify effective balance is correctly updated.
|
||||
if newS.Validators()[0].EffectiveBalance != params.BeaconConfig().MaxEffectiveBalance {
|
||||
t.Errorf("effective balance incorrectly updated, got %d", s.Validators()[0].EffectiveBalance)
|
||||
}
|
||||
if newS.Validators()[1].EffectiveBalance != 31*1e9 {
|
||||
t.Errorf("effective balance incorrectly updated, got %d", s.Validators()[1].EffectiveBalance)
|
||||
}
|
||||
assert.Equal(t, params.BeaconConfig().MaxEffectiveBalance, newS.Validators()[0].EffectiveBalance, "Effective balance incorrectly updated")
|
||||
assert.Equal(t, uint64(31*1e9), newS.Validators()[1].EffectiveBalance, "Effective balance incorrectly updated")
|
||||
|
||||
// Verify slashed balances correctly updated.
|
||||
if newS.Slashings()[ce] != newS.Slashings()[ne] {
|
||||
t.Errorf("wanted slashed balance %d, got %d",
|
||||
newS.Slashings()[ce],
|
||||
newS.Slashings()[ne])
|
||||
}
|
||||
assert.Equal(t, newS.Slashings()[ce], newS.Slashings()[ne], "Unexpected slashed balance")
|
||||
|
||||
// Verify randao is correctly updated in the right position.
|
||||
if mix, err := newS.RandaoMixAtIndex(ne); err != nil || bytes.Equal(mix, params.BeaconConfig().ZeroHash[:]) {
|
||||
t.Error("latest RANDAO still zero hashes")
|
||||
}
|
||||
mix, err := newS.RandaoMixAtIndex(ne)
|
||||
assert.NoError(t, err)
|
||||
assert.DeepNotEqual(t, params.BeaconConfig().ZeroHash[:], mix, "latest RANDAO still zero hashes")
|
||||
|
||||
// Verify historical root accumulator was appended.
|
||||
if len(newS.HistoricalRoots()) != 1 {
|
||||
t.Errorf("wanted slashed balance %d, got %d", 1, len(newS.HistoricalRoots()[ce]))
|
||||
}
|
||||
|
||||
if newS.CurrentEpochAttestations() == nil {
|
||||
t.Error("nil value stored in current epoch attestations instead of empty slice")
|
||||
}
|
||||
assert.Equal(t, 1, len(newS.HistoricalRoots()), "Unexpected slashed balance")
|
||||
assert.NotNil(t, newS.CurrentEpochAttestations(), "Nil value stored in current epoch attestations instead of empty slice")
|
||||
}
|
||||
|
||||
func TestProcessRegistryUpdates_NoRotation(t *testing.T) {
|
||||
@@ -372,33 +307,24 @@ func TestProcessRegistryUpdates_NoRotation(t *testing.T) {
|
||||
params.BeaconConfig().MaxEffectiveBalance,
|
||||
params.BeaconConfig().MaxEffectiveBalance,
|
||||
},
|
||||
FinalizedCheckpoint: ðpb.Checkpoint{},
|
||||
FinalizedCheckpoint: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
}
|
||||
state, err := state.InitializeFromProto(base)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
newState, err := ProcessRegistryUpdates(state)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
newState, err := epoch.ProcessRegistryUpdates(state)
|
||||
require.NoError(t, err)
|
||||
for i, validator := range newState.Validators() {
|
||||
if validator.ExitEpoch != params.BeaconConfig().MaxSeedLookahead {
|
||||
t.Errorf("Could not update registry %d, wanted exit slot %d got %d",
|
||||
i, params.BeaconConfig().MaxSeedLookahead, validator.ExitEpoch)
|
||||
}
|
||||
assert.Equal(t, params.BeaconConfig().MaxSeedLookahead, validator.ExitEpoch, "Could not update registry %d", i)
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessRegistryUpdates_EligibleToActivate(t *testing.T) {
|
||||
base := &pb.BeaconState{
|
||||
Slot: 5 * params.BeaconConfig().SlotsPerEpoch,
|
||||
FinalizedCheckpoint: ðpb.Checkpoint{Epoch: 6},
|
||||
FinalizedCheckpoint: ðpb.Checkpoint{Epoch: 6, Root: make([]byte, 32)},
|
||||
}
|
||||
limit, err := helpers.ValidatorChurnLimit(0)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
for i := uint64(0); i < limit+10; i++ {
|
||||
base.Validators = append(base.Validators, ðpb.Validator{
|
||||
ActivationEligibilityEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
@@ -407,16 +333,12 @@ func TestProcessRegistryUpdates_EligibleToActivate(t *testing.T) {
|
||||
})
|
||||
}
|
||||
state, err := state.InitializeFromProto(base)
|
||||
require.NoError(t, err)
|
||||
currentEpoch := helpers.CurrentEpoch(state)
|
||||
newState, err := ProcessRegistryUpdates(state)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
newState, err := epoch.ProcessRegistryUpdates(state)
|
||||
require.NoError(t, err)
|
||||
for i, validator := range newState.Validators() {
|
||||
if validator.ActivationEligibilityEpoch != currentEpoch+1 {
|
||||
t.Errorf("Could not update registry %d, wanted activation eligibility epoch %d got %d",
|
||||
i, currentEpoch, validator.ActivationEligibilityEpoch)
|
||||
}
|
||||
assert.Equal(t, currentEpoch+1, validator.ActivationEligibilityEpoch, "Could not update registry %d, unexpected activation eligibility epoch", i)
|
||||
if uint64(i) < limit && validator.ActivationEpoch != helpers.ActivationExitEpoch(currentEpoch) {
|
||||
t.Errorf("Could not update registry %d, validators failed to activate: wanted activation epoch %d, got %d",
|
||||
i, helpers.ActivationExitEpoch(currentEpoch), validator.ActivationEpoch)
|
||||
@@ -437,21 +359,14 @@ func TestProcessRegistryUpdates_ActivationCompletes(t *testing.T) {
|
||||
{ExitEpoch: params.BeaconConfig().MaxSeedLookahead,
|
||||
ActivationEpoch: 5 + params.BeaconConfig().MaxSeedLookahead + 1},
|
||||
},
|
||||
FinalizedCheckpoint: ðpb.Checkpoint{},
|
||||
FinalizedCheckpoint: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
}
|
||||
state, err := state.InitializeFromProto(base)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
newState, err := ProcessRegistryUpdates(state)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
newState, err := epoch.ProcessRegistryUpdates(state)
|
||||
require.NoError(t, err)
|
||||
for i, validator := range newState.Validators() {
|
||||
if validator.ExitEpoch != params.BeaconConfig().MaxSeedLookahead {
|
||||
t.Errorf("Could not update registry %d, wanted exit slot %d got %d",
|
||||
i, params.BeaconConfig().MaxSeedLookahead, validator.ExitEpoch)
|
||||
}
|
||||
assert.Equal(t, params.BeaconConfig().MaxSeedLookahead, validator.ExitEpoch, "Could not update registry %d, unexpected exit slot", i)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -468,30 +383,23 @@ func TestProcessRegistryUpdates_ValidatorsEjected(t *testing.T) {
|
||||
EffectiveBalance: params.BeaconConfig().EjectionBalance - 1,
|
||||
},
|
||||
},
|
||||
FinalizedCheckpoint: ðpb.Checkpoint{},
|
||||
FinalizedCheckpoint: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
}
|
||||
state, err := state.InitializeFromProto(base)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
newState, err := ProcessRegistryUpdates(state)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
newState, err := epoch.ProcessRegistryUpdates(state)
|
||||
require.NoError(t, err)
|
||||
for i, validator := range newState.Validators() {
|
||||
if validator.ExitEpoch != params.BeaconConfig().MaxSeedLookahead+1 {
|
||||
t.Errorf("Could not update registry %d, wanted exit slot %d got %d",
|
||||
i, params.BeaconConfig().MaxSeedLookahead+1, validator.ExitEpoch)
|
||||
}
|
||||
assert.Equal(t, params.BeaconConfig().MaxSeedLookahead+1, validator.ExitEpoch, "Could not update registry %d, unexpected exit slot", i)
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessRegistryUpdates_CanExits(t *testing.T) {
|
||||
epoch := uint64(5)
|
||||
exitEpoch := helpers.ActivationExitEpoch(epoch)
|
||||
e := uint64(5)
|
||||
exitEpoch := helpers.ActivationExitEpoch(e)
|
||||
minWithdrawalDelay := params.BeaconConfig().MinValidatorWithdrawabilityDelay
|
||||
base := &pb.BeaconState{
|
||||
Slot: epoch * params.BeaconConfig().SlotsPerEpoch,
|
||||
Slot: e * params.BeaconConfig().SlotsPerEpoch,
|
||||
Validators: []*ethpb.Validator{
|
||||
{
|
||||
ExitEpoch: exitEpoch,
|
||||
@@ -500,28 +408,18 @@ func TestProcessRegistryUpdates_CanExits(t *testing.T) {
|
||||
ExitEpoch: exitEpoch,
|
||||
WithdrawableEpoch: exitEpoch + minWithdrawalDelay},
|
||||
},
|
||||
FinalizedCheckpoint: ðpb.Checkpoint{},
|
||||
FinalizedCheckpoint: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
}
|
||||
state, err := state.InitializeFromProto(base)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
newState, err := ProcessRegistryUpdates(state)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
newState, err := epoch.ProcessRegistryUpdates(state)
|
||||
require.NoError(t, err)
|
||||
for i, validator := range newState.Validators() {
|
||||
if validator.ExitEpoch != exitEpoch {
|
||||
t.Errorf("Could not update registry %d, wanted exit slot %d got %d",
|
||||
i,
|
||||
exitEpoch,
|
||||
validator.ExitEpoch,
|
||||
)
|
||||
}
|
||||
assert.Equal(t, exitEpoch, validator.ExitEpoch, "Could not update registry %d, unexpected exit slot", i)
|
||||
}
|
||||
}
|
||||
|
||||
func buildState(slot uint64, validatorCount uint64) *state.BeaconState {
|
||||
func buildState(t testing.TB, slot uint64, validatorCount uint64) *state.BeaconState {
|
||||
validators := make([]*ethpb.Validator, validatorCount)
|
||||
for i := 0; i < len(validators); i++ {
|
||||
validators[i] = ðpb.Validator{
|
||||
@@ -547,19 +445,15 @@ func buildState(slot uint64, validatorCount uint64) *state.BeaconState {
|
||||
for i := 0; i < len(latestRandaoMixes); i++ {
|
||||
latestRandaoMixes[i] = params.BeaconConfig().ZeroHash[:]
|
||||
}
|
||||
s, err := state.InitializeFromProto(&pb.BeaconState{
|
||||
Slot: slot,
|
||||
Balances: validatorBalances,
|
||||
Validators: validators,
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
Slashings: make([]uint64, params.BeaconConfig().EpochsPerSlashingsVector),
|
||||
BlockRoots: make([][]byte, params.BeaconConfig().SlotsPerEpoch*10),
|
||||
FinalizedCheckpoint: ðpb.Checkpoint{},
|
||||
PreviousJustifiedCheckpoint: ðpb.Checkpoint{},
|
||||
CurrentJustifiedCheckpoint: ðpb.Checkpoint{},
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
s := testutil.NewBeaconState()
|
||||
if err := s.SetSlot(slot); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if err := s.SetBalances(validatorBalances); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if err := s.SetValidators(validators); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
@@ -46,6 +46,8 @@ go_test(
|
||||
"//shared/mathutil:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"//shared/testutil:go_default_library",
|
||||
"//shared/testutil/assert:go_default_library",
|
||||
"//shared/testutil/require:go_default_library",
|
||||
"@com_github_gogo_protobuf//proto:go_default_library",
|
||||
"@com_github_prysmaticlabs_ethereumapis//eth/v1alpha1:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
|
||||
|
||||
@@ -33,6 +33,9 @@ func ProcessAttestations(
|
||||
var err error
|
||||
|
||||
for _, a := range append(state.PreviousEpochAttestations(), state.CurrentEpochAttestations()...) {
|
||||
if a.InclusionDelay == 0 {
|
||||
return nil, nil, errors.New("attestation with inclusion delay of 0")
|
||||
}
|
||||
v.IsCurrentEpochAttester, v.IsCurrentEpochTargetAttester, err = AttestedCurrentEpoch(state, a)
|
||||
if err != nil {
|
||||
traceutil.AnnotateError(span, err)
|
||||
|
||||
@@ -2,7 +2,6 @@ package precompute_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
@@ -12,6 +11,8 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/shared/attestationutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
func TestUpdateValidator_Works(t *testing.T) {
|
||||
@@ -28,9 +29,7 @@ func TestUpdateValidator_Works(t *testing.T) {
|
||||
IsPrevEpochAttester: true, IsPrevEpochTargetAttester: true, IsPrevEpochHeadAttester: true,
|
||||
ProposerIndex: 2, InclusionDistance: 1, InclusionSlot: 101}
|
||||
wantedVp := []*precompute.Validator{{}, wanted, {}, wanted, {}, wanted}
|
||||
if !reflect.DeepEqual(vp, wantedVp) {
|
||||
t.Error("Incorrect attesting validator calculations")
|
||||
}
|
||||
assert.DeepEqual(t, wantedVp, vp, "Incorrect attesting validator calculations")
|
||||
}
|
||||
|
||||
func TestUpdateValidator_InclusionOnlyCountsPrevEpoch(t *testing.T) {
|
||||
@@ -43,9 +42,7 @@ func TestUpdateValidator_InclusionOnlyCountsPrevEpoch(t *testing.T) {
|
||||
vp = precompute.UpdateValidator(vp, record, []uint64{0}, a, 100)
|
||||
wanted := &precompute.Validator{IsCurrentEpochAttester: true, IsCurrentEpochTargetAttester: true, InclusionSlot: e}
|
||||
wantedVp := []*precompute.Validator{wanted}
|
||||
if !reflect.DeepEqual(vp, wantedVp) {
|
||||
t.Error("Incorrect attesting validator calculations")
|
||||
}
|
||||
assert.DeepEqual(t, wantedVp, vp, "Incorrect attesting validator calculations")
|
||||
}
|
||||
|
||||
func TestUpdateBalance(t *testing.T) {
|
||||
@@ -69,131 +66,83 @@ func TestUpdateBalance(t *testing.T) {
|
||||
PrevEpochHeadAttested: 200 * params.BeaconConfig().EffectiveBalanceIncrement,
|
||||
}
|
||||
pBal := precompute.UpdateBalance(vp, &precompute.Balance{})
|
||||
if !reflect.DeepEqual(pBal, wantedPBal) {
|
||||
t.Error("Incorrect balance calculations")
|
||||
}
|
||||
assert.DeepEqual(t, wantedPBal, pBal, "Incorrect balance calculations")
|
||||
}
|
||||
|
||||
func TestSameHead(t *testing.T) {
|
||||
beaconState, _ := testutil.DeterministicGenesisState(t, 100)
|
||||
if err := beaconState.SetSlot(1); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, beaconState.SetSlot(1))
|
||||
att := ðpb.Attestation{Data: ðpb.AttestationData{
|
||||
Target: ðpb.Checkpoint{Epoch: 0}}}
|
||||
r := [32]byte{'A'}
|
||||
br := beaconState.BlockRoots()
|
||||
br[0] = r[:]
|
||||
if err := beaconState.SetBlockRoots(br); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, beaconState.SetBlockRoots(br))
|
||||
att.Data.BeaconBlockRoot = r[:]
|
||||
same, err := precompute.SameHead(beaconState, &pb.PendingAttestation{Data: att.Data})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !same {
|
||||
t.Error("head in state does not match head in attestation")
|
||||
}
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, true, same, "Head in state does not match head in attestation")
|
||||
newRoot := [32]byte{'B'}
|
||||
att.Data.BeaconBlockRoot = newRoot[:]
|
||||
same, err = precompute.SameHead(beaconState, &pb.PendingAttestation{Data: att.Data})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if same {
|
||||
t.Error("head in state matches head in attestation")
|
||||
}
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, false, same, "Head in state matches head in attestation")
|
||||
}
|
||||
|
||||
func TestSameTarget(t *testing.T) {
|
||||
beaconState, _ := testutil.DeterministicGenesisState(t, 100)
|
||||
if err := beaconState.SetSlot(1); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, beaconState.SetSlot(1))
|
||||
att := ðpb.Attestation{Data: ðpb.AttestationData{
|
||||
Target: ðpb.Checkpoint{Epoch: 0}}}
|
||||
r := [32]byte{'A'}
|
||||
br := beaconState.BlockRoots()
|
||||
br[0] = r[:]
|
||||
if err := beaconState.SetBlockRoots(br); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, beaconState.SetBlockRoots(br))
|
||||
att.Data.Target.Root = r[:]
|
||||
same, err := precompute.SameTarget(beaconState, &pb.PendingAttestation{Data: att.Data}, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !same {
|
||||
t.Error("head in state does not match head in attestation")
|
||||
}
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, true, same, "Head in state does not match head in attestation")
|
||||
newRoot := [32]byte{'B'}
|
||||
att.Data.Target.Root = newRoot[:]
|
||||
same, err = precompute.SameTarget(beaconState, &pb.PendingAttestation{Data: att.Data}, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if same {
|
||||
t.Error("head in state matches head in attestation")
|
||||
}
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, false, same, "Head in state matches head in attestation")
|
||||
}
|
||||
|
||||
func TestAttestedPrevEpoch(t *testing.T) {
|
||||
beaconState, _ := testutil.DeterministicGenesisState(t, 100)
|
||||
if err := beaconState.SetSlot(params.BeaconConfig().SlotsPerEpoch); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, beaconState.SetSlot(params.BeaconConfig().SlotsPerEpoch))
|
||||
att := ðpb.Attestation{Data: ðpb.AttestationData{
|
||||
Target: ðpb.Checkpoint{Epoch: 0}}}
|
||||
r := [32]byte{'A'}
|
||||
br := beaconState.BlockRoots()
|
||||
br[0] = r[:]
|
||||
if err := beaconState.SetBlockRoots(br); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, beaconState.SetBlockRoots(br))
|
||||
att.Data.Target.Root = r[:]
|
||||
att.Data.BeaconBlockRoot = r[:]
|
||||
votedEpoch, votedTarget, votedHead, err := precompute.AttestedPrevEpoch(beaconState, &pb.PendingAttestation{Data: att.Data})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !votedEpoch {
|
||||
t.Error("did not vote epoch")
|
||||
}
|
||||
if !votedTarget {
|
||||
t.Error("did not vote target")
|
||||
}
|
||||
if !votedHead {
|
||||
t.Error("did not vote head")
|
||||
}
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, true, votedEpoch, "Did not vote epoch")
|
||||
assert.Equal(t, true, votedTarget, "Did not vote target")
|
||||
assert.Equal(t, true, votedHead, "Did not vote head")
|
||||
}
|
||||
|
||||
func TestAttestedCurrentEpoch(t *testing.T) {
|
||||
beaconState, _ := testutil.DeterministicGenesisState(t, 100)
|
||||
if err := beaconState.SetSlot(params.BeaconConfig().SlotsPerEpoch + 1); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, beaconState.SetSlot(params.BeaconConfig().SlotsPerEpoch+1))
|
||||
att := ðpb.Attestation{Data: ðpb.AttestationData{
|
||||
Target: ðpb.Checkpoint{Epoch: 1}}}
|
||||
r := [32]byte{'A'}
|
||||
|
||||
br := beaconState.BlockRoots()
|
||||
br[params.BeaconConfig().SlotsPerEpoch] = r[:]
|
||||
if err := beaconState.SetBlockRoots(br); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, beaconState.SetBlockRoots(br))
|
||||
att.Data.Target.Root = r[:]
|
||||
att.Data.BeaconBlockRoot = r[:]
|
||||
votedEpoch, votedTarget, err := precompute.AttestedCurrentEpoch(beaconState, &pb.PendingAttestation{Data: att.Data})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !votedEpoch {
|
||||
t.Error("did not vote epoch")
|
||||
}
|
||||
if !votedTarget {
|
||||
t.Error("did not vote target")
|
||||
}
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, true, votedEpoch, "Did not vote epoch")
|
||||
assert.Equal(t, true, votedTarget, "Did not vote target")
|
||||
}
|
||||
|
||||
func TestProcessAttestations(t *testing.T) {
|
||||
@@ -202,9 +151,7 @@ func TestProcessAttestations(t *testing.T) {
|
||||
|
||||
validators := uint64(64)
|
||||
beaconState, _ := testutil.DeterministicGenesisState(t, validators)
|
||||
if err := beaconState.SetSlot(params.BeaconConfig().SlotsPerEpoch); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, beaconState.SetSlot(params.BeaconConfig().SlotsPerEpoch))
|
||||
|
||||
bf := []byte{0xff}
|
||||
att1 := ðpb.Attestation{Data: ðpb.AttestationData{
|
||||
@@ -219,34 +166,23 @@ func TestProcessAttestations(t *testing.T) {
|
||||
br := beaconState.BlockRoots()
|
||||
newRt := [32]byte{'B'}
|
||||
br[0] = newRt[:]
|
||||
if err := beaconState.SetBlockRoots(br); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, beaconState.SetBlockRoots(br))
|
||||
att2.Data.Target.Root = newRt[:]
|
||||
att2.Data.BeaconBlockRoot = newRt[:]
|
||||
err := beaconState.SetPreviousEpochAttestations([]*pb.PendingAttestation{{Data: att1.Data, AggregationBits: bf}})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = beaconState.SetCurrentEpochAttestations([]*pb.PendingAttestation{{Data: att2.Data, AggregationBits: bf}})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err := beaconState.SetPreviousEpochAttestations([]*pb.PendingAttestation{{Data: att1.Data, AggregationBits: bf, InclusionDelay: 1}})
|
||||
require.NoError(t, err)
|
||||
err = beaconState.SetCurrentEpochAttestations([]*pb.PendingAttestation{{Data: att2.Data, AggregationBits: bf, InclusionDelay: 1}})
|
||||
require.NoError(t, err)
|
||||
|
||||
pVals := make([]*precompute.Validator, validators)
|
||||
for i := 0; i < len(pVals); i++ {
|
||||
pVals[i] = &precompute.Validator{CurrentEpochEffectiveBalance: 100}
|
||||
}
|
||||
pBal := &precompute.Balance{}
|
||||
pVals, pBal, err = precompute.ProcessAttestations(context.Background(), beaconState, pVals, pBal)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
pVals, _, err = precompute.ProcessAttestations(context.Background(), beaconState, pVals, &precompute.Balance{})
|
||||
require.NoError(t, err)
|
||||
|
||||
committee, err := helpers.BeaconCommitteeFromState(beaconState, att1.Data.Slot, att1.Data.CommitteeIndex)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
indices := attestationutil.AttestingIndices(att1.AggregationBits, committee)
|
||||
for _, i := range indices {
|
||||
if !pVals[i].IsPrevEpochAttester {
|
||||
@@ -254,45 +190,24 @@ func TestProcessAttestations(t *testing.T) {
|
||||
}
|
||||
}
|
||||
committee, err = helpers.BeaconCommitteeFromState(beaconState, att2.Data.Slot, att2.Data.CommitteeIndex)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
indices = attestationutil.AttestingIndices(att2.AggregationBits, committee)
|
||||
for _, i := range indices {
|
||||
if !pVals[i].IsPrevEpochAttester {
|
||||
t.Error("Not a prev epoch attester")
|
||||
}
|
||||
if !pVals[i].IsPrevEpochTargetAttester {
|
||||
t.Error("Not a prev epoch target attester")
|
||||
}
|
||||
if !pVals[i].IsPrevEpochHeadAttester {
|
||||
t.Error("Not a prev epoch head attester")
|
||||
}
|
||||
assert.Equal(t, true, pVals[i].IsPrevEpochAttester, "Not a prev epoch attester")
|
||||
assert.Equal(t, true, pVals[i].IsPrevEpochTargetAttester, "Not a prev epoch target attester")
|
||||
assert.Equal(t, true, pVals[i].IsPrevEpochHeadAttester, "Not a prev epoch head attester")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnsureBalancesLowerBound(t *testing.T) {
|
||||
b := &precompute.Balance{}
|
||||
b = precompute.EnsureBalancesLowerBound(b)
|
||||
if b.ActiveCurrentEpoch != params.BeaconConfig().EffectiveBalanceIncrement {
|
||||
t.Error("Did not get wanted active current balance")
|
||||
}
|
||||
if b.ActivePrevEpoch != params.BeaconConfig().EffectiveBalanceIncrement {
|
||||
t.Error("Did not get wanted active previous balance")
|
||||
}
|
||||
if b.CurrentEpochAttested != params.BeaconConfig().EffectiveBalanceIncrement {
|
||||
t.Error("Did not get wanted current attested balance")
|
||||
}
|
||||
if b.CurrentEpochTargetAttested != params.BeaconConfig().EffectiveBalanceIncrement {
|
||||
t.Error("Did not get wanted target attested balance")
|
||||
}
|
||||
if b.PrevEpochAttested != params.BeaconConfig().EffectiveBalanceIncrement {
|
||||
t.Error("Did not get wanted prev attested balance")
|
||||
}
|
||||
if b.PrevEpochTargetAttested != params.BeaconConfig().EffectiveBalanceIncrement {
|
||||
t.Error("Did not get wanted prev target attested balance")
|
||||
}
|
||||
if b.PrevEpochHeadAttested != params.BeaconConfig().EffectiveBalanceIncrement {
|
||||
t.Error("Did not get wanted prev head attested balance")
|
||||
}
|
||||
balanceIncrement := params.BeaconConfig().EffectiveBalanceIncrement
|
||||
assert.Equal(t, balanceIncrement, b.ActiveCurrentEpoch, "Did not get wanted active current balance")
|
||||
assert.Equal(t, balanceIncrement, b.ActivePrevEpoch, "Did not get wanted active previous balance")
|
||||
assert.Equal(t, balanceIncrement, b.CurrentEpochAttested, "Did not get wanted current attested balance")
|
||||
assert.Equal(t, balanceIncrement, b.CurrentEpochTargetAttested, "Did not get wanted target attested balance")
|
||||
assert.Equal(t, balanceIncrement, b.PrevEpochAttested, "Did not get wanted prev attested balance")
|
||||
assert.Equal(t, balanceIncrement, b.PrevEpochTargetAttested, "Did not get wanted prev target attested balance")
|
||||
assert.Equal(t, balanceIncrement, b.PrevEpochHeadAttested, "Did not get wanted prev head attested balance")
|
||||
}
|
||||
|
||||
@@ -49,7 +49,11 @@ import (
|
||||
// if all(bits[0:2]) and old_current_justified_checkpoint.epoch + 1 == current_epoch:
|
||||
// state.finalized_checkpoint = old_current_justified_checkpoint
|
||||
func ProcessJustificationAndFinalizationPreCompute(state *stateTrie.BeaconState, pBal *Balance) (*stateTrie.BeaconState, error) {
|
||||
if state.Slot() <= helpers.StartSlot(2) {
|
||||
canProcessSlot, err := helpers.StartSlot(2 /*epoch*/)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if state.Slot() <= canProcessSlot {
|
||||
return state, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package precompute_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
@@ -10,6 +9,8 @@ import (
|
||||
beaconstate "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
func TestProcessJustificationAndFinalizationPreCompute_ConsecutiveEpochs(t *testing.T) {
|
||||
@@ -29,42 +30,24 @@ func TestProcessJustificationAndFinalizationPreCompute_ConsecutiveEpochs(t *test
|
||||
Epoch: 0,
|
||||
Root: params.BeaconConfig().ZeroHash[:],
|
||||
},
|
||||
FinalizedCheckpoint: ðpb.Checkpoint{},
|
||||
FinalizedCheckpoint: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
JustificationBits: bitfield.Bitvector4{0x0F}, // 0b1111
|
||||
Validators: []*ethpb.Validator{{ExitEpoch: e}, {ExitEpoch: e}, {ExitEpoch: e}, {ExitEpoch: e}},
|
||||
Balances: []uint64{a, a, a, a}, // validator total balance should be 128000000000
|
||||
BlockRoots: blockRoots,
|
||||
}
|
||||
state, err := beaconstate.InitializeFromProto(base)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
attestedBalance := 4 * e * 3 / 2
|
||||
b := &precompute.Balance{PrevEpochTargetAttested: attestedBalance}
|
||||
newState, err := precompute.ProcessJustificationAndFinalizationPreCompute(state, b)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
rt := [32]byte{byte(64)}
|
||||
if !bytes.Equal(newState.CurrentJustifiedCheckpoint().Root, rt[:]) {
|
||||
t.Errorf("Wanted current justified root: %v, got: %v",
|
||||
[]byte{byte(64)}, newState.CurrentJustifiedCheckpoint().Root)
|
||||
}
|
||||
if newState.CurrentJustifiedCheckpoint().Epoch != 2 {
|
||||
t.Errorf("Wanted justified epoch: %d, got: %d",
|
||||
2, newState.CurrentJustifiedCheckpoint().Epoch)
|
||||
}
|
||||
if newState.PreviousJustifiedCheckpoint().Epoch != 0 {
|
||||
t.Errorf("Wanted previous justified epoch: %d, got: %d",
|
||||
0, newState.PreviousJustifiedCheckpoint().Epoch)
|
||||
}
|
||||
if !bytes.Equal(newState.FinalizedCheckpoint().Root, params.BeaconConfig().ZeroHash[:]) {
|
||||
t.Errorf("Wanted current finalized root: %v, got: %v",
|
||||
params.BeaconConfig().ZeroHash, newState.FinalizedCheckpoint().Root)
|
||||
}
|
||||
if newState.FinalizedCheckpointEpoch() != 0 {
|
||||
t.Errorf("Wanted finalized epoch: 0, got: %d", newState.FinalizedCheckpointEpoch())
|
||||
}
|
||||
assert.DeepEqual(t, rt[:], newState.CurrentJustifiedCheckpoint().Root, "Unexpected justified root")
|
||||
assert.Equal(t, uint64(2), newState.CurrentJustifiedCheckpoint().Epoch, "Unexpected justified epoch")
|
||||
assert.Equal(t, uint64(0), newState.PreviousJustifiedCheckpoint().Epoch, "Unexpected previous justified epoch")
|
||||
assert.DeepEqual(t, params.BeaconConfig().ZeroHash[:], newState.FinalizedCheckpoint().Root, "Unexpected finalized root")
|
||||
assert.Equal(t, uint64(0), newState.FinalizedCheckpointEpoch(), "Unexpected finalized epoch")
|
||||
}
|
||||
|
||||
func TestProcessJustificationAndFinalizationPreCompute_JustifyCurrentEpoch(t *testing.T) {
|
||||
@@ -84,42 +67,24 @@ func TestProcessJustificationAndFinalizationPreCompute_JustifyCurrentEpoch(t *te
|
||||
Epoch: 0,
|
||||
Root: params.BeaconConfig().ZeroHash[:],
|
||||
},
|
||||
FinalizedCheckpoint: ðpb.Checkpoint{},
|
||||
FinalizedCheckpoint: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
JustificationBits: bitfield.Bitvector4{0x03}, // 0b0011
|
||||
Validators: []*ethpb.Validator{{ExitEpoch: e}, {ExitEpoch: e}, {ExitEpoch: e}, {ExitEpoch: e}},
|
||||
Balances: []uint64{a, a, a, a}, // validator total balance should be 128000000000
|
||||
BlockRoots: blockRoots,
|
||||
}
|
||||
state, err := beaconstate.InitializeFromProto(base)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
attestedBalance := 4 * e * 3 / 2
|
||||
b := &precompute.Balance{PrevEpochTargetAttested: attestedBalance}
|
||||
newState, err := precompute.ProcessJustificationAndFinalizationPreCompute(state, b)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
rt := [32]byte{byte(64)}
|
||||
if !bytes.Equal(newState.CurrentJustifiedCheckpoint().Root, rt[:]) {
|
||||
t.Errorf("Wanted current justified root: %v, got: %v",
|
||||
[]byte{byte(64)}, newState.CurrentJustifiedCheckpoint().Root)
|
||||
}
|
||||
if newState.CurrentJustifiedCheckpoint().Epoch != 2 {
|
||||
t.Errorf("Wanted justified epoch: %d, got: %d",
|
||||
2, newState.CurrentJustifiedCheckpoint().Epoch)
|
||||
}
|
||||
if newState.PreviousJustifiedCheckpoint().Epoch != 0 {
|
||||
t.Errorf("Wanted previous justified epoch: %d, got: %d",
|
||||
0, newState.PreviousJustifiedCheckpoint().Epoch)
|
||||
}
|
||||
if !bytes.Equal(newState.FinalizedCheckpoint().Root, params.BeaconConfig().ZeroHash[:]) {
|
||||
t.Errorf("Wanted current finalized root: %v, got: %v",
|
||||
params.BeaconConfig().ZeroHash, newState.FinalizedCheckpoint().Root)
|
||||
}
|
||||
if newState.FinalizedCheckpointEpoch() != 0 {
|
||||
t.Errorf("Wanted finalized epoch: 0, got: %d", newState.FinalizedCheckpointEpoch())
|
||||
}
|
||||
assert.DeepEqual(t, rt[:], newState.CurrentJustifiedCheckpoint().Root, "Unexpected current justified root")
|
||||
assert.Equal(t, uint64(2), newState.CurrentJustifiedCheckpoint().Epoch, "Unexpected justified epoch")
|
||||
assert.Equal(t, uint64(0), newState.PreviousJustifiedCheckpoint().Epoch, "Unexpected previous justified epoch")
|
||||
assert.DeepEqual(t, params.BeaconConfig().ZeroHash[:], newState.FinalizedCheckpoint().Root)
|
||||
assert.Equal(t, uint64(0), newState.FinalizedCheckpointEpoch(), "Unexpected finalized epoch")
|
||||
}
|
||||
|
||||
func TestProcessJustificationAndFinalizationPreCompute_JustifyPrevEpoch(t *testing.T) {
|
||||
@@ -142,36 +107,18 @@ func TestProcessJustificationAndFinalizationPreCompute_JustifyPrevEpoch(t *testi
|
||||
JustificationBits: bitfield.Bitvector4{0x03}, // 0b0011
|
||||
Validators: []*ethpb.Validator{{ExitEpoch: e}, {ExitEpoch: e}, {ExitEpoch: e}, {ExitEpoch: e}},
|
||||
Balances: []uint64{a, a, a, a}, // validator total balance should be 128000000000
|
||||
BlockRoots: blockRoots, FinalizedCheckpoint: ðpb.Checkpoint{},
|
||||
BlockRoots: blockRoots, FinalizedCheckpoint: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
}
|
||||
state, err := beaconstate.InitializeFromProto(base)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
attestedBalance := 4 * e * 3 / 2
|
||||
b := &precompute.Balance{PrevEpochTargetAttested: attestedBalance}
|
||||
newState, err := precompute.ProcessJustificationAndFinalizationPreCompute(state, b)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
rt := [32]byte{byte(64)}
|
||||
if !bytes.Equal(newState.CurrentJustifiedCheckpoint().Root, rt[:]) {
|
||||
t.Errorf("Wanted current justified root: %v, got: %v",
|
||||
[]byte{byte(64)}, newState.CurrentJustifiedCheckpoint().Root)
|
||||
}
|
||||
if newState.PreviousJustifiedCheckpoint().Epoch != 0 {
|
||||
t.Errorf("Wanted previous justified epoch: %d, got: %d",
|
||||
0, newState.PreviousJustifiedCheckpoint().Epoch)
|
||||
}
|
||||
if newState.CurrentJustifiedCheckpoint().Epoch != 2 {
|
||||
t.Errorf("Wanted justified epoch: %d, got: %d",
|
||||
2, newState.CurrentJustifiedCheckpoint().Epoch)
|
||||
}
|
||||
if !bytes.Equal(newState.FinalizedCheckpoint().Root, params.BeaconConfig().ZeroHash[:]) {
|
||||
t.Errorf("Wanted current finalized root: %v, got: %v",
|
||||
params.BeaconConfig().ZeroHash, newState.FinalizedCheckpoint().Root)
|
||||
}
|
||||
if newState.FinalizedCheckpointEpoch() != 0 {
|
||||
t.Errorf("Wanted finalized epoch: 0, got: %d", newState.FinalizedCheckpointEpoch())
|
||||
}
|
||||
assert.DeepEqual(t, rt[:], newState.CurrentJustifiedCheckpoint().Root, "Unexpected current justified root")
|
||||
assert.Equal(t, uint64(0), newState.PreviousJustifiedCheckpoint().Epoch, "Unexpected previous justified epoch")
|
||||
assert.Equal(t, uint64(2), newState.CurrentJustifiedCheckpoint().Epoch, "Unexpected justified epoch")
|
||||
assert.DeepEqual(t, params.BeaconConfig().ZeroHash[:], newState.FinalizedCheckpoint().Root)
|
||||
assert.Equal(t, uint64(0), newState.FinalizedCheckpointEpoch(), "Unexpected finalized epoch")
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package precompute_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
@@ -10,6 +9,8 @@ import (
|
||||
beaconstate "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
@@ -27,36 +28,39 @@ func TestNew(t *testing.T) {
|
||||
{WithdrawableEpoch: ffe, ExitEpoch: 1, EffectiveBalance: 100},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
e := params.BeaconConfig().FarFutureEpoch
|
||||
v, b, err := precompute.New(context.Background(), s)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(v[0], &precompute.Validator{IsSlashed: true, CurrentEpochEffectiveBalance: 100,
|
||||
InclusionDistance: e, InclusionSlot: e}) {
|
||||
t.Error("Incorrect validator 0 status")
|
||||
}
|
||||
if !reflect.DeepEqual(v[1], &precompute.Validator{IsWithdrawableCurrentEpoch: true, CurrentEpochEffectiveBalance: 100,
|
||||
InclusionDistance: e, InclusionSlot: e}) {
|
||||
t.Error("Incorrect validator 1 status")
|
||||
}
|
||||
if !reflect.DeepEqual(v[2], &precompute.Validator{IsActiveCurrentEpoch: true, IsActivePrevEpoch: true,
|
||||
CurrentEpochEffectiveBalance: 100, InclusionDistance: e, InclusionSlot: e}) {
|
||||
t.Error("Incorrect validator 2 status")
|
||||
}
|
||||
if !reflect.DeepEqual(v[3], &precompute.Validator{IsActivePrevEpoch: true, CurrentEpochEffectiveBalance: 100,
|
||||
InclusionDistance: e, InclusionSlot: e}) {
|
||||
t.Error("Incorrect validator 3 status")
|
||||
}
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, &precompute.Validator{
|
||||
IsSlashed: true,
|
||||
CurrentEpochEffectiveBalance: 100,
|
||||
InclusionDistance: e,
|
||||
InclusionSlot: e,
|
||||
}, v[0], "Incorrect validator 0 status")
|
||||
assert.DeepEqual(t, &precompute.Validator{
|
||||
IsWithdrawableCurrentEpoch: true,
|
||||
CurrentEpochEffectiveBalance: 100,
|
||||
InclusionDistance: e,
|
||||
InclusionSlot: e,
|
||||
}, v[1], "Incorrect validator 1 status")
|
||||
assert.DeepEqual(t, &precompute.Validator{
|
||||
IsActiveCurrentEpoch: true,
|
||||
IsActivePrevEpoch: true,
|
||||
CurrentEpochEffectiveBalance: 100,
|
||||
InclusionDistance: e,
|
||||
InclusionSlot: e,
|
||||
}, v[2], "Incorrect validator 2 status")
|
||||
assert.DeepEqual(t, &precompute.Validator{
|
||||
IsActivePrevEpoch: true,
|
||||
CurrentEpochEffectiveBalance: 100,
|
||||
InclusionDistance: e,
|
||||
InclusionSlot: e,
|
||||
}, v[3], "Incorrect validator 3 status")
|
||||
|
||||
wantedBalances := &precompute.Balance{
|
||||
ActiveCurrentEpoch: 100,
|
||||
ActivePrevEpoch: 200,
|
||||
}
|
||||
if !reflect.DeepEqual(b, wantedBalances) {
|
||||
t.Error("Incorrect wanted balance")
|
||||
}
|
||||
assert.DeepEqual(t, wantedBalances, b, "Incorrect wanted balance")
|
||||
}
|
||||
|
||||
@@ -162,6 +162,10 @@ func ProposersDelta(state *stateTrie.BeaconState, pBal *Balance, vp []*Validator
|
||||
baseRewardsPerEpoch := params.BeaconConfig().BaseRewardsPerEpoch
|
||||
proposerRewardQuotient := params.BeaconConfig().ProposerRewardQuotient
|
||||
for _, v := range vp {
|
||||
if v.ProposerIndex >= uint64(len(rewards)) {
|
||||
// This should never happen with a valid state / validator.
|
||||
return nil, errors.New("proposer index out of range")
|
||||
}
|
||||
// Only apply inclusion rewards to proposer only if the attested hasn't been slashed.
|
||||
if v.IsPrevEpochAttester && !v.IsSlashed {
|
||||
vBalance := v.CurrentEpochEffectiveBalance
|
||||
|
||||
@@ -12,6 +12,8 @@ import (
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/mathutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
func TestProcessRewardsAndPenaltiesPrecompute(t *testing.T) {
|
||||
@@ -22,8 +24,8 @@ func TestProcessRewardsAndPenaltiesPrecompute(t *testing.T) {
|
||||
for i := 0; i < len(atts); i++ {
|
||||
atts[i] = &pb.PendingAttestation{
|
||||
Data: ðpb.AttestationData{
|
||||
Target: ðpb.Checkpoint{},
|
||||
Source: ðpb.Checkpoint{},
|
||||
Target: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
Source: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
},
|
||||
AggregationBits: bitfield.Bitlist{0xC0, 0xC0, 0xC0, 0xC0, 0x01},
|
||||
InclusionDelay: 1,
|
||||
@@ -32,37 +34,23 @@ func TestProcessRewardsAndPenaltiesPrecompute(t *testing.T) {
|
||||
base.PreviousEpochAttestations = atts
|
||||
|
||||
state, err := state.InitializeFromProto(base)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
vp, bp, err := New(context.Background(), state)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
vp, bp, err = ProcessAttestations(context.Background(), state, vp, bp)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
state, err = ProcessRewardsAndPenaltiesPrecompute(state, bp, vp)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Indices that voted everything except for head, lost a bit money
|
||||
wanted := uint64(31999810265)
|
||||
if state.Balances()[4] != wanted {
|
||||
t.Errorf("wanted balance: %d, got: %d",
|
||||
wanted, state.Balances()[4])
|
||||
}
|
||||
assert.Equal(t, wanted, state.Balances()[4], "Unexpected balance")
|
||||
|
||||
// Indices that did not vote, lost more money
|
||||
wanted = uint64(31999873505)
|
||||
if state.Balances()[0] != wanted {
|
||||
t.Errorf("wanted balance: %d, got: %d",
|
||||
wanted, state.Balances()[0])
|
||||
}
|
||||
assert.Equal(t, wanted, state.Balances()[0], "Unexpected balance")
|
||||
}
|
||||
|
||||
func TestAttestationDeltaPrecompute(t *testing.T) {
|
||||
@@ -88,50 +76,34 @@ func TestAttestationDeltaPrecompute(t *testing.T) {
|
||||
}
|
||||
base.PreviousEpochAttestations = atts
|
||||
state, err := state.InitializeFromProto(base)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
slashedAttestedIndices := []uint64{1413}
|
||||
for _, i := range slashedAttestedIndices {
|
||||
vs := state.Validators()
|
||||
vs[i].Slashed = true
|
||||
if state.SetValidators(vs) != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.Equal(t, nil, state.SetValidators(vs))
|
||||
}
|
||||
|
||||
vp, bp, err := New(context.Background(), state)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
vp, bp, err = ProcessAttestations(context.Background(), state, vp, bp)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Add some variances to target and head balances.
|
||||
// See: https://github.com/prysmaticlabs/prysm/issues/5593
|
||||
bp.PrevEpochTargetAttested = bp.PrevEpochTargetAttested / 2
|
||||
bp.PrevEpochHeadAttested = bp.PrevEpochHeadAttested * 2 / 3
|
||||
rewards, penalties, err := AttestationsDelta(state, bp, vp)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
attestedBalance, err := epoch.AttestingBalance(state, atts)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
totalBalance, err := helpers.TotalActiveBalance(state)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
attestedIndices := []uint64{55, 1339, 1746, 1811, 1569}
|
||||
for _, i := range attestedIndices {
|
||||
base, err := epoch.BaseReward(state, i)
|
||||
if err != nil {
|
||||
t.Errorf("Could not get base reward: %v", err)
|
||||
}
|
||||
require.NoError(t, err, "Could not get base reward")
|
||||
|
||||
// Base rewards for getting source right
|
||||
wanted := attestedBalance*base/totalBalance +
|
||||
@@ -141,43 +113,27 @@ func TestAttestationDeltaPrecompute(t *testing.T) {
|
||||
// on chain in the fatest manner
|
||||
proposerReward := base / params.BeaconConfig().ProposerRewardQuotient
|
||||
wanted += (base-proposerReward)*params.BeaconConfig().MinAttestationInclusionDelay - 1
|
||||
if rewards[i] != wanted {
|
||||
t.Errorf("Wanted reward balance %d, got %d for validator with index %d", wanted, rewards[i], i)
|
||||
}
|
||||
assert.Equal(t, wanted, rewards[i], "Unexpected reward balance for validator with index %d", i)
|
||||
// Since all these validators attested, they shouldn't get penalized.
|
||||
if penalties[i] != 0 {
|
||||
t.Errorf("Wanted penalty balance 0, got %d", penalties[i])
|
||||
}
|
||||
assert.Equal(t, uint64(0), penalties[i], "Unexpected penalty balance")
|
||||
}
|
||||
|
||||
for _, i := range slashedAttestedIndices {
|
||||
base, err := epoch.BaseReward(state, i)
|
||||
if err != nil {
|
||||
t.Errorf("Could not get base reward: %v", err)
|
||||
}
|
||||
if rewards[i] != 0 {
|
||||
t.Errorf("Wanted slashed indices reward balance 0, got %d", penalties[i])
|
||||
}
|
||||
if penalties[i] != 3*base {
|
||||
t.Errorf("Wanted slashed indices penalty balance %d, got %d", 3*base, penalties[i])
|
||||
}
|
||||
assert.NoError(t, err, "Could not get base reward")
|
||||
assert.Equal(t, uint64(0), rewards[i], "Unexpected slashed indices reward balance")
|
||||
assert.Equal(t, uint64(3*base), penalties[i], "Unexpected slashed indices penalty balance")
|
||||
}
|
||||
|
||||
nonAttestedIndices := []uint64{434, 677, 872, 791}
|
||||
for _, i := range nonAttestedIndices {
|
||||
base, err := epoch.BaseReward(state, i)
|
||||
if err != nil {
|
||||
t.Errorf("Could not get base reward: %v", err)
|
||||
}
|
||||
assert.NoError(t, err, "Could not get base reward")
|
||||
wanted := 3 * base
|
||||
// Since all these validators did not attest, they shouldn't get rewarded.
|
||||
if rewards[i] != 0 {
|
||||
t.Errorf("Wanted reward balance 0, got %d", rewards[i])
|
||||
}
|
||||
assert.Equal(t, uint64(0), rewards[i], "Unexpected reward balance")
|
||||
// Base penalties for not attesting.
|
||||
if penalties[i] != wanted {
|
||||
t.Errorf("Wanted penalty balance %d, got %d", wanted, penalties[i])
|
||||
}
|
||||
assert.Equal(t, wanted, penalties[i], "Unexpected penalty balance")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -204,25 +160,50 @@ func TestAttestationDeltas_ZeroEpoch(t *testing.T) {
|
||||
}
|
||||
base.PreviousEpochAttestations = atts
|
||||
state, err := state.InitializeFromProto(base)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
pVals, pBal, err := New(context.Background(), state)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
pVals, pBal, err = ProcessAttestations(context.Background(), state, pVals, pBal)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
pBal.ActiveCurrentEpoch = 0 // Could cause a divide by zero panic.
|
||||
|
||||
_, _, err = AttestationsDelta(state, pBal, pVals)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestAttestationDeltas_ZeroInclusionDelay(t *testing.T) {
|
||||
e := params.BeaconConfig().SlotsPerEpoch
|
||||
validatorCount := uint64(2048)
|
||||
base := buildState(e+2, validatorCount)
|
||||
atts := make([]*pb.PendingAttestation, 3)
|
||||
var emptyRoot [32]byte
|
||||
for i := 0; i < len(atts); i++ {
|
||||
atts[i] = &pb.PendingAttestation{
|
||||
Data: ðpb.AttestationData{
|
||||
Target: ðpb.Checkpoint{
|
||||
Root: emptyRoot[:],
|
||||
},
|
||||
Source: ðpb.Checkpoint{
|
||||
Root: emptyRoot[:],
|
||||
},
|
||||
BeaconBlockRoot: emptyRoot[:],
|
||||
},
|
||||
AggregationBits: bitfield.Bitlist{0xC0, 0xC0, 0xC0, 0xC0, 0x01},
|
||||
// Inclusion delay of 0 is not possible in a valid state and could cause a divide by
|
||||
// zero panic.
|
||||
InclusionDelay: 0,
|
||||
}
|
||||
}
|
||||
base.PreviousEpochAttestations = atts
|
||||
state, err := state.InitializeFromProto(base)
|
||||
require.NoError(t, err)
|
||||
|
||||
pVals, pBal, err := New(context.Background(), state)
|
||||
require.NoError(t, err)
|
||||
_, _, err = ProcessAttestations(context.Background(), state, pVals, pBal)
|
||||
require.ErrorContains(t, "attestation with inclusion delay of 0", err)
|
||||
}
|
||||
|
||||
func TestProcessRewardsAndPenaltiesPrecompute_SlashedInactivePenalty(t *testing.T) {
|
||||
@@ -233,8 +214,8 @@ func TestProcessRewardsAndPenaltiesPrecompute_SlashedInactivePenalty(t *testing.
|
||||
for i := 0; i < len(atts); i++ {
|
||||
atts[i] = &pb.PendingAttestation{
|
||||
Data: ðpb.AttestationData{
|
||||
Target: ðpb.Checkpoint{},
|
||||
Source: ðpb.Checkpoint{},
|
||||
Target: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
Source: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
},
|
||||
AggregationBits: bitfield.Bitlist{0xC0, 0xC0, 0xC0, 0xC0, 0x01},
|
||||
InclusionDelay: 1,
|
||||
@@ -243,52 +224,33 @@ func TestProcessRewardsAndPenaltiesPrecompute_SlashedInactivePenalty(t *testing.
|
||||
base.PreviousEpochAttestations = atts
|
||||
|
||||
state, err := state.InitializeFromProto(base)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := state.SetSlot(params.BeaconConfig().SlotsPerEpoch * 10); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, state.SetSlot(params.BeaconConfig().SlotsPerEpoch*10))
|
||||
|
||||
slashedAttestedIndices := []uint64{14, 37, 68, 77, 139}
|
||||
for _, i := range slashedAttestedIndices {
|
||||
vs := state.Validators()
|
||||
vs[i].Slashed = true
|
||||
if state.SetValidators(vs) != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, state.SetValidators(vs))
|
||||
}
|
||||
|
||||
vp, bp, err := New(context.Background(), state)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
vp, bp, err = ProcessAttestations(context.Background(), state, vp, bp)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
rewards, penalties, err := AttestationsDelta(state, bp, vp)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
finalityDelay := helpers.PrevEpoch(state) - state.FinalizedCheckpointEpoch()
|
||||
for _, i := range slashedAttestedIndices {
|
||||
base, err := epoch.BaseReward(state, i)
|
||||
if err != nil {
|
||||
t.Errorf("Could not get base reward: %v", err)
|
||||
}
|
||||
require.NoError(t, err, "Could not get base reward")
|
||||
penalty := 3 * base
|
||||
proposerReward := base / params.BeaconConfig().ProposerRewardQuotient
|
||||
penalty += params.BeaconConfig().BaseRewardsPerEpoch*base - proposerReward
|
||||
penalty += vp[i].CurrentEpochEffectiveBalance * finalityDelay / params.BeaconConfig().InactivityPenaltyQuotient
|
||||
if penalties[i] != penalty {
|
||||
t.Errorf("Wanted slashed indices penalty balance %d, got %d", penalty, penalties[i])
|
||||
}
|
||||
|
||||
if rewards[i] != 0 {
|
||||
t.Errorf("Wanted slashed indices reward balance 0, got %d", penalties[i])
|
||||
}
|
||||
assert.Equal(t, penalty, penalties[i], "Unexpected slashed indices penalty balance")
|
||||
assert.Equal(t, uint64(0), rewards[i], "Unexpected slashed indices reward balance")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -325,9 +287,9 @@ func buildState(slot uint64, validatorCount uint64) *pb.BeaconState {
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
Slashings: make([]uint64, params.BeaconConfig().EpochsPerSlashingsVector),
|
||||
BlockRoots: make([][]byte, params.BeaconConfig().SlotsPerEpoch*10),
|
||||
FinalizedCheckpoint: ðpb.Checkpoint{},
|
||||
PreviousJustifiedCheckpoint: ðpb.Checkpoint{},
|
||||
CurrentJustifiedCheckpoint: ðpb.Checkpoint{},
|
||||
FinalizedCheckpoint: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
PreviousJustifiedCheckpoint: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
CurrentJustifiedCheckpoint: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -336,9 +298,7 @@ func TestProposerDeltaPrecompute_HappyCase(t *testing.T) {
|
||||
validatorCount := uint64(10)
|
||||
base := buildState(e, validatorCount)
|
||||
state, err := state.InitializeFromProto(base)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
proposerIndex := uint64(1)
|
||||
b := &Balance{ActiveCurrentEpoch: 1000}
|
||||
@@ -346,17 +306,29 @@ func TestProposerDeltaPrecompute_HappyCase(t *testing.T) {
|
||||
{IsPrevEpochAttester: true, CurrentEpochEffectiveBalance: 32, ProposerIndex: proposerIndex},
|
||||
}
|
||||
r, err := ProposersDelta(state, b, v)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
baseReward := v[0].CurrentEpochEffectiveBalance * params.BeaconConfig().BaseRewardFactor /
|
||||
mathutil.IntegerSquareRoot(b.ActiveCurrentEpoch) / params.BeaconConfig().BaseRewardsPerEpoch
|
||||
proposerReward := baseReward / params.BeaconConfig().ProposerRewardQuotient
|
||||
|
||||
if r[proposerIndex] != proposerReward {
|
||||
t.Errorf("Wanted proposer reward %d, got %d", proposerReward, r[proposerIndex])
|
||||
assert.Equal(t, proposerReward, r[proposerIndex], "Unexpected proposer reward")
|
||||
}
|
||||
|
||||
func TestProposerDeltaPrecompute_ValidatorIndexOutOfRange(t *testing.T) {
|
||||
e := params.BeaconConfig().SlotsPerEpoch
|
||||
validatorCount := uint64(10)
|
||||
base := buildState(e, validatorCount)
|
||||
state, err := state.InitializeFromProto(base)
|
||||
require.NoError(t, err)
|
||||
|
||||
proposerIndex := validatorCount
|
||||
b := &Balance{ActiveCurrentEpoch: 1000}
|
||||
v := []*Validator{
|
||||
{IsPrevEpochAttester: true, CurrentEpochEffectiveBalance: 32, ProposerIndex: proposerIndex},
|
||||
}
|
||||
_, err = ProposersDelta(state, b, v)
|
||||
assert.ErrorContains(t, "proposer index out of range", err)
|
||||
}
|
||||
|
||||
func TestProposerDeltaPrecompute_SlashedCase(t *testing.T) {
|
||||
@@ -364,9 +336,7 @@ func TestProposerDeltaPrecompute_SlashedCase(t *testing.T) {
|
||||
validatorCount := uint64(10)
|
||||
base := buildState(e, validatorCount)
|
||||
state, err := state.InitializeFromProto(base)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
proposerIndex := uint64(1)
|
||||
b := &Balance{ActiveCurrentEpoch: 1000}
|
||||
@@ -374,22 +344,15 @@ func TestProposerDeltaPrecompute_SlashedCase(t *testing.T) {
|
||||
{IsPrevEpochAttester: true, CurrentEpochEffectiveBalance: 32, ProposerIndex: proposerIndex, IsSlashed: true},
|
||||
}
|
||||
r, err := ProposersDelta(state, b, v)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if r[proposerIndex] != 0 {
|
||||
t.Errorf("Wanted proposer reward for slashed %d, got %d", 0, r[proposerIndex])
|
||||
}
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, uint64(0), r[proposerIndex], "Unexpected proposer reward for slashed")
|
||||
}
|
||||
|
||||
func TestFinalityDelay(t *testing.T) {
|
||||
base := buildState(params.BeaconConfig().SlotsPerEpoch*10, 1)
|
||||
base.FinalizedCheckpoint = ðpb.Checkpoint{Epoch: 3}
|
||||
state, err := state.InitializeFromProto(base)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
prevEpoch := uint64(0)
|
||||
finalizedEpoch := uint64(0)
|
||||
// Set values for each test case
|
||||
@@ -400,38 +363,26 @@ func TestFinalityDelay(t *testing.T) {
|
||||
setVal()
|
||||
d := finalityDelay(prevEpoch, finalizedEpoch)
|
||||
w := helpers.PrevEpoch(state) - state.FinalizedCheckpointEpoch()
|
||||
if d != w {
|
||||
t.Error("Did not get wanted finality delay")
|
||||
}
|
||||
assert.Equal(t, w, d, "Did not get wanted finality delay")
|
||||
|
||||
if err := state.SetFinalizedCheckpoint(ðpb.Checkpoint{Epoch: 4}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, state.SetFinalizedCheckpoint(ðpb.Checkpoint{Epoch: 4}))
|
||||
setVal()
|
||||
d = finalityDelay(prevEpoch, finalizedEpoch)
|
||||
w = helpers.PrevEpoch(state) - state.FinalizedCheckpointEpoch()
|
||||
if d != w {
|
||||
t.Error("Did not get wanted finality delay")
|
||||
}
|
||||
assert.Equal(t, w, d, "Did not get wanted finality delay")
|
||||
|
||||
if err := state.SetFinalizedCheckpoint(ðpb.Checkpoint{Epoch: 5}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, state.SetFinalizedCheckpoint(ðpb.Checkpoint{Epoch: 5}))
|
||||
setVal()
|
||||
d = finalityDelay(prevEpoch, finalizedEpoch)
|
||||
w = helpers.PrevEpoch(state) - state.FinalizedCheckpointEpoch()
|
||||
if d != w {
|
||||
t.Error("Did not get wanted finality delay")
|
||||
}
|
||||
assert.Equal(t, w, d, "Did not get wanted finality delay")
|
||||
}
|
||||
|
||||
func TestIsInInactivityLeak(t *testing.T) {
|
||||
base := buildState(params.BeaconConfig().SlotsPerEpoch*10, 1)
|
||||
base.FinalizedCheckpoint = ðpb.Checkpoint{Epoch: 3}
|
||||
state, err := state.InitializeFromProto(base)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
prevEpoch := uint64(0)
|
||||
finalizedEpoch := uint64(0)
|
||||
// Set values for each test case
|
||||
@@ -440,23 +391,11 @@ func TestIsInInactivityLeak(t *testing.T) {
|
||||
finalizedEpoch = state.FinalizedCheckpointEpoch()
|
||||
}
|
||||
setVal()
|
||||
if !isInInactivityLeak(prevEpoch, finalizedEpoch) {
|
||||
t.Error("Wanted inactivity leak true")
|
||||
}
|
||||
|
||||
if err := state.SetFinalizedCheckpoint(ðpb.Checkpoint{Epoch: 4}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Equal(t, true, isInInactivityLeak(prevEpoch, finalizedEpoch), "Wanted inactivity leak true")
|
||||
require.NoError(t, state.SetFinalizedCheckpoint(ðpb.Checkpoint{Epoch: 4}))
|
||||
setVal()
|
||||
if !isInInactivityLeak(prevEpoch, finalizedEpoch) {
|
||||
t.Error("Wanted inactivity leak true")
|
||||
}
|
||||
|
||||
if err := state.SetFinalizedCheckpoint(ðpb.Checkpoint{Epoch: 5}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Equal(t, true, isInInactivityLeak(prevEpoch, finalizedEpoch), "Wanted inactivity leak true")
|
||||
require.NoError(t, state.SetFinalizedCheckpoint(ðpb.Checkpoint{Epoch: 5}))
|
||||
setVal()
|
||||
if isInInactivityLeak(prevEpoch, finalizedEpoch) {
|
||||
t.Error("Wanted inactivity leak false")
|
||||
}
|
||||
assert.Equal(t, false, isInInactivityLeak(prevEpoch, finalizedEpoch), "Wanted inactivity leak false")
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ func ProcessSlashingsPrecompute(state *stateTrie.BeaconState, pBal *Balance) err
|
||||
totalSlashing += slashing
|
||||
}
|
||||
|
||||
minSlashing := mathutil.Min(totalSlashing*3, pBal.ActiveCurrentEpoch)
|
||||
minSlashing := mathutil.Min(totalSlashing*params.BeaconConfig().ProportionalSlashingMultiplier, pBal.ActiveCurrentEpoch)
|
||||
epochToWithdraw := currentEpoch + exitLength/2
|
||||
increment := params.BeaconConfig().EffectiveBalanceIncrement
|
||||
validatorFunc := func(idx int, val *ethpb.Validator) (bool, error) {
|
||||
|
||||
@@ -9,6 +9,8 @@ import (
|
||||
beaconstate "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
func TestProcessSlashingsPrecompute_NotSlashed(t *testing.T) {
|
||||
@@ -18,22 +20,15 @@ func TestProcessSlashingsPrecompute_NotSlashed(t *testing.T) {
|
||||
Balances: []uint64{params.BeaconConfig().MaxEffectiveBalance},
|
||||
Slashings: []uint64{0, 1e9},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
pBal := &precompute.Balance{ActiveCurrentEpoch: params.BeaconConfig().MaxEffectiveBalance}
|
||||
if err := precompute.ProcessSlashingsPrecompute(s, pBal); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, precompute.ProcessSlashingsPrecompute(s, pBal))
|
||||
|
||||
wanted := params.BeaconConfig().MaxEffectiveBalance
|
||||
if s.Balances()[0] != wanted {
|
||||
t.Errorf("Wanted slashed balance: %d, got: %d", wanted, s.Balances()[0])
|
||||
}
|
||||
assert.Equal(t, wanted, s.Balances()[0], "Unexpected slashed balance")
|
||||
}
|
||||
|
||||
func TestProcessSlashingsPrecompute_SlashedLess(t *testing.T) {
|
||||
|
||||
tests := []struct {
|
||||
state *pb.BeaconState
|
||||
want uint64
|
||||
@@ -114,21 +109,9 @@ func TestProcessSlashingsPrecompute_SlashedLess(t *testing.T) {
|
||||
|
||||
original := proto.Clone(tt.state)
|
||||
state, err := beaconstate.InitializeFromProto(tt.state)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := precompute.ProcessSlashingsPrecompute(state, pBal); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if state.Balances()[0] != tt.want {
|
||||
t.Errorf(
|
||||
"ProcessSlashings({%v}) = newState; newState.Balances[0] = %d; wanted %d",
|
||||
original,
|
||||
state.Balances()[0],
|
||||
tt.want,
|
||||
)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, precompute.ProcessSlashingsPrecompute(state, pBal))
|
||||
assert.Equal(t, tt.want, state.Balances()[0], "ProcessSlashings({%v}) = newState; newState.Balances[0] = %d; wanted %d", original, state.Balances()[0])
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ go_test(
|
||||
"//shared/params/spectest:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"//shared/testutil:go_default_library",
|
||||
"//shared/testutil/require:go_default_library",
|
||||
"@com_github_gogo_protobuf//proto:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_ssz//:go_default_library",
|
||||
"@in_gopkg_d4l3k_messagediff_v1//:go_default_library",
|
||||
@@ -67,6 +68,7 @@ go_test(
|
||||
"//shared/params/spectest:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"//shared/testutil:go_default_library",
|
||||
"//shared/testutil/require:go_default_library",
|
||||
"@com_github_gogo_protobuf//proto:go_default_library",
|
||||
"@in_gopkg_d4l3k_messagediff_v1//:go_default_library",
|
||||
"@io_bazel_rules_go//go/tools/bazel:go_default_library",
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/params/spectest"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
||||
)
|
||||
|
||||
type Delta struct {
|
||||
@@ -24,53 +25,39 @@ type Delta struct {
|
||||
var deltaFiles = []string{"source_deltas.yaml", "target_deltas.yaml", "head_deltas.yaml", "inactivity_penalty_deltas.yaml", "inclusion_delay_deltas.yaml"}
|
||||
|
||||
func runPrecomputeRewardsAndPenaltiesTests(t *testing.T, config string) {
|
||||
if err := spectest.SetConfig(t, config); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
testPath := "rewards/core/pyspec_tests"
|
||||
testFolders, testsFolderPath := testutil.TestFolders(t, config, testPath)
|
||||
for _, folder := range testFolders {
|
||||
helpers.ClearCache()
|
||||
t.Run(folder.Name(), func(t *testing.T) {
|
||||
folderPath := path.Join(testsFolderPath, folder.Name())
|
||||
runPrecomputeRewardsAndPenaltiesTest(t, folderPath)
|
||||
})
|
||||
require.NoError(t, spectest.SetConfig(t, config))
|
||||
testPaths := []string{"rewards/basic/pyspec_tests", "rewards/leak/pyspec_tests", "rewards/random/pyspec_tests"}
|
||||
for _, testPath := range testPaths {
|
||||
testFolders, testsFolderPath := testutil.TestFolders(t, config, testPath)
|
||||
for _, folder := range testFolders {
|
||||
helpers.ClearCache()
|
||||
t.Run(folder.Name(), func(t *testing.T) {
|
||||
folderPath := path.Join(testsFolderPath, folder.Name())
|
||||
runPrecomputeRewardsAndPenaltiesTest(t, folderPath)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func runPrecomputeRewardsAndPenaltiesTest(t *testing.T, testFolderPath string) {
|
||||
ctx := context.Background()
|
||||
preBeaconStateFile, err := testutil.BazelFileBytes(path.Join(testFolderPath, "pre.ssz"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
preBeaconStateBase := &pb.BeaconState{}
|
||||
if err := ssz.Unmarshal(preBeaconStateFile, preBeaconStateBase); err != nil {
|
||||
t.Fatalf("Failed to unmarshal: %v", err)
|
||||
}
|
||||
require.NoError(t, ssz.Unmarshal(preBeaconStateFile, preBeaconStateBase), "Failed to unmarshal")
|
||||
preBeaconState, err := beaconstate.InitializeFromProto(preBeaconStateBase)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
vp, bp, err := precompute.New(ctx, preBeaconState)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
vp, bp, err = precompute.ProcessAttestations(ctx, preBeaconState, vp, bp)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
rewards, penalties, err := precompute.AttestationsDelta(preBeaconState, bp, vp)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
pRewards, err := precompute.ProposersDelta(preBeaconState, bp, vp)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(rewards) != len(penalties) && len(pRewards) != len(pRewards) {
|
||||
require.NoError(t, err)
|
||||
if len(rewards) != len(penalties) && len(rewards) != len(pRewards) {
|
||||
t.Fatal("Incorrect lengths")
|
||||
}
|
||||
for i, reward := range rewards {
|
||||
@@ -82,9 +69,7 @@ func runPrecomputeRewardsAndPenaltiesTest(t *testing.T, testFolderPath string) {
|
||||
|
||||
for _, dFile := range deltaFiles {
|
||||
sourceFile, err := testutil.BazelFileBytes(path.Join(testFolderPath, dFile))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
d := &Delta{}
|
||||
err = yaml.Unmarshal(sourceFile, &d)
|
||||
if err != nil {
|
||||
|
||||
@@ -33,6 +33,7 @@ go_test(
|
||||
"//shared/params/spectest:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"//shared/testutil:go_default_library",
|
||||
"//shared/testutil/require:go_default_library",
|
||||
"@com_github_gogo_protobuf//proto:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_ssz//:go_default_library",
|
||||
"@in_gopkg_d4l3k_messagediff_v1//:go_default_library",
|
||||
@@ -65,6 +66,7 @@ go_test(
|
||||
"//shared/params/spectest:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"//shared/testutil:go_default_library",
|
||||
"//shared/testutil/require:go_default_library",
|
||||
"@com_github_gogo_protobuf//proto:go_default_library",
|
||||
"@in_gopkg_d4l3k_messagediff_v1//:go_default_library",
|
||||
"@io_bazel_rules_go//go/tools/bazel:go_default_library",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user