mirror of
https://gitlab.com/pulsechaincom/erigon-pulse.git
synced 2024-12-31 16:21:21 +00:00
436493350e
1. changes sentinel to use an http-like interface 2. moves hexutil, crypto/blake2b, metrics packages to erigon-lib
262 lines
7.3 KiB
Go
262 lines
7.3 KiB
Go
package consensus_tests
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"github.com/ledgerwatch/erigon/spectest"
|
|
"io/fs"
|
|
"testing"
|
|
|
|
"github.com/ledgerwatch/erigon/cl/abstract"
|
|
"github.com/ledgerwatch/erigon/cl/clparams"
|
|
"github.com/ledgerwatch/erigon/cl/cltypes/solid"
|
|
"github.com/ledgerwatch/erigon/cl/phase1/forkchoice"
|
|
"github.com/ledgerwatch/erigon/cl/phase1/forkchoice/fork_graph"
|
|
"github.com/ledgerwatch/erigon/cl/pool"
|
|
"github.com/spf13/afero"
|
|
|
|
"github.com/ledgerwatch/erigon-lib/common"
|
|
"github.com/ledgerwatch/erigon/cl/cltypes"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func (f *ForkChoiceStep) StepType() string {
|
|
if f.PayloadStatus != nil {
|
|
return "on_payload_info"
|
|
}
|
|
if f.AttesterSlashing != nil {
|
|
return "on_attester_slashing"
|
|
}
|
|
if f.PowBlock != nil {
|
|
return "on_merge_block"
|
|
}
|
|
if f.Block != nil {
|
|
return "on_block"
|
|
}
|
|
if f.Attestation != nil {
|
|
return "attestation"
|
|
}
|
|
if f.Tick != nil {
|
|
return "on_tick"
|
|
}
|
|
if f.Checks != nil {
|
|
return "checks"
|
|
}
|
|
return "unknown"
|
|
}
|
|
|
|
type ForkChoiceStep struct {
|
|
Tick *int `yaml:"tick,omitempty"`
|
|
Valid *bool `yaml:"valid,omitempty"`
|
|
Attestation *string `yaml:"attestation,omitempty"`
|
|
Block *string `yaml:"block,omitempty"`
|
|
PowBlock *string `yaml:"pow_block,omitempty"`
|
|
AttesterSlashing *string `yaml:"attester_slashing,omitempty"`
|
|
BlockHash *string `yaml:"block_hash,omitempty"`
|
|
PayloadStatus *ForkChoicePayloadStatus `yaml:"payload_status,omitempty"`
|
|
Checks *ForkChoiceChecks `yaml:"checks,omitempty"`
|
|
}
|
|
|
|
func (f *ForkChoiceStep) GetTick() int {
|
|
if f.Tick == nil {
|
|
return 0
|
|
}
|
|
return *f.Tick
|
|
}
|
|
func (f *ForkChoiceStep) GetValid() bool {
|
|
if f.Valid == nil {
|
|
return true
|
|
}
|
|
return *f.Valid
|
|
}
|
|
func (f *ForkChoiceStep) GetAttestation() string {
|
|
if f.Attestation == nil {
|
|
return ""
|
|
}
|
|
return *f.Attestation
|
|
}
|
|
func (f *ForkChoiceStep) GetBlock() string {
|
|
if f.Block == nil {
|
|
return ""
|
|
}
|
|
return *f.Block
|
|
}
|
|
func (f *ForkChoiceStep) GetPowBlock() string {
|
|
if f.PowBlock == nil {
|
|
return ""
|
|
}
|
|
return *f.PowBlock
|
|
}
|
|
func (f *ForkChoiceStep) GetAttesterSlashing() string {
|
|
if f.AttesterSlashing == nil {
|
|
return ""
|
|
}
|
|
return *f.AttesterSlashing
|
|
}
|
|
func (f *ForkChoiceStep) GetBlockHash() string {
|
|
if f.BlockHash == nil {
|
|
return ""
|
|
}
|
|
return *f.BlockHash
|
|
}
|
|
func (f *ForkChoiceStep) GetPayloadStatus() *ForkChoicePayloadStatus {
|
|
if f.PayloadStatus == nil {
|
|
return nil
|
|
}
|
|
return f.PayloadStatus
|
|
}
|
|
func (f *ForkChoiceStep) GetChecks() *ForkChoiceChecks {
|
|
if f.Checks == nil {
|
|
return nil
|
|
}
|
|
return f.Checks
|
|
}
|
|
|
|
type ForkChoiceChecks struct {
|
|
Head *struct {
|
|
Slot *int `yaml:"slot,omitempty"`
|
|
Root *common.Hash `yaml:"root,omitempty"`
|
|
} `yaml:"head,omitempty"`
|
|
Time *int `yaml:"time,omitempty"`
|
|
GenesisTime *int `yaml:"genesis_time,omitempty"`
|
|
JustifiedCheckpoint *struct {
|
|
Epoch *int `yaml:"epoch,omitempty"`
|
|
Root *common.Hash `yaml:"root,omitempty"`
|
|
} `yaml:"justified_checkpoint,omitempty"`
|
|
|
|
FinalizedCheckpoint *struct {
|
|
Epoch *int `yaml:"epoch,omitempty"`
|
|
Root *common.Hash `yaml:"root,omitempty"`
|
|
} `yaml:"finalized_checkpoint,omitempty"`
|
|
ProposerBoostRoot *common.Hash `yaml:"proposer_boost_root,omitempty"`
|
|
}
|
|
|
|
type ForkChoicePayloadStatus struct {
|
|
Status string `yaml:"status"`
|
|
LatestValidHash string `yaml:"latest_valid_hash"`
|
|
ValidationError string `yaml:"validation_error"`
|
|
}
|
|
|
|
type ForkChoice struct {
|
|
}
|
|
|
|
func NewForkChoice(fn func(s abstract.BeaconState) error) *ForkChoice {
|
|
return &ForkChoice{}
|
|
}
|
|
|
|
func (b *ForkChoice) Run(t *testing.T, root fs.FS, c spectest.TestCase) (err error) {
|
|
anchorBlock, err := spectest.ReadAnchorBlock(root, c.Version(), "anchor_block.ssz_snappy")
|
|
require.NoError(t, err)
|
|
|
|
// TODO: what to do with anchor block ?
|
|
_ = anchorBlock
|
|
|
|
anchorState, err := spectest.ReadBeaconState(root, c.Version(), "anchor_state.ssz_snappy")
|
|
require.NoError(t, err)
|
|
|
|
forkStore, err := forkchoice.NewForkChoiceStore(context.Background(), anchorState, nil, nil, pool.NewOperationsPool(&clparams.MainnetBeaconConfig), fork_graph.NewForkGraphDisk(anchorState, afero.NewMemMapFs()))
|
|
require.NoError(t, err)
|
|
|
|
var steps []ForkChoiceStep
|
|
err = spectest.ReadYml(root, "steps.yaml", &steps)
|
|
require.NoError(t, err)
|
|
|
|
for stepIdx, step := range steps {
|
|
stepstr := fmt.Sprintf("step %d: %s", stepIdx, step.StepType())
|
|
switch step.StepType() {
|
|
case "on_payload_info":
|
|
// we are not doing engine level mocking, so simply return the test when this is received
|
|
return nil
|
|
case "on_attester_slashing":
|
|
data := &cltypes.AttesterSlashing{}
|
|
err := spectest.ReadSsz(root, c.Version(), step.GetAttesterSlashing()+".ssz_snappy", data)
|
|
require.NoError(t, err, stepstr)
|
|
err = forkStore.OnAttesterSlashing(data, false)
|
|
if step.GetValid() {
|
|
require.NoError(t, err, stepstr)
|
|
} else {
|
|
require.Error(t, err, stepstr)
|
|
}
|
|
case "on_merge_block":
|
|
return nil
|
|
case "on_block":
|
|
blk := cltypes.NewSignedBeaconBlock(anchorState.BeaconConfig())
|
|
err := spectest.ReadSsz(root, c.Version(), step.GetBlock()+".ssz_snappy", blk)
|
|
require.NoError(t, err, stepstr)
|
|
err = forkStore.OnBlock(blk, true, true)
|
|
if step.GetValid() {
|
|
require.NoError(t, err, stepstr)
|
|
} else {
|
|
require.Error(t, err, stepstr)
|
|
}
|
|
case "attestation":
|
|
att := &solid.Attestation{}
|
|
err := spectest.ReadSsz(root, c.Version(), step.GetAttestation()+".ssz_snappy", att)
|
|
require.NoError(t, err, stepstr)
|
|
err = forkStore.OnAttestation(att, false)
|
|
if step.GetValid() {
|
|
require.NoError(t, err, stepstr)
|
|
} else {
|
|
require.Error(t, err, stepstr)
|
|
}
|
|
case "on_tick":
|
|
forkStore.OnTick(uint64(step.GetTick()))
|
|
//TODO: onTick needs to be able to return error
|
|
// if step.GetValid() {
|
|
// require.NoError(t, err)
|
|
// } else {
|
|
// require.Error(t, err)
|
|
// }
|
|
case "checks":
|
|
chk := step.GetChecks()
|
|
doCheck(t, stepstr, forkStore, chk)
|
|
default:
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func doCheck(t *testing.T, stepstr string, store *forkchoice.ForkChoiceStore, e *ForkChoiceChecks) {
|
|
if e.Head != nil {
|
|
root, v, err := store.GetHead()
|
|
require.NoError(t, err, stepstr)
|
|
if e.Head.Root != nil {
|
|
assert.EqualValues(t, *e.Head.Root, root, stepstr)
|
|
}
|
|
if e.Head.Slot != nil {
|
|
assert.EqualValues(t, *e.Head.Slot, int(v), stepstr)
|
|
}
|
|
}
|
|
if e.Time != nil {
|
|
assert.EqualValues(t, *e.Time, store.Time(), stepstr)
|
|
}
|
|
/*if e.GenesisTime != nil {
|
|
// TODO: what value to use here??
|
|
//assert.EqualValues(t, e.Time, store.GenesisTime())
|
|
}*/
|
|
if e.ProposerBoostRoot != nil {
|
|
assert.EqualValues(t, *e.ProposerBoostRoot, store.ProposerBoostRoot(), stepstr)
|
|
}
|
|
|
|
if e.FinalizedCheckpoint != nil {
|
|
cp := store.FinalizedCheckpoint()
|
|
if e.FinalizedCheckpoint.Root != nil {
|
|
assert.EqualValues(t, *e.FinalizedCheckpoint.Root, cp.BlockRoot(), stepstr)
|
|
}
|
|
if e.FinalizedCheckpoint.Epoch != nil {
|
|
assert.EqualValues(t, *e.FinalizedCheckpoint.Epoch, cp.Epoch(), stepstr)
|
|
}
|
|
}
|
|
if e.JustifiedCheckpoint != nil {
|
|
cp := store.JustifiedCheckpoint()
|
|
if e.JustifiedCheckpoint.Root != nil {
|
|
assert.EqualValues(t, *e.JustifiedCheckpoint.Root, cp.BlockRoot(), stepstr)
|
|
}
|
|
if e.JustifiedCheckpoint.Epoch != nil {
|
|
assert.EqualValues(t, *e.JustifiedCheckpoint.Epoch, cp.Epoch(), stepstr)
|
|
}
|
|
}
|
|
}
|