Restore forkchoice dump endpoint. (#11312)

* Restore forkchoice dump endpoint.

Only working on doubly-linked-tree.

* unit test

* revert proto changes

* protoarray

* Deepsource

* shut up!

Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
This commit is contained in:
Potuz
2022-08-25 20:37:23 -03:00
committed by GitHub
parent a2193ee014
commit e1f56d403c
16 changed files with 843 additions and 258 deletions

View File

@@ -18,6 +18,7 @@ go_library(
"//beacon-chain/state:go_default_library",
"//config/fieldparams:go_default_library",
"//consensus-types/primitives:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"@com_github_pkg_errors//:go_default_library",
],
)

View File

@@ -612,3 +612,52 @@ func (f *ForkChoice) JustifiedPayloadBlockHash() [32]byte {
}
return node.payloadHash
}
// ForkchoiceDump returns a full dump of forkhoice.
func (f *ForkChoice) ForkChoiceDump(ctx context.Context) (*ethpb.ForkChoiceResponse, error) {
jc := &ethpb.Checkpoint{
Epoch: f.store.justifiedCheckpoint.Epoch,
Root: f.store.justifiedCheckpoint.Root[:],
}
bjc := &ethpb.Checkpoint{
Epoch: f.store.bestJustifiedCheckpoint.Epoch,
Root: f.store.bestJustifiedCheckpoint.Root[:],
}
ujc := &ethpb.Checkpoint{
Epoch: f.store.unrealizedJustifiedCheckpoint.Epoch,
Root: f.store.unrealizedJustifiedCheckpoint.Root[:],
}
fc := &ethpb.Checkpoint{
Epoch: f.store.finalizedCheckpoint.Epoch,
Root: f.store.finalizedCheckpoint.Root[:],
}
ufc := &ethpb.Checkpoint{
Epoch: f.store.unrealizedFinalizedCheckpoint.Epoch,
Root: f.store.unrealizedFinalizedCheckpoint.Root[:],
}
nodes := make([]*ethpb.ForkChoiceNode, 0, f.NodeCount())
var err error
if f.store.treeRootNode != nil {
nodes, err = f.store.treeRootNode.nodeTreeDump(ctx, nodes)
if err != nil {
return nil, err
}
}
var headRoot [32]byte
if f.store.headNode != nil {
headRoot = f.store.headNode.root
}
resp := &ethpb.ForkChoiceResponse{
JustifiedCheckpoint: jc,
BestJustifiedCheckpoint: bjc,
UnrealizedJustifiedCheckpoint: ujc,
FinalizedCheckpoint: fc,
UnrealizedFinalizedCheckpoint: ufc,
ProposerBoostRoot: f.store.proposerBoostRoot[:],
PreviousProposerBoostRoot: f.store.previousProposerBoostRoot[:],
HeadRoot: headRoot[:],
ForkchoiceNodes: nodes,
}
return resp, nil
}

View File

@@ -7,6 +7,7 @@ import (
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v3/config/params"
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
)
// depth returns the length of the path to the root of Fork Choice
@@ -126,3 +127,37 @@ func (n *Node) setNodeAndParentValidated(ctx context.Context) error {
}
return n.parent.setNodeAndParentValidated(ctx)
}
// nodeTreeDump appends to the given list all the nodes descending from this one
func (n *Node) nodeTreeDump(ctx context.Context, nodes []*ethpb.ForkChoiceNode) ([]*ethpb.ForkChoiceNode, error) {
if ctx.Err() != nil {
return nil, ctx.Err()
}
var parentRoot [32]byte
if n.parent != nil {
parentRoot = n.parent.root
}
thisNode := &ethpb.ForkChoiceNode{
Slot: n.slot,
Root: n.root[:],
ParentRoot: parentRoot[:],
JustifiedEpoch: n.justifiedEpoch,
FinalizedEpoch: n.finalizedEpoch,
UnrealizedJustifiedEpoch: n.unrealizedJustifiedEpoch,
UnrealizedFinalizedEpoch: n.unrealizedFinalizedEpoch,
Balance: n.balance,
Weight: n.weight,
ExecutionOptimistic: n.optimistic,
ExecutionPayload: n.payloadHash[:],
}
nodes = append(nodes, thisNode)
var err error
for _, child := range n.children {
nodes, err = child.nodeTreeDump(ctx, nodes)
if err != nil {
return nil, err
}
}
return nodes, nil
}

