mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-10 22:07:59 -05:00
Compare commits
113 Commits
custom_has
...
kintsugi-n
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d2c197d040 | ||
|
|
87bc6aa5e5 | ||
|
|
5b5065b01d | ||
|
|
ee1c567561 | ||
|
|
ff1416c98d | ||
|
|
471c94031f | ||
|
|
9863fb3d6a | ||
|
|
f3c2d1a00b | ||
|
|
5d8879a4df | ||
|
|
abea0a11bc | ||
|
|
80ce1603bd | ||
|
|
ca478244e0 | ||
|
|
8a864b66a1 | ||
|
|
72f3b9e84b | ||
|
|
493e95060f | ||
|
|
e7e1ecd72f | ||
|
|
c286ac8b87 | ||
|
|
bde315224c | ||
|
|
00520705bc | ||
|
|
c7fcd804d7 | ||
|
|
985ac2e848 | ||
|
|
f4a0e98926 | ||
|
|
5f93ff10ea | ||
|
|
544248f60f | ||
|
|
3b41968510 | ||
|
|
7fc418042a | ||
|
|
9a03946706 | ||
|
|
33dd6dd5f2 | ||
|
|
56542e1958 | ||
|
|
e82d7b4c0b | ||
|
|
6cb69d8ff0 | ||
|
|
70b55a0191 | ||
|
|
50f4951194 | ||
|
|
1a14f2368d | ||
|
|
bb8cad58f1 | ||
|
|
05412c1f0e | ||
|
|
b03441fed8 | ||
|
|
fa7d7cef69 | ||
|
|
1caa6c969f | ||
|
|
eeb7d5bbfb | ||
|
|
d7c7d150b1 | ||
|
|
63c4d2eb2b | ||
|
|
9de1f694a0 | ||
|
|
8a79d06cbd | ||
|
|
5290ad93b8 | ||
|
|
2128208ef7 | ||
|
|
296323719c | ||
|
|
5e9583ea85 | ||
|
|
17196e0f80 | ||
|
|
c50d54000d | ||
|
|
85b3061d1b | ||
|
|
0146c5317a | ||
|
|
fcbc48ffd9 | ||
|
|
76ee51af9d | ||
|
|
370b0b97ed | ||
|
|
990ebd3fe3 | ||
|
|
54449c72e8 | ||
|
|
1dbd0b98eb | ||
|
|
09c3896c6b | ||
|
|
d494845e19 | ||
|
|
4d0c0f7234 | ||
|
|
bfe570b1aa | ||
|
|
56db696823 | ||
|
|
d312e15db8 | ||
|
|
907d4cf7e6 | ||
|
|
891353d6ad | ||
|
|
0adc08660c | ||
|
|
de31425dcd | ||
|
|
2094e0f21f | ||
|
|
2c6f554500 | ||
|
|
18a1e07711 | ||
|
|
5e432f5aaa | ||
|
|
284e2696cb | ||
|
|
7547aaa6ce | ||
|
|
953315c2cc | ||
|
|
9662d06b08 | ||
|
|
ecaea26ace | ||
|
|
63819e2690 | ||
|
|
a6d0cd06b3 | ||
|
|
2dbe4f5e67 | ||
|
|
2689d6814d | ||
|
|
69a681ddc0 | ||
|
|
7f9f1fd36c | ||
|
|
57c97eb561 | ||
|
|
f0f94a8193 | ||
|
|
87b0bf2c2a | ||
|
|
d8ad317dec | ||
|
|
ab5f488cf4 | ||
|
|
296d7464ad | ||
|
|
221c542e4f | ||
|
|
7ad32aaa96 | ||
|
|
3dc0969c0c | ||
|
|
0e18e835c3 | ||
|
|
8adfbfc382 | ||
|
|
68b0b5e0ce | ||
|
|
eede309e0f | ||
|
|
b11628dc53 | ||
|
|
ea3ae22d3b | ||
|
|
02bb39ddeb | ||
|
|
1618c1f55d | ||
|
|
73c8493fd7 | ||
|
|
a4f59a4f15 | ||
|
|
3c497efdb8 | ||
|
|
9f5daafbb7 | ||
|
|
11d7ffdfa8 | ||
|
|
c26b3305e6 | ||
|
|
38d8b63fbf | ||
|
|
aea67405c8 | ||
|
|
57d830f8b3 | ||
|
|
ac4b1ef4ea | ||
|
|
1d32119f5a | ||
|
|
3540cc7b05 | ||
|
|
191e7767a6 |
@@ -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-----
|
||||
|
||||
@@ -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",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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{
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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, ðpb.Checkpoint{Root: blkRoot[:]}))
|
||||
require.NoError(t, beaconDB.SaveFinalizedCheckpoint(ctx, ðpb.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, ðpb.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, ðpb.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, ðpb.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)
|
||||
|
||||
1
beacon-chain/cache/BUILD.bazel
vendored
1
beacon-chain/cache/BUILD.bazel
vendored
@@ -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",
|
||||
|
||||
11
beacon-chain/cache/sync_committee_head_state.go
vendored
11
beacon-chain/cache/sync_committee_head_state.go
vendored
@@ -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
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
24
beacon-chain/core/execution/BUILD.bazel
Normal file
24
beacon-chain/core/execution/BUILD.bazel
Normal 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",
|
||||
],
|
||||
)
|
||||
226
beacon-chain/core/execution/process.go
Normal file
226
beacon-chain/core/execution/process.go
Normal 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 ðpb.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 ðpb.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 ðpb.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),
|
||||
}
|
||||
}
|
||||
85
beacon-chain/core/execution/upgrade.go
Normal file
85
beacon-chain/core/execution/upgrade.go
Normal 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 := ðpb.BeaconStateMerge{
|
||||
GenesisTime: state.GenesisTime(),
|
||||
GenesisValidatorsRoot: state.GenesisValidatorRoot(),
|
||||
Slot: state.Slot(),
|
||||
Fork: ðpb.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: ðpb.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)
|
||||
}
|
||||
@@ -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++ {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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"
|
||||
)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -609,6 +609,13 @@ func unmarshalBlock(_ context.Context, enc []byte) (block.SignedBeaconBlock, err
|
||||
return nil, err
|
||||
}
|
||||
return wrapper.WrappedAltairSignedBeaconBlock(rawBlock)
|
||||
case hasMergeKey(enc):
|
||||
rawBlock := ðpb.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 := ðpb.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:
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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 := ðpb.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 := ðpb.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")
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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, ®ularsync.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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
],
|
||||
)
|
||||
|
||||
45
beacon-chain/node/registration/powchain.go
Normal file
45
beacon-chain/node/registration/powchain.go
Normal 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
|
||||
}
|
||||
71
beacon-chain/node/registration/powchain_test.go
Normal file
71
beacon-chain/node/registration/powchain_test.go
Normal 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)
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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 ðpb.SignedBeaconBlockAltair{}
|
||||
if topic == BlockSubnetTopicFormat {
|
||||
if epoch >= params.BeaconConfig().MergeForkEpoch {
|
||||
return ðpb.SignedBeaconBlockMerge{}
|
||||
}
|
||||
if epoch >= params.BeaconConfig().AltairForkEpoch {
|
||||
return ðpb.SignedBeaconBlockAltair{}
|
||||
}
|
||||
}
|
||||
return gossipTopicMappings[topic]
|
||||
}
|
||||
@@ -52,4 +57,5 @@ func init() {
|
||||
}
|
||||
// Specially handle Altair Objects.
|
||||
GossipTypeMapping[reflect.TypeOf(ðpb.SignedBeaconBlockAltair{})] = BlockSubnetTopicFormat
|
||||
GossipTypeMapping[reflect.TypeOf(ðpb.SignedBeaconBlockMerge{})] = BlockSubnetTopicFormat
|
||||
}
|
||||
|
||||
@@ -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
BIN
beacon-chain/p2p/metaData
Normal file
Binary file not shown.
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -39,6 +39,9 @@ func InitializeDataMaps() {
|
||||
bytesutil.ToBytes4(params.BeaconConfig().AltairForkVersion): func() (block.SignedBeaconBlock, error) {
|
||||
return wrapper.WrappedAltairSignedBeaconBlock(ðpb.SignedBeaconBlockAltair{Block: ðpb.BeaconBlockAltair{}})
|
||||
},
|
||||
bytesutil.ToBytes4(params.BeaconConfig().MergeForkVersion): func() (block.SignedBeaconBlock, error) {
|
||||
return wrapper.WrappedMergeSignedBeaconBlock(ðpb.SignedBeaconBlockMerge{Block: ðpb.BeaconBlockMerge{}})
|
||||
},
|
||||
}
|
||||
|
||||
// Reset our metadata map.
|
||||
@@ -49,5 +52,8 @@ func InitializeDataMaps() {
|
||||
bytesutil.ToBytes4(params.BeaconConfig().AltairForkVersion): func() metadata.Metadata {
|
||||
return wrapper.WrappedMetadataV1(ðpb.MetaDataV1{})
|
||||
},
|
||||
bytesutil.ToBytes4(params.BeaconConfig().MergeForkVersion): func() metadata.Metadata {
|
||||
return wrapper.WrappedMetadataV1(ðpb.MetaDataV1{})
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
386
beacon-chain/powchain/execution_engine.go
Normal file
386
beacon-chain/powchain/execution_engine.go
Normal 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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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])
|
||||
}
|
||||
|
||||
@@ -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, ðpb.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 {
|
||||
|
||||
@@ -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{}
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 ðpb.GenericBeaconBlock{Block: ðpb.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 ðpb.GenericBeaconBlock{Block: ðpb.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 ðpb.GenericBeaconBlock{Block: ðpb.GenericBeaconBlock_Altair{Altair: blk}}, nil
|
||||
|
||||
log.Info("Sending block to client, transaction field is nil: ", blk.Body.ExecutionPayload.Transactions == nil)
|
||||
|
||||
return ðpb.GenericBeaconBlock{Block: ðpb.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 := ðpb.BeaconBlockMerge{
|
||||
Slot: altairBlk.Slot,
|
||||
ProposerIndex: altairBlk.ProposerIndex,
|
||||
ParentRoot: altairBlk.ParentRoot,
|
||||
StateRoot: params.BeaconConfig().ZeroHash[:],
|
||||
Body: ðpb.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(
|
||||
ðpb.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 ðpb.BeaconBlockAltair{
|
||||
Slot: req.Slot,
|
||||
ParentRoot: blkData.ParentRoot,
|
||||
StateRoot: stateRoot,
|
||||
ProposerIndex: blkData.ProposerIdx,
|
||||
Body: ðpb.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")
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 ðpb.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()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -28,7 +28,7 @@ func TestResume(t *testing.T) {
|
||||
require.NoError(t, service.beaconDB.SaveGenesisBlockRoot(ctx, root))
|
||||
require.NoError(t, service.beaconDB.SaveFinalizedCheckpoint(ctx, ðpb.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")
|
||||
|
||||
@@ -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__",
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
48
beacon-chain/state/v3/BUILD.bazel
Normal file
48
beacon-chain/state/v3/BUILD.bazel
Normal 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",
|
||||
],
|
||||
)
|
||||
16
beacon-chain/state/v3/deprecated_getters.go
Normal file
16
beacon-chain/state/v3/deprecated_getters.go
Normal 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")
|
||||
}
|
||||
37
beacon-chain/state/v3/deprecated_setters.go
Normal file
37
beacon-chain/state/v3/deprecated_setters.go
Normal 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")
|
||||
}
|
||||
59
beacon-chain/state/v3/field_root_eth1.go
Normal file
59
beacon-chain/state/v3/field_root_eth1.go
Normal 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
|
||||
}
|
||||
89
beacon-chain/state/v3/field_root_validator.go
Normal file
89
beacon-chain/state/v3/field_root_validator.go
Normal 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
Reference in New Issue
Block a user