mirror of
https://gitlab.com/pulsechaincom/erigon-pulse.git
synced 2024-12-22 11:41:19 +00:00
186 lines
6.0 KiB
Go
186 lines
6.0 KiB
Go
package dbutils
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"errors"
|
|
"fmt"
|
|
|
|
libcommon "github.com/ledgerwatch/erigon-lib/common"
|
|
"github.com/ledgerwatch/erigon-lib/common/length"
|
|
)
|
|
|
|
const NumberLength = 8
|
|
|
|
// EncodeBlockNumber encodes a block number as big endian uint64
|
|
func EncodeBlockNumber(number uint64) []byte {
|
|
enc := make([]byte, NumberLength)
|
|
binary.BigEndian.PutUint64(enc, number)
|
|
return enc
|
|
}
|
|
|
|
var ErrInvalidSize = errors.New("bit endian number has an invalid size")
|
|
|
|
func DecodeBlockNumber(number []byte) (uint64, error) {
|
|
if len(number) != NumberLength {
|
|
return 0, fmt.Errorf("%w: %d", ErrInvalidSize, len(number))
|
|
}
|
|
return binary.BigEndian.Uint64(number), nil
|
|
}
|
|
|
|
// HeaderKey = num (uint64 big endian) + hash
|
|
func HeaderKey(number uint64, hash libcommon.Hash) []byte {
|
|
k := make([]byte, NumberLength+length.Hash)
|
|
binary.BigEndian.PutUint64(k, number)
|
|
copy(k[NumberLength:], hash[:])
|
|
return k
|
|
}
|
|
|
|
// BlockBodyKey = num (uint64 big endian) + hash
|
|
func BlockBodyKey(number uint64, hash libcommon.Hash) []byte {
|
|
k := make([]byte, NumberLength+length.Hash)
|
|
binary.BigEndian.PutUint64(k, number)
|
|
copy(k[NumberLength:], hash[:])
|
|
return k
|
|
}
|
|
|
|
// LogKey = blockN (uint64 big endian) + txId (uint32 big endian)
|
|
func LogKey(blockNumber uint64, txId uint32) []byte {
|
|
newK := make([]byte, 8+4)
|
|
binary.BigEndian.PutUint64(newK, blockNumber)
|
|
binary.BigEndian.PutUint32(newK[8:], txId)
|
|
return newK
|
|
}
|
|
|
|
// bloomBitsKey = bloomBitsPrefix + bit (uint16 big endian) + section (uint64 big endian) + hash
|
|
func BloomBitsKey(bit uint, section uint64, hash libcommon.Hash) []byte {
|
|
key := append(make([]byte, 10), hash.Bytes()...)
|
|
|
|
binary.BigEndian.PutUint16(key[0:], uint16(bit))
|
|
binary.BigEndian.PutUint64(key[2:], section)
|
|
|
|
return key
|
|
}
|
|
|
|
// AddrHash + KeyHash
|
|
// Only for trie
|
|
func GenerateCompositeTrieKey(addressHash libcommon.Hash, seckey libcommon.Hash) []byte {
|
|
compositeKey := make([]byte, 0, length.Hash+length.Hash)
|
|
compositeKey = append(compositeKey, addressHash[:]...)
|
|
compositeKey = append(compositeKey, seckey[:]...)
|
|
return compositeKey
|
|
}
|
|
|
|
// AddrHash + incarnation + KeyHash
|
|
// For contract storage
|
|
func GenerateCompositeStorageKey(addressHash libcommon.Hash, incarnation uint64, seckey libcommon.Hash) []byte {
|
|
compositeKey := make([]byte, length.Hash+length.Incarnation+length.Hash)
|
|
copy(compositeKey, addressHash[:])
|
|
binary.BigEndian.PutUint64(compositeKey[length.Hash:], incarnation)
|
|
copy(compositeKey[length.Hash+length.Incarnation:], seckey[:])
|
|
return compositeKey
|
|
}
|
|
|
|
func ParseCompositeStorageKey(compositeKey []byte) (libcommon.Hash, uint64, libcommon.Hash) {
|
|
prefixLen := length.Hash + length.Incarnation
|
|
addrHash, inc := ParseStoragePrefix(compositeKey[:prefixLen])
|
|
var key libcommon.Hash
|
|
copy(key[:], compositeKey[prefixLen:prefixLen+length.Hash])
|
|
return addrHash, inc, key
|
|
}
|
|
|
|
// AddrHash + incarnation + KeyHash
|
|
// For contract storage (for plain state)
|
|
func PlainGenerateCompositeStorageKey(address []byte, incarnation uint64, key []byte) []byte {
|
|
compositeKey := make([]byte, length.Addr+length.Incarnation+length.Hash)
|
|
copy(compositeKey, address)
|
|
binary.BigEndian.PutUint64(compositeKey[length.Addr:], incarnation)
|
|
copy(compositeKey[length.Addr+length.Incarnation:], key)
|
|
return compositeKey
|
|
}
|
|
|
|
func PlainParseCompositeStorageKey(compositeKey []byte) (libcommon.Address, uint64, libcommon.Hash) {
|
|
prefixLen := length.Addr + length.Incarnation
|
|
addr, inc := PlainParseStoragePrefix(compositeKey[:prefixLen])
|
|
var key libcommon.Hash
|
|
copy(key[:], compositeKey[prefixLen:prefixLen+length.Hash])
|
|
return addr, inc, key
|
|
}
|
|
|
|
// AddrHash + incarnation + StorageHashPrefix
|
|
func GenerateCompositeStoragePrefix(addressHash []byte, incarnation uint64, storageHashPrefix []byte) []byte {
|
|
key := make([]byte, length.Hash+length.Incarnation+len(storageHashPrefix))
|
|
copy(key, addressHash)
|
|
binary.BigEndian.PutUint64(key[length.Hash:], incarnation)
|
|
copy(key[length.Hash+length.Incarnation:], storageHashPrefix)
|
|
return key
|
|
}
|
|
|
|
// address hash + incarnation prefix
|
|
func GenerateStoragePrefix(addressHash []byte, incarnation uint64) []byte {
|
|
prefix := make([]byte, length.Hash+NumberLength)
|
|
copy(prefix, addressHash)
|
|
binary.BigEndian.PutUint64(prefix[length.Hash:], incarnation)
|
|
return prefix
|
|
}
|
|
|
|
// address hash + incarnation prefix (for plain state)
|
|
func PlainGenerateStoragePrefix(address []byte, incarnation uint64) []byte {
|
|
prefix := make([]byte, length.Addr+NumberLength)
|
|
copy(prefix, address)
|
|
binary.BigEndian.PutUint64(prefix[length.Addr:], incarnation)
|
|
return prefix
|
|
}
|
|
|
|
func PlainParseStoragePrefix(prefix []byte) (libcommon.Address, uint64) {
|
|
var addr libcommon.Address
|
|
copy(addr[:], prefix[:length.Addr])
|
|
inc := binary.BigEndian.Uint64(prefix[length.Addr : length.Addr+length.Incarnation])
|
|
return addr, inc
|
|
}
|
|
|
|
func ParseStoragePrefix(prefix []byte) (libcommon.Hash, uint64) {
|
|
var addrHash libcommon.Hash
|
|
copy(addrHash[:], prefix[:length.Hash])
|
|
inc := binary.BigEndian.Uint64(prefix[length.Hash : length.Hash+length.Incarnation])
|
|
return addrHash, inc
|
|
}
|
|
|
|
// Key + blockNum
|
|
func CompositeKeySuffix(key []byte, timestamp uint64) (composite, encodedTS []byte) {
|
|
encodedTS = encodeTimestamp(timestamp)
|
|
composite = make([]byte, len(key)+len(encodedTS))
|
|
copy(composite, key)
|
|
copy(composite[len(key):], encodedTS)
|
|
return composite, encodedTS
|
|
}
|
|
|
|
// encodeTimestamp has the property: if a < b, then Encoding(a) < Encoding(b) lexicographically
|
|
func encodeTimestamp(timestamp uint64) []byte {
|
|
var suffix []byte
|
|
var limit uint64 = 32
|
|
|
|
for bytecount := 1; bytecount <= 8; bytecount++ {
|
|
if timestamp < limit {
|
|
suffix = make([]byte, bytecount)
|
|
b := timestamp
|
|
for i := bytecount - 1; i > 0; i-- {
|
|
suffix[i] = byte(b & 0xff)
|
|
b >>= 8
|
|
}
|
|
suffix[0] = byte(b) | (byte(bytecount) << 5) // 3 most significant bits of the first byte are bytecount
|
|
break
|
|
}
|
|
limit <<= 8
|
|
}
|
|
return suffix
|
|
}
|
|
|
|
func decodeTimestamp(suffix []byte) (uint64, []byte) {
|
|
bytecount := int(suffix[0] >> 5)
|
|
timestamp := uint64(suffix[0] & 0x1f)
|
|
for i := 1; i < bytecount; i++ {
|
|
timestamp = (timestamp << 8) | uint64(suffix[i])
|
|
}
|
|
return timestamp, suffix[bytecount:]
|
|
}
|