Steem Blockchain Platform

repository·main·Indexed 23 days ago

https://github.com/steemit/steem

A blockchain platform utilizing a 'Proof of Brain' social consensus algorithm for decentralized social media and Smart Media Tokens (SMTs). The repository includes the steemd node implementation and several core libraries: AppBase (a plugin framework), ChainBase (a transactional database for blockchain state), FC (a high-performance utility library for asynchronous C++), and MIRA (a RocksDB adapter for Boost Multi-Index Containers).

Tokens
25.8K
Snippets
55
Records
139
Agent score
84%

What's inside steem

  1. Overview of the FC (fast-compiling C++) library

    main

    FC is a utility library designed to accelerate the development of asynchronous C++ libraries. It provides several core capabilities for high-performance system development:

    • Asynchronous Programming: A cooperative multi-tasking library featuring support for Futures, mutexes, and signals.
    • Boost ASIO Wrapper: Provides a wrapper for Boost ASIO to handle asynchronous operations cooperatively, allowing developers to write code in a synchronous style.
    • Reflection & Serialization: Enables C++ reflection, allowing for automatic serialization of C++ structs into JSON and Binary formats.
    • RPC Support: Automatically generates client and server stubs for reflected interfaces, supporting JSON-RPC.
    • Cryptography: Includes cryptographic primitives for various hash functions and encryption algorithms.
    • Infrastructure: Provides logging infrastructure and wraps several Boost APIs (such as boost::filesystem, boost::thread, and boost::exception) to accelerate compilation times.
    • Process Management: Supports the unofficial Boost.Process library.
  2. What is ChainBase?

    main
    ChainBase is a fast, version-controlled, transactional database designed for blockchain applications and any use case requiring robust transactional state with near-infinite undo history. It supports multiple objects (tables) with multiple indices and provides persistent state that can be shared among multiple processes.
  3. What is the debug_node plugin and when to use it

    main

    The debug_node plugin allows you to simulate future hypothetical actions by modifying the local chain state. It is primarily used for debugging hardforks or new features by speeding up time or simulating changes to account balances and signing keys without needing actual witness private keys.

    Key capabilities:

    • Simulate changes to chain state (e.g., editing account balances or signing keys).
    • Speed up time by generating blocks locally.
    • Test how the node and wallet react to specific scenarios (e.g., a sudden change in an account's active key).

    Security Note: This plugin is intended for local development and debugging. Because it allows editing the database to report simulated state, it can cause the node to fail to sync with the real network. Do not expose the RPC endpoint to the internet when debug_node_api is enabled.

  4. What is MIRA (Multi-Index RocksDB Adapter)

    main
    MIRA is a wrapper that integrates Boost Multi-Index Containers with RocksDB. It allows developers to use the interface and capabilities of Boost Multi-Index containers while using RocksDB as the underlying storage engine. This enables writing code that can interchangeably use either a pure Boost implementation or a RocksDB-backed implementation by exposing equivalent interfaces.
  5. Understand Steem resource dynamics

    main

    Steem uses a resource model to manage medium-to-long-term blockchain limits. A resource is any capacity the blockchain needs to limit (e.g., subsidized accounts, history bytes, market bytes, state bytes, and execution time).

    For each resource, the blockchain maintains a resource pool that is influenced by three forces every block:

    1. Usage: Resources consumed by user transactions are subtracted from the pool.
    2. Budget: A fixed amount of resources added to the pool each block.
    3. Decay: A fixed percentage of resources subtracted from the pool each block to prevent unused resources from accumulating indefinitely (exponential decay).

    Key mathematical concepts for resource pools:

    • Equilibrium pool level: The level where budget and decay balance (assuming zero usage).
    • Half-life: The time it takes the pool to fall to 50% of its initial level (assuming zero usage/budget).
    • Characteristic time: The time it takes the pool to fall to ~36.8% ($1/e$) of its initial level.
  6. Use configuration overlays to tune specific databases

    main

    In MIRA, every object is its own RocksDB database. While the base configuration key applies settings to every database, you can use configuration overlays to override settings for a specific object.

    To create an overlay, add a key to the JSON configuration named after the specific object (e.g., account_authority_object).

    Critical Rule: When overriding a configuration value, you must override the complete first-level option. For example, if you want to change bits_per_key inside block_based_table_options, you must provide the entire block_based_table_options object in your overlay. Other settings not explicitly mentioned in the overlay will be inherited from base.

    {
      "base": {
        "block_based_table_options": {
          "bits_per_key": 10
        }
      },
      "account_authority_object": {
        "block_based_table_options": {
          "bits_per_key": 12
        }
      }
    }
  7. How AppBase plugin lifecycle and dependencies work

    main

    AppBase is a framework for building applications composed of plugins. It manages the lifecycle of these plugins to ensure they are configured, initialized, started, and shut down in the correct order based on their dependencies.

    Plugin Lifecycle

    Every plugin follows these three steps:

    1. Initialize: Parse configuration file options.
    2. Startup: Begin execution using the parsed configuration.
    3. Shutdown: Stop operations and free resources.

    Lifecycle Rules:

    • All plugins must complete the Initialize step before any plugin enters the Startup step.
    • Dependencies: If a plugin specifies a dependency using APPBASE_PLUGIN_REQUIRES, the required plugin will be Initialized or Started before the dependent plugin.
    • Shutdown Order: Shutdown is performed in the exact reverse order of Startup.
    class net_plugin : public appbase::plugin<net_plugin>
    {
       public:
         net_plugin(){};
         ~net_plugin(){};
    
         APPBASE_PLUGIN_REQUIRES( (chain_plugin) );
    
         virtual void set_program_options( options_description& cli, options_description& cfg ) override
         { ... }
    
         void plugin_initialize( const variables_map& options ) { ... }
         void plugin_startup()  { ... }
         void plugin_shutdown() { ... }
    };
  8. How API identifiers work (Numeric vs String)

    main

    Steem APIs can be addressed in two ways:

    1. Numeric Identifiers: APIs are assigned sequential IDs starting from 0 based on their order in the public-api configuration. While functional, this requires clients to coordinate closely with server configuration.
    2. String Identifiers: Clients can reference APIs by their name (e.g., "hello_api_api").

    Best Practice: Always use String Identifiers. This makes client code robust against server-side configuration changes that might reorder or renumber the APIs.

  9. Understand the structure of the Steem protocol definition

    main

    The protocol definition is contained within the steem/protocol headers. These classes provide the complete definition of the protocol and are organized by feature.

    When developing against or extending the protocol, note the following architectural constraints:

    • The protocol directory is designed to be self-contained.
    • Components in this directory should only depend on fc (foundation classes) or other types defined within the protocol directory itself.
    • Implementation details, such as objects defined in the object database, are intentionally excluded from this layer to maintain a clean separation between protocol definitions and stateful implementation.
  10. How the Python Debug Node works

    main

    The Python Debug Node acts as a high-level automation layer for the Steem Debug Node plugin. It bridges the gap between low-level node configuration and high-level blockchain interaction by:

    1. Programmatic Launching: It allows you to launch a node directly from Python code.
    2. RPC Interfacing: It utilizes community libraries (specifically Xeroc's python-steemlib) to interface with the node over RPC or WebSocket interfaces.
    3. Lifecycle Management: By using the Python with context manager pattern, it ensures that the steemd process is correctly connected, managed, and subsequently shut down/cleaned up automatically.
  11. Distinguish between Required and Optional Actions

    main

    Automated Actions are categorized into two types based on how nodes handle them:

    Required Actions

    • Mandatory: Must be included in blocks and verified trustlessly by every steemd node.
    • Deterministic: Nodes track expected required actions and apply them in lock-step. Blocks must include these actions in the exact order they are generated by the local node; failure to do so results in consensus rejection.
    • Execution Timing: Actions have an execution time and can only be included when the execution time is $\le$ the head block time.
    • Ordering: Pending actions are paginated by execution time and follow FIFO (First-In-First-Out) order within each time slot.
    • Block Space: 25% of the block size is reserved for required actions. To accommodate this, block generation typically fills user transactions only up to 75% of the block size.

    Optional Actions

    • Non-Mandatory: Not required to be included in every block. They can be skipped if block space is unavailable.
    • Flexible Ordering: Can be included in any order.
    • Resource Constraints: For SMTs (Steem Minted Tokens), optional actions like token emissions are excluded from block generation if there are insufficient Resource Credits (RCs).
    • Lifecycle: In the reference implementation, pending optional actions are removed from state once their execution time is $\le$ the last irreversible block's block time.
  12. How MIRA's multi-tiered storage architecture works

    main

    MIRA uses a multi-tiered architecture to manage data retrieval and storage across different layers. Each blockchain index acts as a distinct database. The tiers move from high-performance main memory (Object cache, Global shared cache, Global write buffer) to disk-based storage (Tier 0, Tier 1, etc.).

    Database TierLocationReadingWriting
    Object cacheMain memory
    Global shared cacheMain memory
    Global write bufferMain memory
    Tier 0 file basedDisk
    Tier 1 file basedDisk