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 }