Skip to content

Commit

Permalink
drop blinded block rejection (#305)
Browse files Browse the repository at this point in the history
* drop blinded block rejection

* generate JSONs

* Added test for Runner receiving different type of block (normal/blinded)

* Merge with branch 'main'

* Separate blinded test from full happy flow test

* Move tests; Add tests to all_tests file

* Revert to previous types/tests.json

---------

Co-authored-by: Matheus Franco <[email protected]>
  • Loading branch information
moshe-blox and MatheusFranco99 authored Sep 11, 2023
1 parent 384b025 commit 8fd4372
Show file tree
Hide file tree
Showing 14 changed files with 5,237 additions and 25 deletions.
2 changes: 2 additions & 0 deletions ssv/spectest/all_tests.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ var AllTests = []tests.TestF{

proposer.ProposeBlindedBlockDecidedRegular,
proposer.ProposeRegularBlockDecidedBlinded,
proposer.BlindedRunnerAcceptsNormalBlock,
proposer.NormalProposerAcceptsBlindedBlock,

// pre_consensus_justifications.PastSlot,
// pre_consensus_justifications.InvalidData,
Expand Down

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion ssv/spectest/generate/tests.json

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package proposer

import (
"fmt"

"github.com/attestantio/go-eth2-client/spec"

"github.com/bloxapp/ssv-spec/ssv/spectest/tests"
"github.com/bloxapp/ssv-spec/types"
"github.com/bloxapp/ssv-spec/types/testingutils"
)

// BlindedRunnerAcceptsNormalBlock tests a full happy flow for a proposer runner that produces blinded blocks but receives as proposal a normal block
func BlindedRunnerAcceptsNormalBlock() tests.SpecTest {
ks := testingutils.Testing4SharesSet()

multiSpecTest := &tests.MultiMsgProcessingSpecTest{
Name: "blinded proposer accepts normal block proposal",
Tests: []*tests.MsgProcessingSpecTest{},
}

// proposerBlindedReceivingNormalBlockV creates a test specification for versioned blinded proposer receiving a normal block.
proposerBlindedReceivingNormalBlockV := func(version spec.DataVersion) *tests.MsgProcessingSpecTest {
return &tests.MsgProcessingSpecTest{
Name: fmt.Sprintf("blinded proposer accepts normal block proposal (%s)", version.String()),
Runner: testingutils.ProposerBlindedBlockRunner(ks),
Duty: testingutils.TestingProposerDutyV(version),
Messages: append(
testingutils.SSVDecidingMsgsV(testingutils.TestProposerConsensusDataV(version), ks, types.BNRoleProposer), // consensus
[]*types.SSVMessage{ // post consensus
testingutils.SSVMsgProposer(nil, testingutils.PostConsensusProposerMsgV(ks.Shares[1], 1, version)),
testingutils.SSVMsgProposer(nil, testingutils.PostConsensusProposerMsgV(ks.Shares[2], 2, version)),
testingutils.SSVMsgProposer(nil, testingutils.PostConsensusProposerMsgV(ks.Shares[3], 3, version)),
}...,
),
PostDutyRunnerStateRoot: fullHappyFlowBlindedProposerReceivingNormalBlockSC(version).Root(),
PostDutyRunnerState: fullHappyFlowBlindedProposerReceivingNormalBlockSC(version).ExpectedState,
OutputMessages: []*types.SignedPartialSignatureMessage{
testingutils.PreConsensusRandaoMsgV(ks.Shares[1], 1, version),
testingutils.PostConsensusProposerMsgV(ks.Shares[1], 1, version),
},
BeaconBroadcastedRoots: []string{
testingutils.GetSSZRootNoError(testingutils.TestingSignedBeaconBlockV(ks, version)),
},
}
}

for _, v := range testingutils.SupportedBlockVersions {
multiSpecTest.Tests = append(multiSpecTest.Tests, []*tests.MsgProcessingSpecTest{proposerBlindedReceivingNormalBlockV(v)}...)
}
return multiSpecTest
}
124 changes: 124 additions & 0 deletions ssv/spectest/tests/runner/duties/proposer/blinded_sc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package proposer

import (
"github.com/attestantio/go-eth2-client/spec"

"github.com/bloxapp/ssv-spec/qbft"
"github.com/bloxapp/ssv-spec/ssv"
ssvcomparable "github.com/bloxapp/ssv-spec/ssv/spectest/comparable"
"github.com/bloxapp/ssv-spec/types"
"github.com/bloxapp/ssv-spec/types/testingutils"
"github.com/bloxapp/ssv-spec/types/testingutils/comparable"
)

// fullHappyFlowProposerReceivingBlindedBlockSC returns state comparison object for the FullHappyFlow for a normal Proposer receiving a Blinded Block versioned spec test
func fullHappyFlowProposerReceivingBlindedBlockSC(version spec.DataVersion) *comparable.StateComparison {
ks := testingutils.Testing4SharesSet()
// consensus data used for message creation
cd := testingutils.TestProposerBlindedBlockConsensusDataV(version)
// encoded consensus data relative to messages
cdBytes := testingutils.TestProposerBlindedBlockConsensusDataBytsV(version)
// encoded consensus data that the runner set as StartValue
startedCdBytes := testingutils.TestProposerConsensusDataBytsV(version)

return &comparable.StateComparison{
ExpectedState: func() ssv.Runner {
ret := testingutils.ProposerRunner(ks)
ret.GetBaseRunner().State = &ssv.State{
PreConsensusContainer: ssvcomparable.SetMessagesInContainer(
ssv.NewPartialSigContainer(3),
testingutils.ExpectedSSVDecidingMsgsV(cd, ks, types.BNRoleProposer)[:3],
),
PostConsensusContainer: ssvcomparable.SetMessagesInContainer(
ssv.NewPartialSigContainer(3),
[]*types.SSVMessage{
testingutils.SSVMsgProposer(nil, testingutils.PostConsensusProposerMsgV(ks.Shares[1], 1, version)),
testingutils.SSVMsgProposer(nil, testingutils.PostConsensusProposerMsgV(ks.Shares[2], 2, version)),
testingutils.SSVMsgProposer(nil, testingutils.PostConsensusProposerMsgV(ks.Shares[3], 3, version)),
},
),
DecidedValue: comparable.FixIssue178(cd, version),
StartingDuty: &testingutils.TestProposerConsensusDataV(version).Duty,
Finished: true,
}
ret.GetBaseRunner().State.RunningInstance = &qbft.Instance{
State: &qbft.State{
Share: testingutils.TestingShare(ks),
ID: ret.GetBaseRunner().QBFTController.Identifier,
Round: qbft.FirstRound,
Height: qbft.Height(testingutils.TestingDutySlotV(version)),
LastPreparedRound: qbft.FirstRound,
LastPreparedValue: cdBytes,
ProposalAcceptedForCurrentRound: testingutils.TestingProposalMessageWithIdentifierAndFullData(
ks.Shares[1], types.OperatorID(1), ret.GetBaseRunner().QBFTController.Identifier, cdBytes, qbft.Height(testingutils.TestingDutySlotV(version))),
Decided: true,
DecidedValue: cdBytes,
},
StartValue: startedCdBytes,
}
ret.GetBaseRunner().QBFTController.Height = qbft.Height(testingutils.TestingDutySlotV(version))
comparable.SetMessages(
ret.GetBaseRunner().State.RunningInstance,
testingutils.ExpectedSSVDecidingMsgsV(cd, ks, types.BNRoleProposer)[3:10],
)
ret.GetBaseRunner().QBFTController.StoredInstances = append(ret.GetBaseRunner().QBFTController.StoredInstances, ret.GetBaseRunner().State.RunningInstance)
return ret
}(),
}
}

// fullHappyFlowBlindedProposerReceivingNormalBlockSC returns state comparison object for the FullHappyFlow for a Blinded Proposer receiving a Normal Block versioned spec test
func fullHappyFlowBlindedProposerReceivingNormalBlockSC(version spec.DataVersion) *comparable.StateComparison {
ks := testingutils.Testing4SharesSet()
// consensus data used for message creation
cd := testingutils.TestProposerConsensusDataV(version)
// encoded consensus data relative to messages
cdBytes := testingutils.TestProposerConsensusDataBytsV(version)
// encoded consensus data that the runner set as StartValue
startedCdBytes := testingutils.TestProposerBlindedBlockConsensusDataBytsV(version)

return &comparable.StateComparison{
ExpectedState: func() ssv.Runner {
ret := testingutils.ProposerBlindedBlockRunner(ks)
ret.GetBaseRunner().State = &ssv.State{
PreConsensusContainer: ssvcomparable.SetMessagesInContainer(
ssv.NewPartialSigContainer(3),
testingutils.ExpectedSSVDecidingMsgsV(cd, ks, types.BNRoleProposer)[:3],
),
PostConsensusContainer: ssvcomparable.SetMessagesInContainer(
ssv.NewPartialSigContainer(3),
[]*types.SSVMessage{
testingutils.SSVMsgProposer(nil, testingutils.PostConsensusProposerMsgV(ks.Shares[1], 1, version)),
testingutils.SSVMsgProposer(nil, testingutils.PostConsensusProposerMsgV(ks.Shares[2], 2, version)),
testingutils.SSVMsgProposer(nil, testingutils.PostConsensusProposerMsgV(ks.Shares[3], 3, version)),
},
),
DecidedValue: comparable.FixIssue178(cd, version),
StartingDuty: &testingutils.TestProposerConsensusDataV(version).Duty,
Finished: true,
}
ret.GetBaseRunner().State.RunningInstance = &qbft.Instance{
State: &qbft.State{
Share: testingutils.TestingShare(ks),
ID: ret.GetBaseRunner().QBFTController.Identifier,
Round: qbft.FirstRound,
Height: qbft.Height(testingutils.TestingDutySlotV(version)),
LastPreparedRound: qbft.FirstRound,
LastPreparedValue: cdBytes,
ProposalAcceptedForCurrentRound: testingutils.TestingProposalMessageWithIdentifierAndFullData(
ks.Shares[1], types.OperatorID(1), ret.GetBaseRunner().QBFTController.Identifier, cdBytes, qbft.Height(testingutils.TestingDutySlotV(version))),
Decided: true,
DecidedValue: cdBytes,
},
StartValue: startedCdBytes,
}
ret.GetBaseRunner().QBFTController.Height = qbft.Height(testingutils.TestingDutySlotV(version))
comparable.SetMessages(
ret.GetBaseRunner().State.RunningInstance,
testingutils.ExpectedSSVDecidingMsgsV(cd, ks, types.BNRoleProposer)[3:10],
)
ret.GetBaseRunner().QBFTController.StoredInstances = append(ret.GetBaseRunner().QBFTController.StoredInstances, ret.GetBaseRunner().State.RunningInstance)
return ret
}(),
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package proposer

import (
"fmt"

"github.com/attestantio/go-eth2-client/spec"

"github.com/bloxapp/ssv-spec/ssv/spectest/tests"
"github.com/bloxapp/ssv-spec/types"
"github.com/bloxapp/ssv-spec/types/testingutils"
)

// NormalProposerAcceptsBlindedBlock tests a full happy flow for a proposer runner that produces normal blocks but receives as proposal a blinded block
func NormalProposerAcceptsBlindedBlock() tests.SpecTest {
ks := testingutils.Testing4SharesSet()

multiSpecTest := &tests.MultiMsgProcessingSpecTest{
Name: "normal proposer accepts blinded block proposal",
Tests: []*tests.MsgProcessingSpecTest{},
}

// proposerReceivingBlindedBlockV creates a test specification for versioned normal proposer receiving blinded block as proposal.
proposerReceivingBlindedBlockV := func(version spec.DataVersion) *tests.MsgProcessingSpecTest {
return &tests.MsgProcessingSpecTest{
Name: fmt.Sprintf("normal proposer accepts blinded block proposal (%s)", version.String()),
Runner: testingutils.ProposerRunner(ks),
Duty: testingutils.TestingProposerDutyV(version),
Messages: append(
testingutils.SSVDecidingMsgsV(testingutils.TestProposerBlindedBlockConsensusDataV(version), ks, types.BNRoleProposer), // consensus
[]*types.SSVMessage{ // post consensus
testingutils.SSVMsgProposer(nil, testingutils.PostConsensusProposerMsgV(ks.Shares[1], 1, version)),
testingutils.SSVMsgProposer(nil, testingutils.PostConsensusProposerMsgV(ks.Shares[2], 2, version)),
testingutils.SSVMsgProposer(nil, testingutils.PostConsensusProposerMsgV(ks.Shares[3], 3, version)),
}...,
),
PostDutyRunnerStateRoot: fullHappyFlowProposerReceivingBlindedBlockSC(version).Root(),
PostDutyRunnerState: fullHappyFlowProposerReceivingBlindedBlockSC(version).ExpectedState,
OutputMessages: []*types.SignedPartialSignatureMessage{
testingutils.PreConsensusRandaoMsgV(ks.Shares[1], 1, version),
testingutils.PostConsensusProposerMsgV(ks.Shares[1], 1, version),
},
BeaconBroadcastedRoots: []string{
testingutils.GetSSZRootNoError(testingutils.TestingSignedBeaconBlockV(ks, version)),
},
}
}

for _, v := range testingutils.SupportedBlockVersions {
multiSpecTest.Tests = append(multiSpecTest.Tests, []*tests.MsgProcessingSpecTest{proposerReceivingBlindedBlockV(v)}...)
}

return multiSpecTest
}
3 changes: 1 addition & 2 deletions ssv/spectest/tests/valcheck/test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ type SpecTest struct {
BeaconRole types.BeaconRole
Input []byte
SlashableDataRoots [][]byte
SupportsBlinded bool
ExpectedError string
AnyError bool
}
Expand Down Expand Up @@ -50,7 +49,7 @@ func (test *SpecTest) valCheckF(signer types.BeaconSigner) qbft.ProposedValueChe
case types.BNRoleAttester:
return ssv.AttesterValueCheckF(signer, test.Network, testingutils.TestingValidatorPubKey[:], testingutils.TestingValidatorIndex, nil)
case types.BNRoleProposer:
return ssv.ProposerValueCheckF(signer, test.Network, testingutils.TestingValidatorPubKey[:], testingutils.TestingValidatorIndex, nil, test.SupportsBlinded)
return ssv.ProposerValueCheckF(signer, test.Network, testingutils.TestingValidatorPubKey[:], testingutils.TestingValidatorIndex, nil)
case types.BNRoleAggregator:
return ssv.AggregatorValueCheckF(signer, test.Network, testingutils.TestingValidatorPubKey[:], testingutils.TestingValidatorIndex)
case types.BNRoleSyncCommittee:
Expand Down
19 changes: 5 additions & 14 deletions ssv/spectest/tests/valcheck/valcheckproposer/blinded_block.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,11 @@ func BlindedBlock() tests.SpecTest {
Name: "blinded blocks",
Tests: []*valcheck.SpecTest{
{
Name: "blinded blocks not allowed",
Network: types.BeaconTestNetwork,
BeaconRole: types.BNRoleProposer,
Input: testingutils.TestProposerBlindedBlockConsensusDataBytsV(spec.DataVersionBellatrix),
SupportsBlinded: false,
ExpectedError: "blinded blocks are not supported",
},
{
Name: "blinded blocks allowed",
Network: types.BeaconTestNetwork,
BeaconRole: types.BNRoleProposer,
Input: testingutils.TestProposerBlindedBlockConsensusDataBytsV(spec.DataVersionBellatrix),
SupportsBlinded: true,
AnyError: false,
Name: "blinded blocks accepted",
Network: types.BeaconTestNetwork,
BeaconRole: types.BNRoleProposer,
Input: testingutils.TestProposerBlindedBlockConsensusDataBytsV(spec.DataVersionBellatrix),
AnyError: false,
},
},
}
Expand Down
5 changes: 0 additions & 5 deletions ssv/value_check.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package ssv

import (
"bytes"
"fmt"

"github.com/attestantio/go-eth2-client/spec/phase0"
"github.com/pkg/errors"
Expand Down Expand Up @@ -85,7 +84,6 @@ func ProposerValueCheckF(
validatorPK types.ValidatorPK,
validatorIndex phase0.ValidatorIndex,
sharePublicKey []byte,
supportsBlinded bool,
) qbft.ProposedValueCheckF {
return func(data []byte) error {
cd := &types.ConsensusData{}
Expand All @@ -101,9 +99,6 @@ func ProposerValueCheckF(
}

if blockData, _, err := cd.GetBlindedBlockData(); err == nil {
if !supportsBlinded {
return fmt.Errorf("blinded blocks are not supported")
}
slot, err := blockData.Slot()
if err != nil {
return errors.Wrap(err, "failed to get slot from blinded block data")
Expand Down
2 changes: 1 addition & 1 deletion types/spectest/generate/tests.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions types/testingutils/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@ var AttesterRunner7Operators = func(keySet *TestKeySet) ssv.Runner {
}

var ProposerRunner = func(keySet *TestKeySet) ssv.Runner {
return baseRunner(types.BNRoleProposer, ssv.ProposerValueCheckF(NewTestingKeyManager(), types.BeaconTestNetwork, TestingValidatorPubKey[:], TestingValidatorIndex, nil, true), keySet)
return baseRunner(types.BNRoleProposer, ssv.ProposerValueCheckF(NewTestingKeyManager(), types.BeaconTestNetwork, TestingValidatorPubKey[:], TestingValidatorIndex, nil), keySet)
}

var ProposerBlindedBlockRunner = func(keySet *TestKeySet) ssv.Runner {
ret := baseRunner(
types.BNRoleProposer,
ssv.ProposerValueCheckF(NewTestingKeyManager(), types.BeaconTestNetwork, TestingValidatorPubKey[:], TestingValidatorIndex, nil, true),
ssv.ProposerValueCheckF(NewTestingKeyManager(), types.BeaconTestNetwork, TestingValidatorPubKey[:], TestingValidatorIndex, nil),
keySet,
)
ret.(*ssv.ProposerRunner).ProducesBlindedBlocks = true
Expand Down

0 comments on commit 8fd4372

Please sign in to comment.