Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pre consensus fix #240

Open
wants to merge 127 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
127 commits
Select commit Hold shift + click to select a range
9213261
qbft round change fix
alonmuroch May 16, 2023
b76a0c4
hold pre-consensus msgs in container
alonmuroch May 16, 2023
6c37340
add pre-consensus justification when calling baseRunner.Decide
alonmuroch May 16, 2023
3ab8043
comment
alonmuroch May 16, 2023
91ba801
refactor msg container + initial tests
alonmuroch May 17, 2023
cfb3953
Merge branch 'main' into pre-consensus-fix
alonmuroch May 18, 2023
6149768
new msg container spec tests
alonmuroch May 18, 2023
a69c0fc
fixed get pre consensus justifications func
alonmuroch May 18, 2023
0266dd8
add pre consensus to test fixtures
alonmuroch May 18, 2023
4beb72b
add version and pre consensus to all consensus data fixtures
alonmuroch May 18, 2023
cc6fdff
prev
alonmuroch May 20, 2023
5093469
ssv happy flow passes
alonmuroch May 21, 2023
4a2e4a6
Merge branch 'main' into pre-consensus-fix
alonmuroch May 25, 2023
92d01ab
merge fix qbft tests
alonmuroch May 25, 2023
eed7716
merge ssv tests fix
alonmuroch May 25, 2023
55e916f
ssv full happy flow passes
alonmuroch May 25, 2023
81871de
Merge branch 'main' into pre-consensus-fix
alonmuroch Jun 7, 2023
3a2f27a
remove future msg
GalRogozinski Aug 1, 2023
3792c8b
remove backwards compatability
GalRogozinski Aug 1, 2023
72e5463
Merge branch 'meta/ignore-roots' into spec/remove_future_msg
GalRogozinski Aug 1, 2023
0482edc
update states
GalRogozinski Aug 1, 2023
1443cbb
clean tests
GalRogozinski Aug 1, 2023
35c8180
regenerate ssv tests
GalRogozinski Aug 1, 2023
c8550c2
revert message validation comment
GalRogozinski Aug 1, 2023
752b291
Merge branch 'main' into spec/remove_future_msg
GalRogozinski Aug 2, 2023
6019385
more jsons
GalRogozinski Aug 2, 2023
cf709d8
fix error messages
GalRogozinski Aug 2, 2023
f806ac8
don't sync upon decided.go
GalRogozinski Aug 2, 2023
ad45eff
Merge branch 'spec/remove_future_msg' into pre-consensus-fix
GalRogozinski Aug 3, 2023
6667490
fix run_test
GalRogozinski Aug 3, 2023
2371834
remove sync
GalRogozinski Aug 3, 2023
27a228d
remove sync from tests
GalRogozinski Aug 3, 2023
cc21873
tests.json
GalRogozinski Aug 3, 2023
353550e
Merge branch 'spec/remove_future_msg' into pre-consensus-fix
GalRogozinski Aug 6, 2023
c75605e
add post state
GalRogozinski Aug 6, 2023
9a35080
fix NewPartialSignatureContainer
GalRogozinski Aug 6, 2023
8a9c481
TestSyncCommitteeContributionConsensusData
GalRogozinski Aug 6, 2023
eb58c28
new PartialSig5
GalRogozinski Aug 6, 2023
b2b0e01
TestAggregatorConsensusData(ks)
GalRogozinski Aug 6, 2023
dfb206b
TestAggregatorConsensusDataBytes(ks)
GalRogozinski Aug 6, 2023
fbab680
TestSyncCommitteeContributionConsensusDataByts(ks)
GalRogozinski Aug 6, 2023
71c1386
use Bellatrix
GalRogozinski Aug 6, 2023
5d79a72
rename
GalRogozinski Aug 6, 2023
0ae002d
should only process quorum once
GalRogozinski Aug 6, 2023
a2cb272
generate SSV Jsons
GalRogozinski Aug 7, 2023
abb8bd3
fix lint
GalRogozinski Aug 7, 2023
a033359
fix run_test.go
GalRogozinski Aug 7, 2023
e83dc30
types tests.json
GalRogozinski Aug 7, 2023
efaac9b
Merge branch 'main' into spec/remove_future_msg
GalRogozinski Aug 8, 2023
d2b48a7
delete comment
GalRogozinski Aug 8, 2023
1e8fe8b
undo formatting
GalRogozinski Aug 10, 2023
acbfcb0
Merge branch 'main' into pre-consensus-fix
GalRogozinski Aug 10, 2023
298aa64
return error
GalRogozinski Aug 10, 2023
26a84c5
fix tests
GalRogozinski Aug 10, 2023
d477e51
tests.json
GalRogozinski Aug 13, 2023
a907617
fix runner.go
GalRogozinski Aug 13, 2023
27b2b35
fix happy flow.go
GalRogozinski Aug 13, 2023
027d33d
pre-consensus justifications
GalRogozinski Aug 13, 2023
6e21a03
shouldProcessJustifications
GalRogozinski Aug 13, 2023
ebb500a
remove highest decided slot
GalRogozinski Aug 13, 2023
2e27dae
fix error
GalRogozinski Aug 13, 2023
9b88f72
Merge branch 'main' into spec/remove_future_msg
GalRogozinski Aug 13, 2023
052306e
fix tests
GalRogozinski Aug 13, 2023
bc1d358
remove highest decided slot
GalRogozinski Aug 14, 2023
49bf06d
easier debugging
GalRogozinski Aug 14, 2023
fee005a
past slot test runs
GalRogozinski Aug 14, 2023
2fbcc0b
Merge branch 'spec/remove_future_msg' into pre-consensus-fix
GalRogozinski Aug 14, 2023
61c39b9
fix height
GalRogozinski Aug 14, 2023
5d6def1
add expected error
GalRogozinski Aug 14, 2023
57f10c0
past slot passes
GalRogozinski Aug 14, 2023
492b425
fix invalid data
GalRogozinski Aug 14, 2023
64be057
fix future_height.go
GalRogozinski Aug 14, 2023
db0c2f2
fix invalid msg type
GalRogozinski Aug 15, 2023
38172ac
fix past height
GalRogozinski Aug 15, 2023
d0f5c3b
fix wrong beacon role
GalRogozinski Aug 15, 2023
0259922
fix height:1 with sed
GalRogozinski Aug 15, 2023
1eaad21
fix decided instance
GalRogozinski Aug 15, 2023
e3ed9e0
fix first height
GalRogozinski Aug 16, 2023
d88a5ab
first height test
GalRogozinski Aug 16, 2023
ecc6a3f
first height fix
GalRogozinski Aug 16, 2023
18e6b47
fix test
GalRogozinski Aug 16, 2023
2bddef9
fix custom duty
GalRogozinski Aug 16, 2023
4b5e267
add errors
GalRogozinski Aug 16, 2023
c3f8472
happy_flow.go passes
GalRogozinski Aug 16, 2023
82f901f
happy flow breaks
GalRogozinski Aug 16, 2023
4e12057
tests pass
GalRogozinski Aug 16, 2023
b6eac02
fix precon test
GalRogozinski Aug 16, 2023
8705dd2
tests now pass
GalRogozinski Aug 17, 2023
4b1d5d7
generate ssv jsons
GalRogozinski Aug 17, 2023
72090e6
Merge branch 'main' into pre-consensus-fix
GalRogozinski Aug 17, 2023
623e539
types.json
GalRogozinski Aug 17, 2023
69b0924
fix lint
GalRogozinski Aug 17, 2023
62b1714
fix justifications with no precon
GalRogozinski Sep 5, 2023
5cf7b48
invalid expected roots
GalRogozinski Sep 5, 2023
a42beb6
Revert "tests now pass"
GalRogozinski Sep 5, 2023
d404818
duplicate msg different roots
GalRogozinski Sep 5, 2023
daec545
fix typo
GalRogozinski Sep 6, 2023
18b3a65
fix blinded block
GalRogozinski Sep 6, 2023
e7611df
wrong beacons sig should use correct slot
GalRogozinski Sep 6, 2023
3ba384d
generate jsons
GalRogozinski Sep 6, 2023
ece2452
delete precon justifications
GalRogozinski Sep 6, 2023
f076f17
generate jsons
GalRogozinski Sep 6, 2023
1d2fdc6
delete more preconsensus data from testingutils
GalRogozinski Sep 6, 2023
ea887f9
generate jsons
GalRogozinski Sep 6, 2023
3a609dc
fix decided_instance.go to not output any messages
GalRogozinski Sep 6, 2023
9b1d012
delete preconsensus justifications
GalRogozinski Sep 6, 2023
932a909
fix valid first height test
GalRogozinski Sep 6, 2023
9798156
generate jsons
GalRogozinski Sep 6, 2023
bc66e11
Merge branch 'main' into pre-consensus-fix
GalRogozinski Sep 7, 2023
104ec06
fix merge
GalRogozinski Sep 7, 2023
d4af87e
generate jsons
GalRogozinski Sep 7, 2023
f72ecb6
non-nil output messages
GalRogozinski Sep 7, 2023
a658202
tests.json
GalRogozinski Sep 7, 2023
7d06b45
fix jsons
GalRogozinski Sep 7, 2023
d3d5248
Merge branch 'main' into pre-consensus-fix
GalRogozinski Sep 18, 2023
21cb37e
new file and fix after merge
GalRogozinski Sep 18, 2023
fdedf9c
clean up ks with smart refactor
GalRogozinski Sep 19, 2023
7fc3513
duplicate message fix
GalRogozinski Sep 20, 2023
c90b22c
change function name
GalRogozinski Oct 2, 2023
0097b19
Merge branch 'main' into pre-consensus-fix
GalRogozinski Nov 8, 2023
32a59cd
generate jsons
GalRogozinski Nov 8, 2023
3fe7387
Merge branch 'main' into pre-consensus-fix
GalRogozinski Dec 24, 2023
9b50318
generate jsons
GalRogozinski Dec 24, 2023
48f04e3
rename func
GalRogozinski Jan 25, 2024
5609083
refactor roots
GalRogozinski Jan 25, 2024
690bee0
len(ps)
GalRogozinski Feb 21, 2024
21dafa4
quorum -> should process
GalRogozinski Feb 21, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
4 changes: 3 additions & 1 deletion qbft/round_change.go
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,9 @@ func getRoundChangeData(state *State, config IConfig, instanceStartValue []byte)

