btcwallet Documentation

repository·master·Indexed 22 days ago

https://github.com/btcsuite/btcwallet

btcwallet is a Bitcoin wallet daemon that manages hierarchical deterministic (HD) wallets following BIP0032 and BIP0044. It acts as an RPC client for btcd and provides both legacy JSON-RPC and experimental gRPC interfaces. The project includes the waddrmgr package for secure HD wallet address management and walletdb for namespaced database storage with pluggable backends like Boltdb.

Tokens
30.7K
Snippets
53
Records
178
Agent score
78%

What's inside btcwallet

  1. Overview of wtxmgr features

    master

    The wtxmgr package is responsible for the storage and spend tracking of wallet transactions, including their inputs and outputs.

    Key capabilities include:

    • Transaction Storage: Maintains records of relevant wallet transactions.
    • Output Control: Ability to mark specific outputs as being controlled by the wallet.
    • UTXO Management: Provides an Unspent Transaction Output (UTXO) index.
    • Balance Tracking: Monitors wallet balances.
    • Spend Tracking: Automatically tracks spending when transactions are inserted or removed.
    • Reorg Resilience: Detects and corrects double spends following blockchain reorganizations.
    • Scalable Design: Uses specific prefixes to allow cursor iteration over transaction inputs and outputs and operates under its own walletdb namespace.
  2. What is waddrmgr?

    master

    The waddrmgr package is a secure hierarchical deterministic (HD) wallet address manager. It is designed to manage Bitcoin addresses and keys using industry standards and high-security practices.

    Key Features

    Standards Compliance

    • BIP0032: Implements hierarchical deterministic keys.
    • BIP0043/BIP0044: Supports multi-account hierarchy.

    Security Model

    • Encrypted Database: All data, including public addresses and private keys/scripts, is stored in a fully encrypted database.
    • Memory Protection: Actively clears private material from memory when the wallet is locked to protect against memory scraping.
    • Cryptographic Isolation: Uses different crypto keys for public, private, and script data. It also supports different passphrases for public and private data.
    • Key Derivation: Uses Scrypt-based key derivation.
    • Encryption Algorithms: Utilizes NaCl-based secretbox cryptography (XSalsa20 and Poly1305).

    Scalability and Flexibility

    • Multi-tier Key Design: Allows for instant password changes without needing to re-encrypt all stored addresses.
    • Import Capabilities: Supports importing WIF keys and pay-to-script-hash scripts (e.g., for multi-signature transactions).
    • Watching-only Mode: Supports starting in or converting to a "watching-only" mode, which contains no private key material.
    • Synchronization: Includes address synchronization capabilities.
  3. Access the wallet via gRPC RPC server

    master

    The primary method for interacting with the wallet from external processes is through its built-in gRPC server. This allows client programs to perform remote procedure calls to manage wallet operations.

    For detailed information on how to use this interface, refer to the following resources:

    • API Specification: Defines the available services and methods.
    • Client Usage: Provides guidance on how to implement and use clients to interact with the server.

    Note: A legacy JSON-RPC API (compatible with Bitcoin Core's wallet) is available but is not covered in this documentation.

  4. What is walletdb and how does its namespaced interface work?

    master

    The walletdb package provides a namespaced database interface designed for the btcwallet daemon. It allows different components of a wallet (such as address management, voting pools, or metadata) to store data in their own isolated namespaces within a single shared database. This prevents key collisions between different packages while maintaining atomicity.

    Key features include:

    • Key/value store: Standard KV operations.
    • Namespace support: Enables multiple packages to operate in their own area without conflicts.
    • Transactions: Supports both read-only and read-write transactions in both manual and managed modes.
    • Nested buckets: Allows for hierarchical data organization.
    • Pluggable backends: Supports registration of different backend database types via drivers.
  5. What is btcwallet and how does it work?

    master

    btcwallet is a daemon that manages bitcoin wallet functionality for a single user. It operates as both an RPC client to btcd (for blockchain queries and websocket notifications) and an RPC server for wallet clients or legacy applications.

    Key Characteristics

    • HD Wallet: Uses the BIP0032 hierarchical deterministic format. It follows the m/44'/<coin type>'/<account>'/<branch>/<address index> path as described in BIP0044.
    • Security: Unencrypted private keys are never supported and are never written to disk. It also provides an option to encrypt public data to prevent privacy leaks (tracking balances/transactions) if the wallet file is compromised.
    • Connectivity: It is NOT an SPV client; it requires a connection to a btcd instance (local or remote) for asynchronous blockchain queries.

    RPC Server Options

    1. Legacy JSON-RPC: Enabled by default. It is designed for compatibility with Bitcoin Core to ease migration, though some API behaviors (especially regarding accounts) differ due to BIP0044.
    2. Experimental gRPC: Built specifically for btcwallet. It is feature-gated and requires the --experimentalrpclisten configuration option. This server is recommended if you need wallet change notifications and do not mind potential API instability.
  6. Manage concurrency safely in btcwallet

    master

    Concurrency is managed using strict rules to prevent subtle bugs and goroutine leaks. Follow these core principles:

    • Share Memory By Communicating: Prefer passing ownership of data over channels rather than using locks to protect shared memory.
    • Predictable Goroutine Exit: Never start a goroutine without a clear, predictable exit path. Use context.Context to manage lifecycles.
    • Structured Concurrency: Every function performing network calls, database queries, or blocking operations must accept context.Context as its first argument to enable cancellation and deadline propagation. For managing groups of goroutines, use golang.org/x/sync/errgroup.

    Common Pitfalls

    • Slices: Slices are unsafe for concurrent modification. Either pass a pointer (*[]MyType) protected by a mutex or use channels to pass ownership.
    • Maps: Go's built-in map is not thread-safe. Any map accessed by multiple goroutines must be protected by a sync.Mutex or sync.RWMutex.
    • Synchronization Primitives: Always pass primitives like sync.Mutex by pointer. Passing them by value creates a copy that does not protect the original resource.
    // GOOD: Goroutine will exit when the context is cancelled.
    func worker(ctx context.Context, jobs <-chan Job) {
        for {
            select {
            case <-ctx.Done():
                return
            case job := <-jobs:
                process(job)
            }
        }
    }
  7. How network selection and safety checks work in btcwallet

    master

    When starting the btcwallet daemon, the following lifecycle occurs regarding database and network management:

    1. Network Selection: The daemon reads the active network flag (e.g., --network=testnet).
    2. DSN Lookup: It selects the corresponding db.dsn from the btcwallet.conf file for that specific network.
    3. Network Binding Verification: To prevent data corruption (such as accidentally pointing a testnet configuration to a mainnet database), btcwallet uses a meta table within the database to bind it to a specific network.
    4. Startup Safety: On every startup, the daemon verifies this binding. If the network specified by the CLI flag does not match the network bound in the database's meta table, btcwallet will refuse to start and will output a clear error.
  8. How the Actor Model is used for concurrency

    master

    To manage concurrency and state safely, the project uses the Actor Model. Instead of sharing memory and protecting it with mutexes, state is isolated within independent, long-running goroutines called "actors."

    An actor follows these three rules:

    1. Owns its state exclusively: No other part of the system can touch its internal data.
    2. Runs in a dedicated goroutine.
    3. Communicates only via messages: Messages are sent over channels (the actor's "mailbox").

    This approach ensures concurrency safety and decouples subsystems for easier testing and maintenance.

  9. Implement Deep Modules to Simplify Interfaces

    master

    A core architectural goal is to ensure a module's interface is significantly simpler than its internal implementation. This reduces the cognitive load on users of the API.

    Example Pattern: Instead of exposing the complexities of mempool checks and database synchronization, the TxPublisher interface provides a single, clean method:

    // The user sees this simple interface
    TxPublisher.Broadcast(tx)
    
    // Internally, it handles:
    // 1. Mempool acceptance checks
    // 2. Atomic database updates via addTxToWallet
    // 3. Network broadcast
  10. Use Context Propagation for control and observability

    master

    Passing a context.Context through every function call in a request's lifecycle is the most important pattern for controlling behavior. It allows for:

    • Enforcing timeouts.
    • Propagating cancellation signals.
    • Gracefully tearing down work for abandoned requests.

    Best Practice: Inside long-running loops, always check for cancellation using select { case <-ctx.Done(): ... }.

    // Every function that is part of a request accepts a context.
    func (a *MyActor) ProcessPayment(ctx context.Context, payment Payment) error {
        // Pass the context down to the next actor/function.
        err := a.db.Save(ctx, payment)
        if err != nil {
            return err
        }
        // ...
        return nil
    }
    
    // Inside a long-running loop, always check for cancellation.
    for {
        select {
        case <-ctx.Done():
            return ctx.Err() // Exit cleanly
        // ... do other work
        }
    }
  11. Implement the Pipeline Pattern for data flow

    master

    The Pipeline Pattern structures work as a series of actors (stages) connected by channels. Each actor performs a specific task and passes its output to the next actor in the chain. This is used to break down complex processes into simple, decoupled, and reusable stages.

    // Stage 1: Doubles numbers
    func doubler(in <-chan int, out chan<- int) {
        for num := range in {
            out <- num * 2
        }
        close(out)
    }
    
    // Stage 2: Adds 5 to numbers
    func adder(in <-chan int, out chan<- int) {
        for num := range in {
            out <- num + 5
        }
        close(out)
    }
    
    // Building the pipeline:
    // inputChan -> doubler -> adder -> outputChan
  12. Keep test case structs for data only

    master

    In table-driven tests, the test case struct should only contain data (inputs and expected outputs).

    Avoid embedding setup logic: Do not include functions or complex setup logic inside the test case struct. Embedding setup (like a setup func(...) field) obscures the test's behavior and makes it harder to understand each case in isolation. Setup should be explicit and clear within the test's body.

    // Good Example: Data-only Struct
    func TestBuildTxDetail(t *testing.T) {
        tests := []struct {
            name             string
            details          *wtxmgr.TxDetails // Input
            currentHeight    int32             // Input
            expectedTxDetail *TxDetail         // Expected Output
        }{
            // ... test cases defined here
        }
    
        for _, test := range tests {
            // ... test logic here
        }
    }