chain

package
v0.0.0-...-0e82d15 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 20, 2026 License: MIT Imports: 28 Imported by: 0

Documentation

Overview

Package chain provides Namecoin blockchain functionality built on btcd.

The chain package wraps btcd's blockchain.BlockChain with Namecoin-specific name operation validation, AuxPow (Auxiliary Proof of Work) support, and name database integration. It implements composition over reimplementation, leveraging btcd's battle-tested blockchain components while adding the necessary extensions for Namecoin's naming system.

Architecture

The package follows a layered design:

  • BlockChain: Embeds btcd's blockchain.BlockChain with name validation hooks
  • AuxPow: Merged mining support for blocks after height 19,200
  • Block: Namecoin block wrapper with AuxPow header support
  • Validation: Name operation and protocol compliance checking

Name Operations

The chain validates three types of name operations:

  • NAME_NEW: Pre-registration commitment to prevent front-running
  • NAME_FIRSTUPDATE: First registration, reveals the name from NAME_NEW
  • NAME_UPDATE: Updates name value and extends expiration by 36,000 blocks

Each operation must comply with Namecoin protocol rules including:

  • Name length: 1-255 bytes
  • Value size: ≤1023 bytes (consensus), ≤520 bytes (UI limit for user-facing APIs)
  • Timing: NAME_FIRSTUPDATE within 12-36,000 blocks of NAME_NEW
  • Uniqueness: No duplicate unexpired names

AuxPow (Merged Mining)

After block 19,200, Namecoin requires Auxiliary Proof of Work (AuxPow) which allows miners to mine Namecoin alongside Bitcoin or other Scrypt-based chains. AuxPow validation includes:

  • Version bit verification (0x100 must be set)
  • Parent block header validation
  • Coinbase transaction merkle proof verification
  • Chain ID validation (Namecoin = 1)

The package includes an LRU cache for AuxPow data to handle the mismatch between btcd's block representation and Namecoin's extended block format.

Thread Safety

BlockChain is safe for concurrent use. All shared state is protected with sync.RWMutex. Block validation and name database updates are atomic.

Example Usage

Creating a new blockchain:

cfg := &chain.Config{
    ChainParams: &config.NamecoinMainNetParams,
    NameDBPath:  "/path/to/names.db",
    DataDir:     "/path/to/data",
}
bc, err := chain.NewBlockChain(cfg, nil)
if err != nil {
    log.Fatal(err)
}
defer bc.Close()

// Process a block
err = bc.ProcessBlock(block, blockchain.BFNone)
if err != nil {
    log.Printf("Block rejected: %v", err)
}

Known Limitations

The protocol constants, name operations, and AuxPow deserialization are fully compliant with Namecoin Core (22/22 checks pass, 6/6 mainnet test vectors pass). See docs/development/PROTOCOL_COMPLIANCE_AUDIT.md for the full audit.

Remaining gaps that affect production mainnet readiness:

  • Full AuxPow parent-chain Proof of Work verification (pragmatic shortcut used)
  • Namecoin-specific subsidy calculation edge cases

These gaps do not affect name operation correctness or block structure validation. The package is suitable for development, testing, and name resolution use cases.

Index

Constants

View Source
const DefaultAuxPowCacheSize = 100

DefaultAuxPowCacheSize is the default maximum number of AuxPow entries to cache. This value is chosen to be large enough to handle normal operation (blocks are processed sequentially) while providing protection against adversarial scenarios. Each AuxPow entry is approximately 1KB, so 100 entries use ~100KB memory.

View Source
const NamecoinChainID = 1

Namecoin chain ID for merge mining Per Namecoin Core src/auxpow.cpp: Namecoin uses chain ID = 1

Variables

This section is empty.

Functions

func CheckMerkleBranch

func CheckMerkleBranch(leaf *chainhash.Hash, branch *MerkleBranch, root *chainhash.Hash) bool

CheckMerkleBranch verifies a merkle branch proof.

Verifies that 'leaf' is included in a merkle tree with 'root' as the merkle root, using the provided merkle branch path.

Per Namecoin Core src/auxpow.cpp (CheckMerkleBranch): The algorithm walks up the merkle tree from the leaf to the root, combining the current hash with sibling hashes from the branch. The SideMask determines whether the sibling is on the left (bit=1) or right (bit=0) at each level.

