Welcome to the new Provenance Blockchain developer documentation portal!
logo
The Provenance Blockchain name service builds up a hierarchy of names similar to DNS using dot-separated strings, where each level in the hierarchy can be owned by an account that must sign transactions to add new names under that level. The system supports delegating control through ownership transfer, implements strict normalization rules for name components including length restrictions and character validation, uses the restricted flag to control child name creation permissions, and requires root names to be created through genesis or governance proposals due to the hierarchical dependency structure.
While public names is not traditional to many blockchains, Provenance was created to engender trust in blockchain technology amongst the financial community. Thus, the name module was created, which can give increased transparency, on chain and when required/desired, for greater trust and adoption.

Concepts

Delegating Control

Every label in a name is owned by an address. Starting from the root address each level can be configured to allow any user to add a new child or for the exclusive control of the creator to add child names. The Restricted flag is used to indicate the permission requirements for adding child nodes.
protobuf
// Source: https://github.com/provenance-io/provenance // NameRecord is a structure used to bind ownership of a name heirarchy to a collection of addresses message NameRecord { option (gogoproto.goproto_stringer) = false; // The bound name string name = 1; // The address the name resolves to. string address = 2; // Whether owner signature is required to add sub-names. bool restricted = 3; }

Normalization

Name records are normalized before being processed for creation or query. Each component of the name must conform to a standard set of rules. The sha256 of the normalized value is used internally for comparison purposes.

Normalization Rules

  • Names are always stored and compared using a lower case form or a hash derived from this normalized form.
  • Unicode values that are not graphic, lower case, or digits are considered invalid.
  • A single occurrence of the hyphen-minus character is allowed unless the value conforms to a valid UUID.
HYPHEN-MINUS
Unicode: U+002D, UTF-8: 2D
  • Each component of the name is restricted to a length of 2 to 32 characters (inclusive). These limits are configurable in the module parameters.
  • A maximum of 16 components for a name (levels in the hierarchy) is also enforced and configurable in the module parameters.
  • Leading and trailing spaces are always trimmed off of names for consistency during processing and evaluation.

Creation of Root Names

As every name hierarchy depends on the name above it for permissioning and control, the root names present a problem with no parent to enforce their management. Because of this inception problem root names must be created in the genesis of the blockchain or through a governance proposal process.

State

The Provenance Blockchain name service maintains a simple state collection that stores name records using hash-based keys for efficient hierarchical queries and includes an address cache for fast reverse lookup operations. The state uses concatenated SHA256 hashes of each label component to create unique keys that enable quick iteration over all names under a given hierarchy level, while maintaining a separate address-to-name index for reverse resolution queries, with all records encoded using the NameRecord protobuf structure that binds names to addresses and ownership permissions.

Name Record KV Values

Name records are stored using a key based upon a concatenated list of hashes based on each label within the name. This approach allows all of the names in the tree under a given name to be quickly queried and iterated over.

Example Key Structure

Name: foo
Key: 2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae
Name: foo.bar
Key: 2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae.fcde2b2edba56bf408601fb721fe9b5c338d10ee429ea04fae5511b68fbf8fb9
Name: foo.bar.baz
Key: 2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae.fcde2b2edba56bf408601fb721fe9b5c338d10ee429ea04fae5511b68fbf8fb9.baa5a0964d3320fbc0c6a922140453c8513ea24ab8fd0577034804a967248096

Address Record KV Index

In addition to the records stored by name an address cache is maintained for the addresses associated with each name record. This allows simple and fast reverse lookup queries to be performed.

Example Address Index

Address: pb1tg3ktger9ttlscehl3r5j4pqw7qzmvs4qr9vpm
Key: 5A2365A3232AD7F86337FC4749542077802DB215.2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae.fcde2b2edba56bf408601fb721fe9b5c338d10ee429ea04fae5511b68fbf8fb9
Value: foo.bar

Name Record

Name records are encoded using the following protobuf type:
protobuf
// Source: https://github.com/provenance-io/provenance // NameRecord is a structure used to bind ownership of a name heirarchy to a collection of addresses message NameRecord { option (gogoproto.goproto_stringer) = false; // The bound name string name = 1; // The address the name resolved to. string address = 2; // Whether owner signature is required to add sub-names. bool restricted = 3; }

Messages

The Provenance Blockchain name service provides a comprehensive set of messages for managing the hierarchical name system, including MsgBindNameRequest for creating new name records under existing parents with ownership validation, MsgDeleteNameRequest for removing leaf name records and their associated attributes, MsgModifyNameRequest for updating existing name records through governance or owner authority, and both CreateRootNameProposal and MsgCreateRootNameRequest for establishing new root-level names through the governance process, ensuring proper authorization and validation at each level of the name hierarchy.

MsgBindNameRequest

