StringUtils

Git Source

Title: String Utilities Library

Provides string manipulation utilities for DotNS contracts.

Extends OpenZeppelin's Strings library with additional UTF-8 and conversion helpers.

Note: security-contact: admin@parity.io

Constants

LITE_SUFFIX_DIGITS

Number of digits in a lite-person PoP label's suffix.

The count the gateway emits, and an exact requirement here: the separator sits at a fixed offset from the end, so a one or three digit suffix is rejected. The gateway reads its own minimum, so widening it there does not widen this.

uint256 internal constant LITE_SUFFIX_DIGITS = 2

MAX_DNS_LABEL_OCTETS

Maximum number of octets in a single DNS label.

RFC 1035 caps each label at 63 octets. Enforced inside @custom:function _isDnsLabel so every public validator (@custom:function isSingleLabel, @custom:function isNamePath,

Note: function: isLitePersonLabel) inherits the bound and oversized labels never reach the registrar. A lite label bounds its stem rather than the whole string, so it reaches MAX_DNS_LABEL_OCTETS + LITE_SUFFIX_DIGITS + 1 octets. Its stem is bounded here but checked in @custom:function _isLitePersonLabel, which is stricter on charset than a DNS label: letters only. This is the per-segment bound only; @custom:function isNamePath additionally bounds the whole path with @custom:constant MAX_NAME_PATH_OCTETS.

uint256 internal constant MAX_DNS_LABEL_OCTETS = 63

MAX_NAME_PATH_OCTETS

Cap on the dotted parent path a caller submits, in octets.

Not an RFC 1035 figure, despite the value. That ceiling is 255 octets of wire name, where each label carries a length prefix and the name ends in a zero byte, and it covers the fully qualified name. This bounds the dotted presentation string the caller passes in, which also carries no TLD, so the two are not the same quantity and this one must not be retuned to "match RFC 1035". What reaches a LabelStore row is longer again, and depends on the network's TLD: subLabel + "." + path + the TLD, so about 323 octets at the maximum where the TLD is four octets.

@custom:constant MAX_DNS_LABEL_OCTETS bounds one segment; this bounds the path. Without it a caller composes an arbitrarily long parentLabel out of legal 63-octet segments, and DotnsRegistry.setSubnodeOwner stores the full name built from it verbatim in a LabelStore row that has no delete path, so the text is a permanent multiplier on every enumeration that reads the row back.

uint256 internal constant MAX_NAME_PATH_OCTETS = 255

LABEL_SEPARATOR

ASCII full stop separating a lite label's stem from its digit suffix.

A lite label is the only label shape in DotNS that carries a separator;

Note: function: _isDnsLabel rejects it everywhere else.

bytes1 internal constant LABEL_SEPARATOR = 0x2e

Functions

strlen

Computes the character length of a UTF-8 encoded string.

Counts Unicode code points, not bytes. Handles multi-byte UTF-8 sequences:

  • 1 byte: 0x00-0x7F (ASCII)
  • 2 bytes: 0xC0-0xDF
  • 3 bytes: 0xE0-0xEF
  • 4 bytes: 0xF0-0xF7
  • 5 bytes: 0xF8-0xFB (rare, outside Unicode standard)
  • 6 bytes: 0xFC-0xFD (rare, outside Unicode standard)
function strlen(string memory value) internal pure returns (uint256 len);

Parameters

NameTypeDescription
valuestringThe UTF-8 encoded string to measure.

Returns

NameTypeDescription
lenuint256The number of Unicode characters in the string.

isSingleLabel

Validates that s is a single canonical DNS label.

Lowercase ASCII letters, digits, and hyphen only; hyphen may not be the first or last character; length must be in (0, MAX_DNS_LABEL_OCTETS]. No dots allowed; use

Note: function: isNamePath for dotted forms. Mirrors the label rules enforced at the registrar.

function isSingleLabel(string calldata value) internal pure returns (bool isValid);

Parameters

NameTypeDescription
valuestringCandidate label.

Returns

NameTypeDescription
isValidboolTrue if value is a canonical DNS label.

isSingleLabelMemory

Memory-location helper for @custom:function isSingleLabel, used where the candidate label is produced by an upstream string transformation (e.g. the output of

Note: function: stripDigits) so callers do not need a calldata round-trip.

function isSingleLabelMemory(string memory value) internal pure returns (bool isValid);

Parameters

NameTypeDescription
valuestringCandidate label held in memory.

Returns

NameTypeDescription
isValidboolTrue if value is a canonical DNS label.

isLitePersonLabel

Validates the lite-person PoP label format: <stem>.<digits>.

A lite-person label is a stem of lowercase ASCII letters, one

Notes:

  • constant: LABEL_SEPARATOR, then exactly

  • constant: LITE_SUFFIX_DIGITS digits (e.g. joseph.42). Letters only, because the stem is the name a person chose, which is restricted to letters. How short a stem may be is policy rather than format, so it is left to the governance-reserved band in

  • function: IPopRules.classifyName. It is the only label shape in DotNS permitted to carry a separator, which is what reserves the dotted space to the gateway. A digit suffix is not exclusive: an ordinary label may end in digits, but it is measured as written and so classifies by its full length. Cross-flow priority is arbitrated on the stem, not on the whole label: a lite label's stem is reserved as a base name through

  • function: IPopRules.reserveBaseNameForPop, so joseph.42 contends with joseph. There is no flat spelling of a lite label for it to contend with.