Arguments:

  • leaf: The hash of the leaf node (e.g., transaction hash)
  • branch: The merkle branch proof (sibling hashes and side mask)
  • root: The expected merkle root

Returns:

  • true if the proof is valid (computed root matches expected root)
  • false if the proof is invalid

func ExtractChainIDFromVersion

func ExtractChainIDFromVersion(version int32) uint32

ExtractChainIDFromVersion extracts the chain ID from a Namecoin block version.

Per Namecoin Core src/primitives/pureheader.h: The chain ID is stored in bits 16+ of the block version. Formula: chainID = (version >> 16)

For Namecoin mainnet blocks with AuxPoW: - Version 0x00010101 = chain ID 1 (0x0001) - The AuxPoW bit is 0x100 (bit 8) - The base version is in bits 0-7

This function extracts the chain ID from any Namecoin block version, allowing validation that the block is intended for the Namecoin chain.

Arguments:

  • version: The block version from the Namecoin block header

Returns:

  • Chain ID extracted from the version

Types

type AuxPow

type AuxPow struct {
	// CoinbaseTx is the coinbase transaction from the parent blockchain
	// that commits to this block's hash in its scriptSig or output.
	CoinbaseTx wire.MsgTx

	// BlockHash is the hash of the auxiliary blockchain block (this Namecoin block).
	// This hash must appear in the parent chain's coinbase transaction.
	BlockHash chainhash.Hash

	// CoinbaseBranch is the merkle branch proving the coinbase transaction
	// is included in the parent block's merkle tree.
	CoinbaseBranch MerkleBranch

	// ChainMerkleBranch is the merkle branch proving the auxiliary block hash
	// is committed to in the coinbase transaction.
	ChainMerkleBranch MerkleBranch

	// ParentBlock is the header of the parent blockchain block.
	// This header's merkle root must match the merkle proof from CoinbaseBranch,
	// and its hash must meet the difficulty target.
	ParentBlock wire.BlockHeader
}

AuxPow represents an auxiliary proof of work used in merged mining. This structure contains the proof that a block was included in a parent blockchain's (typically Bitcoin's) merkle tree, allowing Namecoin to leverage Bitcoin's proof of work.

Per Namecoin Core src/primitives/pureheader.h and src/auxpow.cpp: An AuxPow consists of: 1. Coinbase transaction from parent chain containing the merge-mined block hash 2. Block hash of the merge-mined block 3. Merkle branch proving coinbase is in parent block 4. Merkle branch proving aux block hash is in coinbase 5. Parent block header

References: - Namecoin Core: https://github.com/namecoin/namecoin-core/blob/master/src/primitives/pureheader.h - BIP: https://en.bitcoin.it/wiki/Merged_mining_specification

func DeserializeAuxPow

func DeserializeAuxPow(r io.Reader) (*AuxPow, error)

DeserializeAuxPow reads an AuxPow structure from a reader. This implements the wire protocol deserialization for AuxPow blocks.

Per Namecoin Core wire format (src/auxpow.cpp): 1. Coinbase transaction (standard Bitcoin tx format) 2. Block hash (32 bytes) 3. Coinbase merkle branch (variable length) 4. Chain merkle branch (variable length) 5. Parent block header (80 bytes)

Returns:

  • AuxPow structure if successful
  • Error if deserialization fails (malformed data, EOF, etc.)

func (*AuxPow) SerializeAuxPow

func (ap *AuxPow) SerializeAuxPow(w io.Writer) error

SerializeAuxPow writes an AuxPow structure to a writer. This implements the wire protocol serialization for AuxPow blocks.

Format matches DeserializeAuxPow: 1. Coinbase transaction 2. Block hash 3. Coinbase merkle branch 4. Chain merkle branch 5. Parent block header

func (*AuxPow) ValidateAuxPow

func (ap *AuxPow) ValidateAuxPow(blockHash, targetDifficulty *chainhash.Hash) error

ValidateAuxPow validates an AuxPow proof for a merged-mined block.