A name record is created using the MsgBindNameRequest message.
protobuf
// Source: https://github.com/provenance-io/provenance message MsgBindNameRequest { option (gogoproto.equal) = false; option (gogoproto.goproto_getters) = false; // The parent record to bind this name under. NameRecord parent = 1 [(gogoproto.nullable) = false]; // The name record to bind under the parent NameRecord record = 2 [(gogoproto.nullable) = false]; }

Expected Failures

This message is expected to fail if:
  • The parent name record does not exist
  • The requestor does not match the owner listed on the parent record and the parent record indicates creation of child records is restricted
  • The record being created is otherwise invalid due to format or contents of the name value itself
  • Insufficient length of name
  • Excessive length of name
  • Not deriving from the parent record (targets another root)
If successful a name record will be created as described and an address index record will be created for the address associated with the name.

MsgDeleteNameRequest

The delete name request method allows a name record that does not contain any children records to be removed from the system. All associated attributes on account addresses will be deleted.
protobuf
// Source: https://github.com/provenance-io/provenance // MsgDeleteNameRequest defines an sdk.Msg type that is used to remove an existing address/name binding. The binding // may not have any child names currently bound for this request to be successful. All associated attributes on account addresses will be deleted. message MsgDeleteNameRequest { option (gogoproto.equal) = false; option (gogoproto.goproto_getters) = false; // The parent record the record to remove is under. NameRecord parent = 1 [(gogoproto.nullable) = false]; // The record being removed NameRecord record = 2 [(gogoproto.nullable) = false]; }

Expected Failures

This message is expected to fail if:
  • Any components of the request do not pass basic integrity and format checks
  • The parent name record does not exist
  • The record to remove does not exist
  • Any child records exist under the record being removed
  • The requestor does not match the owner listed on the record

MsgModifyNameRequest

A name record is modified by proposing the MsgModifyNameRequest message.
protobuf
// Source: https://github.com/provenance-io/provenance // MsgModifyNameRequest defines a method that is used to update an existing address/name binding. message MsgModifyNameRequest { option (cosmos.msg.v1.signer) = "authority"; // The address signing the message string authority = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; // The record being updated NameRecord record = 2 [(gogoproto.nullable) = false]; }

Expected Failures

This message is expected to fail if:
  • Any components of the request do not pass basic integrity and format checks
  • The record to update does not exist
  • The authority does not match the gov module or the name owner
If successful a name record will be updated with the new address and restriction.

CreateRootNameProposal

The create root name proposal is a governance proposal that allows new root level names to be established after the genesis of the blockchain.
protobuf
// Source: https://github.com/provenance-io/provenance message CreateRootNameProposal { option (gogoproto.equal) = false; option (gogoproto.goproto_getters) = false; option (gogoproto.goproto_stringer) = false; string title = 1; string description = 2; string name = 3; string owner = 4; bool restricted = 5; }

Expected Failures

This message is expected to fail if:
  • The name already exists
  • Insufficient length of name
  • Excessive length of name

MsgCreateRootNameRequest

The MsgCreateRootNameRequest is a governance proposal that allows new root level names to be established after the genesis of the blockchain.
protobuf
// Source: https://github.com/provenance-io/provenance message MsgCreateRootNameRequest { option (cosmos.msg.v1.signer) = "authority"; // The signing authority for the request string authority = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; // NameRecord is a structure used to bind ownership of a name hierarchy to a collection of addresses NameRecord record = 2; }

Expected Failures

This message is expected to fail if:
  • The name already exists
  • Insufficient length of name
  • Excessive length of name
  • The authority does not match the gov module
If successful a name record will be created with the provided address and restriction.

Events

The Provenance Blockchain name service emits specific events for each message handler operation to provide comprehensive tracking and auditing of name record lifecycle management. These events include name_bound events for successful name creation and root name proposals, name_unbound events for name deletion operations, and name_modify events for name record updates, with each event containing detailed attribute information about the name, address, and restriction status to enable complete visibility into name service operations.

Handlers

MsgBindNameRequest

Type
Attribute Key
Attribute Value
name_bound
name
{NameRecord.name}
name_bound
address
{NameRecord.address}
name_bound
restricted
{NameRecord.restricted}

MsgDeleteNameRequest

Type
Attribute Key
Attribute Value
name_unbound
name
{NameRecord.name}
name_unbound
address
{NameRecord.address}
name_unbound
restricted
{NameRecord.restricted}

MsgModifyNameRequest

Type
Attribute Key
Attribute Value
name_modify
authority
{String}
name_modify
name
{NameRecord.name}
name_modify
address
{NameRecord.address}
name_modify
restricted
{NameRecord.restricted}

CreateRootNameProposal

Type
Attribute Key
Attribute Value
name_bound
name
{NameRecord.name}
name_bound
address
{NameRecord.address}
name_bound
restricted
{NameRecord.restricted}

Related Resources

