Skip to content

Instantly share code, notes, and snippets.

@cyio
Last active February 14, 2026 09:56
Show Gist options
  • Select an option

  • Save cyio/77fbd26a1ef46e8f1fe8d80997615e71 to your computer and use it in GitHub Desktop.

Select an option

Save cyio/77fbd26a1ef46e8f1fe8d80997615e71 to your computer and use it in GitHub Desktop.
Metanet Microblog Protocol Specification

Metanet Microblog Protocol Specification

Version: 1.0.0 Last Updated: 2026-02-14

Author: @cloudsay | Website: microblog.bitspv.com | Published at: Gist

1. Abstract

This document defines the protocol specification for Metanet Microblog, a decentralized social media protocol built on the BSV blockchain. It enables developers to build diverse applications on a shared, on-chain data layer where users retain full data ownership. The protocol leverages a Key-Value store model for all data interactions.

2. Core Technology

  • Storage Layer: The protocol MUST use the GlobalKVStore component from the @bsv/sdk library to store data on the BSV blockchain.
  • Data Model: All data is stored in a Key-Value model, where the key is a unique string and the value is a JSON-encoded string.
  • Identity: The identity of a user (e.g., author, liker, tipper) is the public key that controls the UTXO creating the KVStore record.

3. Protocol Identifiers

To ensure data isolation between different data types and applications, all KVStore entries MUST use a PROTOCOL_ID. A PROTOCOL_ID is a tuple of [number, string].

For development and testing, it is RECOMMENDED to prefix the string identifier with DEV (e.g., [0, 'DEV Microblog Posts v1']) to isolate test data from production data.

The official PROTOCOL_IDs are:

Data Type PROTOCOL_ID Description
Posts [0, 'Microblog Posts v1'] For all posts, including original posts and reposts.
Likes [0, 'Microblog Likes v1'] For "like" actions on posts.
Comments [0, 'Microblog Comments v1'] For comments on posts.
Tips [0, 'Microblog Tips v1'] For tipping content creators.
Chats [0, 'Microblog Chat v1'] For direct chat messages.

Note: The Reposts protocol mentioned in older versions is now deprecated. Reposts are a special type of Post and use the Microblog Posts v1 protocol.

4. Data Models and Operations

This section details the specific structure for each data type's Key, Value, and Tags.

4.1 Posts

A "Post" is the fundamental content type. Reposts are considered a special type of Post.

  • Key Format: post_{uuid}

    • uuid: A unique, randomly generated Base62 string. This identifier MUST be stable for the lifetime of the post.
  • Value Format (JSON String): A JSON object containing the post's data.

    Base Fields (for all posts):

    Field Type Required Description
    uuid string MUST The same unique identifier used in the key.
    content string MUST The main content of the post.
    timestamp number MUST A UTC Unix Timestamp in seconds indicating when the post was created.
    format string OPTIONAL The format of the content. Can be "text" or "markdown". If omitted, clients SHOULD interpret it as "text".

    Repost-Specific Fields: For reposts, the following fields MUST be added to the base structure.

    Field Type Required Description
    isRepost boolean MUST MUST be true.
    originalAuthorPublicKey string MUST The public key of the original post's author.
    originalUuid string MUST The uuid of the original post being reposted.
  • Tags: Tags are used for efficient querying and establishing relationships.

    Tag Format Required Description
    post_id_{uuid} MUST The primary identifier for the post. uuid is the post's own unique ID.
    repost_of_{originalPost.key} If Repost Links to the original post. originalPost.key is the full key of the original post (e.g., post_...).
    reposted_by_{reposterPublicKey} If Repost Identifies the reposter. reposterPublicKey is the public key of the user creating the repost.

4.2 Likes

A "Like" indicates a user's appreciation for a post.

  • Key Format: like_{post.uuid}

    • The key is composed of the prefix like_ and the uuid of the post being liked. The identity of the liker is derived from the UTXO controller, so it is not needed in the key to ensure uniqueness for one like per person per post.
  • Value Format (JSON String):

    Field Type Required Description
    likedAt number MUST A UTC Unix Timestamp in seconds indicating when the like was created.
  • Tags:

    Tag Format Required Description
    post_id_{post.uuid} MUST Links the like to the corresponding post, enabling efficient querying of all likes for that post.

4.3 Comments

A "Comment" is a textual response to a post.

  • Key Format: comment_{post.uuid}_{comment_uuid}

    • post.uuid: The uuid of the post being commented on.
    • comment_uuid: A new, unique, randomly generated Base62 string for the comment itself.
  • Value Format (JSON String): Comments share a similar value structure to Posts.

    Field Type Required Description
    uuid string MUST The same unique identifier used in the key (comment_uuid).
    content string MUST The content of the comment.
    timestamp number MUST A UTC Unix Timestamp in seconds.
    format string OPTIONAL Format of the content ("text" or "markdown").
  • Tags:

    Tag Format Required Description
    post_id_{post.uuid} MUST Links the comment to the parent post.

4.4 Tips

