diff --git a/tortoise/state.go b/tortoise/state.go index 362c648b78..1be4141b1f 100644 --- a/tortoise/state.go +++ b/tortoise/state.go @@ -94,7 +94,7 @@ func (s *state) layer(lid types.LayerID) *layerInfo { layer, exist := s.layers[lid] if !exist { layersNumber.Inc() - layer = &layerInfo{lid: lid} + layer = &layerInfo{lid: lid, opinions: map[types.Hash32]votes{}} s.layers[lid] = layer } return layer @@ -179,6 +179,10 @@ type layerInfo struct { verifying verifyingInfo coinflip sign + // unique opinions recorded from the ballots in this layer. + // ballot votes an opinion and encodes sidecar + opinions map[types.Hash32]votes + opinion types.Hash32 // a pointer to the value stored on the previous layerInfo object // it is stored as a pointer so that when previous layerInfo is evicted diff --git a/tortoise/tortoise.go b/tortoise/tortoise.go index 0142fd8477..b6a8f54531 100644 --- a/tortoise/tortoise.go +++ b/tortoise/tortoise.go @@ -60,6 +60,7 @@ func newTurtle(logger *zap.Logger, config Config) *turtle { t.layers[genesis] = &layerInfo{ lid: genesis, hareTerminated: true, + opinions: map[types.Hash32]votes{}, } t.verifying = newVerifying(config, t.state) t.full = newFullTortoise(config, t.state) @@ -748,11 +749,23 @@ func (t *turtle) decodeBallot(ballot *types.BallotTortoiseData) (*ballotInfo, ty zap.Uint32("lid", ballot.Layer.Uint32()), ) - votes, min, err := decodeVotes(t.evicted, binfo.layer, base, ballot.Opinion.Votes) - if err != nil { - return nil, 0, err + layer := t.layer(binfo.layer) + + existing, exists := layer.opinions[ballot.Opinion.Hash] + var min types.LayerID + if exists { + binfo.votes = existing + } else { + var ( + votes votes + err error + ) + votes, min, err = decodeVotes(t.evicted, binfo.layer, base, ballot.Opinion.Votes) + if err != nil { + return nil, 0, err + } + binfo.votes = votes } - binfo.votes = votes t.logger.Debug("decoded exceptions", zap.Stringer("block", binfo.id), zap.Uint32("lid", binfo.layer.Uint32()), @@ -771,15 +784,22 @@ func (t *turtle) storeBallot(ballot *ballotInfo, min types.LayerID) error { } t.state.addBallot(ballot) - for current := ballot.votes.tail; current != nil && !current.lid.Before(min); current = current.prev { - for i, block := range current.supported { - existing := t.getBlock(block.header()) - if existing != nil { - current.supported[i] = existing - } else { - t.addBlock(block) + layer := t.layer(ballot.layer) + existing, exists := layer.opinions[ballot.opinion()] + if exists { + ballot.votes = existing + } else { + for current := ballot.votes.tail; current != nil && !current.lid.Before(min); current = current.prev { + for i, block := range current.supported { + existing := t.getBlock(block.header()) + if existing != nil { + current.supported[i] = existing + } else { + t.addBlock(block) + } } } + layer.opinions[ballot.opinion()] = ballot.votes } if !ballot.layer.After(t.processed) { if err := t.countBallot(ballot); err != nil {