Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions lib/block_view.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,9 @@ type UtxoView struct {
// Locked stake mappings
LockedStakeMapKeyToLockedStakeEntry map[LockedStakeMapKey]*LockedStakeEntry

// Current EpochEntry
CurrentEpochEntry *EpochEntry

// The hash of the tip the view is currently referencing. Mainly used
// for error-checking when doing a bulk operation on the view.
TipHash *BlockHash
Expand Down Expand Up @@ -228,6 +231,9 @@ func (bav *UtxoView) _ResetViewMappingsAfterFlush() {

// LockedStakeEntries
bav.LockedStakeMapKeyToLockedStakeEntry = make(map[LockedStakeMapKey]*LockedStakeEntry)

// CurrentEpochEntry
bav.CurrentEpochEntry = nil
}

func (bav *UtxoView) CopyUtxoView() (*UtxoView, error) {
Expand Down Expand Up @@ -505,6 +511,11 @@ func (bav *UtxoView) CopyUtxoView() (*UtxoView, error) {
newView.LockedStakeMapKeyToLockedStakeEntry[entryKey] = entry.Copy()
}

// Copy the CurrentEpochEntry
if bav.CurrentEpochEntry != nil {
newView.CurrentEpochEntry = bav.CurrentEpochEntry.Copy()
}

return newView, nil
}

Expand Down
6 changes: 6 additions & 0 deletions lib/block_view_flush.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,12 @@ func (bav *UtxoView) FlushToDbWithTxn(txn *badger.Txn, blockHeight uint64) error
if err := bav._flushLockedStakeEntriesToDbWithTxn(txn, blockHeight); err != nil {
return err
}
// TODO: We may want to move this into a new FlushToDb function that only flushes
// entries set in the OnEpochEndHook. No sense in wasting a bunch of cycles flushing
// all the other entries which will always be nil/empty in the OnEpochEndHook.
if err := bav._flushCurrentEpochEntryToDbWithTxn(txn, blockHeight); err != nil {
return err
}
return nil
}

Expand Down
16 changes: 8 additions & 8 deletions lib/block_view_stake.go
Original file line number Diff line number Diff line change
Expand Up @@ -576,14 +576,14 @@ func DBGetStakeEntryWithTxn(
if err == badger.ErrKeyNotFound {
return nil, nil
}
return nil, errors.Wrapf(err, "DBGetStakeByValidatorByStaker: problem retrieving StakeEntry: ")
return nil, errors.Wrapf(err, "DBGetStakeEntry: problem retrieving StakeEntry: ")
}

// Decode StakeEntry from bytes.
rr := bytes.NewReader(stakeEntryBytes)
stakeEntry, err := DecodeDeSoEncoder(&StakeEntry{}, rr)
if err != nil {
return nil, errors.Wrapf(err, "DBGetStakeByValidatorByStaker: problem decoding StakeEntry: ")
return nil, errors.Wrapf(err, "DBGetStakeEntry: problem decoding StakeEntry: ")
}
return stakeEntry, nil
}
Expand Down Expand Up @@ -649,7 +649,7 @@ func DBGetLockedStakeEntryWithTxn(
return nil, nil
}
return nil, errors.Wrapf(
err, "DBGetLockedStakeByValidatorByStakerByLockedAt: problem retrieving LockedStakeEntry: ",
err, "DBGetLockedStakeEntry: problem retrieving LockedStakeEntry: ",
)
}

