diff --git a/tortoise/state.go b/tortoise/state.go index 2c6df9cb10..3a15ae1dd5 100644 --- a/tortoise/state.go +++ b/tortoise/state.go @@ -99,7 +99,10 @@ func (s *state) layer(lid types.LayerID) *layerInfo { last := s.evicted + types.LayerID(len(s.layers)) for j := 0; j <= int(i)-lth; j++ { layersNumber.Inc() - s.layers = append(s.layers, &layerInfo{lid: last + types.LayerID(j) + 1}) + s.layers = append(s.layers, &layerInfo{ + lid: last + types.LayerID(j) + 1, + opinions: map[types.Hash32]*votes{}, + }) } return s.layer(lid) } @@ -183,6 +186,8 @@ type layerInfo struct { verifying verifyingInfo coinflip sign + 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 3fa834f343..bb515087a8 100644 --- a/tortoise/tortoise.go +++ b/tortoise/tortoise.go @@ -60,6 +60,7 @@ func newTurtle(logger *zap.Logger, config Config) *turtle { t.layers = append(t.layers, &layerInfo{ lid: genesis, hareTerminated: true, + opinions: map[types.Hash32]*votes{}, }) t.verifying = newVerifying(config, t.state) t.full = newFullTortoise(config, t.state) @@ -750,11 +751,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 := layer.opinions[ballot.Opinion.Hash] + var min types.LayerID + if existing != nil { + 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()), @@ -773,15 +786,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) + votes := layer.opinions[ballot.opinion()] + if votes != nil { + ballot.votes.tail = votes.tail + } 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 {