Per Namecoin Core src/auxpow.cpp (CheckAuxPow): Full validation includes: 1. Verify coinbase merkle branch connects coinbase to parent block merkle root 2. Verify chain merkle branch connects aux block hash to coinbase 3. Verify parent block hash meets difficulty target 4. Extract and validate chain ID matches expected chain 5. Verify aux block hash appears in correct position in coinbase

Note: Chain ID validation is the caller's responsibility. The caller should extract the chain ID from the Namecoin block's version using ExtractChainIDFromVersion() and validate it before calling this function.

Arguments:

  • blockHash: The hash of the auxiliary blockchain block (this Namecoin block)
  • targetDifficulty: The required proof-of-work difficulty target for the parent block

Returns:

  • nil if validation succeeds
  • error describing validation failure

type Block

type Block struct {
	*btcutil.Block
	// contains filtered or unexported fields
}

Block extends btcutil.Block with Namecoin-specific AuxPow data. This wrapper allows us to work with both standard Bitcoin blocks (pre-AuxPow) and Namecoin merged-mined blocks (post-AuxPow activation at height 19,200).

Design: Instead of forking btcd's Block type, we compose it and add AuxPow as an additional field. This maintains compatibility with btcd's blockchain package while adding Namecoin-specific functionality.

func NewBlock

func NewBlock(msgBlock *wire.MsgBlock) *Block

NewBlock creates a new Block from a wire.MsgBlock. The AuxPow field is initially nil and must be set separately via SetAuxPow() or by using NewBlockFromReader() which deserializes the full block including AuxPow.

func NewBlockFromBytes

func NewBlockFromBytes(serializedBlock []byte) (*Block, error)

NewBlockFromBytes deserializes a block from a byte slice, including AuxPow data if present.

The wire format for Namecoin blocks differs based on the block version:

Pre-AuxPoW blocks (version bit 0x100 NOT set):

  1. Block header (80 bytes)
  2. Transaction count (varint)
  3. Transactions (variable length)

AuxPoW blocks (version bit 0x100 set):

  1. Block header (80 bytes)
  2. AuxPoW data (variable length) - BEFORE transactions!
  3. Transaction count (varint)
  4. Transactions (variable length)

This function automatically detects whether AuxPow is present based on the block version and deserializes it in the correct order.

Arguments:

  • serializedBlock: The complete serialized block including AuxPow (if present)

Returns:

  • Block with AuxPow populated (if block version indicates AuxPow)
  • Error if deserialization fails

func NewBlockFromReader

func NewBlockFromReader(r io.Reader) (*Block, error)

NewBlockFromReader deserializes a block from an io.Reader, including AuxPow data if present.

This is the primary deserialization function for Namecoin blocks. It handles both: 1. Pre-AuxPow blocks (< height 19,200): Standard Bitcoin block format 2. AuxPow blocks (>= height 19,200): Header + AuxPow + Transactions

IMPORTANT: The wire format for AuxPoW blocks places the AuxPoW data BEFORE the transaction count and transactions, NOT after. This differs from what one might expect and requires custom deserialization logic.

Reference: This ordering (AuxPoW serialized immediately after the header and before the transaction vector) matches Namecoin Core's wire format as implemented in src/primitives/block.h (CBlockHeader serialization with AuxPow) and related AuxPow handling code. Maintain this ordering to stay consensus-compatible.

Wire format for AuxPoW blocks:

  1. Block header (80 bytes)
  2. AuxPoW structure: - Coinbase TX from parent chain - Block hash (32 bytes) - Coinbase merkle branch - Chain merkle branch - Parent block header (80 bytes)
  3. Transaction count (varint)
  4. Block transactions

Arguments:

  • r: Reader containing the serialized block data

Returns:

  • Block with AuxPow populated (if block version indicates AuxPow)
  • Error if deserialization fails (malformed block, incomplete AuxPow, etc.)

func (*Block) AuxPow

func (b *Block) AuxPow() *AuxPow

AuxPow returns the AuxPow data for this block, or nil if the block is pre-AuxPow.

Returns:

  • AuxPow structure for merged-mined blocks (version bit 0x100 set)
  • nil for pre-AuxPow blocks or if AuxPow was not deserialized

func (*Block) Bytes

func (b *Block) Bytes() ([]byte, error)

Bytes returns the serialized block as a byte slice, including AuxPow if present.

Returns:

  • Byte slice containing the complete serialized block
  • Error if serialization fails