Expand All @@ -658,7 +658,7 @@ func DBGetLockedStakeEntryWithTxn(
lockedStakeEntry, err := DecodeDeSoEncoder(&LockedStakeEntry{}, rr)
if err != nil {
return nil, errors.Wrapf(
err, "DBGetLockedStakeByValidatorByStakerByLockedAt: problem decoding LockedStakeEntry: ",
err, "DBGetLockedStakeEntry: problem decoding LockedStakeEntry: ",
)
}
return lockedStakeEntry, nil
Expand Down Expand Up @@ -755,7 +755,7 @@ func DBPutStakeEntryWithTxn(
key := DBKeyForStakeByValidatorByStaker(stakeEntry)
if err := DBSetWithTxn(txn, snap, key, EncodeToBytes(blockHeight, stakeEntry)); err != nil {
return errors.Wrapf(
err, "DBPutStakeWithTxn: problem storing StakeEntry in index PrefixStakeByValidatorByStaker",
err, "DBPutStakeEntryWithTxn: problem storing StakeEntry in index PrefixStakeByValidatorByStaker: ",
)
}

Expand All @@ -776,7 +776,7 @@ func DBPutLockedStakeEntryWithTxn(
key := DBKeyForLockedStakeByValidatorByStakerByLockedAt(lockedStakeEntry)
if err := DBSetWithTxn(txn, snap, key, EncodeToBytes(blockHeight, lockedStakeEntry)); err != nil {
return errors.Wrapf(
err, "DBPutLockedStakeWithTxn: problem storing LockedStakeEntry in index PrefixLockedStakeByValidatorByStakerByLockedAt",
err, "DBPutLockedStakeEntryWithTxn: problem storing LockedStakeEntry in index PrefixLockedStakeByValidatorByStakerByLockedAt: ",
)
}

Expand All @@ -797,7 +797,7 @@ func DBDeleteStakeEntryWithTxn(
key := DBKeyForStakeByValidatorByStaker(stakeEntry)
if err := DBDeleteWithTxn(txn, snap, key); err != nil {
return errors.Wrapf(
err, "DBDeleteStakeWithTxn: problem deleting StakeEntry from index PrefixStakeByValidatorByStaker",
err, "DBDeleteStakeEntryWithTxn: problem deleting StakeEntry from index PrefixStakeByValidatorByStaker: ",
)
}

Expand All @@ -818,7 +818,7 @@ func DBDeleteLockedStakeEntryWithTxn(
key := DBKeyForLockedStakeByValidatorByStakerByLockedAt(lockedStakeEntry)
if err := DBDeleteWithTxn(txn, snap, key); err != nil {
return errors.Wrapf(
err, "DBDeleteLockedStakeWithTxn: problem deleting StakeEntry from index PrefixLockedStakeByValidatorByStakerByLockedAt",
err, "DBDeleteLockedStakeEntryWithTxn: problem deleting StakeEntry from index PrefixLockedStakeByValidatorByStakerByLockedAt: ",
)
}

Expand Down
5 changes: 4 additions & 1 deletion lib/block_view_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,10 @@ const (
EncoderTypeValidatorEntry EncoderType = 40
EncoderTypeStakeEntry EncoderType = 41
EncoderTypeLockedStakeEntry EncoderType = 42
EncoderTypeEpochEntry EncoderType = 43

// EncoderTypeEndBlockView encoder type should be at the end and is used for automated tests.
EncoderTypeEndBlockView EncoderType = 43
EncoderTypeEndBlockView EncoderType = 44
)

// Txindex encoder types.
Expand Down Expand Up @@ -250,6 +251,8 @@ func (encoderType EncoderType) New() DeSoEncoder {
return &StakeEntry{}
case EncoderTypeLockedStakeEntry:
return &LockedStakeEntry{}
case EncoderTypeEpochEntry:
return &EpochEntry{}
}

// Txindex encoder types
Expand Down
9 changes: 8 additions & 1 deletion lib/db_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,11 @@ type DBPrefixes struct {
// Prefix, ValidatorPKID, StakerPKID, LockedAtEpochNumber -> LockedStakeEntry
PrefixLockedStakeByValidatorByStakerByLockedAt []byte `prefix_id:"[82]" is_state:"true"`

// NEXT_TAG: 83
// PrefixCurrentEpoch: Retrieve the current EpochEntry.
// Prefix -> EpochEntry
PrefixCurrentEpoch []byte `prefix_id:"[83]" is_state:"true"`

// NEXT_TAG: 84
}

// StatePrefixToDeSoEncoder maps each state prefix to a DeSoEncoder type that is stored under that prefix.
Expand Down Expand Up @@ -719,6 +723,9 @@ func StatePrefixToDeSoEncoder(prefix []byte) (_isEncoder bool, _encoder DeSoEnco
} else if bytes.Equal(prefix, Prefixes.PrefixLockedStakeByValidatorByStakerByLockedAt) {
// prefix_id:"[82]"
return true, &LockedStakeEntry{}
} else if bytes.Equal(prefix, Prefixes.PrefixCurrentEpoch) {
// prefix_id:"[83]"
return true, &EpochEntry{}
}

return true, nil
Expand Down
170 changes: 170 additions & 0 deletions lib/pos_epoch.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
package lib

import (
"bytes"
"github.com/dgraph-io/badger/v3"
"github.com/golang/glog"
"github.com/pkg/errors"
)

//
// TYPE
//

type EpochEntry struct {
EpochNumber uint64
FinalBlockHeight uint64
}

func (epochEntry *EpochEntry) Copy() *EpochEntry {
return &EpochEntry{
EpochNumber: epochEntry.EpochNumber,
FinalBlockHeight: epochEntry.FinalBlockHeight,
}
}

func (epochEntry *EpochEntry) RawEncodeWithoutMetadata(blockHeight uint64, skipMetadata ...bool) []byte {
var data []byte
data = append(data, UintToBuf(epochEntry.EpochNumber)...)
data = append(data, UintToBuf(epochEntry.FinalBlockHeight)...)
return data
}

func (epochEntry *EpochEntry) RawDecodeWithoutMetadata(blockHeight uint64, rr *bytes.Reader) error {
var err error

// EpochNumber
epochEntry.EpochNumber, err = ReadUvarint(rr)
if err != nil {
return errors.Wrapf(err, "EpochEntry.Decode: Problem reading EpochNumber: ")
}

// FinalBlockHeight
epochEntry.FinalBlockHeight, err = ReadUvarint(rr)
if err != nil {
return errors.Wrapf(err, "EpochEntry.Decode: Problem reading FinalBlockHeight: ")
}

return err
}

func (epochEntry *EpochEntry) GetVersionByte(blockHeight uint64) byte {
return 0
}

func (epochEntry *EpochEntry) GetEncoderType() EncoderType {
return EncoderTypeEpochEntry
}

//
// UTXO VIEW UTILS
//

func (bav *UtxoView) GetCurrentEpochEntry() (*EpochEntry, error) {
var epochEntry *EpochEntry
var err error

// First, check the UtxoView.
epochEntry = bav.CurrentEpochEntry
if epochEntry != nil {
return epochEntry.Copy(), nil
}

// If not found, check the database.
epochEntry, err = DBGetCurrentEpochEntry(bav.Handle, bav.Snapshot)
if err != nil {
return nil, errors.Wrapf(err, "UtxoView.GetCurrentEpoch: problem retrieving EpochEntry from db: ")
}
if epochEntry != nil {
// Cache in the UtxoView.
bav.CurrentEpochEntry = epochEntry.Copy()
}
return epochEntry, nil
}

func (bav *UtxoView) GetCurrentEpochNumber() (uint64, error) {
epochEntry, err := bav.GetCurrentEpochEntry()
if err != nil {
return 0, errors.Wrapf(err, "UtxoView.GetCurrentEpochNumber: ")
}
if epochEntry == nil {
return 0, errors.New("UtxoView.GetCurrentEpochNumber: no CurrentEpochEntry found")
}
return epochEntry.EpochNumber, nil
}

func (bav *UtxoView) _setCurrentEpochEntry(epochEntry *EpochEntry) {
if epochEntry == nil {
glog.Errorf("UtxoView._setCurrentEpochEntry: called with nil EpochEntry")
return
}
bav.CurrentEpochEntry = epochEntry.Copy()
}

func (bav *UtxoView) _flushCurrentEpochEntryToDbWithTxn(txn *badger.Txn, blockHeight uint64) error {
if bav.CurrentEpochEntry == nil {
// It is possible that the current UtxoView never interacted with the CurrentEpochEntry
// in which case the CurrentEpochEntry in the UtxoView will be nil. In that case, we
// don't want to overwrite what is in the database. Just no-op.
return nil
}
if err := DBPutCurrentEpochEntryWithTxn(txn, bav.Snapshot, bav.CurrentEpochEntry, blockHeight); err != nil {
return errors.Wrapf(err, "_flushCurrentEpochEntryToDbWithTxn: ")
}
return nil
}

//
// DB UTILS
//

func DBKeyForCurrentEpoch() []byte {
return append([]byte{}, Prefixes.PrefixCurrentEpoch...)
}

func DBGetCurrentEpochEntry(handle *badger.DB, snap *Snapshot) (*EpochEntry, error) {
var ret *EpochEntry
err := handle.View(func(txn *badger.Txn) error {
var innerErr error
ret, innerErr = DBGetCurrentEpochEntryWithTxn(txn, snap)
return innerErr
})
return ret, err
}

func DBGetCurrentEpochEntryWithTxn(txn *badger.Txn, snap *Snapshot) (*EpochEntry, error) {
// Retrieve StakeEntry from db.
key := DBKeyForCurrentEpoch()
epochEntryBytes, err := DBGetWithTxn(txn, snap, key)
if err != nil {
// We don't want to error if the key isn't found. Instead, return nil.
if err == badger.ErrKeyNotFound {
return nil, nil
}
return nil, errors.Wrapf(err, "DBGetCurrentEpochEntry: problem retrieving EpochEntry: ")
}

// Decode EpochEntry from bytes.
rr := bytes.NewReader(epochEntryBytes)
epochEntry, err := DecodeDeSoEncoder(&EpochEntry{}, rr)
if err != nil {
return nil, errors.Wrapf(err, "DBGetCurrentEpochEntry: problem decoding EpochEntry: ")
}
return epochEntry, nil
}

func DBPutCurrentEpochEntryWithTxn(txn *badger.Txn, snap *Snapshot, epochEntry *EpochEntry, blockHeight uint64) error {
// Set EpochEntry in PrefixCurrentEpoch.
if epochEntry == nil {
// This is just a safety check that we are not accidentally overwriting an
// existing EpochEntry with a nil EpochEntry. This should never happen.
return errors.New("DBPutCurrentEpochEntryWithTxn: called with nil EpochEntry")
}
key := DBKeyForCurrentEpoch()
if err := DBSetWithTxn(txn, snap, key, EncodeToBytes(blockHeight, epochEntry)); err != nil {
return errors.Wrapf(
err, "DBPutCurrentEpochEntryWithTxn: problem storing EpochEntry in index PrefixCurrentEpoch: ",
)
}
return nil
}
Loading