282 lines
5.7 KiB
Go
282 lines
5.7 KiB
Go
// SPDX-License-Identifier: EUPL-1.2
|
|
|
|
package primitives
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"fmt"
|
|
)
|
|
|
|
const (
|
|
// MaxNameStateSize is the maximum serialized size of a name state,
|
|
// mirroring the JS reference's `NameState.MAX_SIZE` constant.
|
|
MaxNameStateSize = 668
|
|
|
|
// NameStateMaxSize is an alias for MaxNameStateSize.
|
|
NameStateMaxSize = MaxNameStateSize
|
|
)
|
|
|
|
// GetSize returns the serialized size of the name state.
|
|
func (ns NameState) GetSize() int {
|
|
size := 1 + len(ns.Name) + 2 + len(ns.Data) + 4 + 4 + 2
|
|
|
|
if !outpointIsNull(ns.Owner) {
|
|
size += len(ns.Owner.TxHash)
|
|
size += sizeVarint64(uint64(ns.Owner.Index))
|
|
}
|
|
|
|
if ns.Value != 0 {
|
|
size += sizeVarint64(ns.Value)
|
|
}
|
|
|
|
if ns.Highest != 0 {
|
|
size += sizeVarint64(ns.Highest)
|
|
}
|
|
|
|
if ns.Transfer != 0 {
|
|
size += 4
|
|
}
|
|
|
|
if ns.Revoked != 0 {
|
|
size += 4
|
|
}
|
|
|
|
if ns.Claimed != 0 {
|
|
size += 4
|
|
}
|
|
|
|
if ns.Renewals != 0 {
|
|
size += sizeVarint64(uint64(ns.Renewals))
|
|
}
|
|
|
|
return size
|
|
}
|
|
|
|
// MarshalBinary serializes the name state using the compact JS reference layout.
|
|
//
|
|
// The encoding does not include NameHash, which is derived from Name by the
|
|
// caller and is not part of the on-wire payload.
|
|
func (ns NameState) MarshalBinary() ([]byte, error) {
|
|
if len(ns.Name) > 0xff {
|
|
return nil, fmt.Errorf("primitives.NameState.MarshalBinary: name too long")
|
|
}
|
|
|
|
if len(ns.Data) > 0xffff {
|
|
return nil, fmt.Errorf("primitives.NameState.MarshalBinary: data too long")
|
|
}
|
|
|
|
buf := make([]byte, 0, ns.GetSize())
|
|
|
|
buf = append(buf, byte(len(ns.Name)))
|
|
buf = append(buf, ns.Name...)
|
|
|
|
var tmp [10]byte
|
|
binary.LittleEndian.PutUint16(tmp[:2], uint16(len(ns.Data)))
|
|
buf = append(buf, tmp[:2]...)
|
|
buf = append(buf, ns.Data...)
|
|
|
|
binary.LittleEndian.PutUint32(tmp[:4], ns.Height)
|
|
buf = append(buf, tmp[:4]...)
|
|
|
|
binary.LittleEndian.PutUint32(tmp[:4], ns.Renewal)
|
|
buf = append(buf, tmp[:4]...)
|
|
|
|
var field uint16
|
|
if !outpointIsNull(ns.Owner) {
|
|
field |= 1 << 0
|
|
}
|
|
if ns.Value != 0 {
|
|
field |= 1 << 1
|
|
}
|
|
if ns.Highest != 0 {
|
|
field |= 1 << 2
|
|
}
|
|
if ns.Transfer != 0 {
|
|
field |= 1 << 3
|
|
}
|
|
if ns.Revoked != 0 {
|
|
field |= 1 << 4
|
|
}
|
|
if ns.Claimed != 0 {
|
|
field |= 1 << 5
|
|
}
|
|
if ns.Renewals != 0 {
|
|
field |= 1 << 6
|
|
}
|
|
if ns.Registered {
|
|
field |= 1 << 7
|
|
}
|
|
if ns.Expired {
|
|
field |= 1 << 8
|
|
}
|
|
if ns.Weak {
|
|
field |= 1 << 9
|
|
}
|
|
|
|
binary.LittleEndian.PutUint16(tmp[:2], field)
|
|
buf = append(buf, tmp[:2]...)
|
|
|
|
if !outpointIsNull(ns.Owner) {
|
|
buf = append(buf, ns.Owner.TxHash[:]...)
|
|
buf = appendVarint(buf, uint64(ns.Owner.Index))
|
|
}
|
|
|
|
if ns.Value != 0 {
|
|
buf = appendVarint(buf, ns.Value)
|
|
}
|
|
|
|
if ns.Highest != 0 {
|
|
buf = appendVarint(buf, ns.Highest)
|
|
}
|
|
|
|
if ns.Transfer != 0 {
|
|
binary.LittleEndian.PutUint32(tmp[:4], ns.Transfer)
|
|
buf = append(buf, tmp[:4]...)
|
|
}
|
|
|
|
if ns.Revoked != 0 {
|
|
binary.LittleEndian.PutUint32(tmp[:4], ns.Revoked)
|
|
buf = append(buf, tmp[:4]...)
|
|
}
|
|
|
|
if ns.Claimed != 0 {
|
|
binary.LittleEndian.PutUint32(tmp[:4], ns.Claimed)
|
|
buf = append(buf, tmp[:4]...)
|
|
}
|
|
|
|
if ns.Renewals != 0 {
|
|
buf = appendVarint(buf, uint64(ns.Renewals))
|
|
}
|
|
|
|
return buf, nil
|
|
}
|
|
|
|
// UnmarshalBinary decodes the compact name-state layout used by the JS reference.
|
|
func (ns *NameState) UnmarshalBinary(data []byte) error {
|
|
*ns = NameState{}
|
|
|
|
if len(data) < 1 {
|
|
return fmt.Errorf("primitives.NameState.UnmarshalBinary: short buffer")
|
|
}
|
|
|
|
nameLen := int(data[0])
|
|
data = data[1:]
|
|
|
|
if len(data) < nameLen+2+4+4+2 {
|
|
return fmt.Errorf("primitives.NameState.UnmarshalBinary: short buffer")
|
|
}
|
|
|
|
ns.Name = append([]byte(nil), data[:nameLen]...)
|
|
data = data[nameLen:]
|
|
|
|
dataLen := int(binary.LittleEndian.Uint16(data[:2]))
|
|
data = data[2:]
|
|
|
|
if len(data) < dataLen+4+4+2 {
|
|
return fmt.Errorf("primitives.NameState.UnmarshalBinary: short buffer")
|
|
}
|
|
|
|
ns.Data = append([]byte(nil), data[:dataLen]...)
|
|
data = data[dataLen:]
|
|
|
|
ns.Height = binary.LittleEndian.Uint32(data[:4])
|
|
data = data[4:]
|
|
|
|
ns.Renewal = binary.LittleEndian.Uint32(data[:4])
|
|
data = data[4:]
|
|
|
|
field := binary.LittleEndian.Uint16(data[:2])
|
|
data = data[2:]
|
|
|
|
if field&(1<<0) != 0 {
|
|
if len(data) < len(ns.Owner.TxHash) {
|
|
return fmt.Errorf("primitives.NameState.UnmarshalBinary: short buffer")
|
|
}
|
|
|
|
copy(ns.Owner.TxHash[:], data[:len(ns.Owner.TxHash)])
|
|
data = data[len(ns.Owner.TxHash):]
|
|
|
|
index, n, err := readVarint(data)
|
|
if err != nil {
|
|
return fmt.Errorf("primitives.NameState.UnmarshalBinary: %w", err)
|
|
}
|
|
|
|
ns.Owner.Index = uint32(index)
|
|
data = data[n:]
|
|
}
|
|
|
|
if field&(1<<1) != 0 {
|
|
value, n, err := readVarint(data)
|
|
if err != nil {
|
|
return fmt.Errorf("primitives.NameState.UnmarshalBinary: %w", err)
|
|
}
|
|
|
|
ns.Value = value
|
|
data = data[n:]
|
|
}
|
|
|
|
if field&(1<<2) != 0 {
|
|
highest, n, err := readVarint(data)
|
|
if err != nil {
|
|
return fmt.Errorf("primitives.NameState.UnmarshalBinary: %w", err)
|
|
}
|
|
|
|
ns.Highest = highest
|
|
data = data[n:]
|
|
}
|
|
|
|
if field&(1<<3) != 0 {
|
|
if len(data) < 4 {
|
|
return fmt.Errorf("primitives.NameState.UnmarshalBinary: short buffer")
|
|
}
|
|
|
|
ns.Transfer = binary.LittleEndian.Uint32(data[:4])
|
|
data = data[4:]
|
|
}
|
|
|
|
if field&(1<<4) != 0 {
|
|
if len(data) < 4 {
|
|
return fmt.Errorf("primitives.NameState.UnmarshalBinary: short buffer")
|
|
}
|
|
|
|
ns.Revoked = binary.LittleEndian.Uint32(data[:4])
|
|
data = data[4:]
|
|
}
|
|
|
|
if field&(1<<5) != 0 {
|
|
if len(data) < 4 {
|
|
return fmt.Errorf("primitives.NameState.UnmarshalBinary: short buffer")
|
|
}
|
|
|
|
ns.Claimed = binary.LittleEndian.Uint32(data[:4])
|
|
data = data[4:]
|
|
}
|
|
|
|
if field&(1<<6) != 0 {
|
|
renewals, n, err := readVarint(data)
|
|
if err != nil {
|
|
return fmt.Errorf("primitives.NameState.UnmarshalBinary: %w", err)
|
|
}
|
|
|
|
ns.Renewals = uint32(renewals)
|
|
data = data[n:]
|
|
}
|
|
|
|
if field&(1<<7) != 0 {
|
|
ns.Registered = true
|
|
}
|
|
|
|
if field&(1<<8) != 0 {
|
|
ns.Expired = true
|
|
}
|
|
|
|
if field&(1<<9) != 0 {
|
|
ns.Weak = true
|
|
}
|
|
|
|
if len(data) != 0 {
|
|
return fmt.Errorf("primitives.NameState.UnmarshalBinary: trailing data")
|
|
}
|
|
|
|
return nil
|
|
}
|