func (*Block) HasAuxPow

func (b *Block) HasAuxPow() bool

HasAuxPow returns true if this block has AuxPow data. This checks both: 1. The block version has the AuxPow bit set 2. The auxPow field is non-nil

Returns:

  • true if block should have and does have AuxPow
  • false for pre-AuxPow blocks or if AuxPow is missing

func (*Block) Serialize

func (b *Block) Serialize(w io.Writer) error

Serialize writes the complete block to a writer, including AuxPow if present.

Wire format for AuxPoW blocks:

  1. Block header (80 bytes)
  2. AuxPoW data (if HasAuxPow() returns true) - BEFORE transactions!
  3. Transaction count (varint)
  4. Transactions (variable length)

Wire format for pre-AuxPoW blocks:

  1. Block header (80 bytes)
  2. Transaction count (varint)
  3. Transactions (variable length)

This produces a serialized block that can be sent over the Namecoin P2P network or stored in block files.

Arguments:

  • w: Writer to serialize the block to

Returns:

  • nil on success
  • error if serialization fails

func (*Block) SetAuxPow

func (b *Block) SetAuxPow(auxPow *AuxPow)

SetAuxPow sets the AuxPow data for this block. This is used when constructing blocks programmatically (e.g., in tests).

Arguments:

  • auxPow: The AuxPow structure to attach to this block (can be nil)

type BlockChain

type BlockChain struct {
	*blockchain.BlockChain
	// contains filtered or unexported fields
}

BlockChain wraps btcd blockchain with name operation validation

func NewBlockChain

func NewBlockChain(cfg *Config, indexManager blockchain.IndexManager) (*BlockChain, error)

NewBlockChain creates a new blockchain with name support

func (*BlockChain) BestSnapshot

func (bc *BlockChain) BestSnapshot() *blockchain.BestState

BestSnapshot returns the current best chain snapshot

func (*BlockChain) ChainParams

func (bc *BlockChain) ChainParams() *chaincfg.Params

ChainParams returns the chain parameters

func (*BlockChain) Close

func (bc *BlockChain) Close() error

Close closes the blockchain and name database

func (*BlockChain) GetBlockByHash

func (bc *BlockChain) GetBlockByHash(hash *chainhash.Hash) (*btcutil.Block, error)

GetBlockByHash returns a block by hash

func (*BlockChain) GetBlockHeader

func (bc *BlockChain) GetBlockHeader(hash *chainhash.Hash) (wire.BlockHeader, error)

GetBlockHeader returns a block header by hash

func (*BlockChain) GetName

func (bc *BlockChain) GetName(name string) (*namedb.NameRecord, error)

GetName retrieves a name from the database

func (*BlockChain) GetNameDB

func (bc *BlockChain) GetNameDB() *namedb.NameDatabase

GetNameDB returns the name database instance. This allows external packages to access the name database for read operations.

func (*BlockChain) GetNameHistory

func (bc *BlockChain) GetNameHistory(name string) ([]*namedb.NameRecord, error)

GetNameHistory retrieves the historical records for a specific name. Returns all past operations on the name in chronological order.

func (*BlockChain) GetNameUTXO

func (bc *BlockChain) GetNameUTXO(name string) (*namedb.UTXO, error)

GetNameUTXO retrieves the UTXO that holds a specific name

func (*BlockChain) GetUTXOsForAddress

func (bc *BlockChain) GetUTXOsForAddress(address string) ([]*namedb.UTXO, error)

GetUTXOsForAddress retrieves all UTXOs for a specific address

func (*BlockChain) HandleBlockchainNotification

func (bc *BlockChain) HandleBlockchainNotification(notification *blockchain.Notification)

HandleBlockchainNotification processes blockchain notifications. This method must NOT acquire bc.mu because it may be dispatched synchronously from within bc.BlockChain.ProcessBlock() (which holds bc.mu), causing a deadlock. All operations here delegate to bc.nameDB which has its own independent mutex.

func (*BlockChain) ListNames

func (bc *BlockChain) ListNames() ([]*namedb.NameRecord, error)

ListNames retrieves all names from the database

func (*BlockChain) ProcessBlock

func (bc *BlockChain) ProcessBlock(block *btcutil.Block, flags blockchain.BehaviorFlags) (bool, bool, error)