go
// Example event emission structure // Source: https://github.com/provenance-io/provenance // Event types emitted by the name module const ( EventTypNameBound = "name_bound" EventTypeNameUnbound = "name_unbound" EventTypeNameModify = "name_modify" ) // Attribute keys used in events const ( AttributeKeyName = "name" AttributeKeyAddress = "address" AttributeKeyRestricted = "restricted" AttributeKeyAuthority = "authority" )

Queries

The Provenance Blockchain name service provides a comprehensive query interface for resolving names to addresses and performing reverse lookups to find all names associated with a given address. The query service includes endpoints for retrieving module parameters, resolving names to their bound addresses with restriction status information, and performing reverse lookups with pagination support to discover all names bound to a specific address, enabling efficient name resolution and discovery operations within the hierarchical name system.

Params

Queries the parameters of the name module.
HTTP Endpoint: GET /provenance/name/v1/params
Request: QueryParamsRequestResponse: QueryParamsResponse

QueryParamsRequest

protobuf
// Source: https://github.com/provenance-io/provenance // QueryParamsRequest is the request type for the Query/Params RPC method. message QueryParamsRequest {}

QueryParamsResponse

protobuf
// Source: https://github.com/provenance-io/provenance // QueryParamsResponse is the response type for the Query/Params RPC method. message QueryParamsResponse { // params defines the parameters of the module. Params params = 1 [(gogoproto.nullable) = false]; }

Resolve

Queries for the address associated with a given name.
HTTP Endpoint: GET /provenance/name/v1/resolve/{name}
Request: QueryResolveRequestResponse: QueryResolveResponse

QueryResolveRequest

protobuf
// Source: https://github.com/provenance-io/provenance // QueryResolveRequest is the request type for the Query/Resolve method. message QueryResolveRequest { option (gogoproto.equal) = false; option (gogoproto.goproto_getters) = false; // name to resolve the address for string name = 1; }

QueryResolveResponse

protobuf
// Source: https://github.com/provenance-io/provenance // QueryResolveResponse is the response type for the Query/Resolve method. message QueryResolveResponse { // a string containing the address the name resolves to string address = 1; // Whether owner signature is required to add sub-names. bool restricted = 2; }

ReverseLookup

Queries for all names bound against a given address.
HTTP Endpoint: GET /provenance/name/v1/lookup/{address}
Request: QueryReverseLookupRequestResponse: QueryReverseLookupResponse

QueryReverseLookupRequest

protobuf
// Source: https://github.com/provenance-io/provenance // QueryReverseLookupRequest is the request type for the Query/ReverseLookup method. message QueryReverseLookupRequest { option (gogoproto.equal) = false; option (gogoproto.goproto_getters) = false; // address to find name records for string address = 1; // pagination defines an optional pagination for the request. cosmos.base.query.v1beta1.PageRequest pagination = 2; }

QueryReverseLookupResponse

protobuf
// Source: https://github.com/provenance-io/provenance // QueryReverseLookupResponse is the response type for the Query/Resolve method. message QueryReverseLookupResponse { option (gogoproto.equal) = false; option (gogoproto.goproto_getters) = false; // an array of names bound against a given address repeated string name = 1; // pagination defines an optional pagination for the request. cosmos.base.query.v1beta1.PageResponse pagination = 2; }
protobuf
// Example Query Service Definition // Source: https://github.com/provenance-io/provenance service Query { // Params queries params of the name module. rpc Params(QueryParamsRequest) returns (QueryParamsResponse) { option (google.api.http).get = "/provenance/name/v1/params"; } // Resolve queries for the address associated with a given name rpc Resolve(QueryResolveRequest) returns (QueryResolveResponse) { option (google.api.http).get = "/provenance/name/v1/resolve/{name}"; } // ReverseLookup queries for all names bound against a given address rpc ReverseLookup(QueryReverseLookupRequest) returns (QueryReverseLookupResponse) { option (google.api.http).get = "/provenance/name/v1/lookup/{address}"; } }

Params

Name Service Parameters

The Provenance Blockchain name service module contains configurable parameters that control the structure and validation rules for the hierarchical name system. These parameters define the minimum and maximum segment lengths for individual name components, set limits on the total number of hierarchy levels allowed in a name, and control whether unrestricted names can be created, providing essential constraints to ensure name consistency, prevent abuse, and maintain the integrity of the naming system across the blockchain network.

Parameters

The name module contains the following parameters:
Key
Type
Example
MaxSegmentLength
uint32
32
MinSegmentLength
uint32
2
MaxNameLevels
uint32
16
AllowUnrestrictedNames
bool
false

Parameter Details

MaxSegmentLength

Maximum length allowed for individual name segments (components).
Type: uint32Example: 32

MinSegmentLength

Minimum length required for individual name segments (components).
Type: uint32Example: 2

MaxNameLevels

Maximum number of levels (hierarchy depth) allowed in a complete name.
Type: uint32Example: 16

AllowUnrestrictedNames

Controls whether unrestricted names can be created in the system.
Type: boolExample: false