A "Tip" is an atomic operation that combines a fund transfer and an on-chain metadata record in a single transaction.

  • Key Format: tip_{post.uuid}_{timestamp}

    • post.uuid: The uuid of the post being tipped.
    • timestamp: The UTC Unix Timestamp (in seconds) of the tip, used to ensure key uniqueness for multiple tips from the same user.
  • Operation: A single transaction with two outputs:

    1. Output 1 (Fund Transfer): A standard P2PKH output sending satoshis to the post's author. It is RECOMMENDED to use a PeerPay-style (BRC-29) key derivation to protect recipient privacy.
    2. Output 2 (Metadata): A PushDrop output creating the GlobalKVStore record for the tip.
  • Value Format (JSON String):

    Field Type Required Description
    amount number MUST The amount of satoshis tipped.
    timestamp number MUST A UTC Unix Timestamp in seconds.
  • Tags:

    Tag Format Required Description
    post_id_{post.uuid} MUST Links the tip to the tipped post.
    tipper_id_{tipperPublicKey} MUST Identifies the tipper.
    recipient_id_{authorPublicKey} MUST Identifies the recipient of the tip.
  • Notification: It is RECOMMENDED to notify the recipient of the tip via an off-chain mechanism, such as @bsv/message-box-client.

5. Version History

  • v1.0.0 (2026-02-14):
    • Initial formal specification.
    • Transitioned post keys from post_{authorPublicKey}_{randomNonce} to a stable post_{uuid} format.
    • Introduced a uuid field in the value of Posts and Comments for consistent identification.
    • Updated key and tag structures for Likes, Reposts, and Tips to use the post uuid.
    • Added Chat and Tips to the list of official protocols.
    • Clarified that Reposts are a special type of Post.

Development Prompt: Building a Read-Only MVP for Metanet Microblog

1. Project Objective

Your task is to create a lightweight, read-only MVP (Minimum Viable Product) of a web application. This application will serve as a "mirror" to display public posts from the Metanet Microblog, a decentralized social media protocol built on the BSV blockchain.

2. Core Features

  1. Public Feed: Display a feed of the most recent public posts from the network.
  2. User Post Search: Include a search feature where a user can input an author's public key to view all posts created by that specific author.

3. Technical Stack & Dependencies

  • Framework: Use a modern JavaScript framework. React is highly recommended due to its component-based architecture.
  • Core Library: The application's connection to the blockchain data layer is managed by @bsv/sdk.
  • Styling: No complex styling is required. Focus on functionality.

4. Data Layer: GlobalKVStore

The entire protocol relies on @bsv/sdk's GlobalKVStore component, which functions as an on-chain key-value database.

  • Initialization: To query posts, you must first create a GlobalKVStore instance configured for the specific protocol. The wallet parameter can be omitted for read-only operations.

    import { GlobalKVStore } from '@bsv/sdk';
    
    // Protocol ID for production microblog posts
    const POSTS_PROTOCOL_ID = [0, 'Microblog Posts v1'];
    
    const postsKvStore = new GlobalKVStore({
      protocolID: POSTS_PROTOCOL_ID
    });

5. Data Structure & Schemas

Understanding the data schema is crucial for correctly fetching and parsing posts.

  • Post Key: The key for each post follows the format post_{uuid}, where uuid is a unique Base62 string that acts as a stable identifier.
  • Post Value: The value is a JSON string containing the post's metadata and content.
    • Example Value:
      {
        "content": "This is a sample post on the Metanet Microblog!",
        "timestamp": 1679347200000,
        "uuid": "aBcDeFg123",
        "format": "text" // Can be "text" or "markdown"
      }
  • Author Identity: The author of a post is identified by the controller field of the UTXO entry returned by the query. This field contains the author's public key.

6. Implementation Guide

Step 1: Fetching and Displaying All Public Posts

  • Use the get() method on the postsKvStore instance to retrieve a list of the latest posts.

  • Implement pagination using the limit and skip options to load data in batches.

  • Sort by newest first using sortOrder: 'desc'.

    async function fetchPublicPosts(page = 0, pageSize = 20) {
      const query = {
        limit: pageSize,
        skip: page * pageSize,
        sortOrder: 'desc'
      };
      
      // The `includeToken: true` option is useful for getting metadata
      const posts = await postsKvStore.get(query, { includeToken: true });
    
      // The result `posts` will be an array of KVStoreEntry objects.
      // You'll need to parse `entry.value` (JSON) and use `entry.controller` as the author's key.
      return posts;
    }

Step 2: Implementing the User Search Functionality

  • Add a text input field to the UI for users to paste an author's public key.

  • When a search is performed, call the get() method again, but this time, add the controller property to the query object.

    async function fetchPostsByUser(publicKey, page = 0, pageSize = 20) {
      if (!publicKey) return [];
    
      const query = {
        controller: publicKey,
        limit: pageSize,
        skip: page * pageSize,
        sortOrder: 'desc'
      };
    
      const userPosts = await postsKvStore.get(query, { includeToken: true });
      return userPosts;
    }

Step 3: Rendering the Posts

  • Create a Post component that takes the parsed post data as props.
  • Inside the component, display the post content and the author's public key (controller).
  • The application should have a state to hold the list of posts to be rendered. This state will be updated by both the public feed fetch and the user-specific search.

7. UI/UX Requirements

  • A main view that lists the posts.
  • An input field and a "Search" button to filter by author public key.
  • A "Load More" button at the bottom of the list to handle pagination.
  • A "Show All Posts" / "Clear Search" button to switch from a user-specific view back to the global public feed.

8. Optional Enhancements (Extra Credit)

  • Timestamp: Convert the timestamp field into a human-readable format (e.g., "Dec 21, 2025").
  • Markdown Support: If a post's format field is "markdown", render its content as Markdown.
  • Author Name Resolution: Instead of just showing the author's long public key, you can implement a simple function to fetch a more user-friendly identity (name/avatar) from known on-chain identity services. The original project uses a resolveIdentities utility for this. For this MVP, a hardcoded map or a simple placeholder would suffice.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment