package prefixes import ( "bytes" "encoding/binary" "encoding/hex" "fmt" "log" "reflect" "sort" "strings" "github.com/lbryio/lbry.go/extras/errors" ) const ( ClaimToSupport = 'K' SupportToClaim = 'L' ClaimToTXO = 'E' TXOToClaim = 'G' ClaimToChannel = 'I' ChannelToClaim = 'J' ClaimShortIdPrefix = 'F' EffectiveAmount = 'D' ClaimExpiration = 'O' ClaimTakeover = 'P' PendingActivation = 'Q' ActivatedClaimAndSupport = 'R' ActiveAmount = 'S' Repost = 'V' RepostedClaim = 'W' Undo = 'M' ClaimDiff = 'Y' Tx = 'B' BlockHash = 'C' Header = 'H' TxNum = 'N' TxCount = 'T' TxHash = 'X' UTXO = 'u' HashXUTXO = 'h' HashXHistory = 'x' DBState = 's' ChannelCount = 'Z' SupportAmount = 'a' BlockTXs = 'b' ACTIVATED_CLAIM_TXO_TYPE = 1 ACTIVATED_SUPPORT_TXO_TYPE = 2 OnesCompTwiddle uint64 = 0xffffffffffffffff ) type PrefixRowKV struct { Key interface{} Value interface{} } type UTXOKey struct { Prefix []byte `json:"prefix"` HashX []byte `json:"hashx"` TxNum uint32 `json:"tx_num"` Nout uint16 `json:"nout"` } type UTXOValue struct { Amount uint64 `json:"amount"` } type HashXUTXOKey struct { Prefix []byte `json:"prefix"` ShortTXHash []byte `json:"short_tx_hash"` TxNum uint32 `json:"tx_num"` Nout uint16 `json:"nout"` } type HashXUTXOValue struct { HashX []byte `json:"hashx"` } /* class HashXHistoryKey(NamedTuple): hashX: bytes height: int def __str__(self): return f"{self.__class__.__name__}(hashX={self.hashX.hex()}, height={self.height})" class HashXHistoryValue(NamedTuple): hashXes: typing.List[int] */ type HashXHistoryKey struct { Prefix []byte `json:"prefix"` HashX []byte `json:"hashx"` Height uint32 `json:"height"` } type HashXHistoryValue struct { HashXes []uint32 `json:"hashxes"` } /* class BlockHashKey(NamedTuple): height: int class BlockHashValue(NamedTuple): block_hash: bytes def __str__(self): return f"{self.__class__.__name__}(block_hash={self.block_hash.hex()})" */ type BlockHashKey struct { Prefix []byte `json:"prefix"` Height uint32 `json:"height"` } type BlockHashValue struct { BlockHash []byte `json:"block_hash"` } /* class BlockTxsKey(NamedTuple): height: int class BlockTxsValue(NamedTuple): tx_hashes: typing.List[bytes] */ type BlockTxsKey struct { Prefix []byte `json:"prefix"` Height uint32 `json:"height"` } type BlockTxsValue struct { TxHashes []byte `json:"tx_hashes"` } /* class TxCountKey(NamedTuple): height: int class TxCountValue(NamedTuple): tx_count: int */ type TxCountKey struct { Prefix []byte `json:"prefix"` Height uint32 `json:"height"` } type TxCountValue struct { TxCount uint32 `json:"tx_count"` } /* class TxHashKey(NamedTuple): tx_num: int class TxHashValue(NamedTuple): tx_hash: bytes def __str__(self): return f"{self.__class__.__name__}(tx_hash={self.tx_hash.hex()})" */ type TxHashKey struct { Prefix []byte `json:"prefix"` TxNum uint32 `json:"tx_num"` } type TxHashValue struct { TxHash []byte `json:"tx_hash"` } /* class TxNumKey(NamedTuple): tx_hash: bytes def __str__(self): return f"{self.__class__.__name__}(tx_hash={self.tx_hash.hex()})" class TxNumValue(NamedTuple): tx_num: int */ type TxNumKey struct { Prefix []byte `json:"prefix"` TxHash []byte `json:"tx_hash"` } type TxNumValue struct { TxNum int32 `json:"tx_num"` } /* class TxKey(NamedTuple): tx_hash: bytes def __str__(self): return f"{self.__class__.__name__}(tx_hash={self.tx_hash.hex()})" class TxValue(NamedTuple): raw_tx: bytes def __str__(self): return f"{self.__class__.__name__}(raw_tx={base64.b64encode(self.raw_tx)})" */ type TxKey struct { Prefix []byte `json:"prefix"` TxHash []byte `json:"tx_hash"` } type TxValue struct { RawTx []byte `json:"raw_tx"` } /* class BlockHeaderKey(NamedTuple): height: int class BlockHeaderValue(NamedTuple): header: bytes def __str__(self): return f"{self.__class__.__name__}(header={base64.b64encode(self.header)})" */ type BlockHeaderKey struct { Prefix []byte `json:"prefix"` Height int32 `json:"height"` } type BlockHeaderValue struct { Header []byte `json:"header"` } /* class ClaimToTXOKey(typing.NamedTuple): claim_hash: bytes def __str__(self): return f"{self.__class__.__name__}(claim_hash={self.claim_hash.hex()})" class ClaimToTXOValue(typing.NamedTuple): tx_num: int position: int root_tx_num: int root_position: int amount: int # activation: int channel_signature_is_valid: bool name: str @property def normalized_name(self) -> str: try: return normalize_name(self.name) except UnicodeDecodeError: return self.name */ type ClaimToTXOKey struct { Prefix []byte `json:"prefix"` ClaimHash []byte `json:"claim_hash"` } type ClaimToTXOValue struct { TxNum int32 `json:"tx_num"` Position int32 `json:"position"` RootTxNum int32 `json:"root_tx_num"` RootPosition int32 `json:"root_position"` Amount int32 `json:"amount"` ChannelSignatureIsValid bool `json:"channel_signature_is_valid"` Name string `json:"name"` } func (v *ClaimToTXOValue) NormalizedName() string { //TODO implemented return v.Name } /* class TXOToClaimKey(typing.NamedTuple): tx_num: int position: int class TXOToClaimValue(typing.NamedTuple): claim_hash: bytes name: str def __str__(self): return f"{self.__class__.__name__}(claim_hash={self.claim_hash.hex()}, name={self.name})" */ type TXOToClaimKey struct { Prefix []byte `json:"prefix"` TxNum uint32 `json:"tx_num"` Position uint16 `json:"position"` } type TXOToClaimValue struct { ClaimHash []byte `json:"claim_hash"` Name string `json:"name"` } func (k *TXOToClaimKey) PackKey() []byte { prefixLen := 1 // b'>LH' n := prefixLen + 4 + 2 key := make([]byte, n) copy(key, k.Prefix) binary.BigEndian.PutUint32(key[prefixLen:], k.TxNum) binary.BigEndian.PutUint16(key[prefixLen+4:], k.Position) return key } func (v *TXOToClaimValue) PackValue() []byte { nameLen := len(v.Name) n := 20 + 2 + nameLen value := make([]byte, n) copy(value, v.ClaimHash[:20]) binary.BigEndian.PutUint16(value[20:], uint16(nameLen)) copy(value[22:], []byte(v.Name)) return value } func TXOToClaimKeyPackPartialNFields(nFields int) func(*TXOToClaimKey) []byte { return func(u *TXOToClaimKey) []byte { return TXOToClaimKeyPackPartial(u, nFields) } } func TXOToClaimKeyPackPartial(k *TXOToClaimKey, nFields int) []byte { // Limit nFields between 0 and number of fields, we always at least need // the prefix, and we never need to iterate past the number of fields. if nFields > 2 { nFields = 2 } if nFields < 0 { nFields = 0 } prefixLen := 1 var n = prefixLen for i := 0; i <= nFields; i++ { switch i { case 1: n += 4 case 2: n += 2 } } key := make([]byte, n) for i := 0; i <= nFields; i++ { switch i { case 0: copy(key, k.Prefix) case 1: binary.BigEndian.PutUint32(key[prefixLen:], k.TxNum) case 2: binary.BigEndian.PutUint16(key[prefixLen+4:], k.Position) } } return key } func TXOToClaimKeyUnpack(key []byte) *TXOToClaimKey { prefixLen := 1 return &TXOToClaimKey{ Prefix: key[:prefixLen], TxNum: binary.BigEndian.Uint32(key[prefixLen:]), Position: binary.BigEndian.Uint16(key[prefixLen+4:]), } } func TXOToClaimValueUnpack(value []byte) *TXOToClaimValue { nameLen := binary.BigEndian.Uint16(value[20:]) return &TXOToClaimValue{ ClaimHash: value[:20], Name: string(value[22 : 22+nameLen]), } } /* class ClaimShortIDKey(typing.NamedTuple): normalized_name: str partial_claim_id: str root_tx_num: int root_position: int def __str__(self): return f"{self.__class__.__name__}(normalized_name={self.normalized_name}, " \ f"partial_claim_id={self.partial_claim_id}, " \ f"root_tx_num={self.root_tx_num}, root_position={self.root_position})" class ClaimShortIDValue(typing.NamedTuple): tx_num: int position: int */ type ClaimShortIDKey struct { Prefix []byte `json:"prefix"` NormalizedName string `json:"normalized_name"` PartialClaimId string `json:"partial_claim_id"` RootTxNum uint32 `json:"root_tx_num"` RootPosition uint16 `json:"root_position"` } type ClaimShortIDValue struct { TxNum uint32 `json:"tx_num"` Position uint16 `json:"position"` } func (k *ClaimShortIDKey) PackKey() []byte { prefixLen := 1 nameLen := len(k.NormalizedName) partialClaimLen := len(k.PartialClaimId) log.Printf("nameLen: %d, partialClaimLen: %d\n", nameLen, partialClaimLen) n := prefixLen + 2 + nameLen + 1 + partialClaimLen + 4 + 2 key := make([]byte, n) copy(key, k.Prefix) binary.BigEndian.PutUint16(key[prefixLen:], uint16(nameLen)) copy(key[prefixLen+2:], []byte(k.NormalizedName[:nameLen])) key[prefixLen+2+nameLen] = uint8(partialClaimLen) copy(key[prefixLen+2+nameLen+1:], []byte(k.PartialClaimId[:partialClaimLen])) binary.BigEndian.PutUint32(key[prefixLen+2+nameLen+1+partialClaimLen:], k.RootTxNum) binary.BigEndian.PutUint16(key[prefixLen+2+nameLen+1+partialClaimLen+4:], k.RootPosition) return key } func (v *ClaimShortIDValue) PackValue() []byte { value := make([]byte, 6) binary.BigEndian.PutUint32(value, v.TxNum) binary.BigEndian.PutUint16(value[4:], v.Position) return value } func ClaimShortIDKeyPackPartialNFields(nFields int) func(*ClaimShortIDKey) []byte { return func(u *ClaimShortIDKey) []byte { return ClaimShortIDKeyPackPartial(u, nFields) } } func ClaimShortIDKeyPackPartial(k *ClaimShortIDKey, nFields int) []byte { // Limit nFields between 0 and number of fields, we always at least need // the prefix, and we never need to iterate past the number of fields. if nFields > 4 { nFields = 4 } if nFields < 0 { nFields = 0 } // b'>4sLH' prefixLen := 1 nameLen := len(k.NormalizedName) partialClaimLen := len(k.PartialClaimId) var n = prefixLen for i := 0; i <= nFields; i++ { switch i { case 1: n += 2 + nameLen case 2: n += 1 + partialClaimLen case 3: n += 4 case 4: n += 2 } } key := make([]byte, n) for i := 0; i <= nFields; i++ { switch i { case 0: copy(key, k.Prefix) case 1: binary.BigEndian.PutUint16(key[prefixLen:], uint16(nameLen)) copy(key[prefixLen+2:], []byte(k.NormalizedName)) case 2: key[prefixLen+2+nameLen] = uint8(partialClaimLen) copy(key[prefixLen+2+nameLen+1:], []byte(k.PartialClaimId)) case 3: binary.BigEndian.PutUint32(key[prefixLen+2+nameLen+1+partialClaimLen:], k.RootTxNum) case 4: binary.BigEndian.PutUint16(key[prefixLen+2+nameLen+1+partialClaimLen+4:], k.RootPosition) } } return key } func ClaimShortIDKeyUnpack(key []byte) *ClaimShortIDKey { prefixLen := 1 nameLen := int(binary.BigEndian.Uint16(key[prefixLen:])) partialClaimLen := int(uint8(key[prefixLen+2+nameLen])) return &ClaimShortIDKey{ Prefix: key[:prefixLen], NormalizedName: string(key[prefixLen+2 : prefixLen+2+nameLen]), PartialClaimId: string(key[prefixLen+2+nameLen+1 : prefixLen+2+nameLen+1+partialClaimLen]), RootTxNum: binary.BigEndian.Uint32(key[prefixLen+2+nameLen+1+partialClaimLen:]), RootPosition: binary.BigEndian.Uint16(key[prefixLen+2+nameLen+1+partialClaimLen+4:]), } } func ClaimShortIDValueUnpack(value []byte) *ClaimShortIDValue { return &ClaimShortIDValue{ TxNum: binary.BigEndian.Uint32(value), Position: binary.BigEndian.Uint16(value[4:]), } } /* class ClaimToChannelKey(typing.NamedTuple): claim_hash: bytes tx_num: int position: int def __str__(self): return f"{self.__class__.__name__}(claim_hash={self.claim_hash.hex()}, " \ f"tx_num={self.tx_num}, position={self.position})" class ClaimToChannelValue(typing.NamedTuple): signing_hash: bytes def __str__(self): return f"{self.__class__.__name__}(signing_hash={self.signing_hash.hex()})" */ type ClaimToChannelKey struct { Prefix []byte `json:"prefix"` ClaimHash []byte `json:"claim_hash"` TxNum uint32 `json:"tx_num"` Position uint16 `json:"position"` } type ClaimToChannelValue struct { SigningHash []byte `json:"signing_hash"` } func (k *ClaimToChannelKey) PackKey() []byte { prefixLen := 1 // b'>20sLH' n := prefixLen + 20 + 4 + 2 key := make([]byte, n) copy(key, k.Prefix) copy(key[prefixLen:], k.ClaimHash[:20]) binary.BigEndian.PutUint32(key[prefixLen+20:], k.TxNum) binary.BigEndian.PutUint16(key[prefixLen+24:], k.Position) return key } func (v *ClaimToChannelValue) PackValue() []byte { value := make([]byte, 20) copy(value, v.SigningHash[:20]) return value } func ClaimToChannelKeyPackPartialNFields(nFields int) func(*ClaimToChannelKey) []byte { return func(u *ClaimToChannelKey) []byte { return ClaimToChannelKeyPackPartial(u, nFields) } } func ClaimToChannelKeyPackPartial(k *ClaimToChannelKey, nFields int) []byte { // Limit nFields between 0 and number of fields, we always at least need // the prefix, and we never need to iterate past the number of fields. if nFields > 3 { nFields = 3 } if nFields < 0 { nFields = 0 } // b'>4sLH' prefixLen := 1 var n = prefixLen for i := 0; i <= nFields; i++ { switch i { case 1: n += 20 case 2: n += 4 case 3: n += 2 } } key := make([]byte, n) for i := 0; i <= nFields; i++ { switch i { case 0: copy(key, k.Prefix) case 1: copy(key[prefixLen:], k.ClaimHash[:20]) case 2: binary.BigEndian.PutUint32(key[prefixLen+20:], k.TxNum) case 3: binary.BigEndian.PutUint16(key[prefixLen+24:], k.Position) } } return key } func ClaimToChannelKeyUnpack(key []byte) *ClaimToChannelKey { prefixLen := 1 return &ClaimToChannelKey{ Prefix: key[:prefixLen], ClaimHash: key[prefixLen : prefixLen+20], TxNum: binary.BigEndian.Uint32(key[prefixLen+20:]), Position: binary.BigEndian.Uint16(key[prefixLen+24:]), } } func ClaimToChannelValueUnpack(value []byte) *ClaimToChannelValue { return &ClaimToChannelValue{ SigningHash: value[:20], } } /* class ChannelToClaimKey(typing.NamedTuple): signing_hash: bytes name: str tx_num: int position: int def __str__(self): return f"{self.__class__.__name__}(signing_hash={self.signing_hash.hex()}, name={self.name}, " \ f"tx_num={self.tx_num}, position={self.position})" class ChannelToClaimValue(typing.NamedTuple): claim_hash: bytes def __str__(self): return f"{self.__class__.__name__}(claim_hash={self.claim_hash.hex()})" */ type ChannelToClaimKey struct { Prefix []byte `json:"prefix"` SigningHash []byte `json:"signing_hash"` Name string `json:"name"` TxNum uint32 `json:"tx_num"` Position uint16 `json:"position"` } type ChannelToClaimValue struct { ClaimHash []byte `json:"claim_hash"` } func (k *ChannelToClaimKey) PackKey() []byte { prefixLen := 1 nameLen := len(k.Name) n := prefixLen + 20 + 2 + nameLen + 4 + 2 key := make([]byte, n) copy(key, k.Prefix) copy(key[prefixLen:], k.SigningHash[:20]) binary.BigEndian.PutUint16(key[prefixLen+20:], uint16(nameLen)) copy(key[prefixLen+22:], []byte(k.Name[:nameLen])) binary.BigEndian.PutUint32(key[prefixLen+22+nameLen:], k.TxNum) binary.BigEndian.PutUint16(key[prefixLen+22+nameLen+4:], k.Position) return key } func (v *ChannelToClaimValue) PackValue() []byte { value := make([]byte, 20) copy(value, v.ClaimHash[:20]) return value } func ChannelToClaimKeyPackPartialNFields(nFields int) func(*ChannelToClaimKey) []byte { return func(u *ChannelToClaimKey) []byte { return ChannelToClaimKeyPackPartial(u, nFields) } } func ChannelToClaimKeyPackPartial(k *ChannelToClaimKey, nFields int) []byte { // Limit nFields between 0 and number of fields, we always at least need // the prefix, and we never need to iterate past the number of fields. if nFields > 4 { nFields = 4 } if nFields < 0 { nFields = 0 } nameLen := len(k.Name) prefixLen := 1 var n = prefixLen for i := 0; i <= nFields; i++ { switch i { case 1: n += 20 case 2: n += 2 + nameLen case 3: n += 4 case 4: n += 2 } } key := make([]byte, n) for i := 0; i <= nFields; i++ { switch i { case 0: copy(key, k.Prefix) case 1: copy(key[prefixLen:], k.SigningHash[:20]) case 2: binary.BigEndian.PutUint16(key[prefixLen+20:], uint16(nameLen)) copy(key[prefixLen+22:], []byte(k.Name)) case 3: binary.BigEndian.PutUint32(key[prefixLen+22+nameLen:], k.TxNum) case 4: binary.BigEndian.PutUint16(key[prefixLen+22+nameLen+4:], k.Position) } } return key } func ChannelToClaimKeyUnpack(key []byte) *ChannelToClaimKey { prefixLen := 1 nameLen := int(binary.BigEndian.Uint16(key[prefixLen+20:])) return &ChannelToClaimKey{ Prefix: key[:prefixLen], SigningHash: key[prefixLen : prefixLen+20], Name: string(key[prefixLen+22 : prefixLen+22+nameLen]), TxNum: binary.BigEndian.Uint32(key[prefixLen+22+nameLen:]), Position: binary.BigEndian.Uint16(key[prefixLen+22+nameLen+4:]), } } func ChannelToClaimValueUnpack(value []byte) *ChannelToClaimValue { return &ChannelToClaimValue{ ClaimHash: value[:20], } } /* class ChannelCountKey(typing.NamedTuple): channel_hash: bytes def __str__(self): return f"{self.__class__.__name__}(channel_hash={self.channel_hash.hex()})" class ChannelCountValue(typing.NamedTuple): count: int */ type ChannelCountKey struct { Prefix []byte `json:"prefix"` ChannelHash []byte `json:"channel_hash"` } type ChannelCountValue struct { Count int32 `json:"count"` } /* class SupportAmountKey(typing.NamedTuple): claim_hash: bytes def __str__(self): return f"{self.__class__.__name__}(claim_hash={self.claim_hash.hex()})" class SupportAmountValue(typing.NamedTuple): amount: int */ type SupportAmountKey struct { Prefix []byte `json:"prefix"` ClaimHash []byte `json:"claim_hash"` } type SupportAmountValue struct { Amount int32 `json:"amount"` } /* class ClaimToSupportKey(typing.NamedTuple): claim_hash: bytes tx_num: int position: int def __str__(self): return f"{self.__class__.__name__}(claim_hash={self.claim_hash.hex()}, tx_num={self.tx_num}, " \ f"position={self.position})" class ClaimToSupportValue(typing.NamedTuple): amount: int */ type ClaimToSupportKey struct { Prefix []byte `json:"prefix"` ClaimHash []byte `json:"claim_hash"` TxNum uint32 `json:"tx_num"` Position uint16 `json:"position"` } type ClaimToSupportValue struct { Amount uint64 `json:"amount"` } func (k *ClaimToSupportKey) PackKey() []byte { prefixLen := 1 // b'>20sLH' n := prefixLen + 20 + 4 + 2 key := make([]byte, n) copy(key, k.Prefix) copy(key[prefixLen:], k.ClaimHash[:20]) binary.BigEndian.PutUint32(key[prefixLen+20:], k.TxNum) binary.BigEndian.PutUint16(key[prefixLen+24:], k.Position) return key } func (v *ClaimToSupportValue) PackValue() []byte { value := make([]byte, 8) binary.BigEndian.PutUint64(value, v.Amount) return value } func ClaimToSupportKeyPackPartialNFields(nFields int) func(*ClaimToSupportKey) []byte { return func(u *ClaimToSupportKey) []byte { return ClaimToSupportKeyPackPartial(u, nFields) } } func ClaimToSupportKeyPackPartial(k *ClaimToSupportKey, nFields int) []byte { // Limit nFields between 0 and number of fields, we always at least need // the prefix, and we never need to iterate past the number of fields. if nFields > 3 { nFields = 3 } if nFields < 0 { nFields = 0 } // b'>4sLH' prefixLen := 1 var n = prefixLen for i := 0; i <= nFields; i++ { switch i { case 1: n += 20 case 2: n += 4 case 3: n += 2 } } key := make([]byte, n) for i := 0; i <= nFields; i++ { switch i { case 0: copy(key, k.Prefix) case 1: copy(key[prefixLen:], k.ClaimHash) case 2: binary.BigEndian.PutUint32(key[prefixLen+20:], k.TxNum) case 3: binary.BigEndian.PutUint16(key[prefixLen+24:], k.Position) } } return key } func ClaimToSupportKeyUnpack(key []byte) *ClaimToSupportKey { prefixLen := 1 return &ClaimToSupportKey{ Prefix: key[:prefixLen], ClaimHash: key[prefixLen : prefixLen+20], TxNum: binary.BigEndian.Uint32(key[prefixLen+20:]), Position: binary.BigEndian.Uint16(key[prefixLen+24:]), } } func ClaimToSupportValueUnpack(value []byte) *ClaimToSupportValue { return &ClaimToSupportValue{ Amount: binary.BigEndian.Uint64(value), } } /* class SupportToClaimKey(typing.NamedTuple): tx_num: int position: int class SupportToClaimValue(typing.NamedTuple): claim_hash: bytes def __str__(self): return f"{self.__class__.__name__}(claim_hash={self.claim_hash.hex()})" */ type SupportToClaimKey struct { Prefix []byte `json:"prefix"` TxNum uint32 `json:"tx_num"` Position uint16 `json:"position"` } type SupportToClaimValue struct { ClaimHash []byte `json:"claim_hash"` } func (k *SupportToClaimKey) PackKey() []byte { prefixLen := 1 // b'>LH' n := prefixLen + 4 + 2 key := make([]byte, n) copy(key, k.Prefix) binary.BigEndian.PutUint32(key[prefixLen:], k.TxNum) binary.BigEndian.PutUint16(key[prefixLen+4:], k.Position) return key } func (v *SupportToClaimValue) PackValue() []byte { value := make([]byte, 20) copy(value, v.ClaimHash) return value } func SupportToClaimKeyPackPartialNFields(nFields int) func(*SupportToClaimKey) []byte { return func(u *SupportToClaimKey) []byte { return SupportToClaimKeyPackPartial(u, nFields) } } func SupportToClaimKeyPackPartial(k *SupportToClaimKey, nFields int) []byte { // Limit nFields between 0 and number of fields, we always at least need // the prefix, and we never need to iterate past the number of fields. if nFields > 2 { nFields = 2 } if nFields < 0 { nFields = 0 } prefixLen := 1 var n = prefixLen for i := 0; i <= nFields; i++ { switch i { case 1: n += 4 case 2: n += 2 } } key := make([]byte, n) for i := 0; i <= nFields; i++ { switch i { case 0: copy(key, k.Prefix) case 1: binary.BigEndian.PutUint32(key[prefixLen:], k.TxNum) case 2: binary.BigEndian.PutUint16(key[prefixLen+4:], k.Position) } } return key } func SupportToClaimKeyUnpack(key []byte) *SupportToClaimKey { prefixLen := 1 return &SupportToClaimKey{ Prefix: key[:prefixLen], TxNum: binary.BigEndian.Uint32(key[prefixLen:]), Position: binary.BigEndian.Uint16(key[prefixLen+4:]), } } func SupportToClaimValueUnpack(value []byte) *SupportToClaimValue { return &SupportToClaimValue{ ClaimHash: value[:20], } } /* class ClaimExpirationKey(typing.NamedTuple): expiration: int tx_num: int position: int class ClaimExpirationValue(typing.NamedTuple): claim_hash: bytes normalized_name: str def __str__(self): return f"{self.__class__.__name__}(claim_hash={self.claim_hash.hex()}, normalized_name={self.normalized_name})" */ type ClaimExpirationKey struct { Prefix []byte `json:"prefix"` Expiration uint32 `json:"expiration"` TxNum uint32 `json:"tx_num"` Position uint16 `json:"position"` } type ClaimExpirationValue struct { ClaimHash []byte `json:"claim_hash"` NormalizedName string `json:"normalized_name"` } func (k *ClaimExpirationKey) PackKey() []byte { prefixLen := 1 // b'>LLH' n := prefixLen + 4 + 4 + 2 key := make([]byte, n) copy(key, k.Prefix) binary.BigEndian.PutUint32(key[prefixLen:], k.Expiration) binary.BigEndian.PutUint32(key[prefixLen+4:], k.TxNum) binary.BigEndian.PutUint16(key[prefixLen+8:], k.Position) return key } func (v *ClaimExpirationValue) PackValue() []byte { nameLen := len(v.NormalizedName) n := 20 + 2 + nameLen value := make([]byte, n) copy(value, v.ClaimHash) binary.BigEndian.PutUint16(value[20:], uint16(nameLen)) copy(value[22:], []byte(v.NormalizedName)) return value } func ClaimExpirationKeyPackPartialNFields(nFields int) func(*ClaimExpirationKey) []byte { return func(u *ClaimExpirationKey) []byte { return ClaimExpirationKeyPackPartial(u, nFields) } } func ClaimExpirationKeyPackPartial(k *ClaimExpirationKey, nFields int) []byte { // Limit nFields between 0 and number of fields, we always at least need // the prefix, and we never need to iterate past the number of fields. if nFields > 3 { nFields = 3 } if nFields < 0 { nFields = 0 } // b'>4sLH' prefixLen := 1 var n = prefixLen for i := 0; i <= nFields; i++ { switch i { case 1: n += 4 case 2: n += 4 case 3: n += 2 } } key := make([]byte, n) for i := 0; i <= nFields; i++ { switch i { case 0: copy(key, k.Prefix) case 1: binary.BigEndian.PutUint32(key[prefixLen:], k.Expiration) case 2: binary.BigEndian.PutUint32(key[prefixLen+4:], k.TxNum) case 3: binary.BigEndian.PutUint16(key[prefixLen+8:], k.Position) } } return key } func ClaimExpirationKeyUnpack(key []byte) *ClaimExpirationKey { prefixLen := 1 return &ClaimExpirationKey{ Prefix: key[:prefixLen], Expiration: binary.BigEndian.Uint32(key[prefixLen:]), TxNum: binary.BigEndian.Uint32(key[prefixLen+4:]), Position: binary.BigEndian.Uint16(key[prefixLen+8:]), } } func ClaimExpirationValueUnpack(value []byte) *ClaimExpirationValue { nameLen := binary.BigEndian.Uint16(value[20:]) return &ClaimExpirationValue{ ClaimHash: value[:20], NormalizedName: string(value[22 : 22+nameLen]), } } /* class ClaimTakeoverKey(typing.NamedTuple): normalized_name: str class ClaimTakeoverValue(typing.NamedTuple): claim_hash: bytes height: int def __str__(self): return f"{self.__class__.__name__}(claim_hash={self.claim_hash.hex()}, height={self.height})" */ type ClaimTakeoverKey struct { Prefix []byte `json:"prefix"` NormalizedName string `json:"normalized_name"` } type ClaimTakeoverValue struct { ClaimHash []byte `json:"claim_hash"` Height uint32 `json:"height"` } func (v *ClaimTakeoverValue) String() string { return fmt.Sprintf( "%s(claim_hash=%s, height=%d)", reflect.TypeOf(v), hex.EncodeToString(v.ClaimHash), v.Height, ) } func (k *ClaimTakeoverKey) PackKey() []byte { prefixLen := 1 nameLen := len(k.NormalizedName) n := prefixLen + 2 + nameLen key := make([]byte, n) copy(key, k.Prefix) binary.BigEndian.PutUint16(key[prefixLen:], uint16(nameLen)) copy(key[prefixLen+2:], []byte(k.NormalizedName)) return key } func (v *ClaimTakeoverValue) PackValue() []byte { // b'>20sL' value := make([]byte, 24) copy(value, v.ClaimHash[:20]) binary.BigEndian.PutUint32(value[20:], uint32(v.Height)) return value } func ClaimTakeoverKeyPackPartialNFields(nFields int) func(*ClaimTakeoverKey) []byte { return func(u *ClaimTakeoverKey) []byte { return ClaimTakeoverKeyPackPartial(u, nFields) } } func ClaimTakeoverKeyPackPartial(k *ClaimTakeoverKey, nFields int) []byte { // Limit nFields between 0 and number of fields, we always at least need // the prefix, and we never need to iterate past the number of fields. if nFields > 1 { nFields = 1 } if nFields < 0 { nFields = 0 } prefixLen := 1 nameLen := len(k.NormalizedName) var n = prefixLen for i := 0; i <= nFields; i++ { switch i { case 1: n += 2 + nameLen } } key := make([]byte, n) for i := 0; i <= nFields; i++ { switch i { case 0: copy(key, k.Prefix) case 1: binary.BigEndian.PutUint16(key[prefixLen:], uint16(nameLen)) copy(key[prefixLen+2:], []byte(k.NormalizedName)) } } return key } func ClaimTakeoverKeyUnpack(key []byte) *ClaimTakeoverKey { prefixLen := 1 nameLen := binary.BigEndian.Uint16(key[prefixLen:]) return &ClaimTakeoverKey{ Prefix: key[:prefixLen], NormalizedName: string(key[prefixLen+2 : prefixLen+2+int(nameLen)]), } } func ClaimTakeoverValueUnpack(value []byte) *ClaimTakeoverValue { return &ClaimTakeoverValue{ ClaimHash: value[:20], Height: binary.BigEndian.Uint32(value[20:]), } } /* class PendingActivationKey(typing.NamedTuple): height: int txo_type: int tx_num: int position: int @property def is_support(self) -> bool: return self.txo_type == ACTIVATED_SUPPORT_TXO_TYPE @property def is_claim(self) -> bool: return self.txo_type == ACTIVATED_CLAIM_TXO_TYPE class PendingActivationValue(typing.NamedTuple): claim_hash: bytes normalized_name: str def __str__(self): return f"{self.__class__.__name__}(claim_hash={self.claim_hash.hex()}, normalized_name={self.normalized_name})" */ type PendingActivationKey struct { Prefix []byte `json:"prefix"` Height uint32 `json:"height"` TxoType uint8 `json:"txo_type"` TxNum uint32 `json:"tx_num"` Position uint16 `json:"position"` } func (k *PendingActivationKey) IsSupport() bool { return k.TxoType == ACTIVATED_SUPPORT_TXO_TYPE } func (k *PendingActivationKey) IsClaim() bool { return k.TxoType == ACTIVATED_CLAIM_TXO_TYPE } type PendingActivationValue struct { ClaimHash []byte `json:"claim_hash"` NormalizedName string `json:"normalized_name"` } func (k *PendingActivationKey) PackKey() []byte { prefixLen := 1 // b'>LBLH' n := prefixLen + 4 + 1 + 4 + 2 key := make([]byte, n) copy(key, k.Prefix) binary.BigEndian.PutUint32(key[prefixLen:], k.Height) key[prefixLen+4] = k.TxoType binary.BigEndian.PutUint32(key[prefixLen+5:], k.TxNum) binary.BigEndian.PutUint16(key[prefixLen+9:], k.Position) return key } func (v *PendingActivationValue) PackValue() []byte { nameLen := len(v.NormalizedName) n := 20 + 2 + nameLen value := make([]byte, n) copy(value, v.ClaimHash[:20]) binary.BigEndian.PutUint16(value[20:], uint16(nameLen)) copy(value[22:], []byte(v.NormalizedName)) return value } func PendingActivationKeyPackPartialNFields(nFields int) func(*PendingActivationKey) []byte { return func(u *PendingActivationKey) []byte { return PendingActivationKeyPackPartial(u, nFields) } } func PendingActivationKeyPackPartial(k *PendingActivationKey, nFields int) []byte { // Limit nFields between 0 and number of fields, we always at least need // the prefix, and we never need to iterate past the number of fields. if nFields > 4 { nFields = 4 } if nFields < 0 { nFields = 0 } // b'>4sLH' prefixLen := 1 var n = prefixLen for i := 0; i <= nFields; i++ { switch i { case 1: n += 4 case 2: n += 1 case 3: n += 4 case 4: n += 2 } } key := make([]byte, n) for i := 0; i <= nFields; i++ { switch i { case 0: copy(key, k.Prefix) case 1: binary.BigEndian.PutUint32(key[prefixLen:], k.Height) case 2: key[prefixLen+4] = k.TxoType case 3: binary.BigEndian.PutUint32(key[prefixLen+5:], k.TxNum) case 4: binary.BigEndian.PutUint16(key[prefixLen+9:], k.Position) } } return key } func PendingActivationKeyUnpack(key []byte) *PendingActivationKey { prefixLen := 1 return &PendingActivationKey{ Prefix: key[:prefixLen], Height: binary.BigEndian.Uint32(key[prefixLen:]), TxoType: key[prefixLen+4], TxNum: binary.BigEndian.Uint32(key[prefixLen+5:]), Position: binary.BigEndian.Uint16(key[prefixLen+9:]), } } func PendingActivationValueUnpack(value []byte) *PendingActivationValue { nameLen := binary.BigEndian.Uint16(value[20:]) return &PendingActivationValue{ ClaimHash: value[:20], NormalizedName: string(value[22 : 22+nameLen]), } } /* class ActivationKey(typing.NamedTuple): txo_type: int tx_num: int position: int class ActivationValue(typing.NamedTuple): height: int claim_hash: bytes normalized_name: str def __str__(self): return f"{self.__class__.__name__}(height={self.height}, claim_hash={self.claim_hash.hex()}, " \ f"normalized_name={self.normalized_name})" */ type ActivationKey struct { Prefix []byte `json:"prefix"` TxoType uint8 `json:"txo_type"` TxNum uint32 `json:"tx_num"` Position uint16 `json:"position"` } type ActivationValue struct { Height uint32 `json:"height"` ClaimHash []byte `json:"claim_hash"` NormalizedName string `json:"normalized_name"` } func (k *ActivationKey) PackKey() []byte { prefixLen := 1 // b'>BLH' n := prefixLen + 1 + 4 + 2 key := make([]byte, n) copy(key, k.Prefix) copy(key[prefixLen:], []byte{k.TxoType}) binary.BigEndian.PutUint32(key[prefixLen+1:], k.TxNum) binary.BigEndian.PutUint16(key[prefixLen+5:], k.Position) return key } func (v *ActivationValue) PackValue() []byte { nameLen := len(v.NormalizedName) n := 4 + 20 + 2 + nameLen value := make([]byte, n) binary.BigEndian.PutUint32(value, v.Height) copy(value[4:], v.ClaimHash[:20]) binary.BigEndian.PutUint16(value[24:], uint16(nameLen)) copy(value[26:], []byte(v.NormalizedName)) return value } func ActivationKeyPackPartialNFields(nFields int) func(*ActivationKey) []byte { return func(u *ActivationKey) []byte { return ActivationKeyPackPartial(u, nFields) } } func ActivationKeyPackPartial(k *ActivationKey, nFields int) []byte { // Limit nFields between 0 and number of fields, we always at least need // the prefix, and we never need to iterate past the number of fields. if nFields > 3 { nFields = 3 } if nFields < 0 { nFields = 0 } prefixLen := 1 var n = prefixLen for i := 0; i <= nFields; i++ { switch i { case 1: n += 1 case 2: n += 4 case 3: n += 2 } } key := make([]byte, n) for i := 0; i <= nFields; i++ { switch i { case 0: copy(key, k.Prefix) case 1: key[prefixLen] = k.TxoType case 2: binary.BigEndian.PutUint32(key[prefixLen+1:], k.TxNum) case 3: binary.BigEndian.PutUint16(key[prefixLen+5:], k.Position) } } return key } func ActivationKeyUnpack(key []byte) *ActivationKey { prefixLen := 1 return &ActivationKey{ Prefix: key[:prefixLen], TxoType: key[prefixLen], TxNum: binary.BigEndian.Uint32(key[prefixLen+1:]), Position: binary.BigEndian.Uint16(key[prefixLen+5:]), } } func ActivationValueUnpack(value []byte) *ActivationValue { nameLen := binary.BigEndian.Uint16(value[24:]) return &ActivationValue{ Height: binary.BigEndian.Uint32(value), ClaimHash: value[4 : 20+4], NormalizedName: string(value[26 : 26+nameLen]), } } /* class ActiveAmountKey(typing.NamedTuple): claim_hash: bytes txo_type: int activation_height: int tx_num: int position: int def __str__(self): return f"{self.__class__.__name__}(claim_hash={self.claim_hash.hex()}, txo_type={self.txo_type}, " \ f"activation_height={self.activation_height}, tx_num={self.tx_num}, position={self.position})" class ActiveAmountValue(typing.NamedTuple): amount: int */ type ActiveAmountKey struct { Prefix []byte `json:"prefix"` ClaimHash []byte `json:"claim_hash"` TxoType uint8 `json:"txo_type"` ActivationHeight uint32 `json:"activation_height"` TxNum uint32 `json:"tx_num"` Position uint16 `json:"position"` } type ActiveAmountValue struct { Amount uint64 `json:"amount"` } func (k *ActiveAmountKey) PackKey() []byte { prefixLen := 1 // b'>20sBLLH' n := prefixLen + 20 + 1 + 4 + 4 + 2 key := make([]byte, n) copy(key, k.Prefix) copy(key[prefixLen:], k.ClaimHash[:20]) copy(key[prefixLen+20:], []byte{k.TxoType}) binary.BigEndian.PutUint32(key[prefixLen+20+1:], k.ActivationHeight) binary.BigEndian.PutUint32(key[prefixLen+20+1+4:], k.TxNum) binary.BigEndian.PutUint16(key[prefixLen+20+1+4+4:], k.Position) return key } func (v *ActiveAmountValue) PackValue() []byte { // b'>Q' value := make([]byte, 8) binary.BigEndian.PutUint64(value, v.Amount) return value } func ActiveAmountKeyPackPartialNFields(nFields int) func(*ActiveAmountKey) []byte { return func(u *ActiveAmountKey) []byte { return ActiveAmountKeyPackPartial(u, nFields) } } func ActiveAmountKeyPackPartial(k *ActiveAmountKey, nFields int) []byte { // Limit nFields between 0 and number of fields, we always at least need // the prefix, and we never need to iterate past the number of fields. if nFields > 5 { nFields = 5 } if nFields < 0 { nFields = 0 } prefixLen := 1 var n = prefixLen for i := 0; i <= nFields; i++ { switch i { case 1: n += 20 case 2: n += 1 case 3: n += 4 case 4: n += 4 case 5: n += 2 } } key := make([]byte, n) for i := 0; i <= nFields; i++ { switch i { case 0: copy(key, k.Prefix) case 1: copy(key[prefixLen:], k.ClaimHash) case 2: copy(key[prefixLen+20:], []byte{k.TxoType}) case 3: binary.BigEndian.PutUint32(key[prefixLen+20+1:], k.ActivationHeight) case 4: binary.BigEndian.PutUint32(key[prefixLen+20+1+4:], k.TxNum) case 5: binary.BigEndian.PutUint16(key[prefixLen+20+1+4+4:], k.Position) } } return key } func ActiveAmountKeyUnpack(key []byte) *ActiveAmountKey { prefixLen := 1 return &ActiveAmountKey{ Prefix: key[:prefixLen], ClaimHash: key[prefixLen : prefixLen+20], TxoType: uint8(key[prefixLen+20 : prefixLen+20+1][0]), ActivationHeight: binary.BigEndian.Uint32(key[prefixLen+20+1:]), TxNum: binary.BigEndian.Uint32(key[prefixLen+20+1+4:]), Position: binary.BigEndian.Uint16(key[prefixLen+20+1+4+4:]), } } func ActiveAmountValueUnpack(value []byte) *ActiveAmountValue { return &ActiveAmountValue{ Amount: binary.BigEndian.Uint64(value), } } // // EffectiveAmountKey / EffectiveAmountValue // /* class EffectiveAmountKey(typing.NamedTuple): normalized_name: str effective_amount: int tx_num: int position: int class EffectiveAmountValue(typing.NamedTuple): claim_hash: bytes def __str__(self): return f"{self.__class__.__name__}(claim_hash={self.claim_hash.hex()})" */ type EffectiveAmountKey struct { Prefix []byte `json:"prefix"` NormalizedName string `json:"normalized_name"` EffectiveAmount uint64 `json:"effective_amount"` TxNum uint32 `json:"tx_num"` Position uint16 `json:"position"` } type EffectiveAmountValue struct { ClaimHash []byte `json:"claim_hash"` } func (k *EffectiveAmountKey) PackKey() []byte { prefixLen := 1 // 2 byte length field, plus number of bytes in name nameLen := len(k.NormalizedName) nameLenLen := 2 + nameLen // b'>QLH' n := prefixLen + nameLenLen + 8 + 4 + 2 key := make([]byte, n) copy(key, k.Prefix) binary.BigEndian.PutUint16(key[prefixLen:], uint16(nameLen)) copy(key[prefixLen+2:], []byte(k.NormalizedName)) binary.BigEndian.PutUint64(key[prefixLen+nameLenLen:], OnesCompTwiddle-k.EffectiveAmount) binary.BigEndian.PutUint32(key[prefixLen+nameLenLen+8:], k.TxNum) binary.BigEndian.PutUint16(key[prefixLen+nameLenLen+8+4:], k.Position) return key } func (v *EffectiveAmountValue) PackValue() []byte { // b'>20s' value := make([]byte, 20) copy(value, v.ClaimHash[:20]) return value } func EffectiveAmountKeyPackPartialNFields(nFields int) func(*EffectiveAmountKey) []byte { return func(u *EffectiveAmountKey) []byte { return EffectiveAmountKeyPackPartial(u, nFields) } } func EffectiveAmountKeyPackPartial(k *EffectiveAmountKey, nFields int) []byte { // Limit nFields between 0 and number of fields, we always at least need // the prefix, and we never need to iterate past the number of fields. nameLen := len(k.NormalizedName) nameLenLen := 2 + nameLen if nFields > 4 { nFields = 4 } if nFields < 0 { nFields = 0 } prefixLen := 1 var n = prefixLen for i := 0; i <= nFields; i++ { switch i { case 1: n += 2 + nameLen case 2: n += 8 case 3: n += 4 case 4: n += 2 } } key := make([]byte, n) for i := 0; i <= nFields; i++ { switch i { case 0: copy(key, k.Prefix) case 1: binary.BigEndian.PutUint16(key[prefixLen:], uint16(nameLen)) copy(key[prefixLen+2:], []byte(k.NormalizedName)) case 2: binary.BigEndian.PutUint64(key[prefixLen+nameLenLen:], OnesCompTwiddle-k.EffectiveAmount) case 3: binary.BigEndian.PutUint32(key[prefixLen+nameLenLen+8:], k.TxNum) case 4: binary.BigEndian.PutUint16(key[prefixLen+nameLenLen+8+4:], k.Position) } } return key } func EffectiveAmountKeyUnpack(key []byte) *EffectiveAmountKey { prefixLen := 1 nameLen := binary.BigEndian.Uint16(key[prefixLen:]) return &EffectiveAmountKey{ Prefix: key[:prefixLen], NormalizedName: string(key[prefixLen+2 : prefixLen+2+int(nameLen)]), EffectiveAmount: OnesCompTwiddle - binary.BigEndian.Uint64(key[prefixLen+2+int(nameLen):]), TxNum: binary.BigEndian.Uint32(key[prefixLen+2+int(nameLen)+8:]), Position: binary.BigEndian.Uint16(key[prefixLen+2+int(nameLen)+8+4:]), } } func EffectiveAmountValueUnpack(value []byte) *EffectiveAmountValue { return &EffectiveAmountValue{ ClaimHash: value[:20], } } /* class RepostKey(typing.NamedTuple): claim_hash: bytes def __str__(self): return f"{self.__class__.__name__}(claim_hash={self.claim_hash.hex()})" class RepostValue(typing.NamedTuple): reposted_claim_hash: bytes def __str__(self): return f"{self.__class__.__name__}(reposted_claim_hash={self.reposted_claim_hash.hex()})" */ type RepostKey struct { Prefix []byte `json:"prefix"` ClaimHash []byte `json:"claim_hash"` } type RepostValue struct { RepostedClaimHash []byte `json:"reposted_claim_hash"` } func (k *RepostKey) PackKey() []byte { prefixLen := 1 // b'>20s' n := prefixLen + 20 key := make([]byte, n) copy(key, k.Prefix) copy(key[prefixLen:], k.ClaimHash) return key } func (v *RepostValue) PackValue() []byte { // FIXME: Is there a limit to this length? n := len(v.RepostedClaimHash) value := make([]byte, n) copy(value, v.RepostedClaimHash) return value } func RepostKeyPackPartialNFields(nFields int) func(*RepostKey) []byte { return func(u *RepostKey) []byte { return RepostKeyPackPartial(u, nFields) } } func RepostKeyPackPartial(k *RepostKey, nFields int) []byte { // Limit nFields between 0 and number of fields, we always at least need // the prefix, and we never need to iterate past the number of fields. if nFields > 1 { nFields = 1 } if nFields < 0 { nFields = 0 } prefixLen := 1 var n = prefixLen for i := 0; i <= nFields; i++ { switch i { case 1: n += 20 } } key := make([]byte, n) for i := 0; i <= nFields; i++ { switch i { case 0: copy(key, k.Prefix) case 1: copy(key[prefixLen:], k.ClaimHash) } } return key } func RepostKeyUnpack(key []byte) *RepostKey { prefixLen := 1 return &RepostKey{ Prefix: key[:prefixLen], ClaimHash: key[prefixLen : prefixLen+20], } } func RepostValueUnpack(value []byte) *RepostValue { return &RepostValue{ RepostedClaimHash: value[:], } } /* class RepostedKey(typing.NamedTuple): reposted_claim_hash: bytes tx_num: int position: int def __str__(self): return f"{self.__class__.__name__}(reposted_claim_hash={self.reposted_claim_hash.hex()}, " \ f"tx_num={self.tx_num}, position={self.position})" class RepostedValue(typing.NamedTuple): claim_hash: bytes def __str__(self): return f"{self.__class__.__name__}(claim_hash={self.claim_hash.hex()})" */ type RepostedKey struct { Prefix []byte `json:"prefix"` RepostedClaimHash []byte `json:"reposted_claim_hash"` TxNum uint32 `json:"tx_num"` Position uint16 `json:"position"` } type RepostedValue struct { ClaimHash []byte `json:"claim_hash"` } func (k *RepostedKey) PackKey() []byte { prefixLen := 1 // b'>20sLH' n := prefixLen + 20 + 4 + 2 key := make([]byte, n) copy(key, k.Prefix) copy(key[prefixLen:], k.RepostedClaimHash) binary.BigEndian.PutUint32(key[prefixLen+20:], k.TxNum) binary.BigEndian.PutUint16(key[prefixLen+24:], k.Position) return key } func (v *RepostedValue) PackValue() []byte { // b'>20s' value := make([]byte, 20) copy(value, v.ClaimHash) return value } func RepostedKeyPackPartialNFields(nFields int) func(*RepostedKey) []byte { return func(u *RepostedKey) []byte { return RepostedKeyPackPartial(u, nFields) } } func RepostedKeyPackPartial(k *RepostedKey, nFields int) []byte { // Limit nFields between 0 and number of fields, we always at least need // the prefix, and we never need to iterate past the number of fields. if nFields > 3 { nFields = 3 } if nFields < 0 { nFields = 0 } prefixLen := 1 var n = prefixLen for i := 0; i <= nFields; i++ { switch i { case 1: n += 20 case 2: n += 4 case 3: n += 2 } } key := make([]byte, n) for i := 0; i <= nFields; i++ { switch i { case 0: copy(key, k.Prefix) case 1: copy(key[prefixLen:], k.RepostedClaimHash) case 2: binary.BigEndian.PutUint32(key[prefixLen+20:], k.TxNum) case 3: binary.BigEndian.PutUint16(key[prefixLen+24:], k.Position) } } return key } func RepostedKeyUnpack(key []byte) *RepostedKey { prefixLen := 1 return &RepostedKey{ Prefix: key[:prefixLen], RepostedClaimHash: key[prefixLen : prefixLen+20], TxNum: binary.BigEndian.Uint32(key[prefixLen+20:]), Position: binary.BigEndian.Uint16(key[prefixLen+24:]), } } func RepostedValueUnpack(value []byte) *RepostedValue { return &RepostedValue{ ClaimHash: value[:20], } } // // TouchedOrDeletedClaimKey / TouchedOrDeletedClaimValue // /* class TouchedOrDeletedClaimKey(typing.NamedTuple): height: int class TouchedOrDeletedClaimValue(typing.NamedTuple): touched_claims: typing.Set[bytes] deleted_claims: typing.Set[bytes] def __str__(self): return f"{self.__class__.__name__}(" \ f"touched_claims={','.join(map(lambda x: x.hex(), self.touched_claims))}," \ f"deleted_claims={','.join(map(lambda x: x.hex(), self.deleted_claims))})" */ type TouchedOrDeletedClaimKey struct { Prefix []byte `json:"prefix"` Height int32 `json:"height"` } type TouchedOrDeletedClaimValue struct { TouchedClaims [][]byte `json:"touched_claims"` DeletedClaims [][]byte `json:"deleted_claims"` } func (v *TouchedOrDeletedClaimValue) String() string { touchedSB := strings.Builder{} touchedLen := len(v.TouchedClaims) for i, claim := range v.TouchedClaims { touchedSB.WriteString(hex.EncodeToString(claim)) if i < touchedLen-1 { touchedSB.WriteString(",") } } deletedSB := strings.Builder{} deletedLen := len(v.DeletedClaims) for i, claim := range v.DeletedClaims { deletedSB.WriteString(hex.EncodeToString(claim)) if i < deletedLen-1 { deletedSB.WriteString(",") } } return fmt.Sprintf( "%s(touched_claims=%s, deleted_claims=%s)", reflect.TypeOf(v), touchedSB.String(), deletedSB.String(), ) } func (k *TouchedOrDeletedClaimKey) PackKey() []byte { prefixLen := 1 // b'>L' n := prefixLen + 4 key := make([]byte, n) copy(key, k.Prefix) binary.BigEndian.PutUint32(key[prefixLen:], uint32(k.Height)) return key } func (v *TouchedOrDeletedClaimValue) PackValue() []byte { var touchedLen, deletedLen uint32 = 0, 0 if v.TouchedClaims != nil { for _, claim := range v.TouchedClaims { if len(claim) != 20 { log.Println("TouchedOrDeletedClaimValue: claim not length 20?!?") return nil } } touchedLen = uint32(len(v.TouchedClaims)) } if v.DeletedClaims != nil { for _, claim := range v.DeletedClaims { if len(claim) != 20 { log.Println("TouchedOrDeletedClaimValue: claim not length 20?!?") return nil } } deletedLen = uint32(len(v.DeletedClaims)) } n := 4 + 4 + 20*touchedLen + 20*deletedLen value := make([]byte, n) binary.BigEndian.PutUint32(value, touchedLen) binary.BigEndian.PutUint32(value[4:], deletedLen) // These are sorted for consistency with the Python implementation sort.Slice(v.TouchedClaims, func(i, j int) bool { return bytes.Compare(v.TouchedClaims[i], v.TouchedClaims[j]) < 0 }) sort.Slice(v.DeletedClaims, func(i, j int) bool { return bytes.Compare(v.DeletedClaims[i], v.DeletedClaims[j]) < 0 }) var i = 8 for j := 0; j < int(touchedLen); j++ { copy(value[i:], v.TouchedClaims[j]) i += 20 } for j := 0; j < int(deletedLen); j++ { copy(value[i:], v.DeletedClaims[j]) i += 20 } return value } func TouchedOrDeletedClaimPackPartialNFields(nFields int) func(*TouchedOrDeletedClaimKey) []byte { return func(u *TouchedOrDeletedClaimKey) []byte { return TouchedOrDeletedClaimKeyPackPartial(u, nFields) } } func TouchedOrDeletedClaimKeyPackPartial(k *TouchedOrDeletedClaimKey, nFields int) []byte { // Limit nFields between 0 and number of fields, we always at least need // the prefix, and we never need to iterate past the number of fields. if nFields > 1 { nFields = 1 } if nFields < 0 { nFields = 0 } prefixLen := 1 var n = prefixLen for i := 0; i <= nFields; i++ { switch i { case 1: n += 4 } } key := make([]byte, n) for i := 0; i <= nFields; i++ { switch i { case 0: copy(key, k.Prefix) case 1: binary.BigEndian.PutUint32(key[prefixLen:], uint32(k.Height)) } } return key } func TouchedOrDeletedClaimKeyUnpack(key []byte) *TouchedOrDeletedClaimKey { prefixLen := 1 return &TouchedOrDeletedClaimKey{ Prefix: key[:prefixLen], Height: int32(binary.BigEndian.Uint32(key[prefixLen:])), } } func TouchedOrDeletedClaimValueUnpack(value []byte) *TouchedOrDeletedClaimValue { touchedLen := binary.BigEndian.Uint32(value) deletedLen := binary.BigEndian.Uint32(value[4:]) touchedClaims := make([][]byte, touchedLen) deletedClaims := make([][]byte, deletedLen) var j = 8 for i := 0; i < int(touchedLen); i++ { touchedClaims[i] = value[j : j+20] j += 20 } for i := 0; i < int(deletedLen); i++ { deletedClaims[i] = value[j : j+20] j += 20 } return &TouchedOrDeletedClaimValue{ TouchedClaims: touchedClaims, DeletedClaims: deletedClaims, } } // // HashXUTXOKey / HashXUTXOValue // func (k *HashXUTXOKey) String() string { return fmt.Sprintf( "%s(short_tx_hash=%s, tx_num=%d, nout=%d)", reflect.TypeOf(k), hex.EncodeToString(k.ShortTXHash), k.TxNum, k.Nout, ) } func (v *HashXUTXOValue) String() string { return fmt.Sprintf( "%s(hashX=%s)", reflect.TypeOf(v), hex.EncodeToString(v.HashX), ) } func (k *HashXUTXOKey) PackKey() []byte { prefixLen := 1 // b'>4sLH' n := prefixLen + 4 + 4 + 2 key := make([]byte, n) copy(key, k.Prefix) copy(key[prefixLen:], k.ShortTXHash) binary.BigEndian.PutUint32(key[prefixLen+4:], k.TxNum) binary.BigEndian.PutUint16(key[prefixLen+8:], k.Nout) return key } func (v *HashXUTXOValue) PackValue() []byte { value := make([]byte, 11) copy(value, v.HashX) return value } // HashXUTXOKeyPackPartialNFields creates a pack partial key function for n fields. func HashXUTXOKeyPackPartialNFields(nFields int) func(*HashXUTXOKey) []byte { return func(u *HashXUTXOKey) []byte { return HashXUTXOKeyPackPartial(u, nFields) } } // HashXUTXOKeyPackPartial packs a variable number of fields into a byte // array func HashXUTXOKeyPackPartial(k *HashXUTXOKey, nFields int) []byte { // Limit nFields between 0 and number of fields, we always at least need // the prefix, and we never need to iterate past the number of fields. if nFields > 3 { nFields = 3 } if nFields < 0 { nFields = 0 } // b'>4sLH' prefixLen := 1 var n = prefixLen for i := 0; i <= nFields; i++ { switch i { case 1: n += 4 case 2: n += 4 case 3: n += 2 } } key := make([]byte, n) for i := 0; i <= nFields; i++ { switch i { case 0: copy(key, k.Prefix) case 1: copy(key[prefixLen:], k.ShortTXHash) case 2: binary.BigEndian.PutUint32(key[prefixLen+4:], k.TxNum) case 3: binary.BigEndian.PutUint16(key[prefixLen+8:], k.Nout) } } return key } func HashXUTXOKeyUnpack(key []byte) *HashXUTXOKey { prefixLen := 1 return &HashXUTXOKey{ Prefix: key[:prefixLen], ShortTXHash: key[prefixLen : prefixLen+4], TxNum: binary.BigEndian.Uint32(key[prefixLen+4:]), Nout: binary.BigEndian.Uint16(key[prefixLen+8:]), } } func HashXUTXOValueUnpack(value []byte) *HashXUTXOValue { return &HashXUTXOValue{ HashX: value[:11], } } // // UTXOKey / UTXOValue // func (k *UTXOKey) String() string { return fmt.Sprintf( "%s(hashX=%s, tx_num=%d, nout=%d)", reflect.TypeOf(k), hex.EncodeToString(k.HashX), k.TxNum, k.Nout, ) } func (k *UTXOKey) PackKey() []byte { prefixLen := 1 // b'>11sLH' n := prefixLen + 11 + 4 + 2 key := make([]byte, n) copy(key, k.Prefix) copy(key[prefixLen:], k.HashX) binary.BigEndian.PutUint32(key[prefixLen+11:], k.TxNum) binary.BigEndian.PutUint16(key[prefixLen+15:], k.Nout) return key } func (k *UTXOValue) PackValue() []byte { value := make([]byte, 8) binary.BigEndian.PutUint64(value, k.Amount) return value } // UTXOKeyPackPartialNFields creates a pack partial key function for n fields. func UTXOKeyPackPartialNFields(nFields int) func(*UTXOKey) []byte { return func(u *UTXOKey) []byte { return UTXOKeyPackPartial(u, nFields) } } // UTXOKeyPackPartial packs a variable number of fields for a UTXOKey into // a byte array. func UTXOKeyPackPartial(k *UTXOKey, nFields int) []byte { // Limit nFields between 0 and number of fields, we always at least need // the prefix, and we never need to iterate past the number of fields. if nFields > 3 { nFields = 3 } if nFields < 0 { nFields = 0 } // b'>11sLH' prefixLen := 1 var n = prefixLen for i := 0; i <= nFields; i++ { switch i { case 1: n += 11 case 2: n += 4 case 3: n += 2 } } key := make([]byte, n) for i := 0; i <= nFields; i++ { switch i { case 0: copy(key, k.Prefix) case 1: copy(key[prefixLen:], k.HashX) case 2: binary.BigEndian.PutUint32(key[prefixLen+11:], k.TxNum) case 3: binary.BigEndian.PutUint16(key[prefixLen+15:], k.Nout) } } return key } func UTXOKeyUnpack(key []byte) *UTXOKey { prefixLen := 1 return &UTXOKey{ Prefix: key[:prefixLen], HashX: key[prefixLen : prefixLen+11], TxNum: binary.BigEndian.Uint32(key[prefixLen+11:]), Nout: binary.BigEndian.Uint16(key[prefixLen+15:]), } } func UTXOValueUnpack(value []byte) *UTXOValue { return &UTXOValue{ Amount: binary.BigEndian.Uint64(value), } } func UnpackGenericKey(key []byte) (byte, interface{}, error) { if len(key) == 0 { return 0x0, nil, errors.Base("key length zero") } firstByte := key[0] switch firstByte { case ClaimToSupport: return ClaimToSupport, ClaimToSupportKeyUnpack(key), nil case SupportToClaim: return SupportToClaim, SupportToClaimKeyUnpack(key), nil case ClaimToTXO: return 0x0, nil, errors.Base("key unpack function for %v not implemented", firstByte) case TXOToClaim: return TXOToClaim, TXOToClaimKeyUnpack(key), nil case ClaimToChannel: return ClaimToChannel, ClaimToChannelKeyUnpack(key), nil case ChannelToClaim: return ChannelToClaim, ChannelToClaimKeyUnpack(key), nil case ClaimShortIdPrefix: return ClaimShortIdPrefix, ClaimShortIDKeyUnpack(key), nil case EffectiveAmount: return EffectiveAmount, EffectiveAmountKeyUnpack(key), nil case ClaimExpiration: return ClaimExpiration, ClaimExpirationKeyUnpack(key), nil case ClaimTakeover: return ClaimTakeover, ClaimTakeoverKeyUnpack(key), nil case PendingActivation: return PendingActivation, PendingActivationKeyUnpack(key), nil case ActivatedClaimAndSupport: return ActivatedClaimAndSupport, ActivationKeyUnpack(key), nil case ActiveAmount: return ActiveAmount, ActiveAmountKeyUnpack(key), nil case Repost: return Repost, RepostKeyUnpack(key), nil case RepostedClaim: return RepostedClaim, RepostedKeyUnpack(key), nil case Undo: return 0x0, nil, errors.Base("key unpack function for %v not implemented", firstByte) case ClaimDiff: return ClaimDiff, TouchedOrDeletedClaimKeyUnpack(key), nil case Tx: case BlockHash: case Header: case TxNum: case TxCount: case TxHash: return 0x0, nil, errors.Base("key unpack function for %v not implemented", firstByte) case UTXO: return UTXO, UTXOKeyUnpack(key), nil case HashXUTXO: return UTXO, HashXUTXOKeyUnpack(key), nil case HashXHistory: case DBState: case ChannelCount: case SupportAmount: case BlockTXs: } return 0x0, nil, errors.Base("key unpack function for %v not implemented", firstByte) } func UnpackGenericValue(key, value []byte) (byte, interface{}, error) { if len(key) == 0 { return 0x0, nil, errors.Base("key length zero") } if len(value) == 0 { return 0x0, nil, errors.Base("value length zero") } firstByte := key[0] switch firstByte { case ClaimToSupport: return ClaimToSupport, ClaimToSupportValueUnpack(value), nil case SupportToClaim: return SupportToClaim, SupportToClaimValueUnpack(value), nil case ClaimToTXO: return 0x0, nil, errors.Base("value unpack not implemented for key %v", key) case TXOToClaim: return TXOToClaim, TXOToClaimValueUnpack(value), nil case ClaimToChannel: return ClaimToChannel, ClaimToChannelValueUnpack(value), nil case ChannelToClaim: return ChannelToClaim, ChannelToClaimValueUnpack(value), nil case ClaimShortIdPrefix: return ClaimShortIdPrefix, ClaimShortIDValueUnpack(value), nil case EffectiveAmount: return EffectiveAmount, EffectiveAmountValueUnpack(value), nil case ClaimExpiration: return ClaimExpiration, ClaimExpirationValueUnpack(value), nil case ClaimTakeover: return ClaimTakeover, ClaimTakeoverValueUnpack(value), nil case PendingActivation: return PendingActivation, PendingActivationValueUnpack(value), nil case ActivatedClaimAndSupport: return ActivatedClaimAndSupport, ActivationValueUnpack(value), nil case ActiveAmount: return ActiveAmount, ActiveAmountValueUnpack(value), nil case Repost: return Repost, RepostValueUnpack(value), nil case RepostedClaim: return RepostedClaim, RepostedValueUnpack(value), nil case Undo: return 0x0, nil, errors.Base("value unpack not implemented for key %v", key) case ClaimDiff: return ClaimDiff, TouchedOrDeletedClaimValueUnpack(value), nil case Tx: case BlockHash: case Header: case TxNum: case TxCount: case TxHash: return 0x0, nil, errors.Base("value unpack not implemented for key %v", key) case UTXO: return UTXO, UTXOValueUnpack(value), nil case HashXUTXO: return HashXUTXO, HashXUTXOValueUnpack(value), nil case HashXHistory: case DBState: case ChannelCount: case SupportAmount: case BlockTXs: } return 0x0, nil, errors.Base("value unpack not implemented for key %v", key) }