function isLitePersonLabel(string calldata value) internal pure returns (bool isValid);

Parameters

NameTypeDescription
valuestringCandidate label.

Returns

NameTypeDescription
isValidboolTrue if value is a stem of lowercase ASCII letters followed by a separator and exactly @custom:constant LITE_SUFFIX_DIGITS digits.

isLitePersonLabelMemory

Memory-location helper for @custom:function isLitePersonLabel.

For callers holding the label in memory rather than calldata: the controller reads it back from a struct before deriving the node, and the lens reads it out of a store. Same predicate, different data location.

function isLitePersonLabelMemory(string memory value) internal pure returns (bool isValid);

Parameters

NameTypeDescription
valuestringCandidate label held in memory.

Returns

NameTypeDescription
isValidboolTrue if value is a stem of lowercase ASCII letters followed by a separator and exactly @custom:constant LITE_SUFFIX_DIGITS digits.

_isLitePersonLabel

function _isLitePersonLabel(bytes memory raw) private pure returns (bool isValid);

isPersonLabel

Validates that value is a name a person chose: lowercase ASCII letters only.

Matches the gateway's full-person label rule, which admits no digits and no hyphens, so a label outside this shape cannot have been issued. Stricter than @custom:function isSingleLabel, and it is the same rule

Note: function: isLitePersonLabel applies to a lite stem. How short a name may be is policy rather than format, so no floor is applied here.

function isPersonLabel(string calldata value) internal pure returns (bool isValid);

Parameters

NameTypeDescription
valuestringCandidate label.

Returns

NameTypeDescription
isValidboolTrue if every octet of value is a lowercase ASCII letter.

_isPersonLabel

function _isPersonLabel(
    bytes memory raw,
    uint256 start,
    uint256 end
)
    private
    pure
    returns (bool isValid);

splitLiteLabel

Splits a lite-person label <stem>.<digits> into its stem and digit suffix.

Splits at the first @custom:constant LABEL_SEPARATOR. A lite label carries exactly one separator, so the caller is expected to have run @custom:function isLitePersonLabelMemory first; a label with no separator returns the whole input as the stem and an empty suffix, which the caller's later label checks reject.

function splitLiteLabel(string memory value)
    internal
    pure
    returns (string memory stem, string memory suffix);

Parameters

NameTypeDescription
valuestringLite label held in memory, for example alice.01.

Returns

NameTypeDescription
stemstringThe label before the separator, for example alice.
suffixstringThe digit suffix after the separator, for example 01.

isNamePath

Validates that value is a dot-separated path of canonical DNS labels, within the whole-path octet ceiling.

Each segment between dots must satisfy @custom:function isSingleLabel. Empty segments (leading, trailing, or consecutive dots) fail. Used when callers submit multi-label paths (e.g. alice.dot) rather than bare labels. Two bounds apply and they are not the same one: @custom:constant MAX_DNS_LABEL_OCTETS caps each segment, and @custom:constant MAX_NAME_PATH_OCTETS caps the path. Without the second, a caller composes an unbounded path out of legal segments, so the segment bound alone does not bound what a caller can submit here.

function isNamePath(string calldata value) internal pure returns (bool isValid);

Parameters

NameTypeDescription
valuestringCandidate name path.

Returns

NameTypeDescription
isValidboolTrue if the path is at most @custom:constant MAX_NAME_PATH_OCTETS octets and every dot-separated segment is a canonical DNS label.

_isDnsLabel

function _isDnsLabel(
    bytes memory label,
    uint256 start,
    uint256 end
)
    private
    pure
    returns (bool isValid);

uintToString

Converts a uint256 to its decimal string representation.

Wraps OpenZeppelin's Strings.toString().

function uintToString(uint256 value) internal pure returns (string memory);

Parameters

NameTypeDescription
valueuint256The unsigned integer to convert.

Returns

NameTypeDescription
<none>stringThe decimal string representation.

addressToHex

Converts an address to its checksummed hexadecimal string representation.

Wraps OpenZeppelin's Strings.toHexString(). Returns lowercase hex with "0x" prefix.

function addressToHex(address account) internal pure returns (string memory);

Parameters

NameTypeDescription
accountaddressThe address to convert.

Returns

NameTypeDescription
<none>stringThe hexadecimal string representation (42 characters including "0x").

bytes32ToString

Converts a bytes32 value to a string, treating it as a null-terminated ASCII string.

Reads bytes until the first null byte (0x00) or end of bytes32. Useful for converting short strings stored in bytes32 back to string type.

function bytes32ToString(bytes32 _bytes32) internal pure returns (string memory);

Parameters

NameTypeDescription
_bytes32bytes32The bytes32 value containing a null-terminated ASCII string.

Returns

NameTypeDescription
<none>stringThe extracted string (up to 32 characters).