bsc/core/vote/vote_journal.go

126 lines
3.0 KiB
Go

package vote
import (
"encoding/json"
lru "github.com/hashicorp/golang-lru"
"github.com/tidwall/wal"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics"
)
const (
maxSizeOfRecentEntry = 512
maliciousVoteSlashScope = 256
)
type VoteJournal struct {
journalPath string // file path of disk journal for saving the vote.
walLog *wal.Log
voteDataBuffer *lru.Cache
}
var voteJournalErrorCounter = metrics.NewRegisteredCounter("voteJournal/error", nil)
func NewVoteJournal(filePath string) (*VoteJournal, error) {
walLog, err := wal.Open(filePath, &wal.Options{
LogFormat: wal.JSON,
SegmentCacheSize: maxSizeOfRecentEntry,
})
if err != nil {
log.Error("Failed to open vote journal", "err", err)
return nil, err
}
voteDataBuffer, err := lru.New(maxSizeOfRecentEntry)
if err != nil {
return nil, err
}
firstIndex, err := walLog.FirstIndex()
if err != nil {
log.Error("Failed to get first index of votes journal", "err", err)
}
lastIndex, err := walLog.LastIndex()
if err != nil {
log.Error("Failed to get lastIndex of vote journal", "err", err)
return nil, err
}
voteJournal := &VoteJournal{
journalPath: filePath,
walLog: walLog,
}
// Reload all voteData from journal to lru memory everytime node reboot.
for index := firstIndex; index <= lastIndex; index++ {
if voteEnvelop, err := voteJournal.ReadVote(index); err == nil && voteEnvelop != nil {
voteData := voteEnvelop.Data
voteDataBuffer.Add(voteData.TargetNumber, voteData)
}
}
voteJournal.voteDataBuffer = voteDataBuffer
return voteJournal, nil
}
func (journal *VoteJournal) WriteVote(voteMessage *types.VoteEnvelope) error {
walLog := journal.walLog
vote, err := json.Marshal(voteMessage)
if err != nil {
log.Error("Failed to unmarshal vote", "err", err)
return err
}
lastIndex, err := walLog.LastIndex()
if err != nil {
log.Error("Failed to get lastIndex of vote journal", "err", err)
return err
}
lastIndex += 1
if err = walLog.Write(lastIndex, vote); err != nil {
log.Error("Failed to write vote journal", "err", err)
return err
}
firstIndex, err := walLog.FirstIndex()
if err != nil {
log.Error("Failed to get first index of votes journal", "err", err)
}
if lastIndex-firstIndex+1 > maxSizeOfRecentEntry {
if err := walLog.TruncateFront(lastIndex - maxSizeOfRecentEntry + 1); err != nil {
log.Error("Failed to truncate votes journal", "err", err)
}
}
journal.voteDataBuffer.Add(voteMessage.Data.TargetNumber, voteMessage.Data)
return nil
}
func (journal *VoteJournal) ReadVote(index uint64) (*types.VoteEnvelope, error) {
voteMessage, err := journal.walLog.Read(index)
if err != nil && err != wal.ErrNotFound {
log.Error("Failed to read votes journal", "err", err)
return nil, err
}
var vote *types.VoteEnvelope
if voteMessage != nil {
vote = &types.VoteEnvelope{}
if err := json.Unmarshal(voteMessage, vote); err != nil {
log.Error("Failed to read vote from voteJournal", "err", err)
return nil, err
}
}
return vote, nil
}