View File

@@ -6,6 +6,7 @@ import (
"github.com/prysmaticlabs/prysm/v3/config/params"
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v3/testing/assert"
"github.com/prysmaticlabs/prysm/v3/testing/require"
)
@@ -206,6 +207,8 @@ func TestNode_LeadsToViableHead(t *testing.T) {
func TestNode_SetFullyValidated(t *testing.T) {
f := setup(1, 1)
ctx := context.Background()
storeNodes := make([]*Node, 6)
storeNodes[0] = f.store.treeRootNode
// insert blocks in the fork pattern (optimistic status in parenthesis)
//
// 0 (false) -- 1 (false) -- 2 (false) -- 3 (true) -- 4 (true)
@@ -215,20 +218,25 @@ func TestNode_SetFullyValidated(t *testing.T) {
state, blkRoot, err := prepareForkchoiceState(ctx, 1, indexToHash(1), params.BeaconConfig().ZeroHash, params.BeaconConfig().ZeroHash, 1, 1)
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
storeNodes[1] = f.store.nodeByRoot[blkRoot]
require.NoError(t, f.SetOptimisticToValid(ctx, params.BeaconConfig().ZeroHash))
state, blkRoot, err = prepareForkchoiceState(ctx, 2, indexToHash(2), indexToHash(1), params.BeaconConfig().ZeroHash, 1, 1)
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
storeNodes[2] = f.store.nodeByRoot[blkRoot]
require.NoError(t, f.SetOptimisticToValid(ctx, indexToHash(1)))
state, blkRoot, err = prepareForkchoiceState(ctx, 3, indexToHash(3), indexToHash(2), params.BeaconConfig().ZeroHash, 1, 1)
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
storeNodes[3] = f.store.nodeByRoot[blkRoot]
state, blkRoot, err = prepareForkchoiceState(ctx, 4, indexToHash(4), indexToHash(3), params.BeaconConfig().ZeroHash, 1, 1)
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
storeNodes[4] = f.store.nodeByRoot[blkRoot]
state, blkRoot, err = prepareForkchoiceState(ctx, 5, indexToHash(5), indexToHash(1), params.BeaconConfig().ZeroHash, 1, 1)
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
storeNodes[5] = f.store.nodeByRoot[blkRoot]
opt, err := f.IsOptimistic(indexToHash(5))
require.NoError(t, err)
@@ -253,4 +261,21 @@ func TestNode_SetFullyValidated(t *testing.T) {
opt, err = f.IsOptimistic(indexToHash(3))
require.NoError(t, err)
require.Equal(t, false, opt)
respNodes := make([]*ethpb.ForkChoiceNode, 0)
respNodes, err = f.store.treeRootNode.nodeTreeDump(ctx, respNodes)
require.NoError(t, err)
require.Equal(t, len(respNodes), f.NodeCount())
for i, respNode := range respNodes {
require.Equal(t, storeNodes[i].slot, respNode.Slot)
require.DeepEqual(t, storeNodes[i].root[:], respNode.Root)
require.Equal(t, storeNodes[i].balance, respNode.Balance)
require.Equal(t, storeNodes[i].weight, respNode.Weight)
require.Equal(t, storeNodes[i].optimistic, respNode.ExecutionOptimistic)
require.Equal(t, storeNodes[i].justifiedEpoch, respNode.JustifiedEpoch)
require.Equal(t, storeNodes[i].unrealizedJustifiedEpoch, respNode.UnrealizedJustifiedEpoch)
require.Equal(t, storeNodes[i].finalizedEpoch, respNode.FinalizedEpoch)
require.Equal(t, storeNodes[i].unrealizedFinalizedEpoch, respNode.UnrealizedFinalizedEpoch)
}
}

View File

@@ -7,6 +7,7 @@ import (
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state"
fieldparams "github.com/prysmaticlabs/prysm/v3/config/fieldparams"
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
)
// ForkChoicer represents the full fork choice interface composed of all the sub-interfaces.
@@ -62,6 +63,7 @@ type Getter interface {
NodeCount() int
HighestReceivedBlockSlot() types.Slot
ReceivedBlocksLastEpoch() (uint64, error)
ForkChoiceDump(context.Context) (*ethpb.ForkChoiceResponse, error)
}
// Setter allows to set forkchoice information

View File

@@ -1079,3 +1079,7 @@ func (f *ForkChoice) ReceivedBlocksLastEpoch() (uint64, error) {
}
return count, nil
}
func (*ForkChoice) ForkChoiceDump(_ context.Context) (*ethpb.ForkChoiceResponse, error) {
return nil, errors.New("ForkChoiceDump is not supported by protoarray")
}

View File

@@ -4,6 +4,7 @@ go_library(
name = "go_default_library",
srcs = [
"block.go",
"forkchoice.go",
"p2p.go",
"server.go",
"state.go",
@@ -38,6 +39,7 @@ go_test(
name = "go_default_test",
srcs = [
"block_test.go",
"forkchoice_test.go",
"p2p_test.go",
"state_test.go",
],
@@ -46,6 +48,8 @@ go_test(
"//beacon-chain/blockchain/testing:go_default_library",
"//beacon-chain/core/helpers:go_default_library",
"//beacon-chain/db/testing:go_default_library",
"//beacon-chain/forkchoice/doubly-linked-tree:go_default_library",
"//beacon-chain/forkchoice/types:go_default_library",
"//beacon-chain/p2p/testing:go_default_library",
"//beacon-chain/state/stategen:go_default_library",
"//beacon-chain/state/stategen/mock:go_default_library",

View File

@@ -0,0 +1,13 @@
package debug
import (
"context"
"github.com/golang/protobuf/ptypes/empty"
pbrpc "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
)
// GetForkChoice returns a dump fork choice store.
func (ds *Server) GetForkChoice(ctx context.Context, _ *empty.Empty) (*pbrpc.ForkChoiceResponse, error) {
return ds.ForkFetcher.ForkChoicer().ForkChoiceDump(ctx)
}

View File

@@ -0,0 +1,28 @@
package debug
import (
"context"
"testing"
"github.com/golang/protobuf/ptypes/empty"
mock "github.com/prysmaticlabs/prysm/v3/beacon-chain/blockchain/testing"
doublylinkedtree "github.com/prysmaticlabs/prysm/v3/beacon-chain/forkchoice/doubly-linked-tree"
forkchoicetypes "github.com/prysmaticlabs/prysm/v3/beacon-chain/forkchoice/types"
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v3/testing/require"
)
func TestServer_GetForkChoice(t *testing.T) {
store := doublylinkedtree.New()
fRoot := [32]byte{'a'}
jRoot := [32]byte{'b'}
fc := &forkchoicetypes.Checkpoint{Epoch: 2, Root: fRoot}
jc := &forkchoicetypes.Checkpoint{Epoch: 3, Root: jRoot}
require.NoError(t, store.UpdateFinalizedCheckpoint(fc))
require.NoError(t, store.UpdateJustifiedCheckpoint(jc))
bs := &Server{ForkFetcher: &mock.ChainService{ForkChoiceStore: store}}
res, err := bs.GetForkChoice(context.Background(), &empty.Empty{})
require.NoError(t, err)
require.Equal(t, types.Epoch(3), res.JustifiedCheckpoint.Epoch, "Did not get wanted justified epoch")
require.Equal(t, types.Epoch(2), res.FinalizedCheckpoint.Epoch, "Did not get wanted finalized epoch")
}

View File

@@ -28,6 +28,7 @@ type Server struct {
GenesisTimeFetcher blockchain.TimeFetcher
StateGen *stategen.State
HeadFetcher blockchain.HeadFetcher
ForkFetcher blockchain.ForkFetcher
PeerManager p2p.PeerManager
PeersFetcher p2p.PeersProvider
ReplayerBuilder stategen.ReplayerBuilder

View File

@@ -336,6 +336,7 @@ func (s *Service) Start() {
BeaconDB: s.cfg.BeaconDB,
StateGen: s.cfg.StateGen,
HeadFetcher: s.cfg.HeadFetcher,
ForkFetcher: s.cfg.ForkFetcher,
PeerManager: s.cfg.PeerManager,
PeersFetcher: s.cfg.PeersFetcher,
ReplayerBuilder: ch,

View File

@@ -1,5 +1,5 @@
// Code generated by fastssz. DO NOT EDIT.
// Hash: ad51a4b973de342442a318504b01cb08f7a593b3fbf85ba975661d30f9fab45b
// Hash: 63cd476809ef83858e4cec3d59394a44f6ca0b3d7f00ad5a1307cb4bcbf8f1e1
package v1
import (

View File

@@ -1,5 +1,5 @@
// Code generated by fastssz. DO NOT EDIT.
// Hash: 963b5caa78ce8e108d0839e5e6555aef3b6ae2f0deae5b5eac6b47a36683506c
// Hash: ae3cb8e10550566178c17ab0fda3b1391784159840f50d8dee9e66f45e4c3041
package eth
import (

File diff suppressed because it is too large Load Diff

View File

@@ -7,6 +7,7 @@ import "proto/prysm/v1alpha1/node.proto";
import "proto/prysm/v1alpha1/p2p_messages.proto";
import "google/api/annotations.proto";
import "google/protobuf/empty.proto";
import "proto/prysm/v1alpha1/attestation.proto";
option csharp_namespace = "Ethereum.Eth.V1alpha1";
option go_package = "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1;eth";
@@ -97,6 +98,54 @@ message LoggingLevelRequest {
Level level = 1;
}
message ForkChoiceResponse {
// Latest justified checkpoint in forkchoice store.
Checkpoint justified_checkpoint = 1;
// Latest finalized checkpoint in forkchoice store.
Checkpoint finalized_checkpoint = 2;
// Best justified checkpoint in forkchoice store.
Checkpoint best_justified_checkpoint = 3;
// Unrealized justified checkpoint in forkchoice store.
Checkpoint unrealized_justified_checkpoint = 4;
// Unrealized finalized checkpoint in forkchoice store.
Checkpoint unrealized_finalized_checkpoint = 5;
// Proposer Boost Root in forkchoice store.
bytes proposer_boost_root = 6 [(ethereum.eth.ext.ssz_size) = "32"];
// Previous proposer Boost Root in forkchoice store.
bytes previous_proposer_boost_root = 7 [(ethereum.eth.ext.ssz_size) = "32"];
// Head root in forkchoice store.
bytes head_root = 8 [(ethereum.eth.ext.ssz_size) = "32"];
// The list of the forkchoice nodes in store.
repeated ForkChoiceNode forkchoice_nodes = 9;
}
message ForkChoiceNode {
// Slot of the forkchoice node.
uint64 slot = 1 [(ethereum.eth.ext.cast_type) = "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives.Slot"];
// Root of the forkchoice node.
bytes root = 2 [(ethereum.eth.ext.ssz_size) = "32"];
// Parent root of the forkchoice node.
bytes parent_root = 3 [(ethereum.eth.ext.ssz_size) = "32"];
// Justified epoch of the current forkchoice node.
uint64 justified_epoch = 4 [(ethereum.eth.ext.cast_type) = "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives.Epoch"];
// finalized epoch of the current forkchoice node.
uint64 finalized_epoch = 5 [(ethereum.eth.ext.cast_type) = "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives.Epoch"];
// Unrealized justified epoch of the current forkchoice node.
uint64 unrealized_justified_epoch = 6 [(ethereum.eth.ext.cast_type) = "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives.Epoch"];
// Unrealized finalized epoch of the current forkchoice node.
uint64 unrealized_finalized_epoch = 7 [(ethereum.eth.ext.cast_type) = "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives.Epoch"];
// Current balance of the current forkchoice node.
uint64 balance = 8;
// Current weight of the current forkchoice node.
uint64 weight = 9;
// Optimistic status of the current forkchoice node.
bool execution_optimistic = 10;
// Execution payload block hash of the current forkchoice node.
bytes execution_payload = 11 [(ethereum.eth.ext.ssz_size) = "32"];
}
message DebugPeerResponses {
repeated DebugPeerResponse responses = 1;
}

View File

@@ -1,5 +1,5 @@
// Code generated by fastssz. DO NOT EDIT.
// Hash: 5e2a4b9f444ea4a724365be701c6d0b8e40c0d4c5cd2d7dd9f9fddad02c8928d
// Hash: 069828a9448f866cb491192b13a4ab076a2510e07c3fa8031de0507240bd6bb5
package eth
import (