Compare commits

..

113 Commits

Author SHA1 Message Date
terence tsao
d2c197d040 Add debug logging 2021-11-10 12:12:47 -08:00
terence tsao
87bc6aa5e5 Manually override nil transaction field. M2 works 2021-11-09 16:06:01 -08:00
terence tsao
5b5065b01d Remove unused merge genesis state gen tool 2021-11-09 11:09:59 -08:00
terence tsao
ee1c567561 Remove secp256k1 2021-11-09 08:43:10 -08:00
terence tsao
ff1416c98d Update Kintsugi consensus implementations (#9872) 2021-11-08 21:26:58 -08:00
terence tsao
471c94031f Update spec test shas 2021-11-08 19:39:13 -08:00
terence tsao
9863fb3d6a All spec tests pass 2021-11-08 19:31:28 -08:00
kasey
f3c2d1a00b Kintsugi ssz (#9867) 2021-11-08 18:42:23 -08:00
terence tsao
5d8879a4df Update Kintsugi engine API (#9865) 2021-11-08 09:56:14 -08:00
terence tsao
abea0a11bc Update WORKSPACE 2021-11-05 12:06:19 -07:00
terence tsao
80ce1603bd Merge branch 'kintsugi' of github.com:prysmaticlabs/prysm into kintsugi 2021-11-03 20:40:22 -07:00
terence tsao
ca478244e0 Add and use TBH_ACTIVATION_EPOCH 2021-11-03 20:39:51 -07:00
terence tsao
8a864b66a1 Add and use 2021-11-03 20:38:40 -07:00
terence tsao
72f3b9e84b Remove extraneous p2p condition 2021-11-03 19:17:12 -07:00
terence tsao
493e95060f Fix gossip and tx size limits for the merge part 1 2021-11-03 17:03:06 -07:00
terence tsao
e7e1ecd72f Update penalty params for Merge 2021-11-03 16:37:17 -07:00
terence tsao
c286ac8b87 Remove gas validations 2021-11-03 14:47:33 -07:00
terence tsao
bde315224c Merge branch 'develop' of github.com:prysmaticlabs/prysm into merge-oct 2021-11-03 12:52:50 -07:00
terence tsao
00520705bc Sync with develop 2021-11-02 20:52:33 -07:00
Zahoor Mohamed
c7fcd804d7 all gossip tests passing 2021-10-27 18:48:22 +05:30
terence tsao
985ac2e848 Update htrutils.go 2021-10-24 11:35:59 -07:00
terence tsao
f4a0e98926 Disable genesis ETH1.0 chain header logging 2021-10-19 22:13:59 -07:00
terence tsao
5f93ff10ea Merge: switch from go bindings to raw rpc calls (#9803) 2021-10-19 21:00:11 -07:00
terence tsao
544248f60f Go fmt 2021-10-18 22:38:57 -07:00
terence tsao
3b41968510 Merge branch 'merge-oct' of github.com:prysmaticlabs/prysm into merge-oct 2021-10-18 22:38:21 -07:00
terence tsao
7fc418042a Disable deposit contract lookback 2021-10-18 22:38:09 -07:00
terence tsao
9a03946706 Disable contract lookback 2021-10-18 22:34:50 -07:00
terence tsao
33dd6dd5f2 Use proper receive block path for initial syncing 2021-10-18 21:28:16 -07:00
terence tsao
56542e1958 Correctly upgrade to merge state + object mapping fixes 2021-10-18 17:46:55 -07:00
terence tsao
e82d7b4c0b Use uint64 for ttd 2021-10-18 14:00:45 -07:00
terence tsao
6cb69d8ff0 Merge branch 'develop' of github.com:prysmaticlabs/prysm into merge-oct 2021-10-18 09:26:42 -07:00
terence tsao
70b55a0191 Proper upgrade altair to merge state 2021-10-15 12:48:21 -07:00
terence tsao
50f4951194 Various fixes to pass all spec tests for Merge (#9777) 2021-10-14 15:34:31 -07:00
terence tsao
1a14f2368d Merge branch 'develop' of github.com:prysmaticlabs/prysm into merge-oct 2021-10-14 11:52:28 -07:00
terence tsao
bb8cad58f1 Update beacon_block.pb.go 2021-10-13 13:49:16 -07:00
terence tsao
05412c1f0e Update mainnet_config.go 2021-10-13 13:26:48 -07:00
terence tsao
b03441fed8 Fix finding terminal block hash calculation 2021-10-13 11:29:17 -07:00
terence tsao
fa7d7cef69 Merge: support terminal difficulty override (#9769) 2021-10-12 20:40:01 -07:00
terence tsao
1caa6c969f Merge branch 'develop' of github.com:prysmaticlabs/prysm into merge-oct 2021-10-12 09:43:42 -07:00
Kasey Kirkham
eeb7d5bbfb tell bazel about this new file 2021-10-08 13:31:57 -05:00
Kasey Kirkham
d7c7d150b1 separate ExecutionPayload/Header from codegen 2021-10-08 11:06:21 -05:00
Kasey Kirkham
63c4d2eb2b defensive nil check 2021-10-08 09:18:02 -05:00
Kasey Kirkham
9de1f694a0 restoring generated pb field ordering 2021-10-08 08:16:43 -05:00
terence tsao
8a79d06cbd Fix bazel build //... 2021-10-07 15:31:49 -07:00
terence tsao
5290ad93b8 Merge conflict. Sync with upstream 2021-10-07 15:07:29 -07:00
terence tsao
2128208ef7 M2 works with Geth 🎉 2021-10-07 14:57:20 -07:00
Kasey Kirkham
296323719c get rid of codegen garbage 2021-10-07 16:31:35 -05:00
Kasey Kirkham
5e9583ea85 noisy commit, restoring pb field order codegen 2021-10-07 15:59:28 -05:00
Zahoor Mohamed
17196e0f80 changes test cases per ssz changes 2021-10-08 01:39:30 +05:30
kasey
c50d54000d Merge union debugging (#9751) 2021-10-07 10:44:26 -07:00
terence tsao
85b3061d1b Update go commit 2021-10-07 10:10:46 -07:00
terence tsao
0146c5317a Merge branch 'develop' of github.com:prysmaticlabs/prysm into merge-oct 2021-10-07 09:06:55 -07:00
Zahoor Mohamed
fcbc48ffd9 fix finding Transactions size 2021-10-07 14:16:15 +05:30
terence tsao
76ee51af9d Interop merge beacon state 2021-10-06 17:22:47 -07:00
terence tsao
370b0b97ed Fix beacon chain build 2021-10-06 14:41:43 -07:00
terence tsao
990ebd3fe3 Merge branch 'develop' of github.com:prysmaticlabs/prysm into merge-oct 2021-10-06 14:34:33 -07:00
Zahoor Mohamed
54449c72e8 Merge branch 'merge-oct' of https://github.com/prysmaticlabs/prysm into merge-oct 2021-10-06 23:53:43 +05:30
Zahoor Mohamed
1dbd0b98eb add merge specific checks when receiving a block from gossip 2021-10-06 23:53:24 +05:30
terence tsao
09c3896c6b Go fmt 2021-10-06 09:38:24 -07:00
terence tsao
d494845e19 Merge branch 'develop' of github.com:prysmaticlabs/prysm into merge-oct 2021-10-06 09:36:13 -07:00
terence tsao
4d0c0f7234 Update todo strings 2021-10-05 14:43:01 -07:00
terence tsao
bfe570b1aa Merge branch 'merge-oct-net' of github.com:prysmaticlabs/prysm into merge-oct 2021-10-05 14:41:24 -07:00
terence tsao
56db696823 Clean up and fix a test 2021-10-05 14:38:09 -07:00
terence tsao
d312e15db8 Clean up misc state store 2021-10-05 14:17:44 -07:00
terence tsao
907d4cf7e6 Clean up validator additions 2021-10-05 14:06:03 -07:00
terence tsao
891353d6ad Clean up beacon chain additions 2021-10-05 11:28:36 -07:00
terence tsao
0adc08660c Rest of the validator changes 2021-10-05 10:18:26 -07:00
terence tsao
de31425dcd Add proposer get execution payload helpers 2021-10-04 16:37:22 -07:00
terence tsao
2094e0f21f Update rpc service and proposer get block 2021-10-04 16:37:01 -07:00
terence tsao
2c6f554500 Update process_block.go 2021-10-04 10:45:56 -07:00
terence tsao
18a1e07711 Update and use forked go-ethereum with catalyst go binding 2021-10-04 10:45:39 -07:00
prestonvanloon
5e432f5aaa Use MariusVanDerWijden go-ethereum fork with latest catalyst updates 2021-10-03 22:05:21 -05:00
prestonvanloon
284e2696cb Merge branch 'rm-bazel-go-ethereum' of github.com:prysmaticlabs/prysm into merge-oct 2021-10-03 21:52:13 -05:00
terence tsao
7547aaa6ce Fix build, update comments 2021-10-03 19:11:43 -07:00
prestonvanloon
953315c2cc fix geth e2e flags 2021-10-03 14:01:26 -05:00
terence tsao
9662d06b08 Update catalyst merge commit 2021-10-03 11:51:12 -07:00
prestonvanloon
ecaea26ace fix geth e2e flags 2021-10-03 13:31:52 -05:00
prestonvanloon
63819e2690 move vendor stuff to third_party so that go mod wont be mad anymore 2021-10-03 13:21:27 -05:00
prestonvanloon
a6d0cd06b3 Remove bazel-go-ethereum, use vendored libraries only 2021-10-03 13:11:50 -05:00
prestonvanloon
2dbe4f5e67 viz improvement 2021-10-03 13:11:26 -05:00
prestonvanloon
2689d6814d Add karalabe/usb 2021-10-03 13:11:16 -05:00
prestonvanloon
69a681ddc0 gaz 2021-10-03 12:29:17 -05:00
prestonvanloon
7f9f1fd36c Check in go-ethereum crypto/sepc256k1 package with proper build rules 2021-10-03 12:27:40 -05:00
terence tsao
57c97eb561 Merge branch 'develop' of github.com:prysmaticlabs/prysm into merge-oct 2021-10-03 09:42:34 -07:00
terence tsao
f0f94a8193 Handle more version merge cases 2021-10-02 11:43:50 -07:00
Zahoor Mohamed
87b0bf2c2a fix more merge conflicts 2021-10-02 12:27:12 +05:30
Zahoor Mohamed
d8ad317dec fix mrge conflicts 2021-10-02 12:19:29 +05:30
terence tsao
ab5f488cf4 Fix spectest merge fork 2021-10-01 16:27:21 -07:00
terence tsao
296d7464ad Add powchain execution methods 2021-10-01 16:07:33 -07:00
terence tsao
221c542e4f Go mod tidy and build 2021-10-01 13:43:57 -07:00
terence tsao
7ad32aaa96 Add execution caller engine interface 2021-10-01 12:59:04 -07:00
terence tsao
3dc0969c0c Point go-ethereum to https://github.com/ethereum/go-ethereum/pull/23607 2021-10-01 08:30:15 -07:00
Zahoor Mohamed
0e18e835c3 req/resp structure has not changed. so no need of a new version 2021-09-30 21:34:19 +05:30
terence tsao
8adfbfc382 Update sync_committee.go 2021-09-30 08:21:40 -07:00
Zahoor Mohamed
68b0b5e0ce add merge in fork watcher 2021-09-30 14:09:18 +05:30
terence tsao
eede309e0f Fix build 2021-09-29 16:26:13 -07:00
terence tsao
b11628dc53 Can configure flags 2021-09-29 16:04:39 -07:00
terence tsao
ea3ae22d3b Merge branch 'develop' of github.com:prysmaticlabs/prysm into merge-oct 2021-09-29 14:25:16 -07:00
terence tsao
02bb39ddeb Minor clean up to improve readability 2021-09-29 10:21:00 -07:00
terence tsao
1618c1f55d Fix comment 2021-09-29 07:57:43 -07:00
terence tsao
73c8493fd7 Merge branch 'develop' of github.com:prysmaticlabs/prysm into merge-oct 2021-09-28 14:54:24 -07:00
terence tsao
a4f59a4f15 Forkchoice and upgrade changes 2021-09-28 14:53:11 -07:00
Zahoor Mohamed
3c497efdb8 Merge branch 'merge-oct' of https://github.com/prysmaticlabs/prysm into merge-oct-net 2021-09-28 21:58:22 +05:30
Zahoor Mohamed
9f5daafbb7 initial networking code 2021-09-28 20:02:47 +05:30
terence tsao
11d7ffdfa8 Add merge spec tests 2021-09-26 11:07:31 -07:00
terence tsao
c26b3305e6 Resolve conflict 2021-09-25 09:49:53 -07:00
terence tsao
38d8b63fbf Merge branch 'develop' of github.com:prysmaticlabs/prysm into merge-oct 2021-09-25 09:15:20 -07:00
terence tsao
aea67405c8 Add upgrade to merge path 2021-09-21 14:34:03 -07:00
terence tsao
57d830f8b3 Add wrapper, cloner and interface 2021-09-21 13:34:10 -07:00
terence tsao
ac4b1ef4ea Merge branch 'develop' of github.com:prysmaticlabs/prysm into merge-oct 2021-09-21 13:07:01 -07:00
terence tsao
1d32119f5a can process execution header 2021-09-20 17:08:53 -07:00
terence tsao
3540cc7b05 Add state v3 2021-09-16 21:31:08 -07:00
terence tsao
191e7767a6 Add beacon block and state protos 2021-09-16 16:15:55 -07:00
370 changed files with 15193 additions and 7533 deletions

View File

@@ -5,22 +5,21 @@ Contact: mailto:security@prysmaticlabs.com
Encryption: openpgp4fpr:0AE0051D647BA3C1A917AF4072E33E4DF1A5036E
Encryption: openpgp4fpr:CD08DE68C60B82D3EE2A3F7D95452A701810FEDB
Encryption: openpgp4fpr:317D6E91058F8F3C2303BA7756313E44581297A6
Encryption: openpgp4fpr:79C59A585E3FD3AFFA00F5C22940A6479DA7C9EC
Preferred-Languages: en
Canonical: https://github.com/prysmaticlabs/prysm/tree/master/.well-known/security.txt
-----BEGIN PGP SIGNATURE-----
iQIzBAEBCgAdFiEECuAFHWR7o8GpF69AcuM+TfGlA24FAmGOfiYACgkQcuM+TfGl
A24YwRAAiQk3w6yzqSEggrOlNoNn04iu/rWZdn5ihkQgzACXy8XH2D1gdKLChE/X
7e5bUtgE2aCuHryQjwoKxqZakviBJFstVmHgF64rXv2zKhpqA30Mj4fI+T3zn8I+
+FpFV0TTsxNLDx+AcR1eQ1nSayO7ImUDIfOQNDDnSZZy42Bc+F+QIGKB3aH/8bpG
kT+bDTZrXvX+TE1gZTbAtZG8sH8g/zadoWEHIhfXUuYb0kTz+DRzAxoqU4j4Z4ee
1zSfFAgfJwxJP4kWD7s4xkE1sBbCgGBeD6cW/C2lbcfIei+XSizLpHW3jD9dNqh4
fLkmEspSa/LV/iXFq8nFzu/GLww4q+sQZDzzDKZyws54CrATinRitZMhzoIL0bTn
yFZVOGHosFAMEVZ36dl1Aw2+B2W6tr2CVr9c5zfV+kup5/KZH1EmT5nYY/zFwfg2
jYCFB5wmYeiyWZvuprgJXRArgVZLZaJxwWazlPVk4i/4vPvRgvfHqOwHCBe8DXy0
VHPhpewwb/ECYek1KoaNQflgR8iH2GMHkC5RjhGDAt1S0AQDtite5m4ZYt1kvO9E
k/znkv89dduhL9CKDvZvnI+DICwsTrf//4KJ8PM/qaPAJa4GvtiUU/eS/jKBivtv
OP5dZQtX6KPc9ewqqZgn622uHSezoBidgeTkdZsJ6tw2eIu0lsY=
=V7L0
iQIzBAEBCgAdFiEECuAFHWR7o8GpF69AcuM+TfGlA24FAl++klgACgkQcuM+TfGl
A27rQw/6A29p1W20J0v+h218p8XWLSUpTIGLnZTxw6KqdyVXMzlsQK0YG4G2s2AB
0LKh7Ae/Di5E0U+Z4AjUW5nc5eaCxK36GMscH9Ah0rgJwNYxEJw7/2o8ZqVT/Ip2
+56rFihRqxFZfaCNKFVuZFaL9jKewV9FKYP38ID6/SnTcrOHiu2AoAlyZGmB03p+
iT57SPRHatygeY4xb/gwcfREFWEv+VHGyBTv8A+6ABZDxyurboCFMERHzFICrbmk
8UdHxxlWZDnHAbAUyAwpERC5znx6IHXQJwF8TMtu6XY6a6axT2XBOyJDF9/mZOz+
kdkz6loX5uxaQBGLtTv6Kqf1yUGANOZ16VhHvWwL209LmHmigIVQ+qSM6c79PsW/
vrsqdz3GBsiMC5Fq2vYgnbgzpfE8Atjn0y7E+j4R7IvwOAE/Ro/b++nqnc4YqhME
P/yTcfGftaCrdSNnQCXeoV9JxpFM5Xy8KV3eexvNKbcgA/9DtgxL5i+s5ZJkUT9A
+qJvoRrRyIym32ghkHgtFJKB3PLCdobeoOVRk6EnMo9zKSiSK2rZEJW8Ccbo515D
W9qUOn3GF7lNVuUFAU/YKEdmDp/AVaViZ7vH+8aq0LC0HBkZ8XlzWnWoArS8sMhw
fX0R9g/HMgrwNte/d0mwim5lJ2Plgv60Bh4grJqwZJeWbU0zi1U=
=uW+X
-----END PGP SIGNATURE-----

View File

@@ -362,9 +362,9 @@ filegroup(
visibility = ["//visibility:public"],
)
""",
sha256 = "0a3d94428ea28916276694c517b82b364122063fdbf924f54ee9ae0bc500289f",
sha256 = "54ce527b83d092da01127f2e3816f4d5cfbab69354caba8537f1ea55889b6d7c",
urls = [
"https://github.com/prysmaticlabs/prysm-web-ui/releases/download/v1.0.1/prysm-web-ui.tar.gz",
"https://github.com/prysmaticlabs/prysm-web-ui/releases/download/v1.0.0-beta.4/prysm-web-ui.tar.gz",
],
)

View File

@@ -34,6 +34,7 @@ go_library(
"//beacon-chain/cache/depositcache:go_default_library",
"//beacon-chain/core/altair:go_default_library",
"//beacon-chain/core/epoch/precompute:go_default_library",
"//beacon-chain/core/execution:go_default_library",
"//beacon-chain/core/feed:go_default_library",
"//beacon-chain/core/feed/state:go_default_library",
"//beacon-chain/core/helpers:go_default_library",
@@ -65,6 +66,9 @@ go_library(
"//time:go_default_library",
"//time/slots:go_default_library",
"@com_github_emicklei_dot//:go_default_library",
"@com_github_ethereum_go_ethereum//common:go_default_library",
"@com_github_ethereum_go_ethereum//eth/catalyst:go_default_library",
"@com_github_holiman_uint256//: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",

View File

@@ -40,6 +40,7 @@ func logStateTransitionData(b block.BeaconBlock) {
log = log.WithField("syncBitsCount", agg.SyncCommitteeBits.Count())
}
}
// TODO_MERGE: Add payload logging here
log.Info("Finished applying state transition")
}
@@ -51,11 +52,11 @@ func logBlockSyncStatus(block block.BeaconBlock, blockRoot [32]byte, finalized *
log.WithFields(logrus.Fields{
"slot": block.Slot(),
"slotInEpoch": block.Slot() % params.BeaconConfig().SlotsPerEpoch,
"block": fmt.Sprintf("0x%s...", hex.EncodeToString(blockRoot[:])[:8]),
"blockRoot": fmt.Sprintf("0x%s...", hex.EncodeToString(blockRoot[:])[:8]),
"parentRoot": fmt.Sprintf("0x%s...", hex.EncodeToString(blockRoot[:])[:8]),
"epoch": slots.ToEpoch(block.Slot()),
"finalizedEpoch": finalized.Epoch,
"finalizedRoot": fmt.Sprintf("0x%s...", hex.EncodeToString(finalized.Root)[:8]),
"parentRoot": fmt.Sprintf("0x%s...", hex.EncodeToString(block.ParentRoot())[:8]),
"version": version.String(block.Version()),
}).Info("Synced new block")
log.WithFields(logrus.Fields{

View File

@@ -254,6 +254,15 @@ func reportEpochMetrics(ctx context.Context, postState, headState state.BeaconSt
if err != nil {
return err
}
case version.Merge:
v, b, err = altair.InitializePrecomputeValidators(ctx, headState)
if err != nil {
return err
}
_, b, err = altair.ProcessEpochParticipation(ctx, headState, b, v)
if err != nil {
return err
}
default:
return errors.Errorf("invalid state type provided: %T", headState.InnerStateUnsafe())
}

View File

@@ -11,7 +11,6 @@ import (
"github.com/prysmaticlabs/prysm/beacon-chain/operations/voluntaryexits"
"github.com/prysmaticlabs/prysm/beacon-chain/p2p"
"github.com/prysmaticlabs/prysm/beacon-chain/powchain"
"github.com/prysmaticlabs/prysm/beacon-chain/state"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stategen"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
)
@@ -50,6 +49,14 @@ func WithChainStartFetcher(f powchain.ChainStartFetcher) Option {
}
}
// WithExecutionEngineCaller to call execution engine.
func WithExecutionEngineCaller(c powchain.ExecutionEngineCaller) Option {
return func(s *Service) error {
s.cfg.ExecutionEngineCaller = c
return nil
}
}
// WithDepositCache for deposit lifecycle after chain inclusion.
func WithDepositCache(c *depositcache.DepositCache) Option {
return func(s *Service) error {
@@ -129,11 +136,3 @@ func WithSlasherAttestationsFeed(f *event.Feed) Option {
return nil
}
}
// WithFinalizedStateAtStartUp to store finalized state at start up.
func WithFinalizedStateAtStartUp(st state.BeaconState) Option {
return func(s *Service) error {
s.cfg.FinalizedStateAtStartUp = st
return nil
}
}

View File

@@ -1,16 +1,23 @@
package blockchain
import (
"bytes"
"context"
"fmt"
"math/big"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/eth/catalyst"
"github.com/holiman/uint256"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/beacon-chain/core/execution"
"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"
coreTime "github.com/prysmaticlabs/prysm/beacon-chain/core/time"
"github.com/prysmaticlabs/prysm/beacon-chain/core/transition"
"github.com/prysmaticlabs/prysm/beacon-chain/powchain"
"github.com/prysmaticlabs/prysm/beacon-chain/state"
"github.com/prysmaticlabs/prysm/config/features"
"github.com/prysmaticlabs/prysm/config/params"
@@ -21,6 +28,7 @@ import (
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/attestation"
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/block"
"github.com/prysmaticlabs/prysm/runtime/version"
"github.com/prysmaticlabs/prysm/time/slots"
"go.opencensus.io/trace"
)
@@ -98,11 +106,42 @@ func (s *Service) onBlock(ctx context.Context, signed block.SignedBeaconBlock, b
return err
}
body := signed.Block().Body()
// TODO_MERGE: Break `ExecuteStateTransition` into per_slot and block processing so we can call `ExecutePayload` in the middle.
postState, err := transition.ExecuteStateTransition(ctx, preState, signed)
if err != nil {
// TODO_MERGE: Notify execution client in the event of invalid conensus block
return err
}
if postState.Version() == version.Merge {
executionEnabled, err := execution.Enabled(postState, body)
if err != nil {
return errors.Wrap(err, "could not check if execution is enabled")
}
if executionEnabled {
payload, err := body.ExecutionPayload()
if err != nil {
return errors.Wrap(err, "could not get body execution payload")
}
// This is not the earliest we can call `ExecutePayload`, see above to do as the soonest we can call is after per_slot processing.
_, err = s.cfg.ExecutionEngineCaller.ExecutePayload(ctx, executionPayloadToExecutableData(payload))
if err != nil {
return errors.Wrap(err, "could not execute payload")
}
mergeBlock, err := execution.IsMergeBlock(postState, body)
if err != nil {
return errors.Wrap(err, "could not check if merge block is terminal")
}
if mergeBlock {
if err := s.validateTerminalBlock(signed); err != nil {
return err
}
}
}
}
if err := s.savePostStateInfo(ctx, blockRoot, signed, postState, false /* reg sync */); err != nil {
return err
}
@@ -155,6 +194,49 @@ func (s *Service) onBlock(ctx context.Context, signed block.SignedBeaconBlock, b
log.WithError(err).Warn("Could not update head")
}
// Notify execution layer with fork choice head update if this is post merge block.
if postState.Version() == version.Merge {
executionEnabled, err := execution.Enabled(postState, body)
if err != nil {
return errors.Wrap(err, "could not check if execution is enabled")
}
if executionEnabled {
// Spawn the update task, without waiting for it to complete.
go func() {
headPayload, err := s.headBlock().Block().Body().ExecutionPayload()
if err != nil {
log.WithError(err)
return
}
// TODO_MERGE: Loading the finalized block from DB on per block is not ideal. Finalized block should be cached here
finalizedBlock, err := s.cfg.BeaconDB.Block(ctx, bytesutil.ToBytes32(s.finalizedCheckpt.Root))
if err != nil {
log.WithError(err)
return
}
finalizedBlockHash := params.BeaconConfig().ZeroHash[:]
if finalizedBlock != nil && finalizedBlock.Version() == version.Merge {
finalizedPayload, err := finalizedBlock.Block().Body().ExecutionPayload()
if err != nil {
log.WithError(err)
return
}
finalizedBlockHash = finalizedPayload.BlockHash
}
f := catalyst.ForkchoiceStateV1{
HeadBlockHash: common.BytesToHash(headPayload.BlockHash),
SafeBlockHash: common.BytesToHash(headPayload.BlockHash),
FinalizedBlockHash: common.BytesToHash(finalizedBlockHash),
}
if err := s.cfg.ExecutionEngineCaller.NotifyForkChoiceValidated(ctx, f); err != nil {
log.WithError(err)
return
}
}()
}
}
if err := s.pruneCanonicalAttsFromPool(ctx, blockRoot, signed); err != nil {
return err
}
@@ -475,3 +557,99 @@ func (s *Service) pruneCanonicalAttsFromPool(ctx context.Context, r [32]byte, b
}
return nil
}
// validates terminal block hash in the event of manual overrides before checking for total difficulty.
//
// def validate_merge_block(block: BeaconBlock) -> None:
// """
// Check the parent PoW block of execution payload is a valid terminal PoW block.
//
// Note: Unavailable PoW block(s) may later become available,
// and a client software MAY delay a call to ``validate_merge_block``
// until the PoW block(s) become available.
// """
// if TERMINAL_BLOCK_HASH != Hash32():
// # If `TERMINAL_BLOCK_HASH` is used as an override, the activation epoch must be reached.
// assert compute_epoch_at_slot(block.slot) >= TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH
// return block.block_hash == TERMINAL_BLOCK_HASH
//
// pow_block = get_pow_block(block.body.execution_payload.parent_hash)
// # Check if `pow_block` is available
// assert pow_block is not None
// pow_parent = get_pow_block(pow_block.parent_hash)
// # Check if `pow_parent` is available
// assert pow_parent is not None
// # Check if `pow_block` is a valid terminal PoW block
// assert is_valid_terminal_pow_block(pow_block, pow_parent)
func (s *Service) validateTerminalBlock(b block.SignedBeaconBlock) error {
payload, err := b.Block().Body().ExecutionPayload()
if err != nil {
return err
}
if bytesutil.ToBytes32(params.BeaconConfig().TerminalBlockHash.Bytes()) != [32]byte{} {
// `TERMINAL_BLOCK_HASH` is used as an override, the activation epoch must be reached.
if params.BeaconConfig().TerminalBlockHashActivationEpoch > slots.ToEpoch(b.Block().Slot()) {
return errors.New("terminal block hash activation epoch not reached")
}
if !bytes.Equal(payload.ParentHash, params.BeaconConfig().TerminalBlockHash.Bytes()) {
return errors.New("parent hash does not match terminal block hash")
}
return nil
}
transitionBlk, err := s.cfg.ExecutionEngineCaller.ExecutionBlockByHash(common.BytesToHash(payload.ParentHash))
if err != nil {
return errors.Wrap(err, "could not get transition block")
}
parentTransitionBlk, err := s.cfg.ExecutionEngineCaller.ExecutionBlockByHash(common.HexToHash(transitionBlk.ParentHash))
if err != nil {
return errors.Wrap(err, "could not get transition parent block")
}
if !validTerminalPowBlock(transitionBlk, parentTransitionBlk) {
return errors.New("invalid difficulty for terminal block")
}
return nil
}
// validates terminal pow block by comparing own total difficulty with parent's total difficulty.
//
// def is_valid_terminal_pow_block(block: PowBlock, parent: PowBlock) -> bool:
// is_total_difficulty_reached = block.total_difficulty >= TERMINAL_TOTAL_DIFFICULTY
// is_parent_total_difficulty_valid = parent.total_difficulty < TERMINAL_TOTAL_DIFFICULTY
// return is_total_difficulty_reached and is_parent_total_difficulty_valid
func validTerminalPowBlock(transitionBlock *powchain.ExecutionBlock, transitionParentBlock *powchain.ExecutionBlock) bool {
transitionBlkTTD, err := uint256.FromHex(transitionBlock.TotalDifficulty)
if err != nil {
return false
}
transitionParentBlkTTD, err := uint256.FromHex(transitionParentBlock.TotalDifficulty)
if err != nil {
return false
}
terminalTotalDifficulty := uint256.NewInt(params.BeaconConfig().TerminalTotalDifficulty)
totalDifficultyReached := transitionBlkTTD.Cmp(terminalTotalDifficulty) >= 0
parentTotalDifficultyValid := terminalTotalDifficulty.Cmp(transitionParentBlkTTD) >= 0
return totalDifficultyReached && parentTotalDifficultyValid
}
func executionPayloadToExecutableData(payload *ethpb.ExecutionPayload) *catalyst.ExecutableDataV1 {
baseFeePerGas := new(big.Int)
// TODO_MERGE: The conversion from 32bytes to big int is broken. This assumes base fee per gas in single digit
baseFeePerGas.SetBytes([]byte{payload.BaseFeePerGas[0]})
return &catalyst.ExecutableDataV1{
BlockHash: common.BytesToHash(payload.BlockHash),
ParentHash: common.BytesToHash(payload.ParentHash),
Coinbase: common.BytesToAddress(payload.Coinbase),
StateRoot: common.BytesToHash(payload.StateRoot),
ReceiptRoot: common.BytesToHash(payload.ReceiptRoot),
LogsBloom: payload.LogsBloom,
Random: common.BytesToHash(payload.Random),
Number: payload.BlockNumber,
GasLimit: payload.GasLimit,
GasUsed: payload.GasUsed,
Timestamp: payload.Timestamp,
ExtraData: payload.ExtraData,
BaseFeePerGas: baseFeePerGas,
Transactions: payload.Transactions,
}
}

View File

@@ -135,24 +135,7 @@ func (s *Service) verifyBlkFinalizedSlot(b block.BeaconBlock) error {
// shouldUpdateCurrentJustified prevents bouncing attack, by only update conflicting justified
// checkpoints in the fork choice if in the early slots of the epoch.
// Otherwise, delay incorporation of new justified checkpoint until next epoch boundary.
//
// Spec code:
// def should_update_justified_checkpoint(store: Store, new_justified_checkpoint: Checkpoint) -> bool:
// """
// To address the bouncing attack, only update conflicting justified
// checkpoints in the fork choice if in the early slots of the epoch.
// Otherwise, delay incorporation of new justified checkpoint until next epoch boundary.
//
// See https://ethresear.ch/t/prevention-of-bouncing-attack-on-ffg/6114 for more detailed analysis and discussion.
// """
// if compute_slots_since_epoch_start(get_current_slot(store)) < SAFE_SLOTS_TO_UPDATE_JUSTIFIED:
// return True
//
// justified_slot = compute_start_slot_at_epoch(store.justified_checkpoint.epoch)
// if not get_ancestor(store, new_justified_checkpoint.root, justified_slot) == store.justified_checkpoint.root:
// return False
//
// return True
// See https://ethresear.ch/t/prevention-of-bouncing-attack-on-ffg/6114 for more detailed analysis and discussion.
func (s *Service) shouldUpdateCurrentJustified(ctx context.Context, newJustifiedCheckpt *ethpb.Checkpoint) (bool, error) {
ctx, span := trace.StartSpan(ctx, "blockChain.shouldUpdateCurrentJustified")
defer span.End()
@@ -160,20 +143,51 @@ func (s *Service) shouldUpdateCurrentJustified(ctx context.Context, newJustified
if slots.SinceEpochStarts(s.CurrentSlot()) < params.BeaconConfig().SafeSlotsToUpdateJustified {
return true, nil
}
var newJustifiedBlockSigned block.SignedBeaconBlock
justifiedRoot := s.ensureRootNotZeros(bytesutil.ToBytes32(newJustifiedCheckpt.Root))
var err error
if s.hasInitSyncBlock(justifiedRoot) {
newJustifiedBlockSigned = s.getInitSyncBlock(justifiedRoot)
} else {
newJustifiedBlockSigned, err = s.cfg.BeaconDB.Block(ctx, justifiedRoot)
if err != nil {
return false, err
}
}
if newJustifiedBlockSigned == nil || newJustifiedBlockSigned.IsNil() || newJustifiedBlockSigned.Block().IsNil() {
return false, errors.New("nil new justified block")
}
newJustifiedBlock := newJustifiedBlockSigned.Block()
jSlot, err := slots.EpochStart(s.justifiedCheckpt.Epoch)
if err != nil {
return false, err
}
justifiedRoot := s.ensureRootNotZeros(bytesutil.ToBytes32(newJustifiedCheckpt.Root))
b, err := s.ancestor(ctx, justifiedRoot[:], jSlot)
if newJustifiedBlock.Slot() <= jSlot {
return false, nil
}
var justifiedBlockSigned block.SignedBeaconBlock
cachedJustifiedRoot := s.ensureRootNotZeros(bytesutil.ToBytes32(s.justifiedCheckpt.Root))
if s.hasInitSyncBlock(cachedJustifiedRoot) {
justifiedBlockSigned = s.getInitSyncBlock(cachedJustifiedRoot)
} else {
justifiedBlockSigned, err = s.cfg.BeaconDB.Block(ctx, cachedJustifiedRoot)
if err != nil {
return false, err
}
}
if justifiedBlockSigned == nil || justifiedBlockSigned.IsNil() || justifiedBlockSigned.Block().IsNil() {
return false, errors.New("nil justified block")
}
justifiedBlock := justifiedBlockSigned.Block()
b, err := s.ancestor(ctx, justifiedRoot[:], justifiedBlock.Slot())
if err != nil {
return false, err
}
if !bytes.Equal(b, s.justifiedCheckpt.Root) {
return false, nil
}
return true, nil
}

View File

@@ -229,8 +229,6 @@ func TestShouldUpdateJustified_ReturnFalse(t *testing.T) {
service, err := NewService(ctx)
require.NoError(t, err)
service.cfg = cfg
service.cfg.ForkChoiceStore = protoarray.New(0, 0, [32]byte{})
lastJustifiedBlk := util.NewBeaconBlock()
lastJustifiedBlk.Block.ParentRoot = bytesutil.PadTo([]byte{'G'}, 32)
lastJustifiedRoot, err := lastJustifiedBlk.Block.HashTreeRoot()
@@ -327,7 +325,7 @@ func TestUpdateJustified_CouldUpdateBest(t *testing.T) {
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
cfg := &config{BeaconDB: beaconDB, StateGen: stategen.New(beaconDB), ForkChoiceStore: protoarray.New(0, 0, [32]byte{})}
cfg := &config{BeaconDB: beaconDB, StateGen: stategen.New(beaconDB)}
service, err := NewService(ctx)
require.NoError(t, err)
service.cfg = cfg

View File

@@ -84,7 +84,8 @@ type config struct {
StateGen *stategen.State
SlasherAttestationsFeed *event.Feed
WeakSubjectivityCheckpt *ethpb.Checkpoint
FinalizedStateAtStartUp state.BeaconState
BlockFetcher powchain.POWBlockFetcher
ExecutionEngineCaller powchain.ExecutionEngineCaller
}
// NewService instantiates a new block service instance that will
@@ -115,7 +116,34 @@ func NewService(ctx context.Context, opts ...Option) (*Service, error) {
// Start a blockchain service's main event loop.
func (s *Service) Start() {
beaconState := s.cfg.FinalizedStateAtStartUp
// 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.cfg.BeaconDB.FinalizedCheckpoint(s.ctx)
if err != nil {
log.Fatalf("Could not fetch finalized cp: %v", err)
}
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.cfg.BeaconDB.GenesisBlock(s.ctx)
if err != nil {
log.Fatalf("Could not fetch finalized cp: %v", err)
}
if genesisBlock != nil && !genesisBlock.IsNil() {
r, err = genesisBlock.Block().HashTreeRoot()
if err != nil {
log.Fatalf("Could not tree hash genesis block: %v", err)
}
}
}
beaconState, err := s.cfg.StateGen.StateByRoot(s.ctx, r)
if err != nil {
log.Fatalf("Could not fetch beacon state by root: %v", err)
}
// Make sure that attestation processor is subscribed and ready for state initializing event.
attestationProcessorSubscribed := make(chan struct{}, 1)
@@ -123,6 +151,7 @@ func (s *Service) Start() {
// If the chain has already been initialized, simply start the block processing routine.
if beaconState != nil && !beaconState.IsNil() {
log.Info("Blockchain data already exists in DB, initializing...")
s.genesisTime = time.Unix(int64(beaconState.GenesisTime()), 0)
s.cfg.AttService.SetGenesisTime(beaconState.GenesisTime())
if err := s.initializeChainInfo(s.ctx); err != nil {
@@ -389,7 +418,7 @@ func (s *Service) initializeChainInfo(ctx context.Context) error {
finalizedRoot := s.ensureRootNotZeros(bytesutil.ToBytes32(finalized.Root))
var finalizedState state.BeaconState
finalizedState, err = s.cfg.StateGen.Resume(ctx, s.cfg.FinalizedStateAtStartUp)
finalizedState, err = s.cfg.StateGen.Resume(ctx)
if err != nil {
return errors.Wrap(err, "could not get finalized state from db")
}
@@ -411,7 +440,7 @@ func (s *Service) initializeChainInfo(ctx context.Context) error {
if err != nil {
return errors.Wrap(err, "could not hash head block")
}
finalizedState, err := s.cfg.StateGen.Resume(ctx, s.cfg.FinalizedStateAtStartUp)
finalizedState, err := s.cfg.StateGen.Resume(ctx)
if err != nil {
return errors.Wrap(err, "could not get finalized state from db")
}

View File

@@ -94,12 +94,11 @@ func setupBeaconChain(t *testing.T, beaconDB db.Database) *Service {
DepositContainers: []*ethpb.DepositContainer{},
})
require.NoError(t, err)
web3Service, err = powchain.NewService(
ctx,
powchain.WithDatabase(beaconDB),
powchain.WithHttpEndpoints([]string{endpoint}),
powchain.WithDepositContractAddress(common.Address{}),
)
web3Service, err = powchain.NewService(ctx, &powchain.Web3ServiceConfig{
BeaconDB: beaconDB,
HttpEndpoints: []string{endpoint},
DepositContract: common.Address{},
})
require.NoError(t, err, "Unable to set up web3 service")
attService, err := attestations.NewService(ctx, &attestations.Config{Pool: attestations.NewPool()})
@@ -151,7 +150,7 @@ func TestChainStartStop_Initialized(t *testing.T) {
require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, blkRoot))
require.NoError(t, beaconDB.SaveJustifiedCheckpoint(ctx, &ethpb.Checkpoint{Root: blkRoot[:]}))
require.NoError(t, beaconDB.SaveFinalizedCheckpoint(ctx, &ethpb.Checkpoint{Root: blkRoot[:]}))
chainService.cfg.FinalizedStateAtStartUp = s
// Test the start function.
chainService.Start()
@@ -178,7 +177,7 @@ func TestChainStartStop_GenesisZeroHashes(t *testing.T) {
require.NoError(t, beaconDB.SaveState(ctx, s, blkRoot))
require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, blkRoot))
require.NoError(t, beaconDB.SaveJustifiedCheckpoint(ctx, &ethpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}))
chainService.cfg.FinalizedStateAtStartUp = s
// Test the start function.
chainService.Start()
@@ -249,7 +248,7 @@ func TestChainService_CorrectGenesisRoots(t *testing.T) {
require.NoError(t, beaconDB.SaveHeadBlockRoot(ctx, blkRoot))
require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, blkRoot))
require.NoError(t, beaconDB.SaveFinalizedCheckpoint(ctx, &ethpb.Checkpoint{Root: blkRoot[:]}))
chainService.cfg.FinalizedStateAtStartUp = s
// Test the start function.
chainService.Start()
@@ -285,7 +284,6 @@ func TestChainService_InitializeChainInfo(t *testing.T) {
require.NoError(t, beaconDB.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(headBlock)))
require.NoError(t, beaconDB.SaveFinalizedCheckpoint(ctx, &ethpb.Checkpoint{Epoch: slots.ToEpoch(finalizedSlot), Root: headRoot[:]}))
c := &Service{cfg: &config{BeaconDB: beaconDB, StateGen: stategen.New(beaconDB)}}
c.cfg.FinalizedStateAtStartUp = headState
require.NoError(t, c.initializeChainInfo(ctx))
headBlk, err := c.HeadBlock(ctx)
require.NoError(t, err)
@@ -383,7 +381,7 @@ func TestChainService_InitializeChainInfo_HeadSync(t *testing.T) {
}))
c := &Service{cfg: &config{BeaconDB: beaconDB, StateGen: stategen.New(beaconDB)}}
c.cfg.FinalizedStateAtStartUp = headState
require.NoError(t, c.initializeChainInfo(ctx))
s, err := c.HeadState(ctx)
require.NoError(t, err)

View File

@@ -39,6 +39,7 @@ go_library(
deps = [
"//beacon-chain/state:go_default_library",
"//beacon-chain/state/v2:go_default_library",
"//beacon-chain/state/v3:go_default_library",
"//cache/lru:go_default_library",
"//config/features:go_default_library",
"//config/params:go_default_library",

View File

@@ -7,6 +7,7 @@ import (
types "github.com/prysmaticlabs/eth2-types"
"github.com/prysmaticlabs/prysm/beacon-chain/state"
stateAltair "github.com/prysmaticlabs/prysm/beacon-chain/state/v2"
v3 "github.com/prysmaticlabs/prysm/beacon-chain/state/v3"
lruwrpr "github.com/prysmaticlabs/prysm/cache/lru"
)
@@ -31,10 +32,6 @@ func (c *SyncCommitteeHeadStateCache) Put(slot types.Slot, st state.BeaconState)
if st == nil || st.IsNil() {
return ErrNilValueProvided
}
_, ok := st.(*stateAltair.BeaconState)
if !ok {
return ErrIncorrectType
}
c.cache.Add(slot, st)
return nil
}
@@ -47,9 +44,13 @@ func (c *SyncCommitteeHeadStateCache) Get(slot types.Slot) (state.BeaconState, e
if !exists {
return nil, ErrNotFound
}
var st state.BeaconState
st, ok := val.(*stateAltair.BeaconState)
if !ok {
return nil, ErrIncorrectType
st, ok = val.(*v3.BeaconState)
if !ok {
return nil, ErrIncorrectType
}
}
return st, nil
}

View File

@@ -38,6 +38,7 @@ go_library(
"//proto/prysm/v1alpha1:go_default_library",
"//proto/prysm/v1alpha1/attestation:go_default_library",
"//proto/prysm/v1alpha1/block:go_default_library",
"//runtime/version:go_default_library",
"//time/slots:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@com_github_prysmaticlabs_eth2_types//:go_default_library",

View File

@@ -10,6 +10,7 @@ import (
"github.com/prysmaticlabs/prysm/beacon-chain/state"
"github.com/prysmaticlabs/prysm/config/params"
"github.com/prysmaticlabs/prysm/math"
"github.com/prysmaticlabs/prysm/runtime/version"
"go.opencensus.io/trace"
)
@@ -183,14 +184,12 @@ func ProcessEpochParticipation(
}
if has && vals[i].IsActivePrevEpoch {
vals[i].IsPrevEpochAttester = true
vals[i].IsPrevEpochSourceAttester = true
}
has, err = HasValidatorFlag(b, targetIdx)
if err != nil {
return nil, nil, err
}
if has && vals[i].IsActivePrevEpoch {
vals[i].IsPrevEpochAttester = true
vals[i].IsPrevEpochTargetAttester = true
}
has, err = HasValidatorFlag(b, headIdx)
@@ -201,7 +200,7 @@ func ProcessEpochParticipation(
vals[i].IsPrevEpochHeadAttester = true
}
}
bal = precompute.UpdateBalance(vals, bal, beaconState.Version())
bal = precompute.UpdateBalance(vals, bal)
return vals, bal, nil
}
@@ -266,6 +265,9 @@ func AttestationsDelta(beaconState state.BeaconStateAltair, bal *precompute.Bala
baseRewardMultiplier := increment * factor / math.IntegerSquareRoot(bal.ActiveCurrentEpoch)
leak := helpers.IsInInactivityLeak(prevEpoch, finalizedEpoch)
inactivityDenominator := cfg.InactivityScoreBias * cfg.InactivityPenaltyQuotientAltair
if beaconState.Version() == version.Merge {
inactivityDenominator = cfg.InactivityScoreBias * cfg.InactivityPenaltyQuotientMerge
}
for i, v := range vals {
rewards[i], penalties[i], err = attestationDelta(bal, v, baseRewardMultiplier, inactivityDenominator, leak)
@@ -300,7 +302,7 @@ func attestationDelta(
headWeight := cfg.TimelyHeadWeight
reward, penalty = uint64(0), uint64(0)
// Process source reward / penalty
if val.IsPrevEpochSourceAttester && !val.IsSlashed {
if val.IsPrevEpochAttester && !val.IsSlashed {
if !inactivityLeak {
n := baseReward * srcWeight * (bal.PrevEpochAttested / increment)
reward += n / (activeIncrement * weightDenominator)

View File

@@ -108,7 +108,6 @@ func TestProcessEpochParticipation(t *testing.T) {
CurrentEpochEffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
IsCurrentEpochAttester: true,
IsPrevEpochAttester: true,
IsPrevEpochSourceAttester: true,
}, validators[1])
require.DeepEqual(t, &precompute.Validator{
IsActiveCurrentEpoch: true,
@@ -117,7 +116,6 @@ func TestProcessEpochParticipation(t *testing.T) {
CurrentEpochEffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
IsCurrentEpochAttester: true,
IsPrevEpochAttester: true,
IsPrevEpochSourceAttester: true,
IsCurrentEpochTargetAttester: true,
IsPrevEpochTargetAttester: true,
}, validators[2])
@@ -128,7 +126,6 @@ func TestProcessEpochParticipation(t *testing.T) {
CurrentEpochEffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
IsCurrentEpochAttester: true,
IsPrevEpochAttester: true,
IsPrevEpochSourceAttester: true,
IsCurrentEpochTargetAttester: true,
IsPrevEpochTargetAttester: true,
IsPrevEpochHeadAttester: true,
@@ -183,7 +180,6 @@ func TestProcessEpochParticipation_InactiveValidator(t *testing.T) {
IsActiveCurrentEpoch: false,
IsActivePrevEpoch: true,
IsPrevEpochAttester: true,
IsPrevEpochSourceAttester: true,
IsPrevEpochTargetAttester: true,
IsWithdrawableCurrentEpoch: true,
CurrentEpochEffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
@@ -195,7 +191,6 @@ func TestProcessEpochParticipation_InactiveValidator(t *testing.T) {
CurrentEpochEffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
IsCurrentEpochAttester: true,
IsPrevEpochAttester: true,
IsPrevEpochSourceAttester: true,
IsCurrentEpochTargetAttester: true,
IsPrevEpochTargetAttester: true,
IsPrevEpochHeadAttester: true,

View File

@@ -213,7 +213,7 @@ func ValidateSyncMessageTime(slot types.Slot, genesisTime time.Time, clockDispar
// Verify sync message slot is within the time range.
if messageTime.Before(lowerBound) || messageTime.After(upperBound) {
return fmt.Errorf(
"sync message slot %d not within allowable range of %d to %d (current slot)",
"sync message slot %d not within allowable range of slots %d to %d",
slot,
uint64(lowerBound.Unix()-genesisTime.Unix())/params.BeaconConfig().SecondsPerSlot,
uint64(upperBound.Unix()-genesisTime.Unix())/params.BeaconConfig().SecondsPerSlot,

View File

@@ -8,6 +8,7 @@ import (
"github.com/prysmaticlabs/prysm/beacon-chain/core/epoch/precompute"
"github.com/prysmaticlabs/prysm/beacon-chain/state"
"github.com/prysmaticlabs/prysm/config/params"
"github.com/prysmaticlabs/prysm/runtime/version"
"go.opencensus.io/trace"
)
@@ -69,9 +70,16 @@ func ProcessEpoch(ctx context.Context, state state.BeaconStateAltair) (state.Bea
}
// Modified in Altair.
state, err = e.ProcessSlashings(state, params.BeaconConfig().ProportionalSlashingMultiplierAltair)
if err != nil {
return nil, err
if state.Version() == version.Altair {
state, err = e.ProcessSlashings(state, params.BeaconConfig().ProportionalSlashingMultiplierAltair)
if err != nil {
return nil, err
}
} else {
state, err = e.ProcessSlashings(state, params.BeaconConfig().ProportionalSlashingMultiplierMerge)
if err != nil {
return nil, err
}
}
state, err = e.ProcessEth1DataReset(state)

View File

@@ -83,6 +83,8 @@ func ProcessAttesterSlashing(
slashingQuotient = cfg.MinSlashingPenaltyQuotient
case beaconState.Version() == version.Altair:
slashingQuotient = cfg.MinSlashingPenaltyQuotientAltair
case beaconState.Version() == version.Merge:
slashingQuotient = cfg.MinSlashingPenaltyQuotientMerge
default:
return nil, errors.New("unknown state version")
}

View File

@@ -81,6 +81,8 @@ func ProcessProposerSlashing(
slashingQuotient = cfg.MinSlashingPenaltyQuotient
case beaconState.Version() == version.Altair:
slashingQuotient = cfg.MinSlashingPenaltyQuotientAltair
case beaconState.Version() == version.Merge:
slashingQuotient = cfg.MinSlashingPenaltyQuotientMerge
default:
return nil, errors.New("unknown state version")
}

View File

@@ -24,7 +24,6 @@ go_library(
"//monitoring/tracing:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//proto/prysm/v1alpha1/attestation:go_default_library",
"//runtime/version:go_default_library",
"//time/slots:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@com_github_prysmaticlabs_eth2_types//:go_default_library",
@@ -52,7 +51,6 @@ go_test(
"//math:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//proto/prysm/v1alpha1/attestation:go_default_library",
"//runtime/version:go_default_library",
"//testing/assert:go_default_library",
"//testing/require:go_default_library",
"//testing/util:go_default_library",

View File

@@ -13,7 +13,6 @@ import (
"github.com/prysmaticlabs/prysm/monitoring/tracing"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/attestation"
"github.com/prysmaticlabs/prysm/runtime/version"
"go.opencensus.io/trace"
)
@@ -65,7 +64,7 @@ func ProcessAttestations(
vp = UpdateValidator(vp, v, indices, a, a.Data.Slot)
}
pBal = UpdateBalance(vp, pBal, state.Version())
pBal = UpdateBalance(vp, pBal)
return vp, pBal, nil
}
@@ -171,7 +170,7 @@ func UpdateValidator(vp []*Validator, record *Validator, indices []uint64, a *et
}
// UpdateBalance updates pre computed balance store.
func UpdateBalance(vp []*Validator, bBal *Balance, stateVersion int) *Balance {
func UpdateBalance(vp []*Validator, bBal *Balance) *Balance {
for _, v := range vp {
if !v.IsSlashed {
if v.IsCurrentEpochAttester {
@@ -180,10 +179,7 @@ func UpdateBalance(vp []*Validator, bBal *Balance, stateVersion int) *Balance {
if v.IsCurrentEpochTargetAttester {
bBal.CurrentEpochTargetAttested += v.CurrentEpochEffectiveBalance
}
if stateVersion == version.Phase0 && v.IsPrevEpochAttester {
bBal.PrevEpochAttested += v.CurrentEpochEffectiveBalance
}
if stateVersion == version.Altair && v.IsPrevEpochSourceAttester {
if v.IsPrevEpochAttester {
bBal.PrevEpochAttested += v.CurrentEpochEffectiveBalance
}
if v.IsPrevEpochTargetAttester {

View File

@@ -10,7 +10,6 @@ import (
"github.com/prysmaticlabs/prysm/config/params"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/attestation"
"github.com/prysmaticlabs/prysm/runtime/version"
"github.com/prysmaticlabs/prysm/testing/assert"
"github.com/prysmaticlabs/prysm/testing/require"
"github.com/prysmaticlabs/prysm/testing/util"
@@ -66,7 +65,7 @@ func TestUpdateBalance(t *testing.T) {
PrevEpochTargetAttested: 100 * params.BeaconConfig().EffectiveBalanceIncrement,
PrevEpochHeadAttested: 200 * params.BeaconConfig().EffectiveBalanceIncrement,
}
pBal := precompute.UpdateBalance(vp, &precompute.Balance{}, version.Phase0)
pBal := precompute.UpdateBalance(vp, &precompute.Balance{})
assert.DeepEqual(t, wantedPBal, pBal, "Incorrect balance calculations")
}

View File

@@ -20,14 +20,12 @@ type Validator struct {
IsCurrentEpochTargetAttester bool
// IsPrevEpochAttester is true if the validator attested previous epoch.
IsPrevEpochAttester bool
// IsPrevEpochSourceAttester is true if the validator attested to source previous epoch. [Only for Altair]
IsPrevEpochSourceAttester bool
// IsPrevEpochTargetAttester is true if the validator attested previous epoch target.
IsPrevEpochTargetAttester bool
// IsHeadAttester is true if the validator attested head.
IsPrevEpochHeadAttester bool
// CurrentEpochEffectiveBalance is how much effective balance this validator has current epoch.
// CurrentEpochEffectiveBalance is how much effective balance this validator validator has current epoch.
CurrentEpochEffectiveBalance uint64
// InclusionSlot is the slot of when the attestation gets included in the chain.
InclusionSlot types.Slot

View File

@@ -0,0 +1,24 @@
load("@prysm//tools/go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = [
"process.go",
"upgrade.go",
],
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/core/execution",
visibility = ["//visibility:public"],
deps = [
"//beacon-chain/core/helpers:go_default_library",
"//beacon-chain/core/time:go_default_library",
"//beacon-chain/state:go_default_library",
"//beacon-chain/state/v3:go_default_library",
"//config/params:go_default_library",
"//encoding/bytesutil:go_default_library",
"//encoding/ssz:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//proto/prysm/v1alpha1/block:go_default_library",
"//time/slots:go_default_library",
"@com_github_pkg_errors//:go_default_library",
],
)

View File

@@ -0,0 +1,226 @@
package execution
import (
"bytes"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/beacon-chain/core/time"
"github.com/prysmaticlabs/prysm/beacon-chain/state"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/encoding/ssz"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/block"
"github.com/prysmaticlabs/prysm/time/slots"
)
// IsMergeComplete returns true if the transition merge has happened.
//
// Spec code:
// def is_merge_complete(state: BeaconState) -> bool:
// return state.latest_execution_payload_header != ExecutionPayloadHeader()
func IsMergeComplete(st state.BeaconState) (bool, error) {
h, err := st.LatestExecutionPayloadHeader()
if err != nil {
return false, err
}
// TODO_MERGE: Benchmark this for faster compare.
return !ssz.DeepEqual(h, EmptypayloadHeader()), nil
}
// IsMergeBlock returns true if input block can become the merge block.
//
// Spec code:
// def is_merge_block(state: BeaconState, body: BeaconBlockBody) -> bool:
// return not is_merge_complete(state) and body.execution_payload != ExecutionPayload()
func IsMergeBlock(st state.BeaconState, blk block.BeaconBlockBody) (bool, error) {
mergeComplete, err := IsMergeComplete(st)
if err != nil {
return false, err
}
if mergeComplete {
return false, err
}
payload, err := blk.ExecutionPayload()
if err != nil {
return false, err
}
// TODO_MERGE: Benchmark this for faster compare.
return !ssz.DeepEqual(payload, EmptyPayload()), nil
}
// Enabled returns true if the beacon chain can begin executing.
//
// Spec code:
// def is_execution_enabled(state: BeaconState, body: BeaconBlockBody) -> bool:
// return is_merge_block(state, body) or is_merge_complete(state)
func Enabled(st state.BeaconState, blk block.BeaconBlockBody) (bool, error) {
mergeBlock, err := IsMergeBlock(st, blk)
if err != nil {
return false, err
}
if mergeBlock {
return true, nil
}
return IsMergeComplete(st)
}
// ProcessPayload processes input execution payload using beacon state.
//
// Spec code:
// def process_execution_payload(state: BeaconState, payload: ExecutionPayload, execution_engine: ExecutionEngine) -> None:
// # Verify consistency of the parent hash with respect to the previous execution payload header
// if is_merge_complete(state):
// assert payload.parent_hash == state.latest_execution_payload_header.block_hash
// # Verify random
// assert payload.random == get_randao_mix(state, get_current_epoch(state))
// # Verify timestamp
// assert payload.timestamp == compute_timestamp_at_slot(state, state.slot)
// # Verify the execution payload is valid
// assert execution_engine.execute_payload(payload)
// # Cache execution payload header
// state.latest_execution_payload_header = ExecutionPayloadHeader(
// parent_hash=payload.parent_hash,
// coinbase=payload.coinbase,
// state_root=payload.state_root,
// receipt_root=payload.receipt_root,
// logs_bloom=payload.logs_bloom,
// random=payload.random,
// block_number=payload.block_number,
// gas_limit=payload.gas_limit,
// gas_used=payload.gas_used,
// timestamp=payload.timestamp,
// extra_data=payload.extra_data,
// base_fee_per_gas=payload.base_fee_per_gas,
// block_hash=payload.block_hash,
// transactions_root=hash_tree_root(payload.transactions),
// )
func ProcessPayload(st state.BeaconState, payload *ethpb.ExecutionPayload) (state.BeaconState, error) {
if err := validatePayloadWhenMergeCompletes(st, payload); err != nil {
return nil, err
}
if err := validatePayload(st, payload); err != nil {
return nil, err
}
// This deviate with spec definition. It supposed to perform `execution_engine.on_payload(payload)` here.
// Core pkg contains all pure functions. They don't have access to execution engine i.e. rpc service.
// The soonest we can do this is after state transition.
header, err := payloadToHeader(payload)
if err != nil {
return nil, err
}
if err := st.SetLatestExecutionPayloadHeader(header); err != nil {
return nil, err
}
return st, nil
}
// This validates if payload is valid according to beacon state.
// These validation steps ONLY apply to post merge.
func validatePayloadWhenMergeCompletes(st state.BeaconState, payload *ethpb.ExecutionPayload) error {
complete, err := IsMergeComplete(st)
if err != nil {
return err
}
if !complete {
return nil
}
header, err := st.LatestExecutionPayloadHeader()
if err != nil {
return err
}
if !bytes.Equal(payload.ParentHash, header.BlockHash) {
return errors.New("incorrect block hash")
}
return nil
}
// This validates if payload is valid according to beacon state.
// These validation steps apply to both pre merge and post merge.
func validatePayload(st state.BeaconState, payload *ethpb.ExecutionPayload) error {
random, err := helpers.RandaoMix(st, time.CurrentEpoch(st))
if err != nil {
return err
}
if !bytes.Equal(payload.Random, random) {
return errors.New("incorrect random")
}
t, err := slots.ToTime(st.GenesisTime(), st.Slot())
if err != nil {
return err
}
if payload.Timestamp != uint64(t.Unix()) {
return errors.New("incorrect timestamp")
}
return nil
}
// This converts `payload` into execution payload header format.
func payloadToHeader(payload *ethpb.ExecutionPayload) (*ethpb.ExecutionPayloadHeader, error) {
txRoot, err := ssz.TransactionsRoot(payload.Transactions)
if err != nil {
return nil, err
}
return &ethpb.ExecutionPayloadHeader{
ParentHash: bytesutil.SafeCopyBytes(payload.ParentHash),
Coinbase: bytesutil.SafeCopyBytes(payload.Coinbase),
StateRoot: bytesutil.SafeCopyBytes(payload.StateRoot),
ReceiptRoot: bytesutil.SafeCopyBytes(payload.ReceiptRoot),
LogsBloom: bytesutil.SafeCopyBytes(payload.LogsBloom),
Random: bytesutil.SafeCopyBytes(payload.Random),
BlockNumber: payload.BlockNumber,
GasLimit: payload.GasLimit,
GasUsed: payload.GasUsed,
Timestamp: payload.Timestamp,
ExtraData: bytesutil.SafeCopyBytes(payload.ExtraData),
BaseFeePerGas: bytesutil.SafeCopyBytes(payload.BaseFeePerGas),
BlockHash: bytesutil.SafeCopyBytes(payload.BlockHash),
TransactionsRoot: txRoot[:],
}, nil
}
// EmptyPayload represents `ExecutionPayload()` in spec.
func EmptyPayload() *ethpb.ExecutionPayload {
return &ethpb.ExecutionPayload{
ParentHash: make([]byte, 32),
Coinbase: make([]byte, 20),
StateRoot: make([]byte, 32),
ReceiptRoot: make([]byte, 32),
LogsBloom: make([]byte, 256),
Random: make([]byte, 32),
BlockNumber: 0,
GasLimit: 0,
GasUsed: 0,
Timestamp: 0,
ExtraData: nil,
BaseFeePerGas: make([]byte, 32),
BlockHash: make([]byte, 32),
Transactions: nil,
}
}
// This represents `ExecutionPayloadHeader()` in spec.
func EmptypayloadHeader() *ethpb.ExecutionPayloadHeader {
return &ethpb.ExecutionPayloadHeader{
ParentHash: make([]byte, 32),
Coinbase: make([]byte, 20),
StateRoot: make([]byte, 32),
ReceiptRoot: make([]byte, 32),
LogsBloom: make([]byte, 256),
Random: make([]byte, 32),
BlockNumber: 0,
GasLimit: 0,
GasUsed: 0,
Timestamp: 0,
ExtraData: nil,
BaseFeePerGas: make([]byte, 32),
BlockHash: make([]byte, 32),
TransactionsRoot: make([]byte, 32),
}
}

View File

@@ -0,0 +1,85 @@
package execution
import (
"context"
"github.com/prysmaticlabs/prysm/beacon-chain/core/time"
"github.com/prysmaticlabs/prysm/beacon-chain/state"
v2 "github.com/prysmaticlabs/prysm/beacon-chain/state/v3"
"github.com/prysmaticlabs/prysm/config/params"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
)
// UpgradeToMerge updates input state to return the version Merge state.
func UpgradeToMerge(ctx context.Context, state state.BeaconState) (state.BeaconState, error) {
epoch := time.CurrentEpoch(state)
currentSyncCommittee, err := state.CurrentSyncCommittee()
if err != nil {
return nil, err
}
nextSyncCommittee, err := state.NextSyncCommittee()
if err != nil {
return nil, err
}
prevEpochParticipation, err := state.PreviousEpochParticipation()
if err != nil {
return nil, err
}
currentEpochParticipation, err := state.CurrentEpochParticipation()
if err != nil {
return nil, err
}
inactivityScores, err := state.InactivityScores()
if err != nil {
return nil, err
}
s := &ethpb.BeaconStateMerge{
GenesisTime: state.GenesisTime(),
GenesisValidatorsRoot: state.GenesisValidatorRoot(),
Slot: state.Slot(),
Fork: &ethpb.Fork{
PreviousVersion: state.Fork().CurrentVersion,
CurrentVersion: params.BeaconConfig().MergeForkVersion,
Epoch: epoch,
},
LatestBlockHeader: state.LatestBlockHeader(),
BlockRoots: state.BlockRoots(),
StateRoots: state.StateRoots(),
HistoricalRoots: state.HistoricalRoots(),
Eth1Data: state.Eth1Data(),
Eth1DataVotes: state.Eth1DataVotes(),
Eth1DepositIndex: state.Eth1DepositIndex(),
Validators: state.Validators(),
Balances: state.Balances(),
RandaoMixes: state.RandaoMixes(),
Slashings: state.Slashings(),
PreviousEpochParticipation: prevEpochParticipation,
CurrentEpochParticipation: currentEpochParticipation,
JustificationBits: state.JustificationBits(),
PreviousJustifiedCheckpoint: state.PreviousJustifiedCheckpoint(),
CurrentJustifiedCheckpoint: state.CurrentJustifiedCheckpoint(),
FinalizedCheckpoint: state.FinalizedCheckpoint(),
InactivityScores: inactivityScores,
CurrentSyncCommittee: currentSyncCommittee,
NextSyncCommittee: nextSyncCommittee,
LatestExecutionPayloadHeader: &ethpb.ExecutionPayloadHeader{
ParentHash: make([]byte, 32),
Coinbase: make([]byte, 20),
StateRoot: make([]byte, 32),
ReceiptRoot: make([]byte, 32),
LogsBloom: make([]byte, 256),
Random: make([]byte, 32),
BlockNumber: 0,
GasLimit: 0,
GasUsed: 0,
Timestamp: 0,
BaseFeePerGas: make([]byte, 32),
BlockHash: make([]byte, 32),
TransactionsRoot: make([]byte, 32),
},
}
return v2.InitializeFromProto(s)
}

View File

@@ -199,7 +199,7 @@ func CommitteeAssignments(
// Each slot in an epoch has a different set of committees. This value is derived from the
// active validator set, which does not change.
numCommitteesPerSlot := SlotCommitteeCount(uint64(len(activeValidatorIndices)))
validatorIndexToCommittee := make(map[types.ValidatorIndex]*CommitteeAssignmentContainer, len(activeValidatorIndices))
validatorIndexToCommittee := make(map[types.ValidatorIndex]*CommitteeAssignmentContainer, params.BeaconConfig().SlotsPerEpoch.Mul(numCommitteesPerSlot))
// Compute all committees for all slots.
for i := types.Slot(0); i < params.BeaconConfig().SlotsPerEpoch; i++ {

View File

@@ -2,9 +2,9 @@ package signing
import (
"github.com/pkg/errors"
"github.com/prysmaticlabs/eth2-types"
types "github.com/prysmaticlabs/eth2-types"
"github.com/prysmaticlabs/prysm/crypto/bls"
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
eth "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
)
// Domain returns the domain version for BLS private key to sign and verify.

View File

@@ -3,9 +3,9 @@ package signing
import (
"testing"
"github.com/prysmaticlabs/eth2-types"
types "github.com/prysmaticlabs/eth2-types"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
eth "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/testing/assert"
"github.com/prysmaticlabs/prysm/testing/require"
)

View File

@@ -114,40 +114,6 @@ func TestCanUpgradeToAltair(t *testing.T) {
}
}
func TestCanUpgradeToMerge(t *testing.T) {
bc := params.BeaconConfig()
bc.MergeForkEpoch = 5
params.OverrideBeaconConfig(bc)
tests := []struct {
name string
slot types.Slot
want bool
}{
{
name: "not epoch start",
slot: 1,
want: false,
},
{
name: "not merge epoch",
slot: params.BeaconConfig().SlotsPerEpoch,
want: false,
},
{
name: "merge epoch",
slot: types.Slot(params.BeaconConfig().MergeForkEpoch) * params.BeaconConfig().SlotsPerEpoch,
want: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := CanUpgradeToMerge(tt.slot); got != tt.want {
t.Errorf("CanUpgradeToMerge() = %v, want %v", got, tt.want)
}
})
}
}
func TestCanProcessEpoch_TrueOnEpochsLastSlot(t *testing.T) {
tests := []struct {
slot types.Slot

View File

@@ -30,6 +30,7 @@ go_library(
"//beacon-chain/core/blocks:go_default_library",
"//beacon-chain/core/epoch:go_default_library",
"//beacon-chain/core/epoch/precompute:go_default_library",
"//beacon-chain/core/execution:go_default_library",
"//beacon-chain/core/helpers:go_default_library",
"//beacon-chain/core/time:go_default_library",
"//beacon-chain/core/transition/interop:go_default_library",

View File

@@ -14,6 +14,7 @@ import (
"github.com/prysmaticlabs/prysm/beacon-chain/core/altair"
e "github.com/prysmaticlabs/prysm/beacon-chain/core/epoch"
"github.com/prysmaticlabs/prysm/beacon-chain/core/epoch/precompute"
"github.com/prysmaticlabs/prysm/beacon-chain/core/execution"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/beacon-chain/core/time"
"github.com/prysmaticlabs/prysm/beacon-chain/state"
@@ -250,6 +251,12 @@ func ProcessSlots(ctx context.Context, state state.BeaconState, slot types.Slot)
tracing.AnnotateError(span, err)
return nil, errors.Wrap(err, "could not process epoch")
}
case version.Merge:
state, err = altair.ProcessEpoch(ctx, state)
if err != nil {
tracing.AnnotateError(span, err)
return nil, errors.Wrap(err, "could not process epoch")
}
default:
return nil, errors.New("beacon state should have a version")
}
@@ -266,6 +273,14 @@ func ProcessSlots(ctx context.Context, state state.BeaconState, slot types.Slot)
return nil, err
}
}
if time.CanUpgradeToMerge(state.Slot()) {
state, err = execution.UpgradeToMerge(ctx, state)
if err != nil {
tracing.AnnotateError(span, err)
return nil, err
}
}
}
if highestSlot < state.Slot() {

View File

@@ -8,6 +8,7 @@ import (
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/beacon-chain/core/altair"
b "github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
"github.com/prysmaticlabs/prysm/beacon-chain/core/execution"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/beacon-chain/core/transition/interop"
v "github.com/prysmaticlabs/prysm/beacon-chain/core/validators"
@@ -152,7 +153,7 @@ func CalculateStateRoot(
if err != nil {
return [32]byte{}, errors.Wrap(err, "could not process block")
}
if signed.Version() == version.Altair {
if signed.Version() == version.Altair || signed.Version() == version.Merge {
sa, err := signed.Block().Body().SyncAggregate()
if err != nil {
return [32]byte{}, err
@@ -198,7 +199,7 @@ func ProcessBlockNoVerifyAnySig(
if err != nil {
return nil, nil, err
}
if signed.Version() == version.Altair {
if signed.Version() == version.Altair || signed.Version() == version.Merge {
sa, err := signed.Block().Body().SyncAggregate()
if err != nil {
return nil, nil, err
@@ -278,6 +279,11 @@ func ProcessOperationsNoVerifyAttsSigs(
if err != nil {
return nil, err
}
case version.Merge:
state, err = altairOperations(ctx, state, signedBeaconBlock)
if err != nil {
return nil, err
}
default:
return nil, errors.New("block does not have correct version")
}
@@ -302,7 +308,7 @@ func ProcessBlockForStateRoot(
body := blk.Body()
bodyRoot, err := body.HashTreeRoot()
if err != nil {
return nil, err
return nil, errors.Wrap(err, "could not hash tree root beacon block body")
}
state, err = b.ProcessBlockHeaderNoVerify(ctx, state, blk.Slot(), blk.ProposerIndex(), blk.ParentRoot(), bodyRoot[:])
if err != nil {
@@ -310,6 +316,24 @@ func ProcessBlockForStateRoot(
return nil, errors.Wrap(err, "could not process block header")
}
if state.Version() == version.Merge {
enabled, err := execution.Enabled(state, blk.Body())
if err != nil {
tracing.AnnotateError(span, err)
return nil, errors.Wrap(err, "could not check if execution is enabled")
}
if enabled {
payload, err := blk.Body().ExecutionPayload()
if err != nil {
return nil, err
}
state, err = execution.ProcessPayload(state, payload)
if err != nil {
return nil, errors.Wrap(err, "could not process execution payload")
}
}
}
state, err = b.ProcessRandaoNoVerify(state, signed.Block().Body().RandaoReveal())
if err != nil {
tracing.AnnotateError(span, err)

View File

@@ -42,6 +42,7 @@ go_library(
"//beacon-chain/state/genesis:go_default_library",
"//beacon-chain/state/v1:go_default_library",
"//beacon-chain/state/v2:go_default_library",
"//beacon-chain/state/v3:go_default_library",
"//config/features:go_default_library",
"//config/params:go_default_library",
"//container/slice:go_default_library",

View File

@@ -9,3 +9,10 @@ func hasAltairKey(enc []byte) bool {
}
return bytes.Equal(enc[:len(altairKey)], altairKey)
}
func hasMergeKey(enc []byte) bool {
if len(mergeKey) >= len(enc) {
return false
}
return bytes.Equal(enc[:len(mergeKey)], mergeKey)
}

View File

@@ -609,6 +609,13 @@ func unmarshalBlock(_ context.Context, enc []byte) (block.SignedBeaconBlock, err
return nil, err
}
return wrapper.WrappedAltairSignedBeaconBlock(rawBlock)
case hasMergeKey(enc):
rawBlock := &ethpb.SignedBeaconBlockMerge{}
err := rawBlock.UnmarshalSSZ(enc[len(mergeKey):])
if err != nil {
return nil, err
}
return wrapper.WrappedMergeSignedBeaconBlock(rawBlock)
default:
// Marshal block bytes to phase 0 beacon block.
rawBlock := &ethpb.SignedBeaconBlock{}
@@ -627,6 +634,8 @@ func marshalBlock(_ context.Context, blk block.SignedBeaconBlock) ([]byte, error
return nil, err
}
switch blk.Version() {
case version.Merge:
return snappy.Encode(nil, append(mergeKey, obj...)), nil
case version.Altair:
return snappy.Encode(nil, append(altairKey, obj...)), nil
case version.Phase0:

View File

@@ -46,6 +46,7 @@ var (
// Altair key used to identify object is altair compatible.
// Objects that are only compatible with altair should be prefixed with such key.
altairKey = []byte("altair")
mergeKey = []byte("merge")
// Deprecated: This index key was migrated in PR 6461. Do not use, except for migrations.
lastArchivedIndexKey = []byte("last-archived")

View File

@@ -12,6 +12,7 @@ import (
"github.com/prysmaticlabs/prysm/beacon-chain/state/genesis"
v1 "github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
v2 "github.com/prysmaticlabs/prysm/beacon-chain/state/v2"
v3 "github.com/prysmaticlabs/prysm/beacon-chain/state/v3"
"github.com/prysmaticlabs/prysm/config/features"
"github.com/prysmaticlabs/prysm/config/params"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
@@ -385,6 +386,20 @@ func (s *Store) unmarshalState(_ context.Context, enc []byte, validatorEntries [
}
switch {
case hasMergeKey(enc):
// Marshal state bytes to altair beacon state.
protoState := &ethpb.BeaconStateMerge{}
if err := protoState.UnmarshalSSZ(enc[len(mergeKey):]); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal encoding for altair")
}
ok, err := s.isStateValidatorMigrationOver()
if err != nil {
return nil, err
}
if ok {
protoState.Validators = validatorEntries
}
return v3.InitializeFromProtoUnsafe(protoState)
case hasAltairKey(enc):
// Marshal state bytes to altair beacon state.
protoState := &ethpb.BeaconStateAltair{}
@@ -438,6 +453,19 @@ func marshalState(ctx context.Context, st state.ReadOnlyBeaconState) ([]byte, er
return nil, err
}
return snappy.Encode(nil, append(altairKey, rawObj...)), nil
case *ethpb.BeaconStateMerge:
rState, ok := st.InnerStateUnsafe().(*ethpb.BeaconStateMerge)
if !ok {
return nil, errors.New("non valid inner state")
}
if rState == nil {
return nil, errors.New("nil state")
}
rawObj, err := rState.MarshalSSZ()
if err != nil {
return nil, err
}
return snappy.Encode(nil, append(mergeKey, rawObj...)), nil
default:
return nil, errors.New("invalid inner state")
}

View File

@@ -36,7 +36,6 @@ go_library(
"//beacon-chain/rpc:go_default_library",
"//beacon-chain/rpc/apimiddleware:go_default_library",
"//beacon-chain/slasher:go_default_library",
"//beacon-chain/state:go_default_library",
"//beacon-chain/state/stategen:go_default_library",
"//beacon-chain/sync:go_default_library",
"//beacon-chain/sync/initial-sync:go_default_library",
@@ -45,7 +44,6 @@ go_library(
"//config/features:go_default_library",
"//config/params:go_default_library",
"//container/slice:go_default_library",
"//encoding/bytesutil:go_default_library",
"//monitoring/backup:go_default_library",
"//monitoring/prometheus:go_default_library",
"//monitoring/tracing:go_default_library",
@@ -77,7 +75,6 @@ go_test(
"//config/params:go_default_library",
"//testing/assert:go_default_library",
"//testing/require:go_default_library",
"@com_github_ethereum_go_ethereum//common:go_default_library",
"@com_github_prysmaticlabs_eth2_types//:go_default_library",
"@com_github_sirupsen_logrus//hooks/test:go_default_library",
"@com_github_urfave_cli_v2//:go_default_library",

View File

@@ -97,7 +97,12 @@ func configureInteropConfig(cliCtx *cli.Context) {
}
}
func configureExecutionSetting(cliCtx *cli.Context) {
func configureExecutionMode(cliCtx *cli.Context) {
if cliCtx.IsSet(flags.EnableMerge.Name) {
c := params.BeaconConfig()
c.EnabledMerge = cliCtx.Bool(flags.EnableMerge.Name)
params.OverrideBeaconConfig(c)
}
if cliCtx.IsSet(flags.TerminalTotalDifficultyOverride.Name) {
c := params.BeaconConfig()
c.TerminalTotalDifficulty = cliCtx.Uint64(flags.TerminalTotalDifficultyOverride.Name)
@@ -113,9 +118,9 @@ func configureExecutionSetting(cliCtx *cli.Context) {
c.TerminalBlockHashActivationEpoch = types.Epoch(cliCtx.Uint64(flags.TerminalBlockHashActivationEpochOverride.Name))
params.OverrideBeaconConfig(c)
}
if cliCtx.IsSet(flags.Coinbase.Name) {
if cliCtx.IsSet(flags.FeeRecipient.Name) {
c := params.BeaconConfig()
c.Coinbase = common.HexToAddress(cliCtx.String(flags.Coinbase.Name))
c.FeeRecipient = common.HexToAddress(cliCtx.String(flags.FeeRecipient.Name))
params.OverrideBeaconConfig(c)
}
}

View File

@@ -6,7 +6,6 @@ import (
"strconv"
"testing"
"github.com/ethereum/go-ethereum/common"
types "github.com/prysmaticlabs/eth2-types"
"github.com/prysmaticlabs/prysm/cmd"
"github.com/prysmaticlabs/prysm/cmd/beacon-chain/flags"
@@ -71,29 +70,6 @@ func TestConfigureProofOfWork(t *testing.T) {
assert.Equal(t, "deposit-contract", params.BeaconConfig().DepositContractAddress)
}
func TestConfigureExecutionSetting(t *testing.T) {
params.SetupTestConfigCleanup(t)
app := cli.App{}
set := flag.NewFlagSet("test", 0)
set.Uint64(flags.TerminalTotalDifficultyOverride.Name, 0, "")
set.String(flags.TerminalBlockHashOverride.Name, "", "")
set.Uint64(flags.TerminalBlockHashActivationEpochOverride.Name, 0, "")
set.String(flags.Coinbase.Name, "", "")
require.NoError(t, set.Set(flags.TerminalTotalDifficultyOverride.Name, strconv.Itoa(100)))
require.NoError(t, set.Set(flags.TerminalBlockHashOverride.Name, "0xA"))
require.NoError(t, set.Set(flags.TerminalBlockHashActivationEpochOverride.Name, strconv.Itoa(200)))
require.NoError(t, set.Set(flags.Coinbase.Name, "0xB"))
cliCtx := cli.NewContext(&app, set, nil)
configureExecutionSetting(cliCtx)
assert.Equal(t, uint64(100), params.BeaconConfig().TerminalTotalDifficulty)
assert.Equal(t, common.HexToHash("0xA"), params.BeaconConfig().TerminalBlockHash)
assert.Equal(t, types.Epoch(200), params.BeaconConfig().TerminalBlockHashActivationEpoch)
assert.Equal(t, common.HexToAddress("0xB"), params.BeaconConfig().Coinbase)
}
func TestConfigureNetwork(t *testing.T) {
params.SetupTestConfigCleanup(t)

View File

@@ -38,7 +38,6 @@ import (
"github.com/prysmaticlabs/prysm/beacon-chain/rpc"
"github.com/prysmaticlabs/prysm/beacon-chain/rpc/apimiddleware"
"github.com/prysmaticlabs/prysm/beacon-chain/slasher"
"github.com/prysmaticlabs/prysm/beacon-chain/state"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stategen"
regularsync "github.com/prysmaticlabs/prysm/beacon-chain/sync"
initialsync "github.com/prysmaticlabs/prysm/beacon-chain/sync/initial-sync"
@@ -47,7 +46,6 @@ import (
"github.com/prysmaticlabs/prysm/config/features"
"github.com/prysmaticlabs/prysm/config/params"
"github.com/prysmaticlabs/prysm/container/slice"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/monitoring/backup"
"github.com/prysmaticlabs/prysm/monitoring/prometheus"
"github.com/prysmaticlabs/prysm/runtime"
@@ -63,14 +61,6 @@ const testSkipPowFlag = "test-skip-pow"
// 128MB max message size when enabling debug endpoints.
const debugGrpcMaxMsgSize = 1 << 27
// Used as a struct to keep cli flag options for configuring services
// for the beacon node. We keep this as a separate struct to not pollute the actual BeaconNode
// struct, as it is merely used to pass down configuration options into the appropriate services.
type serviceFlagOpts struct {
blockchainFlagOpts []blockchain.Option
powchainFlagOpts []powchain.Option
}
// BeaconNode defines a struct that handles the services running a random beacon chain
// full PoS node. It handles the lifecycle of the entire system and registers
// services to a service registry.
@@ -96,8 +86,7 @@ type BeaconNode struct {
collector *bcnodeCollector
slasherBlockHeadersFeed *event.Feed
slasherAttestationsFeed *event.Feed
finalizedStateAtStartUp state.BeaconState
serviceFlagOpts *serviceFlagOpts
blockchainFlagOpts []blockchain.Option
}
// New creates a new node instance, sets up configuration options, and registers
@@ -116,6 +105,7 @@ func New(cliCtx *cli.Context, opts ...Option) (*BeaconNode, error) {
configureEth1Config(cliCtx)
configureNetwork(cliCtx)
configureInteropConfig(cliCtx)
configureExecutionMode(cliCtx)
// Initializes any forks here.
params.BeaconConfig().InitializeForkSchedule()
@@ -138,7 +128,6 @@ func New(cliCtx *cli.Context, opts ...Option) (*BeaconNode, error) {
syncCommitteePool: synccommittee.NewPool(),
slasherBlockHeadersFeed: new(event.Feed),
slasherAttestationsFeed: new(event.Feed),
serviceFlagOpts: &serviceFlagOpts{},
}
for _, opt := range opts {
@@ -147,7 +136,7 @@ func New(cliCtx *cli.Context, opts ...Option) (*BeaconNode, error) {
}
}
depositAddress, err := powchain.DepositContractAddress()
depositAddress, err := registration.DepositContractAddress()
if err != nil {
return nil, err
}
@@ -159,9 +148,7 @@ func New(cliCtx *cli.Context, opts ...Option) (*BeaconNode, error) {
return nil, err
}
if err := beacon.startStateGen(); err != nil {
return nil, err
}
beacon.startStateGen()
if err := beacon.registerP2P(cliCtx); err != nil {
return nil, err
@@ -434,34 +421,8 @@ func (b *BeaconNode) startSlasherDB(cliCtx *cli.Context) error {
return nil
}
func (b *BeaconNode) startStateGen() error {
func (b *BeaconNode) startStateGen() {
b.stateGen = stategen.New(b.db)
cp, err := b.db.FinalizedCheckpoint(b.ctx)
if err != nil {
return err
}
r := bytesutil.ToBytes32(cp.Root)
// Consider edge case where finalized root are zeros instead of genesis root hash.
if r == params.BeaconConfig().ZeroHash {
genesisBlock, err := b.db.GenesisBlock(b.ctx)
if err != nil {
return err
}
if genesisBlock != nil && !genesisBlock.IsNil() {
r, err = genesisBlock.Block().HashTreeRoot()
if err != nil {
return err
}
}
}
b.finalizedStateAtStartUp, err = b.stateGen.StateByRoot(b.ctx, r)
if err != nil {
return err
}
return nil
}
func (b *BeaconNode) registerP2P(cliCtx *cli.Context) error {
@@ -528,10 +489,11 @@ func (b *BeaconNode) registerBlockchainService() error {
// skipcq: CRT-D0001
opts := append(
b.serviceFlagOpts.blockchainFlagOpts,
b.blockchainFlagOpts,
blockchain.WithDatabase(b.db),
blockchain.WithDepositCache(b.depositCache),
blockchain.WithChainStartFetcher(web3Service),
blockchain.WithExecutionEngineCaller(web3Service),
blockchain.WithAttestationPool(b.attestationPool),
blockchain.WithExitPool(b.exitPool),
blockchain.WithSlashingPool(b.slashingsPool),
@@ -541,7 +503,6 @@ func (b *BeaconNode) registerBlockchainService() error {
blockchain.WithAttestationService(attService),
blockchain.WithStateGen(b.stateGen),
blockchain.WithSlasherAttestationsFeed(b.slasherAttestationsFeed),
blockchain.WithFinalizedStateAtStartUp(b.finalizedStateAtStartUp),
)
blockchainService, err := blockchain.NewService(b.ctx, opts...)
if err != nil {
@@ -554,27 +515,29 @@ func (b *BeaconNode) registerPOWChainService() error {
if b.cliCtx.Bool(testSkipPowFlag) {
return b.services.RegisterService(&powchain.Service{})
}
bs, err := powchain.NewPowchainCollector(b.ctx)
if err != nil {
return err
}
depositContractAddr, err := powchain.DepositContractAddress()
depAddress, endpoints, err := registration.PowchainPreregistration(b.cliCtx)
if err != nil {
return err
}
// skipcq: CRT-D0001
opts := append(
b.serviceFlagOpts.powchainFlagOpts,
powchain.WithDepositContractAddress(common.HexToAddress(depositContractAddr)),
powchain.WithDatabase(b.db),
powchain.WithDepositCache(b.depositCache),
powchain.WithStateNotifier(b),
powchain.WithStateGen(b.stateGen),
powchain.WithBeaconNodeStatsUpdater(bs),
powchain.WithFinalizedStateAtStartup(b.finalizedStateAtStartUp),
)
web3Service, err := powchain.NewService(b.ctx, opts...)
bs, err := powchain.NewPowchainCollector(b.ctx)
if err != nil {
return err
}
cfg := &powchain.Web3ServiceConfig{
HttpEndpoints: endpoints,
DepositContract: common.HexToAddress(depAddress),
BeaconDB: b.db,
DepositCache: b.depositCache,
StateNotifier: b,
StateGen: b.stateGen,
Eth1HeaderReqLimit: b.cliCtx.Uint64(flags.Eth1HeaderReqLimit.Name),
BeaconNodeStatsUpdater: bs,
}
web3Service, err := powchain.NewService(b.ctx, cfg)
if err != nil {
return errors.Wrap(err, "could not register proof-of-work chain web3Service")
}
@@ -598,24 +561,24 @@ func (b *BeaconNode) registerSyncService() error {
return err
}
rs := regularsync.NewService(
b.ctx,
regularsync.WithDatabase(b.db),
regularsync.WithP2P(b.fetchP2P()),
regularsync.WithChainService(chainService),
regularsync.WithInitialSync(initSync),
regularsync.WithStateNotifier(b),
regularsync.WithBlockNotifier(b),
regularsync.WithAttestationNotifier(b),
regularsync.WithOperationNotifier(b),
regularsync.WithAttestationPool(b.attestationPool),
regularsync.WithExitPool(b.exitPool),
regularsync.WithSlashingPool(b.slashingsPool),
regularsync.WithSyncCommsPool(b.syncCommitteePool),
regularsync.WithStateGen(b.stateGen),
regularsync.WithSlasherAttestationsFeed(b.slasherAttestationsFeed),
regularsync.WithSlasherBlockHeadersFeed(b.slasherBlockHeadersFeed),
)
rs := regularsync.NewService(b.ctx, &regularsync.Config{
DB: b.db,
P2P: b.fetchP2P(),
Chain: chainService,
InitialSync: initSync,
StateNotifier: b,
BlockNotifier: b,
AttestationNotifier: b,
OperationNotifier: b,
AttPool: b.attestationPool,
ExitPool: b.exitPool,
SlashingPool: b.slashingsPool,
SyncCommsPool: b.syncCommitteePool,
StateGen: b.stateGen,
SlasherAttestationsFeed: b.slasherAttestationsFeed,
SlasherBlockHeadersFeed: b.slasherBlockHeadersFeed,
})
return b.services.RegisterService(rs)
}
@@ -757,6 +720,7 @@ func (b *BeaconNode) registerRPCService() error {
StateGen: b.stateGen,
EnableDebugRPCEndpoints: enableDebugRPCEndpoints,
MaxMsgSize: maxMsgSize,
ExecutionEngineCaller: web3Service,
})
return b.services.RegisterService(rpcService)

View File

@@ -1,9 +1,6 @@
package node
import (
"github.com/prysmaticlabs/prysm/beacon-chain/blockchain"
"github.com/prysmaticlabs/prysm/beacon-chain/powchain"
)
import "github.com/prysmaticlabs/prysm/beacon-chain/blockchain"
// Option for beacon node configuration.
type Option func(bn *BeaconNode) error
@@ -11,15 +8,7 @@ type Option func(bn *BeaconNode) error
// WithBlockchainFlagOptions includes functional options for the blockchain service related to CLI flags.
func WithBlockchainFlagOptions(opts []blockchain.Option) Option {
return func(bn *BeaconNode) error {
bn.serviceFlagOpts.blockchainFlagOpts = opts
return nil
}
}
// WithPowchainFlagOptions includes functional options for the powchain service related to CLI flags.
func WithPowchainFlagOptions(opts []powchain.Option) Option {
return func(bn *BeaconNode) error {
bn.serviceFlagOpts.powchainFlagOpts = opts
bn.blockchainFlagOpts = opts
return nil
}
}

View File

@@ -5,12 +5,15 @@ go_library(
srcs = [
"log.go",
"p2p.go",
"powchain.go",
],
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/node/registration",
visibility = ["//beacon-chain/node:__subpackages__"],
deps = [
"//cmd:go_default_library",
"//cmd/beacon-chain/flags:go_default_library",
"//config/params:go_default_library",
"@com_github_ethereum_go_ethereum//common:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
"@com_github_urfave_cli_v2//:go_default_library",
"@in_gopkg_yaml_v2//:go_default_library",
@@ -19,13 +22,18 @@ go_library(
go_test(
name = "go_default_test",
srcs = ["p2p_test.go"],
srcs = [
"p2p_test.go",
"powchain_test.go",
],
embed = [":go_default_library"],
deps = [
"//cmd:go_default_library",
"//cmd/beacon-chain/flags:go_default_library",
"//config/params:go_default_library",
"//testing/assert:go_default_library",
"//testing/require:go_default_library",
"@com_github_sirupsen_logrus//hooks/test:go_default_library",
"@com_github_urfave_cli_v2//:go_default_library",
],
)

View File

@@ -0,0 +1,45 @@
package registration
import (
"errors"
"github.com/ethereum/go-ethereum/common"
"github.com/prysmaticlabs/prysm/cmd/beacon-chain/flags"
"github.com/prysmaticlabs/prysm/config/params"
"github.com/urfave/cli/v2"
)
// PowchainPreregistration prepares data for powchain.Service's registration.
func PowchainPreregistration(cliCtx *cli.Context) (depositContractAddress string, endpoints []string, err error) {
depositContractAddress, err = DepositContractAddress()
if err != nil {
return "", nil, err
}
if cliCtx.String(flags.HTTPWeb3ProviderFlag.Name) == "" && len(cliCtx.StringSlice(flags.FallbackWeb3ProviderFlag.Name)) == 0 {
log.Error(
"No ETH1 node specified to run with the beacon node. Please consider running your own Ethereum proof-of-work node for better uptime, security, and decentralization of Ethereum. Visit https://docs.prylabs.network/docs/prysm-usage/setup-eth1 for more information.",
)
log.Error(
"You will need to specify --http-web3provider and/or --fallback-web3provider to attach an eth1 node to the prysm node. Without an eth1 node block proposals for your validator will be affected and the beacon node will not be able to initialize the genesis state.",
)
}
endpoints = []string{cliCtx.String(flags.HTTPWeb3ProviderFlag.Name)}
endpoints = append(endpoints, cliCtx.StringSlice(flags.FallbackWeb3ProviderFlag.Name)...)
return
}
// DepositContractAddress returns the address of the deposit contract.
func DepositContractAddress() (string, error) {
address := params.BeaconConfig().DepositContractAddress
if address == "" {
return "", errors.New("valid deposit contract is required")
}
if !common.IsHexAddress(address) {
return "", errors.New("invalid deposit contract address given: " + address)
}
return address, nil
}

View File

@@ -0,0 +1,71 @@
package registration
import (
"flag"
"testing"
"github.com/prysmaticlabs/prysm/cmd/beacon-chain/flags"
"github.com/prysmaticlabs/prysm/config/params"
"github.com/prysmaticlabs/prysm/testing/assert"
"github.com/prysmaticlabs/prysm/testing/require"
logTest "github.com/sirupsen/logrus/hooks/test"
"github.com/urfave/cli/v2"
)
func TestPowchainPreregistration(t *testing.T) {
app := cli.App{}
set := flag.NewFlagSet("test", 0)
set.String(flags.HTTPWeb3ProviderFlag.Name, "primary", "")
fallback := cli.StringSlice{}
err := fallback.Set("fallback1")
require.NoError(t, err)
err = fallback.Set("fallback2")
require.NoError(t, err)
set.Var(&fallback, flags.FallbackWeb3ProviderFlag.Name, "")
ctx := cli.NewContext(&app, set, nil)
address, endpoints, err := PowchainPreregistration(ctx)
require.NoError(t, err)
assert.Equal(t, params.BeaconConfig().DepositContractAddress, address)
assert.DeepEqual(t, []string{"primary", "fallback1", "fallback2"}, endpoints)
}
func TestPowchainPreregistration_EmptyWeb3Provider(t *testing.T) {
hook := logTest.NewGlobal()
app := cli.App{}
set := flag.NewFlagSet("test", 0)
set.String(flags.HTTPWeb3ProviderFlag.Name, "", "")
fallback := cli.StringSlice{}
set.Var(&fallback, flags.FallbackWeb3ProviderFlag.Name, "")
ctx := cli.NewContext(&app, set, nil)
_, _, err := PowchainPreregistration(ctx)
require.NoError(t, err)
assert.LogsContain(t, hook, "No ETH1 node specified to run with the beacon node")
}
func TestDepositContractAddress_Ok(t *testing.T) {
address, err := DepositContractAddress()
require.NoError(t, err)
assert.Equal(t, params.BeaconConfig().DepositContractAddress, address)
}
func TestDepositContractAddress_EmptyAddress(t *testing.T) {
params.SetupTestConfigCleanup(t)
config := params.BeaconConfig()
config.DepositContractAddress = ""
params.OverrideBeaconConfig(config)
_, err := DepositContractAddress()
assert.ErrorContains(t, "valid deposit contract is required", err)
}
func TestDepositContractAddress_NotHexAddress(t *testing.T) {
params.SetupTestConfigCleanup(t)
config := params.BeaconConfig()
config.DepositContractAddress = "abc?!"
params.OverrideBeaconConfig(config)
_, err := DepositContractAddress()
assert.ErrorContains(t, "invalid deposit contract address given", err)
}

View File

@@ -14,7 +14,8 @@ func (s *Service) forkWatcher() {
select {
case currSlot := <-slotTicker.C():
currEpoch := slots.ToEpoch(currSlot)
if currEpoch == params.BeaconConfig().AltairForkEpoch {
if currEpoch == params.BeaconConfig().AltairForkEpoch ||
currEpoch == params.BeaconConfig().MergeForkEpoch {
// If we are in the fork epoch, we update our enr with
// the updated fork digest. These repeatedly does
// this over the epoch, which might be slightly wasteful

View File

@@ -103,13 +103,13 @@ func (s *Service) topicScoreParams(topic string) (*pubsub.TopicScoreParams, erro
case strings.Contains(topic, GossipBlockMessage):
return defaultBlockTopicParams(), nil
case strings.Contains(topic, GossipAggregateAndProofMessage):
return defaultAggregateTopicParams(activeValidators), nil
return defaultAggregateTopicParams(activeValidators)
case strings.Contains(topic, GossipAttestationMessage):
return defaultAggregateSubnetTopicParams(activeValidators), nil
return defaultAggregateSubnetTopicParams(activeValidators)
case strings.Contains(topic, GossipSyncCommitteeMessage):
return defaultSyncSubnetTopicParams(activeValidators), nil
return defaultSyncSubnetTopicParams(activeValidators)
case strings.Contains(topic, GossipContributionAndProofMessage):
return defaultSyncContributionTopicParams(), nil
return defaultSyncContributionTopicParams()
case strings.Contains(topic, GossipExitMessage):
return defaultVoluntaryExitTopicParams(), nil
case strings.Contains(topic, GossipProposerSlashingMessage):
@@ -191,19 +191,19 @@ func defaultBlockTopicParams() *pubsub.TopicScoreParams {
}
}
func defaultAggregateTopicParams(activeValidators uint64) *pubsub.TopicScoreParams {
func defaultAggregateTopicParams(activeValidators uint64) (*pubsub.TopicScoreParams, error) {
// Determine the expected message rate for the particular gossip topic.
aggPerSlot := aggregatorsPerSlot(activeValidators)
firstMessageCap, err := decayLimit(scoreDecay(1*oneEpochDuration()), float64(aggPerSlot*2/gossipSubD))
if err != nil {
log.Warnf("skipping initializing topic scoring: %v", err)
return nil
return nil, nil
}
firstMessageWeight := maxFirstDeliveryScore / firstMessageCap
meshThreshold, err := decayThreshold(scoreDecay(1*oneEpochDuration()), float64(aggPerSlot)/dampeningFactor)
if err != nil {
log.Warnf("skipping initializing topic scoring: %v", err)
return nil
return nil, nil
}
meshWeight := -scoreByWeight(aggregateWeight, meshThreshold)
meshCap := 4 * meshThreshold
@@ -230,22 +230,22 @@ func defaultAggregateTopicParams(activeValidators uint64) *pubsub.TopicScorePara
MeshFailurePenaltyDecay: scoreDecay(1 * oneEpochDuration()),
InvalidMessageDeliveriesWeight: -maxScore() / aggregateWeight,
InvalidMessageDeliveriesDecay: scoreDecay(invalidDecayPeriod),
}
}, nil
}
func defaultSyncContributionTopicParams() *pubsub.TopicScoreParams {
func defaultSyncContributionTopicParams() (*pubsub.TopicScoreParams, error) {
// Determine the expected message rate for the particular gossip topic.
aggPerSlot := params.BeaconConfig().SyncCommitteeSubnetCount * params.BeaconConfig().TargetAggregatorsPerSyncSubcommittee
firstMessageCap, err := decayLimit(scoreDecay(1*oneEpochDuration()), float64(aggPerSlot*2/gossipSubD))
if err != nil {
log.Warnf("skipping initializing topic scoring: %v", err)
return nil
return nil, nil
}
firstMessageWeight := maxFirstDeliveryScore / firstMessageCap
meshThreshold, err := decayThreshold(scoreDecay(1*oneEpochDuration()), float64(aggPerSlot)/dampeningFactor)
if err != nil {
log.Warnf("skipping initializing topic scoring: %v", err)
return nil
return nil, nil
}
meshWeight := -scoreByWeight(syncContributionWeight, meshThreshold)
meshCap := 4 * meshThreshold
@@ -272,23 +272,23 @@ func defaultSyncContributionTopicParams() *pubsub.TopicScoreParams {
MeshFailurePenaltyDecay: scoreDecay(1 * oneEpochDuration()),
InvalidMessageDeliveriesWeight: -maxScore() / syncContributionWeight,
InvalidMessageDeliveriesDecay: scoreDecay(invalidDecayPeriod),
}
}, nil
}
func defaultAggregateSubnetTopicParams(activeValidators uint64) *pubsub.TopicScoreParams {
func defaultAggregateSubnetTopicParams(activeValidators uint64) (*pubsub.TopicScoreParams, error) {
subnetCount := params.BeaconNetworkConfig().AttestationSubnetCount
// Get weight for each specific subnet.
topicWeight := attestationTotalWeight / float64(subnetCount)
subnetWeight := activeValidators / subnetCount
if subnetWeight == 0 {
log.Warn("Subnet weight is 0, skipping initializing topic scoring")
return nil
return nil, nil
}
// Determine the amount of validators expected in a subnet in a single slot.
numPerSlot := time.Duration(subnetWeight / uint64(params.BeaconConfig().SlotsPerEpoch))
if numPerSlot == 0 {
log.Warn("numPerSlot is 0, skipping initializing topic scoring")
return nil
return nil, nil
}
comsPerSlot := committeeCountPerSlot(activeValidators)
exceedsThreshold := comsPerSlot >= 2*subnetCount/uint64(params.BeaconConfig().SlotsPerEpoch)
@@ -301,20 +301,20 @@ func defaultAggregateSubnetTopicParams(activeValidators uint64) *pubsub.TopicSco
rate := numPerSlot * 2 / gossipSubD
if rate == 0 {
log.Warn("rate is 0, skipping initializing topic scoring")
return nil
return nil, nil
}
// Determine expected first deliveries based on the message rate.
firstMessageCap, err := decayLimit(scoreDecay(firstDecay*oneEpochDuration()), float64(rate))
if err != nil {
log.Warnf("skipping initializing topic scoring: %v", err)
return nil
return nil, nil
}
firstMessageWeight := maxFirstDeliveryScore / firstMessageCap
// Determine expected mesh deliveries based on message rate applied with a dampening factor.
meshThreshold, err := decayThreshold(scoreDecay(meshDecay*oneEpochDuration()), float64(numPerSlot)/dampeningFactor)
if err != nil {
log.Warnf("skipping initializing topic scoring: %v", err)
return nil
return nil, nil
}
meshWeight := -scoreByWeight(topicWeight, meshThreshold)
meshCap := 4 * meshThreshold
@@ -341,10 +341,10 @@ func defaultAggregateSubnetTopicParams(activeValidators uint64) *pubsub.TopicSco
MeshFailurePenaltyDecay: scoreDecay(meshDecay * oneEpochDuration()),
InvalidMessageDeliveriesWeight: -maxScore() / topicWeight,
InvalidMessageDeliveriesDecay: scoreDecay(invalidDecayPeriod),
}
}, nil
}
func defaultSyncSubnetTopicParams(activeValidators uint64) *pubsub.TopicScoreParams {
func defaultSyncSubnetTopicParams(activeValidators uint64) (*pubsub.TopicScoreParams, error) {
subnetCount := params.BeaconConfig().SyncCommitteeSubnetCount
// Get weight for each specific subnet.
topicWeight := syncCommitteesTotalWeight / float64(subnetCount)
@@ -356,7 +356,7 @@ func defaultSyncSubnetTopicParams(activeValidators uint64) *pubsub.TopicScorePar
subnetWeight := activeValidators / subnetCount
if subnetWeight == 0 {
log.Warn("Subnet weight is 0, skipping initializing topic scoring")
return nil
return nil, nil
}
firstDecay := time.Duration(1)
meshDecay := time.Duration(4)
@@ -364,20 +364,20 @@ func defaultSyncSubnetTopicParams(activeValidators uint64) *pubsub.TopicScorePar
rate := subnetWeight * 2 / gossipSubD
if rate == 0 {
log.Warn("rate is 0, skipping initializing topic scoring")
return nil
return nil, nil
}
// Determine expected first deliveries based on the message rate.
firstMessageCap, err := decayLimit(scoreDecay(firstDecay*oneEpochDuration()), float64(rate))
if err != nil {
log.WithError(err).Warn("Skipping initializing topic scoring")
return nil
return nil, nil
}
firstMessageWeight := maxFirstDeliveryScore / firstMessageCap
// Determine expected mesh deliveries based on message rate applied with a dampening factor.
meshThreshold, err := decayThreshold(scoreDecay(meshDecay*oneEpochDuration()), float64(subnetWeight)/dampeningFactor)
if err != nil {
log.WithError(err).Warn("Skipping initializing topic scoring")
return nil
return nil, nil
}
meshWeight := -scoreByWeight(topicWeight, meshThreshold)
meshCap := 4 * meshThreshold
@@ -404,7 +404,7 @@ func defaultSyncSubnetTopicParams(activeValidators uint64) *pubsub.TopicScorePar
MeshFailurePenaltyDecay: scoreDecay(meshDecay * oneEpochDuration()),
InvalidMessageDeliveriesWeight: -maxScore() / topicWeight,
InvalidMessageDeliveriesDecay: scoreDecay(invalidDecayPeriod),
}
}, nil
}
func defaultAttesterSlashingTopicParams() *pubsub.TopicScoreParams {

View File

@@ -68,9 +68,11 @@ func TestLoggingParameters(t *testing.T) {
logGossipParameters("testing", &pubsub.TopicScoreParams{})
// Test out actual gossip parameters.
logGossipParameters("testing", defaultBlockTopicParams())
p := defaultAggregateSubnetTopicParams(10000)
p, err := defaultAggregateSubnetTopicParams(10000)
assert.NoError(t, err)
logGossipParameters("testing", p)
p = defaultAggregateTopicParams(10000)
p, err = defaultAggregateTopicParams(10000)
assert.NoError(t, err)
logGossipParameters("testing", p)
logGossipParameters("testing", defaultAttesterSlashingTopicParams())
logGossipParameters("testing", defaultProposerSlashingTopicParams())

View File

@@ -26,8 +26,13 @@ var gossipTopicMappings = map[string]proto.Message{
// GossipTopicMappings is a function to return the assigned data type
// versioned by epoch.
func GossipTopicMappings(topic string, epoch types.Epoch) proto.Message {
if topic == BlockSubnetTopicFormat && epoch >= params.BeaconConfig().AltairForkEpoch {
return &ethpb.SignedBeaconBlockAltair{}
if topic == BlockSubnetTopicFormat {
if epoch >= params.BeaconConfig().MergeForkEpoch {
return &ethpb.SignedBeaconBlockMerge{}
}
if epoch >= params.BeaconConfig().AltairForkEpoch {
return &ethpb.SignedBeaconBlockAltair{}
}
}
return gossipTopicMappings[topic]
}
@@ -52,4 +57,5 @@ func init() {
}
// Specially handle Altair Objects.
GossipTypeMapping[reflect.TypeOf(&ethpb.SignedBeaconBlockAltair{})] = BlockSubnetTopicFormat
GossipTypeMapping[reflect.TypeOf(&ethpb.SignedBeaconBlockMerge{})] = BlockSubnetTopicFormat
}

View File

@@ -24,18 +24,28 @@ func TestMappingHasNoDuplicates(t *testing.T) {
func TestGossipTopicMappings_CorrectBlockType(t *testing.T) {
params.SetupTestConfigCleanup(t)
bCfg := params.BeaconConfig()
forkEpoch := eth2types.Epoch(100)
bCfg.AltairForkEpoch = forkEpoch
altairForkEpoch := eth2types.Epoch(100)
mergeForkEpoch := eth2types.Epoch(200)
bCfg.AltairForkEpoch = altairForkEpoch
bCfg.MergeForkEpoch = mergeForkEpoch
bCfg.ForkVersionSchedule[bytesutil.ToBytes4(bCfg.AltairForkVersion)] = eth2types.Epoch(100)
bCfg.ForkVersionSchedule[bytesutil.ToBytes4(bCfg.MergeForkVersion)] = eth2types.Epoch(200)
params.OverrideBeaconConfig(bCfg)
// Before Fork
// Phase 0
pMessage := GossipTopicMappings(BlockSubnetTopicFormat, 0)
_, ok := pMessage.(*ethpb.SignedBeaconBlock)
assert.Equal(t, true, ok)
// After Fork
pMessage = GossipTopicMappings(BlockSubnetTopicFormat, forkEpoch)
// Altair Fork
pMessage = GossipTopicMappings(BlockSubnetTopicFormat, altairForkEpoch)
_, ok = pMessage.(*ethpb.SignedBeaconBlockAltair)
assert.Equal(t, true, ok)
// Merge Fork
pMessage = GossipTopicMappings(BlockSubnetTopicFormat, mergeForkEpoch)
_, ok = pMessage.(*ethpb.SignedBeaconBlockMerge)
assert.Equal(t, true, ok)
}

BIN
beacon-chain/p2p/metaData Normal file

Binary file not shown.

View File

@@ -183,16 +183,8 @@ func (s *Service) loop(ctx context.Context) {
for {
select {
case <-decayBadResponsesStats.C:
// Exit early if context is canceled.
if ctx.Err() != nil {
return
}
s.scorers.badResponsesScorer.Decay()
case <-decayBlockProviderStats.C:
// Exit early if context is canceled.
if ctx.Err() != nil {
return
}
s.scorers.blockProviderScorer.Decay()
case <-ctx.Done():
return

View File

@@ -37,17 +37,24 @@ func (s *Service) CanSubscribe(topic string) bool {
if parts[1] != "eth2" {
return false
}
fd, err := s.currentForkDigest()
phase0ForkDigest, err := s.currentForkDigest()
if err != nil {
log.WithError(err).Error("Could not determine fork digest")
return false
}
digest, err := forks.ForkDigestFromEpoch(params.BeaconConfig().AltairForkEpoch, s.genesisValidatorsRoot)
altairForkDigest, err := forks.ForkDigestFromEpoch(params.BeaconConfig().AltairForkEpoch, s.genesisValidatorsRoot)
if err != nil {
log.WithError(err).Error("Could not determine next fork digest")
log.WithError(err).Error("Could not determine altair fork digest")
return false
}
if parts[2] != fmt.Sprintf("%x", fd) && parts[2] != fmt.Sprintf("%x", digest) {
mergeForkDigest, err := forks.ForkDigestFromEpoch(params.BeaconConfig().MergeForkEpoch, s.genesisValidatorsRoot)
if err != nil {
log.WithError(err).Error("Could not determine merge fork digest")
return false
}
if parts[2] != fmt.Sprintf("%x", phase0ForkDigest) &&
parts[2] != fmt.Sprintf("%x", altairForkDigest) &&
parts[2] != fmt.Sprintf("%x", mergeForkDigest) {
return false
}
if parts[4] != encoder.ProtocolSuffixSSZSnappy {

View File

@@ -102,7 +102,7 @@ func TestTopicFromMessage_CorrectType(t *testing.T) {
assert.Equal(t, SchemaVersionV1, version)
}
// After Fork
// Altair Fork
for m := range messageMapping {
topic, err := TopicFromMessage(m, forkEpoch)
assert.NoError(t, err)

View File

@@ -39,6 +39,9 @@ func InitializeDataMaps() {
bytesutil.ToBytes4(params.BeaconConfig().AltairForkVersion): func() (block.SignedBeaconBlock, error) {
return wrapper.WrappedAltairSignedBeaconBlock(&ethpb.SignedBeaconBlockAltair{Block: &ethpb.BeaconBlockAltair{}})
},
bytesutil.ToBytes4(params.BeaconConfig().MergeForkVersion): func() (block.SignedBeaconBlock, error) {
return wrapper.WrappedMergeSignedBeaconBlock(&ethpb.SignedBeaconBlockMerge{Block: &ethpb.BeaconBlockMerge{}})
},
}
// Reset our metadata map.
@@ -49,5 +52,8 @@ func InitializeDataMaps() {
bytesutil.ToBytes4(params.BeaconConfig().AltairForkVersion): func() metadata.Metadata {
return wrapper.WrappedMetadataV1(&ethpb.MetaDataV1{})
},
bytesutil.ToBytes4(params.BeaconConfig().MergeForkVersion): func() metadata.Metadata {
return wrapper.WrappedMetadataV1(&ethpb.MetaDataV1{})
},
}
}

View File

@@ -6,9 +6,9 @@ go_library(
"block_cache.go",
"block_reader.go",
"deposit.go",
"execution_engine.go",
"log.go",
"log_processing.go",
"options.go",
"prometheus.go",
"provider.go",
"service.go",
@@ -16,7 +16,6 @@ go_library(
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/powchain",
visibility = [
"//beacon-chain:__subpackages__",
"//cmd/beacon-chain:__subpackages__",
"//contracts:__subpackages__",
],
deps = [
@@ -31,6 +30,7 @@ go_library(
"//beacon-chain/state:go_default_library",
"//beacon-chain/state/stategen:go_default_library",
"//beacon-chain/state/v1:go_default_library",
"//config/features:go_default_library",
"//config/params:go_default_library",
"//container/trie:go_default_library",
"//contracts/deposit:go_default_library",
@@ -48,7 +48,9 @@ go_library(
"@com_github_ethereum_go_ethereum//accounts/abi/bind:go_default_library",
"@com_github_ethereum_go_ethereum//common:go_default_library",
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
"@com_github_ethereum_go_ethereum//common/math:go_default_library",
"@com_github_ethereum_go_ethereum//core/types:go_default_library",
"@com_github_ethereum_go_ethereum//eth/catalyst:go_default_library",
"@com_github_ethereum_go_ethereum//ethclient:go_default_library",
"@com_github_ethereum_go_ethereum//rpc:go_default_library",
"@com_github_pkg_errors//:go_default_library",
@@ -96,6 +98,7 @@ go_test(
"//network:go_default_library",
"//network/authorization:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//proto/prysm/v1alpha1/wrapper:go_default_library",
"//testing/assert:go_default_library",
"//testing/require:go_default_library",
"//testing/util:go_default_library",

View File

@@ -6,6 +6,7 @@ import (
"math/big"
"github.com/ethereum/go-ethereum/common"
gethTypes "github.com/ethereum/go-ethereum/core/types"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/beacon-chain/powchain/types"
"github.com/prysmaticlabs/prysm/config/params"
@@ -173,6 +174,28 @@ func (s *Service) BlockByTimestamp(ctx context.Context, time uint64) (*types.Hea
return s.findMoreTargetEth1Block(ctx, big.NewInt(int64(estimatedBlk)), time)
}
// BlockByHash returns the pow block by hash.
func (s *Service) BlockByHash(ctx context.Context, hash common.Hash) (*gethTypes.Block, error) {
ctx, span := trace.StartSpan(ctx, "beacon-chain.web3service.BlockByHash")
defer span.End()
if s.eth1DataFetcher == nil {
return nil, errors.New("nil eth1DataFetcher")
}
return s.eth1DataFetcher.BlockByHash(ctx, hash)
}
// BlockByNumber returns the pow block by number.
func (s *Service) BlockByNumber(ctx context.Context, number *big.Int) (*gethTypes.Block, error) {
ctx, span := trace.StartSpan(ctx, "beacon-chain.web3service.BlockByNumber")
defer span.End()
if s.eth1DataFetcher == nil {
return nil, errors.New("nil eth1DataFetcher")
}
return s.eth1DataFetcher.BlockByNumber(ctx, number)
}
// Performs a search to find a target eth1 block which is earlier than or equal to the
// target time. This method is used when head.time > targetTime
func (s *Service) findLessTargetEth1Block(ctx context.Context, startBlk *big.Int, targetTime uint64) (*types.HeaderInfo, error) {

View File

@@ -22,7 +22,7 @@ var endpoint = "http://127.0.0.1"
func setDefaultMocks(service *Service) *Service {
service.eth1DataFetcher = &goodFetcher{}
service.httpLogger = &goodLogger{}
service.cfg.stateNotifier = &goodNotifier{}
service.cfg.StateNotifier = &goodNotifier{}
return service
}
@@ -31,11 +31,11 @@ func TestLatestMainchainInfo_OK(t *testing.T) {
require.NoError(t, err, "Unable to set up simulated backend")
beaconDB := dbutil.SetupDB(t)
web3Service, err := NewService(context.Background(),
WithHttpEndpoints([]string{endpoint}),
WithDepositContractAddress(testAcc.ContractAddr),
WithDatabase(beaconDB),
)
web3Service, err := NewService(context.Background(), &Web3ServiceConfig{
HttpEndpoints: []string{endpoint},
DepositContract: testAcc.ContractAddr,
BeaconDB: beaconDB,
})
require.NoError(t, err, "Unable to setup web3 ETH1.0 chain service")
web3Service = setDefaultMocks(web3Service)
@@ -69,10 +69,10 @@ func TestLatestMainchainInfo_OK(t *testing.T) {
func TestBlockHashByHeight_ReturnsHash(t *testing.T) {
beaconDB := dbutil.SetupDB(t)
web3Service, err := NewService(context.Background(),
WithHttpEndpoints([]string{endpoint}),
WithDatabase(beaconDB),
)
web3Service, err := NewService(context.Background(), &Web3ServiceConfig{
HttpEndpoints: []string{endpoint},
BeaconDB: beaconDB,
})
require.NoError(t, err, "unable to setup web3 ETH1.0 chain service")
web3Service = setDefaultMocks(web3Service)
@@ -96,10 +96,10 @@ func TestBlockHashByHeight_ReturnsHash(t *testing.T) {
func TestBlockHashByHeight_ReturnsError_WhenNoEth1Client(t *testing.T) {
beaconDB := dbutil.SetupDB(t)
web3Service, err := NewService(context.Background(),
WithHttpEndpoints([]string{endpoint}),
WithDatabase(beaconDB),
)
web3Service, err := NewService(context.Background(), &Web3ServiceConfig{
HttpEndpoints: []string{endpoint},
BeaconDB: beaconDB,
})
require.NoError(t, err, "unable to setup web3 ETH1.0 chain service")
web3Service = setDefaultMocks(web3Service)
@@ -112,10 +112,10 @@ func TestBlockHashByHeight_ReturnsError_WhenNoEth1Client(t *testing.T) {
func TestBlockExists_ValidHash(t *testing.T) {
beaconDB := dbutil.SetupDB(t)
web3Service, err := NewService(context.Background(),
WithHttpEndpoints([]string{endpoint}),
WithDatabase(beaconDB),
)
web3Service, err := NewService(context.Background(), &Web3ServiceConfig{
HttpEndpoints: []string{endpoint},
BeaconDB: beaconDB,
})
require.NoError(t, err, "unable to setup web3 ETH1.0 chain service")
web3Service = setDefaultMocks(web3Service)
@@ -143,10 +143,10 @@ func TestBlockExists_ValidHash(t *testing.T) {
func TestBlockExists_InvalidHash(t *testing.T) {
beaconDB := dbutil.SetupDB(t)
web3Service, err := NewService(context.Background(),
WithHttpEndpoints([]string{endpoint}),
WithDatabase(beaconDB),
)
web3Service, err := NewService(context.Background(), &Web3ServiceConfig{
HttpEndpoints: []string{endpoint},
BeaconDB: beaconDB,
})
require.NoError(t, err, "unable to setup web3 ETH1.0 chain service")
web3Service = setDefaultMocks(web3Service)
@@ -157,10 +157,10 @@ func TestBlockExists_InvalidHash(t *testing.T) {
func TestBlockExists_UsesCachedBlockInfo(t *testing.T) {
beaconDB := dbutil.SetupDB(t)
web3Service, err := NewService(context.Background(),
WithHttpEndpoints([]string{endpoint}),
WithDatabase(beaconDB),
)
web3Service, err := NewService(context.Background(), &Web3ServiceConfig{
HttpEndpoints: []string{endpoint},
BeaconDB: beaconDB,
})
require.NoError(t, err, "unable to setup web3 ETH1.0 chain service")
// nil eth1DataFetcher would panic if cached value not used
web3Service.eth1DataFetcher = nil
@@ -180,10 +180,10 @@ func TestBlockExists_UsesCachedBlockInfo(t *testing.T) {
func TestBlockExistsWithCache_UsesCachedHeaderInfo(t *testing.T) {
beaconDB := dbutil.SetupDB(t)
web3Service, err := NewService(context.Background(),
WithHttpEndpoints([]string{endpoint}),
WithDatabase(beaconDB),
)
web3Service, err := NewService(context.Background(), &Web3ServiceConfig{
HttpEndpoints: []string{endpoint},
BeaconDB: beaconDB,
})
require.NoError(t, err, "unable to setup web3 ETH1.0 chain service")
header := &gethTypes.Header{
@@ -201,10 +201,10 @@ func TestBlockExistsWithCache_UsesCachedHeaderInfo(t *testing.T) {
func TestBlockExistsWithCache_HeaderNotCached(t *testing.T) {
beaconDB := dbutil.SetupDB(t)
web3Service, err := NewService(context.Background(),
WithHttpEndpoints([]string{endpoint}),
WithDatabase(beaconDB),
)
web3Service, err := NewService(context.Background(), &Web3ServiceConfig{
HttpEndpoints: []string{endpoint},
BeaconDB: beaconDB,
})
require.NoError(t, err, "unable to setup web3 ETH1.0 chain service")
exists, height, err := web3Service.BlockExistsWithCache(context.Background(), common.BytesToHash([]byte("hash")))
@@ -217,10 +217,10 @@ func TestService_BlockNumberByTimestamp(t *testing.T) {
beaconDB := dbutil.SetupDB(t)
testAcc, err := contracts.Setup()
require.NoError(t, err, "Unable to set up simulated backend")
web3Service, err := NewService(context.Background(),
WithHttpEndpoints([]string{endpoint}),
WithDatabase(beaconDB),
)
web3Service, err := NewService(context.Background(), &Web3ServiceConfig{
HttpEndpoints: []string{endpoint},
BeaconDB: beaconDB,
})
require.NoError(t, err)
web3Service = setDefaultMocks(web3Service)
web3Service.eth1DataFetcher = &goodFetcher{backend: testAcc.Backend}
@@ -244,10 +244,10 @@ func TestService_BlockNumberByTimestampLessTargetTime(t *testing.T) {
beaconDB := dbutil.SetupDB(t)
testAcc, err := contracts.Setup()
require.NoError(t, err, "Unable to set up simulated backend")
web3Service, err := NewService(context.Background(),
WithHttpEndpoints([]string{endpoint}),
WithDatabase(beaconDB),
)
web3Service, err := NewService(context.Background(), &Web3ServiceConfig{
HttpEndpoints: []string{endpoint},
BeaconDB: beaconDB,
})
require.NoError(t, err)
web3Service = setDefaultMocks(web3Service)
web3Service.eth1DataFetcher = &goodFetcher{backend: testAcc.Backend}
@@ -277,10 +277,10 @@ func TestService_BlockNumberByTimestampMoreTargetTime(t *testing.T) {
beaconDB := dbutil.SetupDB(t)
testAcc, err := contracts.Setup()
require.NoError(t, err, "Unable to set up simulated backend")
web3Service, err := NewService(context.Background(),
WithHttpEndpoints([]string{endpoint}),
WithDatabase(beaconDB),
)
web3Service, err := NewService(context.Background(), &Web3ServiceConfig{
HttpEndpoints: []string{endpoint},
BeaconDB: beaconDB,
})
require.NoError(t, err)
web3Service = setDefaultMocks(web3Service)
web3Service.eth1DataFetcher = &goodFetcher{backend: testAcc.Backend}
@@ -308,10 +308,10 @@ func TestService_BlockNumberByTimestampMoreTargetTime(t *testing.T) {
func TestService_BlockTimeByHeight_ReturnsError_WhenNoEth1Client(t *testing.T) {
beaconDB := dbutil.SetupDB(t)
web3Service, err := NewService(context.Background(),
WithHttpEndpoints([]string{endpoint}),
WithDatabase(beaconDB),
)
web3Service, err := NewService(context.Background(), &Web3ServiceConfig{
HttpEndpoints: []string{endpoint},
BeaconDB: beaconDB,
})
require.NoError(t, err, "unable to setup web3 ETH1.0 chain service")
web3Service = setDefaultMocks(web3Service)

View File

@@ -3,26 +3,11 @@ package powchain
import (
"context"
"github.com/ethereum/go-ethereum/common"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
"github.com/prysmaticlabs/prysm/config/params"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
)
// DepositContractAddress returns the deposit contract address for the given chain.
func DepositContractAddress() (string, error) {
address := params.BeaconConfig().DepositContractAddress
if address == "" {
return "", errors.New("valid deposit contract is required")
}
if !common.IsHexAddress(address) {
return "", errors.New("invalid deposit contract address given: " + address)
}
return address, nil
}
func (s *Service) processDeposit(ctx context.Context, eth1Data *ethpb.Eth1Data, deposit *ethpb.Deposit) error {
var err error
if err := s.preGenesisState.SetEth1Data(eth1Data); err != nil {

View File

@@ -22,39 +22,12 @@ import (
const pubKeyErr = "could not convert bytes to public key"
func TestDepositContractAddress_EmptyAddress(t *testing.T) {
params.SetupTestConfigCleanup(t)
config := params.BeaconConfig()
config.DepositContractAddress = ""
params.OverrideBeaconConfig(config)
_, err := DepositContractAddress()
assert.ErrorContains(t, "valid deposit contract is required", err)
}
func TestDepositContractAddress_NotHexAddress(t *testing.T) {
params.SetupTestConfigCleanup(t)
config := params.BeaconConfig()
config.DepositContractAddress = "abc?!"
params.OverrideBeaconConfig(config)
_, err := DepositContractAddress()
assert.ErrorContains(t, "invalid deposit contract address given", err)
}
func TestDepositContractAddress_OK(t *testing.T) {
params.SetupTestConfigCleanup(t)
addr, err := DepositContractAddress()
require.NoError(t, err)
assert.Equal(t, params.BeaconConfig().DepositContractAddress, addr)
}
func TestProcessDeposit_OK(t *testing.T) {
beaconDB := testDB.SetupDB(t)
web3Service, err := NewService(context.Background(),
WithHttpEndpoints([]string{endpoint}),
WithDatabase(beaconDB),
)
web3Service, err := NewService(context.Background(), &Web3ServiceConfig{
HttpEndpoints: []string{endpoint},
BeaconDB: beaconDB,
})
require.NoError(t, err, "Unable to setup web3 ETH1.0 chain service")
web3Service = setDefaultMocks(web3Service)
@@ -75,10 +48,10 @@ func TestProcessDeposit_OK(t *testing.T) {
func TestProcessDeposit_InvalidMerkleBranch(t *testing.T) {
beaconDB := testDB.SetupDB(t)
web3Service, err := NewService(context.Background(),
WithHttpEndpoints([]string{endpoint}),
WithDatabase(beaconDB),
)
web3Service, err := NewService(context.Background(), &Web3ServiceConfig{
HttpEndpoints: []string{endpoint},
BeaconDB: beaconDB,
})
require.NoError(t, err, "unable to setup web3 ETH1.0 chain service")
web3Service = setDefaultMocks(web3Service)
@@ -101,10 +74,10 @@ func TestProcessDeposit_InvalidMerkleBranch(t *testing.T) {
func TestProcessDeposit_InvalidPublicKey(t *testing.T) {
hook := logTest.NewGlobal()
beaconDB := testDB.SetupDB(t)
web3Service, err := NewService(context.Background(),
WithHttpEndpoints([]string{endpoint}),
WithDatabase(beaconDB),
)
web3Service, err := NewService(context.Background(), &Web3ServiceConfig{
HttpEndpoints: []string{endpoint},
BeaconDB: beaconDB,
})
require.NoError(t, err, "unable to setup web3 ETH1.0 chain service")
web3Service = setDefaultMocks(web3Service)
@@ -137,10 +110,10 @@ func TestProcessDeposit_InvalidPublicKey(t *testing.T) {
func TestProcessDeposit_InvalidSignature(t *testing.T) {
hook := logTest.NewGlobal()
beaconDB := testDB.SetupDB(t)
web3Service, err := NewService(context.Background(),
WithHttpEndpoints([]string{endpoint}),
WithDatabase(beaconDB),
)
web3Service, err := NewService(context.Background(), &Web3ServiceConfig{
HttpEndpoints: []string{endpoint},
BeaconDB: beaconDB,
})
require.NoError(t, err, "unable to setup web3 ETH1.0 chain service")
web3Service = setDefaultMocks(web3Service)
@@ -172,10 +145,10 @@ func TestProcessDeposit_InvalidSignature(t *testing.T) {
func TestProcessDeposit_UnableToVerify(t *testing.T) {
hook := logTest.NewGlobal()
beaconDB := testDB.SetupDB(t)
web3Service, err := NewService(context.Background(),
WithHttpEndpoints([]string{endpoint}),
WithDatabase(beaconDB),
)
web3Service, err := NewService(context.Background(), &Web3ServiceConfig{
HttpEndpoints: []string{endpoint},
BeaconDB: beaconDB,
})
require.NoError(t, err, "unable to setup web3 ETH1.0 chain service")
web3Service = setDefaultMocks(web3Service)
@@ -204,10 +177,10 @@ func TestProcessDeposit_UnableToVerify(t *testing.T) {
func TestProcessDeposit_IncompleteDeposit(t *testing.T) {
beaconDB := testDB.SetupDB(t)
web3Service, err := NewService(context.Background(),
WithHttpEndpoints([]string{endpoint}),
WithDatabase(beaconDB),
)
web3Service, err := NewService(context.Background(), &Web3ServiceConfig{
HttpEndpoints: []string{endpoint},
BeaconDB: beaconDB,
})
require.NoError(t, err, "unable to setup web3 ETH1.0 chain service")
web3Service = setDefaultMocks(web3Service)
require.NoError(t, web3Service.preGenesisState.SetValidators([]*ethpb.Validator{}))
@@ -266,10 +239,10 @@ func TestProcessDeposit_IncompleteDeposit(t *testing.T) {
func TestProcessDeposit_AllDepositedSuccessfully(t *testing.T) {
beaconDB := testDB.SetupDB(t)
web3Service, err := NewService(context.Background(),
WithHttpEndpoints([]string{endpoint}),
WithDatabase(beaconDB),
)
web3Service, err := NewService(context.Background(), &Web3ServiceConfig{
HttpEndpoints: []string{endpoint},
BeaconDB: beaconDB,
})
require.NoError(t, err, "unable to setup web3 ETH1.0 chain service")
web3Service = setDefaultMocks(web3Service)

View File

@@ -0,0 +1,386 @@
package powchain
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/eth/catalyst"
"github.com/pkg/errors"
)
var errNoExecutionEngineConnection = errors.New("can't connect to execution engine")
var errInvalidPayload = errors.New("invalid payload")
var errSyncing = errors.New("syncing")
// ExecutionEngineCaller defines methods that wraps around execution engine API calls to enable other prysm services to interact with.
type ExecutionEngineCaller interface {
// PreparePayload is a wrapper on top of `CatalystClient` to abstract out `types.AssembleBlockParams`.
PreparePayload(ctx context.Context, forkchoiceState catalyst.ForkchoiceStateV1, payloadAttributes catalyst.PayloadAttributesV1) (uint64, error)
// GetPayload is a wrapper on top of `CatalystClient`.
GetPayload(ctx context.Context, payloadID uint64) (*catalyst.ExecutableDataV1, error)
// NotifyForkChoiceValidated is the wrapper on top of `CatalystClient` to abstract out `types.ConsensusValidatedParams`.
NotifyForkChoiceValidated(ctx context.Context, forkchoiceState catalyst.ForkchoiceStateV1) error
// ExecutePayload is the wrapper on top of `CatalystClient` to abstract out `types.ForkChoiceParams`.
ExecutePayload(ctx context.Context, data *catalyst.ExecutableDataV1) ([]byte, error)
// LatestExecutionBlock returns the latest execution block of the pow chain.
LatestExecutionBlock() (*ExecutionBlock, error)
// ExecutionBlockByHash returns the execution block of a given block hash.
ExecutionBlockByHash(blockHash common.Hash) (*ExecutionBlock, error)
}
type EngineRequest struct {
JsonRPC string `json:"jsonrpc"`
Method string `json:"method"`
Params []interface{} `json:"params"`
Id int `json:"id"`
}
type ErrorRespond struct {
Code int `json:"code"`
Message string `json:"message"`
}
type GetPayloadRespond struct {
JsonRPC string `json:"jsonrpc"`
ExecutableData *catalyst.ExecutableDataV1 `json:"result"`
Id int `json:"id"`
Error ErrorRespond `json:"error"`
}
type PreparePayloadRespond struct {
JsonRPC string `json:"jsonrpc"`
Result PayloadIDRespond `json:"result"`
Id int `json:"id"`
}
type PayloadIDRespond struct {
PayloadID string `json:"payloadId"`
}
type ForkchoiceUpdatedRespond struct {
JsonRPC string `json:"jsonrpc"`
Result ForkchoiceUpdatedResult `json:"result"`
Id int `json:"id"`
Error ErrorRespond `json:"error"`
}
type ForkchoiceUpdatedResult struct {
Status string `json:"status"`
PayloadID string `json:"payloadId"`
}
type ExecutePayloadRespond struct {
JsonRPC string `json:"jsonrpc"`
Result ExecutePayloadResult `json:"result"`
Id int `json:"id"`
Error ErrorRespond `json:"error"`
}
type ExecutePayloadResult struct {
Status string `json:"status"`
LatestValidHash string `json:"latestValidHash"`
Message string `json:"message"`
}
type ExecutionBlockRespond struct {
JsonRPC string `json:"jsonrpc"`
Result *ExecutionBlock `json:"result"`
Id int `json:"id"`
}
type ExecutionBlock struct {
ParentHash string `json:"parentHash"`
Sha3Uncles string `json:"sha3Uncles"`
Miner string `json:"miner"`
StateRoot string `json:"stateRoot"`
TransactionsRoot string `json:"transactionsRoot"`
ReceiptsRoot string `json:"receiptsRoot"`
LogsBloom string `json:"logsBloom"`
Difficulty string `json:"difficulty"`
Number string `json:"number"`
GasLimit string `json:"gasLimit"`
GasUsed string `json:"gasUsed"`
Timestamp string `json:"timestamp"`
ExtraData string `json:"extraData"`
MixHash string `json:"mixHash"`
Nonce string `json:"nonce"`
TotalDifficulty string `json:"totalDifficulty"`
BaseFeePerGas string `json:"baseFeePerGas"`
Size string `json:"size"`
Hash string `json:"hash"`
Transactions []string `json:"transactions"`
Uncles []string `json:"uncles"`
}
//GetPayload returns the most recent version of the execution payload that has been built since the corresponding
//call to `PreparePayload` method. It returns the `ExecutionPayload` object.
//Engine API definition:
// https://github.com/ethereum/execution-apis/blob/main/src/engine/specification.md#engine_getpayloadv1
func (s *Service) GetPayload(ctx context.Context, payloadID uint64) (*catalyst.ExecutableDataV1, error) {
reqBody := &EngineRequest{
JsonRPC: "2.0",
Method: "engine_getPayloadV1",
Params: []interface{}{hexutil.EncodeUint64(payloadID)},
}
enc, err := json.Marshal(reqBody)
if err != nil {
return nil, err
}
req, err := http.NewRequest("POST", s.currHttpEndpoint.Url, bytes.NewBuffer(enc))
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
res, err := client.Do(req)
if err != nil {
return nil, err
}
defer func() {
if err := res.Body.Close(); err != nil {
panic(err)
}
}()
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return nil, err
}
var respond GetPayloadRespond
if err := json.Unmarshal(body, &respond); err != nil {
return nil, err
}
if respond.Error.Code != 0 {
return nil, fmt.Errorf("could not call engine_getPayloadV1, code: %d, message: %s", respond.Error.Code, respond.Error.Message)
}
return respond.ExecutableData, nil
}
// ExecutePayload executes execution payload by calling execution engine.
// Engine API definition:
// https://github.com/ethereum/execution-apis/blob/main/src/engine/specification.md#engine_executepayloadv1
func (s *Service) ExecutePayload(ctx context.Context, data *catalyst.ExecutableDataV1) ([]byte, error) {
reqBody := &EngineRequest{
JsonRPC: "2.0",
Method: "engine_executePayloadV1",
Params: []interface{}{data},
}
enc, err := json.Marshal(reqBody)
if err != nil {
return nil, err
}
req, err := http.NewRequest("POST", s.currHttpEndpoint.Url, bytes.NewBuffer(enc))
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
res, err := client.Do(req)
if err != nil {
return nil, err
}
defer func() {
if err := res.Body.Close(); err != nil {
panic(err)
}
}()
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return nil, err
}
var respond ExecutePayloadRespond
if err := json.Unmarshal(body, &respond); err != nil {
return nil, err
}
if respond.Error.Code != 0 {
return nil, fmt.Errorf("could not call engine_executePayloadV1, code: %d, message: %s", respond.Error.Code, respond.Error.Message)
}
if respond.Result.Status == catalyst.INVALID.Status {
return common.FromHex(respond.Result.LatestValidHash), errInvalidPayload
}
if respond.Result.Status == catalyst.SYNCING.Status {
return common.FromHex(respond.Result.LatestValidHash), errSyncing
}
return common.FromHex(respond.Result.LatestValidHash), nil
}
// NotifyForkChoiceValidated notifies execution engine on fork choice updates.
// Engine API definition:
// https://github.com/ethereum/execution-apis/blob/main/src/engine/specification.md#engine_forkchoiceupdatedv1
func (s *Service) NotifyForkChoiceValidated(ctx context.Context, forkchoiceState catalyst.ForkchoiceStateV1) error {
reqBody := &EngineRequest{
JsonRPC: "2.0",
Method: "engine_forkchoiceUpdatedV1",
Params: []interface{}{forkchoiceState, nil},
}
enc, err := json.Marshal(reqBody)
if err != nil {
return err
}
req, err := http.NewRequest("POST", s.currHttpEndpoint.Url, bytes.NewBuffer(enc))
if err != nil {
return err
}
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
res, err := client.Do(req)
if err != nil {
return err
}
defer func() {
if err := res.Body.Close(); err != nil {
panic(err)
}
}()
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return err
}
var respond ForkchoiceUpdatedRespond
if err := json.Unmarshal(body, &respond); err != nil {
return err
}
if respond.Error.Code != 0 {
return fmt.Errorf("could not call engine_forkchoiceUpdatedV1, code: %d, message: %s", respond.Error.Code, respond.Error.Message)
}
if respond.Result.Status == catalyst.SYNCING.Status {
return errSyncing
}
return nil
}
// PreparePayload signals execution engine to prepare execution payload along with the latest fork choice state.
// It reuses `engine_forkchoiceUpdatedV1` end point to prepare payload.
// Engine API definition:
// https://github.com/ethereum/execution-apis/blob/main/src/engine/specification.md#engine_forkchoiceupdatedv1
func (s *Service) PreparePayload(ctx context.Context, forkchoiceState catalyst.ForkchoiceStateV1, payloadAttributes catalyst.PayloadAttributesV1) (uint64, error) {
reqBody := &EngineRequest{
JsonRPC: "2.0",
Method: "engine_forkchoiceUpdatedV1",
Params: []interface{}{forkchoiceState, payloadAttributes},
}
enc, err := json.Marshal(reqBody)
if err != nil {
return 0, err
}
req, err := http.NewRequest("POST", s.currHttpEndpoint.Url, bytes.NewBuffer(enc))
if err != nil {
return 0, err
}
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
res, err := client.Do(req)
if err != nil {
return 0, err
}
defer func() {
if err := res.Body.Close(); err != nil {
panic(err)
}
}()
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return 0, err
}
var respond ForkchoiceUpdatedRespond
if err := json.Unmarshal(body, &respond); err != nil {
return 0, err
}
if respond.Error.Code != 0 {
return 0, fmt.Errorf("could not call engine_forkchoiceUpdatedV1, code: %d, message: %s", respond.Error.Code, respond.Error.Message)
}
if respond.Result.Status == catalyst.SYNCING.Status {
return 0, errSyncing
}
id, ok := math.ParseUint64(respond.Result.PayloadID)
if !ok {
return 0, errors.New("could not parse hex to uint64")
}
return id, nil
}
func (s *Service) LatestExecutionBlock() (*ExecutionBlock, error) {
reqBody := &EngineRequest{
JsonRPC: "2.0",
Method: "eth_getBlockByNumber",
Params: []interface{}{"latest", false},
}
enc, err := json.Marshal(reqBody)
if err != nil {
return nil, err
}
req, err := http.NewRequest("GET", s.currHttpEndpoint.Url, bytes.NewBuffer(enc))
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
res, err := client.Do(req)
if err != nil {
return nil, err
}
defer func() {
if err := res.Body.Close(); err != nil {
panic(err)
}
}()
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return nil, err
}
var data ExecutionBlockRespond
if err := json.Unmarshal(body, &data); err != nil {
return nil, err
}
return data.Result, nil
}
func (s *Service) ExecutionBlockByHash(blockHash common.Hash) (*ExecutionBlock, error) {
reqBody := &EngineRequest{
JsonRPC: "2.0",
Method: "eth_getBlockByHash",
Params: []interface{}{blockHash.String(), false},
}
enc, err := json.Marshal(reqBody)
if err != nil {
return nil, err
}
req, err := http.NewRequest("GET", s.currHttpEndpoint.Url, bytes.NewBuffer(enc))
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
res, err := client.Do(req)
if err != nil {
return nil, err
}
defer func() {
if err := res.Body.Close(); err != nil {
panic(err)
}
}()
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return nil, err
}
var data ExecutionBlockRespond
if err := json.Unmarshal(body, &data); err != nil {
return nil, err
}
return data.Result, nil
}

View File

@@ -52,7 +52,7 @@ func (s *Service) Eth2GenesisPowchainInfo() (uint64, *big.Int) {
func (s *Service) ProcessETH1Block(ctx context.Context, blkNum *big.Int) error {
query := ethereum.FilterQuery{
Addresses: []common.Address{
s.cfg.depositContractAddr,
s.cfg.DepositContract,
},
FromBlock: blkNum,
ToBlock: blkNum,
@@ -155,7 +155,7 @@ func (s *Service) ProcessDepositLog(ctx context.Context, depositLog gethTypes.Lo
}
// We always store all historical deposits in the DB.
err = s.cfg.depositCache.InsertDeposit(ctx, deposit, depositLog.BlockNumber, index, s.depositTrie.HashTreeRoot())
err = s.cfg.DepositCache.InsertDeposit(ctx, deposit, depositLog.BlockNumber, index, s.depositTrie.HashTreeRoot())
if err != nil {
return errors.Wrap(err, "unable to insert deposit into cache")
}
@@ -172,7 +172,7 @@ func (s *Service) ProcessDepositLog(ctx context.Context, depositLog gethTypes.Lo
validData = false
}
} else {
s.cfg.depositCache.InsertPendingDeposit(ctx, deposit, depositLog.BlockNumber, index, s.depositTrie.HashTreeRoot())
s.cfg.DepositCache.InsertPendingDeposit(ctx, deposit, depositLog.BlockNumber, index, s.depositTrie.HashTreeRoot())
}
if validData {
log.WithFields(logrus.Fields{
@@ -231,7 +231,7 @@ func (s *Service) ProcessChainStart(genesisTime uint64, eth1BlockHash [32]byte,
log.WithFields(logrus.Fields{
"ChainStartTime": chainStartTime,
}).Info("Minimum number of validators reached for beacon-chain to start")
s.cfg.stateNotifier.StateFeed().Send(&feed.Event{
s.cfg.StateNotifier.StateFeed().Send(&feed.Event{
Type: statefeed.ChainStarted,
Data: &statefeed.ChainStartedData{
StartTime: chainStartTime,
@@ -288,7 +288,7 @@ func (s *Service) processPastLogs(ctx context.Context) error {
return err
}
batchSize := s.cfg.eth1HeaderReqLimit
batchSize := s.cfg.Eth1HeaderReqLimit
additiveFactor := uint64(float64(batchSize) * additiveFactorMultiplier)
for currentBlockNum < latestFollowHeight {
@@ -301,7 +301,7 @@ func (s *Service) processPastLogs(ctx context.Context) error {
}
query := ethereum.FilterQuery{
Addresses: []common.Address{
s.cfg.depositContractAddr,
s.cfg.DepositContract,
},
FromBlock: big.NewInt(int64(start)),
ToBlock: big.NewInt(int64(end)),
@@ -354,18 +354,18 @@ func (s *Service) processPastLogs(ctx context.Context) error {
}
currentBlockNum = end
if batchSize < s.cfg.eth1HeaderReqLimit {
if batchSize < s.cfg.Eth1HeaderReqLimit {
// update the batchSize with additive increase
batchSize += additiveFactor
if batchSize > s.cfg.eth1HeaderReqLimit {
batchSize = s.cfg.eth1HeaderReqLimit
if batchSize > s.cfg.Eth1HeaderReqLimit {
batchSize = s.cfg.Eth1HeaderReqLimit
}
}
}
s.latestEth1Data.LastRequestedBlock = currentBlockNum
c, err := s.cfg.beaconDB.FinalizedCheckpoint(ctx)
c, err := s.cfg.BeaconDB.FinalizedCheckpoint(ctx)
if err != nil {
return err
}
@@ -374,12 +374,12 @@ func (s *Service) processPastLogs(ctx context.Context) error {
if fRoot == params.BeaconConfig().ZeroHash {
return nil
}
fState, err := s.cfg.stateGen.StateByRoot(ctx, fRoot)
fState, err := s.cfg.StateGen.StateByRoot(ctx, fRoot)
if err != nil {
return err
}
if fState != nil && !fState.IsNil() && fState.Eth1DepositIndex() > 0 {
s.cfg.depositCache.PrunePendingDeposits(ctx, int64(fState.Eth1DepositIndex()))
s.cfg.DepositCache.PrunePendingDeposits(ctx, int64(fState.Eth1DepositIndex()))
}
return nil
}
@@ -500,7 +500,7 @@ func (s *Service) savePowchainData(ctx context.Context) error {
ChainstartData: s.chainStartData,
BeaconState: pbState, // I promise not to mutate it!
Trie: s.depositTrie.ToProto(),
DepositContainers: s.cfg.depositCache.AllDepositContainers(ctx),
DepositContainers: s.cfg.DepositCache.AllDepositContainers(ctx),
}
return s.cfg.beaconDB.SavePowchainData(ctx, eth1Data)
return s.cfg.BeaconDB.SavePowchainData(ctx, eth1Data)
}

View File

@@ -33,12 +33,12 @@ func TestProcessDepositLog_OK(t *testing.T) {
depositCache, err := depositcache.New()
require.NoError(t, err)
web3Service, err := NewService(context.Background(),
WithHttpEndpoints([]string{endpoint}),
WithDepositContractAddress(testAcc.ContractAddr),
WithDatabase(beaconDB),
WithDepositCache(depositCache),
)
web3Service, err := NewService(context.Background(), &Web3ServiceConfig{
HttpEndpoints: []string{endpoint},
DepositContract: testAcc.ContractAddr,
BeaconDB: beaconDB,
DepositCache: depositCache,
})
require.NoError(t, err, "unable to setup web3 ETH1.0 chain service")
web3Service = setDefaultMocks(web3Service)
web3Service.depositContractCaller, err = contracts.NewDepositContractCaller(testAcc.ContractAddr, testAcc.Backend)
@@ -62,7 +62,7 @@ func TestProcessDepositLog_OK(t *testing.T) {
query := ethereum.FilterQuery{
Addresses: []common.Address{
web3Service.cfg.depositContractAddr,
web3Service.cfg.DepositContract,
},
}
@@ -97,12 +97,12 @@ func TestProcessDepositLog_InsertsPendingDeposit(t *testing.T) {
depositCache, err := depositcache.New()
require.NoError(t, err)
web3Service, err := NewService(context.Background(),
WithHttpEndpoints([]string{endpoint}),
WithDepositContractAddress(testAcc.ContractAddr),
WithDatabase(beaconDB),
WithDepositCache(depositCache),
)
web3Service, err := NewService(context.Background(), &Web3ServiceConfig{
HttpEndpoints: []string{endpoint},
DepositContract: testAcc.ContractAddr,
BeaconDB: beaconDB,
DepositCache: depositCache,
})
require.NoError(t, err, "unable to setup web3 ETH1.0 chain service")
web3Service = setDefaultMocks(web3Service)
web3Service.depositContractCaller, err = contracts.NewDepositContractCaller(testAcc.ContractAddr, testAcc.Backend)
@@ -129,7 +129,7 @@ func TestProcessDepositLog_InsertsPendingDeposit(t *testing.T) {
query := ethereum.FilterQuery{
Addresses: []common.Address{
web3Service.cfg.depositContractAddr,
web3Service.cfg.DepositContract,
},
}
@@ -143,7 +143,7 @@ func TestProcessDepositLog_InsertsPendingDeposit(t *testing.T) {
err = web3Service.ProcessDepositLog(context.Background(), logs[1])
require.NoError(t, err)
pendingDeposits := web3Service.cfg.depositCache.PendingDeposits(context.Background(), nil /*blockNum*/)
pendingDeposits := web3Service.cfg.DepositCache.PendingDeposits(context.Background(), nil /*blockNum*/)
require.Equal(t, 2, len(pendingDeposits), "Unexpected number of deposits")
hook.Reset()
@@ -153,11 +153,11 @@ func TestUnpackDepositLogData_OK(t *testing.T) {
testAcc, err := contracts.Setup()
require.NoError(t, err, "Unable to set up simulated backend")
beaconDB := testDB.SetupDB(t)
web3Service, err := NewService(context.Background(),
WithHttpEndpoints([]string{endpoint}),
WithDepositContractAddress(testAcc.ContractAddr),
WithDatabase(beaconDB),
)
web3Service, err := NewService(context.Background(), &Web3ServiceConfig{
HttpEndpoints: []string{endpoint},
BeaconDB: beaconDB,
DepositContract: testAcc.ContractAddr,
})
require.NoError(t, err, "unable to setup web3 ETH1.0 chain service")
web3Service = setDefaultMocks(web3Service)
web3Service.depositContractCaller, err = contracts.NewDepositContractCaller(testAcc.ContractAddr, testAcc.Backend)
@@ -179,7 +179,7 @@ func TestUnpackDepositLogData_OK(t *testing.T) {
query := ethereum.FilterQuery{
Addresses: []common.Address{
web3Service.cfg.depositContractAddr,
web3Service.cfg.DepositContract,
},
}
@@ -203,12 +203,12 @@ func TestProcessETH2GenesisLog_8DuplicatePubkeys(t *testing.T) {
depositCache, err := depositcache.New()
require.NoError(t, err)
web3Service, err := NewService(context.Background(),
WithHttpEndpoints([]string{endpoint}),
WithDepositContractAddress(testAcc.ContractAddr),
WithDatabase(beaconDB),
WithDepositCache(depositCache),
)
web3Service, err := NewService(context.Background(), &Web3ServiceConfig{
HttpEndpoints: []string{endpoint},
DepositContract: testAcc.ContractAddr,
BeaconDB: beaconDB,
DepositCache: depositCache,
})
require.NoError(t, err, "unable to setup web3 ETH1.0 chain service")
web3Service = setDefaultMocks(web3Service)
web3Service.depositContractCaller, err = contracts.NewDepositContractCaller(testAcc.ContractAddr, testAcc.Backend)
@@ -244,7 +244,7 @@ func TestProcessETH2GenesisLog_8DuplicatePubkeys(t *testing.T) {
query := ethereum.FilterQuery{
Addresses: []common.Address{
web3Service.cfg.depositContractAddr,
web3Service.cfg.DepositContract,
},
}
@@ -273,12 +273,12 @@ func TestProcessETH2GenesisLog(t *testing.T) {
depositCache, err := depositcache.New()
require.NoError(t, err)
web3Service, err := NewService(context.Background(),
WithHttpEndpoints([]string{endpoint}),
WithDepositContractAddress(testAcc.ContractAddr),
WithDatabase(beaconDB),
WithDepositCache(depositCache),
)
web3Service, err := NewService(context.Background(), &Web3ServiceConfig{
HttpEndpoints: []string{endpoint},
DepositContract: testAcc.ContractAddr,
BeaconDB: beaconDB,
DepositCache: depositCache,
})
require.NoError(t, err, "unable to setup web3 ETH1.0 chain service")
web3Service = setDefaultMocks(web3Service)
web3Service.depositContractCaller, err = contracts.NewDepositContractCaller(testAcc.ContractAddr, testAcc.Backend)
@@ -311,7 +311,7 @@ func TestProcessETH2GenesisLog(t *testing.T) {
query := ethereum.FilterQuery{
Addresses: []common.Address{
web3Service.cfg.depositContractAddr,
web3Service.cfg.DepositContract,
},
}
@@ -321,7 +321,7 @@ func TestProcessETH2GenesisLog(t *testing.T) {
// Set up our subscriber now to listen for the chain started event.
stateChannel := make(chan *feed.Event, 1)
stateSub := web3Service.cfg.stateNotifier.StateFeed().Subscribe(stateChannel)
stateSub := web3Service.cfg.StateNotifier.StateFeed().Subscribe(stateChannel)
defer stateSub.Unsubscribe()
for _, log := range logs {
@@ -359,12 +359,12 @@ func TestProcessETH2GenesisLog_CorrectNumOfDeposits(t *testing.T) {
depositCache, err := depositcache.New()
require.NoError(t, err)
web3Service, err := NewService(context.Background(),
WithHttpEndpoints([]string{endpoint}),
WithDepositContractAddress(testAcc.ContractAddr),
WithDatabase(kvStore),
WithDepositCache(depositCache),
)
web3Service, err := NewService(context.Background(), &Web3ServiceConfig{
HttpEndpoints: []string{endpoint},
DepositContract: testAcc.ContractAddr,
BeaconDB: kvStore,
DepositCache: depositCache,
})
require.NoError(t, err, "unable to setup web3 ETH1.0 chain service")
web3Service = setDefaultMocks(web3Service)
web3Service.depositContractCaller, err = contracts.NewDepositContractCaller(testAcc.ContractAddr, testAcc.Backend)
@@ -418,7 +418,7 @@ func TestProcessETH2GenesisLog_CorrectNumOfDeposits(t *testing.T) {
// Set up our subscriber now to listen for the chain started event.
stateChannel := make(chan *feed.Event, 1)
stateSub := web3Service.cfg.stateNotifier.StateFeed().Subscribe(stateChannel)
stateSub := web3Service.cfg.StateNotifier.StateFeed().Subscribe(stateChannel)
defer stateSub.Unsubscribe()
err = web3Service.processPastLogs(context.Background())
@@ -452,12 +452,12 @@ func TestProcessETH2GenesisLog_LargePeriodOfNoLogs(t *testing.T) {
depositCache, err := depositcache.New()
require.NoError(t, err)
web3Service, err := NewService(context.Background(),
WithHttpEndpoints([]string{endpoint}),
WithDepositContractAddress(testAcc.ContractAddr),
WithDatabase(kvStore),
WithDepositCache(depositCache),
)
web3Service, err := NewService(context.Background(), &Web3ServiceConfig{
HttpEndpoints: []string{endpoint},
DepositContract: testAcc.ContractAddr,
BeaconDB: kvStore,
DepositCache: depositCache,
})
require.NoError(t, err, "unable to setup web3 ETH1.0 chain service")
web3Service = setDefaultMocks(web3Service)
web3Service.depositContractCaller, err = contracts.NewDepositContractCaller(testAcc.ContractAddr, testAcc.Backend)
@@ -522,7 +522,7 @@ func TestProcessETH2GenesisLog_LargePeriodOfNoLogs(t *testing.T) {
// Set up our subscriber now to listen for the chain started event.
stateChannel := make(chan *feed.Event, 1)
stateSub := web3Service.cfg.stateNotifier.StateFeed().Subscribe(stateChannel)
stateSub := web3Service.cfg.StateNotifier.StateFeed().Subscribe(stateChannel)
defer stateSub.Unsubscribe()
err = web3Service.processPastLogs(context.Background())
@@ -560,12 +560,13 @@ func TestCheckForChainstart_NoValidator(t *testing.T) {
func newPowchainService(t *testing.T, eth1Backend *contracts.TestAccount, beaconDB db.Database) *Service {
depositCache, err := depositcache.New()
require.NoError(t, err)
web3Service, err := NewService(context.Background(),
WithHttpEndpoints([]string{endpoint}),
WithDepositContractAddress(eth1Backend.ContractAddr),
WithDatabase(beaconDB),
WithDepositCache(depositCache),
)
web3Service, err := NewService(context.Background(), &Web3ServiceConfig{
HttpEndpoints: []string{endpoint},
DepositContract: eth1Backend.ContractAddr,
BeaconDB: beaconDB,
DepositCache: depositCache,
})
require.NoError(t, err, "unable to setup web3 ETH1.0 chain service")
web3Service = setDefaultMocks(web3Service)
web3Service.depositContractCaller, err = contracts.NewDepositContractCaller(eth1Backend.ContractAddr, eth1Backend.Backend)

View File

@@ -1,97 +0,0 @@
package powchain
import (
"github.com/ethereum/go-ethereum/common"
"github.com/prysmaticlabs/prysm/beacon-chain/cache/depositcache"
statefeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/state"
"github.com/prysmaticlabs/prysm/beacon-chain/db"
"github.com/prysmaticlabs/prysm/beacon-chain/state"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stategen"
"github.com/prysmaticlabs/prysm/network"
)
type Option func(s *Service) error
// WithHttpEndpoints deduplicates and parses http endpoints for the powchain service to use,
// and sets the "current" endpoint that will be used first.
func WithHttpEndpoints(endpointStrings []string) Option {
return func(s *Service) error {
stringEndpoints := dedupEndpoints(endpointStrings)
endpoints := make([]network.Endpoint, len(stringEndpoints))
for i, e := range stringEndpoints {
endpoints[i] = HttpEndpoint(e)
}
// Select first http endpoint in the provided list.
var currEndpoint network.Endpoint
if len(endpointStrings) > 0 {
currEndpoint = endpoints[0]
}
s.cfg.httpEndpoints = endpoints
s.cfg.currHttpEndpoint = currEndpoint
return nil
}
}
// WithDepositContractAddress for the deposit contract.
func WithDepositContractAddress(addr common.Address) Option {
return func(s *Service) error {
s.cfg.depositContractAddr = addr
return nil
}
}
// WithDatabase for the beacon chain database.
func WithDatabase(database db.HeadAccessDatabase) Option {
return func(s *Service) error {
s.cfg.beaconDB = database
return nil
}
}
// WithDepositCache for caching deposits.
func WithDepositCache(cache *depositcache.DepositCache) Option {
return func(s *Service) error {
s.cfg.depositCache = cache
return nil
}
}
// WithStateNotifier for subscribing to state changes.
func WithStateNotifier(notifier statefeed.Notifier) Option {
return func(s *Service) error {
s.cfg.stateNotifier = notifier
return nil
}
}
// WithStateGen to regenerate beacon states from checkpoints.
func WithStateGen(gen *stategen.State) Option {
return func(s *Service) error {
s.cfg.stateGen = gen
return nil
}
}
// WithEth1HeaderRequestLimit to set the upper limit of eth1 header requests.
func WithEth1HeaderRequestLimit(limit uint64) Option {
return func(s *Service) error {
s.cfg.eth1HeaderReqLimit = limit
return nil
}
}
// WithBeaconNodeStatsUpdater to set the beacon node stats updater.
func WithBeaconNodeStatsUpdater(updater BeaconNodeStatsUpdater) Option {
return func(s *Service) error {
s.cfg.beaconNodeStatsUpdater = updater
return nil
}
}
// WithFinalizedStateAtStartup to set the beacon node's finalized state at startup.
func WithFinalizedStateAtStartup(st state.BeaconState) Option {
return func(s *Service) error {
s.cfg.finalizedStateAtStartup = st
return nil
}
}

View File

@@ -31,6 +31,7 @@ import (
"github.com/prysmaticlabs/prysm/beacon-chain/state"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stategen"
v1 "github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
"github.com/prysmaticlabs/prysm/config/features"
"github.com/prysmaticlabs/prysm/config/params"
"github.com/prysmaticlabs/prysm/container/trie"
contracts "github.com/prysmaticlabs/prysm/contracts/deposit"
@@ -98,6 +99,8 @@ type POWBlockFetcher interface {
BlockHashByHeight(ctx context.Context, height *big.Int) (common.Hash, error)
BlockExists(ctx context.Context, hash common.Hash) (bool, *big.Int, error)
BlockExistsWithCache(ctx context.Context, hash common.Hash) (bool, *big.Int, error)
BlockByHash(ctx context.Context, hash common.Hash) (*gethTypes.Block, error)
BlockByNumber(ctx context.Context, number *big.Int) (*gethTypes.Block, error)
}
// Chain defines a standard interface for the powchain service in Prysm.
@@ -113,6 +116,8 @@ type RPCDataFetcher interface {
HeaderByNumber(ctx context.Context, number *big.Int) (*gethTypes.Header, error)
HeaderByHash(ctx context.Context, hash common.Hash) (*gethTypes.Header, error)
SyncProgress(ctx context.Context) (*ethereum.SyncProgress, error)
BlockByHash(ctx context.Context, hash common.Hash) (*gethTypes.Block, error)
BlockByNumber(ctx context.Context, number *big.Int) (*gethTypes.Block, error)
}
// RPCClient defines the rpc methods required to interact with the eth1 node.
@@ -120,20 +125,6 @@ type RPCClient interface {
BatchCall(b []gethRPC.BatchElem) error
}
// config defines a config struct for dependencies into the service.
type config struct {
depositContractAddr common.Address
beaconDB db.HeadAccessDatabase
depositCache *depositcache.DepositCache
stateNotifier statefeed.Notifier
stateGen *stategen.State
eth1HeaderReqLimit uint64
beaconNodeStatsUpdater BeaconNodeStatsUpdater
httpEndpoints []network.Endpoint
currHttpEndpoint network.Endpoint
finalizedStateAtStartup state.BeaconState
}
// Service fetches important information about the canonical
// Ethereum ETH1.0 chain via a web3 endpoint using an ethclient. The Random
// Beacon Chain requires synchronization with the ETH1.0 chain's current
@@ -144,10 +135,12 @@ type Service struct {
connectedETH1 bool
isRunning bool
processingLock sync.RWMutex
cfg *config
cfg *Web3ServiceConfig
ctx context.Context
cancel context.CancelFunc
headTicker *time.Ticker
httpEndpoints []network.Endpoint
currHttpEndpoint network.Endpoint
httpLogger bind.ContractFilterer
eth1DataFetcher RPCDataFetcher
rpcClient RPCClient
@@ -159,10 +152,24 @@ type Service struct {
lastReceivedMerkleIndex int64 // Keeps track of the last received index to prevent log spam.
runError error
preGenesisState state.BeaconState
bsUpdater BeaconNodeStatsUpdater
}
// NewService sets up a new instance with an ethclient when given a web3 endpoint as a string in the config.
func NewService(ctx context.Context, opts ...Option) (*Service, error) {
// Web3ServiceConfig defines a config struct for web3 service to use through its life cycle.
type Web3ServiceConfig struct {
HttpEndpoints []string
DepositContract common.Address
BeaconDB db.HeadAccessDatabase
DepositCache *depositcache.DepositCache
StateNotifier statefeed.Notifier
StateGen *stategen.State
Eth1HeaderReqLimit uint64
BeaconNodeStatsUpdater BeaconNodeStatsUpdater
}
// NewService sets up a new instance with an ethclient when
// given a web3 endpoint as a string in the config.
func NewService(ctx context.Context, config *Web3ServiceConfig) (*Service, error) {
ctx, cancel := context.WithCancel(ctx)
_ = cancel // govet fix for lost cancel. Cancel is handled in service.Stop()
depositTrie, err := trie.NewTrie(params.BeaconConfig().DepositContractTreeDepth)
@@ -175,13 +182,27 @@ func NewService(ctx context.Context, opts ...Option) (*Service, error) {
return nil, errors.Wrap(err, "could not setup genesis state")
}
if config.Eth1HeaderReqLimit == 0 {
config.Eth1HeaderReqLimit = defaultEth1HeaderReqLimit
}
stringEndpoints := dedupEndpoints(config.HttpEndpoints)
endpoints := make([]network.Endpoint, len(stringEndpoints))
for i, e := range stringEndpoints {
endpoints[i] = HttpEndpoint(e)
}
// Select first http endpoint in the provided list.
var currEndpoint network.Endpoint
if len(config.HttpEndpoints) > 0 {
currEndpoint = endpoints[0]
}
s := &Service{
ctx: ctx,
cancel: cancel,
cfg: &config{
beaconNodeStatsUpdater: &NopBeaconNodeStatsUpdater{},
eth1HeaderReqLimit: defaultEth1HeaderReqLimit,
},
ctx: ctx,
cancel: cancel,
cfg: config,
httpEndpoints: endpoints,
currHttpEndpoint: currEndpoint,
latestEth1Data: &protodb.LatestETH1Data{
BlockHeight: 0,
BlockTime: 0,
@@ -197,25 +218,26 @@ func NewService(ctx context.Context, opts ...Option) (*Service, error) {
lastReceivedMerkleIndex: -1,
preGenesisState: genState,
headTicker: time.NewTicker(time.Duration(params.BeaconConfig().SecondsPerETH1Block) * time.Second),
// use the nop updater by default, rely on upstream set up to pass in an appropriate impl
bsUpdater: config.BeaconNodeStatsUpdater,
}
for _, opt := range opts {
if err := opt(s); err != nil {
return nil, err
}
if config.BeaconNodeStatsUpdater == nil {
s.bsUpdater = &NopBeaconNodeStatsUpdater{}
}
if err := s.ensureValidPowchainData(ctx); err != nil {
return nil, errors.Wrap(err, "unable to validate powchain data")
}
eth1Data, err := s.cfg.beaconDB.PowchainData(ctx)
eth1Data, err := config.BeaconDB.PowchainData(ctx)
if err != nil {
return nil, errors.Wrap(err, "unable to retrieve eth1 data")
}
if err := s.initializeEth1Data(ctx, eth1Data); err != nil {
return nil, err
}
return s, nil
}
@@ -223,10 +245,10 @@ func NewService(ctx context.Context, opts ...Option) (*Service, error) {
func (s *Service) Start() {
// If the chain has not started already and we don't have access to eth1 nodes, we will not be
// able to generate the genesis state.
if !s.chainStartData.Chainstarted && s.cfg.currHttpEndpoint.Url == "" {
if !s.chainStartData.Chainstarted && s.currHttpEndpoint.Url == "" {
// check for genesis state before shutting down the node,
// if a genesis state exists, we can continue on.
genState, err := s.cfg.beaconDB.GenesisState(s.ctx)
genState, err := s.cfg.BeaconDB.GenesisState(s.ctx)
if err != nil {
log.Fatal(err)
}
@@ -236,7 +258,7 @@ func (s *Service) Start() {
}
// Exit early if eth1 endpoint is not set.
if s.cfg.currHttpEndpoint.Url == "" {
if s.currHttpEndpoint.Url == "" {
return
}
go func() {
@@ -297,7 +319,7 @@ func (s *Service) Status() error {
func (s *Service) updateBeaconNodeStats() {
bs := clientstats.BeaconNodeStats{}
if len(s.cfg.httpEndpoints) > 1 {
if len(s.httpEndpoints) > 1 {
bs.SyncEth1FallbackConfigured = true
}
if s.IsConnectedToETH1() {
@@ -307,11 +329,11 @@ func (s *Service) updateBeaconNodeStats() {
bs.SyncEth1FallbackConnected = true
}
}
s.cfg.beaconNodeStatsUpdater.Update(bs)
s.bsUpdater.Update(bs)
}
func (s *Service) updateCurrHttpEndpoint(endpoint network.Endpoint) {
s.cfg.currHttpEndpoint = endpoint
s.currHttpEndpoint = endpoint
s.updateBeaconNodeStats()
}
@@ -357,7 +379,7 @@ func (s *Service) AreAllDepositsProcessed() (bool, error) {
return false, errors.Wrap(err, "could not get deposit count")
}
count := bytesutil.FromBytes8(countByte)
deposits := s.cfg.depositCache.AllDeposits(s.ctx, nil)
deposits := s.cfg.DepositCache.AllDeposits(s.ctx, nil)
if count != uint64(len(deposits)) {
return false, nil
}
@@ -375,12 +397,12 @@ func (s *Service) followBlockHeight(_ context.Context) (uint64, error) {
}
func (s *Service) connectToPowChain() error {
httpClient, rpcClient, err := s.dialETH1Nodes(s.cfg.currHttpEndpoint)
httpClient, rpcClient, err := s.dialETH1Nodes(s.currHttpEndpoint)
if err != nil {
return errors.Wrap(err, "could not dial eth1 nodes")
}
depositContractCaller, err := contracts.NewDepositContractCaller(s.cfg.depositContractAddr, httpClient)
depositContractCaller, err := contracts.NewDepositContractCaller(s.cfg.DepositContract, httpClient)
if err != nil {
return errors.Wrap(err, "could not create deposit contract caller")
}
@@ -476,7 +498,7 @@ func (s *Service) waitForConnection() {
s.updateConnectedETH1(true)
s.runError = nil
log.WithFields(logrus.Fields{
"endpoint": logs.MaskCredentialsLogging(s.cfg.currHttpEndpoint.Url),
"endpoint": logs.MaskCredentialsLogging(s.currHttpEndpoint.Url),
}).Info("Connected to eth1 proof-of-work chain")
return
}
@@ -505,7 +527,7 @@ func (s *Service) waitForConnection() {
for {
select {
case <-ticker.C:
log.Debugf("Trying to dial endpoint: %s", logs.MaskCredentialsLogging(s.cfg.currHttpEndpoint.Url))
log.Debugf("Trying to dial endpoint: %s", logs.MaskCredentialsLogging(s.currHttpEndpoint.Url))
errConnect := s.connectToPowChain()
if errConnect != nil {
errorLogger(errConnect, "Could not connect to powchain endpoint")
@@ -524,7 +546,7 @@ func (s *Service) waitForConnection() {
s.updateConnectedETH1(true)
s.runError = nil
log.WithFields(logrus.Fields{
"endpoint": logs.MaskCredentialsLogging(s.cfg.currHttpEndpoint.Url),
"endpoint": logs.MaskCredentialsLogging(s.currHttpEndpoint.Url),
}).Info("Connected to eth1 proof-of-work chain")
return
}
@@ -570,29 +592,32 @@ func (s *Service) initDepositCaches(ctx context.Context, ctrs []*protodb.Deposit
if len(ctrs) == 0 {
return nil
}
s.cfg.depositCache.InsertDepositContainers(ctx, ctrs)
s.cfg.DepositCache.InsertDepositContainers(ctx, ctrs)
if !s.chainStartData.Chainstarted {
// do not add to pending cache
// if no genesis state exists.
validDepositsCount.Add(float64(s.preGenesisState.Eth1DepositIndex()))
return nil
}
genesisState, err := s.cfg.beaconDB.GenesisState(ctx)
genesisState, err := s.cfg.BeaconDB.GenesisState(ctx)
if err != nil {
return err
}
// Default to all deposits post-genesis deposits in
// the event we cannot find a finalized state.
currIndex := genesisState.Eth1DepositIndex()
chkPt, err := s.cfg.beaconDB.FinalizedCheckpoint(ctx)
chkPt, err := s.cfg.BeaconDB.FinalizedCheckpoint(ctx)
if err != nil {
return err
}
rt := bytesutil.ToBytes32(chkPt.Root)
if rt != [32]byte{} {
fState := s.cfg.finalizedStateAtStartup
fState, err := s.cfg.StateGen.StateByRoot(ctx, rt)
if err != nil {
return errors.Wrap(err, "could not get finalized state")
}
if fState == nil || fState.IsNil() {
return errors.Errorf("finalized state with root %#x is nil", rt)
return errors.Errorf("finalized state with root %#x does not exist in the db", rt)
}
// Set deposit index to the one in the current archived state.
currIndex = fState.Eth1DepositIndex()
@@ -601,9 +626,9 @@ func (s *Service) initDepositCaches(ctx context.Context, ctrs []*protodb.Deposit
// accumulates. we finalize them here before we are ready to receive a block.
// Otherwise, the first few blocks will be slower to compute as we will
// hold the lock and be busy finalizing the deposits.
s.cfg.depositCache.InsertFinalizedDeposits(ctx, int64(currIndex))
s.cfg.DepositCache.InsertFinalizedDeposits(ctx, int64(currIndex))
// Deposit proofs are only used during state transition and can be safely removed to save space.
if err = s.cfg.depositCache.PruneProofs(ctx, int64(currIndex)); err != nil {
if err = s.cfg.DepositCache.PruneProofs(ctx, int64(currIndex)); err != nil {
return errors.Wrap(err, "could not prune deposit proofs")
}
}
@@ -612,7 +637,7 @@ func (s *Service) initDepositCaches(ctx context.Context, ctrs []*protodb.Deposit
// is more than the current index in state.
if uint64(len(ctrs)) > currIndex {
for _, c := range ctrs[currIndex:] {
s.cfg.depositCache.InsertPendingDeposit(ctx, c.Deposit, c.Eth1BlockHeight, c.Index, bytesutil.ToBytes32(c.DepositRoot))
s.cfg.DepositCache.InsertPendingDeposit(ctx, c.Deposit, c.Eth1BlockHeight, c.Index, bytesutil.ToBytes32(c.DepositRoot))
}
}
return nil
@@ -745,12 +770,14 @@ func (s *Service) initPOWService() {
s.latestEth1Data.BlockHeight = header.Number.Uint64()
s.latestEth1Data.BlockHash = header.Hash().Bytes()
s.latestEth1Data.BlockTime = header.Time
if err := s.processPastLogs(ctx); err != nil {
log.Errorf("Unable to process past logs %v", err)
s.retryETH1Node(err)
continue
if !features.Get().MergeTestnet {
if err := s.processPastLogs(ctx); err != nil {
log.Errorf("Unable to process past logs %v", err)
s.retryETH1Node(err)
continue
}
}
// Cache eth1 headers from our voting period.
if err := s.cacheHeadersForEth1DataVote(ctx); err != nil {
log.Errorf("Unable to process past headers %v", err)
@@ -759,7 +786,7 @@ func (s *Service) initPOWService() {
}
// Handle edge case with embedded genesis state by fetching genesis header to determine
// its height.
if s.chainStartData.Chainstarted && s.chainStartData.GenesisBlock == 0 {
if s.chainStartData.Chainstarted && s.chainStartData.GenesisBlock == 0 && !features.Get().MergeTestnet {
genHeader, err := s.eth1DataFetcher.HeaderByHash(ctx, common.BytesToHash(s.chainStartData.Eth1Data.BlockHash))
if err != nil {
log.Errorf("Unable to retrieve genesis ETH1.0 chain header: %v", err)
@@ -898,10 +925,10 @@ func (s *Service) determineEarliestVotingBlock(ctx context.Context, followBlock
// is ready to serve we connect to it again. This method is only
// relevant if we are on our backup endpoint.
func (s *Service) checkDefaultEndpoint() {
primaryEndpoint := s.cfg.httpEndpoints[0]
primaryEndpoint := s.httpEndpoints[0]
// Return early if we are running on our primary
// endpoint.
if s.cfg.currHttpEndpoint.Equals(primaryEndpoint) {
if s.currHttpEndpoint.Equals(primaryEndpoint) {
return
}
@@ -927,11 +954,11 @@ func (s *Service) checkDefaultEndpoint() {
// This is an inefficient way to search for the next endpoint, but given N is expected to be
// small ( < 25), it is fine to search this way.
func (s *Service) fallbackToNextEndpoint() {
currEndpoint := s.cfg.currHttpEndpoint
currEndpoint := s.currHttpEndpoint
currIndex := 0
totalEndpoints := len(s.cfg.httpEndpoints)
totalEndpoints := len(s.httpEndpoints)
for i, endpoint := range s.cfg.httpEndpoints {
for i, endpoint := range s.httpEndpoints {
if endpoint.Equals(currEndpoint) {
currIndex = i
break
@@ -941,9 +968,9 @@ func (s *Service) fallbackToNextEndpoint() {
if nextIndex >= totalEndpoints {
nextIndex = 0
}
s.updateCurrHttpEndpoint(s.cfg.httpEndpoints[nextIndex])
s.updateCurrHttpEndpoint(s.httpEndpoints[nextIndex])
if nextIndex != currIndex {
log.Infof("Falling back to alternative endpoint: %s", logs.MaskCredentialsLogging(s.cfg.currHttpEndpoint.Url))
log.Infof("Falling back to alternative endpoint: %s", logs.MaskCredentialsLogging(s.currHttpEndpoint.Url))
}
}
@@ -999,7 +1026,7 @@ func (s *Service) validateDepositContainers(ctrs []*protodb.DepositContainer) bo
// validates the current powchain data saved and makes sure that any
// embedded genesis state is correctly accounted for.
func (s *Service) ensureValidPowchainData(ctx context.Context) error {
genState, err := s.cfg.beaconDB.GenesisState(ctx)
genState, err := s.cfg.BeaconDB.GenesisState(ctx)
if err != nil {
return err
}
@@ -1007,7 +1034,7 @@ func (s *Service) ensureValidPowchainData(ctx context.Context) error {
if genState == nil || genState.IsNil() {
return nil
}
eth1Data, err := s.cfg.beaconDB.PowchainData(ctx)
eth1Data, err := s.cfg.BeaconDB.PowchainData(ctx)
if err != nil {
return errors.Wrap(err, "unable to retrieve eth1 data")
}
@@ -1028,9 +1055,9 @@ func (s *Service) ensureValidPowchainData(ctx context.Context) error {
ChainstartData: s.chainStartData,
BeaconState: pbState,
Trie: s.depositTrie.ToProto(),
DepositContainers: s.cfg.depositCache.AllDepositContainers(ctx),
DepositContainers: s.cfg.DepositCache.AllDepositContainers(ctx),
}
return s.cfg.beaconDB.SavePowchainData(ctx, eth1Data)
return s.cfg.BeaconDB.SavePowchainData(ctx, eth1Data)
}
return nil
}
@@ -1057,5 +1084,5 @@ func eth1HeadIsBehind(timestamp uint64) bool {
}
func (s *Service) primaryConnected() bool {
return s.cfg.currHttpEndpoint.Equals(s.cfg.httpEndpoints[0])
return s.currHttpEndpoint.Equals(s.httpEndpoints[0])
}

View File

@@ -27,6 +27,7 @@ import (
"github.com/prysmaticlabs/prysm/network"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
protodb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/wrapper"
"github.com/prysmaticlabs/prysm/testing/assert"
"github.com/prysmaticlabs/prysm/testing/require"
"github.com/prysmaticlabs/prysm/testing/util"
@@ -81,6 +82,16 @@ type goodFetcher struct {
backend *backends.SimulatedBackend
}
// BlockByHash is a stub for `goodFetcher`.
func (g *goodFetcher) BlockByHash(ctx context.Context, hash common.Hash) (*gethTypes.Block, error) {
return nil, nil
}
// BlockByNumber is a stub for `goodFetcher`.
func (g *goodFetcher) BlockByNumber(ctx context.Context, number *big.Int) (*gethTypes.Block, error) {
return nil, nil
}
func (g *goodFetcher) HeaderByHash(_ context.Context, hash common.Hash) (*gethTypes.Header, error) {
if bytes.Equal(hash.Bytes(), common.BytesToHash([]byte{0}).Bytes()) {
return nil, fmt.Errorf("expected block hash to be nonzero %v", hash)
@@ -128,11 +139,11 @@ func TestStart_OK(t *testing.T) {
beaconDB := dbutil.SetupDB(t)
testAcc, err := contracts.Setup()
require.NoError(t, err, "Unable to set up simulated backend")
web3Service, err := NewService(context.Background(),
WithHttpEndpoints([]string{endpoint}),
WithDepositContractAddress(testAcc.ContractAddr),
WithDatabase(beaconDB),
)
web3Service, err := NewService(context.Background(), &Web3ServiceConfig{
HttpEndpoints: []string{endpoint},
DepositContract: testAcc.ContractAddr,
BeaconDB: beaconDB,
})
require.NoError(t, err, "unable to setup web3 ETH1.0 chain service")
web3Service = setDefaultMocks(web3Service)
web3Service.rpcClient = &mockPOW.RPCClient{Backend: testAcc.Backend}
@@ -157,11 +168,11 @@ func TestStart_NoHttpEndpointDefinedFails_WithoutChainStarted(t *testing.T) {
beaconDB := dbutil.SetupDB(t)
testAcc, err := contracts.Setup()
require.NoError(t, err, "Unable to set up simulated backend")
s, err := NewService(context.Background(),
WithHttpEndpoints([]string{""}),
WithDepositContractAddress(testAcc.ContractAddr),
WithDatabase(beaconDB),
)
s, err := NewService(context.Background(), &Web3ServiceConfig{
HttpEndpoints: []string{""}, // No endpoint defined!
DepositContract: testAcc.ContractAddr,
BeaconDB: beaconDB,
})
require.NoError(t, err)
// Set custom exit func so test can proceed
log.Logger.ExitFunc = func(i int) {
@@ -200,12 +211,12 @@ func TestStart_NoHttpEndpointDefinedSucceeds_WithGenesisState(t *testing.T) {
require.NoError(t, beaconDB.SaveGenesisBlockRoot(context.Background(), genRoot))
depositCache, err := depositcache.New()
require.NoError(t, err)
s, err := NewService(context.Background(),
WithHttpEndpoints([]string{""}),
WithDepositContractAddress(testAcc.ContractAddr),
WithDatabase(beaconDB),
WithDepositCache(depositCache),
)
s, err := NewService(context.Background(), &Web3ServiceConfig{
HttpEndpoints: []string{""}, // No endpoint defined!
DepositContract: testAcc.ContractAddr,
BeaconDB: beaconDB,
DepositCache: depositCache,
})
require.NoError(t, err)
wg := new(sync.WaitGroup)
@@ -231,11 +242,11 @@ func TestStart_NoHttpEndpointDefinedSucceeds_WithChainStarted(t *testing.T) {
ChainstartData: &protodb.ChainStartData{Chainstarted: true},
Trie: &protodb.SparseMerkleTrie{},
}))
s, err := NewService(context.Background(),
WithHttpEndpoints([]string{""}),
WithDepositContractAddress(testAcc.ContractAddr),
WithDatabase(beaconDB),
)
s, err := NewService(context.Background(), &Web3ServiceConfig{
HttpEndpoints: []string{""}, // No endpoint defined!
DepositContract: testAcc.ContractAddr,
BeaconDB: beaconDB,
})
require.NoError(t, err)
s.Start()
@@ -248,11 +259,11 @@ func TestStop_OK(t *testing.T) {
testAcc, err := contracts.Setup()
require.NoError(t, err, "Unable to set up simulated backend")
beaconDB := dbutil.SetupDB(t)
web3Service, err := NewService(context.Background(),
WithHttpEndpoints([]string{endpoint}),
WithDepositContractAddress(testAcc.ContractAddr),
WithDatabase(beaconDB),
)
web3Service, err := NewService(context.Background(), &Web3ServiceConfig{
HttpEndpoints: []string{endpoint},
DepositContract: testAcc.ContractAddr,
BeaconDB: beaconDB,
})
require.NoError(t, err, "unable to setup web3 ETH1.0 chain service")
web3Service = setDefaultMocks(web3Service)
web3Service.depositContractCaller, err = contracts.NewDepositContractCaller(testAcc.ContractAddr, testAcc.Backend)
@@ -273,11 +284,11 @@ func TestService_Eth1Synced(t *testing.T) {
testAcc, err := contracts.Setup()
require.NoError(t, err, "Unable to set up simulated backend")
beaconDB := dbutil.SetupDB(t)
web3Service, err := NewService(context.Background(),
WithHttpEndpoints([]string{endpoint}),
WithDepositContractAddress(testAcc.ContractAddr),
WithDatabase(beaconDB),
)
web3Service, err := NewService(context.Background(), &Web3ServiceConfig{
HttpEndpoints: []string{endpoint},
DepositContract: testAcc.ContractAddr,
BeaconDB: beaconDB,
})
require.NoError(t, err, "unable to setup web3 ETH1.0 chain service")
web3Service = setDefaultMocks(web3Service)
web3Service.depositContractCaller, err = contracts.NewDepositContractCaller(testAcc.ContractAddr, testAcc.Backend)
@@ -298,11 +309,11 @@ func TestFollowBlock_OK(t *testing.T) {
testAcc, err := contracts.Setup()
require.NoError(t, err, "Unable to set up simulated backend")
beaconDB := dbutil.SetupDB(t)
web3Service, err := NewService(context.Background(),
WithHttpEndpoints([]string{endpoint}),
WithDepositContractAddress(testAcc.ContractAddr),
WithDatabase(beaconDB),
)
web3Service, err := NewService(context.Background(), &Web3ServiceConfig{
HttpEndpoints: []string{endpoint},
DepositContract: testAcc.ContractAddr,
BeaconDB: beaconDB,
})
require.NoError(t, err, "unable to setup web3 ETH1.0 chain service")
// simulated backend sets eth1 block
@@ -371,10 +382,10 @@ func TestStatus(t *testing.T) {
func TestHandlePanic_OK(t *testing.T) {
hook := logTest.NewGlobal()
beaconDB := dbutil.SetupDB(t)
web3Service, err := NewService(context.Background(),
WithHttpEndpoints([]string{endpoint}),
WithDatabase(beaconDB),
)
web3Service, err := NewService(context.Background(), &Web3ServiceConfig{
HttpEndpoints: []string{endpoint},
BeaconDB: beaconDB,
})
require.NoError(t, err, "unable to setup web3 ETH1.0 chain service")
// nil eth1DataFetcher would panic if cached value not used
web3Service.eth1DataFetcher = nil
@@ -410,11 +421,11 @@ func TestLogTillGenesis_OK(t *testing.T) {
testAcc, err := contracts.Setup()
require.NoError(t, err, "Unable to set up simulated backend")
beaconDB := dbutil.SetupDB(t)
web3Service, err := NewService(context.Background(),
WithHttpEndpoints([]string{endpoint}),
WithDepositContractAddress(testAcc.ContractAddr),
WithDatabase(beaconDB),
)
web3Service, err := NewService(context.Background(), &Web3ServiceConfig{
HttpEndpoints: []string{endpoint},
DepositContract: testAcc.ContractAddr,
BeaconDB: beaconDB,
})
require.NoError(t, err, "unable to setup web3 ETH1.0 chain service")
web3Service.depositContractCaller, err = contracts.NewDepositContractCaller(testAcc.ContractAddr, testAcc.Backend)
require.NoError(t, err)
@@ -446,24 +457,24 @@ func TestInitDepositCache_OK(t *testing.T) {
s := &Service{
chainStartData: &protodb.ChainStartData{Chainstarted: false},
preGenesisState: gs,
cfg: &config{beaconDB: beaconDB},
cfg: &Web3ServiceConfig{BeaconDB: beaconDB},
}
var err error
s.cfg.depositCache, err = depositcache.New()
s.cfg.DepositCache, err = depositcache.New()
require.NoError(t, err)
require.NoError(t, s.initDepositCaches(context.Background(), ctrs))
require.Equal(t, 0, len(s.cfg.depositCache.PendingContainers(context.Background(), nil)))
require.Equal(t, 0, len(s.cfg.DepositCache.PendingContainers(context.Background(), nil)))
blockRootA := [32]byte{'a'}
emptyState, err := util.NewBeaconState()
require.NoError(t, err)
require.NoError(t, s.cfg.beaconDB.SaveGenesisBlockRoot(context.Background(), blockRootA))
require.NoError(t, s.cfg.beaconDB.SaveState(context.Background(), emptyState, blockRootA))
require.NoError(t, s.cfg.BeaconDB.SaveGenesisBlockRoot(context.Background(), blockRootA))
require.NoError(t, s.cfg.BeaconDB.SaveState(context.Background(), emptyState, blockRootA))
s.chainStartData.Chainstarted = true
require.NoError(t, s.initDepositCaches(context.Background(), ctrs))
require.Equal(t, 3, len(s.cfg.depositCache.PendingContainers(context.Background(), nil)))
require.Equal(t, 3, len(s.cfg.DepositCache.PendingContainers(context.Background(), nil)))
}
func TestInitDepositCacheWithFinalization_OK(t *testing.T) {
@@ -507,14 +518,14 @@ func TestInitDepositCacheWithFinalization_OK(t *testing.T) {
s := &Service{
chainStartData: &protodb.ChainStartData{Chainstarted: false},
preGenesisState: gs,
cfg: &config{beaconDB: beaconDB},
cfg: &Web3ServiceConfig{BeaconDB: beaconDB},
}
var err error
s.cfg.depositCache, err = depositcache.New()
s.cfg.DepositCache, err = depositcache.New()
require.NoError(t, err)
require.NoError(t, s.initDepositCaches(context.Background(), ctrs))
require.Equal(t, 0, len(s.cfg.depositCache.PendingContainers(context.Background(), nil)))
require.Equal(t, 0, len(s.cfg.DepositCache.PendingContainers(context.Background(), nil)))
headBlock := util.NewBeaconBlock()
headRoot, err := headBlock.Block.HashTreeRoot()
@@ -523,20 +534,22 @@ func TestInitDepositCacheWithFinalization_OK(t *testing.T) {
emptyState, err := util.NewBeaconState()
require.NoError(t, err)
require.NoError(t, s.cfg.beaconDB.SaveGenesisBlockRoot(context.Background(), headRoot))
require.NoError(t, s.cfg.beaconDB.SaveState(context.Background(), emptyState, headRoot))
require.NoError(t, s.cfg.BeaconDB.SaveGenesisBlockRoot(context.Background(), headRoot))
require.NoError(t, s.cfg.BeaconDB.SaveState(context.Background(), emptyState, headRoot))
require.NoError(t, stateGen.SaveState(context.Background(), headRoot, emptyState))
s.cfg.stateGen = stateGen
s.cfg.StateGen = stateGen
require.NoError(t, emptyState.SetEth1DepositIndex(2))
ctx := context.Background()
require.NoError(t, stateGen.SaveState(ctx, headRoot, emptyState))
require.NoError(t, beaconDB.SaveState(ctx, emptyState, headRoot))
require.NoError(t, beaconDB.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(headBlock)))
require.NoError(t, beaconDB.SaveFinalizedCheckpoint(ctx, &ethpb.Checkpoint{Epoch: slots.ToEpoch(0), Root: headRoot[:]}))
s.cfg.finalizedStateAtStartup = emptyState
s.chainStartData.Chainstarted = true
require.NoError(t, s.initDepositCaches(context.Background(), ctrs))
deps := s.cfg.depositCache.NonFinalizedDeposits(context.Background(), nil)
deps := s.cfg.DepositCache.NonFinalizedDeposits(context.Background(), nil)
assert.Equal(t, 0, len(deps))
}
@@ -544,11 +557,11 @@ func TestNewService_EarliestVotingBlock(t *testing.T) {
testAcc, err := contracts.Setup()
require.NoError(t, err, "Unable to set up simulated backend")
beaconDB := dbutil.SetupDB(t)
web3Service, err := NewService(context.Background(),
WithHttpEndpoints([]string{endpoint}),
WithDepositContractAddress(testAcc.ContractAddr),
WithDatabase(beaconDB),
)
web3Service, err := NewService(context.Background(), &Web3ServiceConfig{
HttpEndpoints: []string{endpoint},
DepositContract: testAcc.ContractAddr,
BeaconDB: beaconDB,
})
require.NoError(t, err, "unable to setup web3 ETH1.0 chain service")
web3Service.eth1DataFetcher = &goodFetcher{backend: testAcc.Backend}
// simulated backend sets eth1 block
@@ -595,21 +608,22 @@ func TestNewService_Eth1HeaderRequLimit(t *testing.T) {
require.NoError(t, err, "Unable to set up simulated backend")
beaconDB := dbutil.SetupDB(t)
s1, err := NewService(context.Background(),
WithHttpEndpoints([]string{endpoint}),
WithDepositContractAddress(testAcc.ContractAddr),
WithDatabase(beaconDB),
)
s1, err := NewService(context.Background(), &Web3ServiceConfig{
HttpEndpoints: []string{endpoint},
DepositContract: testAcc.ContractAddr,
BeaconDB: beaconDB,
})
require.NoError(t, err, "unable to setup web3 ETH1.0 chain service")
assert.Equal(t, defaultEth1HeaderReqLimit, s1.cfg.eth1HeaderReqLimit, "default eth1 header request limit not set")
s2, err := NewService(context.Background(),
WithHttpEndpoints([]string{endpoint}),
WithDepositContractAddress(testAcc.ContractAddr),
WithDatabase(beaconDB),
WithEth1HeaderRequestLimit(uint64(150)),
)
assert.Equal(t, defaultEth1HeaderReqLimit, s1.cfg.Eth1HeaderReqLimit, "default eth1 header request limit not set")
s2, err := NewService(context.Background(), &Web3ServiceConfig{
HttpEndpoints: []string{endpoint},
DepositContract: testAcc.ContractAddr,
BeaconDB: beaconDB,
Eth1HeaderReqLimit: uint64(150),
})
require.NoError(t, err, "unable to setup web3 ETH1.0 chain service")
assert.Equal(t, uint64(150), s2.cfg.eth1HeaderReqLimit, "unable to set eth1HeaderRequestLimit")
assert.Equal(t, uint64(150), s2.cfg.Eth1HeaderReqLimit, "unable to set eth1HeaderRequestLimit")
}
type mockBSUpdater struct {
@@ -631,41 +645,41 @@ func TestServiceFallbackCorrectly(t *testing.T) {
beaconDB := dbutil.SetupDB(t)
mbs := &mockBSUpdater{}
s1, err := NewService(context.Background(),
WithHttpEndpoints([]string{firstEndpoint}),
WithDepositContractAddress(testAcc.ContractAddr),
WithDatabase(beaconDB),
WithBeaconNodeStatsUpdater(mbs),
)
s1.cfg.beaconNodeStatsUpdater = mbs
s1, err := NewService(context.Background(), &Web3ServiceConfig{
HttpEndpoints: []string{firstEndpoint},
DepositContract: testAcc.ContractAddr,
BeaconDB: beaconDB,
BeaconNodeStatsUpdater: mbs,
})
s1.bsUpdater = mbs
require.NoError(t, err)
assert.Equal(t, firstEndpoint, s1.cfg.currHttpEndpoint.Url, "Unexpected http endpoint")
assert.Equal(t, firstEndpoint, s1.currHttpEndpoint.Url, "Unexpected http endpoint")
// Stay at the first endpoint.
s1.fallbackToNextEndpoint()
assert.Equal(t, firstEndpoint, s1.cfg.currHttpEndpoint.Url, "Unexpected http endpoint")
assert.Equal(t, firstEndpoint, s1.currHttpEndpoint.Url, "Unexpected http endpoint")
assert.Equal(t, false, mbs.lastBS.SyncEth1FallbackConfigured, "SyncEth1FallbackConfigured in clientstats update should be false when only 1 endpoint is configured")
s1.cfg.httpEndpoints = append(s1.cfg.httpEndpoints, network.Endpoint{Url: secondEndpoint})
s1.httpEndpoints = append(s1.httpEndpoints, network.Endpoint{Url: secondEndpoint})
s1.fallbackToNextEndpoint()
assert.Equal(t, secondEndpoint, s1.cfg.currHttpEndpoint.Url, "Unexpected http endpoint")
assert.Equal(t, secondEndpoint, s1.currHttpEndpoint.Url, "Unexpected http endpoint")
assert.Equal(t, true, mbs.lastBS.SyncEth1FallbackConfigured, "SyncEth1FallbackConfigured in clientstats update should be true when > 1 endpoint is configured")
thirdEndpoint := "C"
fourthEndpoint := "D"
s1.cfg.httpEndpoints = append(s1.cfg.httpEndpoints, network.Endpoint{Url: thirdEndpoint}, network.Endpoint{Url: fourthEndpoint})
s1.httpEndpoints = append(s1.httpEndpoints, network.Endpoint{Url: thirdEndpoint}, network.Endpoint{Url: fourthEndpoint})
s1.fallbackToNextEndpoint()
assert.Equal(t, thirdEndpoint, s1.cfg.currHttpEndpoint.Url, "Unexpected http endpoint")
assert.Equal(t, thirdEndpoint, s1.currHttpEndpoint.Url, "Unexpected http endpoint")
s1.fallbackToNextEndpoint()
assert.Equal(t, fourthEndpoint, s1.cfg.currHttpEndpoint.Url, "Unexpected http endpoint")
assert.Equal(t, fourthEndpoint, s1.currHttpEndpoint.Url, "Unexpected http endpoint")
// Rollover correctly back to the first endpoint
s1.fallbackToNextEndpoint()
assert.Equal(t, firstEndpoint, s1.cfg.currHttpEndpoint.Url, "Unexpected http endpoint")
assert.Equal(t, firstEndpoint, s1.currHttpEndpoint.Url, "Unexpected http endpoint")
}
func TestDedupEndpoints(t *testing.T) {
@@ -693,19 +707,19 @@ func TestService_EnsureConsistentPowchainData(t *testing.T) {
cache, err := depositcache.New()
require.NoError(t, err)
s1, err := NewService(context.Background(),
WithDatabase(beaconDB),
WithDepositCache(cache),
)
s1, err := NewService(context.Background(), &Web3ServiceConfig{
BeaconDB: beaconDB,
DepositCache: cache,
})
require.NoError(t, err)
genState, err := util.NewBeaconState()
require.NoError(t, err)
assert.NoError(t, genState.SetSlot(1000))
require.NoError(t, s1.cfg.beaconDB.SaveGenesisData(context.Background(), genState))
require.NoError(t, s1.cfg.BeaconDB.SaveGenesisData(context.Background(), genState))
require.NoError(t, s1.ensureValidPowchainData(context.Background()))
eth1Data, err := s1.cfg.beaconDB.PowchainData(context.Background())
eth1Data, err := s1.cfg.BeaconDB.PowchainData(context.Background())
assert.NoError(t, err)
assert.NotNil(t, eth1Data)
@@ -717,19 +731,19 @@ func TestService_InitializeCorrectly(t *testing.T) {
cache, err := depositcache.New()
require.NoError(t, err)
s1, err := NewService(context.Background(),
WithDatabase(beaconDB),
WithDepositCache(cache),
)
s1, err := NewService(context.Background(), &Web3ServiceConfig{
BeaconDB: beaconDB,
DepositCache: cache,
})
require.NoError(t, err)
genState, err := util.NewBeaconState()
require.NoError(t, err)
assert.NoError(t, genState.SetSlot(1000))
require.NoError(t, s1.cfg.beaconDB.SaveGenesisData(context.Background(), genState))
require.NoError(t, s1.cfg.BeaconDB.SaveGenesisData(context.Background(), genState))
require.NoError(t, s1.ensureValidPowchainData(context.Background()))
eth1Data, err := s1.cfg.beaconDB.PowchainData(context.Background())
eth1Data, err := s1.cfg.BeaconDB.PowchainData(context.Background())
assert.NoError(t, err)
assert.NoError(t, s1.initializeEth1Data(context.Background(), eth1Data))
@@ -741,25 +755,25 @@ func TestService_EnsureValidPowchainData(t *testing.T) {
cache, err := depositcache.New()
require.NoError(t, err)
s1, err := NewService(context.Background(),
WithDatabase(beaconDB),
WithDepositCache(cache),
)
s1, err := NewService(context.Background(), &Web3ServiceConfig{
BeaconDB: beaconDB,
DepositCache: cache,
})
require.NoError(t, err)
genState, err := util.NewBeaconState()
require.NoError(t, err)
assert.NoError(t, genState.SetSlot(1000))
require.NoError(t, s1.cfg.beaconDB.SaveGenesisData(context.Background(), genState))
require.NoError(t, s1.cfg.BeaconDB.SaveGenesisData(context.Background(), genState))
err = s1.cfg.beaconDB.SavePowchainData(context.Background(), &protodb.ETH1ChainData{
err = s1.cfg.BeaconDB.SavePowchainData(context.Background(), &protodb.ETH1ChainData{
ChainstartData: &protodb.ChainStartData{Chainstarted: true},
DepositContainers: []*protodb.DepositContainer{{Index: 1}},
})
require.NoError(t, err)
require.NoError(t, s1.ensureValidPowchainData(context.Background()))
eth1Data, err := s1.cfg.beaconDB.PowchainData(context.Background())
eth1Data, err := s1.cfg.BeaconDB.PowchainData(context.Background())
assert.NoError(t, err)
assert.NotNil(t, eth1Data)
@@ -771,10 +785,10 @@ func TestService_ValidateDepositContainers(t *testing.T) {
cache, err := depositcache.New()
require.NoError(t, err)
s1, err := NewService(context.Background(),
WithDatabase(beaconDB),
WithDepositCache(cache),
)
s1, err := NewService(context.Background(), &Web3ServiceConfig{
BeaconDB: beaconDB,
DepositCache: cache,
})
require.NoError(t, err)
var tt = []struct {

View File

@@ -6,6 +6,7 @@ import (
"math/big"
"github.com/ethereum/go-ethereum/common"
gethTypes "github.com/ethereum/go-ethereum/core/types"
"github.com/prysmaticlabs/prysm/async/event"
"github.com/prysmaticlabs/prysm/beacon-chain/powchain/types"
"github.com/prysmaticlabs/prysm/beacon-chain/state"
@@ -59,6 +60,16 @@ func (f *FaultyMockPOWChain) DepositRoot() [32]byte {
return [32]byte{}
}
// BlockByHash is a stub for `FaultyMockPOWChain`.
func (m *FaultyMockPOWChain) BlockByHash(ctx context.Context, hash common.Hash) (*gethTypes.Block, error) {
panic("not implemented")
}
// BlockByNumber is a stub for `FaultyMockPOWChain`.
func (m *FaultyMockPOWChain) BlockByNumber(ctx context.Context, number *big.Int) (*gethTypes.Block, error) {
panic("not implemented")
}
// DepositTrie --
func (f *FaultyMockPOWChain) DepositTrie() *trie.SparseMerkleTrie {
return &trie.SparseMerkleTrie{}

View File

@@ -33,6 +33,16 @@ type POWChain struct {
GenesisState state.BeaconState
}
// BlockByHash is a stub for `POWChain`.
func (m *POWChain) BlockByHash(ctx context.Context, hash common.Hash) (*gethTypes.Block, error) {
panic("not implemented")
}
// BlockByNumber is a stub for `POWChain`.
func (m *POWChain) BlockByNumber(ctx context.Context, number *big.Int) (*gethTypes.Block, error) {
panic("not implemented")
}
// GenesisTime represents a static past date - JAN 01 2000.
var GenesisTime = time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC).Unix()

View File

@@ -104,7 +104,6 @@ go_test(
"//testing/require:go_default_library",
"//testing/util:go_default_library",
"//time/slots:go_default_library",
"@com_github_ethereum_go_ethereum//common:go_default_library",
"@com_github_grpc_ecosystem_grpc_gateway_v2//runtime:go_default_library",
"@com_github_prysmaticlabs_eth2_types//:go_default_library",
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",

View File

@@ -5,7 +5,6 @@ import (
"encoding/hex"
"testing"
"github.com/ethereum/go-ethereum/common"
types "github.com/prysmaticlabs/eth2-types"
"github.com/prysmaticlabs/prysm/config/params"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
@@ -51,7 +50,6 @@ func TestGetSpec(t *testing.T) {
config.MergeForkEpoch = 101
config.ShardingForkVersion = []byte("ShardingForkVersion")
config.ShardingForkEpoch = 102
config.MinAnchorPowBlockDifficulty = 1000
config.BLSWithdrawalPrefixByte = byte('b')
config.GenesisDelay = 24
config.SecondsPerSlot = 25
@@ -97,10 +95,6 @@ func TestGetSpec(t *testing.T) {
config.ProportionalSlashingMultiplierAltair = 69
config.InactivityScoreRecoveryRate = 70
config.MinSyncCommitteeParticipants = 71
config.TerminalBlockHash = common.HexToHash("TerminalBlockHash")
config.TerminalBlockHashActivationEpoch = 72
config.TerminalTotalDifficulty = 73
config.Coinbase = common.HexToAddress("Coinbase")
var dbp [4]byte
copy(dbp[:], []byte{'0', '0', '0', '1'})
@@ -130,7 +124,7 @@ func TestGetSpec(t *testing.T) {
resp, err := server.GetSpec(context.Background(), &emptypb.Empty{})
require.NoError(t, err)
assert.Equal(t, 94, len(resp.Data))
assert.Equal(t, 91, len(resp.Data))
for k, v := range resp.Data {
switch k {
case "CONFIG_NAME":
@@ -323,14 +317,6 @@ func TestGetSpec(t *testing.T) {
assert.Equal(t, "0x09000000", v)
case "TRANSITION_TOTAL_DIFFICULTY":
assert.Equal(t, "0", v)
case "TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH":
assert.Equal(t, "72", v)
case "TERMINAL_BLOCK_HASH":
assert.Equal(t, common.HexToHash("TerminalBlockHash"), common.HexToHash(v))
case "TERMINAL_TOTAL_DIFFICULTY":
assert.Equal(t, "73", v)
case "COINBASE":
assert.Equal(t, common.HexToAddress("Coinbase"), v)
default:
t.Errorf("Incorrect key: %s", k)
}

View File

@@ -16,7 +16,6 @@ import (
"github.com/prysmaticlabs/prysm/beacon-chain/core/validators"
"github.com/prysmaticlabs/prysm/beacon-chain/state"
"github.com/prysmaticlabs/prysm/cmd"
"github.com/prysmaticlabs/prysm/config/features"
"github.com/prysmaticlabs/prysm/config/params"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
@@ -675,23 +674,11 @@ func (bs *Server) GetValidatorPerformance(
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not get head state: %v", err)
}
currSlot := bs.GenesisTimeFetcher.CurrentSlot()
if currSlot > headState.Slot() {
if features.Get().EnableNextSlotStateCache {
headRoot, err := bs.HeadFetcher.HeadRoot(ctx)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not retrieve head root: %v", err)
}
headState, err = transition.ProcessSlotsUsingNextSlotCache(ctx, headState, headRoot, currSlot)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not process slots up to %d: %v", currSlot, err)
}
} else {
headState, err = transition.ProcessSlots(ctx, headState, currSlot)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not process slots: %v", err)
}
if bs.GenesisTimeFetcher.CurrentSlot() > headState.Slot() {
headState, err = transition.ProcessSlots(ctx, headState, bs.GenesisTimeFetcher.CurrentSlot())
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not process slots: %v", err)
}
}
var validatorSummary []*precompute.Validator
@@ -801,15 +788,14 @@ func (bs *Server) GetValidatorPerformance(
effectiveBalances = append(effectiveBalances, summary.CurrentEpochEffectiveBalance)
beforeTransitionBalances = append(beforeTransitionBalances, summary.BeforeEpochTransitionBalance)
afterTransitionBalances = append(afterTransitionBalances, summary.AfterEpochTransitionBalance)
correctlyVotedSource = append(correctlyVotedSource, summary.IsPrevEpochAttester)
correctlyVotedTarget = append(correctlyVotedTarget, summary.IsPrevEpochTargetAttester)
correctlyVotedHead = append(correctlyVotedHead, summary.IsPrevEpochHeadAttester)
if headState.Version() == version.Phase0 {
correctlyVotedSource = append(correctlyVotedSource, summary.IsPrevEpochAttester)
inclusionSlots = append(inclusionSlots, summary.InclusionSlot)
inclusionDistances = append(inclusionDistances, summary.InclusionDistance)
} else {
correctlyVotedSource = append(correctlyVotedSource, summary.IsPrevEpochSourceAttester)
inactivityScores = append(inactivityScores, summary.InactivityScore)
}
}

View File

@@ -3,7 +3,6 @@ package debug
import (
"context"
"fmt"
"math"
types "github.com/prysmaticlabs/eth2-types"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
@@ -62,7 +61,7 @@ func (ds *Server) GetInclusionSlot(ctx context.Context, req *pbrpc.InclusionSlot
return nil, status.Errorf(codes.Internal, "Could not retrieve blocks: %v", err)
}
inclusionSlot := types.Slot(math.MaxUint64)
inclusionSlot := types.Slot(1<<64 - 1)
targetStates := make(map[[32]byte]state.ReadOnlyBeaconState)
for _, blk := range blks {
for _, a := range blk.Block().Body().Attestations() {

View File

@@ -14,6 +14,7 @@ go_library(
"proposer_attestations.go",
"proposer_deposits.go",
"proposer_eth1data.go",
"proposer_execution_payload.go",
"proposer_phase0.go",
"proposer_sync_aggregate.go",
"server.go",
@@ -29,6 +30,7 @@ go_library(
"//beacon-chain/cache/depositcache:go_default_library",
"//beacon-chain/core/altair:go_default_library",
"//beacon-chain/core/blocks:go_default_library",
"//beacon-chain/core/execution:go_default_library",
"//beacon-chain/core/feed:go_default_library",
"//beacon-chain/core/feed/block:go_default_library",
"//beacon-chain/core/feed/operation:go_default_library",
@@ -39,6 +41,7 @@ go_library(
"//beacon-chain/core/transition:go_default_library",
"//beacon-chain/core/transition/interop:go_default_library",
"//beacon-chain/core/validators:go_default_library",
"//beacon-chain/db:go_default_library",
"//beacon-chain/operations/attestations:go_default_library",
"//beacon-chain/operations/slashings:go_default_library",
"//beacon-chain/operations/synccommittee:go_default_library",
@@ -68,6 +71,8 @@ go_library(
"//runtime/version:go_default_library",
"//time:go_default_library",
"//time/slots:go_default_library",
"@com_github_ethereum_go_ethereum//common:go_default_library",
"@com_github_ethereum_go_ethereum//eth/catalyst:go_default_library",
"@com_github_ferranbt_fastssz//:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@com_github_prysmaticlabs_eth2_types//:go_default_library",

View File

@@ -13,7 +13,6 @@ import (
coreTime "github.com/prysmaticlabs/prysm/beacon-chain/core/time"
"github.com/prysmaticlabs/prysm/beacon-chain/core/transition"
beaconState "github.com/prysmaticlabs/prysm/beacon-chain/state"
"github.com/prysmaticlabs/prysm/config/features"
"github.com/prysmaticlabs/prysm/config/params"
"github.com/prysmaticlabs/prysm/crypto/rand"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
@@ -125,20 +124,9 @@ func (vs *Server) duties(ctx context.Context, req *ethpb.DutiesRequest) (*ethpb.
return nil, err
}
if s.Slot() < epochStartSlot {
if features.Get().EnableNextSlotStateCache {
headRoot, err := vs.HeadFetcher.HeadRoot(ctx)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not retrieve head root: %v", err)
}
s, err = transition.ProcessSlotsUsingNextSlotCache(ctx, s, headRoot, epochStartSlot)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not process slots up to %d: %v", epochStartSlot, err)
}
} else {
s, err = transition.ProcessSlots(ctx, s, epochStartSlot)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not process slots up to %d: %v", epochStartSlot, err)
}
s, err = transition.ProcessSlots(ctx, s, epochStartSlot)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not process slots up to %d: %v", epochStartSlot, err)
}
}
committeeAssignments, proposerIndexToSlots, err := helpers.CommitteeAssignments(ctx, s, req.Epoch)

View File

@@ -10,6 +10,7 @@ import (
"github.com/prysmaticlabs/prysm/beacon-chain/core/feed"
blockfeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/block"
"github.com/prysmaticlabs/prysm/beacon-chain/core/transition"
"github.com/prysmaticlabs/prysm/beacon-chain/core/transition/interop"
"github.com/prysmaticlabs/prysm/config/params"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
@@ -34,18 +35,29 @@ func (vs *Server) GetBeaconBlock(ctx context.Context, req *ethpb.BlockRequest) (
ctx, span := trace.StartSpan(ctx, "ProposerServer.GetBeaconBlock")
defer span.End()
span.AddAttributes(trace.Int64Attribute("slot", int64(req.Slot)))
if slots.ToEpoch(req.Slot) < params.BeaconConfig().AltairForkEpoch {
blk, err := vs.getPhase0BeaconBlock(ctx, req)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not fetch phase0 beacon block: %v", err)
}
return &ethpb.GenericBeaconBlock{Block: &ethpb.GenericBeaconBlock_Phase0{Phase0: blk}}, nil
} else if slots.ToEpoch(req.Slot) < params.BeaconConfig().MergeForkEpoch {
blk, err := vs.getAltairBeaconBlock(ctx, req)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not fetch Altair beacon block: %v", err)
}
return &ethpb.GenericBeaconBlock{Block: &ethpb.GenericBeaconBlock_Altair{Altair: blk}}, nil
}
blk, err := vs.getAltairBeaconBlock(ctx, req)
blk, err := vs.getMergeBeaconBlock(ctx, req)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not fetch Altair beacon block: %v", err)
return nil, status.Errorf(codes.Internal, "Could not fetch Merge beacon block: %v", err)
}
return &ethpb.GenericBeaconBlock{Block: &ethpb.GenericBeaconBlock_Altair{Altair: blk}}, nil
log.Info("Sending block to client, transaction field is nil: ", blk.Body.ExecutionPayload.Transactions == nil)
return &ethpb.GenericBeaconBlock{Block: &ethpb.GenericBeaconBlock_Merge{Merge: blk}}, nil
}
// GetBlock is called by a proposer during its assigned slot to request a block to sign
@@ -60,6 +72,99 @@ func (vs *Server) GetBlock(ctx context.Context, req *ethpb.BlockRequest) (*ethpb
return vs.getPhase0BeaconBlock(ctx, req)
}
func (vs *Server) getMergeBeaconBlock(ctx context.Context, req *ethpb.BlockRequest) (*ethpb.BeaconBlockMerge, error) {
altairBlk, err := vs.buildAltairBeaconBlock(ctx, req)
if err != nil {
return nil, err
}
payload, err := vs.getExecutionPayload(ctx, req.Slot)
if err != nil {
return nil, errors.Wrap(err, "could not get execution payload")
}
log.WithFields(logrus.Fields{
"blockNumber": payload.BlockNumber,
"blockHash": fmt.Sprintf("%#x", payload.BlockHash),
"parentHash": fmt.Sprintf("%#x", payload.ParentHash),
"coinBase": fmt.Sprintf("%#x", payload.Coinbase),
"gasLimit": payload.GasLimit,
"gasUsed": payload.GasUsed,
"baseFeePerGas": payload.BaseFeePerGas,
"random": fmt.Sprintf("%#x", payload.Random),
"extraData": fmt.Sprintf("%#x", payload.ExtraData),
"txs": payload.Transactions,
}).Info("Retrieved payload")
blk := &ethpb.BeaconBlockMerge{
Slot: altairBlk.Slot,
ProposerIndex: altairBlk.ProposerIndex,
ParentRoot: altairBlk.ParentRoot,
StateRoot: params.BeaconConfig().ZeroHash[:],
Body: &ethpb.BeaconBlockBodyMerge{
RandaoReveal: altairBlk.Body.RandaoReveal,
Eth1Data: altairBlk.Body.Eth1Data,
Graffiti: altairBlk.Body.Graffiti,
ProposerSlashings: altairBlk.Body.ProposerSlashings,
AttesterSlashings: altairBlk.Body.AttesterSlashings,
Attestations: altairBlk.Body.Attestations,
Deposits: altairBlk.Body.Deposits,
VoluntaryExits: altairBlk.Body.VoluntaryExits,
SyncAggregate: altairBlk.Body.SyncAggregate,
ExecutionPayload: payload,
},
}
// Compute state root with the newly constructed block.
wsb, err := wrapper.WrappedMergeSignedBeaconBlock(
&ethpb.SignedBeaconBlockMerge{Block: blk, Signature: make([]byte, 96)},
)
if err != nil {
return nil, err
}
stateRoot, err := vs.computeStateRoot(ctx, wsb)
if err != nil {
interop.WriteBlockToDisk(wsb, true /*failed*/)
return nil, fmt.Errorf("could not compute state root: %v", err)
}
blk.StateRoot = stateRoot
return blk, nil
}
func (vs *Server) buildAltairBeaconBlock(ctx context.Context, req *ethpb.BlockRequest) (*ethpb.BeaconBlockAltair, error) {
ctx, span := trace.StartSpan(ctx, "ProposerServer.buildAltairBeaconBlock")
defer span.End()
blkData, err := vs.buildPhase0BlockData(ctx, req)
if err != nil {
return nil, fmt.Errorf("could not build block data: %v", err)
}
// Use zero hash as stub for state root to compute later.
stateRoot := params.BeaconConfig().ZeroHash[:]
// No need for safe sub as req.Slot cannot be 0 if requesting Altair blocks. If 0, we will be throwing
// an error in the first validity check of this endpoint.
syncAggregate, err := vs.getSyncAggregate(ctx, req.Slot-1, bytesutil.ToBytes32(blkData.ParentRoot))
if err != nil {
return nil, err
}
return &ethpb.BeaconBlockAltair{
Slot: req.Slot,
ParentRoot: blkData.ParentRoot,
StateRoot: stateRoot,
ProposerIndex: blkData.ProposerIdx,
Body: &ethpb.BeaconBlockBodyAltair{
Eth1Data: blkData.Eth1Data,
Deposits: blkData.Deposits,
Attestations: blkData.Attestations,
RandaoReveal: req.RandaoReveal,
ProposerSlashings: blkData.ProposerSlashings,
AttesterSlashings: blkData.AttesterSlashings,
VoluntaryExits: blkData.VoluntaryExits,
Graffiti: blkData.Graffiti[:],
SyncAggregate: syncAggregate,
},
}, nil
}
// ProposeBeaconBlock is called by a proposer during its assigned slot to create a block in an attempt
// to get it processed by the beacon node as the canonical head.
func (vs *Server) ProposeBeaconBlock(ctx context.Context, req *ethpb.GenericSignedBeaconBlock) (*ethpb.ProposeResponse, error) {
@@ -75,6 +180,11 @@ func (vs *Server) ProposeBeaconBlock(ctx context.Context, req *ethpb.GenericSign
if err != nil {
return nil, status.Error(codes.Internal, "could not wrap altair beacon block")
}
case *ethpb.GenericSignedBeaconBlock_Merge:
blk, err = wrapper.WrappedMergeSignedBeaconBlock(b.Merge)
if err != nil {
return nil, status.Error(codes.Internal, "could not wrap merge beacon block")
}
default:
return nil, status.Error(codes.Internal, "block version not supported")
}

View File

@@ -98,6 +98,15 @@ func (a proposerAtts) filter(ctx context.Context, st state.BeaconState) (propose
}
return altair.ProcessAttestationNoVerifySignature(ctx, st, attestation, totalBalance)
}
case version.Merge:
// Use a wrapper here, as go needs strong typing for the function signature.
attestationProcessor = func(ctx context.Context, st state.BeaconState, attestation *ethpb.Attestation) (state.BeaconState, error) {
totalBalance, err := helpers.TotalActiveBalance(st)
if err != nil {
return nil, err
}
return altair.ProcessAttestationNoVerifySignature(ctx, st, attestation, totalBalance)
}
default:
// Exit early if there is an unknown state type.
return validAtts, invalidAtts

View File

@@ -0,0 +1,269 @@
package validator
import (
"context"
"fmt"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/eth/catalyst"
"github.com/pkg/errors"
types "github.com/prysmaticlabs/eth2-types"
"github.com/prysmaticlabs/prysm/beacon-chain/core/execution"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/beacon-chain/core/time"
"github.com/prysmaticlabs/prysm/beacon-chain/core/transition"
"github.com/prysmaticlabs/prysm/config/params"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/runtime/version"
"github.com/prysmaticlabs/prysm/time/slots"
"github.com/sirupsen/logrus"
)
// This returns the execution payload of a given slot. The function has full awareness of pre and post merge.
// Payload is computed given the respected time of merge.
//
// Spec code:
// def prepare_execution_payload(state: BeaconState,
// pow_chain: Dict[Hash32, PowBlock],
// finalized_block_hash: Hash32,
// fee_recipient: ExecutionAddress,
// execution_engine: ExecutionEngine) -> Optional[PayloadId]:
// if not is_merge_complete(state):
// is_terminal_block_hash_set = TERMINAL_BLOCK_HASH != Hash32()
// is_activation_epoch_reached = get_current_epoch(state.slot) >= TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH
// if is_terminal_block_hash_set and not is_activation_epoch_reached:
// # Terminal block hash is set but activation epoch is not yet reached, no prepare payload call is needed
// return None
//
// terminal_pow_block = get_terminal_pow_block(pow_chain)
// if terminal_pow_block is None:
// # Pre-merge, no prepare payload call is needed
// return None
// # Signify merge via producing on top of the terminal PoW block
// parent_hash = terminal_pow_block.block_hash
// else:
// # Post-merge, normal payload
// parent_hash = state.latest_execution_payload_header.block_hash
//
// # Set the forkchoice head and initiate the payload build process
// payload_attributes = PayloadAttributes(
// timestamp=compute_timestamp_at_slot(state, state.slot),
// random=get_randao_mix(state, get_current_epoch(state)),
// fee_recipient=fee_recipient,
// )
// return execution_engine.notify_forkchoice_updated(parent_hash, finalized_block_hash, payload_attributes)
func (vs *Server) getExecutionPayload(ctx context.Context, slot types.Slot) (*ethpb.ExecutionPayload, error) {
// TODO_MERGE: Reuse the same head state as in building phase0 block attestation.
st, err := vs.HeadFetcher.HeadState(ctx)
if err != nil {
return nil, err
}
st, err = transition.ProcessSlots(ctx, st, slot)
if err != nil {
return nil, err
}
var parentHash []byte
var hasTerminalBlock bool
complete, err := execution.IsMergeComplete(st)
if err != nil {
return nil, err
}
if !complete {
if bytesutil.ToBytes32(params.BeaconConfig().TerminalBlockHash.Bytes()) != [32]byte{} {
// `TERMINAL_BLOCK_HASH` is used as an override, the activation epoch must be reached.
isActivationEpochReached := params.BeaconConfig().TerminalBlockHashActivationEpoch <= slots.ToEpoch(slot)
if !isActivationEpochReached {
return execution.EmptyPayload(), nil
}
}
parentHash, hasTerminalBlock, err = vs.getTerminalBlockHash(ctx)
if err != nil {
return nil, err
}
if !hasTerminalBlock {
// No terminal block signals this is pre merge, empty payload is used.
return execution.EmptyPayload(), nil
}
// Terminal block found signals production on top of terminal PoW block.
} else {
// Post merge, normal payload is used.
header, err := st.LatestExecutionPayloadHeader()
if err != nil {
return nil, err
}
parentHash = header.BlockHash
}
t, err := slots.ToTime(st.GenesisTime(), slot)
if err != nil {
return nil, err
}
random, err := helpers.RandaoMix(st, time.CurrentEpoch(st))
if err != nil {
return nil, err
}
finalizedBlock, err := vs.BeaconDB.Block(ctx, bytesutil.ToBytes32(st.FinalizedCheckpoint().Root))
if err != nil {
return nil, err
}
finalizedBlockHash := params.BeaconConfig().ZeroHash[:]
if finalizedBlock != nil && finalizedBlock.Version() == version.Merge {
finalizedPayload, err := finalizedBlock.Block().Body().ExecutionPayload()
if err != nil {
return nil, err
}
finalizedBlockHash = finalizedPayload.BlockHash
}
f := catalyst.ForkchoiceStateV1{
HeadBlockHash: common.BytesToHash(parentHash),
SafeBlockHash: common.BytesToHash(parentHash),
FinalizedBlockHash: common.BytesToHash(finalizedBlockHash),
}
p := catalyst.PayloadAttributesV1{
Timestamp: uint64(t.Unix()),
Random: common.BytesToHash(random),
FeeRecipient: params.BeaconConfig().FeeRecipient,
}
id, err := vs.ExecutionEngineCaller.PreparePayload(ctx, f, p)
if err != nil {
return nil, errors.Wrap(err, "could not prepare payload")
}
data, err := vs.ExecutionEngineCaller.GetPayload(ctx, id)
if err != nil {
return nil, errors.Wrap(err, "could not get payload")
}
return executableDataToExecutionPayload(data), nil
}
func executableDataToExecutionPayload(ed *catalyst.ExecutableDataV1) *ethpb.ExecutionPayload {
return &ethpb.ExecutionPayload{
ParentHash: bytesutil.PadTo(ed.ParentHash.Bytes(), 32),
Coinbase: bytesutil.PadTo(ed.Coinbase.Bytes(), 20),
StateRoot: bytesutil.PadTo(ed.StateRoot.Bytes(), 32),
ReceiptRoot: bytesutil.PadTo(ed.ReceiptRoot.Bytes(), 32),
LogsBloom: bytesutil.PadTo(ed.LogsBloom, 256),
Random: bytesutil.PadTo(ed.Random.Bytes(), 32),
BlockNumber: ed.Number,
GasLimit: ed.GasLimit,
GasUsed: ed.GasUsed,
Timestamp: ed.Timestamp,
ExtraData: ed.ExtraData,
BaseFeePerGas: bytesutil.PadTo(ed.BaseFeePerGas.Bytes(), 32),
BlockHash: bytesutil.PadTo(ed.BlockHash.Bytes(), 32),
Transactions: ed.Transactions,
}
}
// This returns the valid terminal block hash with an existence bool value.
//
// Spec code:
// def get_terminal_pow_block(pow_chain: Dict[Hash32, PowBlock]) -> Optional[PowBlock]:
// if TERMINAL_BLOCK_HASH != Hash32():
// # Terminal block hash override takes precedence over terminal total difficulty
// if TERMINAL_BLOCK_HASH in pow_chain:
// return pow_chain[TERMINAL_BLOCK_HASH]
// else:
// return None
//
// return get_pow_block_at_terminal_total_difficulty(pow_chain)
func (vs *Server) getTerminalBlockHash(ctx context.Context) ([]byte, bool, error) {
terminalBlockHash := params.BeaconConfig().TerminalBlockHash
// Terminal block hash override takes precedence over terminal total difficult.
if params.BeaconConfig().TerminalBlockHash != params.BeaconConfig().ZeroHash {
e, _, err := vs.Eth1BlockFetcher.BlockExists(ctx, terminalBlockHash)
if err != nil {
return nil, false, err
}
if !e {
return nil, false, nil
}
return terminalBlockHash.Bytes(), true, nil
}
return vs.getPowBlockHashAtTerminalTotalDifficulty(ctx)
}
// This returns the valid terminal block hash based on total difficulty.
//
// Spec code:
// def get_pow_block_at_terminal_total_difficulty(pow_chain: Dict[Hash32, PowBlock]) -> Optional[PowBlock]:
// # `pow_chain` abstractly represents all blocks in the PoW chain
// for block in pow_chain:
// parent = pow_chain[block.parent_hash]
// block_reached_ttd = block.total_difficulty >= TERMINAL_TOTAL_DIFFICULTY
// parent_reached_ttd = parent.total_difficulty >= TERMINAL_TOTAL_DIFFICULTY
// if block_reached_ttd and not parent_reached_ttd:
// return block
//
// return None
func (vs *Server) getPowBlockHashAtTerminalTotalDifficulty(ctx context.Context) ([]byte, bool, error) {
blk, err := vs.ExecutionEngineCaller.LatestExecutionBlock()
if err != nil {
return nil, false, errors.Wrap(err, "could not get latest execution block")
}
parentBlk, err := vs.ExecutionEngineCaller.ExecutionBlockByHash(common.HexToHash(blk.ParentHash))
if err != nil {
return nil, false, errors.Wrap(err, "could not get parent execution block")
}
if parentBlk == nil {
return nil, false, nil
}
terminalTotalDifficulty := new(big.Int)
terminalTotalDifficulty.SetUint64(params.BeaconConfig().TerminalTotalDifficulty)
currentTotalDifficulty := common.HexToHash(blk.TotalDifficulty).Big()
parentTotalDifficulty := common.HexToHash(parentBlk.TotalDifficulty).Big()
blkNumber := blk.Number
// TODO_MERGE: This can theoretically loop indefinitely. More discussion: https://github.com/ethereum/consensus-specs/issues/2636
logged := false
for {
blockReachedTTD := currentTotalDifficulty.Cmp(terminalTotalDifficulty) >= 0
parentReachedTTD := terminalTotalDifficulty.Cmp(parentTotalDifficulty) >= 0
if blockReachedTTD && parentReachedTTD {
log.WithFields(logrus.Fields{
"currentTotalDifficulty": currentTotalDifficulty,
"parentTotalDifficulty": parentTotalDifficulty,
"terminalTotalDifficulty": terminalTotalDifficulty,
"terminalBlockHash": fmt.Sprintf("%#x", common.HexToHash(blk.Hash)),
"terminalBlockNumber": blkNumber,
}).Info("'Terminal difficulty reached")
return common.HexToHash(blk.Hash).Bytes(), true, err
} else {
if !logged {
log.WithFields(logrus.Fields{
"currentTotalDifficulty": currentTotalDifficulty,
"parentTotalDifficulty": parentTotalDifficulty,
"terminalTotalDifficulty": terminalTotalDifficulty,
"terminalBlockHash": fmt.Sprintf("%#x", common.HexToHash(blk.Hash)),
"terminalBlockNumber": blkNumber,
}).Info("Terminal difficulty NOT reached")
logged = true
}
blk := parentBlk
blkNumber = blk.Number
// TODO_MERGE: Add pow block cache to avoid requesting seen block.
parentBlk, err = vs.ExecutionEngineCaller.ExecutionBlockByHash(common.HexToHash(blk.ParentHash))
if err != nil {
return nil, false, err
}
if parentBlk == nil {
return nil, false, nil
}
currentTotalDifficulty = common.HexToHash(blk.TotalDifficulty).Big()
parentTotalDifficulty = common.HexToHash(parentBlk.TotalDifficulty).Big()
}
}
}

View File

@@ -16,6 +16,7 @@ import (
opfeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/operation"
statefeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/state"
"github.com/prysmaticlabs/prysm/beacon-chain/core/signing"
"github.com/prysmaticlabs/prysm/beacon-chain/db"
"github.com/prysmaticlabs/prysm/beacon-chain/operations/attestations"
"github.com/prysmaticlabs/prysm/beacon-chain/operations/slashings"
"github.com/prysmaticlabs/prysm/beacon-chain/operations/synccommittee"
@@ -63,6 +64,8 @@ type Server struct {
PendingDepositsFetcher depositcache.PendingDepositsFetcher
OperationNotifier opfeed.Notifier
StateGen stategen.StateManager
ExecutionEngineCaller powchain.ExecutionEngineCaller
BeaconDB db.HeadAccessDatabase
}
// WaitForActivation checks if a validator public key exists in the active validator registry of the current

View File

@@ -108,6 +108,7 @@ type Config struct {
OperationNotifier opfeed.Notifier
StateGen *stategen.State
MaxMsgSize int
ExecutionEngineCaller powchain.ExecutionEngineCaller
}
// NewService instantiates a new RPC service instance that will
@@ -194,6 +195,8 @@ func (s *Service) Start() {
SlashingsPool: s.cfg.SlashingsPool,
StateGen: s.cfg.StateGen,
SyncCommitteePool: s.cfg.SyncCommitteeObjectPool,
ExecutionEngineCaller: s.cfg.ExecutionEngineCaller,
BeaconDB: s.cfg.BeaconDB,
}
validatorServerV1 := &validator.Server{
HeadFetcher: s.cfg.HeadFetcher,
@@ -382,7 +385,7 @@ func (s *Service) logNewClientConnection(ctx context.Context) {
if !s.connectedRPCClients[clientInfo.Addr] {
log.WithFields(logrus.Fields{
"addr": clientInfo.Addr.String(),
}).Infof("NewService gRPC client connected to beacon node")
}).Infof("New gRPC client connected to beacon node")
s.connectedRPCClients[clientInfo.Addr] = true
}
}

View File

@@ -17,6 +17,7 @@ type BeaconState interface {
WriteOnlyBeaconState
Copy() BeaconState
HashTreeRoot(ctx context.Context) ([32]byte, error)
Version() int
FutureForkStub
}
@@ -42,7 +43,7 @@ type ReadOnlyBeaconState interface {
FieldReferencesCount() map[string]uint64
MarshalSSZ() ([]byte, error)
IsNil() bool
Version() int
LatestExecutionPayloadHeader() (*ethpb.ExecutionPayloadHeader, error)
}
// WriteOnlyBeaconState defines a struct which only has write access to beacon state methods.
@@ -64,6 +65,7 @@ type WriteOnlyBeaconState interface {
SetSlashings(val []uint64) error
UpdateSlashingsAtIndex(idx, val uint64) error
AppendHistoricalRoots(root [32]byte) error
SetLatestExecutionPayloadHeader(val *ethpb.ExecutionPayloadHeader) error
}
// ReadOnlyValidator defines a struct which only has read access to validator methods.

View File

@@ -44,7 +44,7 @@ func (s *State) StateByRoot(ctx context.Context, blockRoot [32]byte) (state.Beac
// Genesis case. If block root is zero hash, short circuit to use genesis cachedState stored in DB.
if blockRoot == params.BeaconConfig().ZeroHash {
return s.beaconDB.GenesisState(ctx)
return s.beaconDB.State(ctx, blockRoot)
}
return s.loadStateByRoot(ctx, blockRoot)
}
@@ -57,7 +57,7 @@ func (s *State) StateByRoot(ctx context.Context, blockRoot [32]byte) (state.Beac
func (s *State) StateByRootInitialSync(ctx context.Context, blockRoot [32]byte) (state.BeaconState, error) {
// Genesis case. If block root is zero hash, short circuit to use genesis state stored in DB.
if blockRoot == params.BeaconConfig().ZeroHash {
return s.beaconDB.GenesisState(ctx)
return s.beaconDB.State(ctx, blockRoot)
}
// To invalidate cache for parent root because pre state will get mutated.

View File

@@ -16,23 +16,6 @@ import (
"github.com/prysmaticlabs/prysm/testing/util"
)
func TestStateByRoot_GenesisState(t *testing.T) {
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
service := New(beaconDB)
b := util.NewBeaconBlock()
bRoot, err := b.Block.HashTreeRoot()
require.NoError(t, err)
beaconState, _ := util.DeterministicGenesisState(t, 32)
require.NoError(t, service.beaconDB.SaveState(ctx, beaconState, bRoot))
require.NoError(t, service.beaconDB.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(b)))
require.NoError(t, service.beaconDB.SaveGenesisBlockRoot(ctx, bRoot))
loadedState, err := service.StateByRoot(ctx, params.BeaconConfig().ZeroHash) // Zero hash is genesis state root.
require.NoError(t, err)
require.DeepSSZEqual(t, loadedState.InnerStateUnsafe(), beaconState.InnerStateUnsafe())
}
func TestStateByRoot_ColdState(t *testing.T) {
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
@@ -115,23 +98,6 @@ func TestStateByRoot_HotStateCached(t *testing.T) {
require.DeepSSZEqual(t, loadedState.InnerStateUnsafe(), beaconState.InnerStateUnsafe())
}
func TestStateByRoot_StateByRootInitialSync(t *testing.T) {
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
service := New(beaconDB)
b := util.NewBeaconBlock()
bRoot, err := b.Block.HashTreeRoot()
require.NoError(t, err)
beaconState, _ := util.DeterministicGenesisState(t, 32)
require.NoError(t, service.beaconDB.SaveState(ctx, beaconState, bRoot))
require.NoError(t, service.beaconDB.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(b)))
require.NoError(t, service.beaconDB.SaveGenesisBlockRoot(ctx, bRoot))
loadedState, err := service.StateByRootInitialSync(ctx, params.BeaconConfig().ZeroHash) // Zero hash is genesis state root.
require.NoError(t, err)
require.DeepSSZEqual(t, loadedState.InnerStateUnsafe(), beaconState.InnerStateUnsafe())
}
func TestStateByRootInitialSync_UseEpochStateCache(t *testing.T) {
ctx := context.Background()
beaconDB := testDB.SetupDB(t)

View File

@@ -24,7 +24,7 @@ func NewMockService() *MockStateManager {
}
// Resume --
func (m *MockStateManager) Resume(_ context.Context, _ state.BeaconState) (state.BeaconState, error) {
func (m *MockStateManager) Resume(_ context.Context) (state.BeaconState, error) {
panic("implement me")
}

View File

@@ -3,20 +3,18 @@ package stategen
import (
"context"
"fmt"
"time"
"github.com/pkg/errors"
types "github.com/prysmaticlabs/eth2-types"
"github.com/prysmaticlabs/prysm/beacon-chain/core/altair"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
prysmTime "github.com/prysmaticlabs/prysm/beacon-chain/core/time"
"github.com/prysmaticlabs/prysm/beacon-chain/core/time"
"github.com/prysmaticlabs/prysm/beacon-chain/core/transition"
"github.com/prysmaticlabs/prysm/beacon-chain/db/filters"
"github.com/prysmaticlabs/prysm/beacon-chain/state"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/block"
"github.com/prysmaticlabs/prysm/runtime/version"
"github.com/sirupsen/logrus"
"go.opencensus.io/trace"
)
@@ -30,13 +28,7 @@ func (s *State) ReplayBlocks(
ctx, span := trace.StartSpan(ctx, "stateGen.ReplayBlocks")
defer span.End()
var err error
start := time.Now()
log.WithFields(logrus.Fields{
"startSlot": state.Slot(),
"endSlot": targetSlot,
"diff": targetSlot - state.Slot(),
}).Debug("Replaying state")
log.Debugf("Replaying state from slot %d till slot %d", state.Slot(), targetSlot)
// The input block list is sorted in decreasing slots order.
if len(signed) > 0 {
for i := len(signed) - 1; i >= 0; i-- {
@@ -65,11 +57,6 @@ func (s *State) ReplayBlocks(
}
}
duration := time.Since(start)
log.WithFields(logrus.Fields{
"duration": duration,
}).Debug("Replayed state")
return state, nil
}
@@ -162,7 +149,7 @@ func executeStateTransitionStateGen(
if err != nil {
return nil, errors.Wrap(err, "could not process block")
}
if signed.Version() == version.Altair {
if signed.Version() == version.Altair || signed.Version() == version.Merge {
sa, err := signed.Block().Body().SyncAggregate()
if err != nil {
return nil, err
@@ -201,7 +188,7 @@ func processSlotsStateGen(ctx context.Context, state state.BeaconState, slot typ
if err != nil {
return nil, errors.Wrap(err, "could not process slot")
}
if prysmTime.CanProcessEpoch(state) {
if time.CanProcessEpoch(state) {
switch state.Version() {
case version.Phase0:
state, err = transition.ProcessEpochPrecompute(ctx, state)
@@ -213,6 +200,11 @@ func processSlotsStateGen(ctx context.Context, state state.BeaconState, slot typ
if err != nil {
return nil, errors.Wrap(err, "could not process epoch with optimization")
}
case version.Merge:
state, err = altair.ProcessEpoch(ctx, state)
if err != nil {
return nil, errors.Wrap(err, "could not process epoch with optimization")
}
default:
return nil, errors.New("beacon state should have a version")
}
@@ -221,7 +213,7 @@ func processSlotsStateGen(ctx context.Context, state state.BeaconState, slot typ
return nil, err
}
if prysmTime.CanUpgradeToAltair(state.Slot()) {
if time.CanUpgradeToAltair(state.Slot()) {
state, err = altair.UpgradeToAltair(ctx, state)
if err != nil {
return nil, err

View File

@@ -23,7 +23,7 @@ var defaultHotStateDBInterval types.Slot = 128
// StateManager represents a management object that handles the internal
// logic of maintaining both hot and cold states in DB.
type StateManager interface {
Resume(ctx context.Context, fState state.BeaconState) (state.BeaconState, error)
Resume(ctx context.Context) (state.BeaconState, error)
SaveFinalizedState(fSlot types.Slot, fRoot [32]byte, fState state.BeaconState)
MigrateToCold(ctx context.Context, fRoot [32]byte) error
ReplayBlocks(ctx context.Context, state state.BeaconState, signed []block.SignedBeaconBlock, targetSlot types.Slot) (state.BeaconState, error)
@@ -84,7 +84,7 @@ func New(beaconDB db.NoHeadAccessDatabase) *State {
}
// Resume resumes a new state management object from previously saved finalized check point in DB.
func (s *State) Resume(ctx context.Context, fState state.BeaconState) (state.BeaconState, error) {
func (s *State) Resume(ctx context.Context) (state.BeaconState, error) {
ctx, span := trace.StartSpan(ctx, "stateGen.Resume")
defer span.End()
@@ -97,9 +97,12 @@ func (s *State) Resume(ctx context.Context, fState state.BeaconState) (state.Bea
if fRoot == params.BeaconConfig().ZeroHash {
return s.beaconDB.GenesisState(ctx)
}
fState, err := s.StateByRoot(ctx, fRoot)
if err != nil {
return nil, err
}
if fState == nil || fState.IsNil() {
return nil, errors.New("finalized state is nil")
return nil, errors.New("finalized state not found in disk")
}
go func() {

View File

@@ -28,7 +28,7 @@ func TestResume(t *testing.T) {
require.NoError(t, service.beaconDB.SaveGenesisBlockRoot(ctx, root))
require.NoError(t, service.beaconDB.SaveFinalizedCheckpoint(ctx, &ethpb.Checkpoint{Root: root[:]}))
resumeState, err := service.Resume(ctx, beaconState)
resumeState, err := service.Resume(ctx)
require.NoError(t, err)
require.DeepSSZEqual(t, beaconState.InnerStateUnsafe(), resumeState.InnerStateUnsafe())
assert.Equal(t, params.BeaconConfig().SlotsPerEpoch, service.finalizedInfo.slot, "Did not get watned slot")

View File

@@ -17,7 +17,6 @@ go_library(
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil",
visibility = [
"//beacon-chain:__subpackages__",
"//crypto/hash:__subpackages__",
"//proto/migration:__subpackages__",
"//proto/prysm/v1alpha1:__subpackages__",
"//proto/testing:__subpackages__",

View File

@@ -54,236 +54,6 @@ func ValidatorRootWithHasher(hasher ssz.HashFn, validator *ethpb.Validator) ([32
}
return ssz.BitwiseMerkleizeArrays(hasher, fieldRoots, uint64(len(fieldRoots)), uint64(len(fieldRoots)))
}
func merkleizeFlatArrayAVX(vec [][32]byte,
depth uint8,
hasher func([][32]byte, [][32]byte, uint64),
zero_hash_array [][32]byte) [32]byte {
if depth == 0 && len(vec) == 1 {
return vec[0]
}
if len(vec) == 0 {
panic("Can't have empty vec")
}
// allocate size for the buffer (everything hardcoded cause
layer := (len(vec) + 1) / 2
length := 0
for {
length += layer - 1
if layer == 1 {
break
}
layer = (layer + 1) / 2
}
length += int(depth)
hash_tree := make([][32]byte, length)
first := uint64(0)
height := uint8(1)
last := uint64(len(vec)+1) / 2
if len(vec) > 1 {
hasher(hash_tree, vec, last)
}
if len(vec)%2 == 1 {
hash_tree[last-1] = hash.Hash2ChunksAVX(vec[len(vec)-1], zero_hash_array[0])
}
for {
dist := last - first
if dist < 2 {
break
}
hasher(hash_tree[last:], hash_tree[first:], dist/2)
first = last
last += (dist + 1) / 2
if dist%2 != 0 {
hash_tree[last-1] = hash.Hash2ChunksAVX(hash_tree[first-1], zero_hash_array[height])
}
height++
}
for {
if height >= depth {
break
}
hash_tree[last] = hash.Hash2ChunksAVX(hash_tree[last-1], zero_hash_array[height])
last++
height++
}
return hash_tree[last-1]
}
func merkleizeFlatArrayAVX2(vec [][32]byte,
depth uint8,
hasher func([][32]byte, [][32]byte, uint64),
zero_hash_array [][32]byte) [32]byte {
if depth == 0 && len(vec) == 1 {
return vec[0]
}
if len(vec) == 0 {
panic("Can't have empty vec")
}
// allocate size for the buffer (everything hardcoded cause
layer := (len(vec) + 1) / 2
length := 0
for {
length += layer - 1
if layer == 1 {
break
}
layer = (layer + 1) / 2
}
length += int(depth)
hash_tree := make([][32]byte, length)
first := uint64(0)
height := uint8(1)
last := uint64(len(vec)+1) / 2
if len(vec) > 1 {
hasher(hash_tree, vec, last)
}
if len(vec)%2 == 1 {
hash_tree[last-1] = hash.Hash2ChunksAVX2(vec[len(vec)-1], zero_hash_array[0])
}
for {
dist := last - first
if dist < 2 {
break
}
hasher(hash_tree[last:], hash_tree[first:], dist/2)
first = last
last += (dist + 1) / 2
if dist%2 != 0 {
hash_tree[last-1] = hash.Hash2ChunksAVX2(hash_tree[first-1], zero_hash_array[height])
}
height++
}
for {
if height >= depth {
break
}
hash_tree[last] = hash.Hash2ChunksAVX2(hash_tree[last-1], zero_hash_array[height])
last++
height++
}
return hash_tree[last-1]
}
func merkleizeFlatArray(vec [][32]byte,
depth uint8,
hasher func([][32]byte, [][32]byte, uint64),
zero_hash_array [][32]byte) [32]byte {
if depth == 0 && len(vec) == 1 {
return vec[0]
}
if len(vec) == 0 {
panic("Can't have empty vec")
}
// allocate size for the buffer (everything hardcoded cause
layer := (len(vec) + 1) / 2
length := 0
for {
length += layer - 1
if layer == 1 {
break
}
layer = (layer + 1) / 2
}
length += int(depth)
hash_tree := make([][32]byte, length)
first := uint64(0)
height := uint8(1)
last := uint64(len(vec)+1) / 2
if len(vec) > 1 {
hasher(hash_tree, vec, last)
}
if len(vec)%2 == 1 {
hash_tree[last-1] = hash.Hash2ChunksShani(vec[len(vec)-1], zero_hash_array[0])
}
for {
dist := last - first
if dist < 2 {
break
}
hasher(hash_tree[last:], hash_tree[first:], dist/2)
first = last
last += (dist + 1) / 2
if dist%2 != 0 {
hash_tree[last-1] = hash.Hash2ChunksShani(hash_tree[first-1], zero_hash_array[height])
}
height++
}
for {
if height >= depth {
break
}
hash_tree[last] = hash.Hash2ChunksShani(hash_tree[last-1], zero_hash_array[height])
last++
height++
}
return hash_tree[last-1]
}
// Uint64ListRootWithRegistryLimitShani computes the HashTreeRoot Merkleization of
// a list of uint64 and mixed with registry limit. Flat array implementation
// using Shani extensions
func Uint64ListRootWithRegistryLimitShani(balances []uint64, zero_hash_array [][32]byte) ([32]byte, error) {
// assume len(balances) is multiple of 4 for this benchmark
lenChunks := len(balances) / 4
balancesChunks := make([][32]byte, lenChunks)
for i := 0; i < lenChunks; i++ {
binary.LittleEndian.PutUint64(balancesChunks[i][:], balances[4*i])
binary.LittleEndian.PutUint64(balancesChunks[i][8:], balances[4*i+1])
binary.LittleEndian.PutUint64(balancesChunks[i][16:], balances[4*i+2])
binary.LittleEndian.PutUint64(balancesChunks[i][24:], balances[4*i+3])
}
balancesRootsRoot := merkleizeFlatArray(balancesChunks, 38, hash.PotuzHasherShaniChunks, zero_hash_array)
return hash.MixinLengthShani(balancesRootsRoot, uint64(len(balances))), nil
}
// Uint64ListRootWithRegistryLimitAVX computes the HashTreeRoot Merkleization of
// a list of uint64 and mixed with registry limit. Flat array implementation
// using Shani extensions
func Uint64ListRootWithRegistryLimitAVX(balances []uint64, zero_hash_array [][32]byte) ([32]byte, error) {
// assume len(balances) is multiple of 4 for this benchmark
lenChunks := len(balances) / 4
balancesChunks := make([][32]byte, lenChunks)
for i := 0; i < lenChunks; i++ {
binary.LittleEndian.PutUint64(balancesChunks[i][:], balances[4*i])
binary.LittleEndian.PutUint64(balancesChunks[i][8:], balances[4*i+1])
binary.LittleEndian.PutUint64(balancesChunks[i][16:], balances[4*i+2])
binary.LittleEndian.PutUint64(balancesChunks[i][24:], balances[4*i+3])
}
balancesRootsRoot := merkleizeFlatArrayAVX(balancesChunks, 38, hash.PotuzHasherAVXChunks, zero_hash_array)
return hash.MixinLengthAVX(balancesRootsRoot, uint64(len(balances))), nil
}
// Uint64ListRootWithRegistryLimitAVX2 computes the HashTreeRoot Merkleization of
// a list of uint64 and mixed with registry limit. Flat array implementation
// using Shani extensions
func Uint64ListRootWithRegistryLimitAVX2(balances []uint64, zero_hash_array [][32]byte) ([32]byte, error) {
// assume len(balances) is multiple of 4 for this benchmark
lenChunks := len(balances) / 4
balancesChunks := make([][32]byte, lenChunks)
for i := 0; i < lenChunks; i++ {
binary.LittleEndian.PutUint64(balancesChunks[i][:], balances[4*i])
binary.LittleEndian.PutUint64(balancesChunks[i][8:], balances[4*i+1])
binary.LittleEndian.PutUint64(balancesChunks[i][16:], balances[4*i+2])
binary.LittleEndian.PutUint64(balancesChunks[i][24:], balances[4*i+3])
}
balancesRootsRoot := merkleizeFlatArrayAVX2(balancesChunks, 38, hash.PotuzHasherAVX2Chunks, zero_hash_array)
return hash.MixinLengthAVX2(balancesRootsRoot, uint64(len(balances))), nil
}
// Uint64ListRootWithRegistryLimit computes the HashTreeRoot Merkleization of
// a list of uint64 and mixed with registry limit.

View File

@@ -54,12 +54,12 @@ func (f FieldIndex) String(stateVersion int) string {
case Slashings:
return "slashings"
case PreviousEpochAttestations:
if version.Altair == stateVersion {
if version.Altair == stateVersion || version.Merge == stateVersion {
return "previousEpochParticipationBits"
}
return "previousEpochAttestations"
case CurrentEpochAttestations:
if version.Altair == stateVersion {
if version.Altair == stateVersion || version.Merge == stateVersion {
return "currentEpochParticipationBits"
}
return "currentEpochAttestations"
@@ -77,6 +77,8 @@ func (f FieldIndex) String(stateVersion int) string {
return "currentSyncCommittee"
case NextSyncCommittee:
return "nextSyncCommittee"
case LatestExecutionPayloadHeader:
return "latestExecutionPayloadHeader"
default:
return ""
}
@@ -114,12 +116,13 @@ const (
InactivityScores
CurrentSyncCommittee
NextSyncCommittee
// State fields added in Merge.
LatestExecutionPayloadHeader
)
// Altair fields which replaced previous phase 0 fields.
const (
// Epoch Attestations is switched with participation bits in
// Altair.
// Epoch Attestations is switched with participation bits in Altair.
PreviousEpochParticipationBits = PreviousEpochAttestations
CurrentEpochParticipationBits = CurrentEpochAttestations
)

View File

@@ -29,3 +29,8 @@ func (b *BeaconState) CurrentSyncCommittee() (*ethpb.SyncCommittee, error) {
func (b *BeaconState) NextSyncCommittee() (*ethpb.SyncCommittee, error) {
return nil, errors.New("NextSyncCommittee is not supported for phase 0 beacon state")
}
// LatestExecutionPayloadHeader is not supported for phase 0 beacon state.
func (b *BeaconState) LatestExecutionPayloadHeader() (*ethpb.ExecutionPayloadHeader, error) {
return nil, errors.New("LatestExecutionPayloadHeader is not supported for phase 0 beacon state")
}

View File

@@ -44,3 +44,8 @@ func (b *BeaconState) SetCurrentParticipationBits(val []byte) error {
func (b *BeaconState) SetInactivityScores(val []uint64) error {
return errors.New("SetInactivityScores is not supported for phase 0 beacon state")
}
// SetLatestExecutionPayloadHeader is not supported for phase 0 beacon state.
func (b *BeaconState) SetLatestExecutionPayloadHeader(val *ethpb.ExecutionPayloadHeader) error {
return errors.New("SetLatestExecutionPayloadHeader is not supported for phase 0 beacon state")
}

View File

@@ -14,3 +14,8 @@ func (b *BeaconState) PreviousEpochAttestations() ([]*ethpb.PendingAttestation,
func (b *BeaconState) CurrentEpochAttestations() ([]*ethpb.PendingAttestation, error) {
return nil, errors.New("CurrentEpochAttestations is not supported for hard fork 1 beacon state")
}
// LatestExecutionPayloadHeader is not supported for phase 0 beacon state.
func (b *BeaconState) LatestExecutionPayloadHeader() (*ethpb.ExecutionPayloadHeader, error) {
return nil, errors.New("LatestExecutionPayloadHeader is not supported for hard fork 1 beacon state")
}

View File

@@ -2,6 +2,7 @@ package v2
import (
"github.com/pkg/errors"
v1 "github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
)
@@ -29,3 +30,13 @@ func (b *BeaconState) AppendPreviousEpochAttestations(val *ethpb.PendingAttestat
func (b *BeaconState) RotateAttestations() error {
return errors.New("RotateAttestations is not supported for hard fork 1 beacon state")
}
// ToProto is not supported for HF1 beacon state.
func (b *BeaconState) ToProto() (*v1.BeaconState, error) {
return nil, errors.New("ToProto is not yet supported for hard fork 1 beacon state")
}
// SetLatestExecutionPayloadHeader is not supported for phase 0 beacon state.
func (b *BeaconState) SetLatestExecutionPayloadHeader(val *ethpb.ExecutionPayloadHeader) error {
return errors.New("SetLatestExecutionPayloadHeader is not supported for hard fork 1 beacon state")
}

View File

@@ -0,0 +1,48 @@
load("@prysm//tools/go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = [
"deprecated_getters.go",
"deprecated_setters.go",
"field_root_eth1.go",
"field_root_validator.go",
"field_root_vector.go",
"field_roots.go",
"getters.go",
"setters.go",
"state_trie.go",
"types.go",
],
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/state/v3",
visibility = [
"//beacon-chain:__subpackages__",
"//proto/migration:__subpackages__",
"//runtime/interop:__subpackages__",
"//shared/testutil:__pkg__",
"//testing/spectest:__subpackages__",
"//testing/util:__pkg__",
],
deps = [
"//beacon-chain/state:go_default_library",
"//beacon-chain/state/fieldtrie:go_default_library",
"//beacon-chain/state/stateutil:go_default_library",
"//beacon-chain/state/types:go_default_library",
"//beacon-chain/state/v1:go_default_library",
"//config/features:go_default_library",
"//config/params:go_default_library",
"//container/slice:go_default_library",
"//crypto/hash:go_default_library",
"//encoding/bytesutil:go_default_library",
"//encoding/ssz:go_default_library",
"//proto/eth/v1:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//runtime/version:go_default_library",
"@com_github_dgraph_io_ristretto//:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@com_github_prysmaticlabs_eth2_types//:go_default_library",
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
"@io_opencensus_go//trace:go_default_library",
"@org_golang_google_protobuf//proto:go_default_library",
],
)

View File

@@ -0,0 +1,16 @@
package v3
import (
"github.com/pkg/errors"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
)
// PreviousEpochAttestations is not supported for HF1 beacon state.
func (b *BeaconState) PreviousEpochAttestations() ([]*ethpb.PendingAttestation, error) {
return nil, errors.New("PreviousEpochAttestations is not supported for Merge beacon state")
}
// CurrentEpochAttestations is not supported for HF1 beacon state.
func (b *BeaconState) CurrentEpochAttestations() ([]*ethpb.PendingAttestation, error) {
return nil, errors.New("CurrentEpochAttestations is not supported for Merge beacon state")
}

View File

@@ -0,0 +1,37 @@
package v3
import (
"github.com/pkg/errors"
v1 "github.com/prysmaticlabs/prysm/proto/eth/v1"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
)
// SetPreviousEpochAttestations is not supported for HF1 beacon state.
func (b *BeaconState) SetPreviousEpochAttestations(val []*ethpb.PendingAttestation) error {
return errors.New("SetPreviousEpochAttestations is not supported for Merge beacon state")
}
// SetCurrentEpochAttestations is not supported for HF1 beacon state.
func (b *BeaconState) SetCurrentEpochAttestations(val []*ethpb.PendingAttestation) error {
return errors.New("SetCurrentEpochAttestations is not supported for Merge beacon state")
}
// AppendCurrentEpochAttestations is not supported for HF1 beacon state.
func (b *BeaconState) AppendCurrentEpochAttestations(val *ethpb.PendingAttestation) error {
return errors.New("AppendCurrentEpochAttestations is not supported for Merge beacon state")
}
// AppendPreviousEpochAttestations is not supported for HF1 beacon state.
func (b *BeaconState) AppendPreviousEpochAttestations(val *ethpb.PendingAttestation) error {
return errors.New("AppendPreviousEpochAttestations is not supported for Merge beacon state")
}
// RotateAttestations is not supported for HF1 beacon state.
func (b *BeaconState) RotateAttestations() error {
return errors.New("RotateAttestations is not supported for Merge beacon state")
}
// ToProto is not supported for HF1 beacon state.
func (b *BeaconState) ToProto() (*v1.BeaconState, error) {
return nil, errors.New("ToProto is not yet supported for Merge beacon state")
}

View File

@@ -0,0 +1,59 @@
package v3
import (
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
"github.com/prysmaticlabs/prysm/config/features"
"github.com/prysmaticlabs/prysm/encoding/ssz"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
)
// eth1Root computes the HashTreeRoot Merkleization of
// a BeaconBlockHeader struct according to the eth2
// Simple Serialize specification.
func eth1Root(hasher ssz.HashFn, eth1Data *ethpb.Eth1Data) ([32]byte, error) {
if eth1Data == nil {
return [32]byte{}, errors.New("nil eth1 data")
}
enc := stateutil.Eth1DataEncKey(eth1Data)
if features.Get().EnableSSZCache {
if found, ok := cachedHasher.rootsCache.Get(string(enc)); ok && found != nil {
return found.([32]byte), nil
}
}
root, err := stateutil.Eth1DataRootWithHasher(hasher, eth1Data)
if err != nil {
return [32]byte{}, err
}
if features.Get().EnableSSZCache {
cachedHasher.rootsCache.Set(string(enc), root, 32)
}
return root, nil
}
// eth1DataVotesRoot computes the HashTreeRoot Merkleization of
// a list of Eth1Data structs according to the eth2
// Simple Serialize specification.
func eth1DataVotesRoot(eth1DataVotes []*ethpb.Eth1Data) ([32]byte, error) {
hashKey, err := stateutil.Eth1DatasEncKey(eth1DataVotes)
if err != nil {
return [32]byte{}, err
}
if features.Get().EnableSSZCache {
if found, ok := cachedHasher.rootsCache.Get(string(hashKey[:])); ok && found != nil {
return found.([32]byte), nil
}
}
root, err := stateutil.Eth1DatasRoot(eth1DataVotes)
if err != nil {
return [32]byte{}, err
}
if features.Get().EnableSSZCache {
cachedHasher.rootsCache.Set(string(hashKey[:]), root, 32)
}
return root, nil
}

View File

@@ -0,0 +1,89 @@
package v3
import (
"bytes"
"encoding/binary"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
"github.com/prysmaticlabs/prysm/config/features"
"github.com/prysmaticlabs/prysm/config/params"
"github.com/prysmaticlabs/prysm/crypto/hash"
"github.com/prysmaticlabs/prysm/encoding/ssz"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
)
func (h *stateRootHasher) validatorRegistryRoot(validators []*ethpb.Validator) ([32]byte, error) {
hashKeyElements := make([]byte, len(validators)*32)
roots := make([][32]byte, len(validators))
emptyKey := hash.FastSum256(hashKeyElements)
hasher := hash.CustomSHA256Hasher()
bytesProcessed := 0
for i := 0; i < len(validators); i++ {
val, err := h.validatorRoot(hasher, validators[i])
if err != nil {
return [32]byte{}, errors.Wrap(err, "could not compute validators merkleization")
}
copy(hashKeyElements[bytesProcessed:bytesProcessed+32], val[:])
roots[i] = val
bytesProcessed += 32
}
hashKey := hash.FastSum256(hashKeyElements)
if hashKey != emptyKey && h.rootsCache != nil {
if found, ok := h.rootsCache.Get(string(hashKey[:])); found != nil && ok {
return found.([32]byte), nil
}
}
validatorsRootsRoot, err := ssz.BitwiseMerkleizeArrays(hasher, roots, uint64(len(roots)), params.BeaconConfig().ValidatorRegistryLimit)
if err != nil {
return [32]byte{}, errors.Wrap(err, "could not compute validator registry merkleization")
}
validatorsRootsBuf := new(bytes.Buffer)
if err := binary.Write(validatorsRootsBuf, binary.LittleEndian, uint64(len(validators))); err != nil {
return [32]byte{}, errors.Wrap(err, "could not marshal validator registry length")
}
// We need to mix in the length of the slice.
var validatorsRootsBufRoot [32]byte
copy(validatorsRootsBufRoot[:], validatorsRootsBuf.Bytes())
res := ssz.MixInLength(validatorsRootsRoot, validatorsRootsBufRoot[:])
if hashKey != emptyKey && h.rootsCache != nil {
h.rootsCache.Set(string(hashKey[:]), res, 32)
}
return res, nil
}
func (h *stateRootHasher) validatorRoot(hasher ssz.HashFn, validator *ethpb.Validator) ([32]byte, error) {
if validator == nil {
return [32]byte{}, errors.New("nil validator")
}
enc := stateutil.ValidatorEncKey(validator)
// Check if it exists in cache:
if h.rootsCache != nil {
if found, ok := h.rootsCache.Get(string(enc)); found != nil && ok {
return found.([32]byte), nil
}
}
valRoot, err := stateutil.ValidatorRootWithHasher(hasher, validator)
if err != nil {
return [32]byte{}, err
}
if h.rootsCache != nil {
h.rootsCache.Set(string(enc), valRoot, 32)
}
return valRoot, nil
}
// ValidatorRegistryRoot computes the HashTreeRoot Merkleization of
// a list of validator structs according to the eth2
// Simple Serialize specification.
func ValidatorRegistryRoot(vals []*ethpb.Validator) ([32]byte, error) {
if features.Get().EnableSSZCache {
return cachedHasher.validatorRegistryRoot(vals)
}
return nocachedHasher.validatorRegistryRoot(vals)
}

Some files were not shown because too many files have changed in this diff Show More