return state.LastPreparedRound, r, state.LastPreparedValue, justifications, nil
}
return NoRound, [32]byte{}, nil, nil, nil

// If not previously prepared, return start value as full value for pre-consensus justification
return NoRound, [32]byte{}, instanceStartValue, nil, nil
}

// CreateRoundChange
Expand Down
23 changes: 11 additions & 12 deletions ssv/aggregator.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,13 @@ func NewAggregatorRunner(
network Network,
signer types.KeyManager,
valCheck qbft.ProposedValueCheckF,
highestDecidedSlot phase0.Slot,
) Runner {
return &AggregatorRunner{
BaseRunner: &BaseRunner{
BeaconRoleType: types.BNRoleAggregator,
BeaconNetwork: beaconNetwork,
Share: share,
QBFTController: qbftController,
highestDecidedSlot: highestDecidedSlot,
BeaconRoleType: types.BNRoleAggregator,
BeaconNetwork: beaconNetwork,
Share: share,
QBFTController: qbftController,
},

beacon: beacon,
Expand All @@ -55,13 +53,13 @@ func (r *AggregatorRunner) HasRunningDuty() bool {
}

func (r *AggregatorRunner) ProcessPreConsensus(signedMsg *types.SignedPartialSignatureMessage) error {
quorum, roots, err := r.BaseRunner.basePreConsensusMsgProcessing(r, signedMsg)
shouldProcess, roots, err := r.BaseRunner.basePreConsensusMsgProcessing(r, signedMsg)
if err != nil {
return errors.Wrap(err, "failed processing selection proof message")
}

// quorum returns true only once (first time quorum achieved)
if !quorum {
// shouldProcess returns true only once (first time shouldProcess achieved)
if !shouldProcess {
return nil
}

Expand All @@ -88,9 +86,10 @@ func (r *AggregatorRunner) ProcessPreConsensus(signedMsg *types.SignedPartialSig
return errors.Wrap(err, "could not marshal aggregate and proof")
}
input := &types.ConsensusData{
Duty: *duty,
Version: ver,
DataSSZ: byts,
Duty: *duty,
PreConsensusJustifications: r.BaseRunner.State.GetPreConsensusJustification(),
Version: ver,
DataSSZ: byts,
}

if err := r.BaseRunner.decide(r, input); err != nil {
Expand Down
10 changes: 4 additions & 6 deletions ssv/attester.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,13 @@ func NewAttesterRunnner(
network Network,
signer types.KeyManager,
valCheck qbft.ProposedValueCheckF,
highestDecidedSlot phase0.Slot,
) Runner {
return &AttesterRunner{
BaseRunner: &BaseRunner{
BeaconRoleType: types.BNRoleAttester,
BeaconNetwork: beaconNetwork,
Share: share,
QBFTController: qbftController,
highestDecidedSlot: highestDecidedSlot,
BeaconRoleType: types.BNRoleAttester,
BeaconNetwork: beaconNetwork,
Share: share,
QBFTController: qbftController,
},

beacon: beacon,
Expand Down
78 changes: 49 additions & 29 deletions ssv/partial_sig_container.go
Original file line number Diff line number Diff line change
@@ -1,39 +1,25 @@
package ssv

import (
"encoding/hex"
"bytes"
alonmuroch marked this conversation as resolved.
Show resolved Hide resolved
"github.com/bloxapp/ssv-spec/types"
"github.com/pkg/errors"
"sort"
)

type PartialSigContainer struct {
Signatures map[string]map[types.OperatorID][]byte
// Quorum is the number of min signatures needed for quorum
Quorum uint64
}
type PartialSignatureContainer map[types.OperatorID]*types.SignedPartialSignatureMessage

func NewPartialSigContainer(quorum uint64) *PartialSigContainer {
return &PartialSigContainer{
Quorum: quorum,
Signatures: make(map[string]map[types.OperatorID][]byte),
}
func NewPartialSignatureContainer() PartialSignatureContainer {
return make(PartialSignatureContainer)
}

func (ps *PartialSigContainer) AddSignature(sigMsg *types.PartialSignatureMessage) {
if ps.Signatures[rootHex(sigMsg.SigningRoot)] == nil {
ps.Signatures[rootHex(sigMsg.SigningRoot)] = make(map[types.OperatorID][]byte)
}
m := ps.Signatures[rootHex(sigMsg.SigningRoot)]
// ReconstructSignature return reconstructed signature for a root
func (ps PartialSignatureContainer) ReconstructSignature(root [32]byte, validatorPubKey []byte) ([]byte, error) {
// collect signatures
sigs := ps.SignaturesForRoot(root)

if m[sigMsg.Signer] == nil {
m[sigMsg.Signer] = make([]byte, 96)
copy(m[sigMsg.Signer], sigMsg.PartialSignature)
}
}

func (ps *PartialSigContainer) ReconstructSignature(root [32]byte, validatorPubKey []byte) ([]byte, error) {
// Reconstruct signatures
signature, err := types.ReconstructSignatures(ps.Signatures[rootHex(root)])
// reconstruct
signature, err := types.ReconstructSignatures(sigs)
if err != nil {
return nil, errors.Wrap(err, "failed to reconstruct signatures")
}
Expand All @@ -43,10 +29,44 @@ func (ps *PartialSigContainer) ReconstructSignature(root [32]byte, validatorPubK
return signature.Serialize(), nil
}

func (ps *PartialSigContainer) HasQuorum(root [32]byte) bool {
return uint64(len(ps.Signatures[rootHex(root)])) >= ps.Quorum
// SignaturesForRoot returns a map of signer and signature for a specific root
func (ps PartialSignatureContainer) SignaturesForRoot(root [32]byte) map[types.OperatorID][]byte {
sigs := make(map[types.OperatorID][]byte, 0)
for operatorID, sigMsg := range ps {
for _, msg := range sigMsg.Message.Messages {
if bytes.Equal(msg.SigningRoot[:], root[:]) {
sigs[operatorID] = msg.PartialSignature
}
}
}
return sigs
}

// Roots returns roots for the partial sigs
func (ps PartialSignatureContainer) Roots() [][32]byte {
ret := make([][32]byte, 0)

if len(ps) <= 0 {
return ret
}

for _, sigMsg := range ps {
for _, msg := range sigMsg.Message.Messages {
ret = append(ret, msg.SigningRoot)
}
break // only need to iterate first msg
}
return ret
}

func rootHex(r [32]byte) string {
return hex.EncodeToString(r[:])
// AllSorted returns ordered by signer array of signed messages
func (ps PartialSignatureContainer) AllSorted() []*types.SignedPartialSignatureMessage {
ret := make([]*types.SignedPartialSignatureMessage, len(ps))
for _, m := range ps {
ret = append(ret, m)
}
sort.Slice(ret, func(i, j int) bool {
Copy link
Contributor

@moshe-blox moshe-blox Feb 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not relevant for spec, but same code length with less memory allocations:

Suggested change
sort.Slice(ret, func(i, j int) bool {
ret := make([]*types.SignedPartialSignatureMessage, len(ps))
for i, m := range ps {
ret[i] = m
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why delete sort?

return ret[i].Signer < ret[j].Signer
})
return ret
}
40 changes: 14 additions & 26 deletions ssv/pre_consensus_justification.go
Original file line number Diff line number Diff line change
@@ -1,35 +1,23 @@
package ssv

import (
"github.com/attestantio/go-eth2-client/spec/phase0"
"github.com/bloxapp/ssv-spec/qbft"
"github.com/bloxapp/ssv-spec/types"
"github.com/pkg/errors"
)

// correctQBFTState returns true if QBFT controller state requires pre-consensus justification
func (b *BaseRunner) correctQBFTState(msg *qbft.SignedMessage) bool {
inst := b.QBFTController.InstanceForHeight(b.QBFTController.Height)
decidedInstance := inst != nil && inst.State != nil && inst.State.Decided

// firstHeightNotDecided is true if height == 0 (special case) and did not start yet
firstHeightNotDecided := inst == nil && b.QBFTController.Height == msg.Message.Height && msg.Message.Height == qbft.FirstHeight

// notFirstHeightDecided returns true if height != 0, height decided and the message is for next height
notFirstHeightDecided := decidedInstance && msg.Message.Height > qbft.FirstHeight && b.QBFTController.Height+1 == msg.Message.Height

return firstHeightNotDecided || notFirstHeightDecided
}

// shouldProcessingJustificationsForHeight returns true if pre-consensus justification should be processed, false otherwise
func (b *BaseRunner) shouldProcessingJustificationsForHeight(msg *qbft.SignedMessage) bool {
alonmuroch marked this conversation as resolved.
Show resolved Hide resolved
correctMsgTYpe := msg.Message.MsgType == qbft.ProposalMsgType || msg.Message.MsgType == qbft.RoundChangeMsgType
correctBeaconRole := b.BeaconRoleType == types.BNRoleProposer || b.BeaconRoleType == types.BNRoleAggregator || b.BeaconRoleType == types.BNRoleSyncCommitteeContribution
return b.correctQBFTState(msg) && correctMsgTYpe && correctBeaconRole
// shouldProcessJustifications returns true if pre-consensus justification should be processed, false otherwise
func (b *BaseRunner) shouldProcessJustifications(msg *qbft.SignedMessage) bool {
correctMsgType := msg.Message.MsgType == qbft.ProposalMsgType || msg.Message.MsgType == qbft.RoundChangeMsgType
correctBeaconRole := b.BeaconRoleType == types.BNRoleProposer || b.BeaconRoleType == types.BNRoleAggregator ||
b.BeaconRoleType == types.BNRoleSyncCommitteeContribution
correctQBFTHeight := b.QBFTController.Height < msg.Message.Height ||
(b.QBFTController.Height == msg.Message.Height && b.QBFTController.Height == qbft.FirstHeight)
return correctMsgType && correctBeaconRole && correctQBFTHeight
}

// validatePreConsensusJustifications returns an error if pre-consensus justification is invalid, nil otherwise
func (b *BaseRunner) validatePreConsensusJustifications(data *types.ConsensusData, highestDecidedDutySlot phase0.Slot) error {
func (b *BaseRunner) validatePreConsensusJustifications(data *types.ConsensusData) error {
//test invalid consensus data
if err := data.Validate(); err != nil {
return err
Expand All @@ -39,8 +27,8 @@ func (b *BaseRunner) validatePreConsensusJustifications(data *types.ConsensusDat
return errors.New("wrong beacon role")
}

if data.Duty.Slot <= highestDecidedDutySlot {
return errors.New("duty.slot <= highest decided slot")
if qbft.Height(data.Duty.Slot) <= b.QBFTController.Height && b.QBFTController.Height != qbft.FirstHeight {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we are on first height (which will never happen I guess) then its ok that the duty height is smaller than the controller height? I understand why its ok that its equal but not lower.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it is small or equal it returns an error.
On first height it can only be equal.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you mean if firstHeight would be a number different than 0?
If it will be 1 then we won't need this special condition in all those places in the code

return errors.New("duty.slot <= highest known slot")
}

// validate justification quorum
Expand Down Expand Up @@ -110,8 +98,8 @@ func (b *BaseRunner) validatePreConsensusJustifications(data *types.ConsensusDat
5) add pre-consensus sigs to container
6) decided on duty
*/
func (b *BaseRunner) processPreConsensusJustification(runner Runner, highestDecidedDutySlot phase0.Slot, msg *qbft.SignedMessage) error {
if !b.shouldProcessingJustificationsForHeight(msg) {
func (b *BaseRunner) processPreConsensusJustification(runner Runner, msg *qbft.SignedMessage) error {
if !b.shouldProcessJustifications(msg) {
return nil
}

Expand All @@ -120,7 +108,7 @@ func (b *BaseRunner) processPreConsensusJustification(runner Runner, highestDeci
return errors.Wrap(err, "could not decoded ConsensusData")
}

if err := b.validatePreConsensusJustifications(cd, highestDecidedDutySlot); err != nil {
if err := b.validatePreConsensusJustifications(cd); err != nil {
return err
}

Expand Down
23 changes: 11 additions & 12 deletions ssv/proposer.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,13 @@ func NewProposerRunner(
network Network,
signer types.KeyManager,
valCheck qbft.ProposedValueCheckF,
highestDecidedSlot phase0.Slot,
) Runner {
return &ProposerRunner{
BaseRunner: &BaseRunner{
BeaconRoleType: types.BNRoleProposer,
BeaconNetwork: beaconNetwork,
Share: share,
QBFTController: qbftController,
highestDecidedSlot: highestDecidedSlot,
BeaconRoleType: types.BNRoleProposer,
BeaconNetwork: beaconNetwork,
Share: share,
QBFTController: qbftController,
},

beacon: beacon,
Expand All @@ -60,13 +58,13 @@ func (r *ProposerRunner) HasRunningDuty() bool {
}

func (r *ProposerRunner) ProcessPreConsensus(signedMsg *types.SignedPartialSignatureMessage) error {
quorum, roots, err := r.BaseRunner.basePreConsensusMsgProcessing(r, signedMsg)
shouldProcess, roots, err := r.BaseRunner.basePreConsensusMsgProcessing(r, signedMsg)
if err != nil {
return errors.Wrap(err, "failed processing randao message")
}

// quorum returns true only once (first time quorum achieved)
if !quorum {
// shouldProcess returns true only once (first time shouldProcess achieved)
if !shouldProcess {
return nil
}

Expand Down Expand Up @@ -102,9 +100,10 @@ func (r *ProposerRunner) ProcessPreConsensus(signedMsg *types.SignedPartialSigna
}

input := &types.ConsensusData{
Duty: *duty,
Version: ver,
DataSSZ: byts,
Duty: *duty,
PreConsensusJustifications: r.BaseRunner.State.GetPreConsensusJustification(),
Version: ver,
DataSSZ: byts,
}

if err := r.BaseRunner.decide(r, input); err != nil {
Expand Down
Loading