Compare commits

...

145 Commits

Author SHA1 Message Date
nisdas
4903a809f2 Merge branch 'capella' of https://github.com/prysmaticlabs/geth-sharding into capella-post-merge-genesis 2022-12-09 18:09:24 +08:00
rkapka
e1a2267f86 Merge remote-tracking branch 'origin/capella' into capella 2022-12-08 18:36:44 +01:00
rkapka
3c9e4ee7f7 Merge branch 'recontruct-capella-blinded' into capella
# Conflicts:
#	beacon-chain/blockchain/pow_block.go
#	beacon-chain/execution/engine_client.go
#	beacon-chain/execution/engine_client_test.go
#	beacon-chain/execution/testing/mock_engine_client.go
#	beacon-chain/rpc/eth/beacon/blocks.go
#	beacon-chain/state/state-native/getters_withdrawal.go
#	consensus-types/blocks/factory.go
#	proto/engine/v1/json_marshal_unmarshal.go
#	proto/engine/v1/json_marshal_unmarshal_test.go
2022-12-08 18:31:25 +01:00
rkapka
9ba32c9acd single ExecutionBlockByHash function 2022-12-08 17:53:02 +01:00
rkapka
d23008452e fix failing tests 2022-12-08 17:29:51 +01:00
terencechain
f397cba1e0 Better proposal RPC (#11721) 2022-12-08 07:40:48 -08:00
nisdas
aa2bbb676f make it better 2022-12-08 20:10:50 +08:00
nisdas
1f87322ddf add changes 2022-12-08 20:05:21 +08:00
nisdas
837fac628a Merge branch 'develop' of https://github.com/prysmaticlabs/geth-sharding into post-merge-genesis-mess 2022-12-08 12:58:04 +08:00
Kasey Kirkham
7d3e627d2d fix voting period start, skip altair check 2022-12-07 22:41:02 -06:00
Kasey Kirkham
016a027c48 bugs: genesis body_root and deposit index mismatch 2022-12-07 15:51:34 -06:00
prestonvanloon
3040f3ae4d Print process ID information for purposes of attaching a debugger 2022-12-07 14:07:30 -06:00
Kasey Kirkham
c8f1d51280 WIP 2022-12-07 14:07:24 -06:00
rkapka
1583e93b48 bzl 2022-12-07 18:23:43 +01:00
rkapka
849457df81 deepsource
(cherry picked from commit 903cab75ee)

# Conflicts:
#	beacon-chain/execution/testing/mock_engine_client.go
2022-12-07 16:29:34 +01:00
rkapka
903cab75ee deepsource 2022-12-07 16:27:09 +01:00
rkapka
ee108d4aff add doc to interface
(cherry picked from commit a08baf4a14)
2022-12-07 16:22:14 +01:00
rkapka
49bcc58762 rename methods
(cherry picked from commit 8c56dfdd46)
2022-12-07 16:22:09 +01:00
rkapka
a08baf4a14 add doc to interface 2022-12-07 16:20:43 +01:00
rkapka
8c56dfdd46 rename methods 2022-12-07 16:20:31 +01:00
rkapka
dcdd9af9db remove unneeded test 2022-12-07 16:05:44 +01:00
rkapka
a464cf5c60 Merge branch 'reconstruct-capella-block' into capella
(cherry picked from commit b0601580ef)

# Conflicts:
#	beacon-chain/rpc/eth/beacon/blocks.go
#	proto/engine/v1/json_marshal_unmarshal.go
2022-12-07 15:21:58 +01:00
Kasey Kirkham
5cb5ce7e14 WIP mess 2022-12-06 20:59:15 -06:00
Justin Traglia
6e26a6f128 Replace LastWithdrawalValidatorIndex to updated name (#11725) 2022-12-06 14:40:10 -08:00
Justin Traglia
b512b92a8a Update withdrawal error message to reflect new field name (#11724) 2022-12-06 14:39:17 -08:00
rkapka
b0601580ef Merge branch 'reconstruct-capella-block' into capella 2022-12-06 22:16:59 +01:00
rkapka
c1f29ea651 remove logs 2022-12-06 22:11:35 +01:00
Kasey Kirkham
910822400f WIP 2022-12-06 14:54:31 -06:00
rkapka
881d1d435a logs 2022-12-06 21:46:41 +01:00
rkapka
d1aae0c941 Merge branch 'capella' into reconstruct-capella-block 2022-12-06 21:26:55 +01:00
terence tsao
57bdb907cc Merge branch 'develop' of github.com:prysmaticlabs/prysm into capella 2022-12-02 11:10:39 -08:00
rkapka
15d683c78f Merge branch 'capella' into reconstruct-capella-block 2022-12-02 16:43:56 +01:00
rkapka
bf6c8ced7d working 2022-12-02 16:37:24 +01:00
Potuz
78fb685027 Check BLS changes when requesting from the pool 2022-12-02 10:14:39 -03:00
Kasey Kirkham
c0297ca0c2 send deposits, spam tx to advance, fix miner alloc 2022-12-01 21:46:24 -06:00
Kasey Kirkham
d51fb3a648 fix fork ordering bug and bellatrix genesis blocks 2022-12-01 14:36:11 -06:00
Potuz
98c0b23350 broadcast BLS changes 2022-12-01 11:26:56 -03:00
Kasey Kirkham
3ab486e140 multiple bugfixes 2022-11-30 15:12:57 -06:00
terence tsao
039a0fffba Merge branch 'develop' of github.com:prysmaticlabs/prysm into capella 2022-11-30 12:09:47 -08:00
Potuz
90ec640e7a Fix capella operations spectests 2022-11-30 15:35:55 -03:00
Potuz
10acd31d25 check on verify instead of sig 2022-11-30 15:20:23 -03:00
Kasey Kirkham
f52dbe3c8f WIP 2022-11-30 12:08:58 -06:00
Potuz
df1e8b33d8 BLS Change signature verification 2022-11-30 14:52:31 -03:00
rkapka
cdb4ee42cc not working 2022-11-30 18:22:52 +01:00
rkapka
d29baec77e proper error handling in BuildSignedBeaconBlockFromExecutionPayload 2022-11-30 15:32:57 +01:00
Kasey Kirkham
166c284ca4 remove debug wrapping 2022-11-29 18:20:47 -06:00
Kasey Kirkham
2654e3f080 WIP more fixes towards start from bellatrix 2022-11-29 18:20:19 -06:00
terence tsao
0adc54b7ff Refactor get payload 2022-11-29 12:02:47 -08:00
Potuz
1cbd7e9888 withdraw by default 2022-11-29 13:52:34 -03:00
Kasey Kirkham
ed65688252 use encoding/detect for genesis state bytes 2022-11-29 10:48:46 -06:00
rkapka
0a9e1658dd move stuff to blinded_blocks.go 2022-11-29 17:36:52 +01:00
rkapka
31d4a4cd11 test other functions 2022-11-29 17:36:52 +01:00
rkapka
fbc4e73d31 refactor and test GetSSZBlockV2 2022-11-29 17:36:52 +01:00
rkapka
c1d4eaa79d refactor and test GetBlockV2 2022-11-29 17:36:52 +01:00
rkapka
760af6428e update ssz 2022-11-29 17:36:52 +01:00
Kasey Kirkham
4bae07fdbb WIP 2022-11-29 10:23:33 -06:00
terence tsao
dfa0ccf626 Fix attribute pb nil checks 2022-11-29 07:27:33 -08:00
rkapka
1a51fdbd58 update withdrawals proto 2022-11-29 14:23:11 +01:00
terencechain
368a99ec8d Fix nil attribute for capella branch (#11701) 2022-11-28 17:34:26 -08:00
terence tsao
1c7e734918 Fix some blockchain tests 2022-11-28 13:59:17 -08:00
Kasey Kirkham
42808a0c29 combine bellatrix state w/ rm-pre-genesis branch 2022-11-28 14:24:53 -06:00
Kasey Kirkham
11cbe8fcb9 WIP - grabbing changes from rm-pre-genesis branch 2022-11-28 14:19:44 -06:00
rkapka
764d1325bf Merge remote-tracking branch 'origin/capella' into capella 2022-11-28 21:07:00 +01:00
rkapka
0cf30e9022 Merge branch '__develop' into capella 2022-11-28 21:06:20 +01:00
Potuz
227b20f368 fix nil block from stream 2022-11-28 16:53:11 -03:00
rkapka
d7d70bc25b support SSZ lol
(cherry picked from commit 52bc2c8d617ac3e1254c493fa053cdce4a1ebd63)
2022-11-28 20:19:24 +01:00
rkapka
82f6ddb693 add Capella version
(cherry picked from commit 5d6fd0bbe663e5dd16df5b2e773f68982bbcd24e)
2022-11-28 20:19:19 +01:00
rkapka
9e4e82d2c5 refactor GetBlindedBlockSSZ
(cherry picked from commit 97483c339f99b0d96bd81846a979383ffd2b0cda)

# Conflicts:
#	beacon-chain/rpc/eth/beacon/blocks.go
2022-11-28 20:19:15 +01:00
rkapka
9838369fe9 fix proto generation 2022-11-28 20:15:05 +01:00
rkapka
6085ad1bfa fix issues 2022-11-28 20:07:37 +01:00
rkapka
d3851b27df Merge branch '__develop' into capella
# Conflicts:
#	beacon-chain/rpc/apimiddleware/structs.go
#	beacon-chain/rpc/eth/beacon/blocks.go
#	proto/eth/v2/BUILD.bazel
#	proto/eth/v2/beacon_block.pb.go
#	proto/eth/v2/beacon_block.proto
#	proto/eth/v2/generated.ssz.go
#	proto/migration/v1alpha1_to_v2.go
#	proto/prysm/v1alpha1/beacon_chain.pb.go
#	proto/prysm/v1alpha1/beacon_chain.proto
2022-11-28 19:31:33 +01:00
Potuz
d6100dfdcb fix spectest 2022-11-28 12:38:14 -03:00
Potuz
c2144dac86 Add BLSToExecutionChangge endpoint 2022-11-27 23:00:16 -03:00
Potuz
a47ff569a8 Add Submit BLSChange endpoint 2022-11-27 20:50:21 -03:00
Potuz
f8be022ef2 Merge branch 'develop' into capella 2022-11-27 20:40:41 -03:00
Potuz
4f39e6b685 Implement REST block API endpoints 2022-11-27 16:20:30 -03:00
Potuz
c67b000633 add test 2022-11-27 13:07:50 -03:00
Potuz
02f7443586 Refactor Sync Committee Rewards 2022-11-27 09:04:03 -03:00
terence tsao
6275e7df4e Clean up execution engine 2022-11-25 17:20:28 -08:00
terencechain
1b6b52fda1 Add PayloadAttribute superset and use it for engine-api (#11691) 2022-11-25 17:12:55 -08:00
Potuz
5fa1fd84b9 Hook the BLSTOExecution Pool to the proposer 2022-11-25 09:33:17 -03:00
nisdas
bd0c9f9e8d fix 2022-11-25 09:06:59 -03:00
Potuz
2532bb370c Merge branch 'develop' into capella 2022-11-25 08:16:32 -03:00
nisdas
12efc6c2c1 make it reject 2022-11-24 22:21:12 +08:00
nisdas
a6cc9ac9c5 add sig validation 2022-11-24 22:19:55 +08:00
nisdas
031f5845a2 add gossip handler for bls change object 2022-11-24 21:22:18 +08:00
nisdas
b88559726c Merge branch 'develop' of https://github.com/prysmaticlabs/geth-sharding into capella 2022-11-24 20:05:41 +08:00
Kasey Kirkham
938fca1933 env var to control log path with unique paths
due to flaky test re-run behavior, logs from a failed test run are
overwritten by subsequent retries. This makes it difficult to retrieve
logs after the first failed run. It also takes some squinting through
output to find the location of the log file in the first place. This
flag enables logs to be placed in an arbitrary path. Note that bazel
sandboxing generally will force this path to be in the /tmp tree.
2022-11-23 16:46:45 -06:00
Kasey Kirkham
604688a00e WIP trying to start from bellatrix state 2022-11-23 16:09:46 -06:00
nisdas
62f6b07cba fix gossip registration 2022-11-23 20:10:44 +08:00
terence tsao
f956f1ed6e Handle capella version for packing atts 2022-11-22 17:21:21 -08:00
Potuz
16b0820193 Merge branch 'develop' into capella 2022-11-22 13:43:03 -03:00
Potuz
4b02267e96 add more minimal fixes 2022-11-22 13:34:33 -03:00
Potuz
746584c453 fix missing minimal test 2022-11-22 13:34:33 -03:00
Potuz
b56daaaca2 Fix empty withdrawals slice 2022-11-22 10:38:42 -03:00
terence tsao
931e5e10c3 Fix mainnet fork transition tests 2022-11-16 08:49:06 -05:00
Potuz
c172f838b1 Mark capella fields as dirty 2022-11-15 09:58:34 -05:00
Potuz
c07ae29cd9 move MaxWithdrawalsPerPayload to fieldparams 2022-11-14 22:59:31 -05:00
Potuz
214c9bfd8b fix bls_to_execution_changes 2022-11-14 16:41:17 -05:00
Potuz
716140d64d add bls_to_execution_change tests 2022-11-14 16:26:39 -05:00
Potuz
088cb4ef59 fix expected_withdrawals 2022-11-14 14:50:41 -05:00
Potuz
d1472fc351 Add withdrawals operations tests 2022-11-13 08:54:59 -03:00
terence tsao
5c8c0c31d8 Merge branch 'capella-withdrawal-minimal' into capella 2022-11-12 22:06:43 -08:00
terence tsao
7f3c00c7a2 Can build 2022-11-12 22:06:22 -08:00
terencechain
c180dab791 Merge branch 'develop' into capella 2022-11-12 18:28:18 -08:00
terence tsao
f24acc21c7 Fix bazel 2022-11-12 17:43:19 -08:00
terence tsao
40b637849d Fix miminal capella tests 2022-11-12 17:26:05 -08:00
terence tsao
e7db1685df Add mainnet capella tests 2022-11-12 17:13:26 -08:00
terence tsao
eccbfd1011 Add shared capella spec tests helpers 2022-11-12 17:13:16 -08:00
terence tsao
90211f6769 Fix prev epoch attested precompute 2022-11-12 17:12:29 -08:00
terence tsao
edc32ac18e Fix slashing quotient 2022-11-12 17:12:04 -08:00
terence tsao
fe68e020e3 Add selector with minimal withdrawal size 2022-11-12 16:18:16 -08:00
terence tsao
81e1e3544d Add mainnet ssz vectors 2022-11-12 15:50:07 -08:00
Potuz
09372d5c35 Revert "added mainnet ssz tests"
This reverts commit 078a89e4ca.
2022-11-12 18:40:28 -03:00
Potuz
078a89e4ca added mainnet ssz tests 2022-11-12 18:39:11 -03:00
Potuz
dbc6ae26a6 Add minimal support for capella spec tests
Fixed many issues about hashing
Added fork typing in the state replayer
2022-11-12 18:18:35 -03:00
Potuz
b6f429867a Merge branch 'develop' into capella 2022-11-12 16:35:20 -03:00
Potuz
09f50660ce Merge branch 'develop' into capella 2022-11-12 11:51:06 -03:00
Potuz
189825b495 fix withdrawal hashing 2022-11-11 23:21:41 -03:00
Potuz
764b7ff610 Don't build capella payload twice 2022-11-11 10:47:29 -03:00
Potuz
d499db7f0e Merge branch 'develop' into capella 2022-11-09 21:27:18 -03:00
Potuz
ed2d1c7bf9 Merge branch 'develop' into capella 2022-11-09 09:14:55 -03:00
nisdas
14b73cbd47 register flag 2022-11-09 08:48:36 +08:00
Potuz
3124785a08 Merge branch 'develop' into capella 2022-11-07 10:08:09 -03:00
Potuz
60e6306107 working withrawals initial commits 2022-11-06 16:53:57 -03:00
terence tsao
42ccb7830a Add Capella DB changes 2022-11-06 15:25:34 -03:00
Potuz
0bb03b9292 fix marshalling and engine calls 2022-11-06 15:24:22 -03:00
nisdas
ed6fbf1480 stupid bug 2022-11-07 00:18:01 +08:00
nisdas
477cec6021 wei it 2022-11-07 00:13:12 +08:00
nisdas
924500d111 add unmarshal 2022-11-06 23:57:37 +08:00
Potuz
0677504ef1 Revert "proposer changes"
This reverts commit ca2a7c4d9c.
2022-11-06 12:16:53 -03:00
Potuz
ca2a7c4d9c proposer changes 2022-11-06 12:14:17 -03:00
Potuz
28606629ad marshalling stub 2022-11-06 12:03:25 -03:00
Potuz
c817279464 fix capella payload 2022-11-06 11:14:39 -03:00
Potuz
009d6ed8ed proposer logic 2022-11-06 10:49:32 -03:00
Potuz
5cec1282a9 FCU two versions 2022-11-06 10:22:45 -03:00
Potuz
340170fd29 propose block V2 2022-11-06 09:42:20 -03:00
Potuz
7ed0cc139a marshalling first attempt 2022-11-06 07:47:43 -03:00
Potuz
2c822213eb rpc changes 2022-11-06 00:24:56 -03:00
Potuz
c08bb39ffe add fork versions 2022-11-05 13:38:11 -03:00
Potuz
5083d8ab34 propose capella blocks 2022-11-05 12:38:27 -03:00
Potuz
7552a5dd07 capella fork logic 2022-11-05 07:33:20 -03:00
Potuz
c93d68f853 Capella state transition 2022-11-05 06:06:15 -03:00
Potuz
3e8aa4023d Fix config test and export method 2022-11-04 11:59:49 -03:00
Potuz
b443875e66 Implement get_expected_withdrawals 2022-11-04 11:45:45 -03:00
161 changed files with 7803 additions and 4002 deletions

View File

@@ -64,6 +64,7 @@ go_library(
"//config/params:go_default_library",
"//consensus-types/blocks:go_default_library",
"//consensus-types/interfaces:go_default_library",
"//consensus-types/payload-attribute:go_default_library",
"//consensus-types/primitives:go_default_library",
"//crypto/bls:go_default_library",
"//encoding/bytesutil:go_default_library",

View File

@@ -1,6 +1,7 @@
package blockchain
import (
"bytes"
"context"
"fmt"
@@ -15,9 +16,11 @@ import (
"github.com/prysmaticlabs/prysm/v3/config/params"
consensusblocks "github.com/prysmaticlabs/prysm/v3/consensus-types/blocks"
"github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces"
payloadattribute "github.com/prysmaticlabs/prysm/v3/consensus-types/payload-attribute"
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
enginev1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
"github.com/prysmaticlabs/prysm/v3/runtime/version"
"github.com/prysmaticlabs/prysm/v3/time/slots"
"github.com/sirupsen/logrus"
"go.opencensus.io/trace"
@@ -38,6 +41,7 @@ type notifyForkchoiceUpdateArg struct {
func (s *Service) notifyForkchoiceUpdate(ctx context.Context, arg *notifyForkchoiceUpdateArg) (*enginev1.PayloadIDBytes, error) {
ctx, span := trace.StartSpan(ctx, "blockChain.notifyForkchoiceUpdate")
defer span.End()
log.Infof("notifyForkchoiceUpdate, fork version=%#x, headRoot=%#x, headState.latest_block_header=%#x", arg.headState.Fork().CurrentVersion, arg.headRoot, arg.headState.LatestBlockHeader().BodyRoot)
headBlk := arg.headBlock
if headBlk == nil || headBlk.IsNil() || headBlk.Body().IsNil() {
@@ -50,7 +54,25 @@ func (s *Service) notifyForkchoiceUpdate(ctx context.Context, arg *notifyForkcho
log.WithError(err).Error("Could not determine if head block is execution block")
return nil, nil
}
var eth1BlockHash []byte
if !isExecutionBlk {
br, err := headBlk.HashTreeRoot()
if err != nil {
return nil, err
}
// TODO: this is a hack
// try to grab the payload header from the state in case the block doesn't have it but the state does
sp, err := arg.headState.LatestExecutionPayloadHeader()
if err != nil {
log.WithError(err).Infof("notifyForkchoiceUpdate, skipping non-execution block with root=%#x", br)
return nil, nil
}
eth1BlockHash = sp.BlockHash()
if len(sp.BlockHash()) != 32 || bytes.Equal(eth1BlockHash, params.BeaconConfig().ZeroHash[:]) {
log.Infof("notifyForkchoiceUpdate, skipping non-execution block with root=%#x and empty payload header block hash", br)
return nil, nil
}
return nil, nil
}
headPayload, err := headBlk.Body().Execution()
@@ -58,10 +80,11 @@ func (s *Service) notifyForkchoiceUpdate(ctx context.Context, arg *notifyForkcho
log.WithError(err).Error("Could not get execution payload for head block")
return nil, nil
}
eth1BlockHash = headPayload.BlockHash()
finalizedHash := s.ForkChoicer().FinalizedPayloadBlockHash()
justifiedHash := s.ForkChoicer().JustifiedPayloadBlockHash()
fcs := &enginev1.ForkchoiceState{
HeadBlockHash: headPayload.BlockHash(),
HeadBlockHash: eth1BlockHash,
SafeBlockHash: justifiedHash[:],
FinalizedBlockHash: finalizedHash[:],
}
@@ -71,7 +94,6 @@ func (s *Service) notifyForkchoiceUpdate(ctx context.Context, arg *notifyForkcho
if err != nil {
log.WithError(err).Error("Could not get head payload attribute")
}
payloadID, lastValidHash, err := s.cfg.ExecutionEngineCaller.ForkchoiceUpdated(ctx, fcs, attr)
if err != nil {
switch err {
@@ -79,7 +101,7 @@ func (s *Service) notifyForkchoiceUpdate(ctx context.Context, arg *notifyForkcho
forkchoiceUpdatedOptimisticNodeCount.Inc()
log.WithFields(logrus.Fields{
"headSlot": headBlk.Slot(),
"headPayloadBlockHash": fmt.Sprintf("%#x", bytesutil.Trunc(headPayload.BlockHash())),
"headPayloadBlockHash": fmt.Sprintf("%#x", bytesutil.Trunc(eth1BlockHash)),
"finalizedPayloadBlockHash": fmt.Sprintf("%#x", bytesutil.Trunc(finalizedHash[:])),
}).Info("Called fork choice updated with optimistic block")
return payloadID, nil
@@ -144,18 +166,21 @@ func (s *Service) notifyForkchoiceUpdate(ctx context.Context, arg *notifyForkcho
return nil, nil
}
}
log.WithField("payloadID", fmt.Sprintf("%#x", payloadID)).WithField("lastValidHash", fmt.Sprintf("%#x", lastValidHash)).Infof("notifyForkchoiceUpdate, no error from ee call")
forkchoiceUpdatedValidNodeCount.Inc()
if err := s.cfg.ForkChoiceStore.SetOptimisticToValid(ctx, arg.headRoot); err != nil {
log.WithError(err).Error("Could not set head root to valid")
log.WithField("headRoot", fmt.Sprintf("%#x", arg.headRoot)).WithField("payloadID", fmt.Sprintf("%#x", payloadID)).WithField("lastValidHash", fmt.Sprintf("%#x", lastValidHash)).WithError(err).Error("Could not set head root to valid")
return nil, nil
}
if hasAttr && payloadID != nil { // If the forkchoice update call has an attribute, update the proposer payload ID cache.
// If the forkchoice update call has an attribute, update the proposer payload ID cache.
if hasAttr && payloadID != nil {
var pId [8]byte
copy(pId[:], payloadID[:])
s.cfg.ProposerSlotIndexCache.SetProposerAndPayloadIDs(nextSlot, proposerId, pId, arg.headRoot)
log.Infof("notifyForkchoiceUpdate, SetProposerAndPayloadIDs(nextSlot=%d, proposerId=%d, pId=%#x, arg.headRoot=%#x)", nextSlot, proposerId, pId, arg.headRoot)
} else if hasAttr && payloadID == nil {
log.WithFields(logrus.Fields{
"blockHash": fmt.Sprintf("%#x", headPayload.BlockHash()),
"blockHash": fmt.Sprintf("%#x", eth1BlockHash),
"slot": headBlk.Slot(),
}).Error("Received nil payload ID on VALID engine response")
}
@@ -250,22 +275,24 @@ func (s *Service) notifyNewPayload(ctx context.Context, postStateVersion int,
// getPayloadAttributes returns the payload attributes for the given state and slot.
// The attribute is required to initiate a payload build process in the context of an `engine_forkchoiceUpdated` call.
func (s *Service) getPayloadAttribute(ctx context.Context, st state.BeaconState, slot types.Slot) (bool, *enginev1.PayloadAttributes, types.ValidatorIndex, error) {
func (s *Service) getPayloadAttribute(ctx context.Context, st state.BeaconState, slot types.Slot) (bool, payloadattribute.Attributer, types.ValidatorIndex, error) {
emptyAttri := payloadattribute.EmptyWithVersion(st.Version())
// Root is `[32]byte{}` since we are retrieving proposer ID of a given slot. During insertion at assignment the root was not known.
proposerID, _, ok := s.cfg.ProposerSlotIndexCache.GetProposerPayloadIDs(slot, [32]byte{} /* root */)
if !ok { // There's no need to build attribute if there is no proposer for slot.
return false, nil, 0, nil
return false, emptyAttri, 0, nil
}
log.Infof("getPayloadAttribute, GetProposerPayloadIDs(nextSlot=%d, arg.headRoot=%#x,idx=%v)", slot, [32]byte{}, proposerID)
// Get previous randao.
st = st.Copy()
st, err := transition.ProcessSlotsIfPossible(ctx, st, slot)
if err != nil {
return false, nil, 0, err
return false, emptyAttri, 0, err
}
prevRando, err := helpers.RandaoMix(st, time.CurrentEpoch(st))
if err != nil {
return false, nil, 0, nil
return false, emptyAttri, 0, err
}
// Get fee recipient.
@@ -283,7 +310,7 @@ func (s *Service) getPayloadAttribute(ctx context.Context, st state.BeaconState,
"Please refer to our documentation for instructions")
}
case err != nil:
return false, nil, 0, errors.Wrap(err, "could not get fee recipient in db")
return false, emptyAttri, 0, errors.Wrap(err, "could not get fee recipient in db")
default:
feeRecipient = recipient
}
@@ -291,13 +318,38 @@ func (s *Service) getPayloadAttribute(ctx context.Context, st state.BeaconState,
// Get timestamp.
t, err := slots.ToTime(uint64(s.genesisTime.Unix()), slot)
if err != nil {
return false, nil, 0, err
return false, emptyAttri, 0, err
}
attr := &enginev1.PayloadAttributes{
Timestamp: uint64(t.Unix()),
PrevRandao: prevRando,
SuggestedFeeRecipient: feeRecipient.Bytes(),
var attr payloadattribute.Attributer
switch st.Version() {
case version.Capella:
withdrawals, err := st.ExpectedWithdrawals()
if err != nil {
return false, emptyAttri, 0, errors.Wrap(err, "could not get expected withdrawals")
}
attr, err = payloadattribute.New(&enginev1.PayloadAttributesV2{
Timestamp: uint64(t.Unix()),
PrevRandao: prevRando,
SuggestedFeeRecipient: feeRecipient.Bytes(),
Withdrawals: withdrawals,
})
if err != nil {
return false, emptyAttri, 0, err
}
case version.Bellatrix:
attr, err = payloadattribute.New(&enginev1.PayloadAttributes{
Timestamp: uint64(t.Unix()),
PrevRandao: prevRando,
SuggestedFeeRecipient: feeRecipient.Bytes(),
})
if err != nil {
return false, emptyAttri, 0, err
}
default:
return false, emptyAttri, 0, errors.New("unknown state version")
}
return true, attr, proposerID, nil
}

View File

@@ -698,14 +698,14 @@ func Test_NotifyNewPayload(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
e := &mockExecution.EngineClient{ErrNewPayload: tt.newPayloadErr, BlockByHashMap: map[[32]byte]*v1.ExecutionBlock{}}
e.BlockByHashMap[[32]byte{'a'}] = &v1.ExecutionBlock{
e := &mockExecution.EngineClient{ErrNewPayload: tt.newPayloadErr, BlockByHashMap: map[[32]byte]*v1.ExecutionBlockBellatrix{}}
e.BlockByHashMap[[32]byte{'a'}] = &v1.ExecutionBlockBellatrix{
Header: gethtypes.Header{
ParentHash: common.BytesToHash([]byte("b")),
},
TotalDifficulty: "0x2",
}
e.BlockByHashMap[[32]byte{'b'}] = &v1.ExecutionBlock{
e.BlockByHashMap[[32]byte{'b'}] = &v1.ExecutionBlockBellatrix{
Header: gethtypes.Header{
ParentHash: common.BytesToHash([]byte("3")),
},
@@ -759,14 +759,14 @@ func Test_NotifyNewPayload_SetOptimisticToValid(t *testing.T) {
require.NoError(t, err)
service, err := NewService(ctx, opts...)
require.NoError(t, err)
e := &mockExecution.EngineClient{BlockByHashMap: map[[32]byte]*v1.ExecutionBlock{}}
e.BlockByHashMap[[32]byte{'a'}] = &v1.ExecutionBlock{
e := &mockExecution.EngineClient{BlockByHashMap: map[[32]byte]*v1.ExecutionBlockBellatrix{}}
e.BlockByHashMap[[32]byte{'a'}] = &v1.ExecutionBlockBellatrix{
Header: gethtypes.Header{
ParentHash: common.BytesToHash([]byte("b")),
},
TotalDifficulty: "0x2",
}
e.BlockByHashMap[[32]byte{'b'}] = &v1.ExecutionBlock{
e.BlockByHashMap[[32]byte{'b'}] = &v1.ExecutionBlockBellatrix{
Header: gethtypes.Header{
ParentHash: common.BytesToHash([]byte("3")),
},
@@ -807,7 +807,7 @@ func Test_GetPayloadAttribute(t *testing.T) {
require.NoError(t, err)
require.Equal(t, true, hasPayload)
require.Equal(t, suggestedVid, vId)
require.Equal(t, params.BeaconConfig().EthBurnAddressHex, common.BytesToAddress(attr.SuggestedFeeRecipient).String())
require.Equal(t, params.BeaconConfig().EthBurnAddressHex, common.BytesToAddress(attr.SuggestedFeeRecipient()).String())
require.LogsContain(t, hook, "Fee recipient is currently using the burn address")
// Cache hit, advance state, has fee recipient
@@ -818,7 +818,7 @@ func Test_GetPayloadAttribute(t *testing.T) {
require.NoError(t, err)
require.Equal(t, true, hasPayload)
require.Equal(t, suggestedVid, vId)
require.Equal(t, suggestedAddr, common.BytesToAddress(attr.SuggestedFeeRecipient))
require.Equal(t, suggestedAddr, common.BytesToAddress(attr.SuggestedFeeRecipient()))
}
func Test_UpdateLastValidatedCheckpoint(t *testing.T) {

View File

@@ -207,7 +207,7 @@ func (s *Service) setHead(root [32]byte, block interfaces.SignedBeaconBlock, sta
block: bCp,
state: state.Copy(),
}
return nil
return err
}
// This sets head view object which is used to track the head slot, root, block and state. The method

View File

@@ -87,6 +87,7 @@ func logBlockSyncStatus(block interfaces.BeaconBlock, blockRoot [32]byte, justif
"version": version.String(block.Version()),
"sinceSlotStartTime": prysmTime.Now().Sub(startTime),
"chainServiceProcessedTime": prysmTime.Now().Sub(receivedTime),
"deposits": fmt.Sprintf("%d/%d", len(block.Body().Deposits()), block.Body().Eth1Data().DepositCount),
}).Debug("Synced new block")
} else {
log.WithFields(logrus.Fields{

View File

@@ -15,6 +15,8 @@ import (
"github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces"
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
pb "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
"github.com/prysmaticlabs/prysm/v3/runtime/version"
"github.com/prysmaticlabs/prysm/v3/time/slots"
"github.com/sirupsen/logrus"
)
@@ -85,14 +87,19 @@ func (s *Service) validateMergeBlock(ctx context.Context, b interfaces.SignedBea
// getBlkParentHashAndTD retrieves the parent hash and total difficulty of the given block.
func (s *Service) getBlkParentHashAndTD(ctx context.Context, blkHash []byte) ([]byte, *uint256.Int, error) {
blk, err := s.cfg.ExecutionEngineCaller.ExecutionBlockByHash(ctx, common.BytesToHash(blkHash), false /* no txs */)
blk, err := s.cfg.ExecutionEngineCaller.ExecutionBlockByHash(ctx, version.Bellatrix, common.BytesToHash(blkHash), false /* no txs */)
if err != nil {
return nil, nil, errors.Wrap(err, "could not get pow block")
}
if blk == nil {
return nil, nil, errors.New("pow block is nil")
}
blkTDBig, err := hexutil.DecodeBig(blk.TotalDifficulty)
blkBellatrix, ok := blk.(*pb.ExecutionBlockBellatrix)
if !ok {
return nil, nil, fmt.Errorf("wrong execution block type %T", blk)
}
blkTDBig, err := hexutil.DecodeBig(blkBellatrix.TotalDifficulty)
if err != nil {
return nil, nil, errors.Wrap(err, "could not decode merge block total difficulty")
}
@@ -100,7 +107,7 @@ func (s *Service) getBlkParentHashAndTD(ctx context.Context, blkHash []byte) ([]
if overflows {
return nil, nil, errors.New("total difficulty overflows")
}
return blk.ParentHash[:], blkTDUint256, nil
return blkBellatrix.ParentHash[:], blkTDUint256, nil
}
// validateTerminalBlockHash validates if the merge block is a valid terminal PoW block.

View File

@@ -118,18 +118,18 @@ func Test_validateMergeBlock(t *testing.T) {
service, err := NewService(ctx, opts...)
require.NoError(t, err)
engine := &mocks.EngineClient{BlockByHashMap: map[[32]byte]*enginev1.ExecutionBlock{}}
engine := &mocks.EngineClient{BlockByHashMap: map[[32]byte]*enginev1.ExecutionBlockBellatrix{}}
service.cfg.ExecutionEngineCaller = engine
a := [32]byte{'a'}
b := [32]byte{'b'}
mergeBlockParentHash := [32]byte{'3'}
engine.BlockByHashMap[a] = &enginev1.ExecutionBlock{
engine.BlockByHashMap[a] = &enginev1.ExecutionBlockBellatrix{
Header: gethtypes.Header{
ParentHash: b,
},
TotalDifficulty: "0x2",
}
engine.BlockByHashMap[b] = &enginev1.ExecutionBlock{
engine.BlockByHashMap[b] = &enginev1.ExecutionBlockBellatrix{
Header: gethtypes.Header{
ParentHash: mergeBlockParentHash,
},
@@ -168,12 +168,12 @@ func Test_getBlkParentHashAndTD(t *testing.T) {
service, err := NewService(ctx, opts...)
require.NoError(t, err)
engine := &mocks.EngineClient{BlockByHashMap: map[[32]byte]*enginev1.ExecutionBlock{}}
engine := &mocks.EngineClient{BlockByHashMap: map[[32]byte]*enginev1.ExecutionBlockBellatrix{}}
service.cfg.ExecutionEngineCaller = engine
h := [32]byte{'a'}
p := [32]byte{'b'}
td := "0x1"
engine.BlockByHashMap[h] = &enginev1.ExecutionBlock{
engine.BlockByHashMap[h] = &enginev1.ExecutionBlockBellatrix{
Header: gethtypes.Header{
ParentHash: p,
},
@@ -191,7 +191,7 @@ func Test_getBlkParentHashAndTD(t *testing.T) {
_, _, err = service.getBlkParentHashAndTD(ctx, h[:])
require.ErrorContains(t, "pow block is nil", err)
engine.BlockByHashMap[h] = &enginev1.ExecutionBlock{
engine.BlockByHashMap[h] = &enginev1.ExecutionBlockBellatrix{
Header: gethtypes.Header{
ParentHash: p,
},
@@ -200,7 +200,7 @@ func Test_getBlkParentHashAndTD(t *testing.T) {
_, _, err = service.getBlkParentHashAndTD(ctx, h[:])
require.ErrorContains(t, "could not decode merge block total difficulty: hex string without 0x prefix", err)
engine.BlockByHashMap[h] = &enginev1.ExecutionBlock{
engine.BlockByHashMap[h] = &enginev1.ExecutionBlockBellatrix{
Header: gethtypes.Header{
ParentHash: p,
},

View File

@@ -712,6 +712,8 @@ func (s *Service) fillMissingBlockPayloadId(ctx context.Context, ti time.Time) e
// Head root should be empty when retrieving proposer index for the next slot.
_, id, has := s.cfg.ProposerSlotIndexCache.GetProposerPayloadIDs(s.CurrentSlot()+1, [32]byte{} /* head root */)
// There exists proposer for next slot, but we haven't called fcu w/ payload attribute yet.
log.Infof("missingPayloadID, GetProposerPayloadIDs(nextSlot=%d, arg.headRoot=%#x,has=%v,pid=%#x)", s.CurrentSlot()+1, [32]byte{}, has, id)
if has && id == [8]byte{} {
missedPayloadIDFilledCount.Inc()
headBlock, err := s.headBlock()

View File

@@ -69,6 +69,7 @@ func (s *Service) verifyBlkPreState(ctx context.Context, b interfaces.BeaconBloc
// during initial syncing. There's no risk given a state summary object is just a
// a subset of the block object.
if !s.cfg.BeaconDB.HasStateSummary(ctx, parentRoot) && !s.cfg.BeaconDB.HasBlock(ctx, parentRoot) {
log.Errorf("requesting blockroot %#x", bytesutil.Trunc(parentRoot[:]))
return errors.New("could not reconstruct parent state")
}

View File

@@ -1285,14 +1285,14 @@ func Test_validateMergeTransitionBlock(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
e := &mockExecution.EngineClient{BlockByHashMap: map[[32]byte]*enginev1.ExecutionBlock{}}
e.BlockByHashMap[aHash] = &enginev1.ExecutionBlock{
e := &mockExecution.EngineClient{BlockByHashMap: map[[32]byte]*enginev1.ExecutionBlockBellatrix{}}
e.BlockByHashMap[aHash] = &enginev1.ExecutionBlockBellatrix{
Header: gethtypes.Header{
ParentHash: bHash,
},
TotalDifficulty: "0x2",
}
e.BlockByHashMap[bHash] = &enginev1.ExecutionBlock{
e.BlockByHashMap[bHash] = &enginev1.ExecutionBlockBellatrix{
Header: gethtypes.Header{
ParentHash: common.BytesToHash([]byte("3")),
},

View File

@@ -311,7 +311,10 @@ func (s *Service) initializeHeadFromDB(ctx context.Context) error {
if err := s.setHead(finalizedRoot, finalizedBlock, finalizedState); err != nil {
return errors.Wrap(err, "could not set head")
}
_, err = s.notifyForkchoiceUpdate(s.ctx, &notifyForkchoiceUpdateArg{headState: finalizedState, headRoot: finalizedRoot, headBlock: finalizedBlock.Block()})
if err != nil {
return errors.Wrap(err, "error calling FCU with finalized state at startup")
}
return nil
}
@@ -446,6 +449,10 @@ func (s *Service) saveGenesisData(ctx context.Context, genesisState state.Beacon
if err := s.setHead(genesisBlkRoot, genesisBlk, genesisState); err != nil {
log.WithError(err).Fatal("Could not set head")
}
_, err = s.notifyForkchoiceUpdate(s.ctx, &notifyForkchoiceUpdateArg{headState: genesisState, headRoot: genesisBlkRoot, headBlock: genesisBlk.Block()})
if err != nil {
log.WithError(err).Fatal("Could not call FCU with genesis")
}
return nil
}

View File

@@ -53,7 +53,7 @@ func (c *SyncCommitteeHeadStateCache) Get(slot types.Slot) (state.BeaconState, e
return nil, ErrIncorrectType
}
switch st.Version() {
case version.Altair, version.Bellatrix:
case version.Altair, version.Bellatrix, version.Capella:
default:
return nil, ErrIncorrectType
}

View File

@@ -3,6 +3,8 @@ package altair
import (
"context"
log "github.com/sirupsen/logrus"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/epoch/precompute"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/helpers"
@@ -29,6 +31,7 @@ func InitializePrecomputeValidators(ctx context.Context, beaconState state.Beaco
// This shouldn't happen with a correct beacon state,
// but rather be safe to defend against index out of bound panics.
if beaconState.NumValidators() != len(inactivityScores) {
log.Errorf("NumValidators=%d inactivityScores=%d", beaconState.NumValidators(), len(inactivityScores))
return nil, nil, errors.New("num of validators is different than num of inactivity scores")
}
if err := beaconState.ReadFromEveryValidator(func(idx int, val state.ReadOnlyValidator) error {

View File

@@ -19,12 +19,7 @@ go_library(
"withdrawals.go",
],
importpath = "github.com/prysmaticlabs/prysm/v3/beacon-chain/core/blocks",
visibility = [
"//beacon-chain:__subpackages__",
"//testing/spectest:__subpackages__",
"//testing/util:__pkg__",
"//validator:__subpackages__",
],
visibility = ["//visibility:public"],
deps = [
"//beacon-chain/core/helpers:go_default_library",
"//beacon-chain/core/signing:go_default_library",
@@ -46,6 +41,7 @@ go_library(
"//math:go_default_library",
"//network/forks:go_default_library",
"//proto/engine/v1:go_default_library",
"//proto/eth/v2:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//proto/prysm/v1alpha1/attestation:go_default_library",
"//proto/prysm/v1alpha1/slashings:go_default_library",

View File

@@ -3,9 +3,14 @@
package blocks
import (
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state"
fieldparams "github.com/prysmaticlabs/prysm/v3/config/fieldparams"
"github.com/prysmaticlabs/prysm/v3/config/params"
"github.com/prysmaticlabs/prysm/v3/consensus-types/blocks"
"github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces"
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
enginev1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
)
@@ -29,3 +34,60 @@ func NewGenesisBlock(stateRoot []byte) *ethpb.SignedBeaconBlock {
}
return block
}
var ErrUnrecognizedState = errors.New("uknonwn underlying type for state.BeaconState value")
func NewGenesisBlockForState(root [32]byte, st state.BeaconState) (interfaces.SignedBeaconBlock, error) {
ps := st.ToProto()
switch ps.(type) {
case *ethpb.BeaconState:
return blocks.NewSignedBeaconBlock(&ethpb.SignedBeaconBlock{
Block: &ethpb.BeaconBlock{
ParentRoot: params.BeaconConfig().ZeroHash[:],
StateRoot: root[:],
Body: &ethpb.BeaconBlockBody{
RandaoReveal: make([]byte, fieldparams.BLSSignatureLength),
Eth1Data: &ethpb.Eth1Data{
DepositRoot: make([]byte, 32),
BlockHash: make([]byte, 32),
},
Graffiti: make([]byte, 32),
},
},
Signature: params.BeaconConfig().EmptySignature[:],
})
case *ethpb.BeaconStateBellatrix:
return blocks.NewSignedBeaconBlock(&ethpb.SignedBeaconBlockBellatrix{
Block: &ethpb.BeaconBlockBellatrix{
ParentRoot: params.BeaconConfig().ZeroHash[:],
StateRoot: root[:],
Body: &ethpb.BeaconBlockBodyBellatrix{
RandaoReveal: make([]byte, 96),
Eth1Data: &ethpb.Eth1Data{
DepositRoot: make([]byte, 32),
BlockHash: make([]byte, 32),
},
Graffiti: make([]byte, 32),
SyncAggregate: &ethpb.SyncAggregate{
SyncCommitteeBits: make([]byte, fieldparams.SyncCommitteeLength/8),
SyncCommitteeSignature: make([]byte, fieldparams.BLSSignatureLength),
},
ExecutionPayload: &enginev1.ExecutionPayload{
ParentHash: make([]byte, 32),
FeeRecipient: make([]byte, 20),
StateRoot: make([]byte, 32),
ReceiptsRoot: make([]byte, 32),
LogsBloom: make([]byte, 256),
PrevRandao: make([]byte, 32),
BaseFeePerGas: make([]byte, 32),
BlockHash: make([]byte, 32),
Transactions: make([][]byte, 0),
},
},
},
Signature: params.BeaconConfig().EmptySignature[:],
})
default:
return nil, ErrUnrecognizedState
}
}

View File

@@ -133,6 +133,7 @@ func ValidatePayloadWhenMergeCompletes(st state.BeaconState, payload interfaces.
return err
}
if !bytes.Equal(payload.ParentHash(), header.BlockHash()) {
log.Errorf("parent Hash %#x, header Hash: %#x", bytesutil.Trunc(payload.ParentHash()), bytesutil.Trunc(header.BlockHash()))
return ErrInvalidPayloadBlockHash
}
return nil

View File

@@ -2,7 +2,6 @@ package blocks
import (
"bytes"
"context"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/helpers"
@@ -15,6 +14,7 @@ import (
"github.com/prysmaticlabs/prysm/v3/crypto/hash"
"github.com/prysmaticlabs/prysm/v3/encoding/ssz"
enginev1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
ethpbv2 "github.com/prysmaticlabs/prysm/v3/proto/eth/v2"
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v3/runtime/version"
"github.com/prysmaticlabs/prysm/v3/time/slots"
@@ -22,6 +22,10 @@ import (
const executionToBLSPadding = 12
var ErrInvalidBLSChangeBeforeCapella = errors.New("cannot process BLSToExecutionChange before Capella fork")
// ProcessBLSToExecutionChanges process all signed BLS_TO_EXECUTION_MESSAGE found in the block.
// It does not verify their signature.
func ProcessBLSToExecutionChanges(
st state.BeaconState,
signed interfaces.SignedBeaconBlock) (state.BeaconState, error) {
@@ -84,6 +88,9 @@ func processBLSToExecutionChange(st state.BeaconState, signed *ethpb.SignedBLSTo
// ValidateBLSToExecutionChange validates the execution change message against the state and returns the
// validator referenced by the message.
func ValidateBLSToExecutionChange(st state.ReadOnlyBeaconState, signed *ethpb.SignedBLSToExecutionChange) (*ethpb.Validator, error) {
if st.Version() < version.Capella {
return nil, ErrInvalidBLSChangeBeforeCapella
}
if signed == nil {
return nil, errNilSignedWithdrawalMessage
}
@@ -120,13 +127,14 @@ func ProcessWithdrawals(st state.BeaconState, withdrawals []*enginev1.Withdrawal
return nil, errInvalidWithdrawalNumber
}
for i, withdrawal := range withdrawals {
if withdrawal.WithdrawalIndex != expected[i].WithdrawalIndex {
if withdrawal.Index != expected[i].Index {
return nil, errInvalidWithdrawalIndex
}
if withdrawal.ValidatorIndex != expected[i].ValidatorIndex {
log.Errorf("Expected %v, got %v", expected[i], withdrawal)
return nil, errInvalidValidatorIndex
}
if !bytes.Equal(withdrawal.ExecutionAddress, expected[i].ExecutionAddress) {
if !bytes.Equal(withdrawal.Address, expected[i].Address) {
return nil, errInvalidExecutionAddress
}
if withdrawal.Amount != expected[i].Amount {
@@ -138,7 +146,7 @@ func ProcessWithdrawals(st state.BeaconState, withdrawals []*enginev1.Withdrawal
}
}
if len(withdrawals) > 0 {
if err := st.SetNextWithdrawalIndex(withdrawals[len(withdrawals)-1].WithdrawalIndex + 1); err != nil {
if err := st.SetNextWithdrawalIndex(withdrawals[len(withdrawals)-1].Index + 1); err != nil {
return nil, errors.Wrap(err, "could not set next withdrawal index")
}
nextValidatorIndex := withdrawals[len(withdrawals)-1].ValidatorIndex + 1
@@ -146,14 +154,13 @@ func ProcessWithdrawals(st state.BeaconState, withdrawals []*enginev1.Withdrawal
nextValidatorIndex = 0
}
if err := st.SetNextWithdrawalValidatorIndex(nextValidatorIndex); err != nil {
return nil, errors.Wrap(err, "could not set latest withdrawal validator index")
return nil, errors.Wrap(err, "could not set next withdrawal validator index")
}
}
return st, nil
}
func BLSChangesSignatureBatch(
ctx context.Context,
st state.ReadOnlyBeaconState,
changes []*ethpb.SignedBLSToExecutionChange,
) (*bls.SignatureBatch, error) {
@@ -172,9 +179,6 @@ func BLSChangesSignatureBatch(
return nil, err
}
for i, change := range changes {
if ctx.Err() != nil {
return nil, ctx.Err()
}
batch.Signatures[i] = change.Signature
publicKey, err := bls.PublicKeyFromBytes(change.Message.FromBlsPubkey)
if err != nil {
@@ -189,3 +193,17 @@ func BLSChangesSignatureBatch(
}
return batch, nil
}
// VerifyBLSChangeSignature checks the signature in the SignedBLSToExecutionChange message.
func VerifyBLSChangeSignature(
st state.BeaconState,
change *ethpbv2.SignedBLSToExecutionChange,
) error {
epoch := slots.ToEpoch(st.Slot())
domain, err := signing.Domain(st.Fork(), epoch, params.BeaconConfig().DomainBLSToExecutionChange, st.GenesisValidatorsRoot())
if err != nil {
return errors.Wrap(err, "could not compute signing domain")
}
publicKey := change.Message.FromBlsPubkey
return signing.VerifySigningRoot(change.Message, publicKey, change.Signature, domain)
}

View File

@@ -1,7 +1,6 @@
package blocks_test
import (
"context"
"math/rand"
"testing"
@@ -746,7 +745,7 @@ func TestBLSChangesSignatureBatch(t *testing.T) {
}
signedChanges[i] = signed
}
batch, err := blocks.BLSChangesSignatureBatch(context.Background(), st, signedChanges)
batch, err := blocks.BLSChangesSignatureBatch(st, signedChanges)
require.NoError(t, err)
verify, err := batch.Verify()
require.NoError(t, err)

View File

@@ -6,6 +6,7 @@ go_library(
"log.go",
"skip_slot_cache.go",
"state.go",
"state-bellatrix.go",
"trailing_slot_state_cache.go",
"transition.go",
"transition_no_verify_sig.go",
@@ -36,6 +37,7 @@ go_library(
"//beacon-chain/state:go_default_library",
"//beacon-chain/state/state-native:go_default_library",
"//beacon-chain/state/stateutil:go_default_library",
"//config/fieldparams:go_default_library",
"//config/params:go_default_library",
"//consensus-types/blocks:go_default_library",
"//consensus-types/interfaces:go_default_library",
@@ -45,6 +47,7 @@ go_library(
"//encoding/bytesutil:go_default_library",
"//math:go_default_library",
"//monitoring/tracing:go_default_library",
"//proto/engine/v1:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//runtime/version:go_default_library",
"@com_github_pkg_errors//:go_default_library",

View File

@@ -0,0 +1,283 @@
package transition
import (
"context"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/v3/consensus-types/blocks"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/altair"
enginev1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
fieldparams "github.com/prysmaticlabs/prysm/v3/config/fieldparams"
"github.com/pkg/errors"
b "github.com/prysmaticlabs/prysm/v3/beacon-chain/core/blocks"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state"
state_native "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/state-native"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state/stateutil"
"github.com/prysmaticlabs/prysm/v3/config/params"
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
)
// GenesisBeaconStateBellatrix gets called when MinGenesisActiveValidatorCount count of
// full deposits were made to the deposit contract and the ChainStart log gets emitted.
//
// Spec pseudocode definition:
//
// def initialize_beacon_state_from_eth1(eth1_block_hash: Bytes32,
// eth1_timestamp: uint64,
// deposits: Sequence[Deposit]) -> BeaconState:
// fork = Fork(
// previous_version=GENESIS_FORK_VERSION,
// current_version=GENESIS_FORK_VERSION,
// epoch=GENESIS_EPOCH,
// )
// state = BeaconState(
// genesis_time=eth1_timestamp + GENESIS_DELAY,
// fork=fork,
// eth1_data=Eth1Data(block_hash=eth1_block_hash, deposit_count=uint64(len(deposits))),
// latest_block_header=BeaconBlockHeader(body_root=hash_tree_root(BeaconBlockBody())),
// randao_mixes=[eth1_block_hash] * EPOCHS_PER_HISTORICAL_VECTOR, # Seed RANDAO with Eth1 entropy
// )
//
// # Process deposits
// leaves = list(map(lambda deposit: deposit.data, deposits))
// for index, deposit in enumerate(deposits):
// deposit_data_list = List[DepositData, 2**DEPOSIT_CONTRACT_TREE_DEPTH](*leaves[:index + 1])
// state.eth1_data.deposit_root = hash_tree_root(deposit_data_list)
// process_deposit(state, deposit)
//
// # Process activations
// for index, validator in enumerate(state.validators):
// balance = state.balances[index]
// validator.effective_balance = min(balance - balance % EFFECTIVE_BALANCE_INCREMENT, MAX_EFFECTIVE_BALANCE)
// if validator.effective_balance == MAX_EFFECTIVE_BALANCE:
// validator.activation_eligibility_epoch = GENESIS_EPOCH
// validator.activation_epoch = GENESIS_EPOCH
//
// # Set genesis validators root for domain separation and chain versioning
// state.genesis_validators_root = hash_tree_root(state.validators)
//
// return state
//
// This method differs from the spec so as to process deposits beforehand instead of the end of the function.
func GenesisBeaconStateBellatrix(ctx context.Context, deposits []*ethpb.Deposit, genesisTime uint64, eth1Data *ethpb.Eth1Data, ep *enginev1.ExecutionPayload) (state.BeaconState, error) {
st, err := EmptyGenesisStateBellatrix()
if err != nil {
return nil, err
}
// Process initial deposits.
st, err = helpers.UpdateGenesisEth1Data(st, deposits, eth1Data)
if err != nil {
return nil, err
}
st, err = b.ProcessPreGenesisDeposits(ctx, st, deposits)
if err != nil {
return nil, errors.Wrap(err, "could not process validator deposits")
}
// After deposits have been processed, overwrite eth1data to what is passed in. This allows us to "pre-mine" validators
// without the deposit root and count mismatching the real deposit contract.
if err := st.SetEth1Data(eth1Data); err != nil {
return nil, err
}
if err := st.SetEth1DepositIndex(eth1Data.DepositCount); err != nil {
return nil, err
}
return OptimizedGenesisBeaconStateBellatrix(genesisTime, st, st.Eth1Data(), ep)
}
// OptimizedGenesisBeaconState is used to create a state that has already processed deposits. This is to efficiently
// create a mainnet state at chainstart.
func OptimizedGenesisBeaconStateBellatrix(genesisTime uint64, preState state.BeaconState, eth1Data *ethpb.Eth1Data, ep *enginev1.ExecutionPayload) (state.BeaconState, error) {
if eth1Data == nil {
return nil, errors.New("no eth1data provided for genesis state")
}
randaoMixes := make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector)
for i := 0; i < len(randaoMixes); i++ {
h := make([]byte, 32)
copy(h, eth1Data.BlockHash)
randaoMixes[i] = h
}
zeroHash := params.BeaconConfig().ZeroHash[:]
activeIndexRoots := make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector)
for i := 0; i < len(activeIndexRoots); i++ {
activeIndexRoots[i] = zeroHash
}
blockRoots := make([][]byte, params.BeaconConfig().SlotsPerHistoricalRoot)
for i := 0; i < len(blockRoots); i++ {
blockRoots[i] = zeroHash
}
stateRoots := make([][]byte, params.BeaconConfig().SlotsPerHistoricalRoot)
for i := 0; i < len(stateRoots); i++ {
stateRoots[i] = zeroHash
}
slashings := make([]uint64, params.BeaconConfig().EpochsPerSlashingsVector)
genesisValidatorsRoot, err := stateutil.ValidatorRegistryRoot(preState.Validators())
if err != nil {
return nil, errors.Wrapf(err, "could not hash tree root genesis validators %v", err)
}
scores, err := preState.InactivityScores()
if err != nil {
return nil, err
}
scoresMissing := len(preState.Validators()) - len(scores)
if scoresMissing > 0 {
for i := 0; i < scoresMissing; i++ {
scores = append(scores, 0)
}
}
wep, err := blocks.WrappedExecutionPayload(ep)
if err != nil {
return nil, err
}
eph, err := blocks.PayloadToHeader(wep)
if err != nil {
return nil, err
}
st := &ethpb.BeaconStateBellatrix{
// Misc fields.
Slot: 0,
GenesisTime: genesisTime,
GenesisValidatorsRoot: genesisValidatorsRoot[:],
Fork: &ethpb.Fork{
PreviousVersion: params.BeaconConfig().AltairForkVersion,
CurrentVersion: params.BeaconConfig().BellatrixForkVersion,
Epoch: 0,
},
// Validator registry fields.
Validators: preState.Validators(),
Balances: preState.Balances(),
// Randomness and committees.
RandaoMixes: randaoMixes,
// Finality.
PreviousJustifiedCheckpoint: &ethpb.Checkpoint{
Epoch: 0,
Root: params.BeaconConfig().ZeroHash[:],
},
CurrentJustifiedCheckpoint: &ethpb.Checkpoint{
Epoch: 0,
Root: params.BeaconConfig().ZeroHash[:],
},
JustificationBits: []byte{0},
FinalizedCheckpoint: &ethpb.Checkpoint{
Epoch: 0,
Root: params.BeaconConfig().ZeroHash[:],
},
HistoricalRoots: [][]byte{},
BlockRoots: blockRoots,
StateRoots: stateRoots,
Slashings: slashings,
// Eth1 data.
Eth1Data: eth1Data,
Eth1DataVotes: []*ethpb.Eth1Data{},
Eth1DepositIndex: preState.Eth1DepositIndex(),
LatestExecutionPayloadHeader: eph,
InactivityScores: scores,
}
bodyRoot, err := (&ethpb.BeaconBlockBodyBellatrix{
RandaoReveal: make([]byte, 96),
Eth1Data: &ethpb.Eth1Data{
DepositRoot: make([]byte, 32),
BlockHash: make([]byte, 32),
},
Graffiti: make([]byte, 32),
SyncAggregate: &ethpb.SyncAggregate{
SyncCommitteeBits: make([]byte, fieldparams.SyncCommitteeLength/8),
SyncCommitteeSignature: make([]byte, fieldparams.BLSSignatureLength),
},
ExecutionPayload: &enginev1.ExecutionPayload{
ParentHash: make([]byte, 32),
FeeRecipient: make([]byte, 20),
StateRoot: make([]byte, 32),
ReceiptsRoot: make([]byte, 32),
LogsBloom: make([]byte, 256),
PrevRandao: make([]byte, 32),
BaseFeePerGas: make([]byte, 32),
BlockHash: make([]byte, 32),
Transactions: make([][]byte, 0),
},
}).HashTreeRoot()
if err != nil {
return nil, errors.Wrap(err, "could not hash tree root empty block body")
}
st.LatestBlockHeader = &ethpb.BeaconBlockHeader{
ParentRoot: zeroHash,
StateRoot: zeroHash,
BodyRoot: bodyRoot[:],
}
ist, err := state_native.InitializeFromProtoBellatrix(st)
if err != nil {
return nil, err
}
sc, err := altair.NextSyncCommittee(context.Background(), ist)
if err != nil {
return nil, err
}
if err := ist.SetNextSyncCommittee(sc); err != nil {
return nil, err
}
if err := ist.SetCurrentSyncCommittee(sc); err != nil {
return nil, err
}
return ist, nil
}
// EmptyGenesisState returns an empty beacon state object.
func EmptyGenesisStateBellatrix() (state.BeaconState, error) {
st := &ethpb.BeaconStateBellatrix{
// Misc fields.
Slot: 0,
Fork: &ethpb.Fork{
PreviousVersion: params.BeaconConfig().AltairForkVersion,
CurrentVersion: params.BeaconConfig().BellatrixForkVersion,
Epoch: 0,
},
// Validator registry fields.
Validators: []*ethpb.Validator{},
Balances: []uint64{},
JustificationBits: []byte{0},
HistoricalRoots: [][]byte{},
// Eth1 data.
Eth1Data: &ethpb.Eth1Data{},
Eth1DataVotes: []*ethpb.Eth1Data{},
Eth1DepositIndex: 0,
LatestExecutionPayloadHeader: &enginev1.ExecutionPayloadHeader{
ParentHash: make([]byte, 32),
FeeRecipient: make([]byte, 20),
StateRoot: make([]byte, 32),
ReceiptsRoot: make([]byte, 32),
LogsBloom: make([]byte, 256),
PrevRandao: make([]byte, 32),
BaseFeePerGas: make([]byte, 32),
BlockHash: make([]byte, 32),
TransactionsRoot: make([]byte, 32),
},
}
return state_native.InitializeFromProtoBellatrix(st)
}

View File

@@ -205,7 +205,7 @@ func ProcessBlockNoVerifyAnySig(
if err != nil {
return nil, nil, errors.Wrap(err, "could not get BLSToExecutionChanges")
}
cSet, err := b.BLSChangesSignatureBatch(ctx, st, changes)
cSet, err := b.BLSChangesSignatureBatch(st, changes)
if err != nil {
return nil, nil, errors.Wrap(err, "could not get BLSToExecutionChanges signatures")
}

View File

@@ -1,17 +1,14 @@
package kv
import (
"bytes"
"context"
"fmt"
"github.com/prysmaticlabs/prysm/v3/encoding/ssz/detect"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/blocks"
dbIface "github.com/prysmaticlabs/prysm/v3/beacon-chain/db/iface"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state"
state_native "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/state-native"
"github.com/prysmaticlabs/prysm/v3/config/params"
consensusblocks "github.com/prysmaticlabs/prysm/v3/consensus-types/blocks"
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
)
@@ -19,17 +16,25 @@ import (
func (s *Store) SaveGenesisData(ctx context.Context, genesisState state.BeaconState) error {
stateRoot, err := genesisState.HashTreeRoot(ctx)
if err != nil {
return err
return errors.Wrap(err, "HashTreeRoot")
}
genesisBlk := blocks.NewGenesisBlock(stateRoot[:])
genesisBlkRoot, err := genesisBlk.Block.HashTreeRoot()
wsb, err := blocks.NewGenesisBlockForState(stateRoot, genesisState)
if err != nil {
return errors.Wrap(err, "NewGenesisBlockForState")
}
genesisBlkRoot, err := wsb.Block().HashTreeRoot()
if err != nil {
return errors.Wrap(err, "could not get genesis block root")
}
wsb, err := consensusblocks.NewSignedBeaconBlock(genesisBlk)
if err != nil {
return errors.Wrap(err, "could not wrap genesis block")
}
/*
lbhr, err := genesisState.LatestBlockHeader().HashTreeRoot()
if err != nil {
return errors.Wrap(err, "unable to compute HTR of latest block header from genesis state")
}
if genesisBlkRoot != lbhr {
return fmt.Errorf("state.latest_block_header=%#x does not match derived genessis block root=%#x", genesisBlkRoot, lbhr)
}
*/
if err := s.SaveBlock(ctx, wsb); err != nil {
return errors.Wrap(err, "could not save genesis block")
}
@@ -54,11 +59,11 @@ func (s *Store) SaveGenesisData(ctx context.Context, genesisState state.BeaconSt
// LoadGenesis loads a genesis state from a ssz-serialized byte slice, if no genesis exists already.
func (s *Store) LoadGenesis(ctx context.Context, sb []byte) error {
st := &ethpb.BeaconState{}
if err := st.UnmarshalSSZ(sb); err != nil {
vu, err := detect.FromState(sb)
if err != nil {
return err
}
gs, err := state_native.InitializeFromProtoUnsafePhase0(st)
gs, err := vu.UnmarshalBeaconState(sb)
if err != nil {
return err
}
@@ -83,10 +88,6 @@ func (s *Store) LoadGenesis(ctx context.Context, sb []byte) error {
return dbIface.ErrExistingGenesisState
}
if !bytes.Equal(gs.Fork().CurrentVersion, params.BeaconConfig().GenesisForkVersion) {
return fmt.Errorf("loaded genesis fork version (%#x) does not match config genesis "+
"fork version (%#x)", gs.Fork().CurrentVersion, params.BeaconConfig().GenesisForkVersion)
}
return s.SaveGenesisData(ctx, gs)
}

View File

@@ -41,6 +41,8 @@ go_library(
"//config/params:go_default_library",
"//consensus-types/blocks:go_default_library",
"//consensus-types/interfaces:go_default_library",
"//consensus-types/payload-attribute:go_default_library",
"//consensus-types/primitives:go_default_library",
"//container/trie:go_default_library",
"//contracts/deposit:go_default_library",
"//crypto/hash:go_default_library",
@@ -52,6 +54,7 @@ go_library(
"//network/authorization:go_default_library",
"//proto/engine/v1:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//runtime/version:go_default_library",
"//time:go_default_library",
"//time/slots:go_default_library",
"@com_github_ethereum_go_ethereum//:go_default_library",
@@ -108,6 +111,7 @@ go_test(
"//config/params:go_default_library",
"//consensus-types/blocks:go_default_library",
"//consensus-types/interfaces:go_default_library",
"//consensus-types/payload-attribute:go_default_library",
"//consensus-types/primitives:go_default_library",
"//container/trie:go_default_library",
"//contracts/deposit:go_default_library",
@@ -118,6 +122,7 @@ go_test(
"//network/authorization:go_default_library",
"//proto/engine/v1:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//runtime/version:go_default_library",
"//testing/assert:go_default_library",
"//testing/require:go_default_library",
"//testing/util:go_default_library",

View File

@@ -106,7 +106,11 @@ func (s *Service) BlockByTimestamp(ctx context.Context, time uint64) (*types.Hea
latestBlkTime := s.latestEth1Data.BlockTime
s.latestEth1DataLock.RUnlock()
log.WithField("time (req val)", time).WithField("latestBlockTime", latestBlkTime).WithField("latestBlockHeight", s.latestEth1Data.BlockHeight).Info("BlockByTimestamp")
if time > latestBlkTime {
if latestBlkHeight < params.BeaconConfig().Eth1FollowDistance {
}
return nil, errors.Wrap(errBlockTimeTooLate, fmt.Sprintf("(%d > %d)", time, latestBlkTime))
}
// Initialize a pointer to eth1 chain's history to start our search from.

View File

@@ -163,7 +163,7 @@ func TestService_logTtdStatus(t *testing.T) {
require.NoError(t, r.Body.Close())
}()
resp := &pb.ExecutionBlock{
resp := &pb.ExecutionBlockBellatrix{
Header: gethtypes.Header{
ParentHash: common.Hash{},
UncleHash: common.Hash{},
@@ -219,7 +219,7 @@ func TestService_logTtdStatus_NotSyncedClient(t *testing.T) {
require.NoError(t, r.Body.Close())
}()
resp := (*pb.ExecutionBlock)(nil) // Nil response when a client is not synced
resp := (*pb.ExecutionBlockBellatrix)(nil) // Nil response when a client is not synced
respJSON := map[string]interface{}{
"jsonrpc": "2.0",
"id": 1,

View File

@@ -19,8 +19,12 @@ import (
"github.com/prysmaticlabs/prysm/v3/config/params"
"github.com/prysmaticlabs/prysm/v3/consensus-types/blocks"
"github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces"
payloadattribute "github.com/prysmaticlabs/prysm/v3/consensus-types/payload-attribute"
types2 "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
pb "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
"github.com/prysmaticlabs/prysm/v3/runtime/version"
"github.com/prysmaticlabs/prysm/v3/time/slots"
"github.com/sirupsen/logrus"
"go.opencensus.io/trace"
)
@@ -28,10 +32,16 @@ import (
const (
// NewPayloadMethod v1 request string for JSON-RPC.
NewPayloadMethod = "engine_newPayloadV1"
// NewPayloadMethod v2 request string for JSON-RPC.
NewPayloadMethodV2 = "engine_newPayloadV2"
// ForkchoiceUpdatedMethod v1 request string for JSON-RPC.
ForkchoiceUpdatedMethod = "engine_forkchoiceUpdatedV1"
// ForkchoiceUpdatedMethod v2 request string for JSON-RPC.
ForkchoiceUpdatedMethodV2 = "engine_forkchoiceUpdatedV2"
// GetPayloadMethod v1 request string for JSON-RPC.
GetPayloadMethod = "engine_getPayloadV1"
// GetPayloadMethod v2 request string for JSON-RPC.
GetPayloadMethodV2 = "engine_getPayloadV2"
// ExchangeTransitionConfigurationMethod v1 request string for JSON-RPC.
ExchangeTransitionConfigurationMethod = "engine_exchangeTransitionConfigurationV1"
// ExecutionBlockByHashMethod request string for JSON-RPC.
@@ -53,7 +63,7 @@ type ForkchoiceUpdatedResponse struct {
// block with an execution payload from a signed beacon block and a connection
// to an execution client's engine API.
type ExecutionPayloadReconstructor interface {
ReconstructFullBellatrixBlock(
ReconstructFullBlock(
ctx context.Context, blindedBlock interfaces.SignedBeaconBlock,
) (interfaces.SignedBeaconBlock, error)
ReconstructFullBellatrixBlockBatch(
@@ -66,13 +76,13 @@ type ExecutionPayloadReconstructor interface {
type EngineCaller interface {
NewPayload(ctx context.Context, payload interfaces.ExecutionData) ([]byte, error)
ForkchoiceUpdated(
ctx context.Context, state *pb.ForkchoiceState, attrs *pb.PayloadAttributes,
ctx context.Context, state *pb.ForkchoiceState, attrs payloadattribute.Attributer,
) (*pb.PayloadIDBytes, []byte, error)
GetPayload(ctx context.Context, payloadId [8]byte) (*pb.ExecutionPayload, error)
GetPayload(ctx context.Context, payloadId [8]byte, slot types2.Slot) (interfaces.ExecutionData, error)
ExchangeTransitionConfiguration(
ctx context.Context, cfg *pb.TransitionConfiguration,
) error
ExecutionBlockByHash(ctx context.Context, hash common.Hash, withTxs bool) (*pb.ExecutionBlock, error)
ExecutionBlockByHash(ctx context.Context, forkVersion int, hash common.Hash, withTxs bool) (interface{}, error)
GetTerminalBlockHash(ctx context.Context, transitionTime uint64) ([]byte, bool, error)
}
@@ -89,13 +99,21 @@ func (s *Service) NewPayload(ctx context.Context, payload interfaces.ExecutionDa
ctx, cancel := context.WithDeadline(ctx, d)
defer cancel()
result := &pb.PayloadStatus{}
payloadPb, ok := payload.Proto().(*pb.ExecutionPayload)
payloadPb, ok := payload.Proto().(*pb.ExecutionPayloadCapella)
if !ok {
return nil, errors.New("execution data must be an execution payload")
}
err := s.rpcClient.CallContext(ctx, result, NewPayloadMethod, payloadPb)
if err != nil {
return nil, handleRPCError(err)
payloadPb, ok := payload.Proto().(*pb.ExecutionPayload)
if !ok {
return nil, errors.New("execution data must be a Bellatrix or Capella execution payload")
}
err := s.rpcClient.CallContext(ctx, result, NewPayloadMethod, payloadPb)
if err != nil {
return nil, handleRPCError(err)
}
} else {
err := s.rpcClient.CallContext(ctx, result, NewPayloadMethodV2, payloadPb)
if err != nil {
return nil, handleRPCError(err)
}
}
switch result.Status {
@@ -114,7 +132,7 @@ func (s *Service) NewPayload(ctx context.Context, payload interfaces.ExecutionDa
// ForkchoiceUpdated calls the engine_forkchoiceUpdatedV1 method via JSON-RPC.
func (s *Service) ForkchoiceUpdated(
ctx context.Context, state *pb.ForkchoiceState, attrs *pb.PayloadAttributes,
ctx context.Context, state *pb.ForkchoiceState, attrs payloadattribute.Attributer,
) (*pb.PayloadIDBytes, []byte, error) {
ctx, span := trace.StartSpan(ctx, "powchain.engine-api-client.ForkchoiceUpdated")
defer span.End()
@@ -127,9 +145,29 @@ func (s *Service) ForkchoiceUpdated(
ctx, cancel := context.WithDeadline(ctx, d)
defer cancel()
result := &ForkchoiceUpdatedResponse{}
err := s.rpcClient.CallContext(ctx, result, ForkchoiceUpdatedMethod, state, attrs)
if err != nil {
return nil, nil, handleRPCError(err)
if attrs == nil {
return nil, nil, errors.New("nil payload attribute")
}
switch attrs.Version() {
case version.Bellatrix:
a, err := attrs.PbV1()
if err != nil {
return nil, nil, err
}
err = s.rpcClient.CallContext(ctx, result, ForkchoiceUpdatedMethod, state, a)
if err != nil {
return nil, nil, handleRPCError(err)
}
case version.Capella:
a, err := attrs.PbV2()
if err != nil {
return nil, nil, err
}
err = s.rpcClient.CallContext(ctx, result, ForkchoiceUpdatedMethodV2, state, a)
if err != nil {
return nil, nil, handleRPCError(err)
}
}
if result.Status == nil {
@@ -149,7 +187,7 @@ func (s *Service) ForkchoiceUpdated(
}
// GetPayload calls the engine_getPayloadV1 method via JSON-RPC.
func (s *Service) GetPayload(ctx context.Context, payloadId [8]byte) (*pb.ExecutionPayload, error) {
func (s *Service) GetPayload(ctx context.Context, payloadId [8]byte, slot types2.Slot) (interfaces.ExecutionData, error) {
ctx, span := trace.StartSpan(ctx, "powchain.engine-api-client.GetPayload")
defer span.End()
start := time.Now()
@@ -160,9 +198,22 @@ func (s *Service) GetPayload(ctx context.Context, payloadId [8]byte) (*pb.Execut
d := time.Now().Add(defaultEngineTimeout)
ctx, cancel := context.WithDeadline(ctx, d)
defer cancel()
if slots.ToEpoch(slot) >= params.BeaconConfig().CapellaForkEpoch {
result := &pb.ExecutionPayloadCapella{}
err := s.rpcClient.CallContext(ctx, result, GetPayloadMethodV2, pb.PayloadIDBytes(payloadId))
if err != nil {
return nil, handleRPCError(err)
}
return blocks.WrappedExecutionPayloadCapella(result)
}
result := &pb.ExecutionPayload{}
err := s.rpcClient.CallContext(ctx, result, GetPayloadMethod, pb.PayloadIDBytes(payloadId))
return result, handleRPCError(err)
if err != nil {
return nil, handleRPCError(err)
}
return blocks.WrappedExecutionPayload(result)
}
// ExchangeTransitionConfiguration calls the engine_exchangeTransitionConfigurationV1 method via JSON-RPC.
@@ -253,16 +304,20 @@ func (s *Service) GetTerminalBlockHash(ctx context.Context, transitionTime uint6
if parentHash == params.BeaconConfig().ZeroHash {
return nil, false, nil
}
parentBlk, err := s.ExecutionBlockByHash(ctx, parentHash, false /* no txs */)
parentBlk, err := s.ExecutionBlockByHash(ctx, version.Bellatrix, parentHash, false /* no txs */)
if err != nil {
return nil, false, errors.Wrap(err, "could not get parent execution block")
}
if parentBlk == nil {
return nil, false, errors.New("parent execution block is nil")
}
bellatrixParentBlk, ok := parentBlk.(*pb.ExecutionBlockBellatrix)
if !ok {
return nil, false, fmt.Errorf("wrong execution block type %T", parentBlk)
}
if blockReachedTTD {
parentTotalDifficulty, err := tDStringToUint256(parentBlk.TotalDifficulty)
parentTotalDifficulty, err := tDStringToUint256(bellatrixParentBlk.TotalDifficulty)
if err != nil {
return nil, false, errors.Wrap(err, "could not convert total difficulty to uint256")
}
@@ -281,7 +336,7 @@ func (s *Service) GetTerminalBlockHash(ctx context.Context, transitionTime uint6
"number": blk.Number,
"hash": fmt.Sprintf("%#x", bytesutil.Trunc(blk.Hash[:])),
"td": blk.TotalDifficulty,
"parentTd": parentBlk.TotalDifficulty,
"parentTd": bellatrixParentBlk.TotalDifficulty,
"ttd": terminalTotalDifficulty,
}).Info("Retrieved terminal block hash")
return blk.Hash[:], true, nil
@@ -289,17 +344,17 @@ func (s *Service) GetTerminalBlockHash(ctx context.Context, transitionTime uint6
} else {
return nil, false, nil
}
blk = parentBlk
blk = bellatrixParentBlk
}
}
// LatestExecutionBlock fetches the latest execution engine block by calling
// eth_blockByNumber via JSON-RPC.
func (s *Service) LatestExecutionBlock(ctx context.Context) (*pb.ExecutionBlock, error) {
func (s *Service) LatestExecutionBlock(ctx context.Context) (*pb.ExecutionBlockBellatrix, error) {
ctx, span := trace.StartSpan(ctx, "powchain.engine-api-client.LatestExecutionBlock")
defer span.End()
result := &pb.ExecutionBlock{}
result := &pb.ExecutionBlockBellatrix{}
err := s.rpcClient.CallContext(
ctx,
result,
@@ -311,29 +366,38 @@ func (s *Service) LatestExecutionBlock(ctx context.Context) (*pb.ExecutionBlock,
}
// ExecutionBlockByHash fetches an execution engine block by hash by calling
// eth_blockByHash via JSON-RPC.
func (s *Service) ExecutionBlockByHash(ctx context.Context, hash common.Hash, withTxs bool) (*pb.ExecutionBlock, error) {
// eth_blockByHash via JSON-RPC. The forkVersion parameter determines which fork's
// execution block will be returned.
func (s *Service) ExecutionBlockByHash(ctx context.Context, forkVersion int, hash common.Hash, withTxs bool) (interface{}, error) {
ctx, span := trace.StartSpan(ctx, "powchain.engine-api-client.ExecutionBlockByHash")
defer span.End()
result := &pb.ExecutionBlock{}
var result interface{}
switch forkVersion {
case version.Capella:
result = &pb.ExecutionBlockCapella{}
case version.Bellatrix:
result = &pb.ExecutionBlockBellatrix{}
default:
return nil, fmt.Errorf("unsupported execution block version %s", version.String(forkVersion))
}
err := s.rpcClient.CallContext(ctx, result, ExecutionBlockByHashMethod, hash, withTxs)
return result, handleRPCError(err)
}
// ExecutionBlocksByHashes fetches a batch of execution engine blocks by hash by calling
// eth_blockByHash via JSON-RPC.
func (s *Service) ExecutionBlocksByHashes(ctx context.Context, hashes []common.Hash, withTxs bool) ([]*pb.ExecutionBlock, error) {
func (s *Service) ExecutionBlocksByHashes(ctx context.Context, hashes []common.Hash, withTxs bool) ([]*pb.ExecutionBlockBellatrix, error) {
_, span := trace.StartSpan(ctx, "powchain.engine-api-client.ExecutionBlocksByHashes")
defer span.End()
numOfHashes := len(hashes)
elems := make([]gethRPC.BatchElem, 0, numOfHashes)
execBlks := make([]*pb.ExecutionBlock, 0, numOfHashes)
execBlks := make([]*pb.ExecutionBlockBellatrix, 0, numOfHashes)
errs := make([]error, 0, numOfHashes)
if numOfHashes == 0 {
return execBlks, nil
}
for _, h := range hashes {
blk := &pb.ExecutionBlock{}
blk := &pb.ExecutionBlockBellatrix{}
err := error(nil)
newH := h
elems = append(elems, gethRPC.BatchElem{
@@ -377,9 +441,9 @@ func (s *Service) HeaderByNumber(ctx context.Context, number *big.Int) (*types.H
return hdr, err
}
// ReconstructFullBellatrixBlock takes in a blinded beacon block and reconstructs
// ReconstructFullBlock takes in a blinded beacon block and reconstructs
// a beacon block with a full execution payload via the engine API.
func (s *Service) ReconstructFullBellatrixBlock(
func (s *Service) ReconstructFullBlock(
ctx context.Context, blindedBlock interfaces.SignedBeaconBlock,
) (interfaces.SignedBeaconBlock, error) {
if err := blocks.BeaconBlockIsNil(blindedBlock); err != nil {
@@ -404,10 +468,19 @@ func (s *Service) ReconstructFullBellatrixBlock(
}
executionBlockHash := common.BytesToHash(header.BlockHash())
executionBlock, err := s.ExecutionBlockByHash(ctx, executionBlockHash, true /* with txs */)
var executionBlockIface interface{}
if blindedBlock.Version() == version.Bellatrix {
executionBlockIface, err = s.ExecutionBlockByHash(ctx, version.Bellatrix, executionBlockHash, true /* with txs */)
} else {
executionBlockIface, err = s.ExecutionBlockByHash(ctx, version.Capella, executionBlockHash, true /* with txs */)
}
if err != nil {
return nil, fmt.Errorf("could not fetch execution block with txs by hash %#x: %v", executionBlockHash, err)
}
executionBlock, ok := executionBlockIface.(pb.ExecutionBlock)
if !ok {
return nil, fmt.Errorf("block type %T does not implement ExecutionBlock", executionBlockIface)
}
if executionBlock == nil {
return nil, fmt.Errorf("received nil execution block for request by hash %#x", executionBlockHash)
}
@@ -415,7 +488,7 @@ func (s *Service) ReconstructFullBellatrixBlock(
if err != nil {
return nil, err
}
fullBlock, err := blocks.BuildSignedBeaconBlockFromExecutionPayload(blindedBlock, payload)
fullBlock, err := blocks.BuildSignedBeaconBlockFromExecutionPayload(blindedBlock, payload.Proto())
if err != nil {
return nil, err
}
@@ -478,7 +551,7 @@ func (s *Service) ReconstructFullBellatrixBlockBatch(
if err != nil {
return nil, err
}
fullBlock, err := blocks.BuildSignedBeaconBlockFromExecutionPayload(blindedBlocks[realIdx], payload)
fullBlock, err := blocks.BuildSignedBeaconBlockFromExecutionPayload(blindedBlocks[realIdx], payload.Proto())
if err != nil {
return nil, err
}
@@ -499,27 +572,52 @@ func (s *Service) ReconstructFullBellatrixBlockBatch(
}
func fullPayloadFromExecutionBlock(
header interfaces.ExecutionData, block *pb.ExecutionBlock,
) (*pb.ExecutionPayload, error) {
header interfaces.ExecutionData, block pb.ExecutionBlock,
) (interfaces.ExecutionData, error) {
if header.IsNil() || block == nil {
return nil, errors.New("execution block and header cannot be nil")
}
if !bytes.Equal(header.BlockHash(), block.Hash[:]) {
blockHash := block.GetHash()
if !bytes.Equal(header.BlockHash(), blockHash[:]) {
return nil, fmt.Errorf(
"block hash field in execution header %#x does not match execution block hash %#x",
header.BlockHash(),
block.Hash,
blockHash,
)
}
txs := make([][]byte, len(block.Transactions))
for i, tx := range block.Transactions {
blockTransactions := block.GetTransactions()
txs := make([][]byte, len(blockTransactions))
for i, tx := range blockTransactions {
txBin, err := tx.MarshalBinary()
if err != nil {
return nil, err
}
txs[i] = txBin
}
return &pb.ExecutionPayload{
if block.Version() == version.Bellatrix {
return blocks.WrappedExecutionPayload(&pb.ExecutionPayload{
ParentHash: header.ParentHash(),
FeeRecipient: header.FeeRecipient(),
StateRoot: header.StateRoot(),
ReceiptsRoot: header.ReceiptsRoot(),
LogsBloom: header.LogsBloom(),
PrevRandao: header.PrevRandao(),
BlockNumber: header.BlockNumber(),
GasLimit: header.GasLimit(),
GasUsed: header.GasUsed(),
Timestamp: header.Timestamp(),
ExtraData: header.ExtraData(),
BaseFeePerGas: header.BaseFeePerGas(),
BlockHash: blockHash[:],
Transactions: txs,
})
}
withdrawals, err := block.GetWithdrawals()
if err != nil {
return nil, err
}
return blocks.WrappedExecutionPayloadCapella(&pb.ExecutionPayloadCapella{
ParentHash: header.ParentHash(),
FeeRecipient: header.FeeRecipient(),
StateRoot: header.StateRoot(),
@@ -532,9 +630,10 @@ func fullPayloadFromExecutionBlock(
Timestamp: header.Timestamp(),
ExtraData: header.ExtraData(),
BaseFeePerGas: header.BaseFeePerGas(),
BlockHash: block.Hash[:],
BlockHash: blockHash[:],
Transactions: txs,
}, nil
Withdrawals: withdrawals,
})
}
// Handles errors received from the RPC server according to the specification.

View File

@@ -178,7 +178,7 @@ func FuzzExecutionBlock(f *testing.F) {
S: big.NewInt(math.MaxInt),
}
tx := types.NewTx(innerData)
execBlock := &pb.ExecutionBlock{
execBlock := &pb.ExecutionBlockBellatrix{
Header: types.Header{
ParentHash: common.Hash([32]byte{0xFF, 0x01, 0xFF, 0x01, 0xFF, 0x01, 0xFF, 0x01, 0xFF, 0x01, 0xFF, 0x01, 0xFF, 0x01, 0xFF, 0x01}),
Root: common.Hash([32]byte{0xFF, 0x01, 0xFF, 0x01, 0xFF, 0x01, 0xFF, 0x01, 0xFF, 0x01, 0xFF, 0x01, 0xFF, 0x01, 0xFF, 0x01}),
@@ -203,7 +203,7 @@ func FuzzExecutionBlock(f *testing.F) {
f.Fuzz(func(t *testing.T, jsonBlob []byte) {
gethResp := make(map[string]interface{})
prysmResp := &pb.ExecutionBlock{}
prysmResp := &pb.ExecutionBlockBellatrix{}
gethErr := json.Unmarshal(jsonBlob, &gethResp)
prysmErr := json.Unmarshal(jsonBlob, prysmResp)
// Nothing to marshal if we have an error.
@@ -237,7 +237,7 @@ func FuzzExecutionBlock(f *testing.F) {
})
}
func isBogusTransactionHash(blk *pb.ExecutionBlock, jsonMap map[string]interface{}) bool {
func isBogusTransactionHash(blk *pb.ExecutionBlockBellatrix, jsonMap map[string]interface{}) bool {
if blk.Transactions == nil {
return false
}
@@ -260,7 +260,7 @@ func isBogusTransactionHash(blk *pb.ExecutionBlock, jsonMap map[string]interface
func compareHeaders(t *testing.T, jsonBlob []byte) {
gethResp := &types.Header{}
prysmResp := &pb.ExecutionBlock{}
prysmResp := &pb.ExecutionBlockBellatrix{}
gethErr := json.Unmarshal(jsonBlob, gethResp)
prysmErr := json.Unmarshal(jsonBlob, prysmResp)
assert.Equal(t, gethErr != nil, prysmErr != nil, fmt.Sprintf("geth and prysm unmarshaller return inconsistent errors. %v and %v", gethErr, prysmErr))
@@ -282,7 +282,7 @@ func compareHeaders(t *testing.T, jsonBlob []byte) {
assert.DeepEqual(t, newGethResp, newGethResp2)
}
func validateBlockConsistency(execBlock *pb.ExecutionBlock, jsonMap map[string]interface{}) error {
func validateBlockConsistency(execBlock *pb.ExecutionBlockBellatrix, jsonMap map[string]interface{}) error {
blockVal := reflect.ValueOf(execBlock).Elem()
bType := reflect.TypeOf(execBlock).Elem()
@@ -316,7 +316,7 @@ func validateBlockConsistency(execBlock *pb.ExecutionBlock, jsonMap map[string]i
return nil
}
func jsonFieldsAreValid(execBlock *pb.ExecutionBlock, jsonMap map[string]interface{}) (bool, error) {
func jsonFieldsAreValid(execBlock *pb.ExecutionBlockBellatrix, jsonMap map[string]interface{}) (bool, error) {
bType := reflect.TypeOf(execBlock).Elem()
fieldnum := bType.NumField()

View File

@@ -24,8 +24,10 @@ import (
"github.com/prysmaticlabs/prysm/v3/config/params"
"github.com/prysmaticlabs/prysm/v3/consensus-types/blocks"
"github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces"
payloadattribute "github.com/prysmaticlabs/prysm/v3/consensus-types/payload-attribute"
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
pb "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
"github.com/prysmaticlabs/prysm/v3/runtime/version"
"github.com/prysmaticlabs/prysm/v3/testing/assert"
"github.com/prysmaticlabs/prysm/v3/testing/require"
"github.com/prysmaticlabs/prysm/v3/testing/util"
@@ -72,7 +74,9 @@ func TestClient_IPC(t *testing.T) {
t.Run(ForkchoiceUpdatedMethod, func(t *testing.T) {
want, ok := fix["ForkchoiceUpdatedResponse"].(*ForkchoiceUpdatedResponse)
require.Equal(t, true, ok)
payloadID, validHash, err := srv.ForkchoiceUpdated(ctx, &pb.ForkchoiceState{}, &pb.PayloadAttributes{})
attr, err := payloadattribute.New(&pb.PayloadAttributes{})
require.NoError(t, err)
payloadID, validHash, err := srv.ForkchoiceUpdated(ctx, &pb.ForkchoiceState{}, attr)
require.NoError(t, err)
require.DeepEqual(t, want.Status.LatestValidHash, validHash)
require.DeepEqual(t, want.PayloadId, payloadID)
@@ -95,17 +99,17 @@ func TestClient_IPC(t *testing.T) {
require.NoError(t, err)
})
t.Run(ExecutionBlockByNumberMethod, func(t *testing.T) {
want, ok := fix["ExecutionBlock"].(*pb.ExecutionBlock)
want, ok := fix["ExecutionBlock"].(*pb.ExecutionBlockBellatrix)
require.Equal(t, true, ok)
resp, err := srv.LatestExecutionBlock(ctx)
require.NoError(t, err)
require.DeepEqual(t, want, resp)
})
t.Run(ExecutionBlockByHashMethod, func(t *testing.T) {
want, ok := fix["ExecutionBlock"].(*pb.ExecutionBlock)
want, ok := fix["ExecutionBlock"].(*pb.ExecutionBlockBellatrix)
require.Equal(t, true, ok)
arg := common.BytesToHash([]byte("foo"))
resp, err := srv.ExecutionBlockByHash(ctx, arg, true /* with txs */)
resp, err := srv.ExecutionBlockByHash(ctx, version.Bellatrix, arg, true /* with txs */)
require.NoError(t, err)
require.DeepEqual(t, want, resp)
})
@@ -173,7 +177,9 @@ func TestClient_HTTP(t *testing.T) {
srv := forkchoiceUpdateSetup(t, forkChoiceState, payloadAttributes, want)
// We call the RPC method via HTTP and expect a proper result.
payloadID, validHash, err := srv.ForkchoiceUpdated(ctx, forkChoiceState, payloadAttributes)
attr, err := payloadattribute.New(payloadAttributes)
require.NoError(t, err)
payloadID, validHash, err := srv.ForkchoiceUpdated(ctx, forkChoiceState, attr)
require.NoError(t, err)
require.DeepEqual(t, want.Status.LatestValidHash, validHash)
require.DeepEqual(t, want.PayloadId, payloadID)
@@ -194,7 +200,9 @@ func TestClient_HTTP(t *testing.T) {
client := forkchoiceUpdateSetup(t, forkChoiceState, payloadAttributes, want)
// We call the RPC method via HTTP and expect a proper result.
payloadID, validHash, err := client.ForkchoiceUpdated(ctx, forkChoiceState, payloadAttributes)
attr, err := payloadattribute.New(&payloadAttributes)
require.NoError(t, err)
payloadID, validHash, err := client.ForkchoiceUpdated(ctx, forkChoiceState, attr)
require.ErrorIs(t, err, ErrAcceptedSyncingPayloadStatus)
require.DeepEqual(t, (*pb.PayloadIDBytes)(nil), payloadID)
require.DeepEqual(t, []byte(nil), validHash)
@@ -215,7 +223,9 @@ func TestClient_HTTP(t *testing.T) {
client := forkchoiceUpdateSetup(t, forkChoiceState, payloadAttributes, want)
// We call the RPC method via HTTP and expect a proper result.
payloadID, validHash, err := client.ForkchoiceUpdated(ctx, forkChoiceState, payloadAttributes)
attr, err := payloadattribute.New(&payloadAttributes)
require.NoError(t, err)
payloadID, validHash, err := client.ForkchoiceUpdated(ctx, forkChoiceState, attr)
require.ErrorIs(t, err, ErrInvalidPayloadStatus)
require.DeepEqual(t, (*pb.PayloadIDBytes)(nil), payloadID)
require.DeepEqual(t, want.Status.LatestValidHash, validHash)
@@ -236,7 +246,9 @@ func TestClient_HTTP(t *testing.T) {
client := forkchoiceUpdateSetup(t, forkChoiceState, payloadAttributes, want)
// We call the RPC method via HTTP and expect a proper result.
payloadID, validHash, err := client.ForkchoiceUpdated(ctx, forkChoiceState, payloadAttributes)
attr, err := payloadattribute.New(&payloadAttributes)
require.NoError(t, err)
payloadID, validHash, err := client.ForkchoiceUpdated(ctx, forkChoiceState, attr)
require.ErrorIs(t, err, ErrUnknownPayloadStatus)
require.DeepEqual(t, (*pb.PayloadIDBytes)(nil), payloadID)
require.DeepEqual(t, []byte(nil), validHash)
@@ -312,7 +324,7 @@ func TestClient_HTTP(t *testing.T) {
require.DeepEqual(t, []uint8(nil), resp)
})
t.Run(ExecutionBlockByNumberMethod, func(t *testing.T) {
want, ok := fix["ExecutionBlock"].(*pb.ExecutionBlock)
want, ok := fix["ExecutionBlock"].(*pb.ExecutionBlockBellatrix)
require.Equal(t, true, ok)
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
@@ -381,7 +393,7 @@ func TestClient_HTTP(t *testing.T) {
})
t.Run(ExecutionBlockByHashMethod, func(t *testing.T) {
arg := common.BytesToHash([]byte("foo"))
want, ok := fix["ExecutionBlock"].(*pb.ExecutionBlock)
want, ok := fix["ExecutionBlock"].(*pb.ExecutionBlockBellatrix)
require.Equal(t, true, ok)
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
@@ -413,7 +425,7 @@ func TestClient_HTTP(t *testing.T) {
service.rpcClient = rpcClient
// We call the RPC method via HTTP and expect a proper result.
resp, err := service.ExecutionBlockByHash(ctx, arg, true /* with txs */)
resp, err := service.ExecutionBlockByHash(ctx, version.Bellatrix, arg, true /* with txs */)
require.NoError(t, err)
require.DeepEqual(t, want, resp)
})
@@ -424,7 +436,7 @@ func TestReconstructFullBellatrixBlock(t *testing.T) {
t.Run("nil block", func(t *testing.T) {
service := &Service{}
_, err := service.ReconstructFullBellatrixBlock(ctx, nil)
_, err := service.ReconstructFullBlock(ctx, nil)
require.ErrorContains(t, "nil data", err)
})
t.Run("only blinded block", func(t *testing.T) {
@@ -433,7 +445,7 @@ func TestReconstructFullBellatrixBlock(t *testing.T) {
bellatrixBlock := util.NewBeaconBlockBellatrix()
wrapped, err := blocks.NewSignedBeaconBlock(bellatrixBlock)
require.NoError(t, err)
_, err = service.ReconstructFullBellatrixBlock(ctx, wrapped)
_, err = service.ReconstructFullBlock(ctx, wrapped)
require.ErrorContains(t, want, err)
})
t.Run("pre-merge execution payload", func(t *testing.T) {
@@ -448,7 +460,7 @@ func TestReconstructFullBellatrixBlock(t *testing.T) {
require.NoError(t, err)
wantedWrapped, err := blocks.NewSignedBeaconBlock(wanted)
require.NoError(t, err)
reconstructed, err := service.ReconstructFullBellatrixBlock(ctx, wrapped)
reconstructed, err := service.ReconstructFullBlock(ctx, wrapped)
require.NoError(t, err)
require.DeepEqual(t, wantedWrapped, reconstructed)
})
@@ -521,7 +533,7 @@ func TestReconstructFullBellatrixBlock(t *testing.T) {
blindedBlock.Block.Body.ExecutionPayloadHeader = header
wrapped, err := blocks.NewSignedBeaconBlock(blindedBlock)
require.NoError(t, err)
reconstructed, err := service.ReconstructFullBellatrixBlock(ctx, wrapped)
reconstructed, err := service.ReconstructFullBlock(ctx, wrapped)
require.NoError(t, err)
got, err := reconstructed.Block().Body().Execution()
@@ -677,8 +689,8 @@ func TestServer_getPowBlockHashAtTerminalTotalDifficulty(t *testing.T) {
tests := []struct {
name string
paramsTd string
currentPowBlock *pb.ExecutionBlock
parentPowBlock *pb.ExecutionBlock
currentPowBlock *pb.ExecutionBlockBellatrix
parentPowBlock *pb.ExecutionBlockBellatrix
errLatestExecutionBlk error
wantTerminalBlockHash []byte
wantExists bool
@@ -703,7 +715,7 @@ func TestServer_getPowBlockHashAtTerminalTotalDifficulty(t *testing.T) {
{
name: "current execution block invalid TD",
paramsTd: "1",
currentPowBlock: &pb.ExecutionBlock{
currentPowBlock: &pb.ExecutionBlockBellatrix{
Hash: common.BytesToHash([]byte("a")),
TotalDifficulty: "1115792089237316195423570985008687907853269984665640564039457584007913129638912",
},
@@ -712,7 +724,7 @@ func TestServer_getPowBlockHashAtTerminalTotalDifficulty(t *testing.T) {
{
name: "current execution block has zero hash parent",
paramsTd: "2",
currentPowBlock: &pb.ExecutionBlock{
currentPowBlock: &pb.ExecutionBlockBellatrix{
Hash: common.BytesToHash([]byte("a")),
Header: gethtypes.Header{
ParentHash: common.BytesToHash(params.BeaconConfig().ZeroHash[:]),
@@ -723,7 +735,7 @@ func TestServer_getPowBlockHashAtTerminalTotalDifficulty(t *testing.T) {
{
name: "could not get parent block",
paramsTd: "2",
currentPowBlock: &pb.ExecutionBlock{
currentPowBlock: &pb.ExecutionBlockBellatrix{
Hash: common.BytesToHash([]byte("a")),
Header: gethtypes.Header{
ParentHash: common.BytesToHash([]byte("b")),
@@ -735,14 +747,14 @@ func TestServer_getPowBlockHashAtTerminalTotalDifficulty(t *testing.T) {
{
name: "parent execution block invalid TD",
paramsTd: "2",
currentPowBlock: &pb.ExecutionBlock{
currentPowBlock: &pb.ExecutionBlockBellatrix{
Hash: common.BytesToHash([]byte("a")),
Header: gethtypes.Header{
ParentHash: common.BytesToHash([]byte("b")),
},
TotalDifficulty: "0x3",
},
parentPowBlock: &pb.ExecutionBlock{
parentPowBlock: &pb.ExecutionBlockBellatrix{
Hash: common.BytesToHash([]byte("b")),
Header: gethtypes.Header{
ParentHash: common.BytesToHash([]byte("c")),
@@ -754,14 +766,14 @@ func TestServer_getPowBlockHashAtTerminalTotalDifficulty(t *testing.T) {
{
name: "happy case",
paramsTd: "2",
currentPowBlock: &pb.ExecutionBlock{
currentPowBlock: &pb.ExecutionBlockBellatrix{
Hash: common.BytesToHash([]byte("a")),
Header: gethtypes.Header{
ParentHash: common.BytesToHash([]byte("b")),
},
TotalDifficulty: "0x3",
},
parentPowBlock: &pb.ExecutionBlock{
parentPowBlock: &pb.ExecutionBlockBellatrix{
Hash: common.BytesToHash([]byte("b")),
Header: gethtypes.Header{
ParentHash: common.BytesToHash([]byte("c")),
@@ -774,7 +786,7 @@ func TestServer_getPowBlockHashAtTerminalTotalDifficulty(t *testing.T) {
{
name: "happy case, but invalid timestamp",
paramsTd: "2",
currentPowBlock: &pb.ExecutionBlock{
currentPowBlock: &pb.ExecutionBlockBellatrix{
Hash: common.BytesToHash([]byte("a")),
Header: gethtypes.Header{
ParentHash: common.BytesToHash([]byte("b")),
@@ -782,7 +794,7 @@ func TestServer_getPowBlockHashAtTerminalTotalDifficulty(t *testing.T) {
},
TotalDifficulty: "0x3",
},
parentPowBlock: &pb.ExecutionBlock{
parentPowBlock: &pb.ExecutionBlockBellatrix{
Hash: common.BytesToHash([]byte("b")),
Header: gethtypes.Header{
ParentHash: common.BytesToHash([]byte("c")),
@@ -793,14 +805,14 @@ func TestServer_getPowBlockHashAtTerminalTotalDifficulty(t *testing.T) {
{
name: "ttd not reached",
paramsTd: "3",
currentPowBlock: &pb.ExecutionBlock{
currentPowBlock: &pb.ExecutionBlockBellatrix{
Hash: common.BytesToHash([]byte("a")),
Header: gethtypes.Header{
ParentHash: common.BytesToHash([]byte("b")),
},
TotalDifficulty: "0x2",
},
parentPowBlock: &pb.ExecutionBlock{
parentPowBlock: &pb.ExecutionBlockBellatrix{
Hash: common.BytesToHash([]byte("b")),
Header: gethtypes.Header{
ParentHash: common.BytesToHash([]byte("c")),
@@ -814,9 +826,9 @@ func TestServer_getPowBlockHashAtTerminalTotalDifficulty(t *testing.T) {
cfg := params.BeaconConfig().Copy()
cfg.TerminalTotalDifficulty = tt.paramsTd
params.OverrideBeaconConfig(cfg)
var m map[[32]byte]*pb.ExecutionBlock
var m map[[32]byte]*pb.ExecutionBlockBellatrix
if tt.parentPowBlock != nil {
m = map[[32]byte]*pb.ExecutionBlock{
m = map[[32]byte]*pb.ExecutionBlockBellatrix{
tt.parentPowBlock.Hash: tt.parentPowBlock,
}
}
@@ -1079,7 +1091,7 @@ func fixtures() map[string]interface{} {
transactionsRoot := bytesutil.PadTo([]byte("transactionsRoot"), fieldparams.RootLength)
receiptsRoot := bytesutil.PadTo([]byte("receiptsRoot"), fieldparams.RootLength)
logsBloom := bytesutil.PadTo([]byte("logs"), fieldparams.LogsBloomLength)
executionBlock := &pb.ExecutionBlock{
executionBlock := &pb.ExecutionBlockBellatrix{
Header: gethtypes.Header{
ParentHash: common.BytesToHash(parent),
UncleHash: common.BytesToHash(sha3Uncles),
@@ -1182,13 +1194,13 @@ func fixtures() map[string]interface{} {
func Test_fullPayloadFromExecutionBlock(t *testing.T) {
type args struct {
header *pb.ExecutionPayloadHeader
block *pb.ExecutionBlock
block *pb.ExecutionBlockBellatrix
}
wantedHash := common.BytesToHash([]byte("foo"))
tests := []struct {
name string
args args
want *pb.ExecutionPayload
want func() interfaces.ExecutionData
err string
}{
{
@@ -1197,7 +1209,7 @@ func Test_fullPayloadFromExecutionBlock(t *testing.T) {
header: &pb.ExecutionPayloadHeader{
BlockHash: []byte("foo"),
},
block: &pb.ExecutionBlock{
block: &pb.ExecutionBlockBellatrix{
Hash: common.BytesToHash([]byte("bar")),
},
},
@@ -1209,23 +1221,30 @@ func Test_fullPayloadFromExecutionBlock(t *testing.T) {
header: &pb.ExecutionPayloadHeader{
BlockHash: wantedHash[:],
},
block: &pb.ExecutionBlock{
block: &pb.ExecutionBlockBellatrix{
Hash: wantedHash,
},
},
want: &pb.ExecutionPayload{
BlockHash: wantedHash[:],
want: func() interfaces.ExecutionData {
p, err := blocks.WrappedExecutionPayload(&pb.ExecutionPayload{
BlockHash: wantedHash[:],
Transactions: [][]byte{},
})
require.NoError(t, err)
return p
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
wrapped, err := blocks.WrappedExecutionPayloadHeader(tt.args.header)
require.NoError(t, err)
got, err := fullPayloadFromExecutionBlock(wrapped, tt.args.block)
if (err != nil) && !strings.Contains(err.Error(), tt.err) {
t.Fatalf("Wanted err %s got %v", tt.err, err)
if err != nil {
assert.ErrorContains(t, tt.err, err)
} else {
assert.DeepEqual(t, tt.want(), got)
}
require.DeepEqual(t, tt.want, got)
})
}
}
@@ -1308,9 +1327,9 @@ func (*testEngineService) NoArgsRets() {}
func (*testEngineService) GetBlockByHash(
_ context.Context, _ common.Hash, _ bool,
) *pb.ExecutionBlock {
) *pb.ExecutionBlockBellatrix {
fix := fixtures()
item, ok := fix["ExecutionBlock"].(*pb.ExecutionBlock)
item, ok := fix["ExecutionBlock"].(*pb.ExecutionBlockBellatrix)
if !ok {
panic("not found")
}
@@ -1319,9 +1338,9 @@ func (*testEngineService) GetBlockByHash(
func (*testEngineService) GetBlockByNumber(
_ context.Context, _ string, _ bool,
) *pb.ExecutionBlock {
) *pb.ExecutionBlockBellatrix {
fix := fixtures()
item, ok := fix["ExecutionBlock"].(*pb.ExecutionBlock)
item, ok := fix["ExecutionBlock"].(*pb.ExecutionBlockBellatrix)
if !ok {
panic("not found")
}

View File

@@ -288,13 +288,13 @@ func (s *Service) processPastLogs(ctx context.Context) error {
headersMap := make(map[uint64]*types.HeaderInfo)
rawLogCount, err := s.depositContractCaller.GetDepositCount(&bind.CallOpts{})
if err != nil {
return err
return errors.Wrap(err, "GetDepositCount")
}
logCount := binary.LittleEndian.Uint64(rawLogCount)
latestFollowHeight, err := s.followedBlockHeight(ctx)
if err != nil {
return err
return errors.Wrap(err, "followedBlockHeight")
}
batchSize := s.cfg.eth1HeaderReqLimit
@@ -303,7 +303,7 @@ func (s *Service) processPastLogs(ctx context.Context) error {
for currentBlockNum < latestFollowHeight {
currentBlockNum, batchSize, err = s.processBlockInBatch(ctx, currentBlockNum, latestFollowHeight, batchSize, additiveFactor, logCount, headersMap)
if err != nil {
return err
return errors.Wrapf(err, "processBlockInBatch, num=%d, height=%d", currentBlockNum, latestFollowHeight)
}
}
@@ -313,7 +313,7 @@ func (s *Service) processPastLogs(ctx context.Context) error {
c, err := s.cfg.beaconDB.FinalizedCheckpoint(ctx)
if err != nil {
return err
return errors.Wrap(err, "FinalizedCheckpoint")
}
fRoot := bytesutil.ToBytes32(c.Root)
// Return if no checkpoint exists yet.
@@ -333,7 +333,7 @@ func (s *Service) processPastLogs(ctx context.Context) error {
if isNil || slots.ToEpoch(fState.Slot()) != c.Epoch {
fState, err = s.cfg.stateGen.StateByRoot(ctx, fRoot)
if err != nil {
return err
return errors.Wrapf(err, "StateByRoot=%#x", fRoot)
}
}
if fState != nil && !fState.IsNil() && fState.Eth1DepositIndex() > 0 {

View File

@@ -45,7 +45,7 @@ func (s *Service) setupExecutionClientConnections(ctx context.Context, currEndpo
}
return errors.Wrap(err, errStr)
}
s.updateConnectedETH1(true)
s.updateConnectedETH1(true, "execution chain connection established")
s.runError = nil
return nil
}
@@ -88,13 +88,14 @@ func (s *Service) pollConnectionStatus(ctx context.Context) {
// Forces to retry an execution client connection.
func (s *Service) retryExecutionClientConnection(ctx context.Context, err error) {
s.runError = err
s.updateConnectedETH1(false)
log.Debugf("retryExecutionClientConnection, err=%s", err.Error())
s.runError = errors.Wrap(err, "retryExecutionClientConnection")
s.updateConnectedETH1(false, "retryExecutionClientConnection")
// Back off for a while before redialing.
time.Sleep(backOffPeriod)
currClient := s.rpcClient
if err := s.setupExecutionClientConnections(ctx, s.cfg.currHttpEndpoint); err != nil {
s.runError = err
s.runError = errors.Wrap(err, "setupExecutionClientConnections")
return
}
// Close previous client, if connection was successful.

View File

@@ -307,7 +307,8 @@ func (s *Service) updateBeaconNodeStats() {
s.cfg.beaconNodeStatsUpdater.Update(bs)
}
func (s *Service) updateConnectedETH1(state bool) {
func (s *Service) updateConnectedETH1(state bool, reason string) {
log.Infof("updateConnectedETH1 - %s", reason)
s.connectedETH1 = state
s.updateBeaconNodeStats()
}
@@ -319,10 +320,14 @@ func (s *Service) followedBlockHeight(ctx context.Context) (uint64, error) {
latestBlockTime := uint64(0)
if s.latestEth1Data.BlockTime > followTime {
latestBlockTime = s.latestEth1Data.BlockTime - followTime
if s.latestEth1Data.BlockHeight < params.BeaconConfig().Eth1FollowDistance {
latestBlockTime = s.latestEth1Data.BlockTime
}
}
log.WithField("distance", params.BeaconConfig().Eth1FollowDistance).WithField("followTime", followTime).WithField("BlockTime", s.latestEth1Data.BlockTime).WithField("BlockHeight", s.latestEth1Data.BlockHeight).WithField("latestBlockTime", latestBlockTime).Info("followedBlockHeight")
blk, err := s.BlockByTimestamp(ctx, latestBlockTime)
if err != nil {
return 0, err
return 0, errors.Wrapf(err, "BlockByTimestamp=%d", latestBlockTime)
}
return blk.Number.Uint64(), nil
}
@@ -467,21 +472,23 @@ func (s *Service) handleETH1FollowDistance() {
}
if !s.chainStartData.Chainstarted {
if err := s.processChainStartFromBlockNum(ctx, big.NewInt(int64(s.latestEth1Data.LastRequestedBlock))); err != nil {
s.runError = err
s.runError = errors.Wrap(err, "processChainStartFromBlockNum")
log.Error(err)
return
}
}
// If the last requested block has not changed,
// we do not request batched logs as this means there are no new
// logs for the powchain service to process. Also it is a potential
// failure condition as would mean we have not respected the protocol threshold.
if s.latestEth1Data.LastRequestedBlock == s.latestEth1Data.BlockHeight {
log.Error("Beacon node is not respecting the follow distance")
// TODO this is usually an error but temporarily setting it to warn because its noisy when starting from genesis
log.Warn("Beacon node is not respecting the follow distance")
return
}
if err := s.requestBatchedHeadersAndLogs(ctx); err != nil {
s.runError = err
s.runError = errors.Wrap(err, "requestBatchedHeadersAndLogs")
log.Error(err)
return
}
@@ -511,6 +518,7 @@ func (s *Service) initPOWService() {
ctx := s.ctx
header, err := s.HeaderByNumber(ctx, nil)
if err != nil {
err = errors.Wrap(err, "HeaderByNumber")
s.retryExecutionClientConnection(ctx, err)
errorLogger(err, "Unable to retrieve latest execution client header")
continue
@@ -523,6 +531,7 @@ func (s *Service) initPOWService() {
s.latestEth1DataLock.Unlock()
if err := s.processPastLogs(ctx); err != nil {
err = errors.Wrap(err, "processPastLogs")
s.retryExecutionClientConnection(ctx, err)
errorLogger(
err,
@@ -532,6 +541,7 @@ func (s *Service) initPOWService() {
}
// Cache eth1 headers from our voting period.
if err := s.cacheHeadersForEth1DataVote(ctx); err != nil {
err = errors.Wrap(err, "cacheHeadersForEth1DataVote")
s.retryExecutionClientConnection(ctx, err)
if errors.Is(err, errBlockTimeTooLate) {
log.WithError(err).Debug("Unable to cache headers for execution client votes")
@@ -550,6 +560,7 @@ func (s *Service) initPOWService() {
if genHash != [32]byte{} {
genHeader, err := s.HeaderByHash(ctx, genHash)
if err != nil {
err = errors.Wrapf(err, "HeaderByHash, hash=%#x", genHash)
s.retryExecutionClientConnection(ctx, err)
errorLogger(err, "Unable to retrieve proof-of-stake genesis block data")
continue
@@ -558,6 +569,7 @@ func (s *Service) initPOWService() {
}
s.chainStartData.GenesisBlock = genBlock
if err := s.savePowchainData(ctx); err != nil {
err = errors.Wrap(err, "savePowchainData")
s.retryExecutionClientConnection(ctx, err)
errorLogger(err, "Unable to save execution client data")
continue
@@ -583,7 +595,7 @@ func (s *Service) run(done <-chan struct{}) {
s.isRunning = false
s.runError = nil
s.rpcClient.Close()
s.updateConnectedETH1(false)
s.updateConnectedETH1(false, "context canceled in run()")
log.Debug("Context closed, exiting goroutine")
return
case <-s.eth1HeadTicker.C:
@@ -641,11 +653,11 @@ func (s *Service) cacheHeadersForEth1DataVote(ctx context.Context) error {
// Find the end block to request from.
end, err := s.followedBlockHeight(ctx)
if err != nil {
return err
return errors.Wrap(err, "followedBlockHeight")
}
start, err := s.determineEarliestVotingBlock(ctx, end)
if err != nil {
return err
return errors.Wrapf(err, "determineEarliestVotingBlock=%d", end)
}
return s.cacheBlockHeaders(start, end)
}
@@ -677,7 +689,7 @@ func (s *Service) cacheBlockHeaders(start, end uint64) error {
}
continue
}
return err
return errors.Wrapf(err, "cacheBlockHeaders, start=%d, end=%d", startReq, endReq)
}
}
return nil
@@ -696,12 +708,22 @@ func (s *Service) determineEarliestVotingBlock(ctx context.Context, followBlock
}
return earliestBlk, nil
}
if s.latestEth1Data.BlockHeight < params.BeaconConfig().Eth1FollowDistance {
return 0, nil
}
votingTime := slots.VotingPeriodStartTime(genesisTime, currSlot)
followBackDist := 2 * params.BeaconConfig().SecondsPerETH1Block * params.BeaconConfig().Eth1FollowDistance
if followBackDist > votingTime {
return 0, errors.Errorf("invalid genesis time provided. %d > %d", followBackDist, votingTime)
}
earliestValidTime := votingTime - followBackDist
/*
if earliestValidTime > s.latestEth1Data.BlockTime {
return 0, nil
}
log.WithField("earliestValidTime", earliestValidTime).Info("calling BlockByTimestamp")
*/
log.WithField("distance", params.BeaconConfig().Eth1FollowDistance).WithField("earliestValidTime", earliestValidTime).WithField("BlockTime", s.latestEth1Data.BlockTime).WithField("BlockHeight", s.latestEth1Data.BlockHeight).WithField("followBlock", followBlock).Info("determineEarliestVotingBlock")
hdr, err := s.BlockByTimestamp(ctx, earliestValidTime)
if err != nil {
return 0, err

View File

@@ -4,13 +4,14 @@ go_library(
name = "go_default_library",
testonly = True,
srcs = [
"genesis.go",
"mock_engine_client.go",
"mock_execution_chain.go",
"mock_faulty_powchain.go",
],
importpath = "github.com/prysmaticlabs/prysm/v3/beacon-chain/execution/testing",
visibility = [
"//beacon-chain:__subpackages__",
"//visibility:public",
],
deps = [
"//async/event:go_default_library",
@@ -20,13 +21,17 @@ go_library(
"//config/params:go_default_library",
"//consensus-types/blocks:go_default_library",
"//consensus-types/interfaces:go_default_library",
"//consensus-types/payload-attribute:go_default_library",
"//consensus-types/primitives:go_default_library",
"//encoding/bytesutil:go_default_library",
"//proto/engine/v1:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"@com_github_ethereum_go_ethereum//accounts/abi/bind/backends: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//core:go_default_library",
"@com_github_ethereum_go_ethereum//core/types:go_default_library",
"@com_github_ethereum_go_ethereum//params:go_default_library",
"@com_github_ethereum_go_ethereum//rpc:go_default_library",
"@com_github_holiman_uint256//:go_default_library",
"@com_github_pkg_errors//:go_default_library",

File diff suppressed because one or more lines are too long

View File

@@ -2,6 +2,7 @@ package testing
import (
"context"
"fmt"
"math/big"
"github.com/ethereum/go-ethereum/common"
@@ -11,6 +12,8 @@ import (
"github.com/prysmaticlabs/prysm/v3/config/params"
"github.com/prysmaticlabs/prysm/v3/consensus-types/blocks"
"github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces"
payloadattribute "github.com/prysmaticlabs/prysm/v3/consensus-types/payload-attribute"
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
pb "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
)
@@ -21,7 +24,7 @@ type EngineClient struct {
PayloadIDBytes *pb.PayloadIDBytes
ForkChoiceUpdatedResp []byte
ExecutionPayload *pb.ExecutionPayload
ExecutionBlock *pb.ExecutionBlock
ExecutionBlock *pb.ExecutionBlockBellatrix
Err error
ErrLatestExecBlock error
ErrExecBlockByHash error
@@ -29,7 +32,7 @@ type EngineClient struct {
ErrNewPayload error
ErrGetPayload error
ExecutionPayloadByBlockHash map[[32]byte]*pb.ExecutionPayload
BlockByHashMap map[[32]byte]*pb.ExecutionBlock
BlockByHashMap map[[32]byte]*pb.ExecutionBlockBellatrix
NumReconstructedPayloads uint64
TerminalBlockHash []byte
TerminalBlockHashExists bool
@@ -43,7 +46,7 @@ func (e *EngineClient) NewPayload(_ context.Context, _ interfaces.ExecutionData)
// ForkchoiceUpdated --
func (e *EngineClient) ForkchoiceUpdated(
_ context.Context, fcs *pb.ForkchoiceState, _ *pb.PayloadAttributes,
_ context.Context, fcs *pb.ForkchoiceState, _ payloadattribute.Attributer,
) (*pb.PayloadIDBytes, []byte, error) {
if e.OverrideValidHash != [32]byte{} && bytesutil.ToBytes32(fcs.HeadBlockHash) == e.OverrideValidHash {
return e.PayloadIDBytes, e.ForkChoiceUpdatedResp, nil
@@ -52,8 +55,17 @@ func (e *EngineClient) ForkchoiceUpdated(
}
// GetPayload --
func (e *EngineClient) GetPayload(_ context.Context, _ [8]byte) (*pb.ExecutionPayload, error) {
return e.ExecutionPayload, e.ErrGetPayload
func (e *EngineClient) GetPayload(_ context.Context, _ [8]byte, slot types.Slot) (interfaces.ExecutionData, error) {
p, err := blocks.WrappedExecutionPayload(e.ExecutionPayload)
if err != nil {
return nil, err
}
return p, e.ErrGetPayload
}
// GetPayloadV2 --
func (e *EngineClient) GetPayloadV2(_ context.Context, _ [8]byte) (*pb.ExecutionPayloadCapella, error) {
return nil, nil
}
// ExchangeTransitionConfiguration --
@@ -62,12 +74,12 @@ func (e *EngineClient) ExchangeTransitionConfiguration(_ context.Context, _ *pb.
}
// LatestExecutionBlock --
func (e *EngineClient) LatestExecutionBlock(_ context.Context) (*pb.ExecutionBlock, error) {
func (e *EngineClient) LatestExecutionBlock(_ context.Context) (*pb.ExecutionBlockBellatrix, error) {
return e.ExecutionBlock, e.ErrLatestExecBlock
}
// ExecutionBlockByHash --
func (e *EngineClient) ExecutionBlockByHash(_ context.Context, h common.Hash, _ bool) (*pb.ExecutionBlock, error) {
func (e *EngineClient) ExecutionBlockByHash(_ context.Context, _ int, h common.Hash, _ bool) (interface{}, error) {
b, ok := e.BlockByHashMap[h]
if !ok {
return nil, errors.New("block not found")
@@ -75,7 +87,8 @@ func (e *EngineClient) ExecutionBlockByHash(_ context.Context, h common.Hash, _
return b, e.ErrExecBlockByHash
}
func (e *EngineClient) ReconstructFullBellatrixBlock(
// ReconstructFullBlock --
func (e *EngineClient) ReconstructFullBlock(
_ context.Context, blindedBlock interfaces.SignedBeaconBlock,
) (interfaces.SignedBeaconBlock, error) {
if !blindedBlock.Block().IsBlinded() {
@@ -93,12 +106,13 @@ func (e *EngineClient) ReconstructFullBellatrixBlock(
return blocks.BuildSignedBeaconBlockFromExecutionPayload(blindedBlock, payload)
}
// ReconstructFullBellatrixBlockBatch --
func (e *EngineClient) ReconstructFullBellatrixBlockBatch(
ctx context.Context, blindedBlocks []interfaces.SignedBeaconBlock,
) ([]interfaces.SignedBeaconBlock, error) {
fullBlocks := make([]interfaces.SignedBeaconBlock, 0, len(blindedBlocks))
for _, b := range blindedBlocks {
newBlock, err := e.ReconstructFullBellatrixBlock(ctx, b)
newBlock, err := e.ReconstructFullBlock(ctx, b)
if err != nil {
return nil, err
}
@@ -135,12 +149,16 @@ func (e *EngineClient) GetTerminalBlockHash(ctx context.Context, transitionTime
if parentHash == params.BeaconConfig().ZeroHash {
return nil, false, nil
}
parentBlk, err := e.ExecutionBlockByHash(ctx, parentHash, false /* with txs */)
parentBlk, err := e.ExecutionBlockByHash(ctx, 0, parentHash, false /* with txs */)
if err != nil {
return nil, false, errors.Wrap(err, "could not get parent execution block")
}
parentBlkBellatrix, ok := parentBlk.(*pb.ExecutionBlockBellatrix)
if !ok {
return nil, false, fmt.Errorf("wrong execution block type %T", parentBlk)
}
if blockReachedTTD {
b, err := hexutil.DecodeBig(parentBlk.TotalDifficulty)
b, err := hexutil.DecodeBig(parentBlkBellatrix.TotalDifficulty)
if err != nil {
return nil, false, errors.Wrap(err, "could not convert total difficulty to uint256")
}
@@ -155,6 +173,6 @@ func (e *EngineClient) GetTerminalBlockHash(ctx context.Context, transitionTime
} else {
return nil, false, nil
}
blk = parentBlk
blk = parentBlkBellatrix
}
}

View File

@@ -815,6 +815,7 @@ func (b *BeaconNode) registerRPCService() error {
AttestationsPool: b.attestationPool,
ExitPool: b.exitPool,
SlashingsPool: b.slashingsPool,
BLSChangesPool: b.blsToExecPool,
SlashingChecker: slasherService,
SyncCommitteeObjectPool: b.syncCommitteePool,
ExecutionChainService: web3Service,

View File

@@ -11,10 +11,15 @@ go_library(
"//beacon-chain:__subpackages__",
],
deps = [
"//beacon-chain/core/blocks:go_default_library",
"//beacon-chain/state:go_default_library",
"//config/params:go_default_library",
"//consensus-types/primitives:go_default_library",
"//container/doubly-linked-list:go_default_library",
"//crypto/bls/blst:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
],
)
@@ -24,8 +29,15 @@ go_test(
srcs = ["pool_test.go"],
embed = [":go_default_library"],
deps = [
"//beacon-chain/core/signing:go_default_library",
"//beacon-chain/core/time:go_default_library",
"//beacon-chain/state/state-native:go_default_library",
"//config/params:go_default_library",
"//consensus-types/primitives:go_default_library",
"//crypto/bls:go_default_library",
"//crypto/bls/common:go_default_library",
"//crypto/hash:go_default_library",
"//encoding/ssz:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//testing/assert:go_default_library",
"//testing/require:go_default_library",

View File

@@ -4,17 +4,22 @@ import (
"math"
"sync"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/blocks"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state"
"github.com/prysmaticlabs/prysm/v3/config/params"
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
doublylinkedlist "github.com/prysmaticlabs/prysm/v3/container/doubly-linked-list"
"github.com/prysmaticlabs/prysm/v3/crypto/bls/blst"
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
"github.com/sirupsen/logrus"
)
// PoolManager maintains pending and seen BLS-to-execution-change objects.
// This pool is used by proposers to insert BLS-to-execution-change objects into new blocks.
type PoolManager interface {
PendingBLSToExecChanges() ([]*ethpb.SignedBLSToExecutionChange, error)
BLSToExecChangesForInclusion() ([]*ethpb.SignedBLSToExecutionChange, error)
BLSToExecChangesForInclusion(state.BeaconState) ([]*ethpb.SignedBLSToExecutionChange, error)
InsertBLSToExecChange(change *ethpb.SignedBLSToExecutionChange)
MarkIncluded(change *ethpb.SignedBLSToExecutionChange) error
ValidatorExists(idx types.ValidatorIndex) bool
@@ -58,25 +63,69 @@ func (p *Pool) PendingBLSToExecChanges() ([]*ethpb.SignedBLSToExecutionChange, e
// BLSToExecChangesForInclusion returns objects that are ready for inclusion at the given slot.
// This method will not return more than the block enforced MaxBlsToExecutionChanges.
func (p *Pool) BLSToExecChangesForInclusion() ([]*ethpb.SignedBLSToExecutionChange, error) {
func (p *Pool) BLSToExecChangesForInclusion(st state.BeaconState) ([]*ethpb.SignedBLSToExecutionChange, error) {
p.lock.RLock()
defer p.lock.RUnlock()
length := int(math.Min(float64(params.BeaconConfig().MaxBlsToExecutionChanges), float64(p.pending.Len())))
result := make([]*ethpb.SignedBLSToExecutionChange, length)
result := make([]*ethpb.SignedBLSToExecutionChange, 0, length)
node := p.pending.First()
var err error
for i := 0; node != nil && i < length; i++ {
result[i], err = node.Value()
for node != nil && len(result) < length {
change, err := node.Value()
if err != nil {
p.lock.RUnlock()
return nil, err
}
_, err = blocks.ValidateBLSToExecutionChange(st, change)
if err != nil {
logrus.Warning("removing invalid BLSToExecutionChange from pool")
// MarkIncluded removes the invalid change from the pool
p.lock.RUnlock()
if err := p.MarkIncluded(change); err != nil {
return nil, errors.Wrap(err, "could not mark BLSToExecutionChange as included")
}
p.lock.RLock()
} else {
result = append(result, change)
}
node, err = node.Next()
if err != nil {
p.lock.RUnlock()
return nil, err
}
}
return result, nil
p.lock.RUnlock()
if len(result) == 0 {
return result, nil
}
// We now verify the signatures in batches
cSet, err := blocks.BLSChangesSignatureBatch(st, result)
if err != nil {
return nil, errors.Wrap(err, "could not get BLSToExecutionChanges signatures")
}
ok, err := cSet.Verify()
if err != nil {
return nil, errors.Wrap(err, "could not batch verify BLSToExecutionChanges signatures")
}
if ok {
return result, nil
}
// Batch signature failed, check signatures individually
verified := make([]*ethpb.SignedBLSToExecutionChange, 0, length)
for i, sig := range cSet.Signatures {
signature, err := blst.SignatureFromBytes(sig)
if err != nil {
return nil, errors.Wrap(err, "could not get signature from bytes")
}
if !signature.Verify(cSet.PublicKeys[i], cSet.Messages[i][:]) {
logrus.Warning("removing BLSToExecutionChange with invalid signature from pool")
if err := p.MarkIncluded(result[i]); err != nil {
return nil, errors.Wrap(err, "could not mark BLSToExecutionChange as included")
}
} else {
verified = append(verified, result[i])
}
}
return verified, nil
}
// InsertBLSToExecChange inserts an object into the pool.

View File

@@ -3,8 +3,15 @@ package blstoexec
import (
"testing"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/signing"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/time"
state_native "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/state-native"
"github.com/prysmaticlabs/prysm/v3/config/params"
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v3/crypto/bls"
"github.com/prysmaticlabs/prysm/v3/crypto/bls/common"
"github.com/prysmaticlabs/prysm/v3/crypto/hash"
"github.com/prysmaticlabs/prysm/v3/encoding/ssz"
eth "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v3/testing/assert"
"github.com/prysmaticlabs/prysm/v3/testing/require"
@@ -36,42 +43,89 @@ func TestPendingBLSToExecChanges(t *testing.T) {
}
func TestBLSToExecChangesForInclusion(t *testing.T) {
spb := &eth.BeaconStateCapella{
Fork: &eth.Fork{
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
},
}
numValidators := 2 * params.BeaconConfig().MaxBlsToExecutionChanges
validators := make([]*eth.Validator, numValidators)
blsChanges := make([]*eth.BLSToExecutionChange, numValidators)
spb.Balances = make([]uint64, numValidators)
privKeys := make([]common.SecretKey, numValidators)
maxEffectiveBalance := params.BeaconConfig().MaxEffectiveBalance
executionAddress := []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13}
for i := range validators {
v := &eth.Validator{}
v.EffectiveBalance = maxEffectiveBalance
v.WithdrawableEpoch = params.BeaconConfig().FarFutureEpoch
v.WithdrawalCredentials = make([]byte, 32)
priv, err := bls.RandKey()
require.NoError(t, err)
privKeys[i] = priv
pubkey := priv.PublicKey().Marshal()
message := &eth.BLSToExecutionChange{
ToExecutionAddress: executionAddress,
ValidatorIndex: types.ValidatorIndex(i),
FromBlsPubkey: pubkey,
}
hashFn := ssz.NewHasherFunc(hash.CustomSHA256Hasher())
digest := hashFn.Hash(pubkey)
digest[0] = params.BeaconConfig().BLSWithdrawalPrefixByte
copy(v.WithdrawalCredentials, digest[:])
validators[i] = v
blsChanges[i] = message
}
spb.Validators = validators
st, err := state_native.InitializeFromProtoCapella(spb)
require.NoError(t, err)
signedChanges := make([]*eth.SignedBLSToExecutionChange, numValidators)
for i, message := range blsChanges {
signature, err := signing.ComputeDomainAndSign(st, time.CurrentEpoch(st), message, params.BeaconConfig().DomainBLSToExecutionChange, privKeys[i])
require.NoError(t, err)
signed := &eth.SignedBLSToExecutionChange{
Message: message,
Signature: signature,
}
signedChanges[i] = signed
}
t.Run("empty pool", func(t *testing.T) {
pool := NewPool()
for i := uint64(0); i < params.BeaconConfig().MaxBlsToExecutionChanges-1; i++ {
pool.InsertBLSToExecChange(&eth.SignedBLSToExecutionChange{
Message: &eth.BLSToExecutionChange{
ValidatorIndex: types.ValidatorIndex(i),
},
})
}
changes, err := pool.BLSToExecChangesForInclusion()
changes, err := pool.BLSToExecChangesForInclusion(st)
require.NoError(t, err)
assert.Equal(t, int(params.BeaconConfig().MaxBlsToExecutionChanges-1), len(changes))
assert.Equal(t, 0, len(changes))
})
t.Run("Less than MaxBlsToExecutionChanges in pool", func(t *testing.T) {
pool := NewPool()
for i := uint64(0); i < params.BeaconConfig().MaxBlsToExecutionChanges-1; i++ {
pool.InsertBLSToExecChange(signedChanges[i])
}
changes, err := pool.BLSToExecChangesForInclusion(st)
require.NoError(t, err)
assert.Equal(t, int(params.BeaconConfig().MaxBlsToExecutionChanges)-1, len(changes))
})
t.Run("MaxBlsToExecutionChanges in pool", func(t *testing.T) {
pool := NewPool()
for i := uint64(0); i < params.BeaconConfig().MaxBlsToExecutionChanges; i++ {
pool.InsertBLSToExecChange(&eth.SignedBLSToExecutionChange{
Message: &eth.BLSToExecutionChange{
ValidatorIndex: types.ValidatorIndex(i),
},
})
pool.InsertBLSToExecChange(signedChanges[i])
}
changes, err := pool.BLSToExecChangesForInclusion()
changes, err := pool.BLSToExecChangesForInclusion(st)
require.NoError(t, err)
assert.Equal(t, int(params.BeaconConfig().MaxBlsToExecutionChanges), len(changes))
})
t.Run("more than MaxBlsToExecutionChanges in pool", func(t *testing.T) {
pool := NewPool()
for i := uint64(0); i < params.BeaconConfig().MaxBlsToExecutionChanges+1; i++ {
pool.InsertBLSToExecChange(&eth.SignedBLSToExecutionChange{
Message: &eth.BLSToExecutionChange{
ValidatorIndex: types.ValidatorIndex(i),
},
})
for i := uint64(0); i < numValidators; i++ {
pool.InsertBLSToExecChange(signedChanges[i])
}
changes, err := pool.BLSToExecChangesForInclusion()
changes, err := pool.BLSToExecChangesForInclusion(st)
require.NoError(t, err)
// We want FIFO semantics, which means validator with index 16 shouldn't be returned
assert.Equal(t, int(params.BeaconConfig().MaxBlsToExecutionChanges), len(changes))
@@ -79,6 +133,28 @@ func TestBLSToExecChangesForInclusion(t *testing.T) {
assert.NotEqual(t, types.ValidatorIndex(16), ch.Message.ValidatorIndex)
}
})
t.Run("One Bad change", func(t *testing.T) {
pool := NewPool()
signedChanges[1].Message.FromBlsPubkey[5] = 0xff
for i := uint64(0); i < numValidators; i++ {
pool.InsertBLSToExecChange(signedChanges[i])
}
changes, err := pool.BLSToExecChangesForInclusion(st)
require.NoError(t, err)
assert.Equal(t, int(params.BeaconConfig().MaxBlsToExecutionChanges), len(changes))
assert.Equal(t, types.ValidatorIndex(2), changes[1].Message.ValidatorIndex)
})
t.Run("One Bad Signature", func(t *testing.T) {
pool := NewPool()
copy(signedChanges[1].Signature, signedChanges[2].Signature)
for i := uint64(0); i < numValidators; i++ {
pool.InsertBLSToExecChange(signedChanges[i])
}
changes, err := pool.BLSToExecChangesForInclusion(st)
require.NoError(t, err)
assert.Equal(t, int(params.BeaconConfig().MaxBlsToExecutionChanges)-1, len(changes))
assert.Equal(t, types.ValidatorIndex(2), changes[1].Message.ValidatorIndex)
})
}
func TestInsertBLSToExecChange(t *testing.T) {

View File

@@ -19,6 +19,7 @@ go_library(
"//beacon-chain/db:go_default_library",
"//beacon-chain/execution:go_default_library",
"//beacon-chain/operations/attestations:go_default_library",
"//beacon-chain/operations/blstoexec:go_default_library",
"//beacon-chain/operations/slashings:go_default_library",
"//beacon-chain/operations/synccommittee:go_default_library",
"//beacon-chain/operations/voluntaryexits:go_default_library",

View File

@@ -64,6 +64,19 @@ func handleGetBeaconBlockSSZV2(m *apimiddleware.ApiProxyMiddleware, endpoint api
return handleGetSSZ(m, endpoint, w, req, config)
}
func handleGetBlindedBeaconBlockSSZ(
m *apimiddleware.ApiProxyMiddleware,
endpoint apimiddleware.Endpoint,
w http.ResponseWriter,
req *http.Request,
) (handled bool) {
config := sszConfig{
fileName: "beacon_block.ssz",
responseJson: &VersionedSSZResponseJson{},
}
return handleGetSSZ(m, endpoint, w, req, config)
}
func handleSubmitBlockSSZ(m *apimiddleware.ApiProxyMiddleware, endpoint apimiddleware.Endpoint, w http.ResponseWriter, req *http.Request) (handled bool) {
return handlePostSSZ(m, endpoint, w, req)
}

View File

@@ -233,11 +233,21 @@ type bellatrixPublishBlockRequestJson struct {
Signature string `json:"signature" hex:"true"`
}
type capellaPublishBlockRequestJson struct {
CapellaBlock *BeaconBlockCapellaJson `json:"capella_block"`
Signature string `json:"signature" hex:"true"`
}
type bellatrixPublishBlindedBlockRequestJson struct {
BellatrixBlock *BlindedBeaconBlockBellatrixJson `json:"bellatrix_block"`
Signature string `json:"signature" hex:"true"`
}
type capellaPublishBlindedBlockRequestJson struct {
CapellaBlock *BlindedBeaconBlockCapellaJson `json:"capella_block"`
Signature string `json:"signature" hex:"true"`
}
// setInitialPublishBlockPostRequest is triggered before we deserialize the request JSON into a struct.
// We don't know which version of the block got posted, but we can determine it from the slot.
// We know that blocks of all versions have a Message field with a Slot field,
@@ -269,8 +279,10 @@ func setInitialPublishBlockPostRequest(endpoint *apimiddleware.Endpoint,
endpoint.PostRequest = &SignedBeaconBlockContainerJson{}
} else if currentEpoch < params.BeaconConfig().BellatrixForkEpoch {
endpoint.PostRequest = &SignedBeaconBlockAltairContainerJson{}
} else {
} else if currentEpoch < params.BeaconConfig().CapellaForkEpoch {
endpoint.PostRequest = &SignedBeaconBlockBellatrixContainerJson{}
} else {
endpoint.PostRequest = &SignedBeaconBlockCapellaContainerJson{}
}
req.Body = io.NopCloser(bytes.NewBuffer(buf))
return true, nil
@@ -308,6 +320,15 @@ func preparePublishedBlock(endpoint *apimiddleware.Endpoint, _ http.ResponseWrit
endpoint.PostRequest = actualPostReq
return nil
}
if block, ok := endpoint.PostRequest.(*SignedBeaconBlockCapellaContainerJson); ok {
// Prepare post request that can be properly decoded on gRPC side.
actualPostReq := &capellaPublishBlockRequestJson{
CapellaBlock: block.Message,
Signature: block.Signature,
}
endpoint.PostRequest = actualPostReq
return nil
}
return apimiddleware.InternalServerError(errors.New("unsupported block type"))
}
@@ -342,8 +363,10 @@ func setInitialPublishBlindedBlockPostRequest(endpoint *apimiddleware.Endpoint,
endpoint.PostRequest = &SignedBeaconBlockContainerJson{}
} else if currentEpoch < params.BeaconConfig().BellatrixForkEpoch {
endpoint.PostRequest = &SignedBeaconBlockAltairContainerJson{}
} else {
} else if currentEpoch < params.BeaconConfig().CapellaForkEpoch {
endpoint.PostRequest = &SignedBlindedBeaconBlockBellatrixContainerJson{}
} else {
endpoint.PostRequest = &SignedBlindedBeaconBlockCapellaContainerJson{}
}
req.Body = ioutil.NopCloser(bytes.NewBuffer(buf))
return true, nil
@@ -381,6 +404,15 @@ func preparePublishedBlindedBlock(endpoint *apimiddleware.Endpoint, _ http.Respo
endpoint.PostRequest = actualPostReq
return nil
}
if block, ok := endpoint.PostRequest.(*SignedBlindedBeaconBlockCapellaContainerJson); ok {
// Prepare post request that can be properly decoded on gRPC side.
actualPostReq := &capellaPublishBlindedBlockRequestJson{
CapellaBlock: block.Message,
Signature: block.Signature,
}
endpoint.PostRequest = actualPostReq
return nil
}
return apimiddleware.InternalServerError(errors.New("unsupported block type"))
}
@@ -439,6 +471,12 @@ type bellatrixBlockResponseJson struct {
ExecutionOptimistic bool `json:"execution_optimistic"`
}
type capellaBlockResponseJson struct {
Version string `json:"version"`
Data *SignedBeaconBlockCapellaContainerJson `json:"data"`
ExecutionOptimistic bool `json:"execution_optimistic"`
}
type bellatrixBlindedBlockResponseJson struct {
Version string `json:"version"`
Data *SignedBlindedBeaconBlockBellatrixContainerJson `json:"data"`
@@ -486,6 +524,15 @@ func serializeV2Block(response interface{}) (apimiddleware.RunDefault, []byte, a
},
ExecutionOptimistic: respContainer.ExecutionOptimistic,
}
case strings.EqualFold(respContainer.Version, strings.ToLower(ethpbv2.Version_CAPELLA.String())):
actualRespContainer = &capellaBlockResponseJson{
Version: respContainer.Version,
Data: &SignedBeaconBlockCapellaContainerJson{
Message: respContainer.Data.CapellaBlock,
Signature: respContainer.Data.Signature,
},
ExecutionOptimistic: respContainer.ExecutionOptimistic,
}
default:
return false, nil, apimiddleware.InternalServerError(fmt.Errorf("unsupported block version '%s'", respContainer.Version))
}

View File

@@ -39,6 +39,7 @@ func (_ *BeaconEndpointFactory) Paths() []string {
"/eth/v1/beacon/pool/attester_slashings",
"/eth/v1/beacon/pool/proposer_slashings",
"/eth/v1/beacon/pool/voluntary_exits",
"/eth/v1/beacon/pool/bls_to_execution_changes",
"/eth/v1/beacon/pool/sync_committees",
"/eth/v1/beacon/weak_subjectivity",
"/eth/v1/node/identity",
@@ -143,6 +144,7 @@ func (_ *BeaconEndpointFactory) Create(path string) (*apimiddleware.Endpoint, er
endpoint.Hooks = apimiddleware.HookCollection{
OnPreSerializeMiddlewareResponseIntoJson: serializeBlindedBlock,
}
endpoint.CustomHandlers = []apimiddleware.CustomHandler{handleGetBlindedBeaconBlockSSZ}
case "/eth/v1/beacon/pool/attestations":
endpoint.RequestQueryParams = []apimiddleware.QueryParam{{Name: "slot"}, {Name: "committee_index"}}
endpoint.GetResponse = &AttestationsPoolResponseJson{}
@@ -160,6 +162,8 @@ func (_ *BeaconEndpointFactory) Create(path string) (*apimiddleware.Endpoint, er
case "/eth/v1/beacon/pool/voluntary_exits":
endpoint.PostRequest = &SignedVoluntaryExitJson{}
endpoint.GetResponse = &VoluntaryExitsPoolResponseJson{}
case "/eth/v1/beacon/pool/bls_to_execution_changes":
endpoint.PostRequest = &SignedBLSToExecutionChangeJson{}
case "/eth/v1/beacon/pool/sync_committees":
endpoint.PostRequest = &SubmitSyncCommitteeSignaturesRequestJson{}
endpoint.Err = &IndexedVerificationFailureErrorJson{}

View File

@@ -374,6 +374,7 @@ type SignedBeaconBlockContainerV2Json struct {
Phase0Block *BeaconBlockJson `json:"phase0_block"`
AltairBlock *BeaconBlockAltairJson `json:"altair_block"`
BellatrixBlock *BeaconBlockBellatrixJson `json:"bellatrix_block"`
CapellaBlock *BeaconBlockCapellaJson `json:"capella_block"`
Signature string `json:"signature" hex:"true"`
}
@@ -389,12 +390,14 @@ type BeaconBlockContainerV2Json struct {
Phase0Block *BeaconBlockJson `json:"phase0_block"`
AltairBlock *BeaconBlockAltairJson `json:"altair_block"`
BellatrixBlock *BeaconBlockBellatrixJson `json:"bellatrix_block"`
CapellaBlock *BeaconBlockCapellaJson `json:"capella_block"`
}
type BlindedBeaconBlockContainerJson struct {
Phase0Block *BeaconBlockJson `json:"phase0_block"`
AltairBlock *BeaconBlockAltairJson `json:"altair_block"`
BellatrixBlock *BlindedBeaconBlockBellatrixJson `json:"bellatrix_block"`
CapellaBlock *BlindedBeaconBlockCapellaJson `json:"capella_block"`
}
type SignedBeaconBlockAltairContainerJson struct {
@@ -407,6 +410,11 @@ type SignedBeaconBlockBellatrixContainerJson struct {
Signature string `json:"signature" hex:"true"`
}
type SignedBeaconBlockCapellaContainerJson struct {
Message *BeaconBlockCapellaJson `json:"message"`
Signature string `json:"signature" hex:"true"`
}
type SignedBlindedBeaconBlockBellatrixContainerJson struct {
Message *BlindedBeaconBlockBellatrixJson `json:"message"`
Signature string `json:"signature" hex:"true"`
@@ -433,6 +441,14 @@ type BeaconBlockBellatrixJson struct {
Body *BeaconBlockBodyBellatrixJson `json:"body"`
}
type BeaconBlockCapellaJson struct {
Slot string `json:"slot"`
ProposerIndex string `json:"proposer_index"`
ParentRoot string `json:"parent_root" hex:"true"`
StateRoot string `json:"state_root" hex:"true"`
Body *BeaconBlockBodyCapellaJson `json:"body"`
}
type BlindedBeaconBlockBellatrixJson struct {
Slot string `json:"slot"`
ProposerIndex string `json:"proposer_index"`
@@ -474,6 +490,20 @@ type BeaconBlockBodyBellatrixJson struct {
ExecutionPayload *ExecutionPayloadJson `json:"execution_payload"`
}
type BeaconBlockBodyCapellaJson struct {
RandaoReveal string `json:"randao_reveal" hex:"true"`
Eth1Data *Eth1DataJson `json:"eth1_data"`
Graffiti string `json:"graffiti" hex:"true"`
ProposerSlashings []*ProposerSlashingJson `json:"proposer_slashings"`
AttesterSlashings []*AttesterSlashingJson `json:"attester_slashings"`
Attestations []*AttestationJson `json:"attestations"`
Deposits []*DepositJson `json:"deposits"`
VoluntaryExits []*SignedVoluntaryExitJson `json:"voluntary_exits"`
SyncAggregate *SyncAggregateJson `json:"sync_aggregate"`
ExecutionPayload *ExecutionPayloadCapellaJson `json:"execution_payload"`
BLSToExecutionChanges []*SignedBLSToExecutionChangeJson `json:"bls_to_execution_changes"`
}
type BlindedBeaconBlockBodyBellatrixJson struct {
RandaoReveal string `json:"randao_reveal" hex:"true"`
Eth1Data *Eth1DataJson `json:"eth1_data"`
@@ -498,7 +528,7 @@ type BlindedBeaconBlockBodyCapellaJson struct {
VoluntaryExits []*SignedVoluntaryExitJson `json:"voluntary_exits"`
SyncAggregate *SyncAggregateJson `json:"sync_aggregate"`
ExecutionPayloadHeader *ExecutionPayloadHeaderCapellaJson `json:"execution_payload_header"`
BLSToExecutionChanges []*BLSToExecutionChangeJson `json:"bls_to_execution_changes"`
BLSToExecutionChanges []*SignedBLSToExecutionChangeJson `json:"bls_to_execution_changes"`
}
type ExecutionPayloadJson struct {
@@ -518,6 +548,24 @@ type ExecutionPayloadJson struct {
Transactions []string `json:"transactions" hex:"true"`
}
type ExecutionPayloadCapellaJson struct {
ParentHash string `json:"parent_hash" hex:"true"`
FeeRecipient string `json:"fee_recipient" hex:"true"`
StateRoot string `json:"state_root" hex:"true"`
ReceiptsRoot string `json:"receipts_root" hex:"true"`
LogsBloom string `json:"logs_bloom" hex:"true"`
PrevRandao string `json:"prev_randao" hex:"true"`
BlockNumber string `json:"block_number"`
GasLimit string `json:"gas_limit"`
GasUsed string `json:"gas_used"`
TimeStamp string `json:"timestamp"`
ExtraData string `json:"extra_data" hex:"true"`
BaseFeePerGas string `json:"base_fee_per_gas" uint256:"true"`
BlockHash string `json:"block_hash" hex:"true"`
Transactions []string `json:"transactions" hex:"true"`
Withdrawals []*WithdrawalJson `json:"withdrawals"`
}
type ExecutionPayloadHeaderJson struct {
ParentHash string `json:"parent_hash" hex:"true"`
FeeRecipient string `json:"fee_recipient" hex:"true"`
@@ -629,6 +677,11 @@ type BLSToExecutionChangeJson struct {
ToExecutionAddress string `json:"to_execution_address" hex:"true"`
}
type SignedBLSToExecutionChangeJson struct {
BLSToExecutionChange *BLSToExecutionChangeJson `json:"message"`
Signature string `json:"signature" hex:"true"`
}
type DepositJson struct {
Proof []string `json:"proof" hex:"true"`
Data *Deposit_DataJson `json:"data"`
@@ -683,6 +736,13 @@ type VersionJson struct {
Version string `json:"version"`
}
type WithdrawalJson struct {
WithdrawalIndex string `json:"index"`
ValidatorIndex string `json:"validator_index"`
ExecutionAddress string `json:"address" hex:"true"`
Amount string `json:"amount"`
}
type BeaconStateJson struct {
GenesisTime string `json:"genesis_time"`
GenesisValidatorsRoot string `json:"genesis_validators_root" hex:"true"`

View File

@@ -29,6 +29,7 @@ go_library(
"//beacon-chain/db/filters:go_default_library",
"//beacon-chain/execution:go_default_library",
"//beacon-chain/operations/attestations:go_default_library",
"//beacon-chain/operations/blstoexec:go_default_library",
"//beacon-chain/operations/slashings:go_default_library",
"//beacon-chain/operations/voluntaryexits:go_default_library",
"//beacon-chain/p2p:go_default_library",
@@ -106,6 +107,7 @@ go_test(
"//consensus-types/interfaces:go_default_library",
"//consensus-types/primitives:go_default_library",
"//crypto/bls:go_default_library",
"//crypto/hash:go_default_library",
"//encoding/bytesutil:go_default_library",
"//encoding/ssz:go_default_library",
"//proto/engine/v1:go_default_library",

View File

@@ -4,14 +4,20 @@ import (
"context"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v3/config/params"
"github.com/prysmaticlabs/prysm/v3/consensus-types/blocks"
"github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces"
"github.com/prysmaticlabs/prysm/v3/encoding/ssz/detect"
"github.com/prysmaticlabs/prysm/v3/network/forks"
ethpbv1 "github.com/prysmaticlabs/prysm/v3/proto/eth/v1"
ethpbv2 "github.com/prysmaticlabs/prysm/v3/proto/eth/v2"
"github.com/prysmaticlabs/prysm/v3/proto/migration"
eth "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
"go.opencensus.io/trace"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/emptypb"
)
// GetBlindedBlock retrieves blinded block for given block id.
@@ -61,6 +67,159 @@ func (bs *Server) GetBlindedBlock(ctx context.Context, req *ethpbv1.BlockRequest
return nil, status.Errorf(codes.Internal, "Unknown block type %T", blk)
}
// GetBlindedBlockSSZ returns the SSZ-serialized version of the blinded beacon block for given block id.
func (bs *Server) GetBlindedBlockSSZ(ctx context.Context, req *ethpbv1.BlockRequest) (*ethpbv2.SSZContainer, error) {
ctx, span := trace.StartSpan(ctx, "beacon.GetBlindedBlockSSZ")
defer span.End()
blk, err := bs.blockFromBlockID(ctx, req.BlockId)
err = handleGetBlockError(blk, err)
if err != nil {
return nil, err
}
result, err := getSSZBlockPhase0(blk)
if result != nil {
return result, nil
}
// ErrUnsupportedGetter means that we have another block type
if !errors.Is(err, blocks.ErrUnsupportedGetter) {
return nil, status.Errorf(codes.Internal, "Could not get signed beacon block: %v", err)
}
result, err = getSSZBlockAltair(blk)
if result != nil {
return result, nil
}
// ErrUnsupportedGetter means that we have another block type
if !errors.Is(err, blocks.ErrUnsupportedGetter) {
return nil, status.Errorf(codes.Internal, "Could not get signed beacon block: %v", err)
}
result, err = bs.getBlindedSSZBlockBellatrix(ctx, blk)
if result != nil {
return result, nil
}
// ErrUnsupportedGetter means that we have another block type
if !errors.Is(err, blocks.ErrUnsupportedGetter) {
return nil, status.Errorf(codes.Internal, "Could not get signed beacon block: %v", err)
}
result, err = bs.getBlindedSSZBlockCapella(ctx, blk)
if result != nil {
return result, nil
}
// ErrUnsupportedGetter means that we have another block type
if !errors.Is(err, blocks.ErrUnsupportedGetter) {
return nil, status.Errorf(codes.Internal, "Could not get signed beacon block: %v", err)
}
return nil, status.Errorf(codes.Internal, "Unknown block type %T", blk)
}
// SubmitBlindedBlock instructs the beacon node to use the components of the `SignedBlindedBeaconBlock` to construct
// and publish a `SignedBeaconBlock` by swapping out the `transactions_root` for the corresponding full list of `transactions`.
// The beacon node should broadcast a newly constructed `SignedBeaconBlock` to the beacon network,
// to be included in the beacon chain. The beacon node is not required to validate the signed
// `BeaconBlock`, and a successful response (20X) only indicates that the broadcast has been
// successful. The beacon node is expected to integrate the new block into its state, and
// therefore validate the block internally, however blocks which fail the validation are still
// broadcast but a different status code is returned (202).
func (bs *Server) SubmitBlindedBlock(ctx context.Context, req *ethpbv2.SignedBlindedBeaconBlockContainer) (*emptypb.Empty, error) {
ctx, span := trace.StartSpan(ctx, "beacon.SubmitBlindedBlock")
defer span.End()
capellaBlkContainer, ok := req.Message.(*ethpbv2.SignedBlindedBeaconBlockContainer_CapellaBlock)
if ok {
if err := bs.submitBlindedCapellaBlock(ctx, capellaBlkContainer.CapellaBlock, req.Signature); err != nil {
return nil, err
}
}
bellatrixBlkContainer, ok := req.Message.(*ethpbv2.SignedBlindedBeaconBlockContainer_BellatrixBlock)
if ok {
if err := bs.submitBlindedBellatrixBlock(ctx, bellatrixBlkContainer.BellatrixBlock, req.Signature); err != nil {
return nil, err
}
}
// At the end we check forks that don't have blinded blocks.
phase0BlkContainer, ok := req.Message.(*ethpbv2.SignedBlindedBeaconBlockContainer_Phase0Block)
if ok {
if err := bs.submitPhase0Block(ctx, phase0BlkContainer.Phase0Block, req.Signature); err != nil {
return nil, err
}
}
altairBlkContainer, ok := req.Message.(*ethpbv2.SignedBlindedBeaconBlockContainer_AltairBlock)
if ok {
if err := bs.submitAltairBlock(ctx, altairBlkContainer.AltairBlock, req.Signature); err != nil {
return nil, err
}
}
return &emptypb.Empty{}, nil
}
// SubmitBlindedBlockSSZ instructs the beacon node to use the components of the `SignedBlindedBeaconBlock` to construct
// and publish a `SignedBeaconBlock` by swapping out the `transactions_root` for the corresponding full list of `transactions`.
// The beacon node should broadcast a newly constructed `SignedBeaconBlock` to the beacon network,
// to be included in the beacon chain. The beacon node is not required to validate the signed
// `BeaconBlock`, and a successful response (20X) only indicates that the broadcast has been
// successful. The beacon node is expected to integrate the new block into its state, and
// therefore validate the block internally, however blocks which fail the validation are still
// broadcast but a different status code is returned (202).
//
// The provided block must be SSZ-serialized.
func (bs *Server) SubmitBlindedBlockSSZ(ctx context.Context, req *ethpbv2.SSZContainer) (*emptypb.Empty, error) {
ctx, span := trace.StartSpan(ctx, "beacon.SubmitBlindedBlockSSZ")
defer span.End()
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
return &emptypb.Empty{}, status.Errorf(codes.Internal, "Could not read"+versionHeader+" header")
}
ver := md.Get(versionHeader)
if len(ver) == 0 {
return &emptypb.Empty{}, status.Errorf(codes.Internal, "Could not read"+versionHeader+" header")
}
schedule := forks.NewOrderedSchedule(params.BeaconConfig())
forkVer, err := schedule.VersionForName(ver[0])
if err != nil {
return &emptypb.Empty{}, status.Errorf(codes.Internal, "Could not determine fork version: %v", err)
}
unmarshaler, err := detect.FromForkVersion(forkVer)
if err != nil {
return &emptypb.Empty{}, status.Errorf(codes.Internal, "Could not create unmarshaler: %v", err)
}
block, err := unmarshaler.UnmarshalBlindedBeaconBlock(req.Data)
if err != nil {
return &emptypb.Empty{}, status.Errorf(codes.Internal, "Could not unmarshal request data into block: %v", err)
}
if block.IsBlinded() {
b, err := block.PbBlindedBellatrixBlock()
if err != nil {
b, err := block.PbBlindedCapellaBlock()
if err != nil {
return &emptypb.Empty{}, status.Errorf(codes.Internal, "Could not get blinded block: %v", err)
}
bb, err := migration.V1Alpha1BeaconBlockBlindedCapellaToV2Blinded(b.Block)
if err != nil {
return &emptypb.Empty{}, status.Errorf(codes.Internal, "Could not migrate block: %v", err)
}
return &emptypb.Empty{}, bs.submitBlindedCapellaBlock(ctx, bb, b.Signature)
}
bb, err := migration.V1Alpha1BeaconBlockBlindedBellatrixToV2Blinded(b.Block)
if err != nil {
return &emptypb.Empty{}, status.Errorf(codes.Internal, "Could not migrate block: %v", err)
}
return &emptypb.Empty{}, bs.submitBlindedBellatrixBlock(ctx, bb, b.Signature)
}
root, err := block.Block().HashTreeRoot()
if err != nil {
return &emptypb.Empty{}, status.Errorf(codes.Internal, "Could not compute block's hash tree root: %v", err)
}
return &emptypb.Empty{}, bs.submitBlock(ctx, root, block)
}
func getBlindedBlockPhase0(blk interfaces.SignedBeaconBlock) (*ethpbv2.BlindedBlockResponse, error) {
phase0Blk, err := blk.PbPhase0Block()
if err != nil {
@@ -209,6 +368,7 @@ func (bs *Server) getBlindedBlockCapella(ctx context.Context, blk interfaces.Sig
}
return nil, err
}
return nil, err
}
if capellaBlk == nil {
@@ -244,3 +404,191 @@ func (bs *Server) getBlindedBlockCapella(ctx context.Context, blk interfaces.Sig
ExecutionOptimistic: isOptimistic,
}, nil
}
func (bs *Server) getBlindedSSZBlockBellatrix(ctx context.Context, blk interfaces.SignedBeaconBlock) (*ethpbv2.SSZContainer, error) {
bellatrixBlk, err := blk.PbBellatrixBlock()
if err != nil {
// ErrUnsupportedGetter means that we have another block type
if errors.Is(err, blocks.ErrUnsupportedGetter) {
if blindedBellatrixBlk, err := blk.PbBlindedBellatrixBlock(); err == nil {
if blindedBellatrixBlk == nil {
return nil, errNilBlock
}
v2Blk, err := migration.V1Alpha1BeaconBlockBlindedBellatrixToV2Blinded(blindedBellatrixBlk.Block)
if err != nil {
return nil, errors.Wrapf(err, "could not get signed beacon block")
}
root, err := blk.Block().HashTreeRoot()
if err != nil {
return nil, errors.Wrapf(err, "could not get block root")
}
isOptimistic, err := bs.OptimisticModeFetcher.IsOptimisticForRoot(ctx, root)
if err != nil {
return nil, errors.Wrapf(err, "could not check if block is optimistic")
}
sig := blk.Signature()
data := &ethpbv2.SignedBlindedBeaconBlockBellatrix{
Message: v2Blk,
Signature: sig[:],
}
sszData, err := data.MarshalSSZ()
if err != nil {
return nil, errors.Wrapf(err, "could not marshal block into SSZ")
}
return &ethpbv2.SSZContainer{
Version: ethpbv2.Version_BELLATRIX,
ExecutionOptimistic: isOptimistic,
Data: sszData,
}, nil
}
return nil, err
}
}
if bellatrixBlk == nil {
return nil, errNilBlock
}
blindedBlkInterface, err := blk.ToBlinded()
if err != nil {
return nil, errors.Wrapf(err, "could not convert block to blinded block")
}
blindedBellatrixBlock, err := blindedBlkInterface.PbBlindedBellatrixBlock()
if err != nil {
return nil, errors.Wrapf(err, "could not get signed beacon block")
}
v2Blk, err := migration.V1Alpha1BeaconBlockBlindedBellatrixToV2Blinded(blindedBellatrixBlock.Block)
if err != nil {
return nil, errors.Wrapf(err, "could not get signed beacon block")
}
root, err := blk.Block().HashTreeRoot()
if err != nil {
return nil, errors.Wrapf(err, "could not get block root")
}
isOptimistic, err := bs.OptimisticModeFetcher.IsOptimisticForRoot(ctx, root)
if err != nil {
return nil, errors.Wrapf(err, "could not check if block is optimistic")
}
sig := blk.Signature()
data := &ethpbv2.SignedBlindedBeaconBlockBellatrix{
Message: v2Blk,
Signature: sig[:],
}
sszData, err := data.MarshalSSZ()
if err != nil {
return nil, errors.Wrapf(err, "could not marshal block into SSZ")
}
return &ethpbv2.SSZContainer{Version: ethpbv2.Version_BELLATRIX, ExecutionOptimistic: isOptimistic, Data: sszData}, nil
}
func (bs *Server) getBlindedSSZBlockCapella(ctx context.Context, blk interfaces.SignedBeaconBlock) (*ethpbv2.SSZContainer, error) {
capellaBlk, err := blk.PbCapellaBlock()
if err != nil {
// ErrUnsupportedGetter means that we have another block type
if errors.Is(err, blocks.ErrUnsupportedGetter) {
if blindedCapellaBlk, err := blk.PbBlindedCapellaBlock(); err == nil {
if blindedCapellaBlk == nil {
return nil, errNilBlock
}
v2Blk, err := migration.V1Alpha1BeaconBlockBlindedCapellaToV2Blinded(blindedCapellaBlk.Block)
if err != nil {
return nil, errors.Wrapf(err, "could not get signed beacon block")
}
root, err := blk.Block().HashTreeRoot()
if err != nil {
return nil, errors.Wrapf(err, "could not get block root")
}
isOptimistic, err := bs.OptimisticModeFetcher.IsOptimisticForRoot(ctx, root)
if err != nil {
return nil, errors.Wrapf(err, "could not check if block is optimistic")
}
sig := blk.Signature()
data := &ethpbv2.SignedBlindedBeaconBlockCapella{
Message: v2Blk,
Signature: sig[:],
}
sszData, err := data.MarshalSSZ()
if err != nil {
return nil, errors.Wrapf(err, "could not marshal block into SSZ")
}
return &ethpbv2.SSZContainer{
Version: ethpbv2.Version_CAPELLA,
ExecutionOptimistic: isOptimistic,
Data: sszData,
}, nil
}
return nil, err
}
}
if capellaBlk == nil {
return nil, errNilBlock
}
blindedBlkInterface, err := blk.ToBlinded()
if err != nil {
return nil, errors.Wrapf(err, "could not convert block to blinded block")
}
blindedCapellaBlock, err := blindedBlkInterface.PbBlindedCapellaBlock()
if err != nil {
return nil, errors.Wrapf(err, "could not get signed beacon block")
}
v2Blk, err := migration.V1Alpha1BeaconBlockBlindedCapellaToV2Blinded(blindedCapellaBlock.Block)
if err != nil {
return nil, errors.Wrapf(err, "could not get signed beacon block")
}
root, err := blk.Block().HashTreeRoot()
if err != nil {
return nil, errors.Wrapf(err, "could not get block root")
}
isOptimistic, err := bs.OptimisticModeFetcher.IsOptimisticForRoot(ctx, root)
if err != nil {
return nil, errors.Wrapf(err, "could not check if block is optimistic")
}
sig := blk.Signature()
data := &ethpbv2.SignedBlindedBeaconBlockCapella{
Message: v2Blk,
Signature: sig[:],
}
sszData, err := data.MarshalSSZ()
if err != nil {
return nil, errors.Wrapf(err, "could not marshal block into SSZ")
}
return &ethpbv2.SSZContainer{Version: ethpbv2.Version_CAPELLA, ExecutionOptimistic: isOptimistic, Data: sszData}, nil
}
func (bs *Server) submitBlindedBellatrixBlock(ctx context.Context, blindedBellatrixBlk *ethpbv2.BlindedBeaconBlockBellatrix, sig []byte) error {
b, err := migration.BlindedBellatrixToV1Alpha1SignedBlock(&ethpbv2.SignedBlindedBeaconBlockBellatrix{
Message: blindedBellatrixBlk,
Signature: sig,
})
if err != nil {
return status.Errorf(codes.Internal, "Could not get blinded block: %v", err)
}
_, err = bs.V1Alpha1ValidatorServer.ProposeBeaconBlock(ctx, &eth.GenericSignedBeaconBlock{
Block: &eth.GenericSignedBeaconBlock_BlindedBellatrix{
BlindedBellatrix: b,
},
})
if err != nil {
return status.Errorf(codes.Internal, "Could not propose blinded block: %v", err)
}
return nil
}
func (bs *Server) submitBlindedCapellaBlock(ctx context.Context, blindedCapellaBlk *ethpbv2.BlindedBeaconBlockCapella, sig []byte) error {
b, err := migration.BlindedCapellaToV1Alpha1SignedBlock(&ethpbv2.SignedBlindedBeaconBlockCapella{
Message: blindedCapellaBlk,
Signature: sig,
})
if err != nil {
return status.Errorf(codes.Internal, "Could not get blinded block: %v", err)
}
_, err = bs.V1Alpha1ValidatorServer.ProposeBeaconBlock(ctx, &eth.GenericSignedBeaconBlock{
Block: &eth.GenericSignedBeaconBlock_BlindedCapella{
BlindedCapella: b,
},
})
if err != nil {
return status.Errorf(codes.Internal, "Could not propose blinded block: %v", err)
}
return nil
}

View File

@@ -7,10 +7,17 @@ import (
"testing"
mock "github.com/prysmaticlabs/prysm/v3/beacon-chain/blockchain/testing"
builderTest "github.com/prysmaticlabs/prysm/v3/beacon-chain/builder/testing"
dbTest "github.com/prysmaticlabs/prysm/v3/beacon-chain/db/testing"
executionTest "github.com/prysmaticlabs/prysm/v3/beacon-chain/execution/testing"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/operations/synccommittee"
mockp2p "github.com/prysmaticlabs/prysm/v3/beacon-chain/p2p/testing"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/rpc/prysm/v1alpha1/validator"
"github.com/prysmaticlabs/prysm/v3/config/params"
"github.com/prysmaticlabs/prysm/v3/consensus-types/blocks"
"github.com/prysmaticlabs/prysm/v3/crypto/hash"
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/v3/encoding/ssz"
enginev1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
ethpbv1 "github.com/prysmaticlabs/prysm/v3/proto/eth/v1"
ethpbv2 "github.com/prysmaticlabs/prysm/v3/proto/eth/v2"
@@ -19,6 +26,7 @@ import (
"github.com/prysmaticlabs/prysm/v3/testing/assert"
"github.com/prysmaticlabs/prysm/v3/testing/require"
"github.com/prysmaticlabs/prysm/v3/testing/util"
"google.golang.org/grpc/metadata"
)
func TestServer_GetBlindedBlock(t *testing.T) {
@@ -592,3 +600,555 @@ func TestServer_GetBlindedBlock(t *testing.T) {
assert.Equal(t, true, blk.ExecutionOptimistic)
})
}
func TestServer_GetBlindedBlockSSZ(t *testing.T) {
t.Run("Phase 0", func(t *testing.T) {
beaconDB := dbTest.SetupDB(t)
ctx := context.Background()
_, blkContainers := fillDBTestBlocks(ctx, t, beaconDB)
headBlock := blkContainers[len(blkContainers)-1]
b2 := util.NewBeaconBlock()
b2.Block.Slot = 30
b2.Block.ParentRoot = bytesutil.PadTo([]byte{1}, 32)
util.SaveBlock(t, ctx, beaconDB, b2)
wsb, err := blocks.NewSignedBeaconBlock(headBlock.Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block)
require.NoError(t, err)
bs := &Server{
BeaconDB: beaconDB,
ChainInfoFetcher: &mock.ChainService{
DB: beaconDB,
Block: wsb,
Root: headBlock.BlockRoot,
FinalizedCheckPoint: &ethpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot},
},
}
blks, err := beaconDB.BlocksBySlot(ctx, 30)
require.Equal(t, true, len(blks) > 0)
require.NoError(t, err)
sszBlock, err := blks[0].MarshalSSZ()
require.NoError(t, err)
resp, err := bs.GetBlindedBlockSSZ(ctx, &ethpbv1.BlockRequest{BlockId: []byte("30")})
require.NoError(t, err)
assert.NotNil(t, resp)
assert.DeepEqual(t, sszBlock, resp.Data)
assert.Equal(t, ethpbv2.Version_PHASE0, resp.Version)
})
t.Run("Altair", func(t *testing.T) {
beaconDB := dbTest.SetupDB(t)
ctx := context.Background()
_, blkContainers := fillDBTestBlocksAltair(ctx, t, beaconDB)
headBlock := blkContainers[len(blkContainers)-1]
b2 := util.NewBeaconBlockAltair()
b2.Block.Slot = 30
b2.Block.ParentRoot = bytesutil.PadTo([]byte{1}, 32)
util.SaveBlock(t, ctx, beaconDB, b2)
chainBlk, err := blocks.NewSignedBeaconBlock(headBlock.GetAltairBlock())
require.NoError(t, err)
bs := &Server{
BeaconDB: beaconDB,
ChainInfoFetcher: &mock.ChainService{
DB: beaconDB,
Block: chainBlk,
Root: headBlock.BlockRoot,
FinalizedCheckPoint: &ethpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot},
},
}
blks, err := beaconDB.BlocksBySlot(ctx, 30)
require.Equal(t, true, len(blks) > 0)
require.NoError(t, err)
sszBlock, err := blks[0].MarshalSSZ()
require.NoError(t, err)
resp, err := bs.GetBlindedBlockSSZ(ctx, &ethpbv1.BlockRequest{BlockId: []byte("30")})
require.NoError(t, err)
assert.NotNil(t, resp)
assert.DeepEqual(t, sszBlock, resp.Data)
assert.Equal(t, ethpbv2.Version_ALTAIR, resp.Version)
})
t.Run("Bellatrix", func(t *testing.T) {
beaconDB := dbTest.SetupDB(t)
ctx := context.Background()
_, blkContainers := fillDBTestBlocksBellatrixBlinded(ctx, t, beaconDB)
headBlock := blkContainers[len(blkContainers)-1]
b2 := util.NewBlindedBeaconBlockBellatrix()
b2.Block.Slot = 30
b2.Block.ParentRoot = bytesutil.PadTo([]byte{1}, 32)
util.SaveBlock(t, ctx, beaconDB, b2)
chainBlk, err := blocks.NewSignedBeaconBlock(headBlock.GetBlindedBellatrixBlock())
require.NoError(t, err)
bs := &Server{
BeaconDB: beaconDB,
ChainInfoFetcher: &mock.ChainService{
DB: beaconDB,
Block: chainBlk,
Root: headBlock.BlockRoot,
FinalizedCheckPoint: &ethpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot},
},
OptimisticModeFetcher: &mock.ChainService{},
}
blks, err := beaconDB.BlocksBySlot(ctx, 30)
require.Equal(t, true, len(blks) > 0)
require.NoError(t, err)
sszBlock, err := blks[0].MarshalSSZ()
require.NoError(t, err)
resp, err := bs.GetBlindedBlockSSZ(ctx, &ethpbv1.BlockRequest{BlockId: []byte("30")})
require.NoError(t, err)
assert.NotNil(t, resp)
assert.DeepEqual(t, sszBlock, resp.Data)
assert.Equal(t, ethpbv2.Version_BELLATRIX, resp.Version)
})
t.Run("Capella", func(t *testing.T) {
beaconDB := dbTest.SetupDB(t)
ctx := context.Background()
_, blkContainers := fillDBTestBlocksCapellaBlinded(ctx, t, beaconDB)
headBlock := blkContainers[len(blkContainers)-1]
b2 := util.NewBlindedBeaconBlockCapella()
b2.Block.Slot = 30
b2.Block.ParentRoot = bytesutil.PadTo([]byte{1}, 32)
util.SaveBlock(t, ctx, beaconDB, b2)
chainBlk, err := blocks.NewSignedBeaconBlock(headBlock.GetBlindedCapellaBlock())
require.NoError(t, err)
bs := &Server{
BeaconDB: beaconDB,
ChainInfoFetcher: &mock.ChainService{
DB: beaconDB,
Block: chainBlk,
Root: headBlock.BlockRoot,
FinalizedCheckPoint: &ethpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot},
},
OptimisticModeFetcher: &mock.ChainService{},
}
blks, err := beaconDB.BlocksBySlot(ctx, 30)
require.Equal(t, true, len(blks) > 0)
require.NoError(t, err)
sszBlock, err := blks[0].MarshalSSZ()
require.NoError(t, err)
resp, err := bs.GetBlindedBlockSSZ(ctx, &ethpbv1.BlockRequest{BlockId: []byte("30")})
require.NoError(t, err)
assert.NotNil(t, resp)
assert.DeepEqual(t, sszBlock, resp.Data)
assert.Equal(t, ethpbv2.Version_CAPELLA, resp.Version)
})
}
func TestServer_SubmitBlindedBlockSSZ_OK(t *testing.T) {
t.Run("Phase 0", func(t *testing.T) {
beaconDB := dbTest.SetupDB(t)
ctx := context.Background()
genesis := util.NewBeaconBlock()
util.SaveBlock(t, context.Background(), beaconDB, genesis)
numDeposits := uint64(64)
beaconState, _ := util.DeterministicGenesisState(t, numDeposits)
bsRoot, err := beaconState.HashTreeRoot(ctx)
require.NoError(t, err)
genesisRoot, err := genesis.Block.HashTreeRoot()
require.NoError(t, err)
require.NoError(t, beaconDB.SaveState(ctx, beaconState, genesisRoot), "Could not save genesis state")
c := &mock.ChainService{Root: bsRoot[:], State: beaconState}
beaconChainServer := &Server{
BeaconDB: beaconDB,
BlockReceiver: c,
ChainInfoFetcher: c,
BlockNotifier: c.BlockNotifier(),
Broadcaster: mockp2p.NewTestP2P(t),
HeadFetcher: c,
}
req := util.NewBeaconBlock()
req.Block.Slot = 5
req.Block.ParentRoot = bsRoot[:]
util.SaveBlock(t, ctx, beaconDB, req)
blockSsz, err := req.MarshalSSZ()
require.NoError(t, err)
blockReq := &ethpbv2.SSZContainer{
Data: blockSsz,
}
md := metadata.MD{}
md.Set(versionHeader, "phase0")
sszCtx := metadata.NewIncomingContext(ctx, md)
_, err = beaconChainServer.SubmitBlindedBlockSSZ(sszCtx, blockReq)
assert.NoError(t, err, "Could not propose block correctly")
})
t.Run("Altair", func(t *testing.T) {
beaconDB := dbTest.SetupDB(t)
ctx := context.Background()
genesis := util.NewBeaconBlockAltair()
util.SaveBlock(t, context.Background(), beaconDB, genesis)
numDeposits := uint64(64)
beaconState, _ := util.DeterministicGenesisState(t, numDeposits)
bsRoot, err := beaconState.HashTreeRoot(ctx)
require.NoError(t, err)
genesisRoot, err := genesis.Block.HashTreeRoot()
require.NoError(t, err)
require.NoError(t, beaconDB.SaveState(ctx, beaconState, genesisRoot), "Could not save genesis state")
c := &mock.ChainService{Root: bsRoot[:], State: beaconState}
beaconChainServer := &Server{
BeaconDB: beaconDB,
BlockReceiver: c,
ChainInfoFetcher: c,
BlockNotifier: c.BlockNotifier(),
Broadcaster: mockp2p.NewTestP2P(t),
HeadFetcher: c,
}
req := util.NewBeaconBlockAltair()
req.Block.Slot = params.BeaconConfig().SlotsPerEpoch.Mul(uint64(params.BeaconConfig().AltairForkEpoch))
req.Block.ParentRoot = bsRoot[:]
util.SaveBlock(t, ctx, beaconDB, req)
blockSsz, err := req.MarshalSSZ()
require.NoError(t, err)
blockReq := &ethpbv2.SSZContainer{
Data: blockSsz,
}
md := metadata.MD{}
md.Set(versionHeader, "altair")
sszCtx := metadata.NewIncomingContext(ctx, md)
_, err = beaconChainServer.SubmitBlindedBlockSSZ(sszCtx, blockReq)
assert.NoError(t, err, "Could not propose block correctly")
})
t.Run("Bellatrix", func(t *testing.T) {
// INFO: This code block can be removed once Bellatrix
// fork epoch is set to a value other than math.MaxUint64
params.SetupTestConfigCleanup(t)
cfg := params.BeaconConfig()
cfg.BellatrixForkEpoch = cfg.AltairForkEpoch + 1000
cfg.ForkVersionSchedule[bytesutil.ToBytes4(cfg.BellatrixForkVersion)] = cfg.AltairForkEpoch + 1000
params.OverrideBeaconConfig(cfg)
beaconDB := dbTest.SetupDB(t)
ctx := context.Background()
genesis := util.NewBeaconBlockBellatrix()
util.SaveBlock(t, context.Background(), beaconDB, genesis)
numDeposits := uint64(64)
beaconState, _ := util.DeterministicGenesisState(t, numDeposits)
bsRoot, err := beaconState.HashTreeRoot(ctx)
require.NoError(t, err)
genesisRoot, err := genesis.Block.HashTreeRoot()
require.NoError(t, err)
require.NoError(t, beaconDB.SaveState(ctx, beaconState, genesisRoot), "Could not save genesis state")
c := &mock.ChainService{Root: bsRoot[:], State: beaconState}
alphaServer := &validator.Server{
SyncCommitteePool: synccommittee.NewStore(),
P2P: &mockp2p.MockBroadcaster{},
BlockBuilder: &builderTest.MockBuilderService{},
BlockReceiver: c,
BlockNotifier: &mock.MockBlockNotifier{},
}
beaconChainServer := &Server{
BeaconDB: beaconDB,
BlockReceiver: c,
ChainInfoFetcher: c,
BlockNotifier: c.BlockNotifier(),
Broadcaster: mockp2p.NewTestP2P(t),
HeadFetcher: c,
V1Alpha1ValidatorServer: alphaServer,
}
req := util.NewBlindedBeaconBlockBellatrix()
req.Block.Slot = params.BeaconConfig().SlotsPerEpoch.Mul(uint64(params.BeaconConfig().BellatrixForkEpoch))
req.Block.ParentRoot = bsRoot[:]
util.SaveBlock(t, ctx, beaconDB, req)
blockSsz, err := req.MarshalSSZ()
require.NoError(t, err)
blockReq := &ethpbv2.SSZContainer{
Data: blockSsz,
}
md := metadata.MD{}
md.Set(versionHeader, "bellatrix")
sszCtx := metadata.NewIncomingContext(ctx, md)
_, err = beaconChainServer.SubmitBlindedBlockSSZ(sszCtx, blockReq)
assert.NoError(t, err, "Could not propose block correctly")
})
t.Run("Capella", func(t *testing.T) {
t.Skip("This test needs Capella fork version configured properly")
// INFO: This code block can be removed once Capella
// fork epoch is set to a value other than math.MaxUint64
params.SetupTestConfigCleanup(t)
cfg := params.BeaconConfig()
cfg.CapellaForkEpoch = cfg.BellatrixForkEpoch + 1000
cfg.ForkVersionSchedule[bytesutil.ToBytes4(cfg.CapellaForkVersion)] = cfg.BellatrixForkEpoch + 1000
params.OverrideBeaconConfig(cfg)
beaconDB := dbTest.SetupDB(t)
ctx := context.Background()
genesis := util.NewBeaconBlockCapella()
util.SaveBlock(t, context.Background(), beaconDB, genesis)
numDeposits := uint64(64)
beaconState, _ := util.DeterministicGenesisState(t, numDeposits)
bsRoot, err := beaconState.HashTreeRoot(ctx)
require.NoError(t, err)
genesisRoot, err := genesis.Block.HashTreeRoot()
require.NoError(t, err)
require.NoError(t, beaconDB.SaveState(ctx, beaconState, genesisRoot), "Could not save genesis state")
c := &mock.ChainService{Root: bsRoot[:], State: beaconState}
alphaServer := &validator.Server{
SyncCommitteePool: synccommittee.NewStore(),
P2P: &mockp2p.MockBroadcaster{},
BlockBuilder: &builderTest.MockBuilderService{},
BlockReceiver: c,
BlockNotifier: &mock.MockBlockNotifier{},
}
beaconChainServer := &Server{
BeaconDB: beaconDB,
BlockReceiver: c,
ChainInfoFetcher: c,
BlockNotifier: c.BlockNotifier(),
Broadcaster: mockp2p.NewTestP2P(t),
HeadFetcher: c,
V1Alpha1ValidatorServer: alphaServer,
}
req := util.NewBlindedBeaconBlockCapella()
req.Block.Slot = params.BeaconConfig().SlotsPerEpoch.Mul(uint64(params.BeaconConfig().CapellaForkEpoch))
req.Block.ParentRoot = bsRoot[:]
util.SaveBlock(t, ctx, beaconDB, req)
blockSsz, err := req.MarshalSSZ()
require.NoError(t, err)
blockReq := &ethpbv2.SSZContainer{
Data: blockSsz,
}
md := metadata.MD{}
md.Set(versionHeader, "capella")
sszCtx := metadata.NewIncomingContext(ctx, md)
_, err = beaconChainServer.SubmitBlindedBlockSSZ(sszCtx, blockReq)
assert.NoError(t, err, "Could not propose block correctly")
})
}
func TestSubmitBlindedBlock(t *testing.T) {
t.Run("Phase 0", func(t *testing.T) {
beaconDB := dbTest.SetupDB(t)
ctx := context.Background()
genesis := util.NewBeaconBlock()
util.SaveBlock(t, context.Background(), beaconDB, genesis)
numDeposits := uint64(64)
beaconState, _ := util.DeterministicGenesisState(t, numDeposits)
bsRoot, err := beaconState.HashTreeRoot(ctx)
require.NoError(t, err)
genesisRoot, err := genesis.Block.HashTreeRoot()
require.NoError(t, err)
require.NoError(t, beaconDB.SaveState(ctx, beaconState, genesisRoot), "Could not save genesis state")
c := &mock.ChainService{Root: bsRoot[:], State: beaconState}
beaconChainServer := &Server{
BeaconDB: beaconDB,
BlockReceiver: c,
ChainInfoFetcher: c,
BlockNotifier: c.BlockNotifier(),
Broadcaster: mockp2p.NewTestP2P(t),
}
req := util.NewBeaconBlock()
req.Block.Slot = 5
req.Block.ParentRoot = bsRoot[:]
v1Block, err := migration.V1Alpha1ToV1SignedBlock(req)
require.NoError(t, err)
util.SaveBlock(t, ctx, beaconDB, req)
blockReq := &ethpbv2.SignedBlindedBeaconBlockContainer{
Message: &ethpbv2.SignedBlindedBeaconBlockContainer_Phase0Block{Phase0Block: v1Block.Block},
Signature: v1Block.Signature,
}
_, err = beaconChainServer.SubmitBlindedBlock(context.Background(), blockReq)
assert.NoError(t, err, "Could not propose block correctly")
})
t.Run("Altair", func(t *testing.T) {
beaconDB := dbTest.SetupDB(t)
ctx := context.Background()
genesis := util.NewBeaconBlockAltair()
util.SaveBlock(t, context.Background(), beaconDB, genesis)
numDeposits := uint64(64)
beaconState, _ := util.DeterministicGenesisState(t, numDeposits)
bsRoot, err := beaconState.HashTreeRoot(ctx)
require.NoError(t, err)
genesisRoot, err := genesis.Block.HashTreeRoot()
require.NoError(t, err)
require.NoError(t, beaconDB.SaveState(ctx, beaconState, genesisRoot), "Could not save genesis state")
c := &mock.ChainService{Root: bsRoot[:], State: beaconState}
beaconChainServer := &Server{
BeaconDB: beaconDB,
BlockReceiver: c,
ChainInfoFetcher: c,
BlockNotifier: c.BlockNotifier(),
Broadcaster: mockp2p.NewTestP2P(t),
}
req := util.NewBeaconBlockAltair()
req.Block.Slot = 5
req.Block.ParentRoot = bsRoot[:]
v2Block, err := migration.V1Alpha1BeaconBlockAltairToV2(req.Block)
require.NoError(t, err)
util.SaveBlock(t, ctx, beaconDB, req)
blockReq := &ethpbv2.SignedBlindedBeaconBlockContainer{
Message: &ethpbv2.SignedBlindedBeaconBlockContainer_AltairBlock{AltairBlock: v2Block},
Signature: req.Signature,
}
_, err = beaconChainServer.SubmitBlindedBlock(context.Background(), blockReq)
assert.NoError(t, err, "Could not propose block correctly")
})
t.Run("Bellatrix", func(t *testing.T) {
transactions := [][]byte{[]byte("transaction1"), []byte("transaction2")}
transactionsRoot, err := ssz.TransactionsRoot(transactions)
require.NoError(t, err)
beaconDB := dbTest.SetupDB(t)
ctx := context.Background()
genesis := util.NewBeaconBlockBellatrix()
util.SaveBlock(t, context.Background(), beaconDB, genesis)
numDeposits := uint64(64)
beaconState, _ := util.DeterministicGenesisState(t, numDeposits)
bsRoot, err := beaconState.HashTreeRoot(ctx)
require.NoError(t, err)
genesisRoot, err := genesis.Block.HashTreeRoot()
require.NoError(t, err)
require.NoError(t, beaconDB.SaveState(ctx, beaconState, genesisRoot), "Could not save genesis state")
c := &mock.ChainService{Root: bsRoot[:], State: beaconState}
alphaServer := &validator.Server{
SyncCommitteePool: synccommittee.NewStore(),
P2P: &mockp2p.MockBroadcaster{},
BlockBuilder: &builderTest.MockBuilderService{},
BlockReceiver: c,
BlockNotifier: &mock.MockBlockNotifier{},
}
beaconChainServer := &Server{
BeaconDB: beaconDB,
BlockReceiver: c,
ChainInfoFetcher: c,
BlockNotifier: c.BlockNotifier(),
Broadcaster: mockp2p.NewTestP2P(t),
V1Alpha1ValidatorServer: alphaServer,
}
blk := util.NewBeaconBlockBellatrix()
blk.Block.Slot = 5
blk.Block.ParentRoot = bsRoot[:]
blk.Block.Body.ExecutionPayload.Transactions = transactions
blindedBlk := util.NewBlindedBeaconBlockBellatrixV2()
blindedBlk.Message.Slot = 5
blindedBlk.Message.ParentRoot = bsRoot[:]
blindedBlk.Message.Body.ExecutionPayloadHeader.TransactionsRoot = transactionsRoot[:]
util.SaveBlock(t, ctx, beaconDB, blk)
blockReq := &ethpbv2.SignedBlindedBeaconBlockContainer{
Message: &ethpbv2.SignedBlindedBeaconBlockContainer_BellatrixBlock{BellatrixBlock: blindedBlk.Message},
Signature: blindedBlk.Signature,
}
_, err = beaconChainServer.SubmitBlindedBlock(context.Background(), blockReq)
assert.NoError(t, err)
})
t.Run("Capella", func(t *testing.T) {
transactions := [][]byte{[]byte("transaction1"), []byte("transaction2")}
transactionsRoot, err := ssz.TransactionsRoot(transactions)
require.NoError(t, err)
withdrawals := []*enginev1.Withdrawal{
{
Index: 1,
ValidatorIndex: 1,
Address: bytesutil.PadTo([]byte("address1"), 20),
Amount: 1,
},
{
Index: 2,
ValidatorIndex: 2,
Address: bytesutil.PadTo([]byte("address2"), 20),
Amount: 2,
},
}
withdrawalsRoot, err := ssz.WithdrawalSliceRoot(hash.CustomSHA256Hasher(), withdrawals, 16)
require.NoError(t, err)
beaconDB := dbTest.SetupDB(t)
ctx := context.Background()
genesis := util.NewBeaconBlockCapella()
util.SaveBlock(t, context.Background(), beaconDB, genesis)
numDeposits := uint64(64)
beaconState, _ := util.DeterministicGenesisState(t, numDeposits)
bsRoot, err := beaconState.HashTreeRoot(ctx)
require.NoError(t, err)
genesisRoot, err := genesis.Block.HashTreeRoot()
require.NoError(t, err)
require.NoError(t, beaconDB.SaveState(ctx, beaconState, genesisRoot), "Could not save genesis state")
c := &mock.ChainService{Root: bsRoot[:], State: beaconState}
alphaServer := &validator.Server{
SyncCommitteePool: synccommittee.NewStore(),
P2P: &mockp2p.MockBroadcaster{},
BlockBuilder: &builderTest.MockBuilderService{},
BlockReceiver: c,
BlockNotifier: &mock.MockBlockNotifier{},
}
beaconChainServer := &Server{
BeaconDB: beaconDB,
BlockReceiver: c,
ChainInfoFetcher: c,
BlockNotifier: c.BlockNotifier(),
Broadcaster: mockp2p.NewTestP2P(t),
V1Alpha1ValidatorServer: alphaServer,
}
blk := util.NewBeaconBlockCapella()
blk.Block.Slot = 5
blk.Block.ParentRoot = bsRoot[:]
blk.Block.Body.ExecutionPayload.Transactions = transactions
blk.Block.Body.ExecutionPayload.Withdrawals = withdrawals
blindedBlk := util.NewBlindedBeaconBlockCapellaV2()
blindedBlk.Message.Slot = 5
blindedBlk.Message.ParentRoot = bsRoot[:]
blindedBlk.Message.Body.ExecutionPayloadHeader.TransactionsRoot = transactionsRoot[:]
blindedBlk.Message.Body.ExecutionPayloadHeader.WithdrawalsRoot = withdrawalsRoot[:]
util.SaveBlock(t, ctx, beaconDB, blk)
blockReq := &ethpbv2.SignedBlindedBeaconBlockContainer{
Message: &ethpbv2.SignedBlindedBeaconBlockContainer_CapellaBlock{CapellaBlock: blindedBlk.Message},
Signature: blindedBlk.Signature,
}
_, err = beaconChainServer.SubmitBlindedBlock(context.Background(), blockReq)
assert.NoError(t, err)
})
}

View File

@@ -23,7 +23,6 @@ import (
ethpbv1 "github.com/prysmaticlabs/prysm/v3/proto/eth/v1"
ethpbv2 "github.com/prysmaticlabs/prysm/v3/proto/eth/v2"
"github.com/prysmaticlabs/prysm/v3/proto/migration"
eth "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v3/time/slots"
"go.opencensus.io/trace"
"google.golang.org/grpc/codes"
@@ -234,6 +233,12 @@ func (bs *Server) SubmitBlock(ctx context.Context, req *ethpbv2.SignedBeaconBloc
return nil, err
}
}
capellaBlkContainer, ok := req.Message.(*ethpbv2.SignedBeaconBlockContainer_CapellaBlock)
if ok {
if err := bs.submitCapellaBlock(ctx, capellaBlkContainer.CapellaBlock, req.Signature); err != nil {
return nil, err
}
}
return &emptypb.Empty{}, nil
}
@@ -276,97 +281,6 @@ func (bs *Server) SubmitBlockSSZ(ctx context.Context, req *ethpbv2.SSZContainer)
return &emptypb.Empty{}, bs.submitBlock(ctx, root, block)
}
// SubmitBlindedBlock instructs the beacon node to use the components of the `SignedBlindedBeaconBlock` to construct
// and publish a `SignedBeaconBlock` by swapping out the `transactions_root` for the corresponding full list of `transactions`.
// The beacon node should broadcast a newly constructed `SignedBeaconBlock` to the beacon network,
// to be included in the beacon chain. The beacon node is not required to validate the signed
// `BeaconBlock`, and a successful response (20X) only indicates that the broadcast has been
// successful. The beacon node is expected to integrate the new block into its state, and
// therefore validate the block internally, however blocks which fail the validation are still
// broadcast but a different status code is returned (202).
func (bs *Server) SubmitBlindedBlock(ctx context.Context, req *ethpbv2.SignedBlindedBeaconBlockContainer) (*emptypb.Empty, error) {
ctx, span := trace.StartSpan(ctx, "beacon.SubmitBlindedBlock")
defer span.End()
bellatrixBlkContainer, ok := req.Message.(*ethpbv2.SignedBlindedBeaconBlockContainer_BellatrixBlock)
if ok {
if err := bs.submitBlindedBellatrixBlock(ctx, bellatrixBlkContainer.BellatrixBlock, req.Signature); err != nil {
return nil, err
}
}
// At the end we check forks that don't have blinded blocks.
phase0BlkContainer, ok := req.Message.(*ethpbv2.SignedBlindedBeaconBlockContainer_Phase0Block)
if ok {
if err := bs.submitPhase0Block(ctx, phase0BlkContainer.Phase0Block, req.Signature); err != nil {
return nil, err
}
}
altairBlkContainer, ok := req.Message.(*ethpbv2.SignedBlindedBeaconBlockContainer_AltairBlock)
if ok {
if err := bs.submitAltairBlock(ctx, altairBlkContainer.AltairBlock, req.Signature); err != nil {
return nil, err
}
}
return &emptypb.Empty{}, nil
}
// SubmitBlindedBlockSSZ instructs the beacon node to use the components of the `SignedBlindedBeaconBlock` to construct
// and publish a `SignedBeaconBlock` by swapping out the `transactions_root` for the corresponding full list of `transactions`.
// The beacon node should broadcast a newly constructed `SignedBeaconBlock` to the beacon network,
// to be included in the beacon chain. The beacon node is not required to validate the signed
// `BeaconBlock`, and a successful response (20X) only indicates that the broadcast has been
// successful. The beacon node is expected to integrate the new block into its state, and
// therefore validate the block internally, however blocks which fail the validation are still
// broadcast but a different status code is returned (202).
//
// The provided block must be SSZ-serialized.
func (bs *Server) SubmitBlindedBlockSSZ(ctx context.Context, req *ethpbv2.SSZContainer) (*emptypb.Empty, error) {
ctx, span := trace.StartSpan(ctx, "beacon.SubmitBlindedBlockSSZ")
defer span.End()
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
return &emptypb.Empty{}, status.Errorf(codes.Internal, "Could not read"+versionHeader+" header")
}
ver := md.Get(versionHeader)
if len(ver) == 0 {
return &emptypb.Empty{}, status.Errorf(codes.Internal, "Could not read"+versionHeader+" header")
}
schedule := forks.NewOrderedSchedule(params.BeaconConfig())
forkVer, err := schedule.VersionForName(ver[0])
if err != nil {
return &emptypb.Empty{}, status.Errorf(codes.Internal, "Could not determine fork version: %v", err)
}
unmarshaler, err := detect.FromForkVersion(forkVer)
if err != nil {
return &emptypb.Empty{}, status.Errorf(codes.Internal, "Could not create unmarshaler: %v", err)
}
block, err := unmarshaler.UnmarshalBlindedBeaconBlock(req.Data)
if err != nil {
return &emptypb.Empty{}, status.Errorf(codes.Internal, "Could not unmarshal request data into block: %v", err)
}
if block.IsBlinded() {
b, err := block.PbBlindedBellatrixBlock()
if err != nil {
return &emptypb.Empty{}, status.Errorf(codes.Internal, "Could not get blinded block: %v", err)
}
bb, err := migration.V1Alpha1BeaconBlockBlindedBellatrixToV2Blinded(b.Block)
if err != nil {
return &emptypb.Empty{}, status.Errorf(codes.Internal, "Could not migrate block: %v", err)
}
return &emptypb.Empty{}, bs.submitBlindedBellatrixBlock(ctx, bb, b.Signature)
}
root, err := block.Block().HashTreeRoot()
if err != nil {
return &emptypb.Empty{}, status.Errorf(codes.Internal, "Could not compute block's hash tree root: %v", err)
}
return &emptypb.Empty{}, bs.submitBlock(ctx, root, block)
}
// GetBlock retrieves block details for given block ID.
func (bs *Server) GetBlock(ctx context.Context, req *ethpbv1.BlockRequest) (*ethpbv1.BlockResponse, error) {
ctx, span := trace.StartSpan(ctx, "beacon.GetBlock")
@@ -423,128 +337,38 @@ func (bs *Server) GetBlockV2(ctx context.Context, req *ethpbv2.BlockRequestV2) (
return nil, err
}
phase0Blk, err := blk.PbPhase0Block()
if err == nil {
if phase0Blk == nil {
return nil, status.Error(codes.Internal, "Nil block")
}
v1Blk, err := migration.SignedBeaconBlock(blk)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not get signed beacon block: %v", err)
}
return &ethpbv2.BlockResponseV2{
Version: ethpbv2.Version_PHASE0,
Data: &ethpbv2.SignedBeaconBlockContainer{
Message: &ethpbv2.SignedBeaconBlockContainer_Phase0Block{Phase0Block: v1Blk.Block},
Signature: v1Blk.Signature,
},
ExecutionOptimistic: false,
}, nil
result, err := getBlockPhase0(blk)
if result != nil {
return result, nil
}
// ErrUnsupportedGetter means that we have another block type
if !errors.Is(err, blocks.ErrUnsupportedGetter) {
return nil, status.Errorf(codes.Internal, "Could not get signed beacon block: %v", err)
}
altairBlk, err := blk.PbAltairBlock()
if err == nil {
if altairBlk == nil {
return nil, status.Error(codes.Internal, "Nil block")
}
v2Blk, err := migration.V1Alpha1BeaconBlockAltairToV2(altairBlk.Block)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not get signed beacon block: %v", err)
}
sig := blk.Signature()
return &ethpbv2.BlockResponseV2{
Version: ethpbv2.Version_ALTAIR,
Data: &ethpbv2.SignedBeaconBlockContainer{
Message: &ethpbv2.SignedBeaconBlockContainer_AltairBlock{AltairBlock: v2Blk},
Signature: sig[:],
},
ExecutionOptimistic: false,
}, nil
result, err = getBlockAltair(blk)
if result != nil {
return result, nil
}
// ErrUnsupportedGetter means that we have another block type
if !errors.Is(err, blocks.ErrUnsupportedGetter) {
return nil, status.Errorf(codes.Internal, "Could not get signed beacon block: %v", err)
}
bellatrixBlk, err := blk.PbBellatrixBlock()
if err == nil {
if bellatrixBlk == nil {
return nil, status.Error(codes.Internal, "Nil block")
}
v2Blk, err := migration.V1Alpha1BeaconBlockBellatrixToV2(bellatrixBlk.Block)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not get signed beacon block: %v", err)
}
root, err := blk.Block().HashTreeRoot()
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not get block root: %v", err)
}
isOptimistic, err := bs.OptimisticModeFetcher.IsOptimisticForRoot(ctx, root)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not check if block is optimistic: %v", err)
}
sig := blk.Signature()
return &ethpbv2.BlockResponseV2{
Version: ethpbv2.Version_BELLATRIX,
Data: &ethpbv2.SignedBeaconBlockContainer{
Message: &ethpbv2.SignedBeaconBlockContainer_BellatrixBlock{BellatrixBlock: v2Blk},
Signature: sig[:],
},
ExecutionOptimistic: isOptimistic,
}, nil
result, err = bs.getBlockBellatrix(ctx, blk)
if result != nil {
return result, nil
}
// ErrUnsupportedGetter means that we have another block type
if !errors.Is(err, blocks.ErrUnsupportedGetter) {
return nil, status.Errorf(codes.Internal, "Could not get signed beacon block: %v", err)
}
if blindedBellatrixBlk, err := blk.PbBlindedBellatrixBlock(); err == nil {
if blindedBellatrixBlk == nil {
return nil, status.Error(codes.Internal, "Nil block")
}
signedFullBlock, err := bs.ExecutionPayloadReconstructor.ReconstructFullBellatrixBlock(ctx, blk)
if err != nil {
return nil, status.Errorf(
codes.Internal,
"Could not reconstruct full execution payload to create signed beacon block: %v",
err,
)
}
bellatrixBlk, err = signedFullBlock.PbBellatrixBlock()
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not get signed beacon block: %v", err)
}
v2Blk, err := migration.V1Alpha1BeaconBlockBellatrixToV2(bellatrixBlk.Block)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not get signed beacon block: %v", err)
}
root, err := blk.Block().HashTreeRoot()
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not get block root: %v", err)
}
isOptimistic, err := bs.OptimisticModeFetcher.IsOptimisticForRoot(ctx, root)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not check if block is optimistic: %v", err)
}
sig := blk.Signature()
return &ethpbv2.BlockResponseV2{
Version: ethpbv2.Version_BELLATRIX,
Data: &ethpbv2.SignedBeaconBlockContainer{
Message: &ethpbv2.SignedBeaconBlockContainer_BellatrixBlock{BellatrixBlock: v2Blk},
Signature: sig[:],
},
ExecutionOptimistic: isOptimistic,
}, nil
result, err = bs.getBlockCapella(ctx, blk)
if result != nil {
return result, nil
}
// ErrUnsupportedGetter means that we have another block type
if !errors.Is(err, blocks.ErrUnsupportedGetter) {
return nil, status.Errorf(codes.Internal, "Could not get signed beacon block: %v", err)
}
return nil, status.Errorf(codes.Internal, "Unknown block type %T", blk)
}
@@ -559,262 +383,33 @@ func (bs *Server) GetBlockSSZV2(ctx context.Context, req *ethpbv2.BlockRequestV2
return nil, err
}
phase0Blk, err := blk.PbPhase0Block()
if err == nil {
if phase0Blk == nil {
return nil, status.Error(codes.Internal, "Nil block")
}
signedBeaconBlock, err := migration.SignedBeaconBlock(blk)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not get signed beacon block: %v", err)
}
sszBlock, err := signedBeaconBlock.MarshalSSZ()
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not marshal block into SSZ: %v", err)
}
return &ethpbv2.SSZContainer{Version: ethpbv2.Version_PHASE0, ExecutionOptimistic: false, Data: sszBlock}, nil
result, err := getSSZBlockPhase0(blk)
if result != nil {
return result, nil
}
// ErrUnsupportedGetter means that we have another block type
if !errors.Is(err, blocks.ErrUnsupportedGetter) {
return nil, status.Errorf(codes.Internal, "Could not get signed beacon block: %v", err)
}
altairBlk, err := blk.PbAltairBlock()
if err == nil {
if altairBlk == nil {
return nil, status.Error(codes.Internal, "Nil block")
}
v2Blk, err := migration.V1Alpha1BeaconBlockAltairToV2(altairBlk.Block)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not get signed beacon block: %v", err)
}
sig := blk.Signature()
data := &ethpbv2.SignedBeaconBlockAltair{
Message: v2Blk,
Signature: sig[:],
}
sszData, err := data.MarshalSSZ()
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not marshal block into SSZ: %v", err)
}
return &ethpbv2.SSZContainer{Version: ethpbv2.Version_ALTAIR, ExecutionOptimistic: false, Data: sszData}, nil
result, err = getSSZBlockAltair(blk)
if result != nil {
return result, nil
}
// ErrUnsupportedGetter means that we have another block type
if !errors.Is(err, blocks.ErrUnsupportedGetter) {
return nil, status.Errorf(codes.Internal, "Could not get signed beacon block: %v", err)
}
bellatrixBlk, err := blk.PbBellatrixBlock()
if err == nil {
if bellatrixBlk == nil {
return nil, status.Error(codes.Internal, "Nil block")
}
v2Blk, err := migration.V1Alpha1BeaconBlockBellatrixToV2(bellatrixBlk.Block)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not get signed beacon block: %v", err)
}
root, err := blk.Block().HashTreeRoot()
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not get block root: %v", err)
}
isOptimistic, err := bs.OptimisticModeFetcher.IsOptimisticForRoot(ctx, root)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not check if block is optimistic: %v", err)
}
sig := blk.Signature()
data := &ethpbv2.SignedBeaconBlockBellatrix{
Message: v2Blk,
Signature: sig[:],
}
sszData, err := data.MarshalSSZ()
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not marshal block into SSZ: %v", err)
}
return &ethpbv2.SSZContainer{Version: ethpbv2.Version_BELLATRIX, ExecutionOptimistic: isOptimistic, Data: sszData}, nil
result, err = bs.getSSZBlockBellatrix(ctx, blk)
if result != nil {
return result, nil
}
// ErrUnsupportedGetter means that we have another block type
if !errors.Is(err, blocks.ErrUnsupportedGetter) {
return nil, status.Errorf(codes.Internal, "Could not get signed beacon block: %v", err)
}
if blindedBellatrixBlk, err := blk.PbBlindedBellatrixBlock(); err == nil {
if blindedBellatrixBlk == nil {
return nil, status.Error(codes.Internal, "Nil block")
}
signedFullBlock, err := bs.ExecutionPayloadReconstructor.ReconstructFullBellatrixBlock(ctx, blk)
if err != nil {
return nil, status.Errorf(
codes.Internal,
"Could not reconstruct full execution payload to create signed beacon block: %v",
err,
)
}
bellatrixBlk, err = signedFullBlock.PbBellatrixBlock()
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not get signed beacon block: %v", err)
}
v2Blk, err := migration.V1Alpha1BeaconBlockBellatrixToV2(bellatrixBlk.Block)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not get signed beacon block: %v", err)
}
root, err := blk.Block().HashTreeRoot()
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not get block root: %v", err)
}
isOptimistic, err := bs.OptimisticModeFetcher.IsOptimisticForRoot(ctx, root)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not check if block is optimistic: %v", err)
}
sig := blk.Signature()
data := &ethpbv2.SignedBeaconBlockBellatrix{
Message: v2Blk,
Signature: sig[:],
}
sszData, err := data.MarshalSSZ()
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not marshal block into SSZ: %v", err)
}
return &ethpbv2.SSZContainer{
Version: ethpbv2.Version_BELLATRIX,
ExecutionOptimistic: isOptimistic,
Data: sszData,
}, nil
}
// ErrUnsupportedGetter means that we have another block type
if !errors.Is(err, blocks.ErrUnsupportedGetter) {
return nil, status.Errorf(codes.Internal, "Could not get signed beacon block: %v", err)
}
return nil, status.Errorf(codes.Internal, "Unknown block type %T", blk)
}
// GetBlindedBlockSSZ returns the SSZ-serialized version of the blinded beacon block for given block id.
func (bs *Server) GetBlindedBlockSSZ(ctx context.Context, req *ethpbv1.BlockRequest) (*ethpbv2.SSZContainer, error) {
ctx, span := trace.StartSpan(ctx, "beacon.GetBlindedBlockSSZ")
defer span.End()
blk, err := bs.blockFromBlockID(ctx, req.BlockId)
err = handleGetBlockError(blk, err)
if err != nil {
return nil, err
}
phase0Blk, err := blk.PbPhase0Block()
if err == nil {
if phase0Blk == nil {
return nil, status.Error(codes.Internal, "Nil block")
}
signedBeaconBlock, err := migration.SignedBeaconBlock(blk)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not get signed beacon block: %v", err)
}
sszBlock, err := signedBeaconBlock.MarshalSSZ()
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not marshal block into SSZ: %v", err)
}
return &ethpbv2.SSZContainer{Version: ethpbv2.Version_PHASE0, ExecutionOptimistic: false, Data: sszBlock}, nil
}
// ErrUnsupportedGetter means that we have another block type
if !errors.Is(err, blocks.ErrUnsupportedGetter) {
return nil, status.Errorf(codes.Internal, "Could not get signed beacon block: %v", err)
}
altairBlk, err := blk.PbAltairBlock()
if err == nil {
if altairBlk == nil {
return nil, status.Error(codes.Internal, "Nil block")
}
v2Blk, err := migration.V1Alpha1BeaconBlockAltairToV2(altairBlk.Block)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not get signed beacon block: %v", err)
}
sig := blk.Signature()
data := &ethpbv2.SignedBeaconBlockAltair{
Message: v2Blk,
Signature: sig[:],
}
sszData, err := data.MarshalSSZ()
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not marshal block into SSZ: %v", err)
}
return &ethpbv2.SSZContainer{Version: ethpbv2.Version_ALTAIR, ExecutionOptimistic: false, Data: sszData}, nil
}
// ErrUnsupportedGetter means that we have another block type
if !errors.Is(err, blocks.ErrUnsupportedGetter) {
return nil, status.Errorf(codes.Internal, "Could not get signed beacon block: %v", err)
}
bellatrixBlk, err := blk.PbBellatrixBlock()
if err == nil {
if bellatrixBlk == nil {
return nil, status.Error(codes.Internal, "Nil block")
}
blindedBlkInterface, err := blk.ToBlinded()
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not convert block to blinded block: %v", err)
}
blindedBellatrixBlock, err := blindedBlkInterface.PbBlindedBellatrixBlock()
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not get signed beacon block: %v", err)
}
v2Blk, err := migration.V1Alpha1BeaconBlockBlindedBellatrixToV2Blinded(blindedBellatrixBlock.Block)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not get signed beacon block: %v", err)
}
root, err := blk.Block().HashTreeRoot()
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not get block root: %v", err)
}
isOptimistic, err := bs.OptimisticModeFetcher.IsOptimisticForRoot(ctx, root)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not check if block is optimistic: %v", err)
}
sig := blk.Signature()
data := &ethpbv2.SignedBlindedBeaconBlockBellatrix{
Message: v2Blk,
Signature: sig[:],
}
sszData, err := data.MarshalSSZ()
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not marshal block into SSZ: %v", err)
}
return &ethpbv2.SSZContainer{Version: ethpbv2.Version_BELLATRIX, ExecutionOptimistic: isOptimistic, Data: sszData}, nil
}
// ErrUnsupportedGetter means that we have another block type
if !errors.Is(err, blocks.ErrUnsupportedGetter) {
return nil, status.Errorf(codes.Internal, "Could not get signed beacon block: %v", err)
}
if blindedBellatrixBlk, err := blk.PbBlindedBellatrixBlock(); err == nil {
if blindedBellatrixBlk == nil {
return nil, status.Error(codes.Internal, "Nil block")
}
v2Blk, err := migration.V1Alpha1BeaconBlockBlindedBellatrixToV2Blinded(blindedBellatrixBlk.Block)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not get signed beacon block: %v", err)
}
root, err := blk.Block().HashTreeRoot()
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not get block root: %v", err)
}
isOptimistic, err := bs.OptimisticModeFetcher.IsOptimisticForRoot(ctx, root)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not check if block is optimistic: %v", err)
}
sig := blk.Signature()
data := &ethpbv2.SignedBlindedBeaconBlockBellatrix{
Message: v2Blk,
Signature: sig[:],
}
sszData, err := data.MarshalSSZ()
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not marshal block into SSZ: %v", err)
}
return &ethpbv2.SSZContainer{
Version: ethpbv2.Version_BELLATRIX,
ExecutionOptimistic: isOptimistic,
Data: sszData,
}, nil
result, err = bs.getSSZBlockCapella(ctx, blk)
if result != nil {
return result, nil
}
// ErrUnsupportedGetter means that we have another block type
if !errors.Is(err, blocks.ErrUnsupportedGetter) {
@@ -1013,6 +608,386 @@ func handleGetBlockError(blk interfaces.SignedBeaconBlock, err error) error {
return nil
}
func getBlockPhase0(blk interfaces.SignedBeaconBlock) (*ethpbv2.BlockResponseV2, error) {
phase0Blk, err := blk.PbPhase0Block()
if err != nil {
return nil, err
}
if phase0Blk == nil {
return nil, errNilBlock
}
v1Blk, err := migration.SignedBeaconBlock(blk)
if err != nil {
return nil, errors.Wrapf(err, "could not get signed beacon block")
}
return &ethpbv2.BlockResponseV2{
Version: ethpbv2.Version_PHASE0,
Data: &ethpbv2.SignedBeaconBlockContainer{
Message: &ethpbv2.SignedBeaconBlockContainer_Phase0Block{Phase0Block: v1Blk.Block},
Signature: v1Blk.Signature,
},
ExecutionOptimistic: false,
}, nil
}
func getBlockAltair(blk interfaces.SignedBeaconBlock) (*ethpbv2.BlockResponseV2, error) {
altairBlk, err := blk.PbAltairBlock()
if err != nil {
return nil, err
}
if altairBlk == nil {
return nil, errNilBlock
}
v2Blk, err := migration.V1Alpha1BeaconBlockAltairToV2(altairBlk.Block)
if err != nil {
return nil, errors.Wrapf(err, "could not get signed beacon block")
}
sig := blk.Signature()
return &ethpbv2.BlockResponseV2{
Version: ethpbv2.Version_ALTAIR,
Data: &ethpbv2.SignedBeaconBlockContainer{
Message: &ethpbv2.SignedBeaconBlockContainer_AltairBlock{AltairBlock: v2Blk},
Signature: sig[:],
},
ExecutionOptimistic: false,
}, nil
}
func (bs *Server) getBlockBellatrix(ctx context.Context, blk interfaces.SignedBeaconBlock) (*ethpbv2.BlockResponseV2, error) {
bellatrixBlk, err := blk.PbBellatrixBlock()
if err != nil {
// ErrUnsupportedGetter means that we have another block type
if errors.Is(err, blocks.ErrUnsupportedGetter) {
if blindedBellatrixBlk, err := blk.PbBlindedBellatrixBlock(); err == nil {
if blindedBellatrixBlk == nil {
return nil, errNilBlock
}
signedFullBlock, err := bs.ExecutionPayloadReconstructor.ReconstructFullBlock(ctx, blk)
if err != nil {
return nil, errors.Wrapf(err, "could not reconstruct full execution payload to create signed beacon block")
}
bellatrixBlk, err = signedFullBlock.PbBellatrixBlock()
if err != nil {
return nil, errors.Wrapf(err, "could not get signed beacon block")
}
v2Blk, err := migration.V1Alpha1BeaconBlockBellatrixToV2(bellatrixBlk.Block)
if err != nil {
return nil, errors.Wrapf(err, "could not convert beacon block")
}
root, err := blk.Block().HashTreeRoot()
if err != nil {
return nil, errors.Wrapf(err, "could not get block root")
}
isOptimistic, err := bs.OptimisticModeFetcher.IsOptimisticForRoot(ctx, root)
if err != nil {
return nil, errors.Wrapf(err, "could not check if block is optimistic")
}
sig := blk.Signature()
return &ethpbv2.BlockResponseV2{
Version: ethpbv2.Version_BELLATRIX,
Data: &ethpbv2.SignedBeaconBlockContainer{
Message: &ethpbv2.SignedBeaconBlockContainer_BellatrixBlock{BellatrixBlock: v2Blk},
Signature: sig[:],
},
ExecutionOptimistic: isOptimistic,
}, nil
}
return nil, err
}
return nil, err
}
if bellatrixBlk == nil {
return nil, errNilBlock
}
v2Blk, err := migration.V1Alpha1BeaconBlockBellatrixToV2(bellatrixBlk.Block)
if err != nil {
return nil, errors.Wrapf(err, "could not convert beacon block")
}
root, err := blk.Block().HashTreeRoot()
if err != nil {
return nil, errors.Wrapf(err, "could not get block root")
}
isOptimistic, err := bs.OptimisticModeFetcher.IsOptimisticForRoot(ctx, root)
if err != nil {
return nil, errors.Wrapf(err, "could not check if block is optimistic")
}
sig := blk.Signature()
return &ethpbv2.BlockResponseV2{
Version: ethpbv2.Version_BELLATRIX,
Data: &ethpbv2.SignedBeaconBlockContainer{
Message: &ethpbv2.SignedBeaconBlockContainer_BellatrixBlock{BellatrixBlock: v2Blk},
Signature: sig[:],
},
ExecutionOptimistic: isOptimistic,
}, nil
}
func (bs *Server) getBlockCapella(ctx context.Context, blk interfaces.SignedBeaconBlock) (*ethpbv2.BlockResponseV2, error) {
capellaBlk, err := blk.PbCapellaBlock()
if err != nil {
// ErrUnsupportedGetter means that we have another block type
if errors.Is(err, blocks.ErrUnsupportedGetter) {
if blindedCapellaBlk, err := blk.PbBlindedCapellaBlock(); err == nil {
if blindedCapellaBlk == nil {
return nil, errNilBlock
}
signedFullBlock, err := bs.ExecutionPayloadReconstructor.ReconstructFullBlock(ctx, blk)
if err != nil {
return nil, errors.Wrapf(err, "could not reconstruct full execution payload to create signed beacon block")
}
capellaBlk, err = signedFullBlock.PbCapellaBlock()
if err != nil {
return nil, errors.Wrapf(err, "could not get signed beacon block")
}
v2Blk, err := migration.V1Alpha1BeaconBlockCapellaToV2(capellaBlk.Block)
if err != nil {
return nil, errors.Wrapf(err, "could not convert beacon block")
}
root, err := blk.Block().HashTreeRoot()
if err != nil {
return nil, errors.Wrapf(err, "could not get block root")
}
isOptimistic, err := bs.OptimisticModeFetcher.IsOptimisticForRoot(ctx, root)
if err != nil {
return nil, errors.Wrapf(err, "could not check if block is optimistic")
}
sig := blk.Signature()
return &ethpbv2.BlockResponseV2{
Version: ethpbv2.Version_CAPELLA,
Data: &ethpbv2.SignedBeaconBlockContainer{
Message: &ethpbv2.SignedBeaconBlockContainer_CapellaBlock{CapellaBlock: v2Blk},
Signature: sig[:],
},
ExecutionOptimistic: isOptimistic,
}, nil
}
return nil, err
}
return nil, err
}
if capellaBlk == nil {
return nil, errNilBlock
}
v2Blk, err := migration.V1Alpha1BeaconBlockCapellaToV2(capellaBlk.Block)
if err != nil {
return nil, errors.Wrapf(err, "could not convert beacon block")
}
root, err := blk.Block().HashTreeRoot()
if err != nil {
return nil, errors.Wrapf(err, "could not get block root")
}
isOptimistic, err := bs.OptimisticModeFetcher.IsOptimisticForRoot(ctx, root)
if err != nil {
return nil, errors.Wrapf(err, "could not check if block is optimistic")
}
sig := blk.Signature()
return &ethpbv2.BlockResponseV2{
Version: ethpbv2.Version_CAPELLA,
Data: &ethpbv2.SignedBeaconBlockContainer{
Message: &ethpbv2.SignedBeaconBlockContainer_CapellaBlock{CapellaBlock: v2Blk},
Signature: sig[:],
},
ExecutionOptimistic: isOptimistic,
}, nil
}
func getSSZBlockPhase0(blk interfaces.SignedBeaconBlock) (*ethpbv2.SSZContainer, error) {
phase0Blk, err := blk.PbPhase0Block()
if err != nil {
return nil, err
}
if phase0Blk == nil {
return nil, errNilBlock
}
signedBeaconBlock, err := migration.SignedBeaconBlock(blk)
if err != nil {
return nil, errors.Wrapf(err, "could not get signed beacon block")
}
sszBlock, err := signedBeaconBlock.MarshalSSZ()
if err != nil {
return nil, errors.Wrapf(err, "could not marshal block into SSZ")
}
return &ethpbv2.SSZContainer{Version: ethpbv2.Version_PHASE0, ExecutionOptimistic: false, Data: sszBlock}, nil
}
func getSSZBlockAltair(blk interfaces.SignedBeaconBlock) (*ethpbv2.SSZContainer, error) {
altairBlk, err := blk.PbAltairBlock()
if err != nil {
return nil, err
}
if altairBlk == nil {
return nil, errNilBlock
}
v2Blk, err := migration.V1Alpha1BeaconBlockAltairToV2(altairBlk.Block)
if err != nil {
return nil, errors.Wrapf(err, "could not get signed beacon block")
}
sig := blk.Signature()
data := &ethpbv2.SignedBeaconBlockAltair{
Message: v2Blk,
Signature: sig[:],
}
sszData, err := data.MarshalSSZ()
if err != nil {
return nil, errors.Wrapf(err, "could not marshal block into SSZ")
}
return &ethpbv2.SSZContainer{Version: ethpbv2.Version_ALTAIR, ExecutionOptimistic: false, Data: sszData}, nil
}
func (bs *Server) getSSZBlockBellatrix(ctx context.Context, blk interfaces.SignedBeaconBlock) (*ethpbv2.SSZContainer, error) {
bellatrixBlk, err := blk.PbBellatrixBlock()
if err != nil {
// ErrUnsupportedGetter means that we have another block type
if errors.Is(err, blocks.ErrUnsupportedGetter) {
if blindedBellatrixBlk, err := blk.PbBlindedBellatrixBlock(); err == nil {
if blindedBellatrixBlk == nil {
return nil, errNilBlock
}
signedFullBlock, err := bs.ExecutionPayloadReconstructor.ReconstructFullBlock(ctx, blk)
if err != nil {
return nil, errors.Wrapf(err, "could not reconstruct full execution payload to create signed beacon block")
}
bellatrixBlk, err = signedFullBlock.PbBellatrixBlock()
if err != nil {
return nil, errors.Wrapf(err, "could not get signed beacon block")
}
v2Blk, err := migration.V1Alpha1BeaconBlockBellatrixToV2(bellatrixBlk.Block)
if err != nil {
return nil, errors.Wrapf(err, "could not convert signed beacon block")
}
root, err := blk.Block().HashTreeRoot()
if err != nil {
return nil, errors.Wrapf(err, "could not get block root")
}
isOptimistic, err := bs.OptimisticModeFetcher.IsOptimisticForRoot(ctx, root)
if err != nil {
return nil, errors.Wrapf(err, "could not check if block is optimistic")
}
sig := blk.Signature()
data := &ethpbv2.SignedBeaconBlockBellatrix{
Message: v2Blk,
Signature: sig[:],
}
sszData, err := data.MarshalSSZ()
if err != nil {
return nil, errors.Wrapf(err, "could not marshal block into SSZ")
}
return &ethpbv2.SSZContainer{
Version: ethpbv2.Version_BELLATRIX,
ExecutionOptimistic: isOptimistic,
Data: sszData,
}, nil
}
return nil, err
}
return nil, err
}
if bellatrixBlk == nil {
return nil, errNilBlock
}
v2Blk, err := migration.V1Alpha1BeaconBlockBellatrixToV2(bellatrixBlk.Block)
if err != nil {
return nil, errors.Wrapf(err, "could not convert signed beacon block")
}
root, err := blk.Block().HashTreeRoot()
if err != nil {
return nil, errors.Wrapf(err, "could not get block root")
}
isOptimistic, err := bs.OptimisticModeFetcher.IsOptimisticForRoot(ctx, root)
if err != nil {
return nil, errors.Wrapf(err, "could not check if block is optimistic")
}
sig := blk.Signature()
data := &ethpbv2.SignedBeaconBlockBellatrix{
Message: v2Blk,
Signature: sig[:],
}
sszData, err := data.MarshalSSZ()
if err != nil {
return nil, errors.Wrapf(err, "could not marshal block into SSZ")
}
return &ethpbv2.SSZContainer{Version: ethpbv2.Version_BELLATRIX, ExecutionOptimistic: isOptimistic, Data: sszData}, nil
}
func (bs *Server) getSSZBlockCapella(ctx context.Context, blk interfaces.SignedBeaconBlock) (*ethpbv2.SSZContainer, error) {
capellaBlk, err := blk.PbCapellaBlock()
if err != nil {
// ErrUnsupportedGetter means that we have another block type
if errors.Is(err, blocks.ErrUnsupportedGetter) {
if blindedCapellaBlk, err := blk.PbBlindedCapellaBlock(); err == nil {
if blindedCapellaBlk == nil {
return nil, errNilBlock
}
signedFullBlock, err := bs.ExecutionPayloadReconstructor.ReconstructFullBlock(ctx, blk)
if err != nil {
return nil, errors.Wrapf(err, "could not reconstruct full execution payload to create signed beacon block")
}
capellaBlk, err = signedFullBlock.PbCapellaBlock()
if err != nil {
return nil, errors.Wrapf(err, "could not get signed beacon block")
}
v2Blk, err := migration.V1Alpha1BeaconBlockCapellaToV2(capellaBlk.Block)
if err != nil {
return nil, errors.Wrapf(err, "could not convert signed beacon block")
}
root, err := blk.Block().HashTreeRoot()
if err != nil {
return nil, errors.Wrapf(err, "could not get block root")
}
isOptimistic, err := bs.OptimisticModeFetcher.IsOptimisticForRoot(ctx, root)
if err != nil {
return nil, errors.Wrapf(err, "could not check if block is optimistic")
}
sig := blk.Signature()
data := &ethpbv2.SignedBeaconBlockCapella{
Message: v2Blk,
Signature: sig[:],
}
sszData, err := data.MarshalSSZ()
if err != nil {
return nil, errors.Wrapf(err, "could not marshal block into SSZ")
}
return &ethpbv2.SSZContainer{
Version: ethpbv2.Version_CAPELLA,
ExecutionOptimistic: isOptimistic,
Data: sszData,
}, nil
}
return nil, err
}
return nil, err
}
if capellaBlk == nil {
return nil, errNilBlock
}
v2Blk, err := migration.V1Alpha1BeaconBlockCapellaToV2(capellaBlk.Block)
if err != nil {
return nil, errors.Wrapf(err, "could not convert signed beacon block")
}
root, err := blk.Block().HashTreeRoot()
if err != nil {
return nil, errors.Wrapf(err, "could not get block root")
}
isOptimistic, err := bs.OptimisticModeFetcher.IsOptimisticForRoot(ctx, root)
if err != nil {
return nil, errors.Wrapf(err, "could not check if block is optimistic")
}
sig := blk.Signature()
data := &ethpbv2.SignedBeaconBlockCapella{
Message: v2Blk,
Signature: sig[:],
}
sszData, err := data.MarshalSSZ()
if err != nil {
return nil, errors.Wrapf(err, "could not marshal block into SSZ")
}
return &ethpbv2.SSZContainer{Version: ethpbv2.Version_CAPELLA, ExecutionOptimistic: isOptimistic, Data: sszData}, nil
}
func (bs *Server) submitPhase0Block(ctx context.Context, phase0Blk *ethpbv1.BeaconBlock, sig []byte) error {
v1alpha1Blk, err := migration.V1ToV1Alpha1SignedBlock(&ethpbv1.SignedBeaconBlock{Block: phase0Blk, Signature: sig})
if err != nil {
@@ -1066,23 +1041,22 @@ func (bs *Server) submitBellatrixBlock(ctx context.Context, bellatrixBlk *ethpbv
return bs.submitBlock(ctx, root, wrappedBellatrixBlk)
}
func (bs *Server) submitBlindedBellatrixBlock(ctx context.Context, blindedBellatrixBlk *ethpbv2.BlindedBeaconBlockBellatrix, sig []byte) error {
b, err := migration.BlindedBellatrixToV1Alpha1SignedBlock(&ethpbv2.SignedBlindedBeaconBlockBellatrix{
Message: blindedBellatrixBlk,
Signature: sig,
})
func (bs *Server) submitCapellaBlock(ctx context.Context, capellaBlk *ethpbv2.BeaconBlockCapella, sig []byte) error {
v1alpha1Blk, err := migration.CapellaToV1Alpha1SignedBlock(&ethpbv2.SignedBeaconBlockCapella{Message: capellaBlk, Signature: sig})
if err != nil {
return status.Errorf(codes.Internal, "Could not get blinded block: %v", err)
return status.Errorf(codes.InvalidArgument, "Could not convert block to v1 block")
}
_, err = bs.V1Alpha1ValidatorServer.ProposeBeaconBlock(ctx, &eth.GenericSignedBeaconBlock{
Block: &eth.GenericSignedBeaconBlock_BlindedBellatrix{
BlindedBellatrix: b,
},
})
wrappedCapellaBlk, err := blocks.NewSignedBeaconBlock(v1alpha1Blk)
if err != nil {
return status.Errorf(codes.Internal, "Could not propose blinded block: %v", err)
return status.Errorf(codes.InvalidArgument, "Could not prepare block")
}
return nil
root, err := capellaBlk.HashTreeRoot()
if err != nil {
return status.Errorf(codes.InvalidArgument, "Could not tree hash block: %v", err)
}
return bs.submitBlock(ctx, root, wrappedCapellaBlk)
}
func (bs *Server) submitBlock(ctx context.Context, blockRoot [fieldparams.RootLength]byte, block interfaces.SignedBeaconBlock) error {

View File

@@ -7,19 +7,15 @@ import (
"testing"
mock "github.com/prysmaticlabs/prysm/v3/beacon-chain/blockchain/testing"
builderTest "github.com/prysmaticlabs/prysm/v3/beacon-chain/builder/testing"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/db"
dbTest "github.com/prysmaticlabs/prysm/v3/beacon-chain/db/testing"
executionTest "github.com/prysmaticlabs/prysm/v3/beacon-chain/execution/testing"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/operations/synccommittee"
mockp2p "github.com/prysmaticlabs/prysm/v3/beacon-chain/p2p/testing"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/rpc/prysm/v1alpha1/validator"
"github.com/prysmaticlabs/prysm/v3/config/params"
"github.com/prysmaticlabs/prysm/v3/consensus-types/blocks"
"github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces"
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/v3/encoding/ssz"
enginev1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
ethpbv1 "github.com/prysmaticlabs/prysm/v3/proto/eth/v1"
ethpbv2 "github.com/prysmaticlabs/prysm/v3/proto/eth/v2"
@@ -158,6 +154,48 @@ func fillDBTestBlocksBellatrix(ctx context.Context, t *testing.T, beaconDB db.Da
return genBlk, blkContainers
}
func fillDBTestBlocksCapella(ctx context.Context, t *testing.T, beaconDB db.Database) (*ethpbalpha.SignedBeaconBlockCapella, []*ethpbalpha.BeaconBlockContainer) {
parentRoot := [32]byte{1, 2, 3}
genBlk := util.NewBeaconBlockCapella()
genBlk.Block.ParentRoot = parentRoot[:]
root, err := genBlk.Block.HashTreeRoot()
require.NoError(t, err)
util.SaveBlock(t, ctx, beaconDB, genBlk)
require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, root))
count := types.Slot(100)
blks := make([]interfaces.SignedBeaconBlock, count)
blkContainers := make([]*ethpbalpha.BeaconBlockContainer, count)
for i := types.Slot(0); i < count; i++ {
b := util.NewBeaconBlockCapella()
b.Block.Slot = i
b.Block.ParentRoot = bytesutil.PadTo([]byte{uint8(i)}, 32)
att1 := util.NewAttestation()
att1.Data.Slot = i
att1.Data.CommitteeIndex = types.CommitteeIndex(i)
att2 := util.NewAttestation()
att2.Data.Slot = i
att2.Data.CommitteeIndex = types.CommitteeIndex(i + 1)
b.Block.Body.Attestations = []*ethpbalpha.Attestation{att1, att2}
root, err := b.Block.HashTreeRoot()
require.NoError(t, err)
signedB, err := blocks.NewSignedBeaconBlock(b)
require.NoError(t, err)
blks[i] = signedB
blkContainers[i] = &ethpbalpha.BeaconBlockContainer{
Block: &ethpbalpha.BeaconBlockContainer_CapellaBlock{CapellaBlock: b}, BlockRoot: root[:]}
}
require.NoError(t, beaconDB.SaveBlocks(ctx, blks))
headRoot := bytesutil.ToBytes32(blkContainers[len(blks)-1].BlockRoot)
summary := &ethpbalpha.StateSummary{
Root: headRoot[:],
Slot: blkContainers[len(blks)-1].Block.(*ethpbalpha.BeaconBlockContainer_CapellaBlock).CapellaBlock.Block.Slot,
}
require.NoError(t, beaconDB.SaveStateSummary(ctx, summary))
require.NoError(t, beaconDB.SaveHeadBlockRoot(ctx, headRoot))
return genBlk, blkContainers
}
func fillDBTestBlocksBellatrixBlinded(ctx context.Context, t *testing.T, beaconDB db.Database) (*ethpbalpha.SignedBlindedBeaconBlockBellatrix, []*ethpbalpha.BeaconBlockContainer) {
parentRoot := [32]byte{1, 2, 3}
genBlk := util.NewBlindedBeaconBlockBellatrix()
@@ -621,6 +659,44 @@ func TestServer_SubmitBlock_OK(t *testing.T) {
_, err = beaconChainServer.SubmitBlock(context.Background(), blockReq)
assert.NoError(t, err, "Could not propose block correctly")
})
t.Run("Capella", func(t *testing.T) {
beaconDB := dbTest.SetupDB(t)
ctx := context.Background()
genesis := util.NewBeaconBlockCapella()
util.SaveBlock(t, context.Background(), beaconDB, genesis)
numDeposits := uint64(64)
beaconState, _ := util.DeterministicGenesisState(t, numDeposits)
bsRoot, err := beaconState.HashTreeRoot(ctx)
require.NoError(t, err)
genesisRoot, err := genesis.Block.HashTreeRoot()
require.NoError(t, err)
require.NoError(t, beaconDB.SaveState(ctx, beaconState, genesisRoot), "Could not save genesis state")
c := &mock.ChainService{Root: bsRoot[:], State: beaconState}
beaconChainServer := &Server{
BeaconDB: beaconDB,
BlockReceiver: c,
ChainInfoFetcher: c,
BlockNotifier: c.BlockNotifier(),
Broadcaster: mockp2p.NewTestP2P(t),
HeadFetcher: c,
}
req := util.NewBeaconBlockCapella()
req.Block.Slot = 5
req.Block.ParentRoot = bsRoot[:]
v2Block, err := migration.V1Alpha1BeaconBlockCapellaToV2(req.Block)
require.NoError(t, err)
util.SaveBlock(t, ctx, beaconDB, req)
blockReq := &ethpbv2.SignedBeaconBlockContainer{
Message: &ethpbv2.SignedBeaconBlockContainer_CapellaBlock{CapellaBlock: v2Block},
Signature: req.Signature,
}
_, err = beaconChainServer.SubmitBlock(context.Background(), blockReq)
assert.NoError(t, err, "Could not propose block correctly")
})
}
func TestServer_SubmitBlockSSZ_OK(t *testing.T) {
@@ -705,13 +781,6 @@ func TestServer_SubmitBlockSSZ_OK(t *testing.T) {
})
t.Run("Bellatrix", func(t *testing.T) {
// INFO: This code block can be removed once Bellatrix
// fork epoch is set to a value other than math.MaxUint64
cfg := params.BeaconConfig()
cfg.BellatrixForkEpoch = cfg.AltairForkEpoch + 1000
cfg.ForkVersionSchedule[bytesutil.ToBytes4(cfg.BellatrixForkVersion)] = cfg.AltairForkEpoch + 1000
params.OverrideBeaconConfig(cfg)
beaconDB := dbTest.SetupDB(t)
ctx := context.Background()
@@ -750,102 +819,21 @@ func TestServer_SubmitBlockSSZ_OK(t *testing.T) {
_, err = beaconChainServer.SubmitBlockSSZ(sszCtx, blockReq)
assert.NoError(t, err, "Could not propose block correctly")
})
}
func TestServer_SubmitBlindedBlockSSZ_OK(t *testing.T) {
t.Run("Phase 0", func(t *testing.T) {
beaconDB := dbTest.SetupDB(t)
ctx := context.Background()
t.Run("Capella", func(t *testing.T) {
t.Skip("This test needs Capella fork version configured properly")
genesis := util.NewBeaconBlock()
util.SaveBlock(t, context.Background(), beaconDB, genesis)
numDeposits := uint64(64)
beaconState, _ := util.DeterministicGenesisState(t, numDeposits)
bsRoot, err := beaconState.HashTreeRoot(ctx)
require.NoError(t, err)
genesisRoot, err := genesis.Block.HashTreeRoot()
require.NoError(t, err)
require.NoError(t, beaconDB.SaveState(ctx, beaconState, genesisRoot), "Could not save genesis state")
c := &mock.ChainService{Root: bsRoot[:], State: beaconState}
beaconChainServer := &Server{
BeaconDB: beaconDB,
BlockReceiver: c,
ChainInfoFetcher: c,
BlockNotifier: c.BlockNotifier(),
Broadcaster: mockp2p.NewTestP2P(t),
HeadFetcher: c,
}
req := util.NewBeaconBlock()
req.Block.Slot = 5
req.Block.ParentRoot = bsRoot[:]
util.SaveBlock(t, ctx, beaconDB, req)
blockSsz, err := req.MarshalSSZ()
require.NoError(t, err)
blockReq := &ethpbv2.SSZContainer{
Data: blockSsz,
}
md := metadata.MD{}
md.Set(versionHeader, "phase0")
sszCtx := metadata.NewIncomingContext(ctx, md)
_, err = beaconChainServer.SubmitBlindedBlockSSZ(sszCtx, blockReq)
assert.NoError(t, err, "Could not propose block correctly")
})
t.Run("Altair", func(t *testing.T) {
beaconDB := dbTest.SetupDB(t)
ctx := context.Background()
genesis := util.NewBeaconBlockAltair()
util.SaveBlock(t, context.Background(), beaconDB, genesis)
numDeposits := uint64(64)
beaconState, _ := util.DeterministicGenesisState(t, numDeposits)
bsRoot, err := beaconState.HashTreeRoot(ctx)
require.NoError(t, err)
genesisRoot, err := genesis.Block.HashTreeRoot()
require.NoError(t, err)
require.NoError(t, beaconDB.SaveState(ctx, beaconState, genesisRoot), "Could not save genesis state")
c := &mock.ChainService{Root: bsRoot[:], State: beaconState}
beaconChainServer := &Server{
BeaconDB: beaconDB,
BlockReceiver: c,
ChainInfoFetcher: c,
BlockNotifier: c.BlockNotifier(),
Broadcaster: mockp2p.NewTestP2P(t),
HeadFetcher: c,
}
req := util.NewBeaconBlockAltair()
req.Block.Slot = params.BeaconConfig().SlotsPerEpoch.Mul(uint64(params.BeaconConfig().AltairForkEpoch))
req.Block.ParentRoot = bsRoot[:]
util.SaveBlock(t, ctx, beaconDB, req)
blockSsz, err := req.MarshalSSZ()
require.NoError(t, err)
blockReq := &ethpbv2.SSZContainer{
Data: blockSsz,
}
md := metadata.MD{}
md.Set(versionHeader, "altair")
sszCtx := metadata.NewIncomingContext(ctx, md)
_, err = beaconChainServer.SubmitBlindedBlockSSZ(sszCtx, blockReq)
assert.NoError(t, err, "Could not propose block correctly")
})
t.Run("Bellatrix", func(t *testing.T) {
// INFO: This code block can be removed once Bellatrix
// INFO: This code block can be removed once Capella
// fork epoch is set to a value other than math.MaxUint64
params.SetupTestConfigCleanup(t)
cfg := params.BeaconConfig()
cfg.BellatrixForkEpoch = cfg.AltairForkEpoch + 1000
cfg.ForkVersionSchedule[bytesutil.ToBytes4(cfg.BellatrixForkVersion)] = cfg.AltairForkEpoch + 1000
cfg.CapellaForkEpoch = cfg.BellatrixForkEpoch + 1000
cfg.ForkVersionSchedule[bytesutil.ToBytes4(cfg.CapellaForkVersion)] = cfg.BellatrixForkEpoch + 1000
params.OverrideBeaconConfig(cfg)
beaconDB := dbTest.SetupDB(t)
ctx := context.Background()
genesis := util.NewBeaconBlockBellatrix()
genesis := util.NewBeaconBlockCapella()
util.SaveBlock(t, context.Background(), beaconDB, genesis)
numDeposits := uint64(64)
@@ -857,24 +845,16 @@ func TestServer_SubmitBlindedBlockSSZ_OK(t *testing.T) {
require.NoError(t, beaconDB.SaveState(ctx, beaconState, genesisRoot), "Could not save genesis state")
c := &mock.ChainService{Root: bsRoot[:], State: beaconState}
alphaServer := &validator.Server{
SyncCommitteePool: synccommittee.NewStore(),
P2P: &mockp2p.MockBroadcaster{},
BlockBuilder: &builderTest.MockBuilderService{},
BlockReceiver: c,
BlockNotifier: &mock.MockBlockNotifier{},
}
beaconChainServer := &Server{
BeaconDB: beaconDB,
BlockReceiver: c,
ChainInfoFetcher: c,
BlockNotifier: c.BlockNotifier(),
Broadcaster: mockp2p.NewTestP2P(t),
HeadFetcher: c,
V1Alpha1ValidatorServer: alphaServer,
BeaconDB: beaconDB,
BlockReceiver: c,
ChainInfoFetcher: c,
BlockNotifier: c.BlockNotifier(),
Broadcaster: mockp2p.NewTestP2P(t),
HeadFetcher: c,
}
req := util.NewBlindedBeaconBlockBellatrix()
req.Block.Slot = params.BeaconConfig().SlotsPerEpoch.Mul(uint64(params.BeaconConfig().BellatrixForkEpoch))
req := util.NewBeaconBlockCapella()
req.Block.Slot = params.BeaconConfig().SlotsPerEpoch.Mul(uint64(params.BeaconConfig().CapellaForkEpoch))
req.Block.ParentRoot = bsRoot[:]
util.SaveBlock(t, ctx, beaconDB, req)
blockSsz, err := req.MarshalSSZ()
@@ -883,143 +863,13 @@ func TestServer_SubmitBlindedBlockSSZ_OK(t *testing.T) {
Data: blockSsz,
}
md := metadata.MD{}
md.Set(versionHeader, "bellatrix")
md.Set(versionHeader, "capella")
sszCtx := metadata.NewIncomingContext(ctx, md)
_, err = beaconChainServer.SubmitBlindedBlockSSZ(sszCtx, blockReq)
_, err = beaconChainServer.SubmitBlockSSZ(sszCtx, blockReq)
assert.NoError(t, err, "Could not propose block correctly")
})
}
func TestSubmitBlindedBlock(t *testing.T) {
t.Run("Phase 0", func(t *testing.T) {
beaconDB := dbTest.SetupDB(t)
ctx := context.Background()
genesis := util.NewBeaconBlock()
util.SaveBlock(t, context.Background(), beaconDB, genesis)
numDeposits := uint64(64)
beaconState, _ := util.DeterministicGenesisState(t, numDeposits)
bsRoot, err := beaconState.HashTreeRoot(ctx)
require.NoError(t, err)
genesisRoot, err := genesis.Block.HashTreeRoot()
require.NoError(t, err)
require.NoError(t, beaconDB.SaveState(ctx, beaconState, genesisRoot), "Could not save genesis state")
c := &mock.ChainService{Root: bsRoot[:], State: beaconState}
beaconChainServer := &Server{
BeaconDB: beaconDB,
BlockReceiver: c,
ChainInfoFetcher: c,
BlockNotifier: c.BlockNotifier(),
Broadcaster: mockp2p.NewTestP2P(t),
}
req := util.NewBeaconBlock()
req.Block.Slot = 5
req.Block.ParentRoot = bsRoot[:]
v1Block, err := migration.V1Alpha1ToV1SignedBlock(req)
require.NoError(t, err)
util.SaveBlock(t, ctx, beaconDB, req)
blockReq := &ethpbv2.SignedBlindedBeaconBlockContainer{
Message: &ethpbv2.SignedBlindedBeaconBlockContainer_Phase0Block{Phase0Block: v1Block.Block},
Signature: v1Block.Signature,
}
_, err = beaconChainServer.SubmitBlindedBlock(context.Background(), blockReq)
assert.NoError(t, err, "Could not propose block correctly")
})
t.Run("Altair", func(t *testing.T) {
beaconDB := dbTest.SetupDB(t)
ctx := context.Background()
genesis := util.NewBeaconBlockAltair()
util.SaveBlock(t, context.Background(), beaconDB, genesis)
numDeposits := uint64(64)
beaconState, _ := util.DeterministicGenesisState(t, numDeposits)
bsRoot, err := beaconState.HashTreeRoot(ctx)
require.NoError(t, err)
genesisRoot, err := genesis.Block.HashTreeRoot()
require.NoError(t, err)
require.NoError(t, beaconDB.SaveState(ctx, beaconState, genesisRoot), "Could not save genesis state")
c := &mock.ChainService{Root: bsRoot[:], State: beaconState}
beaconChainServer := &Server{
BeaconDB: beaconDB,
BlockReceiver: c,
ChainInfoFetcher: c,
BlockNotifier: c.BlockNotifier(),
Broadcaster: mockp2p.NewTestP2P(t),
}
req := util.NewBeaconBlockAltair()
req.Block.Slot = 5
req.Block.ParentRoot = bsRoot[:]
v2Block, err := migration.V1Alpha1BeaconBlockAltairToV2(req.Block)
require.NoError(t, err)
util.SaveBlock(t, ctx, beaconDB, req)
blockReq := &ethpbv2.SignedBlindedBeaconBlockContainer{
Message: &ethpbv2.SignedBlindedBeaconBlockContainer_AltairBlock{AltairBlock: v2Block},
Signature: req.Signature,
}
_, err = beaconChainServer.SubmitBlindedBlock(context.Background(), blockReq)
assert.NoError(t, err, "Could not propose block correctly")
})
t.Run("Bellatrix - OK", func(t *testing.T) {
transactions := [][]byte{[]byte("transaction1"), []byte("transaction2")}
transactionsRoot, err := ssz.TransactionsRoot(transactions)
require.NoError(t, err)
beaconDB := dbTest.SetupDB(t)
ctx := context.Background()
genesis := util.NewBeaconBlockBellatrix()
util.SaveBlock(t, context.Background(), beaconDB, genesis)
numDeposits := uint64(64)
beaconState, _ := util.DeterministicGenesisState(t, numDeposits)
bsRoot, err := beaconState.HashTreeRoot(ctx)
require.NoError(t, err)
genesisRoot, err := genesis.Block.HashTreeRoot()
require.NoError(t, err)
require.NoError(t, beaconDB.SaveState(ctx, beaconState, genesisRoot), "Could not save genesis state")
c := &mock.ChainService{Root: bsRoot[:], State: beaconState}
alphaServer := &validator.Server{
SyncCommitteePool: synccommittee.NewStore(),
P2P: &mockp2p.MockBroadcaster{},
BlockBuilder: &builderTest.MockBuilderService{},
BlockReceiver: c,
BlockNotifier: &mock.MockBlockNotifier{},
}
beaconChainServer := &Server{
BeaconDB: beaconDB,
BlockReceiver: c,
ChainInfoFetcher: c,
BlockNotifier: c.BlockNotifier(),
Broadcaster: mockp2p.NewTestP2P(t),
V1Alpha1ValidatorServer: alphaServer,
}
blk := util.NewBeaconBlockBellatrix()
blk.Block.Slot = 5
blk.Block.ParentRoot = bsRoot[:]
blk.Block.Body.ExecutionPayload.Transactions = transactions
blindedBlk := util.NewBlindedBeaconBlockBellatrixV2()
blindedBlk.Message.Slot = 5
blindedBlk.Message.ParentRoot = bsRoot[:]
blindedBlk.Message.Body.ExecutionPayloadHeader.TransactionsRoot = transactionsRoot[:]
util.SaveBlock(t, ctx, beaconDB, blk)
blockReq := &ethpbv2.SignedBlindedBeaconBlockContainer{
Message: &ethpbv2.SignedBlindedBeaconBlockContainer_BellatrixBlock{BellatrixBlock: blindedBlk.Message},
Signature: blindedBlk.Signature,
}
_, err = beaconChainServer.SubmitBlindedBlock(context.Background(), blockReq)
assert.NoError(t, err)
})
}
func TestServer_GetBlock(t *testing.T) {
beaconDB := dbTest.SetupDB(t)
ctx := context.Background()
@@ -1544,6 +1394,140 @@ func TestServer_GetBlockV2(t *testing.T) {
}
})
t.Run("Capella", func(t *testing.T) {
beaconDB := dbTest.SetupDB(t)
ctx := context.Background()
genBlk, blkContainers := fillDBTestBlocksCapella(ctx, t, beaconDB)
canonicalRoots := make(map[[32]byte]bool)
for _, bContr := range blkContainers {
canonicalRoots[bytesutil.ToBytes32(bContr.BlockRoot)] = true
}
headBlock := blkContainers[len(blkContainers)-1]
nextSlot := headBlock.GetCapellaBlock().Block.Slot + 1
b2 := util.NewBeaconBlockCapella()
b2.Block.Slot = 30
b2.Block.ParentRoot = bytesutil.PadTo([]byte{1}, 32)
util.SaveBlock(t, ctx, beaconDB, b2)
b3 := util.NewBeaconBlockCapella()
b3.Block.Slot = 30
b3.Block.ParentRoot = bytesutil.PadTo([]byte{4}, 32)
util.SaveBlock(t, ctx, beaconDB, b3)
b4 := util.NewBeaconBlockCapella()
b4.Block.Slot = nextSlot
b4.Block.ParentRoot = bytesutil.PadTo([]byte{8}, 32)
util.SaveBlock(t, ctx, beaconDB, b4)
chainBlk, err := blocks.NewSignedBeaconBlock(headBlock.GetCapellaBlock())
require.NoError(t, err)
mockChainService := &mock.ChainService{
DB: beaconDB,
Block: chainBlk,
Root: headBlock.BlockRoot,
FinalizedCheckPoint: &ethpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot},
CanonicalRoots: canonicalRoots,
}
bs := &Server{
BeaconDB: beaconDB,
ChainInfoFetcher: mockChainService,
HeadFetcher: mockChainService,
OptimisticModeFetcher: mockChainService,
ExecutionPayloadReconstructor: &executionTest.EngineClient{
ExecutionPayloadByBlockHash: map[[32]byte]*enginev1.ExecutionPayload{},
},
}
root, err := genBlk.Block.HashTreeRoot()
require.NoError(t, err)
tests := []struct {
name string
blockID []byte
want *ethpbalpha.SignedBeaconBlockCapella
wantErr bool
}{
{
name: "slot",
blockID: []byte("30"),
want: blkContainers[30].GetCapellaBlock(),
},
{
name: "bad formatting",
blockID: []byte("3bad0"),
wantErr: true,
},
{
name: "canonical",
blockID: []byte("30"),
want: blkContainers[30].GetCapellaBlock(),
},
{
name: "non canonical",
blockID: []byte(fmt.Sprintf("%d", nextSlot)),
wantErr: true,
},
{
name: "head",
blockID: []byte("head"),
want: headBlock.GetCapellaBlock(),
},
{
name: "finalized",
blockID: []byte("finalized"),
want: blkContainers[64].GetCapellaBlock(),
},
{
name: "genesis",
blockID: []byte("genesis"),
want: genBlk,
},
{
name: "genesis root",
blockID: root[:],
want: genBlk,
},
{
name: "root",
blockID: blkContainers[20].BlockRoot,
want: blkContainers[20].GetCapellaBlock(),
},
{
name: "non-existent root",
blockID: bytesutil.PadTo([]byte("hi there"), 32),
wantErr: true,
},
{
name: "no block",
blockID: []byte("105"),
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
blk, err := bs.GetBlockV2(ctx, &ethpbv2.BlockRequestV2{
BlockId: tt.blockID,
})
if tt.wantErr {
require.NotEqual(t, err, nil)
return
}
require.NoError(t, err)
v2Block, err := migration.V1Alpha1BeaconBlockCapellaToV2(tt.want.Block)
require.NoError(t, err)
b, ok := blk.Data.Message.(*ethpbv2.SignedBeaconBlockContainer_CapellaBlock)
require.Equal(t, true, ok)
if !reflect.DeepEqual(b.CapellaBlock, v2Block) {
t.Error("Expected blocks to equal")
}
assert.Equal(t, ethpbv2.Version_CAPELLA, blk.Version)
})
}
})
t.Run("execution optimistic", func(t *testing.T) {
beaconDB := dbTest.SetupDB(t)
ctx := context.Background()
@@ -1734,97 +1718,20 @@ func TestServer_GetBlockSSZV2(t *testing.T) {
assert.DeepEqual(t, sszBlock, resp.Data)
assert.Equal(t, ethpbv2.Version_BELLATRIX, resp.Version)
})
}
func TestServer_GetBlindedBlockSSZ(t *testing.T) {
t.Run("Phase 0", func(t *testing.T) {
t.Run("Capella", func(t *testing.T) {
beaconDB := dbTest.SetupDB(t)
ctx := context.Background()
_, blkContainers := fillDBTestBlocks(ctx, t, beaconDB)
_, blkContainers := fillDBTestBlocksCapella(ctx, t, beaconDB)
headBlock := blkContainers[len(blkContainers)-1]
b2 := util.NewBeaconBlock()
b2 := util.NewBeaconBlockCapella()
b2.Block.Slot = 30
b2.Block.ParentRoot = bytesutil.PadTo([]byte{1}, 32)
util.SaveBlock(t, ctx, beaconDB, b2)
wsb, err := blocks.NewSignedBeaconBlock(headBlock.Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block)
require.NoError(t, err)
bs := &Server{
BeaconDB: beaconDB,
ChainInfoFetcher: &mock.ChainService{
DB: beaconDB,
Block: wsb,
Root: headBlock.BlockRoot,
FinalizedCheckPoint: &ethpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot},
},
}
blks, err := beaconDB.BlocksBySlot(ctx, 30)
require.Equal(t, true, len(blks) > 0)
require.NoError(t, err)
sszBlock, err := blks[0].MarshalSSZ()
require.NoError(t, err)
resp, err := bs.GetBlindedBlockSSZ(ctx, &ethpbv1.BlockRequest{BlockId: []byte("30")})
require.NoError(t, err)
assert.NotNil(t, resp)
assert.DeepEqual(t, sszBlock, resp.Data)
assert.Equal(t, ethpbv2.Version_PHASE0, resp.Version)
})
t.Run("Altair", func(t *testing.T) {
beaconDB := dbTest.SetupDB(t)
ctx := context.Background()
_, blkContainers := fillDBTestBlocksAltair(ctx, t, beaconDB)
headBlock := blkContainers[len(blkContainers)-1]
b2 := util.NewBeaconBlockAltair()
b2.Block.Slot = 30
b2.Block.ParentRoot = bytesutil.PadTo([]byte{1}, 32)
util.SaveBlock(t, ctx, beaconDB, b2)
chainBlk, err := blocks.NewSignedBeaconBlock(headBlock.GetAltairBlock())
require.NoError(t, err)
bs := &Server{
BeaconDB: beaconDB,
ChainInfoFetcher: &mock.ChainService{
DB: beaconDB,
Block: chainBlk,
Root: headBlock.BlockRoot,
FinalizedCheckPoint: &ethpbalpha.Checkpoint{Root: blkContainers[64].BlockRoot},
},
}
blks, err := beaconDB.BlocksBySlot(ctx, 30)
require.Equal(t, true, len(blks) > 0)
require.NoError(t, err)
sszBlock, err := blks[0].MarshalSSZ()
require.NoError(t, err)
resp, err := bs.GetBlindedBlockSSZ(ctx, &ethpbv1.BlockRequest{BlockId: []byte("30")})
require.NoError(t, err)
assert.NotNil(t, resp)
assert.DeepEqual(t, sszBlock, resp.Data)
assert.Equal(t, ethpbv2.Version_ALTAIR, resp.Version)
})
t.Run("Bellatrix", func(t *testing.T) {
beaconDB := dbTest.SetupDB(t)
ctx := context.Background()
_, blkContainers := fillDBTestBlocksBellatrixBlinded(ctx, t, beaconDB)
headBlock := blkContainers[len(blkContainers)-1]
b2 := util.NewBlindedBeaconBlockBellatrix()
b2.Block.Slot = 30
b2.Block.ParentRoot = bytesutil.PadTo([]byte{1}, 32)
util.SaveBlock(t, ctx, beaconDB, b2)
chainBlk, err := blocks.NewSignedBeaconBlock(headBlock.GetBlindedBellatrixBlock())
chainBlk, err := blocks.NewSignedBeaconBlock(headBlock.GetCapellaBlock())
require.NoError(t, err)
bs := &Server{
BeaconDB: beaconDB,
@@ -1843,11 +1750,11 @@ func TestServer_GetBlindedBlockSSZ(t *testing.T) {
sszBlock, err := blks[0].MarshalSSZ()
require.NoError(t, err)
resp, err := bs.GetBlindedBlockSSZ(ctx, &ethpbv1.BlockRequest{BlockId: []byte("30")})
resp, err := bs.GetBlockSSZV2(ctx, &ethpbv2.BlockRequestV2{BlockId: []byte("30")})
require.NoError(t, err)
assert.NotNil(t, resp)
assert.DeepEqual(t, sszBlock, resp.Data)
assert.Equal(t, ethpbv2.Version_BELLATRIX, resp.Version)
assert.Equal(t, ethpbv2.Version_CAPELLA, resp.Version)
})
}

View File

@@ -13,6 +13,7 @@ import (
"github.com/prysmaticlabs/prysm/v3/config/features"
"github.com/prysmaticlabs/prysm/v3/crypto/bls"
ethpbv1 "github.com/prysmaticlabs/prysm/v3/proto/eth/v1"
ethpbv2 "github.com/prysmaticlabs/prysm/v3/proto/eth/v2"
"github.com/prysmaticlabs/prysm/v3/proto/migration"
ethpbalpha "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v3/time/slots"
@@ -304,3 +305,28 @@ func (bs *Server) SubmitVoluntaryExit(ctx context.Context, req *ethpbv1.SignedVo
return &emptypb.Empty{}, nil
}
// SubmitSignedBLSToExecutionChange submits said object to the node's pool
// if it passes validation the node must broadcast it to the network.
func (bs *Server) SubmitSignedBLSToExecutionChange(ctx context.Context, req *ethpbv2.SignedBLSToExecutionChange) (*emptypb.Empty, error) {
ctx, span := trace.StartSpan(ctx, "beacon.SubmitVoluntaryExit")
defer span.End()
alphaChange := migration.V2SignedBLSToExecutionChangeToV1Alpha1(req)
st, err := bs.ChainInfoFetcher.HeadState(ctx)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not get head state: %v", err)
}
_, err = blocks.ValidateBLSToExecutionChange(st, alphaChange)
if err != nil {
return nil, status.Errorf(codes.InvalidArgument, "Could not validate SignedBLSToExecutionChange: %v", err)
}
if err := blocks.VerifyBLSChangeSignature(st, req); err != nil {
return nil, status.Errorf(codes.InvalidArgument, "Could not validate signature: %v", err)
}
bs.BLSChangesPool.InsertBLSToExecChange(alphaChange)
if err := bs.Broadcaster.Broadcast(ctx, alphaChange); err != nil {
return nil, status.Errorf(codes.Internal, "Could not broadcast BLSToExecutionChange: %v", err)
}
return &emptypb.Empty{}, nil
}

View File

@@ -10,6 +10,7 @@ import (
"github.com/prysmaticlabs/prysm/v3/beacon-chain/db"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/execution"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/operations/attestations"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/operations/blstoexec"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/operations/slashings"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/operations/voluntaryexits"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/p2p"
@@ -41,4 +42,5 @@ type Server struct {
CanonicalHistory *stategen.CanonicalHistory
HeadUpdater blockchain.HeadUpdater
ExecutionPayloadReconstructor execution.ExecutionPayloadReconstructor
BLSChangesPool blstoexec.PoolManager
}

View File

@@ -16,6 +16,7 @@ go_library(
"//beacon-chain/core/transition:go_default_library",
"//beacon-chain/db/kv:go_default_library",
"//beacon-chain/operations/attestations:go_default_library",
"//beacon-chain/operations/blstoexec:go_default_library",
"//beacon-chain/operations/synccommittee:go_default_library",
"//beacon-chain/p2p:go_default_library",
"//beacon-chain/rpc/eth/helpers:go_default_library",

View File

@@ -4,6 +4,7 @@ import (
"github.com/prysmaticlabs/prysm/v3/beacon-chain/blockchain"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/cache"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/operations/attestations"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/operations/blstoexec"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/operations/synccommittee"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/p2p"
v1alpha1validator "github.com/prysmaticlabs/prysm/v3/beacon-chain/rpc/prysm/v1alpha1/validator"
@@ -24,6 +25,7 @@ type Server struct {
StateFetcher statefetcher.Fetcher
OptimisticModeFetcher blockchain.OptimisticModeFetcher
SyncCommitteePool synccommittee.Pool
BLSChangesPool blstoexec.PoolManager
V1Alpha1Server *v1alpha1validator.Server
ProposerSlotIndexCache *cache.ProposerPayloadIDsCache
}

View File

@@ -488,16 +488,9 @@ func (vs *Server) ProduceBlindedBlock(ctx context.Context, req *ethpbv1.ProduceB
if optimistic {
return nil, status.Errorf(codes.Unavailable, "The node is currently optimistic and cannot serve validators")
}
altairBlk, err := vs.V1Alpha1Server.BuildAltairBeaconBlock(ctx, v1alpha1req)
b, err := vs.V1Alpha1Server.GetBeaconBlock(ctx, v1alpha1req)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not prepare beacon block: %v", err)
}
ok, b, err := vs.V1Alpha1Server.GetAndBuildBlindBlock(ctx, altairBlk)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not prepare blind beacon block: %v", err)
}
if !ok {
return nil, status.Error(codes.Unavailable, "Builder is not available due to miss-config or circuit breaker")
return nil, err
}
blk, err := migration.V1Alpha1BeaconBlockBlindedBellatrixToV2Blinded(b.GetBlindedBellatrix())
if err != nil {

View File

@@ -943,7 +943,7 @@ func TestProduceBlockV2(t *testing.T) {
v1Alpha1Server := &v1alpha1validator.Server{
ExecutionEngineCaller: &mockExecution.EngineClient{
ExecutionBlock: &enginev1.ExecutionBlock{
ExecutionBlock: &enginev1.ExecutionBlockBellatrix{
TotalDifficulty: "0x1",
},
},
@@ -1438,7 +1438,7 @@ func TestProduceBlockV2SSZ(t *testing.T) {
v1Alpha1Server := &v1alpha1validator.Server{
ExecutionEngineCaller: &mockExecution.EngineClient{
ExecutionBlock: &enginev1.ExecutionBlock{
ExecutionBlock: &enginev1.ExecutionBlockBellatrix{
TotalDifficulty: "0x1",
},
},
@@ -2460,7 +2460,7 @@ func TestProduceBlindedBlockSSZ(t *testing.T) {
v1Alpha1Server := &v1alpha1validator.Server{
ExecutionEngineCaller: &mockExecution.EngineClient{
ExecutionBlock: &enginev1.ExecutionBlock{
ExecutionBlock: &enginev1.ExecutionBlockBellatrix{
TotalDifficulty: "0x1",
},
},

View File

@@ -6,6 +6,7 @@ go_library(
"assignments.go",
"attestations.go",
"blocks.go",
"blstoexec.go",
"committees.go",
"config.go",
"log.go",
@@ -36,6 +37,7 @@ go_library(
"//beacon-chain/db/filters:go_default_library",
"//beacon-chain/execution:go_default_library",
"//beacon-chain/operations/attestations:go_default_library",
"//beacon-chain/operations/blstoexec:go_default_library",
"//beacon-chain/operations/slashings:go_default_library",
"//beacon-chain/p2p:go_default_library",
"//beacon-chain/state:go_default_library",

View File

@@ -122,6 +122,20 @@ func convertToBlockContainer(blk interfaces.SignedBeaconBlock, root [32]byte, is
}
ctr.Block = &ethpb.BeaconBlockContainer_BellatrixBlock{BellatrixBlock: rBlk}
}
case version.Capella:
if blk.IsBlinded() {
rBlk, err := blk.PbBlindedCapellaBlock()
if err != nil {
return nil, err
}
ctr.Block = &ethpb.BeaconBlockContainer_BlindedCapellaBlock{BlindedCapellaBlock: rBlk}
} else {
rBlk, err := blk.PbCapellaBlock()
if err != nil {
return nil, err
}
ctr.Block = &ethpb.BeaconBlockContainer_CapellaBlock{CapellaBlock: rBlk}
}
default:
return nil, errors.Errorf("block type is not recognized: %d", blk.Version())
}

View File

@@ -0,0 +1,24 @@
package beacon
import (
"context"
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
// SubmitBLSToExecutionChange receives a withdrawal credential change object via
// RPC and injects it into the beacon node's operations pool.
// Submission into this pool does not guarantee inclusion into a beacon block. If the object passes validation
// the node MUST broadcast it
func (bs *Server) SubmitBLSToExecutionChange(
ctx context.Context,
req *ethpb.SignedBLSToExecutionChange,
) (*ethpb.BLSToExecutionChangeResponse, error) {
bs.BLSChangesPool.InsertBLSToExecChange(req)
if err := bs.Broadcaster.Broadcast(ctx, req); err != nil {
return nil, status.Errorf(codes.Internal, "Could not broadcast SigledBLSToExecutionChange object: %v", err)
}
return nil, nil
}

View File

@@ -15,6 +15,7 @@ import (
"github.com/prysmaticlabs/prysm/v3/beacon-chain/db"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/execution"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/operations/attestations"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/operations/blstoexec"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/operations/slashings"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/p2p"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state/stategen"
@@ -40,6 +41,7 @@ type Server struct {
Broadcaster p2p.Broadcaster
AttestationsPool attestations.Pool
SlashingsPool slashings.PoolManager
BLSChangesPool blstoexec.PoolManager
ChainStartChan chan time.Time
ReceivedAttestationsBuffer chan *ethpb.Attestation
CollectedAttestationsBuffer chan []*ethpb.Attestation

View File

@@ -16,7 +16,6 @@ go_library(
"proposer_deposits.go",
"proposer_eth1data.go",
"proposer_execution_payload.go",
"proposer_phase0.go",
"proposer_sync_aggregate.go",
"server.go",
"status.go",
@@ -47,6 +46,7 @@ go_library(
"//beacon-chain/execution:go_default_library",
"//beacon-chain/operations/attestations:go_default_library",
"//beacon-chain/operations/slashings:go_default_library",
"//beacon-chain/operations/blstoexec:go_default_library",
"//beacon-chain/operations/synccommittee:go_default_library",
"//beacon-chain/operations/voluntaryexits:go_default_library",
"//beacon-chain/p2p:go_default_library",
@@ -58,6 +58,7 @@ go_library(
"//config/params:go_default_library",
"//consensus-types/blocks:go_default_library",
"//consensus-types/interfaces:go_default_library",
"//consensus-types/payload-attribute:go_default_library",
"//consensus-types/primitives:go_default_library",
"//container/trie:go_default_library",
"//contracts/deposit:go_default_library",

View File

@@ -89,6 +89,17 @@ func sendVerifiedBlocks(stream ethpb.BeaconNodeValidator_StreamBlocksAltairServe
return nil
}
b.Block = &ethpb.StreamBlocksResponse_BellatrixBlock{BellatrixBlock: phBlk}
case version.Capella:
pb, err := data.SignedBlock.Proto()
if err != nil {
return errors.Wrap(err, "could not get protobuf block")
}
phBlk, ok := pb.(*ethpb.SignedBeaconBlockCapella)
if !ok {
log.Warn("Mismatch between version and block type, was expecting SignedBeaconBlockCapella")
return nil
}
b.Block = &ethpb.StreamBlocksResponse_CapellaBlock{CapellaBlock: phBlk}
}
if err := stream.Send(b); err != nil {
@@ -136,6 +147,8 @@ func (vs *Server) sendBlocks(stream ethpb.BeaconNodeValidator_StreamBlocksAltair
b.Block = &ethpb.StreamBlocksResponse_AltairBlock{AltairBlock: p}
case *ethpb.SignedBeaconBlockBellatrix:
b.Block = &ethpb.StreamBlocksResponse_BellatrixBlock{BellatrixBlock: p}
case *ethpb.SignedBeaconBlockCapella:
b.Block = &ethpb.StreamBlocksResponse_CapellaBlock{CapellaBlock: p}
default:
log.Errorf("Unknown block type %T", p)
}

View File

@@ -12,10 +12,15 @@ import (
emptypb "github.com/golang/protobuf/ptypes/empty"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/builder"
blocks2 "github.com/prysmaticlabs/prysm/v3/beacon-chain/core/blocks"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/feed"
blockfeed "github.com/prysmaticlabs/prysm/v3/beacon-chain/core/feed/block"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/transition"
v "github.com/prysmaticlabs/prysm/v3/beacon-chain/core/validators"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/db/kv"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state"
fieldparams "github.com/prysmaticlabs/prysm/v3/config/fieldparams"
"github.com/prysmaticlabs/prysm/v3/config/params"
"github.com/prysmaticlabs/prysm/v3/consensus-types/blocks"
"github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces"
@@ -35,32 +40,247 @@ var eth1DataNotification bool
const eth1dataTimeout = 2 * time.Second
// GetBeaconBlock is called by a proposer during its assigned slot to request a block to sign
// by passing in the slot and the signed randao reveal of the slot. Returns phase0 beacon blocks
// before the Altair fork epoch and Altair blocks post-fork epoch.
// by passing in the slot and the signed randao reveal of the slot. Returns a full block
// corresponding to the fork epoch
func (vs *Server) GetBeaconBlock(ctx context.Context, req *ethpb.BlockRequest) (*ethpb.GenericBeaconBlock, error) {
ctx, span := trace.StartSpan(ctx, "ProposerServer.GetBeaconBlock")
defer span.End()
span.AddAttributes(trace.Int64Attribute("slot", int64(req.Slot)))
if slots.ToEpoch(req.Slot) < params.BeaconConfig().AltairForkEpoch {
blk, err := vs.getPhase0BeaconBlock(ctx, req)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not fetch phase0 beacon block: %v", err)
}
return &ethpb.GenericBeaconBlock{Block: &ethpb.GenericBeaconBlock_Phase0{Phase0: blk}}, nil
} else if slots.ToEpoch(req.Slot) < params.BeaconConfig().BellatrixForkEpoch {
blk, err := vs.getAltairBeaconBlock(ctx, req)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not fetch Altair beacon block: %v", err)
}
return &ethpb.GenericBeaconBlock{Block: &ethpb.GenericBeaconBlock_Altair{Altair: blk}}, nil
// A syncing validator should not produce a block.
if vs.SyncChecker.Syncing() {
return nil, status.Error(codes.Unavailable, "Syncing to latest head, not ready to respond")
}
// An optimistic validator MUST NOT produce a block (i.e., sign across the DOMAIN_BEACON_PROPOSER domain).
if err := vs.optimisticStatus(ctx); err != nil {
return nil, err
return nil, status.Errorf(codes.Unavailable, "Validator is not ready to propose: %v", err)
}
return vs.getBellatrixBeaconBlock(ctx, req)
blk, sBlk, err := emptyBlockToSign(req.Slot)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not prepare block: %v", err)
}
parentRoot, err := vs.HeadFetcher.HeadRoot(ctx)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not get head root: %v", err)
}
head, err := vs.HeadFetcher.HeadState(ctx)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not get head state: %v", err)
}
head, err = transition.ProcessSlotsUsingNextSlotCache(ctx, head, parentRoot, req.Slot)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not process slots up to %d: %v", req.Slot, err)
}
// Set slot, graffiti, randao reveal, and parent root.
blk.SetSlot(req.Slot)
blk.Body().SetGraffiti(req.Graffiti)
blk.Body().SetRandaoReveal(req.RandaoReveal)
blk.SetParentRoot(parentRoot)
// Set eth1 data.
eth1Data, err := vs.eth1DataMajorityVote(ctx, head)
if err != nil {
log.WithError(err).Error("Could not get eth1data")
} else {
blk.Body().SetEth1Data(eth1Data)
// Set deposit and attestation.
deposits, atts, err := vs.packDepositsAndAttestations(ctx, head, eth1Data) // TODO: split attestations and deposits
if err != nil {
log.WithError(err).Error("Could not pack deposits and attestations")
} else {
blk.Body().SetDeposits(deposits)
blk.Body().SetAttestations(atts)
}
}
// Set proposer index
idx, err := helpers.BeaconProposerIndex(ctx, head)
if err != nil {
return nil, fmt.Errorf("could not calculate proposer index %v", err)
}
blk.SetProposerIndex(idx)
// Set slashings
validProposerSlashings, validAttSlashings := vs.getSlashings(ctx, head)
blk.Body().SetProposerSlashings(validProposerSlashings)
blk.Body().SetAttesterSlashings(validAttSlashings)
// Set exits
blk.Body().SetVoluntaryExits(vs.getExits(head, req))
// Set sync aggregate. New in Altair.
if req.Slot > 0 && slots.ToEpoch(req.Slot) >= params.BeaconConfig().AltairForkEpoch {
syncAggregate, err := vs.getSyncAggregate(ctx, req.Slot-1, bytesutil.ToBytes32(parentRoot))
if err != nil {
log.WithError(err).Error("Could not get sync aggregate")
} else {
if err := blk.Body().SetSyncAggregate(syncAggregate); err != nil {
log.WithError(err).Error("Could not set sync aggregate")
if err := blk.Body().SetSyncAggregate(&ethpb.SyncAggregate{
SyncCommitteeBits: make([]byte, params.BeaconConfig().SyncCommitteeSize),
SyncCommitteeSignature: make([]byte, fieldparams.BLSSignatureLength),
}); err != nil {
return nil, status.Errorf(codes.Internal, "Could not set default sync aggregate: %v", err)
}
}
}
}
// Set execution data. New in Bellatrix
if slots.ToEpoch(req.Slot) >= params.BeaconConfig().BellatrixForkEpoch {
fallBackToLocal := true
canUseBuilder, err := vs.canUseBuilder(ctx, req.Slot, idx)
if err != nil {
log.WithError(err).Warn("Proposer: failed to check if builder can be used")
} else if canUseBuilder {
h, err := vs.getPayloadHeaderFromBuilder(ctx, req.Slot, idx)
if err != nil {
log.WithError(err).Warn("Proposer: failed to get payload header from builder")
} else {
blk.SetBlinded(true)
if err := blk.Body().SetExecution(h); err != nil {
log.WithError(err).Warn("Proposer: failed to set execution payload")
} else {
fallBackToLocal = false
}
}
}
if fallBackToLocal {
executionData, err := vs.getExecutionPayload(ctx, req.Slot, idx, bytesutil.ToBytes32(parentRoot), head)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not get execution payload: %v", err)
}
if err := blk.Body().SetExecution(executionData); err != nil {
return nil, status.Errorf(codes.Internal, "Could not set execution payload: %v", err)
}
}
}
// Set bls to execution change. New in Capella
if slots.ToEpoch(req.Slot) >= params.BeaconConfig().CapellaForkEpoch {
changes, err := vs.BLSChangesPool.BLSToExecChangesForInclusion(head)
if err != nil {
log.WithError(err).Error("Could not get bls to execution changes")
} else {
if err := blk.Body().SetBLSToExecutionChanges(changes); err != nil {
log.WithError(err).Error("Could not set bls to execution changes")
}
}
}
if err := sBlk.SetBlock(blk); err != nil {
return nil, status.Errorf(codes.Internal, "Could not set block: %v", err)
}
sr, err := vs.computeStateRoot(ctx, sBlk)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not compute state root: %v", err)
}
blk.SetStateRoot(sr)
pb, err := blk.Proto()
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not convert block to proto: %v", err)
}
if slots.ToEpoch(req.Slot) >= params.BeaconConfig().CapellaForkEpoch {
return &ethpb.GenericBeaconBlock{Block: &ethpb.GenericBeaconBlock_Capella{Capella: pb.(*ethpb.BeaconBlockCapella)}}, nil
} else if slots.ToEpoch(req.Slot) >= params.BeaconConfig().BellatrixForkEpoch {
return &ethpb.GenericBeaconBlock{Block: &ethpb.GenericBeaconBlock_Bellatrix{Bellatrix: pb.(*ethpb.BeaconBlockBellatrix)}}, nil
} else if slots.ToEpoch(req.Slot) >= params.BeaconConfig().AltairForkEpoch {
return &ethpb.GenericBeaconBlock{Block: &ethpb.GenericBeaconBlock_Altair{Altair: pb.(*ethpb.BeaconBlockAltair)}}, nil
}
return &ethpb.GenericBeaconBlock{Block: &ethpb.GenericBeaconBlock_Phase0{Phase0: pb.(*ethpb.BeaconBlock)}}, nil
}
func (vs *Server) getExits(head state.BeaconState, req *ethpb.BlockRequest) []*ethpb.SignedVoluntaryExit {
exits := vs.ExitPool.PendingExits(head, req.Slot, false /*noLimit*/)
validExits := make([]*ethpb.SignedVoluntaryExit, 0, len(exits))
for _, exit := range exits {
val, err := head.ValidatorAtIndexReadOnly(exit.Exit.ValidatorIndex)
if err != nil {
log.WithError(err).Warn("Proposer: invalid exit")
continue
}
if err := blocks2.VerifyExitAndSignature(val, head.Slot(), head.Fork(), exit, head.GenesisValidatorsRoot()); err != nil {
log.WithError(err).Warn("Proposer: invalid exit")
continue
}
validExits = append(validExits, exit)
}
return validExits
}
func (vs *Server) getSlashings(ctx context.Context, head state.BeaconState) ([]*ethpb.ProposerSlashing, []*ethpb.AttesterSlashing) {
proposerSlashings := vs.SlashingsPool.PendingProposerSlashings(ctx, head, false /*noLimit*/)
validProposerSlashings := make([]*ethpb.ProposerSlashing, 0, len(proposerSlashings))
for _, slashing := range proposerSlashings {
_, err := blocks2.ProcessProposerSlashing(ctx, head, slashing, v.SlashValidator)
if err != nil {
log.WithError(err).Warn("Proposer: invalid proposer slashing")
continue
}
validProposerSlashings = append(validProposerSlashings, slashing)
}
attSlashings := vs.SlashingsPool.PendingAttesterSlashings(ctx, head, false /*noLimit*/)
validAttSlashings := make([]*ethpb.AttesterSlashing, 0, len(attSlashings))
for _, slashing := range attSlashings {
_, err := blocks2.ProcessAttesterSlashing(ctx, head, slashing, v.SlashValidator)
if err != nil {
log.WithError(err).Warn("Proposer: invalid attester slashing")
continue
}
validAttSlashings = append(validAttSlashings, slashing)
}
return validProposerSlashings, validAttSlashings
}
func emptyBlockToSign(slot types.Slot) (interfaces.BeaconBlock, interfaces.SignedBeaconBlock, error) {
var blk interfaces.BeaconBlock
var sBlk interfaces.SignedBeaconBlock
var err error
switch {
case slots.ToEpoch(slot) < params.BeaconConfig().AltairForkEpoch:
blk, err = blocks.NewBeaconBlock(&ethpb.BeaconBlock{Body: &ethpb.BeaconBlockBody{}})
if err != nil {
return nil, nil, status.Errorf(codes.Internal, "Could not initialize block for proposal: %v", err)
}
sBlk, err = blocks.NewSignedBeaconBlock(&ethpb.SignedBeaconBlock{Block: &ethpb.BeaconBlock{Body: &ethpb.BeaconBlockBody{}}})
if err != nil {
return nil, nil, status.Errorf(codes.Internal, "Could not initialize block for proposal: %v", err)
}
case slots.ToEpoch(slot) < params.BeaconConfig().BellatrixForkEpoch:
blk, err = blocks.NewBeaconBlock(&ethpb.BeaconBlockAltair{Body: &ethpb.BeaconBlockBodyAltair{}})
if err != nil {
return nil, nil, status.Errorf(codes.Internal, "Could not initialize block for proposal: %v", err)
}
sBlk, err = blocks.NewSignedBeaconBlock(&ethpb.SignedBeaconBlockAltair{Block: &ethpb.BeaconBlockAltair{Body: &ethpb.BeaconBlockBodyAltair{}}})
if err != nil {
return nil, nil, status.Errorf(codes.Internal, "Could not initialize block for proposal: %v", err)
}
case slots.ToEpoch(slot) < params.BeaconConfig().CapellaForkEpoch:
blk, err = blocks.NewBeaconBlock(&ethpb.BeaconBlockBellatrix{Body: &ethpb.BeaconBlockBodyBellatrix{}})
if err != nil {
return nil, nil, status.Errorf(codes.Internal, "Could not initialize block for proposal: %v", err)
}
sBlk, err = blocks.NewSignedBeaconBlock(&ethpb.SignedBeaconBlockBellatrix{Block: &ethpb.BeaconBlockBellatrix{Body: &ethpb.BeaconBlockBodyBellatrix{}}})
if err != nil {
return nil, nil, status.Errorf(codes.Internal, "Could not initialize block for proposal: %v", err)
}
default:
blk, err = blocks.NewBeaconBlock(&ethpb.BeaconBlockCapella{Body: &ethpb.BeaconBlockBodyCapella{}})
if err != nil {
return nil, nil, status.Errorf(codes.Internal, "Could not initialize block for proposal: %v", err)
}
sBlk, err = blocks.NewSignedBeaconBlock(&ethpb.SignedBeaconBlockCapella{Block: &ethpb.BeaconBlockCapella{Body: &ethpb.BeaconBlockBodyCapella{}}})
if err != nil {
return nil, nil, status.Errorf(codes.Internal, "Could not initialize block for proposal: %v", err)
}
}
return blk, sBlk, err
}
// ProposeBeaconBlock is called by a proposer during its assigned slot to create a block in an attempt

View File

@@ -2,11 +2,8 @@ package validator
import (
"context"
"fmt"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/transition/interop"
"github.com/prysmaticlabs/prysm/v3/config/params"
"github.com/prysmaticlabs/prysm/v3/consensus-types/blocks"
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v3/crypto/bls"
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
@@ -15,66 +12,6 @@ import (
"go.opencensus.io/trace"
)
func (vs *Server) BuildAltairBeaconBlock(ctx context.Context, req *ethpb.BlockRequest) (*ethpb.BeaconBlockAltair, error) {
ctx, span := trace.StartSpan(ctx, "ProposerServer.BuildAltairBeaconBlock")
defer span.End()
blkData, err := vs.buildPhase0BlockData(ctx, req)
if err != nil {
return nil, fmt.Errorf("could not build block data: %v", err)
}
// Use zero hash as stub for state root to compute later.
stateRoot := params.BeaconConfig().ZeroHash[:]
// No need for safe sub as req.Slot cannot be 0 if requesting Altair blocks. If 0, we will be throwing
// an error in the first validity check of this endpoint.
syncAggregate, err := vs.getSyncAggregate(ctx, req.Slot-1, bytesutil.ToBytes32(blkData.ParentRoot))
if err != nil {
return nil, err
}
return &ethpb.BeaconBlockAltair{
Slot: req.Slot,
ParentRoot: blkData.ParentRoot,
StateRoot: stateRoot,
ProposerIndex: blkData.ProposerIdx,
Body: &ethpb.BeaconBlockBodyAltair{
Eth1Data: blkData.Eth1Data,
Deposits: blkData.Deposits,
Attestations: blkData.Attestations,
RandaoReveal: req.RandaoReveal,
ProposerSlashings: blkData.ProposerSlashings,
AttesterSlashings: blkData.AttesterSlashings,
VoluntaryExits: blkData.VoluntaryExits,
Graffiti: blkData.Graffiti[:],
SyncAggregate: syncAggregate,
},
}, nil
}
func (vs *Server) getAltairBeaconBlock(ctx context.Context, req *ethpb.BlockRequest) (*ethpb.BeaconBlockAltair, error) {
ctx, span := trace.StartSpan(ctx, "ProposerServer.getAltairBeaconBlock")
defer span.End()
blk, err := vs.BuildAltairBeaconBlock(ctx, req)
if err != nil {
return nil, fmt.Errorf("could not build block data: %v", err)
}
// Compute state root with the newly constructed block.
wsb, err := blocks.NewSignedBeaconBlock(
&ethpb.SignedBeaconBlockAltair{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
}
// getSyncAggregate retrieves the sync contributions from the pool to construct the sync aggregate object.
// The contributions are filtered based on matching of the input root and slot then profitability.
func (vs *Server) getSyncAggregate(ctx context.Context, slot types.Slot, root [32]byte) (*ethpb.SyncAggregate, error) {

View File

@@ -80,7 +80,7 @@ func (vs *Server) packAttestations(ctx context.Context, latestState state.Beacon
// filter separates attestation list into two groups: valid and invalid attestations.
// The first group passes the all the required checks for attestation to be considered for proposing.
// And attestations from the second group should be deleted.
func (a proposerAtts) filter(ctx context.Context, st state.BeaconState) (proposerAtts, proposerAtts) {
func (a proposerAtts) filter(ctx context.Context, st state.BeaconState) (proposerAtts, proposerAtts, error) {
validAtts := make([]*ethpb.Attestation, 0, len(a))
invalidAtts := make([]*ethpb.Attestation, 0, len(a))
var attestationProcessor func(context.Context, state.BeaconState, *ethpb.Attestation) (state.BeaconState, error)
@@ -88,7 +88,7 @@ func (a proposerAtts) filter(ctx context.Context, st state.BeaconState) (propose
switch st.Version() {
case version.Phase0:
attestationProcessor = blocks.ProcessAttestationNoVerifySignature
case version.Altair, version.Bellatrix:
case version.Altair, version.Bellatrix, version.Capella:
// 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)
@@ -99,7 +99,7 @@ func (a proposerAtts) filter(ctx context.Context, st state.BeaconState) (propose
}
default:
// Exit early if there is an unknown state type.
return validAtts, invalidAtts
return validAtts, invalidAtts, errors.Errorf("unknown state type: %v", st.Version())
}
for _, att := range a {
if _, err := attestationProcessor(ctx, st, att); err == nil {
@@ -108,7 +108,7 @@ func (a proposerAtts) filter(ctx context.Context, st state.BeaconState) (propose
}
invalidAtts = append(invalidAtts, att)
}
return validAtts, invalidAtts
return validAtts, invalidAtts, nil
}
// sortByProfitability orders attestations by highest slot and by highest aggregation bit count.
@@ -247,7 +247,10 @@ func (vs *Server) validateAndDeleteAttsInPool(ctx context.Context, st state.Beac
ctx, span := trace.StartSpan(ctx, "ProposerServer.validateAndDeleteAttsInPool")
defer span.End()
validAtts, invalidAtts := proposerAtts(atts).filter(ctx, st)
validAtts, invalidAtts, err := proposerAtts(atts).filter(ctx, st)
if err != nil {
return nil, err
}
if err := vs.deleteAttsInPool(ctx, invalidAtts); err != nil {
return nil, err
}

View File

@@ -12,7 +12,6 @@ import (
"github.com/prometheus/client_golang/prometheus/promauto"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/blocks"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/signing"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/transition/interop"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/db/kv"
"github.com/prysmaticlabs/prysm/v3/config/params"
consensusblocks "github.com/prysmaticlabs/prysm/v3/consensus-types/blocks"
@@ -38,73 +37,20 @@ var builderGetPayloadMissCount = promauto.NewCounter(prometheus.CounterOpts{
// block request. This value is known as `BUILDER_PROPOSAL_DELAY_TOLERANCE` in builder spec.
const blockBuilderTimeout = 1 * time.Second
func (vs *Server) getBellatrixBeaconBlock(ctx context.Context, req *ethpb.BlockRequest) (*ethpb.GenericBeaconBlock, error) {
altairBlk, err := vs.BuildAltairBeaconBlock(ctx, req)
func (vs *Server) canUseBuilder(ctx context.Context, slot types.Slot, idx types.ValidatorIndex) (bool, error) {
registered, err := vs.validatorRegistered(ctx, idx)
if err != nil {
return nil, err
return false, err
}
if !req.SkipMevBoost {
registered, err := vs.validatorRegistered(ctx, altairBlk.ProposerIndex)
if registered && err == nil {
builderReady, b, err := vs.GetAndBuildBlindBlock(ctx, altairBlk)
if err != nil {
// In the event of an error, the node should fall back to default execution engine for building block.
log.WithError(err).Error("Failed to build a block from external builder, falling " +
"back to local execution client")
builderGetPayloadMissCount.Inc()
} else if builderReady {
return b, nil
}
} else if err != nil {
log.WithError(err).WithFields(logrus.Fields{
"slot": req.Slot,
"validatorIndex": altairBlk.ProposerIndex,
}).Error("Could not determine validator has registered. Defaulting to local execution client")
}
if !registered {
return false, nil
}
payload, err := vs.getExecutionPayload(ctx, req.Slot, altairBlk.ProposerIndex, bytesutil.ToBytes32(altairBlk.ParentRoot))
if err != nil {
return nil, err
}
blk := &ethpb.BeaconBlockBellatrix{
Slot: altairBlk.Slot,
ProposerIndex: altairBlk.ProposerIndex,
ParentRoot: altairBlk.ParentRoot,
StateRoot: params.BeaconConfig().ZeroHash[:],
Body: &ethpb.BeaconBlockBodyBellatrix{
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 := consensusblocks.NewSignedBeaconBlock(
&ethpb.SignedBeaconBlockBellatrix{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 &ethpb.GenericBeaconBlock{Block: &ethpb.GenericBeaconBlock_Bellatrix{Bellatrix: blk}}, nil
return vs.circuitBreakBuilder(slot)
}
// This function retrieves the payload header given the slot number and the validator index.
// It's a no-op if the latest head block is not versioned bellatrix.
func (vs *Server) getPayloadHeaderFromBuilder(ctx context.Context, slot types.Slot, idx types.ValidatorIndex) (*enginev1.ExecutionPayloadHeader, error) {
func (vs *Server) getPayloadHeaderFromBuilder(ctx context.Context, slot types.Slot, idx types.ValidatorIndex) (interfaces.ExecutionData, error) {
b, err := vs.HeadFetcher.HeadBlock(ctx)
if err != nil {
return nil, err
@@ -164,48 +110,8 @@ func (vs *Server) getPayloadHeaderFromBuilder(ctx context.Context, slot types.Sl
"builderPubKey": fmt.Sprintf("%#x", bid.Message.Pubkey),
"blockHash": fmt.Sprintf("%#x", bid.Message.Header.BlockHash),
}).Info("Received header with bid")
return bid.Message.Header, nil
}
// This function constructs the builder block given the input altair block and the header. It returns a generic beacon block for signing
func (vs *Server) buildBlindBlock(ctx context.Context, b *ethpb.BeaconBlockAltair, h *enginev1.ExecutionPayloadHeader) (*ethpb.GenericBeaconBlock, error) {
if b == nil || b.Body == nil {
return nil, errors.New("nil block")
}
if h == nil {
return nil, errors.New("nil header")
}
blk := &ethpb.BlindedBeaconBlockBellatrix{
Slot: b.Slot,
ProposerIndex: b.ProposerIndex,
ParentRoot: b.ParentRoot,
StateRoot: params.BeaconConfig().ZeroHash[:],
Body: &ethpb.BlindedBeaconBlockBodyBellatrix{
RandaoReveal: b.Body.RandaoReveal,
Eth1Data: b.Body.Eth1Data,
Graffiti: b.Body.Graffiti,
ProposerSlashings: b.Body.ProposerSlashings,
AttesterSlashings: b.Body.AttesterSlashings,
Attestations: b.Body.Attestations,
Deposits: b.Body.Deposits,
VoluntaryExits: b.Body.VoluntaryExits,
SyncAggregate: b.Body.SyncAggregate,
ExecutionPayloadHeader: h,
},
}
wsb, err := consensusblocks.NewSignedBeaconBlock(
&ethpb.SignedBlindedBeaconBlockBellatrix{Block: blk, Signature: make([]byte, 96)},
)
if err != nil {
return nil, err
}
stateRoot, err := vs.computeStateRoot(ctx, wsb)
if err != nil {
return nil, errors.Wrap(err, "could not compute state root")
}
blk.StateRoot = stateRoot
return &ethpb.GenericBeaconBlock{Block: &ethpb.GenericBeaconBlock_BlindedBellatrix{BlindedBellatrix: blk}}, nil
return coreBlock.WrappedExecutionPayloadHeader(bid.Message.Header)
}
// This function retrieves the full payload block using the input blind block. This input must be versioned as
@@ -319,24 +225,6 @@ func (vs *Server) unblindBuilderBlock(ctx context.Context, b interfaces.SignedBe
return wb, nil
}
// readyForBuilder returns true if builder is allowed to be used. Builder is only allowed to be use after the
// first finalized checkpt has been execution-enabled.
func (vs *Server) readyForBuilder(ctx context.Context) (bool, error) {
cp := vs.FinalizationFetcher.FinalizedCheckpt()
// Checkpoint root is zero means we are still at genesis epoch.
if bytesutil.ToBytes32(cp.Root) == params.BeaconConfig().ZeroHash {
return false, nil
}
b, err := vs.BeaconDB.Block(ctx, bytesutil.ToBytes32(cp.Root))
if err != nil {
return false, err
}
if err = coreBlock.BeaconBlockIsNil(b); err != nil {
return false, err
}
return blocks.IsExecutionBlock(b.Block().Body())
}
// circuitBreakBuilder returns true if the builder is not allowed to be used due to circuit breaker conditions.
func (vs *Server) circuitBreakBuilder(s types.Slot) (bool, error) {
if vs.ForkFetcher == nil || vs.ForkFetcher.ForkChoicer() == nil {
@@ -385,50 +273,6 @@ func (vs *Server) circuitBreakBuilder(s types.Slot) (bool, error) {
return false, nil
}
// GetAndBuildBlindBlock builds blind block from builder network. Returns a boolean status, built block and error.
// If the status is false that means builder the header block is disallowed.
// This routine is time limited by `blockBuilderTimeout`.
func (vs *Server) GetAndBuildBlindBlock(ctx context.Context, b *ethpb.BeaconBlockAltair) (bool, *ethpb.GenericBeaconBlock, error) {
// No op. Builder is not defined. User did not specify a user URL. We should use local EE.
if vs.BlockBuilder == nil || !vs.BlockBuilder.Configured() {
return false, nil, nil
}
ctx, cancel := context.WithTimeout(ctx, blockBuilderTimeout)
defer cancel()
// Does the protocol allow for builder at this current moment. Builder is only allowed post merge after finalization.
ready, err := vs.readyForBuilder(ctx)
if err != nil {
return false, nil, errors.Wrap(err, "could not determine if builder is ready")
}
if !ready {
return false, nil, nil
}
circuitBreak, err := vs.circuitBreakBuilder(b.Slot)
if err != nil {
return false, nil, errors.Wrap(err, "could not determine if builder circuit breaker condition")
}
if circuitBreak {
return false, nil, nil
}
h, err := vs.getPayloadHeaderFromBuilder(ctx, b.Slot, b.ProposerIndex)
if err != nil {
return false, nil, errors.Wrap(err, "could not get payload header")
}
log.WithFields(logrus.Fields{
"blockHash": fmt.Sprintf("%#x", h.BlockHash),
"feeRecipient": fmt.Sprintf("%#x", h.FeeRecipient),
"gasUsed": h.GasUsed,
"slot": b.Slot,
}).Info("Retrieved header from builder")
gb, err := vs.buildBlindBlock(ctx, b, h)
if err != nil {
return false, nil, errors.Wrap(err, "could not combine altair block with payload header")
}
return true, gb, nil
}
// validatorRegistered returns true if validator with index `id` was previously registered in the database.
func (vs *Server) validatorRegistered(ctx context.Context, id types.ValidatorIndex) (bool, error) {
if vs.BeaconDB == nil {
@@ -448,7 +292,7 @@ func (vs *Server) validatorRegistered(ctx context.Context, id types.ValidatorInd
func (vs *Server) validateBuilderSignature(bid *ethpb.SignedBuilderBid) error {
d, err := signing.ComputeDomain(params.BeaconConfig().DomainApplicationBuilder,
nil, /* fork version */
nil /* genesis val root */)
nil /* genesis val root */)
if err != nil {
return err
}

View File

@@ -2,6 +2,7 @@ package validator
import (
"context"
"fmt"
"math/big"
"github.com/pkg/errors"
@@ -41,25 +42,38 @@ func (vs *Server) eth1DataMajorityVote(ctx context.Context, beaconState state.Be
return vs.mockETH1DataVote(ctx, slot)
}
if !vs.Eth1InfoFetcher.ExecutionClientConnected() {
return vs.randomETH1DataVote(ctx)
return vs.randomETH1DataVote(ctx, "ExecutionClientConnected == false")
}
eth1DataNotification = false
eth1FollowDistance := params.BeaconConfig().Eth1FollowDistance
earliestValidTime := votingPeriodStartTime - 2*params.BeaconConfig().SecondsPerETH1Block*eth1FollowDistance
latestValidTime := votingPeriodStartTime - params.BeaconConfig().SecondsPerETH1Block*eth1FollowDistance
genesisTime, _ := vs.Eth1InfoFetcher.GenesisExecutionChainInfo()
followDistanceSeconds := params.BeaconConfig().Eth1FollowDistance * params.BeaconConfig().SecondsPerETH1Block
latestValidTime := votingPeriodStartTime - followDistanceSeconds
earliestValidTime := votingPeriodStartTime - 2*followDistanceSeconds
// Special case for starting from a pre-mined genesis: the eth1 vote should be genesis until the chain has advanced
// by ETH1_FOLLOW_DISTANCE. The head state should maintain the same ETH1Data until this condition has passed, so
// trust the existing head for the right eth1 vote until we can get a meaningful value from the deposit contract.
log.WithField("votingPeriodStartTime", votingPeriodStartTime-genesisTime).WithField("latestValidTime", latestValidTime-genesisTime).WithField("earliestValidTime", earliestValidTime-genesisTime).Info("eth1DataMajorityVote")
if latestValidTime < genesisTime+followDistanceSeconds {
log.WithField("genesisTime", genesisTime).WithField("latestValidTime", latestValidTime).Info("voting period before genesis + follow distance, return head eth1data")
return vs.HeadFetcher.HeadETH1Data(), nil
}
lastBlockByLatestValidTime, err := vs.Eth1BlockFetcher.BlockByTimestamp(ctx, latestValidTime)
if err != nil {
log.WithError(err).Error("Could not get last block by latest valid time")
return vs.randomETH1DataVote(ctx)
return vs.randomETH1DataVote(ctx, "error from BlockByTimestamp")
}
if lastBlockByLatestValidTime.Time < earliestValidTime {
return vs.HeadFetcher.HeadETH1Data(), nil
ed := vs.HeadFetcher.HeadETH1Data()
log.WithField("latestBlock.Time", lastBlockByLatestValidTime.Time).WithField("latestBlock.Height", lastBlockByLatestValidTime.Number).WithFields(logFields(ed)).WithField("condition", "lastBlockByLatestValidTime.Time < earliestValidTime").Info("eth1DataMajorityVote")
return ed, nil
}
lastBlockDepositCount, lastBlockDepositRoot := vs.DepositFetcher.DepositsNumberAndRootAtHeight(ctx, lastBlockByLatestValidTime.Number)
if lastBlockDepositCount == 0 {
log.WithFields(logFields(vs.ChainStartFetcher.ChainStartEth1Data())).WithField("condition", "ChainStartEth1Data").Info("eth1DataMajorityVote")
return vs.ChainStartFetcher.ChainStartEth1Data(), nil
}
@@ -67,17 +81,27 @@ func (vs *Server) eth1DataMajorityVote(ctx context.Context, beaconState state.Be
h, err := vs.Eth1BlockFetcher.BlockHashByHeight(ctx, lastBlockByLatestValidTime.Number)
if err != nil {
log.WithError(err).Error("Could not get hash of last block by latest valid time")
return vs.randomETH1DataVote(ctx)
return vs.randomETH1DataVote(ctx, "deposit count too high")
}
return &ethpb.Eth1Data{
ed := &ethpb.Eth1Data{
BlockHash: h.Bytes(),
DepositCount: lastBlockDepositCount,
DepositRoot: lastBlockDepositRoot[:],
}, nil
}
log.WithFields(logFields(ed)).WithField("condition", "lastBlockDepositCount >= vs.HeadFetcher.HeadETH1Data().DepositCount").Info("eth1DataMajorityVote")
return ed, nil
}
return vs.HeadFetcher.HeadETH1Data(), nil
}
func logFields(ed *ethpb.Eth1Data) map[string]interface{} {
fields := make(map[string]interface{})
fields["deposit_root"] = fmt.Sprintf("%#x", ed.DepositRoot)
fields["deposit_count"] = ed.DepositCount
fields["block_hash"] = fmt.Sprintf("%#x", ed.BlockHash)
return fields
}
func (vs *Server) slotStartTime(slot types.Slot) uint64 {
startTime, _ := vs.Eth1InfoFetcher.GenesisExecutionChainInfo()
return slots.VotingPeriodStartTime(startTime, slot)
@@ -147,7 +171,8 @@ func (vs *Server) mockETH1DataVote(ctx context.Context, slot types.Slot) (*ethpb
}, nil
}
func (vs *Server) randomETH1DataVote(ctx context.Context) (*ethpb.Eth1Data, error) {
func (vs *Server) randomETH1DataVote(ctx context.Context, reason string) (*ethpb.Eth1Data, error) {
log.WithField("reason", reason).Warn("randomETH1DataVote")
if !eth1DataNotification {
log.Warn("Beacon Node is no longer connected to an ETH1 chain, so ETH1 data votes are now random.")
eth1DataNotification = true

View File

@@ -12,11 +12,13 @@ import (
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/blocks"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/time"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/transition"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/db/kv"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state"
fieldparams "github.com/prysmaticlabs/prysm/v3/config/fieldparams"
"github.com/prysmaticlabs/prysm/v3/config/params"
consensusblocks "github.com/prysmaticlabs/prysm/v3/consensus-types/blocks"
"github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces"
payloadattribute "github.com/prysmaticlabs/prysm/v3/consensus-types/payload-attribute"
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
enginev1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
@@ -38,10 +40,17 @@ var (
})
)
// This returns the execution payload of a given slot. The function has full awareness of pre and post merge.
// This returns the execution payload of a given slot.
// The function has full awareness of pre and post merge.
// The payload is computed given the respected time of merge.
func (vs *Server) getExecutionPayload(ctx context.Context, slot types.Slot, vIdx types.ValidatorIndex, headRoot [32]byte) (*enginev1.ExecutionPayload, error) {
func (vs *Server) getExecutionPayload(ctx context.Context,
slot types.Slot,
vIdx types.ValidatorIndex,
headRoot [32]byte,
st state.BeaconState) (interfaces.ExecutionData, error) {
proposerID, payloadId, ok := vs.ProposerSlotIndexCache.GetProposerPayloadIDs(slot, headRoot)
log.Infof("getExecutionPayload, GetProposerPayloadIDs(slot=%d, arg.headRoot=%#x,has=%v,pid=%#x,proposerIdx=%d)", slot, headRoot, ok, payloadId, proposerID)
feeRecipient := params.BeaconConfig().DefaultFeeRecipient
recipient, err := vs.BeaconDB.FeeRecipientByValidatorID(ctx, vIdx)
switch err == nil {
@@ -67,10 +76,10 @@ func (vs *Server) getExecutionPayload(ctx context.Context, slot types.Slot, vIdx
var pid [8]byte
copy(pid[:], payloadId[:])
payloadIDCacheHit.Inc()
payload, err := vs.ExecutionEngineCaller.GetPayload(ctx, pid)
payload, err := vs.ExecutionEngineCaller.GetPayload(ctx, pid, slot)
switch {
case err == nil:
warnIfFeeRecipientDiffers(payload, feeRecipient)
warnIfFeeRecipientDiffers(payload.FeeRecipient(), feeRecipient)
return payload, nil
case errors.Is(err, context.DeadlineExceeded):
default:
@@ -78,15 +87,6 @@ func (vs *Server) getExecutionPayload(ctx context.Context, slot types.Slot, vIdx
}
}
st, err := vs.HeadFetcher.HeadState(ctx)
if err != nil {
return nil, err
}
st, err = transition.ProcessSlotsIfPossible(ctx, st, slot)
if err != nil {
return nil, err
}
var parentHash []byte
var hasTerminalBlock bool
mergeComplete, err := blocks.IsMergeTransitionComplete(st)
@@ -106,14 +106,14 @@ func (vs *Server) getExecutionPayload(ctx context.Context, slot types.Slot, vIdx
parentHash = header.BlockHash()
} else {
if activationEpochNotReached(slot) {
return emptyPayload(), nil
return emptyPayload()
}
parentHash, hasTerminalBlock, err = vs.getTerminalBlockHashIfExists(ctx, uint64(t.Unix()))
if err != nil {
return nil, err
}
if !hasTerminalBlock {
return emptyPayload(), nil
return emptyPayload()
}
}
payloadIDCacheMiss.Inc()
@@ -149,10 +149,13 @@ func (vs *Server) getExecutionPayload(ctx context.Context, slot types.Slot, vIdx
FinalizedBlockHash: finalizedBlockHash,
}
p := &enginev1.PayloadAttributes{
p, err := payloadattribute.New(&enginev1.PayloadAttributes{
Timestamp: uint64(t.Unix()),
PrevRandao: random,
SuggestedFeeRecipient: feeRecipient.Bytes(),
})
if err != nil {
return nil, err
}
payloadID, _, err := vs.ExecutionEngineCaller.ForkchoiceUpdated(ctx, f, p)
if err != nil {
@@ -161,22 +164,22 @@ func (vs *Server) getExecutionPayload(ctx context.Context, slot types.Slot, vIdx
if payloadID == nil {
return nil, fmt.Errorf("nil payload with block hash: %#x", parentHash)
}
payload, err := vs.ExecutionEngineCaller.GetPayload(ctx, *payloadID)
payload, err := vs.ExecutionEngineCaller.GetPayload(ctx, *payloadID, slot)
if err != nil {
return nil, err
}
warnIfFeeRecipientDiffers(payload, feeRecipient)
warnIfFeeRecipientDiffers(payload.FeeRecipient(), feeRecipient)
return payload, nil
}
// warnIfFeeRecipientDiffers logs a warning if the fee recipient in the included payload does not
// match the requested one.
func warnIfFeeRecipientDiffers(payload *enginev1.ExecutionPayload, feeRecipient common.Address) {
func warnIfFeeRecipientDiffers(payloadRecipient []byte, feeRecipient common.Address) {
// Warn if the fee recipient is not the value we expect.
if payload != nil && !bytes.Equal(payload.FeeRecipient, feeRecipient[:]) {
if !bytes.Equal(payloadRecipient, feeRecipient[:]) {
logrus.WithFields(logrus.Fields{
"wantedFeeRecipient": fmt.Sprintf("%#x", feeRecipient),
"received": fmt.Sprintf("%#x", payload.FeeRecipient),
"received": fmt.Sprintf("%#x", payloadRecipient),
}).Warn("Fee recipient address from execution client is not what was expected. " +
"It is possible someone has compromised your client to try and take your transaction fees")
}
@@ -228,8 +231,8 @@ func activationEpochNotReached(slot types.Slot) bool {
return false
}
func emptyPayload() *enginev1.ExecutionPayload {
return &enginev1.ExecutionPayload{
func emptyPayload() (interfaces.ExecutionData, error) {
return consensusblocks.WrappedExecutionPayload(&enginev1.ExecutionPayload{
ParentHash: make([]byte, fieldparams.RootLength),
FeeRecipient: make([]byte, fieldparams.FeeRecipientLength),
StateRoot: make([]byte, fieldparams.RootLength),
@@ -238,5 +241,5 @@ func emptyPayload() *enginev1.ExecutionPayload {
PrevRandao: make([]byte, fieldparams.RootLength),
BaseFeePerGas: make([]byte, fieldparams.RootLength),
BlockHash: make([]byte, fieldparams.RootLength),
}
})
}

View File

@@ -231,8 +231,8 @@ func TestServer_getTerminalBlockHashIfExists(t *testing.T) {
name string
paramsTerminalHash []byte
paramsTd string
currentPowBlock *pb.ExecutionBlock
parentPowBlock *pb.ExecutionBlock
currentPowBlock *pb.ExecutionBlockBellatrix
parentPowBlock *pb.ExecutionBlockBellatrix
wantTerminalBlockHash []byte
wantExists bool
errString string
@@ -253,14 +253,14 @@ func TestServer_getTerminalBlockHashIfExists(t *testing.T) {
{
name: "use terminal total difficulty",
paramsTd: "2",
currentPowBlock: &pb.ExecutionBlock{
currentPowBlock: &pb.ExecutionBlockBellatrix{
Hash: common.BytesToHash([]byte("a")),
Header: gethtypes.Header{
ParentHash: common.BytesToHash([]byte("b")),
},
TotalDifficulty: "0x3",
},
parentPowBlock: &pb.ExecutionBlock{
parentPowBlock: &pb.ExecutionBlockBellatrix{
Hash: common.BytesToHash([]byte("b")),
Header: gethtypes.Header{
ParentHash: common.BytesToHash([]byte("c")),
@@ -273,7 +273,7 @@ func TestServer_getTerminalBlockHashIfExists(t *testing.T) {
{
name: "use terminal total difficulty but fails timestamp",
paramsTd: "2",
currentPowBlock: &pb.ExecutionBlock{
currentPowBlock: &pb.ExecutionBlockBellatrix{
Hash: common.BytesToHash([]byte("a")),
Header: gethtypes.Header{
ParentHash: common.BytesToHash([]byte("b")),
@@ -281,7 +281,7 @@ func TestServer_getTerminalBlockHashIfExists(t *testing.T) {
},
TotalDifficulty: "0x3",
},
parentPowBlock: &pb.ExecutionBlock{
parentPowBlock: &pb.ExecutionBlockBellatrix{
Hash: common.BytesToHash([]byte("b")),
Header: gethtypes.Header{
ParentHash: common.BytesToHash([]byte("c")),
@@ -296,9 +296,9 @@ func TestServer_getTerminalBlockHashIfExists(t *testing.T) {
cfg.TerminalTotalDifficulty = tt.paramsTd
cfg.TerminalBlockHash = common.BytesToHash(tt.paramsTerminalHash)
params.OverrideBeaconConfig(cfg)
var m map[[32]byte]*pb.ExecutionBlock
var m map[[32]byte]*pb.ExecutionBlockBellatrix
if tt.parentPowBlock != nil {
m = map[[32]byte]*pb.ExecutionBlock{
m = map[[32]byte]*pb.ExecutionBlockBellatrix{
tt.parentPowBlock.Hash: tt.parentPowBlock,
}
}

View File

@@ -1,170 +0,0 @@
package validator
import (
"context"
"fmt"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/blocks"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/transition"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/transition/interop"
v "github.com/prysmaticlabs/prysm/v3/beacon-chain/core/validators"
"github.com/prysmaticlabs/prysm/v3/config/params"
consensusblocks "github.com/prysmaticlabs/prysm/v3/consensus-types/blocks"
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
"go.opencensus.io/trace"
)
// blockData required to create a beacon block.
type blockData struct {
ParentRoot []byte
Graffiti [32]byte
ProposerIdx types.ValidatorIndex
Eth1Data *ethpb.Eth1Data
Deposits []*ethpb.Deposit
Attestations []*ethpb.Attestation
ProposerSlashings []*ethpb.ProposerSlashing
AttesterSlashings []*ethpb.AttesterSlashing
VoluntaryExits []*ethpb.SignedVoluntaryExit
}
func (vs *Server) getPhase0BeaconBlock(ctx context.Context, req *ethpb.BlockRequest) (*ethpb.BeaconBlock, error) {
ctx, span := trace.StartSpan(ctx, "ProposerServer.getPhase0BeaconBlock")
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[:]
blk := &ethpb.BeaconBlock{
Slot: req.Slot,
ParentRoot: blkData.ParentRoot,
StateRoot: stateRoot,
ProposerIndex: blkData.ProposerIdx,
Body: &ethpb.BeaconBlockBody{
Eth1Data: blkData.Eth1Data,
Deposits: blkData.Deposits,
Attestations: blkData.Attestations,
RandaoReveal: req.RandaoReveal,
ProposerSlashings: blkData.ProposerSlashings,
AttesterSlashings: blkData.AttesterSlashings,
VoluntaryExits: blkData.VoluntaryExits,
Graffiti: blkData.Graffiti[:],
},
}
// Compute state root with the newly constructed block.
wsb, err := consensusblocks.NewSignedBeaconBlock(&ethpb.SignedBeaconBlock{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, errors.Wrap(err, "could not compute state root")
}
blk.StateRoot = stateRoot
return blk, nil
}
// Build data required for creating a new beacon block, so this method can be shared across forks.
func (vs *Server) buildPhase0BlockData(ctx context.Context, req *ethpb.BlockRequest) (*blockData, error) {
ctx, span := trace.StartSpan(ctx, "ProposerServer.buildPhase0BlockData")
defer span.End()
if vs.SyncChecker.Syncing() {
return nil, fmt.Errorf("syncing to latest head, not ready to respond")
}
if err := vs.HeadUpdater.UpdateHead(ctx); err != nil {
log.WithError(err).Error("Could not process attestations and update head")
}
// Retrieve the parent block as the current head of the canonical chain.
parentRoot, err := vs.HeadFetcher.HeadRoot(ctx)
if err != nil {
return nil, fmt.Errorf("could not retrieve head root: %v", err)
}
head, err := vs.HeadFetcher.HeadState(ctx)
if err != nil {
return nil, fmt.Errorf("could not get head state %v", err)
}
head, err = transition.ProcessSlotsUsingNextSlotCache(ctx, head, parentRoot, req.Slot)
if err != nil {
return nil, fmt.Errorf("could not advance slots to calculate proposer index: %v", err)
}
eth1Data, err := vs.eth1DataMajorityVote(ctx, head)
if err != nil {
return nil, fmt.Errorf("could not get ETH1 data: %v", err)
}
deposits, atts, err := vs.packDepositsAndAttestations(ctx, head, eth1Data)
if err != nil {
return nil, err
}
graffiti := bytesutil.ToBytes32(req.Graffiti)
// Calculate new proposer index.
idx, err := helpers.BeaconProposerIndex(ctx, head)
if err != nil {
return nil, fmt.Errorf("could not calculate proposer index %v", err)
}
proposerSlashings := vs.SlashingsPool.PendingProposerSlashings(ctx, head, false /*noLimit*/)
validProposerSlashings := make([]*ethpb.ProposerSlashing, 0, len(proposerSlashings))
for _, slashing := range proposerSlashings {
_, err := blocks.ProcessProposerSlashing(ctx, head, slashing, v.SlashValidator)
if err != nil {
log.WithError(err).Warn("Proposer: invalid proposer slashing")
continue
}
validProposerSlashings = append(validProposerSlashings, slashing)
}
attSlashings := vs.SlashingsPool.PendingAttesterSlashings(ctx, head, false /*noLimit*/)
validAttSlashings := make([]*ethpb.AttesterSlashing, 0, len(attSlashings))
for _, slashing := range attSlashings {
_, err := blocks.ProcessAttesterSlashing(ctx, head, slashing, v.SlashValidator)
if err != nil {
log.WithError(err).Warn("Proposer: invalid attester slashing")
continue
}
validAttSlashings = append(validAttSlashings, slashing)
}
exits := vs.ExitPool.PendingExits(head, req.Slot, false /*noLimit*/)
validExits := make([]*ethpb.SignedVoluntaryExit, 0, len(exits))
for _, exit := range exits {
val, err := head.ValidatorAtIndexReadOnly(exit.Exit.ValidatorIndex)
if err != nil {
log.WithError(err).Warn("Proposer: invalid exit")
continue
}
if err := blocks.VerifyExitAndSignature(val, head.Slot(), head.Fork(), exit, head.GenesisValidatorsRoot()); err != nil {
log.WithError(err).Warn("Proposer: invalid exit")
continue
}
validExits = append(validExits, exit)
}
return &blockData{
ParentRoot: parentRoot,
Graffiti: graffiti,
ProposerIdx: idx,
Eth1Data: eth1Data,
Deposits: deposits,
Attestations: atts,
ProposerSlashings: validProposerSlashings,
AttesterSlashings: validAttSlashings,
VoluntaryExits: validExits,
}, nil
}

View File

@@ -20,6 +20,7 @@ import (
"github.com/prysmaticlabs/prysm/v3/beacon-chain/db"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/execution"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/operations/attestations"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/operations/blstoexec"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/operations/slashings"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/operations/synccommittee"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/operations/voluntaryexits"
@@ -62,6 +63,7 @@ type Server struct {
SlashingsPool slashings.PoolManager
ExitPool voluntaryexits.PoolManager
SyncCommitteePool synccommittee.Pool
BLSChangesPool blstoexec.PoolManager
BlockReceiver blockchain.BlockReceiver
MockEth1Votes bool
Eth1BlockFetcher execution.POWBlockFetcher

View File

@@ -23,6 +23,7 @@ import (
"github.com/prysmaticlabs/prysm/v3/beacon-chain/db"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/execution"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/operations/attestations"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/operations/blstoexec"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/operations/slashings"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/operations/synccommittee"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/operations/voluntaryexits"
@@ -99,6 +100,7 @@ type Config struct {
SlashingsPool slashings.PoolManager
SlashingChecker slasherservice.SlashingChecker
SyncCommitteeObjectPool synccommittee.Pool
BLSChangesPool blstoexec.PoolManager
SyncService chainSync.Checker
Broadcaster p2p.Broadcaster
PeersFetcher p2p.PeersProvider
@@ -216,6 +218,7 @@ func (s *Service) Start() {
SlashingsPool: s.cfg.SlashingsPool,
StateGen: s.cfg.StateGen,
SyncCommitteePool: s.cfg.SyncCommitteeObjectPool,
BLSChangesPool: s.cfg.BLSChangesPool,
ReplayerBuilder: ch,
ExecutionEngineCaller: s.cfg.ExecutionEngineCaller,
BeaconDB: s.cfg.BeaconDB,
@@ -240,6 +243,7 @@ func (s *Service) Start() {
ReplayerBuilder: ch,
},
SyncCommitteePool: s.cfg.SyncCommitteeObjectPool,
BLSChangesPool: s.cfg.BLSChangesPool,
ProposerSlotIndexCache: s.cfg.ProposerIdsCache,
}
@@ -292,6 +296,7 @@ func (s *Service) Start() {
ReceivedAttestationsBuffer: make(chan *ethpbv1alpha1.Attestation, attestationBufferSize),
CollectedAttestationsBuffer: make(chan []*ethpbv1alpha1.Attestation, attestationBufferSize),
ReplayerBuilder: ch,
BLSChangesPool: s.cfg.BLSChangesPool,
}
beaconChainServerV1 := &beacon.Server{
CanonicalHistory: ch,
@@ -318,6 +323,7 @@ func (s *Service) Start() {
V1Alpha1ValidatorServer: validatorServer,
SyncChecker: s.cfg.SyncService,
ExecutionPayloadReconstructor: s.cfg.ExecutionPayloadReconstructor,
BLSChangesPool: s.cfg.BLSChangesPool,
}
ethpbv1alpha1.RegisterNodeServer(s.grpcServer, nodeServer)
ethpbservice.RegisterBeaconNodeServer(s.grpcServer, nodeServerV1)

View File

@@ -1,6 +1,7 @@
package state_native
import (
fieldparams "github.com/prysmaticlabs/prysm/v3/config/fieldparams"
"github.com/prysmaticlabs/prysm/v3/config/params"
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
@@ -48,7 +49,7 @@ func (b *BeaconState) ExpectedWithdrawals() ([]*enginev1.Withdrawal, error) {
b.lock.RLock()
defer b.lock.RUnlock()
withdrawals := make([]*enginev1.Withdrawal, 0, params.BeaconConfig().MaxWithdrawalsPerPayload)
withdrawals := make([]*enginev1.Withdrawal, 0, fieldparams.MaxWithdrawalsPerPayload)
validatorIndex := b.nextWithdrawalValidatorIndex
withdrawalIndex := b.nextWithdrawalIndex
epoch := slots.ToEpoch(b.slot)
@@ -57,22 +58,22 @@ func (b *BeaconState) ExpectedWithdrawals() ([]*enginev1.Withdrawal, error) {
balance := b.balances[validatorIndex]
if balance > 0 && isFullyWithdrawableValidator(val, epoch) {
withdrawals = append(withdrawals, &enginev1.Withdrawal{
WithdrawalIndex: withdrawalIndex,
ValidatorIndex: validatorIndex,
ExecutionAddress: bytesutil.SafeCopyBytes(val.WithdrawalCredentials[ETH1AddressOffset:]),
Amount: balance,
Index: withdrawalIndex,
ValidatorIndex: validatorIndex,
Address: bytesutil.SafeCopyBytes(val.WithdrawalCredentials[ETH1AddressOffset:]),
Amount: balance,
})
withdrawalIndex++
} else if isPartiallyWithdrawableValidator(val, balance) {
withdrawals = append(withdrawals, &enginev1.Withdrawal{
WithdrawalIndex: withdrawalIndex,
ValidatorIndex: validatorIndex,
ExecutionAddress: bytesutil.SafeCopyBytes(val.WithdrawalCredentials[ETH1AddressOffset:]),
Amount: balance - params.BeaconConfig().MaxEffectiveBalance,
Index: withdrawalIndex,
ValidatorIndex: validatorIndex,
Address: bytesutil.SafeCopyBytes(val.WithdrawalCredentials[ETH1AddressOffset:]),
Amount: balance - params.BeaconConfig().MaxEffectiveBalance,
})
withdrawalIndex++
}
if uint64(len(withdrawals)) == params.BeaconConfig().MaxWithdrawalsPerPayload {
if uint64(len(withdrawals)) == fieldparams.MaxWithdrawalsPerPayload {
break
}
validatorIndex += 1

View File

@@ -26,7 +26,7 @@ func TestNextWithdrawalIndex(t *testing.T) {
})
}
func TestLastWithdrawalValidatorIndex(t *testing.T) {
func TestNextWithdrawalValidatorIndex(t *testing.T) {
t.Run("ok", func(t *testing.T) {
s := BeaconState{version: version.Capella, nextWithdrawalValidatorIndex: 123}
i, err := s.NextWithdrawalValidatorIndex()
@@ -153,10 +153,10 @@ func TestExpectedWithdrawals(t *testing.T) {
require.NoError(t, err)
require.Equal(t, 1, len(expected))
withdrawal := &enginev1.Withdrawal{
WithdrawalIndex: 0,
ValidatorIndex: 3,
ExecutionAddress: s.validators[3].WithdrawalCredentials[12:],
Amount: s.balances[3],
Index: 0,
ValidatorIndex: 3,
Address: s.validators[3].WithdrawalCredentials[12:],
Amount: s.balances[3],
}
require.DeepEqual(t, withdrawal, expected[0])
})
@@ -181,10 +181,10 @@ func TestExpectedWithdrawals(t *testing.T) {
require.NoError(t, err)
require.Equal(t, 1, len(expected))
withdrawal := &enginev1.Withdrawal{
WithdrawalIndex: 0,
ValidatorIndex: 3,
ExecutionAddress: s.validators[3].WithdrawalCredentials[12:],
Amount: params.BeaconConfig().MinDepositAmount,
Index: 0,
ValidatorIndex: 3,
Address: s.validators[3].WithdrawalCredentials[12:],
Amount: params.BeaconConfig().MinDepositAmount,
}
require.DeepEqual(t, withdrawal, expected[0])
})
@@ -212,16 +212,16 @@ func TestExpectedWithdrawals(t *testing.T) {
require.Equal(t, 2, len(expected))
withdrawalFull := &enginev1.Withdrawal{
WithdrawalIndex: 1,
ValidatorIndex: 7,
ExecutionAddress: s.validators[7].WithdrawalCredentials[12:],
Amount: s.balances[7],
Index: 1,
ValidatorIndex: 7,
Address: s.validators[7].WithdrawalCredentials[12:],
Amount: s.balances[7],
}
withdrawalPartial := &enginev1.Withdrawal{
WithdrawalIndex: 0,
ValidatorIndex: 3,
ExecutionAddress: s.validators[3].WithdrawalCredentials[12:],
Amount: params.BeaconConfig().MinDepositAmount,
Index: 0,
ValidatorIndex: 3,
Address: s.validators[3].WithdrawalCredentials[12:],
Amount: params.BeaconConfig().MinDepositAmount,
}
require.DeepEqual(t, withdrawalPartial, expected[0])
require.DeepEqual(t, withdrawalFull, expected[1])
@@ -246,10 +246,10 @@ func TestExpectedWithdrawals(t *testing.T) {
require.NoError(t, err)
require.Equal(t, params.BeaconConfig().MaxWithdrawalsPerPayload, uint64(len(expected)))
withdrawal := &enginev1.Withdrawal{
WithdrawalIndex: 0,
ValidatorIndex: 0,
ExecutionAddress: s.validators[0].WithdrawalCredentials[12:],
Amount: 1,
Index: 0,
ValidatorIndex: 0,
Address: s.validators[0].WithdrawalCredentials[12:],
Amount: 1,
}
require.DeepEqual(t, withdrawal, expected[0])
})
@@ -273,10 +273,10 @@ func TestExpectedWithdrawals(t *testing.T) {
require.NoError(t, err)
require.Equal(t, params.BeaconConfig().MaxWithdrawalsPerPayload, uint64(len(expected)))
withdrawal := &enginev1.Withdrawal{
WithdrawalIndex: 0,
ValidatorIndex: 0,
ExecutionAddress: s.validators[0].WithdrawalCredentials[12:],
Amount: params.BeaconConfig().MaxEffectiveBalance,
Index: 0,
ValidatorIndex: 0,
Address: s.validators[0].WithdrawalCredentials[12:],
Amount: params.BeaconConfig().MaxEffectiveBalance,
}
require.DeepEqual(t, withdrawal, expected[0])
})
@@ -300,10 +300,10 @@ func TestExpectedWithdrawals(t *testing.T) {
require.NoError(t, err)
require.Equal(t, params.BeaconConfig().MaxWithdrawalsPerPayload, uint64(len(expected)))
withdrawal := &enginev1.Withdrawal{
WithdrawalIndex: 0,
ValidatorIndex: 0,
ExecutionAddress: s.validators[0].WithdrawalCredentials[12:],
Amount: params.BeaconConfig().MaxEffectiveBalance + 1,
Index: 0,
ValidatorIndex: 0,
Address: s.validators[0].WithdrawalCredentials[12:],
Amount: params.BeaconConfig().MaxEffectiveBalance + 1,
}
require.DeepEqual(t, withdrawal, expected[0])
})

View File

@@ -20,7 +20,7 @@ func (b *BeaconState) SetNextWithdrawalIndex(i uint64) error {
return nil
}
// SetLastWithdrawalValidatorIndex sets the index of the validator which is
// SetNexWithdrawalValidatorIndex sets the index of the validator which is
// next in line for a partial withdrawal.
func (b *BeaconState) SetNextWithdrawalValidatorIndex(i types.ValidatorIndex) error {
if b.version < version.Capella {

View File

@@ -20,7 +20,7 @@ func TestSetNextWithdrawalIndex(t *testing.T) {
require.Equal(t, true, s.dirtyFields[nativetypes.NextWithdrawalIndex])
}
func TestSetLastWithdrawalValidatorIndex(t *testing.T) {
func TestSetNextWithdrawalValidatorIndex(t *testing.T) {
s := BeaconState{
version: version.Capella,
nextWithdrawalValidatorIndex: 3,

View File

@@ -75,7 +75,7 @@ func (s *Service) beaconBlocksRootRPCHandler(ctx context.Context, msg interface{
}
if blk.Block().IsBlinded() {
blk, err = s.cfg.executionPayloadReconstructor.ReconstructFullBellatrixBlock(ctx, blk)
blk, err = s.cfg.executionPayloadReconstructor.ReconstructFullBlock(ctx, blk)
if err != nil {
log.WithError(err).Error("Could not get reconstruct full bellatrix block from blinded body")
s.writeErrorResponseToStream(responseCodeServerError, types.ErrGeneric.Error(), stream)

View File

@@ -54,7 +54,7 @@ func (s *Service) goodbyeRPCHandler(_ context.Context, msg interface{}, stream l
// disconnectBadPeer checks whether peer is considered bad by some scorer, and tries to disconnect
// the peer, if that is the case. Additionally, disconnection reason is obtained from scorer.
func (s *Service) disconnectBadPeer(ctx context.Context, id peer.ID) {
func (s *Service) disconnectBadPeer(ctx context.Context, id peer.ID, from string) {
if !s.cfg.p2p.Peers().IsBad(id) {
return
}
@@ -63,6 +63,7 @@ func (s *Service) disconnectBadPeer(ctx context.Context, id peer.ID) {
if err == nil {
goodbyeCode = p2ptypes.GoodbyeCodeBanned
}
log.Infof("disconnectBadPeer from %s", from)
if err := s.sendGoodByeAndDisconnect(ctx, goodbyeCode, id); err != nil {
log.WithError(err).Debug("Error when disconnecting with bad peer")
}

View File

@@ -47,7 +47,7 @@ func (s *Service) maintainPeerStatuses() {
}
// Disconnect from peers that are considered bad by any of the registered scorers.
if s.cfg.p2p.Peers().IsBad(id) {
s.disconnectBadPeer(s.ctx, id)
s.disconnectBadPeer(s.ctx, id, "maintainPeerStatuses")
return
}
// If the status hasn't been updated in the recent interval time.
@@ -170,7 +170,7 @@ func (s *Service) sendRPCStatusRequest(ctx context.Context, id peer.ID) error {
err = s.validateStatusMessage(ctx, msg)
s.cfg.p2p.Peers().Scorers().PeerStatusScorer().SetPeerStatus(id, msg, err)
if s.cfg.p2p.Peers().IsBad(id) {
s.disconnectBadPeer(s.ctx, id)
s.disconnectBadPeer(s.ctx, id, "sendRPCStatusRequest")
}
return err
}
@@ -222,6 +222,11 @@ func (s *Service) statusRPCHandler(ctx context.Context, msg interface{}, stream
}
// Close before disconnecting, and wait for the other end to ack our response.
closeStreamAndWait(stream, log)
forkDigest, err := s.currentForkDigest()
if err != nil {
log.WithError(err).Error("failed to compute fork digest")
}
log.Errorf("fork digest mismatch, expected=%#x, saw=%#x", forkDigest, m.ForkDigest)
if err := s.sendGoodByeAndDisconnect(ctx, p2ptypes.GoodbyeCodeWrongNetwork, remotePeer); err != nil {
return err
}

View File

@@ -326,6 +326,7 @@ func (s *Service) subscribeStaticWithSubnets(topic string, validator wrappedVal,
return
case <-ticker.C():
if s.chainStarted.IsSet() && s.cfg.initialSync.Syncing() {
log.Debug("(subscribeStaticWithSubnets) chain started set, but in initial sync")
continue
}
valid, err := isDigestValid(digest, genesis, genRoot)
@@ -396,6 +397,7 @@ func (s *Service) subscribeDynamicWithSubnets(
return
case currentSlot := <-ticker.C():
if s.chainStarted.IsSet() && s.cfg.initialSync.Syncing() {
log.Debug("(subscribeDynamicWithSubnets) chain started set, but in initial sync")
continue
}
valid, err := isDigestValid(digest, genesis, genRoot)
@@ -526,6 +528,7 @@ func (s *Service) subscribeStaticWithSyncSubnets(topic string, validator wrapped
return
case <-ticker.C():
if s.chainStarted.IsSet() && s.cfg.initialSync.Syncing() {
log.Debug("(subscribeStaticWithSyncSubnets) chain started set, but in initial sync")
continue
}
valid, err := isDigestValid(digest, genesis, genRoot)
@@ -595,6 +598,7 @@ func (s *Service) subscribeDynamicWithSyncSubnets(
return
case currentSlot := <-ticker.C():
if s.chainStarted.IsSet() && s.cfg.initialSync.Syncing() {
log.Debug("(subscribeDynamicWithSyncSubnets) chain started set, but in initial sync")
continue
}
valid, err := isDigestValid(digest, genesis, genRoot)

View File

@@ -57,7 +57,7 @@ func (s *Service) validateBlsToExecutionChange(ctx context.Context, pid peer.ID,
return pubsub.ValidationReject, err
}
// Validate the signature of the message using our batch gossip verifier.
sigBatch, err := blocks.BLSChangesSignatureBatch(ctx, st, []*ethpb.SignedBLSToExecutionChange{blsChange})
sigBatch, err := blocks.BLSChangesSignatureBatch(st, []*ethpb.SignedBLSToExecutionChange{blsChange})
if err != nil {
return pubsub.ValidationReject, err
}

View File

@@ -165,6 +165,7 @@ var BeaconChainFlags = append(deprecatedBeaconFlags, append(deprecatedFlags, []c
disableBroadcastSlashingFlag,
enableSlasherFlag,
enableHistoricalSpaceRepresentation,
disableStakinContractCheck,
disablePullTips,
disableVecHTR,
disableForkChoiceDoublyLinkedTree,

View File

@@ -226,6 +226,8 @@ func configForkSchedule(b *BeaconChainConfig) map[[fieldparams.VersionLength]byt
fvs[bytesutil.ToBytes4(b.AltairForkVersion)] = b.AltairForkEpoch
// Set Bellatrix fork data.
fvs[bytesutil.ToBytes4(b.BellatrixForkVersion)] = b.BellatrixForkEpoch
// Set Capella fork data.
fvs[bytesutil.ToBytes4(b.CapellaForkVersion)] = b.CapellaForkEpoch
return fvs
}
@@ -237,5 +239,7 @@ func configForkNames(b *BeaconChainConfig) map[[fieldparams.VersionLength]byte]s
fvn[bytesutil.ToBytes4(b.AltairForkVersion)] = "altair"
// Set Bellatrix fork data.
fvn[bytesutil.ToBytes4(b.BellatrixForkVersion)] = "bellatrix"
// Set Capella fork data.
fvn[bytesutil.ToBytes4(b.CapellaForkVersion)] = "capella"
return fvn
}

View File

@@ -9,7 +9,8 @@ func InteropConfig() *BeaconChainConfig {
c.GenesisForkVersion = []byte{0, 0, 0, 235}
c.AltairForkVersion = []byte{1, 0, 0, 235}
c.BellatrixForkVersion = []byte{2, 0, 0, 235}
c.ShardingForkVersion = []byte{3, 0, 0, 235}
c.CapellaForkVersion = []byte{3, 0, 0, 235}
c.ShardingForkVersion = []byte{4, 0, 0, 235}
c.InitializeForkSchedule()
return c

View File

@@ -1,8 +1,8 @@
package params
const (
altairE2EForkEpoch = 6
bellatrixE2EForkEpoch = 8
altairE2EForkEpoch = 0
bellatrixE2EForkEpoch = 0
)
// E2ETestConfig retrieves the configurations made specifically for E2E testing.
@@ -10,6 +10,8 @@ const (
// WARNING: This config is only for testing, it is not meant for use outside of E2E.
func E2ETestConfig() *BeaconChainConfig {
e2eConfig := MinimalSpecConfig()
e2eConfig.DepositContractAddress = "0x4242424242424242424242424242424242424242"
e2eConfig.Eth1FollowDistance = 8
// Misc.
e2eConfig.MinGenesisActiveValidatorCount = 256
@@ -21,7 +23,6 @@ func E2ETestConfig() *BeaconChainConfig {
e2eConfig.SlotsPerEpoch = 6
e2eConfig.SqrRootSlotsPerEpoch = 2
e2eConfig.SecondsPerETH1Block = 2
e2eConfig.Eth1FollowDistance = 8
e2eConfig.EpochsPerEth1VotingPeriod = 2
e2eConfig.ShardCommitteePeriod = 4
e2eConfig.MaxSeedLookahead = 1
@@ -35,14 +36,15 @@ func E2ETestConfig() *BeaconChainConfig {
e2eConfig.BellatrixForkEpoch = bellatrixE2EForkEpoch
// Terminal Total Difficulty.
e2eConfig.TerminalTotalDifficulty = "616"
e2eConfig.TerminalTotalDifficulty = "0"
// Prysm constants.
e2eConfig.ConfigName = EndToEndName
e2eConfig.GenesisForkVersion = []byte{0, 0, 0, 253}
e2eConfig.AltairForkVersion = []byte{1, 0, 0, 253}
e2eConfig.BellatrixForkVersion = []byte{2, 0, 0, 253}
e2eConfig.ShardingForkVersion = []byte{3, 0, 0, 253}
e2eConfig.CapellaForkVersion = []byte{3, 0, 0, 253}
e2eConfig.ShardingForkVersion = []byte{4, 0, 0, 253}
e2eConfig.InitializeForkSchedule()
return e2eConfig
@@ -50,6 +52,8 @@ func E2ETestConfig() *BeaconChainConfig {
func E2EMainnetTestConfig() *BeaconChainConfig {
e2eConfig := MainnetConfig().Copy()
e2eConfig.DepositContractAddress = "0x4242424242424242424242424242424242424242"
e2eConfig.Eth1FollowDistance = 8
// Misc.
e2eConfig.MinGenesisActiveValidatorCount = 256
@@ -60,7 +64,6 @@ func E2EMainnetTestConfig() *BeaconChainConfig {
e2eConfig.SecondsPerSlot = 6
e2eConfig.SqrRootSlotsPerEpoch = 5
e2eConfig.SecondsPerETH1Block = 2
e2eConfig.Eth1FollowDistance = 8
e2eConfig.ShardCommitteePeriod = 4
// PoW parameters.
@@ -72,14 +75,15 @@ func E2EMainnetTestConfig() *BeaconChainConfig {
e2eConfig.BellatrixForkEpoch = bellatrixE2EForkEpoch
// Terminal Total Difficulty.
e2eConfig.TerminalTotalDifficulty = "616"
e2eConfig.TerminalTotalDifficulty = "0"
// Prysm constants.
e2eConfig.ConfigName = EndToEndMainnetName
e2eConfig.GenesisForkVersion = []byte{0, 0, 0, 254}
e2eConfig.AltairForkVersion = []byte{1, 0, 0, 254}
e2eConfig.BellatrixForkVersion = []byte{2, 0, 0, 254}
e2eConfig.ShardingForkVersion = []byte{3, 0, 0, 254}
e2eConfig.CapellaForkVersion = []byte{3, 0, 0, 254}
e2eConfig.ShardingForkVersion = []byte{4, 0, 0, 254}
e2eConfig.InitializeForkSchedule()
return e2eConfig

View File

@@ -32,6 +32,7 @@ func RopstenConfig() *BeaconChainConfig {
cfg.AltairForkVersion = []byte{0x80, 0x00, 0x00, 0x70}
cfg.BellatrixForkEpoch = 750
cfg.BellatrixForkVersion = []byte{0x80, 0x00, 0x00, 0x71}
cfg.CapellaForkVersion = []byte{0x80, 0x00, 0x00, 0x72}
cfg.TerminalTotalDifficulty = "50000000000000000"
cfg.DepositContractAddress = "0x6f22fFbC56eFF051aECF839396DD1eD9aD6BBA9D"
cfg.InitializeForkSchedule()

View File

@@ -155,6 +155,16 @@ func (e executionPayload) WithdrawalsRoot() ([]byte, error) {
return nil, ErrUnsupportedGetter
}
// PbV1 --
func (e executionPayload) PbV1() (*enginev1.ExecutionPayload, error) {
return e.p, nil
}
// PbV2 --
func (e executionPayload) PbV2() (*enginev1.ExecutionPayloadCapella, error) {
return nil, ErrUnsupportedGetter
}
// executionPayloadHeader is a convenience wrapper around a blinded beacon block body's execution header data structure
// This wrapper allows us to conform to a common interface so that beacon
// blocks for future forks can also be applied across Prysm without issues.
@@ -296,6 +306,16 @@ func (e executionPayloadHeader) WithdrawalsRoot() ([]byte, error) {
return nil, ErrUnsupportedGetter
}
// PbV2 --
func (e executionPayloadHeader) PbV2() (*enginev1.ExecutionPayloadCapella, error) {
return nil, ErrUnsupportedGetter
}
// PbV1 --
func (e executionPayloadHeader) PbV1() (*enginev1.ExecutionPayload, error) {
return nil, ErrUnsupportedGetter
}
// PayloadToHeader converts `payload` into execution payload header format.
func PayloadToHeader(payload interfaces.ExecutionData) (*enginev1.ExecutionPayloadHeader, error) {
txs, err := payload.Transactions()
@@ -465,6 +485,16 @@ func (e executionPayloadCapella) WithdrawalsRoot() ([]byte, error) {
return nil, ErrUnsupportedGetter
}
// PbV2 --
func (e executionPayloadCapella) PbV2() (*enginev1.ExecutionPayloadCapella, error) {
return e.p, nil
}
// PbV1 --
func (e executionPayloadCapella) PbV1() (*enginev1.ExecutionPayload, error) {
return nil, ErrUnsupportedGetter
}
// executionPayloadHeaderCapella is a convenience wrapper around a blinded beacon block body's execution header data structure
// This wrapper allows us to conform to a common interface so that beacon
// blocks for future forks can also be applied across Prysm without issues.
@@ -606,6 +636,16 @@ func (e executionPayloadHeaderCapella) WithdrawalsRoot() ([]byte, error) {
return e.p.WithdrawalsRoot, nil
}
// PbV2 --
func (e executionPayloadHeaderCapella) PbV2() (*enginev1.ExecutionPayloadCapella, error) {
return nil, ErrUnsupportedGetter
}
// PbV1 --
func (e executionPayloadHeaderCapella) PbV1() (*enginev1.ExecutionPayload, error) {
return nil, ErrUnsupportedGetter
}
// PayloadToHeaderCapella converts `payload` into execution payload header format.
func PayloadToHeaderCapella(payload interfaces.ExecutionData) (*enginev1.ExecutionPayloadHeaderCapella, error) {
txs, err := payload.Transactions()

View File

@@ -23,7 +23,8 @@ var (
// ErrNilObject is returned in a constructor when the underlying object is nil.
ErrNilObject = errors.New("received nil object")
// ErrNilSignedBeaconBlock is returned when a nil signed beacon block is received.
ErrNilSignedBeaconBlock = errors.New("signed beacon block can't be nil")
ErrNilSignedBeaconBlock = errors.New("signed beacon block can't be nil")
errNonBlindedSignedBeaconBlock = errors.New("can only build signed beacon block from blinded format")
)
// NewSignedBeaconBlock creates a signed beacon block from a protobuf signed beacon block.
@@ -177,14 +178,13 @@ func BuildSignedBeaconBlockFromExecutionPayload(
if err := BeaconBlockIsNil(blk); err != nil {
return nil, err
}
if !blk.IsBlinded() {
return nil, errNonBlindedSignedBeaconBlock
}
b := blk.Block()
payloadHeader, err := b.Body().Execution()
switch {
case errors.Is(err, ErrUnsupportedGetter):
return nil, errors.Wrap(err, "can only build signed beacon block from blinded format")
case err != nil:
if err != nil {
return nil, errors.Wrap(err, "could not get execution payload header")
default:
}
var wrappedPayload interfaces.ExecutionData

View File

@@ -332,14 +332,14 @@ func TestBuildSignedBeaconBlockFromExecutionPayload(t *testing.T) {
_, err := BuildSignedBeaconBlockFromExecutionPayload(nil, nil)
require.ErrorIs(t, ErrNilSignedBeaconBlock, err)
})
t.Run("unsupported field payload header", func(t *testing.T) {
t.Run("not blinded payload", func(t *testing.T) {
altairBlock := &eth.SignedBeaconBlockAltair{
Block: &eth.BeaconBlockAltair{
Body: &eth.BeaconBlockBodyAltair{}}}
blk, err := NewSignedBeaconBlock(altairBlock)
require.NoError(t, err)
_, err = BuildSignedBeaconBlockFromExecutionPayload(blk, nil)
require.Equal(t, true, errors.Is(err, ErrUnsupportedGetter))
require.Equal(t, true, errors.Is(err, errNonBlindedSignedBeaconBlock))
})
t.Run("payload header root and payload root mismatch", func(t *testing.T) {
blockHash := bytesutil.Bytes32(1)

View File

@@ -29,11 +29,63 @@ func (b *SignedBeaconBlock) Signature() [field_params.BLSSignatureLength]byte {
return b.signature
}
// SetSignature sets the signature of the signed beacon block.
func (b *SignedBeaconBlock) SetSignature(sig []byte) {
copy(b.signature[:], sig)
}
// Block returns the underlying beacon block object.
func (b *SignedBeaconBlock) Block() interfaces.BeaconBlock {
return b.block
}
// SetBlock sets the underlying beacon block object.
func (b *SignedBeaconBlock) SetBlock(blk interfaces.BeaconBlock) error {
copied, err := blk.Copy()
if err != nil {
return err
}
b.block.slot = copied.Slot()
b.block.parentRoot = copied.ParentRoot()
b.block.stateRoot = copied.StateRoot()
b.block.stateRoot = copied.StateRoot()
b.block.proposerIndex = copied.ProposerIndex()
b.block.body.randaoReveal = copied.Body().RandaoReveal()
b.block.body.eth1Data = copied.Body().Eth1Data()
b.block.body.graffiti = copied.Body().Graffiti()
b.block.body.proposerSlashings = copied.Body().ProposerSlashings()
b.block.body.attesterSlashings = copied.Body().AttesterSlashings()
b.block.body.attestations = copied.Body().Attestations()
b.block.body.deposits = copied.Body().Deposits()
b.block.body.voluntaryExits = copied.Body().VoluntaryExits()
if b.version >= version.Altair {
syncAggregate, err := copied.Body().SyncAggregate()
if err != nil {
return err
}
b.block.body.syncAggregate = syncAggregate
}
if b.version >= version.Bellatrix {
executionData, err := copied.Body().Execution()
if err != nil {
return err
}
if b.block.body.isBlinded {
b.block.body.executionPayloadHeader = executionData
} else {
b.block.body.executionPayload = executionData
}
}
if b.version >= version.Capella {
changes, err := copied.Body().BLSToExecutionChanges()
if err != nil {
return err
}
b.block.body.blsToExecutionChanges = changes
}
return nil
}
// IsNil checks if the underlying beacon block is nil.
func (b *SignedBeaconBlock) IsNil() bool {
return b == nil || b.block.IsNil()
@@ -458,21 +510,46 @@ func (b *BeaconBlock) Slot() types.Slot {
return b.slot
}
// SetSlot sets the respective slot of the block.
// This function is not thread safe, it is only used during block creation.
func (b *BeaconBlock) SetSlot(slot types.Slot) {
b.slot = slot
}
// ProposerIndex returns the proposer index of the beacon block.
func (b *BeaconBlock) ProposerIndex() types.ValidatorIndex {
return b.proposerIndex
}
// SetProposerIndex sets the proposer index of the beacon block.
// This function is not thread safe, it is only used during block creation.
func (b *BeaconBlock) SetProposerIndex(proposerIndex types.ValidatorIndex) {
b.proposerIndex = proposerIndex
}
// ParentRoot returns the parent root of beacon block.
func (b *BeaconBlock) ParentRoot() [field_params.RootLength]byte {
return b.parentRoot
}
// SetParentRoot sets the parent root of beacon block.
// This function is not thread safe, it is only used during block creation.
func (b *BeaconBlock) SetParentRoot(parentRoot []byte) {
copy(b.parentRoot[:], parentRoot)
}
// StateRoot returns the state root of the beacon block.
func (b *BeaconBlock) StateRoot() [field_params.RootLength]byte {
return b.stateRoot
}
// SetStateRoot sets the state root of the underlying beacon block
// This function is not thread safe, it is only used during block
// proposal to set the state root of a new block
func (b *BeaconBlock) SetStateRoot(root []byte) {
copy(b.stateRoot[:], root)
}
// Body returns the underlying block body.
func (b *BeaconBlock) Body() interfaces.BeaconBlockBody {
return b.body
@@ -488,6 +565,11 @@ func (b *BeaconBlock) IsBlinded() bool {
return b.body.isBlinded
}
// SetBlinded sets the blinded flag of the beacon block.
func (b *BeaconBlock) SetBlinded(blinded bool) {
b.body.isBlinded = blinded
}
// Version of the underlying protobuf object.
func (b *BeaconBlock) Version() int {
return b.version
@@ -731,6 +813,41 @@ func (b *BeaconBlock) AsSignRequestObject() (validatorpb.SignRequestObject, erro
}
}
func (b *BeaconBlock) Copy() (interfaces.BeaconBlock, error) {
if b == nil {
return nil, nil
}
pb, err := b.Proto()
if err != nil {
return nil, err
}
switch b.version {
case version.Phase0:
cp := eth.CopyBeaconBlock(pb.(*eth.BeaconBlock))
return initBlockFromProtoPhase0(cp)
case version.Altair:
cp := eth.CopyBeaconBlockAltair(pb.(*eth.BeaconBlockAltair))
return initBlockFromProtoAltair(cp)
case version.Bellatrix:
if b.IsBlinded() {
cp := eth.CopyBlindedBeaconBlockBellatrix(pb.(*eth.BlindedBeaconBlockBellatrix))
return initBlindedBlockFromProtoBellatrix(cp)
}
cp := eth.CopyBeaconBlockBellatrix(pb.(*eth.BeaconBlockBellatrix))
return initBlockFromProtoBellatrix(cp)
case version.Capella:
if b.IsBlinded() {
cp := eth.CopyBlindedBeaconBlockCapella(pb.(*eth.BlindedBeaconBlockCapella))
return initBlindedBlockFromProtoCapella(cp)
}
cp := eth.CopyBeaconBlockCapella(pb.(*eth.BeaconBlockCapella))
return initBlockFromProtoCapella(cp)
default:
return nil, errIncorrectBlockVersion
}
}
// IsNil checks if the block body is nil.
func (b *BeaconBlockBody) IsNil() bool {
return b == nil
@@ -741,41 +858,81 @@ func (b *BeaconBlockBody) RandaoReveal() [field_params.BLSSignatureLength]byte {
return b.randaoReveal
}
// SetRandaoReveal sets the randao reveal in the block body.
func (b *BeaconBlockBody) SetRandaoReveal(r []byte) {
copy(b.randaoReveal[:], r)
}
// Eth1Data returns the eth1 data in the block.
func (b *BeaconBlockBody) Eth1Data() *eth.Eth1Data {
return b.eth1Data
}
// SetEth1Data sets the eth1 data in the block.
func (b *BeaconBlockBody) SetEth1Data(e *eth.Eth1Data) {
b.eth1Data = eth.CopyETH1Data(e)
}
// Graffiti returns the graffiti in the block.
func (b *BeaconBlockBody) Graffiti() [field_params.RootLength]byte {
return b.graffiti
}
// SetGraffiti sets the graffiti in the block.
func (b *BeaconBlockBody) SetGraffiti(g []byte) {
copy(b.graffiti[:], g)
}
// ProposerSlashings returns the proposer slashings in the block.
func (b *BeaconBlockBody) ProposerSlashings() []*eth.ProposerSlashing {
return b.proposerSlashings
}
// SetProposerSlashings sets the proposer slashings in the block.
func (b *BeaconBlockBody) SetProposerSlashings(p []*eth.ProposerSlashing) {
b.proposerSlashings = eth.CopyProposerSlashings(p)
}
// AttesterSlashings returns the attester slashings in the block.
func (b *BeaconBlockBody) AttesterSlashings() []*eth.AttesterSlashing {
return b.attesterSlashings
}
// SetAttesterSlashings sets the attester slashings in the block.
func (b *BeaconBlockBody) SetAttesterSlashings(a []*eth.AttesterSlashing) {
b.attesterSlashings = eth.CopyAttesterSlashings(a)
}
// Attestations returns the stored attestations in the block.
func (b *BeaconBlockBody) Attestations() []*eth.Attestation {
return b.attestations
}
// SetAttestations sets the attestations in the block.
func (b *BeaconBlockBody) SetAttestations(a []*eth.Attestation) {
b.attestations = eth.CopyAttestations(a)
}
// Deposits returns the stored deposits in the block.
func (b *BeaconBlockBody) Deposits() []*eth.Deposit {
return b.deposits
}
// SetDeposits sets the deposits in the block.
func (b *BeaconBlockBody) SetDeposits(d []*eth.Deposit) {
b.deposits = eth.CopyDeposits(d)
}
// VoluntaryExits returns the voluntary exits in the block.
func (b *BeaconBlockBody) VoluntaryExits() []*eth.SignedVoluntaryExit {
return b.voluntaryExits
}
// SetVoluntaryExits sets the voluntary exits in the block.
func (b *BeaconBlockBody) SetVoluntaryExits(v []*eth.SignedVoluntaryExit) {
b.voluntaryExits = eth.CopySignedVoluntaryExits(v)
}
// SyncAggregate returns the sync aggregate in the block.
func (b *BeaconBlockBody) SyncAggregate() (*eth.SyncAggregate, error) {
if b.version == version.Phase0 {
@@ -784,6 +941,15 @@ func (b *BeaconBlockBody) SyncAggregate() (*eth.SyncAggregate, error) {
return b.syncAggregate, nil
}
// SetSyncAggregate sets the sync aggregate in the block.
func (b *BeaconBlockBody) SetSyncAggregate(s *eth.SyncAggregate) error {
if b.version == version.Phase0 {
return ErrNotSupported("SyncAggregate", b.version)
}
b.syncAggregate = eth.CopySyncAggregate(s)
return nil
}
// Execution returns the execution payload of the block body.
func (b *BeaconBlockBody) Execution() (interfaces.ExecutionData, error) {
switch b.version {
@@ -836,6 +1002,19 @@ func (b *BeaconBlockBody) Execution() (interfaces.ExecutionData, error) {
}
}
// SetExecution sets the execution payload of the block body.
func (b *BeaconBlockBody) SetExecution(e interfaces.ExecutionData) error {
if b.version == version.Phase0 || b.version == version.Altair {
return ErrNotSupported("Execution", b.version)
}
if b.isBlinded {
b.executionPayloadHeader = e // TODO: Copy?
return nil
}
b.executionPayload = e
return nil
}
func (b *BeaconBlockBody) BLSToExecutionChanges() ([]*eth.SignedBLSToExecutionChange, error) {
if b.version < version.Capella {
return nil, ErrNotSupported("BLSToExecutionChanges", b.version)
@@ -843,6 +1022,15 @@ func (b *BeaconBlockBody) BLSToExecutionChanges() ([]*eth.SignedBLSToExecutionCh
return b.blsToExecutionChanges, nil
}
// SetBLSToExecutionChanges sets the BLS to execution changes in the block.
func (b *BeaconBlockBody) SetBLSToExecutionChanges(blsToExecutionChanges []*eth.SignedBLSToExecutionChange) error {
if b.version < version.Capella {
return ErrNotSupported("BLSToExecutionChanges", b.version)
}
b.blsToExecutionChanges = eth.CopyBLSToExecutionChanges(blsToExecutionChanges)
return nil
}
// HashTreeRoot returns the ssz root of the block body.
func (b *BeaconBlockBody) HashTreeRoot() ([field_params.RootLength]byte, error) {
pb, err := b.Proto()

View File

@@ -14,7 +14,9 @@ import (
// a signed beacon block.
type SignedBeaconBlock interface {
Block() BeaconBlock
SetBlock(BeaconBlock) error
Signature() [field_params.BLSSignatureLength]byte
SetSignature(sig []byte)
IsNil() bool
Copy() (SignedBeaconBlock, error)
Proto() (proto.Message, error)
@@ -37,12 +39,17 @@ type SignedBeaconBlock interface {
// employed by an object that is a beacon block.
type BeaconBlock interface {
Slot() types.Slot
SetSlot(slot types.Slot)
ProposerIndex() types.ValidatorIndex
SetProposerIndex(idx types.ValidatorIndex)
ParentRoot() [field_params.RootLength]byte
SetParentRoot([]byte)
StateRoot() [field_params.RootLength]byte
SetStateRoot([]byte)
Body() BeaconBlockBody
IsNil() bool
IsBlinded() bool
SetBlinded(bool)
HashTreeRoot() ([field_params.RootLength]byte, error)
Proto() (proto.Message, error)
ssz.Marshaler
@@ -50,25 +57,37 @@ type BeaconBlock interface {
ssz.HashRoot
Version() int
AsSignRequestObject() (validatorpb.SignRequestObject, error)
Copy() (BeaconBlock, error)
}
// BeaconBlockBody describes the method set employed by an object
// that is a beacon block body.
type BeaconBlockBody interface {
RandaoReveal() [field_params.BLSSignatureLength]byte
SetRandaoReveal([]byte)
Eth1Data() *ethpb.Eth1Data
SetEth1Data(*ethpb.Eth1Data)
Graffiti() [field_params.RootLength]byte
SetGraffiti([]byte)
ProposerSlashings() []*ethpb.ProposerSlashing
SetProposerSlashings([]*ethpb.ProposerSlashing)
AttesterSlashings() []*ethpb.AttesterSlashing
SetAttesterSlashings([]*ethpb.AttesterSlashing)
Attestations() []*ethpb.Attestation
SetAttestations([]*ethpb.Attestation)
Deposits() []*ethpb.Deposit
SetDeposits([]*ethpb.Deposit)
VoluntaryExits() []*ethpb.SignedVoluntaryExit
SetVoluntaryExits([]*ethpb.SignedVoluntaryExit)
SyncAggregate() (*ethpb.SyncAggregate, error)
SetSyncAggregate(*ethpb.SyncAggregate) error
IsNil() bool
HashTreeRoot() ([field_params.RootLength]byte, error)
Proto() (proto.Message, error)
Execution() (ExecutionData, error)
SetExecution(ExecutionData) error
BLSToExecutionChanges() ([]*ethpb.SignedBLSToExecutionChange, error)
SetBLSToExecutionChanges([]*ethpb.SignedBLSToExecutionChange) error
}
// ExecutionData represents execution layer information that is contained
@@ -96,4 +115,6 @@ type ExecutionData interface {
TransactionsRoot() ([]byte, error)
Withdrawals() ([]*enginev1.Withdrawal, error)
WithdrawalsRoot() ([]byte, error)
PbV2() (*enginev1.ExecutionPayloadCapella, error)
PbV1() (*enginev1.ExecutionPayload, error)
}

View File

@@ -94,6 +94,14 @@ func (SignedBeaconBlock) Header() (*eth.SignedBeaconBlockHeader, error) {
panic("implement me")
}
func (SignedBeaconBlock) SetBlock(_ interfaces.BeaconBlock) error {
panic("implement me")
}
func (SignedBeaconBlock) SetSignature(_ []byte) {
panic("implement me")
}
type BeaconBlock struct {
Htr [field_params.RootLength]byte
HtrErr error
@@ -165,6 +173,30 @@ func (BeaconBlock) Version() int {
panic("implement me")
}
func (BeaconBlock) ToBlinded() (interfaces.BeaconBlock, error) {
panic("implement me")
}
func (BeaconBlock) SetSlot(_ types.Slot) {
panic("implement me")
}
func (BeaconBlock) SetProposerIndex(_ types.ValidatorIndex) {
panic("implement me")
}
func (BeaconBlock) SetParentRoot(_ []byte) {
panic("implement me")
}
func (BeaconBlock) SetBlinded(_ bool) {
panic("implement me")
}
func (BeaconBlock) Copy() (interfaces.BeaconBlock, error) {
panic("implement me")
}
type BeaconBlockBody struct{}
func (BeaconBlockBody) RandaoReveal() [field_params.BLSSignatureLength]byte {
@@ -227,6 +259,50 @@ func (b *BeaconBlock) SetStateRoot(root []byte) {
panic("implement me")
}
func (b *BeaconBlockBody) SetRandaoReveal([]byte) {
panic("implement me")
}
func (b *BeaconBlockBody) SetEth1Data(*eth.Eth1Data) {
panic("implement me")
}
func (b *BeaconBlockBody) SetGraffiti([]byte) {
panic("implement me")
}
func (b *BeaconBlockBody) SetProposerSlashings([]*eth.ProposerSlashing) {
panic("implement me")
}
func (b *BeaconBlockBody) SetAttesterSlashings([]*eth.AttesterSlashing) {
panic("implement me")
}
func (b *BeaconBlockBody) SetAttestations([]*eth.Attestation) {
panic("implement me")
}
func (b *BeaconBlockBody) SetDeposits([]*eth.Deposit) {
panic("implement me")
}
func (b *BeaconBlockBody) SetVoluntaryExits([]*eth.SignedVoluntaryExit) {
panic("implement me")
}
func (b *BeaconBlockBody) SetSyncAggregate(*eth.SyncAggregate) error {
panic("implement me")
}
func (b *BeaconBlockBody) SetExecution(interfaces.ExecutionData) error {
panic("implement me")
}
func (b *BeaconBlockBody) SetBLSToExecutionChanges([]*eth.SignedBLSToExecutionChange) error {
panic("implement me")
}
var _ interfaces.SignedBeaconBlock = &SignedBeaconBlock{}
var _ interfaces.BeaconBlock = &BeaconBlock{}
var _ interfaces.BeaconBlockBody = &BeaconBlockBody{}

View File

@@ -16,6 +16,7 @@ go_library(
],
importpath = "github.com/prysmaticlabs/prysm/v3/crypto/bls/blst",
visibility = [
"//beacon-chain/operations/blstoexec:__pkg__",
"//crypto/bls:__pkg__",
],
deps = [

View File

@@ -10,6 +10,7 @@ go_library(
importpath = "github.com/prysmaticlabs/prysm/v3/crypto/bls/common",
visibility = [
"//beacon-chain/core/blocks:__subpackages__",
"//beacon-chain/operations/blstoexec:__pkg__",
"//crypto/bls:__subpackages__",
"//testing:__subpackages__",
],

View File

@@ -99,6 +99,15 @@ func ToBytes4(x []byte) [4]byte {
return y
}
// ToBytes20 is a convenience method for converting a byte slice to a fix
// sized 20 byte array. This method will truncate the input if it is larger
// than 20 bytes.
func ToBytes20(x []byte) [20]byte {
var y [20]byte
copy(y[:], x)
return y
}
// ToBytes32 is a convenience method for converting a byte slice to a fix
// sized 32 byte array. This method will truncate the input if it is larger
// than 32 bytes.

View File

@@ -41,7 +41,6 @@ go_test(
"//config/fieldparams:go_default_library",
"//config/params:go_default_library",
"//crypto/hash:go_default_library",
"//proto/engine/v1:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//testing/assert:go_default_library",
"//testing/require:go_default_library",

View File

@@ -167,11 +167,11 @@ func transactionRoot(tx []byte) ([32]byte, error) {
func withdrawalRoot(hasher HashFn, w *enginev1.Withdrawal) ([32]byte, error) {
fieldRoots := make([][32]byte, 4)
if w != nil {
binary.LittleEndian.PutUint64(fieldRoots[0][:], w.WithdrawalIndex)
binary.LittleEndian.PutUint64(fieldRoots[0][:], w.Index)
binary.LittleEndian.PutUint64(fieldRoots[1][:], uint64(w.ValidatorIndex))
fieldRoots[2] = bytesutil.ToBytes32(w.ExecutionAddress)
fieldRoots[2] = bytesutil.ToBytes32(w.Address)
binary.LittleEndian.PutUint64(fieldRoots[3][:], w.Amount)
}
return BitwiseMerkleize(hasher, fieldRoots, uint64(len(fieldRoots)), uint64(len(fieldRoots)))

View File

@@ -7,7 +7,6 @@ import (
fieldparams "github.com/prysmaticlabs/prysm/v3/config/fieldparams"
"github.com/prysmaticlabs/prysm/v3/crypto/hash"
"github.com/prysmaticlabs/prysm/v3/encoding/ssz"
enginev1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v3/testing/assert"
"github.com/prysmaticlabs/prysm/v3/testing/require"

View File

@@ -2,6 +2,7 @@
package forks
import (
"bytes"
"math"
"sort"
"time"
@@ -165,7 +166,19 @@ func SortedForkVersions(forkSchedule map[[4]byte]types.Epoch) [][4]byte {
i++
}
sort.Slice(sortedVersions, func(a, b int) bool {
return forkSchedule[sortedVersions[a]] < forkSchedule[sortedVersions[b]]
// va == "version" a, ie the [4]byte version id
va, vb := sortedVersions[a], sortedVersions[b]
// ea == "epoch" a, ie the types.Epoch corresponding to va
ea, eb := forkSchedule[va], forkSchedule[vb]
// Try to sort by epochs first, which works fine when epochs are all distinct.
// in the case of testnets starting from a given fork, all epochs leading to the fork will be zero.
if ea != eb {
return ea < eb
}
// If the epochs are equal, break the tie with a lexicographic comparison of the fork version bytes.
// eg 2 versions both with a fork epoch of 0, 0x00000000 would come before 0x01000000.
// sort.Slice takes a 'less' func, ie `return a < b`, and when va < vb, bytes.Compare will return -1
return bytes.Compare(va[:], vb[:]) < 0
})
return sortedVersions
}

View File

@@ -1,6 +1,7 @@
package forks
import (
"bytes"
"sort"
"strings"
@@ -28,7 +29,12 @@ func (o OrderedSchedule) Len() int { return len(o) }
func (o OrderedSchedule) Swap(i, j int) { o[i], o[j] = o[j], o[i] }
// Less implements the Less method of sort.Interface
func (o OrderedSchedule) Less(i, j int) bool { return o[i].Epoch < o[j].Epoch }
func (o OrderedSchedule) Less(i, j int) bool {
if o[i].Epoch == o[j].Epoch {
return bytes.Compare(o[i].Version[:], o[j].Version[:]) < 0
}
return o[i].Epoch < o[j].Epoch
}
// VersionForEpoch finds the Version with the highest epoch <= the given epoch
func (o OrderedSchedule) VersionForEpoch(epoch types.Epoch) ([fieldparams.VersionLength]byte, error) {

View File

@@ -76,14 +76,17 @@ go_library(
deps = [
"//config/fieldparams:go_default_library",
"//config/params:go_default_library",
"//consensus-types/primitives:go_default_library",
"//encoding/bytesutil:go_default_library",
"//proto/eth/ext:go_default_library",
"//runtime/version: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//core/types:go_default_library",
"@com_github_golang_protobuf//proto:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@com_github_prysmaticlabs_fastssz//:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
"@go_googleapis//google/api:annotations_go_proto",
"@io_bazel_rules_go//proto/wkt:descriptor_go_proto",
"@io_bazel_rules_go//proto/wkt:timestamp_go_proto",
@@ -114,6 +117,7 @@ go_test(
":go_default_library",
"//config/fieldparams:go_default_library",
"//config/params:go_default_library",
"//consensus-types/primitives:go_default_library",
"//encoding/bytesutil:go_default_library",
"//testing/require:go_default_library",
"@com_github_ethereum_go_ethereum//common:go_default_library",

View File

@@ -1029,10 +1029,10 @@ type Withdrawal struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
WithdrawalIndex uint64 `protobuf:"varint,1,opt,name=withdrawal_index,json=withdrawalIndex,proto3" json:"withdrawal_index,omitempty"`
ValidatorIndex github_com_prysmaticlabs_prysm_v3_consensus_types_primitives.ValidatorIndex `protobuf:"varint,2,opt,name=validator_index,json=validatorIndex,proto3" json:"validator_index,omitempty" cast-type:"github.com/prysmaticlabs/prysm/v3/consensus-types/primitives.ValidatorIndex"`
ExecutionAddress []byte `protobuf:"bytes,3,opt,name=execution_address,json=executionAddress,proto3" json:"execution_address,omitempty" ssz-size:"20"`
Amount uint64 `protobuf:"varint,4,opt,name=amount,proto3" json:"amount,omitempty"`
Index uint64 `protobuf:"varint,1,opt,name=index,proto3" json:"index,omitempty"`
ValidatorIndex github_com_prysmaticlabs_prysm_v3_consensus_types_primitives.ValidatorIndex `protobuf:"varint,2,opt,name=validator_index,json=validatorIndex,proto3" json:"validator_index,omitempty" cast-type:"github.com/prysmaticlabs/prysm/v3/consensus-types/primitives.ValidatorIndex"`
Address []byte `protobuf:"bytes,3,opt,name=address,proto3" json:"address,omitempty" ssz-size:"20"`
Amount uint64 `protobuf:"varint,4,opt,name=amount,proto3" json:"amount,omitempty"`
}
func (x *Withdrawal) Reset() {
@@ -1067,9 +1067,9 @@ func (*Withdrawal) Descriptor() ([]byte, []int) {
return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{9}
}
func (x *Withdrawal) GetWithdrawalIndex() uint64 {
func (x *Withdrawal) GetIndex() uint64 {
if x != nil {
return x.WithdrawalIndex
return x.Index
}
return 0
}
@@ -1081,9 +1081,9 @@ func (x *Withdrawal) GetValidatorIndex() github_com_prysmaticlabs_prysm_v3_conse
return github_com_prysmaticlabs_prysm_v3_consensus_types_primitives.ValidatorIndex(0)
}
func (x *Withdrawal) GetExecutionAddress() []byte {
func (x *Withdrawal) GetAddress() []byte {
if x != nil {
return x.ExecutionAddress
return x.Address
}
return nil
}
@@ -1440,49 +1440,47 @@ var file_proto_engine_v1_execution_engine_proto_rawDesc = []byte{
0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x68,
0x61, 0x73, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x33,
0x32, 0x52, 0x12, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x42, 0x6c, 0x6f, 0x63,
0x6b, 0x48, 0x61, 0x73, 0x68, 0x22, 0xfe, 0x01, 0x0a, 0x0a, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72,
0x61, 0x77, 0x61, 0x6c, 0x12, 0x29, 0x0a, 0x10, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77,
0x61, 0x6c, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f,
0x77, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12,
0x78, 0x0a, 0x0f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x69, 0x6e, 0x64,
0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x42, 0x4f, 0x82, 0xb5, 0x18, 0x4b, 0x67, 0x69,
0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x61, 0x74,
0x69, 0x63, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x2f, 0x76, 0x33, 0x2f,
0x63, 0x6f, 0x6e, 0x73, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f,
0x70, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x73, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64,
0x61, 0x74, 0x6f, 0x72, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x52, 0x0e, 0x76, 0x61, 0x6c, 0x69, 0x64,
0x61, 0x74, 0x6f, 0x72, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x33, 0x0a, 0x11, 0x65, 0x78, 0x65,
0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x03,
0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x32, 0x30, 0x52, 0x10, 0x65, 0x78,
0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x16,
0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06,
0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0xd8, 0x01, 0x0a, 0x0b, 0x42, 0x6c, 0x6f, 0x62, 0x73,
0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x12, 0x25, 0x0a, 0x0a, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f,
0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02,
0x33, 0x32, 0x52, 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x12, 0x37, 0x0a,
0x0f, 0x6b, 0x7a, 0x67, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x73,
0x18, 0x02, 0x20, 0x03, 0x28, 0x0c, 0x42, 0x0e, 0x8a, 0xb5, 0x18, 0x04, 0x3f, 0x2c, 0x34, 0x38,
0x92, 0xb5, 0x18, 0x02, 0x31, 0x36, 0x52, 0x0e, 0x6b, 0x7a, 0x67, 0x43, 0x6f, 0x6d, 0x6d, 0x69,
0x74, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x36, 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x62, 0x73, 0x18,
0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d,
0x2e, 0x65, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x6c, 0x6f, 0x62, 0x42,
0x06, 0x92, 0xb5, 0x18, 0x02, 0x31, 0x36, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x62, 0x73, 0x12, 0x31,
0x0a, 0x10, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x70, 0x72, 0x6f,
0x6f, 0x66, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x34, 0x38,
0x52, 0x0f, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x6f,
0x66, 0x22, 0x26, 0x0a, 0x04, 0x42, 0x6c, 0x6f, 0x62, 0x12, 0x1e, 0x0a, 0x04, 0x64, 0x61, 0x74,
0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x0a, 0x8a, 0xb5, 0x18, 0x06, 0x31, 0x33, 0x31,
0x30, 0x37, 0x32, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x42, 0x96, 0x01, 0x0a, 0x16, 0x6f, 0x72,
0x67, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x6e, 0x67, 0x69, 0x6e,
0x65, 0x2e, 0x76, 0x31, 0x42, 0x14, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x45,
0x6e, 0x67, 0x69, 0x6e, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3a, 0x67, 0x69,
0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x61, 0x74,
0x69, 0x63, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x2f, 0x76, 0x33, 0x2f,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x65, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x2f, 0x76, 0x31, 0x3b,
0x65, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x76, 0x31, 0xaa, 0x02, 0x12, 0x45, 0x74, 0x68, 0x65, 0x72,
0x65, 0x75, 0x6d, 0x2e, 0x45, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x12,
0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x5c, 0x45, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x5c,
0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x6b, 0x48, 0x61, 0x73, 0x68, 0x22, 0xd6, 0x01, 0x0a, 0x0a, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72,
0x61, 0x77, 0x61, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20,
0x01, 0x28, 0x04, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x78, 0x0a, 0x0f, 0x76, 0x61,
0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20,
0x01, 0x28, 0x04, 0x42, 0x4f, 0x82, 0xb5, 0x18, 0x4b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x6c, 0x61, 0x62,
0x73, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x2f, 0x76, 0x33, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x65,
0x6e, 0x73, 0x75, 0x73, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x70, 0x72, 0x69, 0x6d, 0x69,
0x74, 0x69, 0x76, 0x65, 0x73, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x49,
0x6e, 0x64, 0x65, 0x78, 0x52, 0x0e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x49,
0x6e, 0x64, 0x65, 0x78, 0x12, 0x20, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18,
0x03, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x32, 0x30, 0x52, 0x07, 0x61,
0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74,
0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0xd8,
0x01, 0x0a, 0x0b, 0x42, 0x6c, 0x6f, 0x62, 0x73, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x12, 0x25,
0x0a, 0x0a, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01,
0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x33, 0x32, 0x52, 0x09, 0x62, 0x6c, 0x6f, 0x63,
0x6b, 0x48, 0x61, 0x73, 0x68, 0x12, 0x37, 0x0a, 0x0f, 0x6b, 0x7a, 0x67, 0x5f, 0x63, 0x6f, 0x6d,
0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0c, 0x42, 0x0e,
0x8a, 0xb5, 0x18, 0x04, 0x3f, 0x2c, 0x34, 0x38, 0x92, 0xb5, 0x18, 0x02, 0x31, 0x36, 0x52, 0x0e,
0x6b, 0x7a, 0x67, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x36,
0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x62, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e,
0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x2e,
0x76, 0x31, 0x2e, 0x42, 0x6c, 0x6f, 0x62, 0x42, 0x06, 0x92, 0xb5, 0x18, 0x02, 0x31, 0x36, 0x52,
0x05, 0x62, 0x6c, 0x6f, 0x62, 0x73, 0x12, 0x31, 0x0a, 0x10, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67,
0x61, 0x74, 0x65, 0x64, 0x5f, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c,
0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x34, 0x38, 0x52, 0x0f, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67,
0x61, 0x74, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x22, 0x26, 0x0a, 0x04, 0x42, 0x6c, 0x6f,
0x62, 0x12, 0x1e, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x42,
0x0a, 0x8a, 0xb5, 0x18, 0x06, 0x31, 0x33, 0x31, 0x30, 0x37, 0x32, 0x52, 0x04, 0x64, 0x61, 0x74,
0x61, 0x42, 0x96, 0x01, 0x0a, 0x16, 0x6f, 0x72, 0x67, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65,
0x75, 0x6d, 0x2e, 0x65, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x42, 0x14, 0x45, 0x78,
0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x50, 0x72, 0x6f,
0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x70,
0x72, 0x79, 0x73, 0x6d, 0x2f, 0x76, 0x33, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x65, 0x6e,
0x67, 0x69, 0x6e, 0x65, 0x2f, 0x76, 0x31, 0x3b, 0x65, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x76, 0x31,
0xaa, 0x02, 0x12, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x45, 0x6e, 0x67, 0x69,
0x6e, 0x65, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x12, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d,
0x5c, 0x45, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x5c, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x33,
}
var (

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