mirror of
https://github.com/luxfi/proto.git
synced 2026-10-30 15:21:09 +00:00
102 lines
3.1 KiB
Go
102 lines
3.1 KiB
Go
// Copyright (C) 2019-2025, Lux Industries, Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package state
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"fmt"
|
|
|
|
"github.com/luxfi/database"
|
|
"github.com/luxfi/ids"
|
|
)
|
|
|
|
const (
|
|
// startDiffKey = [netID] + [inverseHeight]
|
|
startDiffKeyLength = ids.IDLen + database.Uint64Size
|
|
// diffKey = [netID] + [inverseHeight] + [nodeID]
|
|
diffKeyLength = startDiffKeyLength + ids.NodeIDLen
|
|
// diffKeyNodeIDOffset = [netIDLen] + [inverseHeightLen]
|
|
diffKeyNodeIDOffset = ids.IDLen + database.Uint64Size
|
|
|
|
// weightValue = [isNegative] + [weight] + [validationID]
|
|
weightValueLength = database.BoolSize + database.Uint64Size + ids.IDLen
|
|
)
|
|
|
|
var (
|
|
errUnexpectedDiffKeyLength = fmt.Errorf("expected diff key length %d", diffKeyLength)
|
|
errUnexpectedWeightValueLength = fmt.Errorf("expected weight value length %d", weightValueLength)
|
|
)
|
|
|
|
// marshalStartDiffKey is used to determine the starting key when iterating.
|
|
//
|
|
// Invariant: the result is a prefix of [marshalDiffKey] when called with the
|
|
// same arguments.
|
|
func marshalStartDiffKey(netID ids.ID, height uint64) []byte {
|
|
key := make([]byte, startDiffKeyLength)
|
|
copy(key, netID[:])
|
|
packIterableHeight(key[ids.IDLen:], height)
|
|
return key
|
|
}
|
|
|
|
func marshalDiffKey(netID ids.ID, height uint64, nodeID ids.NodeID) []byte {
|
|
key := make([]byte, diffKeyLength)
|
|
copy(key, netID[:])
|
|
packIterableHeight(key[ids.IDLen:], height)
|
|
copy(key[diffKeyNodeIDOffset:], nodeID.Bytes())
|
|
return key
|
|
}
|
|
|
|
func unmarshalDiffKey(key []byte) (ids.ID, uint64, ids.NodeID, error) {
|
|
if len(key) != diffKeyLength {
|
|
return ids.Empty, 0, ids.EmptyNodeID, errUnexpectedDiffKeyLength
|
|
}
|
|
var (
|
|
netID ids.ID
|
|
nodeID ids.NodeID
|
|
)
|
|
copy(netID[:], key)
|
|
height := unpackIterableHeight(key[ids.IDLen:])
|
|
copy(nodeID[:], key[diffKeyNodeIDOffset:])
|
|
return netID, height, nodeID, nil
|
|
}
|
|
|
|
func marshalWeightDiff(diff *ValidatorWeightDiff) []byte {
|
|
value := make([]byte, weightValueLength)
|
|
if diff.Decrease {
|
|
value[0] = database.BoolTrue
|
|
}
|
|
binary.BigEndian.PutUint64(value[database.BoolSize:], diff.Amount)
|
|
copy(value[database.BoolSize+database.Uint64Size:], diff.ValidationID[:])
|
|
return value
|
|
}
|
|
|
|
func unmarshalWeightDiff(value []byte) (*ValidatorWeightDiff, error) {
|
|
if len(value) != weightValueLength {
|
|
return nil, errUnexpectedWeightValueLength
|
|
}
|
|
var validationID ids.ID
|
|
copy(validationID[:], value[database.BoolSize+database.Uint64Size:])
|
|
return &ValidatorWeightDiff{
|
|
Decrease: value[0] == database.BoolTrue,
|
|
Amount: binary.BigEndian.Uint64(value[database.BoolSize:]),
|
|
ValidationID: validationID,
|
|
}, nil
|
|
}
|
|
|
|
// Note: [height] is encoded as a bit flipped big endian number so that
|
|
// iterating lexicographically results in iterating in decreasing heights.
|
|
//
|
|
// Invariant: [key] has sufficient length
|
|
func packIterableHeight(key []byte, height uint64) {
|
|
binary.BigEndian.PutUint64(key, ^height)
|
|
}
|
|
|
|
// Because we bit flip the height when constructing the key, we must remember to
|
|
// bip flip again here.
|
|
//
|
|
// Invariant: [key] has sufficient length
|
|
func unpackIterableHeight(key []byte) uint64 {
|
|
return ^binary.BigEndian.Uint64(key)
|
|
}
|