ProcessBlock processes a block, validates name operations, and returns its chain status.

The supplied block is treated as read-only; the caller retains ownership and may safely reuse the block after ProcessBlock returns.

Return values (isMainChain, isOrphan, err):

(true,  false, nil) — block accepted onto the main chain; name database updated.
(false, false, nil) — block accepted as a side-chain block; name database NOT updated.
(false, true,  nil) — block is an isolated orphan (parent unknown); name database NOT updated.
                      Note: (true, true, nil) is theoretically possible from the embedded
                      btcd BlockChain; callers should handle it as an orphan.
(_,     _,     err) — block rejected; no state was changed.

Callers in network/peermgr.go use `isOrphan || isMainChain` to decide whether to request the orphan's parent; a pure side-chain block (false, false, nil) does not trigger that path.

func (*BlockChain) ScanNames

func (bc *BlockChain) ScanNames(prefix string, count int) ([]*namedb.NameRecord, error)

ScanNames scans names matching a prefix with pagination. Returns up to count names starting from the given prefix. This is used by the name_scan RPC to provide Namecoin Core compatibility.

func (*BlockChain) SetBlockAuxPowFromBytes

func (bc *BlockChain) SetBlockAuxPowFromBytes(blockHash *chainhash.Hash, serializedBlock []byte) error

SetBlockAuxPowFromBytes extracts and caches AuxPow data from a serialized block. This is called by the network layer when blocks arrive from peers.

The function: 1. Checks if the block version has the AuxPow bit set 2. If so, deserializes the entire block including AuxPow 3. Caches the AuxPow for later validation

Arguments:

  • blockHash: Hash of the block (used as cache key)
  • serializedBlock: Complete serialized block bytes including AuxPow

Returns:

  • nil if successful or if block doesn't have AuxPow
  • error if deserialization fails for a block that should have AuxPow

func (*BlockChain) ValidateMempoolTransaction

func (bc *BlockChain) ValidateMempoolTransaction(tx *wire.MsgTx) error

ValidateMempoolTransaction validates a transaction for inclusion in the mempool This performs consensus validation on name operations without requiring the transaction to be part of a block. It checks: - Basic transaction structure and format - Name operation syntax and semantics - Minimum fees for name operations - Name existence and expiration state - UTXO availability for name updates

IMPORTANT LIMITATIONS:

  1. This method does NOT validate script signatures or verify that transactions can actually spend the UTXOs they reference. Signature validation is expensive and deferred to block validation. Invalid transactions with incorrect signatures may be accepted into the mempool and relayed to peers, but will be rejected during block validation. This is an intentional trade-off between DoS resistance and validation cost.

  2. Fee validation requires that all input UTXOs are present in this node's UTXO database. If any input UTXO cannot be found, the transaction is rejected, even if it might be valid on the network. This means a node with incomplete UTXO data (e.g., still syncing or missing historical data) cannot accept transactions that depend on: - UTXOs created in blocks before the node started tracking UTXOs - Recent unconfirmed transactions in other nodes' mempools - Transactions this node has not yet seen This behavior differs from Bitcoin Core's mempool, which can validate and store chains of unconfirmed transactions.

This method is thread-safe and can be called concurrently.

func (*BlockChain) VerifyBlock

func (bc *BlockChain) VerifyBlock(block *btcutil.Block) error

VerifyBlock verifies a block

type Config

type Config struct {
	ChainParams *chaincfg.Params
	NameDBPath  string
	DataDir     string
	// BlockDBPath is the path to the block database directory.
	// If empty, blocks.db will be created in DataDir.
	BlockDBPath string
}

Config holds blockchain configuration

type MainnetTestVector

type MainnetTestVector struct {
	Description string `json:"description"` // Human-readable description
	Network     string `json:"network"`     // mainnet, testnet, or regtest
	Type        string `json:"type"`        // "block" for block vectors
	Height      int32  `json:"height"`      // Block height
	Hash        string `json:"hash"`        // Block hash (hex)
	Hex         string `json:"hex"`         // Serialized block data (hex)
	Valid       bool   `json:"valid"`       // Expected validation result
	Notes       string `json:"notes"`       // Additional context
}

MainnetTestVector represents a blockchain test case from real Namecoin mainnet data

