github.com/MetalBlockchain/metalgo@v1.11.9/vms/platformvm/state/disk_staker_diff_iterator.go (about)

     1  // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  package state
     5  
     6  import (
     7  	"encoding/binary"
     8  	"fmt"
     9  
    10  	"github.com/MetalBlockchain/metalgo/database"
    11  	"github.com/MetalBlockchain/metalgo/ids"
    12  )
    13  
    14  const (
    15  	// startDiffKey = [subnetID] + [inverseHeight]
    16  	startDiffKeyLength = ids.IDLen + database.Uint64Size
    17  	// diffKey = [subnetID] + [inverseHeight] + [nodeID]
    18  	diffKeyLength = startDiffKeyLength + ids.NodeIDLen
    19  	// diffKeyNodeIDOffset = [subnetIDLen] + [inverseHeightLen]
    20  	diffKeyNodeIDOffset = ids.IDLen + database.Uint64Size
    21  
    22  	// weightValue = [isNegative] + [weight]
    23  	weightValueLength = database.BoolSize + database.Uint64Size
    24  )
    25  
    26  var (
    27  	errUnexpectedDiffKeyLength     = fmt.Errorf("expected diff key length %d", diffKeyLength)
    28  	errUnexpectedWeightValueLength = fmt.Errorf("expected weight value length %d", weightValueLength)
    29  )
    30  
    31  // marshalStartDiffKey is used to determine the starting key when iterating.
    32  //
    33  // Invariant: the result is a prefix of [marshalDiffKey] when called with the
    34  // same arguments.
    35  func marshalStartDiffKey(subnetID ids.ID, height uint64) []byte {
    36  	key := make([]byte, startDiffKeyLength)
    37  	copy(key, subnetID[:])
    38  	packIterableHeight(key[ids.IDLen:], height)
    39  	return key
    40  }
    41  
    42  func marshalDiffKey(subnetID ids.ID, height uint64, nodeID ids.NodeID) []byte {
    43  	key := make([]byte, diffKeyLength)
    44  	copy(key, subnetID[:])
    45  	packIterableHeight(key[ids.IDLen:], height)
    46  	copy(key[diffKeyNodeIDOffset:], nodeID.Bytes())
    47  	return key
    48  }
    49  
    50  func unmarshalDiffKey(key []byte) (ids.ID, uint64, ids.NodeID, error) {
    51  	if len(key) != diffKeyLength {
    52  		return ids.Empty, 0, ids.EmptyNodeID, errUnexpectedDiffKeyLength
    53  	}
    54  	var (
    55  		subnetID ids.ID
    56  		nodeID   ids.NodeID
    57  	)
    58  	copy(subnetID[:], key)
    59  	height := unpackIterableHeight(key[ids.IDLen:])
    60  	copy(nodeID[:], key[diffKeyNodeIDOffset:])
    61  	return subnetID, height, nodeID, nil
    62  }
    63  
    64  func marshalWeightDiff(diff *ValidatorWeightDiff) []byte {
    65  	value := make([]byte, weightValueLength)
    66  	if diff.Decrease {
    67  		value[0] = database.BoolTrue
    68  	}
    69  	binary.BigEndian.PutUint64(value[database.BoolSize:], diff.Amount)
    70  	return value
    71  }
    72  
    73  func unmarshalWeightDiff(value []byte) (*ValidatorWeightDiff, error) {
    74  	if len(value) != weightValueLength {
    75  		return nil, errUnexpectedWeightValueLength
    76  	}
    77  	return &ValidatorWeightDiff{
    78  		Decrease: value[0] == database.BoolTrue,
    79  		Amount:   binary.BigEndian.Uint64(value[database.BoolSize:]),
    80  	}, nil
    81  }
    82  
    83  // Note: [height] is encoded as a bit flipped big endian number so that
    84  // iterating lexicographically results in iterating in decreasing heights.
    85  //
    86  // Invariant: [key] has sufficient length
    87  func packIterableHeight(key []byte, height uint64) {
    88  	binary.BigEndian.PutUint64(key, ^height)
    89  }
    90  
    91  // Because we bit flip the height when constructing the key, we must remember to
    92  // bip flip again here.
    93  //
    94  // Invariant: [key] has sufficient length
    95  func unpackIterableHeight(key []byte) uint64 {
    96  	return ^binary.BigEndian.Uint64(key)
    97  }