Fantom-foundation/go-lachesis

View on GitHub
poset/store_roots.go

Summary

Maintainability
A
0 mins
Test Coverage
package poset

import (
    "bytes"

    "github.com/Fantom-foundation/go-lachesis/hash"
    "github.com/Fantom-foundation/go-lachesis/inter"
    "github.com/Fantom-foundation/go-lachesis/inter/idx"
    "github.com/Fantom-foundation/go-lachesis/poset/election"
)

func rootRecordBytes(r *election.RootAndSlot) []byte {
    key := bytes.Buffer{}
    key.Write(r.Slot.Frame.Bytes())
    key.Write(r.Slot.Validator.Bytes())
    key.Write(r.ID.Bytes())
    return key.Bytes()
}

// AddRoot stores the new root
// Not safe for concurrent use due to complex mutable cache!
func (s *Store) AddRoot(root *inter.Event) {
    r := election.RootAndSlot{
        Slot: election.Slot{
            Frame:     root.Frame,
            Validator: root.Creator,
        },
        ID: root.Hash(),
    }

    if err := s.epochTable.Roots.Put(rootRecordBytes(&r), []byte{}); err != nil {
        s.Log.Crit("Failed to put key-value", "err", err)
    }

    // Add to cache.
    if s.cache.FrameRoots != nil {
        if c, ok := s.cache.FrameRoots.Get(root.Frame); ok {
            if rr, ok := c.([]election.RootAndSlot); ok {
                s.cache.FrameRoots.Add(root.Frame, append(rr, r))
            }
        }
    }
}

const (
    frameSize    = 4
    stakerIDSize = 4
    eventIDSize  = 32
)

// GetFrameRoots returns all the roots in the specified frame
// Not safe for concurrent use due to complex mutable cache!
func (s *Store) GetFrameRoots(f idx.Frame) []election.RootAndSlot {
    // Get data from LRU cache first.
    if s.cache.FrameRoots != nil {
        if c, ok := s.cache.FrameRoots.Get(f); ok {
            if rr, ok := c.([]election.RootAndSlot); ok {
                return rr
            }
        }
    }
    rr := make([]election.RootAndSlot, 0, 200)

    it := s.epochTable.Roots.NewIterator(f.Bytes(), nil)
    defer it.Release()
    for it.Next() {
        key := it.Key()
        if len(key) != frameSize+stakerIDSize+eventIDSize {
            s.Log.Crit("Roots table: incorrect key len", "len", len(key))
        }
        r := election.RootAndSlot{
            Slot: election.Slot{
                Frame:     idx.BytesToFrame(key[:frameSize]),
                Validator: idx.BytesToStakerID(key[frameSize : frameSize+stakerIDSize]),
            },
            ID: hash.BytesToEvent(key[frameSize+stakerIDSize:]),
        }
        if r.Slot.Frame != f {
            s.Log.Crit("Roots table: invalid frame", "frame", r.Slot.Frame, "expected", f)
        }

        rr = append(rr, r)
    }
    if it.Error() != nil {
        s.Log.Crit("Failed to iterate keys", "err", it.Error())
    }

    // Add to cache.
    if s.cache.FrameRoots != nil {
        s.cache.FrameRoots.Add(f, rr)
    }

    return rr
}