func LoadMainnetTestVector

func LoadMainnetTestVector(path string) (*MainnetTestVector, error)

LoadMainnetTestVector loads a single mainnet test vector from a JSON file

func LoadMainnetTestVectors

func LoadMainnetTestVectors(dir, pattern string) ([]*MainnetTestVector, error)

LoadMainnetTestVectors loads all mainnet test vectors from a directory matching a glob pattern Example: LoadMainnetTestVectors("testdata/blocks", "block_*.json")

func (*MainnetTestVector) DecodeHex

func (v *MainnetTestVector) DecodeHex() ([]byte, error)

DecodeHex decodes the hex-encoded block data

func (*MainnetTestVector) IsBlock

func (v *MainnetTestVector) IsBlock() bool

IsBlock returns true if this is a block test vector

func (*MainnetTestVector) IsMainnet

func (v *MainnetTestVector) IsMainnet() bool

IsMainnet returns true if this test vector is from mainnet

func (*MainnetTestVector) IsRegtest

func (v *MainnetTestVector) IsRegtest() bool

IsRegtest returns true if this test vector is from regtest

func (*MainnetTestVector) IsTestnet

func (v *MainnetTestVector) IsTestnet() bool

IsTestnet returns true if this test vector is from testnet

func (*MainnetTestVector) String

func (v *MainnetTestVector) String() string

String returns a human-readable representation of the test vector

type MerkleBranch

type MerkleBranch struct {
	// Branch is the list of sibling hashes in the merkle path.
	// The length of this slice is the depth of the merkle tree from leaf to root.
	Branch []chainhash.Hash

	// SideMask is a bit mask indicating the position of the hash at each level.
	// Bit i corresponds to level i of the tree:
	// - 0 = sibling is on the right, we are on the left
	// - 1 = sibling is on the left, we are on the right
	// This determines whether to compute Hash(us || sibling) or Hash(sibling || us)
	SideMask uint32
}

MerkleBranch represents a merkle branch proof in the AuxPow structure. A merkle branch is a path from a leaf (transaction) to the merkle root, consisting of the sibling hashes at each level of the tree.

Per Namecoin Core src/auxpow.cpp (CAuxMerkleBranch): - Branch: List of sibling hashes in the merkle path - SideMask: Bit mask indicating whether the sibling is on the left (0) or right (1)

Example: To prove a transaction is in a block with 8 transactions: - 3 levels of tree (2^3 = 8 leaves) - Branch has 3 hashes (one sibling at each level) - SideMask has 3 bits (indicating left/right position at each level)

func DeserializeMerkleBranch

func DeserializeMerkleBranch(r io.Reader) (*MerkleBranch, error)

DeserializeMerkleBranch reads a MerkleBranch from a reader.

Wire format: 1. Branch size (varint) - number of hashes in the branch 2. Branch hashes (32 bytes each) 3. Side mask (4 bytes, little-endian uint32)

func (*MerkleBranch) SerializeMerkleBranch

func (mb *MerkleBranch) SerializeMerkleBranch(w io.Writer) error

SerializeMerkleBranch writes a MerkleBranch to a writer.

Wire format matches DeserializeMerkleBranch: 1. Branch size (varint) 2. Branch hashes (32 bytes each) 3. Side mask (4 bytes, little-endian uint32)

type NameOperationInfo

type NameOperationInfo struct {
	OpType      namedb.NameOperation // The type of name operation (NameNew, NameFirstUpdate, NameUpdate)
	Name        string               // The name being operated on (empty for NAME_NEW)
	Value       string               // The value associated with the name (empty for NAME_NEW)
	TxHash      chainhash.Hash       // The transaction hash containing this operation
	OutputIndex int                  // The output index within the transaction
}

NameOperationInfo contains parsed name operation data extracted from a transaction output. Used by RPC methods like name_pending to provide information about pending name operations in the mempool before they are confirmed in a block.

func ParseNameOperationsFromTx

func ParseNameOperationsFromTx(tx *wire.MsgTx) []NameOperationInfo

ParseNameOperationsFromTx extracts name operations from a transaction's outputs. Returns a slice of NameOperationInfo for each name operation found in the transaction. This is useful for finding pending name operations in the mempool.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL