Decentralized Registry

Registry infrastructure for the universal transaction protocol


The node registry supports an interoperable network of independently hosted Provider Supporting Nodes (PSN) and Buyer Supporting Nodes (BSN) that are responsible for onboarding participants on either side of a two-sided market. PSNs and BSNs are both Personal Data Stores that specialize in storing and interfacing with different services related to Buyers or Providers respectively.

The node registry allows for basic peer discovery and verification of data transported between buyers and provider peers in a decentralized commercial transaction. We leverage existing cryptographic standards (secp256k1 for signing and keccak256 for hashing) to simplify inter-service communication.

About the Node Registry Infrastructure

The node registry is a decentralized public ledger that maintains the records of PDSs (network servers), their supported Industry Codes, and the geographical regions that they represent. The node registry is queried for a Producers products or services during the search phase of a Buyers transaction lifecycle.

During registration into the network, a Personal Data Store creates an ethereum key pair. The public key is stored on the blockchain in the node registry along with a unique identifier. When communicating with other Node's in the network, a sending Personal Data Store signs the data that they are sending over the network, including the signature hash in the header of the HTTP request. When this message is received by a receiving Node, they should query the registry for the sending Node's public key and use the signature in the request header to decrypt the message. If the message is successfully decrypted, the receiving Personal Data Store can know that the sending Personal Data Store is VERIFIED and properly registered. If the sending Personal Data Store's message is unable to be decrypted, the receiving Personal Data Store should respond to the sending Personal Data Stores request with an error code.

All registered Personal Data Stores self-maintain a location field in the registry table. The location field supports an array of strings that represent a Hexagonal Hierarchical Spatial Index.

Proposal

Dealing with Location Data

The H3 positioning systemis a geospatial indexing system using a hexagonal grid that can be (approximately) subdivided into finer and finer hexagonal grids, combining the benefits of a hexagonal grid with S2's hierarchical subdivisions. Each hexagonal cell is identified by an H3 index that enables efficient storage, querying, and processing of geospatial data. H3 offers the protocol a flexible and precise geospatial standard with prebuilt bindings for a wide range of programming languages like Java, JavaScript, Python, and others are available.

During the discovery phase of a Buyers transaction lifecycle, the registry is queried for PSNs that can offer products and services that fit the search criteria. The H3 system allows for a BSN to query the registry for PSNs offering nearby services during the discovery phase of the Buyers transaction lifecycle, offering local networks the opportunity to transact when there is a geographic restriction to the nature of the transaction; such as in food delivery or rideshare.

The H3 standard also allows the protocol to have a holonic structure that naturally scales to the needs of different industries and urban densities, making for a flexible, dynamic, and precise standard for location-specific commercial transactions.

PSNs should establish H3 indexes based on the Providers that they represent; translating the self-defined serviceable regions of their Providers to an H3 index that is stored in the registry as an array of strings. Each of these strings represents a hexagonal cell that if queried, should return at lease a single Provider able to commence in a transaction.

For more on generating indexes, see the h3 GitHub repository

Registration

To register a new node, you can use the registerNode method provided by the registry SDK. This method takes an object with the following properties:

  • name: The public name of your node.
  • callbackUrl: The public endpoint of your deployed server.
  • location: an array of h3 strings that your node supports. The location property is required for PSNs and optional for other node types.
  • industryCode: a network defined code. Each industry code has a specific protocol that your server must adopt.
  • nodeType: a numerical value representing an enum for your node type (PSN = 0, BSN = 1, GP = 2)

This object is represented by the RegisterNodeEntryParamsStruct object from the contract package @palette-labs/registry-contracts/typechain-types

export type RegisterNodeEntryParamsStruct = {
  name: string;
  callbackUrl: string;
  location: string[];
  industryCode: string;
  nodeType: BigNumberish;
};

Here's an example of how to register a node:

import { NodeRegistry } from "@palette-labs/registry-sdk";
import { ethers, JsonRpcProvider } from 'ethers';
 
  const nodeRegistryContractAddress = "0x56e3B524302Ec60Ec7850aF492D079367E03e5fb";
 
  // Setup provider and signer using environment variables
  const providerUrl = process.env.ETHEREUM_BASE_SEPOLIA_PROVIDER_URL; 
  const privateKey = process.env.SIGNER!; // your private key.
  const provider = new JsonRpcProvider(providerUrl);
  const signer = new ethers.Wallet(privateKey, provider);
 
  // Instantiate the NodeRegistry SDK and connect it with the signer
  const nodeRegistry = new NodeRegistry(nodeRegistryContractAddress);
  nodeRegistry.connect(signer);
 
  // Define a new node to register
  const newNode = {
      name: 'Example Node 2',
      callbackUrl: 'http://example2.com/callback',
      location: ['882681a339fffff'], // Example location
      industryCode: "EX",
      nodeType: 0, // 0 corresponds to PSN
  };
 
  const transaction = await nodeRegistry.registerNode(newNode);
  await transaction.wait();
  const uid = await transaction.wait()
  console.log(`Node registered with UID: ${uid}`);
 
  // Example Output
  // Node registered with UID: 0x56e3B524302Ec60Ec7850aF492D079367E03e5fb

After registering a node, you can use its UID to retrieve it's information.

Getting Schema Information

To retrieve the node information for a specific node UID, you can use the getNode method provided by the Registry SDK. Here's an example:

import { NodeRegistry } from "@palette-labs/registry-sdk";
 
  const nodeRegistryContractAddress = '0x56e3B524302Ec60Ec7850aF492D079367E03e5fb';
  const uid = '0xfd71b914f49331197fd1d14d2f5ab68884dac50d9069b94b927c4d38565df0e3';
  
  // Setup provider and signer using environment variables
  const providerUrl = process.env.ETHEREUM_BASE_SEPOLIA_PROVIDER_URL;
  const privateKey = process.env.SIGNER!; // your private key.
  const provider = new JsonRpcProvider(providerUrl);
  const signer = new ethers.Wallet(privateKey, provider);
 
  // Instantiate the NodeRegistry SDK and connect it with the signer
  const nodeRegistry = new NodeRegistry(nodeRegistryContractAddress);
  nodeRegistry.connect(signer);
 
  const nodeEntry = await nodeRegistry.getNode({ uid });
  console.log("Retrieved node:", nodeEntry);
 
  // Example Output
  Retrieved node: Result(8) [
    '0xfd71b914f49331197fd1d14d2f5ab68884dac50d9069b94b927c4d38565df0e3',
    'Example Node 2',
    'http://example2.com/callback',
    Result(1) [ '882681a339fffff' ],
    'EX',
    '0xd443dDeeC8cD386B6d592b82853738490798922a',
    0n,
    0n
  ]

In the output, you will receive an object containing the node UID and it's contents.