"Elegance never goes out of style"

-- Camille, the Steel Shadow

Welcome to My Blog

By Dylan2 min read

Welcome to my personal blog where I share thoughts on technology, programming, and life.

A Place to Breathe and Reflect

A quiet desk with a laptop and notebook, symbolizing writing and reflection

This blog is my attempt to create a place where thoughts can breathe. Over the years, I have realized that ideas fade quickly if they are not captured, and experiences lose their weight if they are not reflected upon. Writing, for me, is not only a way to communicate but also a way to think—an invitation to slow down in a world that moves too fast.

Lessons from Building Software

As an engineer, I spend much of my time in the practical trenches of technology. I write code, design systems, and wrestle with the trade-offs between performance, simplicity, and scalability. Projects like Delong, and earlier ones such as Papyrus, have taught me that building software is never just about tools or frameworks—it is about clarity of vision, the courage to make decisions, and the humility to revisit them when reality proves otherwise.

Exploring Interests and Frontiers

Abstract Bitcoin & Ethereum illustration with rich colors

My interests are broad, sometimes too broad for my own good. I enjoy diving deep into web development, exploring the elegance of React and Next.js, the type safety of TypeScript, and the art of crafting user experiences that feel seamless. At the same time, I am fascinated by the frontier of blockchain and Web3. Beyond the specifics of any technology, I care about the timeless principles of software engineering: clean abstractions, resilient architectures, and the ways in which good tools empower people.

Beyond Code, Towards Life

A person walking on a long path, symbolizing journey

But this blog will not be limited to code. I believe every engineer is also a human being, and behind every technical decision lies a personal story. Sometimes I will write about the rhythm of learning, the doubts that come with tackling new fields, or the balance between work and life. Other times, I may simply record passing reflections on how technology is changing the world around us—how it reshapes communities, economies, and even our sense of meaning.

An Invitation to Connect

So, welcome. This is a place for notes, experiments, and reflections—sometimes technical, sometimes philosophical, always personal. Thank you for visiting, and I hope the time you spend here leaves you with something worth carrying into your own path.


What is BTC?

By Dylan7 min read

FLP Impossibility Theorem

The FLP Theorem (Fischer, Lynch, and Paterson impossibility theorem) is a foundational result in the field of distributed computing. It was first introduced in 1985 by Fischer, Lynch, and Paterson. The theorem, often simply referred to as the FLP impossibility, addresses the problem of reaching consensus in distributed systems, particularly under asynchronous conditions where process failures are possible.

Statement of the FLP Theorem:

The FLP theorem states that in an asynchronous distributed system, if there is even a single process that can fail (even a simple crash failure, not considering more complex failures such as Byzantine faults or network partitions), then it is impossible to guarantee that the system will always reach a consensus decision in finite time.

In other words, in an asynchronous system with the possibility of failures, no deterministic consensus algorithm can ensure both safety (agreement) and liveness (termination) at the same time.

Implications:

The theorem highlights a fundamental limitation in the design of distributed systems. It forces designers to acknowledge that strong consistency cannot be guaranteed under these assumptions. This insight is closely related to the CAP theorem (Consistency, Availability, Partition tolerance), which similarly describes the trade-offs in distributed systems.

Practical Strategies to Cope with FLP:

Although the theorem proves impossibility in the strict theoretical sense, practical systems adopt various workarounds:

  • Timeouts and failure detectors: By introducing timeouts and failure detection mechanisms, real-world systems can break the pure asynchrony assumption and reach consensus in practice.
  • Partially synchronous systems: Many consensus protocols assume that the system behaves asynchronously most of the time, but eventually becomes synchronous, allowing them to guarantee progress.
  • Consensus algorithms: Protocols like Paxos, Raft, and PBFT (Practical Byzantine Fault Tolerance) are widely used to provide practical consensus guarantees despite theoretical impossibility.

The FLP impossibility reminds us that distributed consensus is always a balance between theoretical limitations and practical engineering trade-offs.


Consensus in Bitcoin (BTC)

In a peer-to-peer blockchain network, every participant node maintains a copy of the blockchain (either the full chain or a subset). This introduces the classic problem of consistency in distributed systems: ensuring that all nodes agree on the state of the ledger, i.e., which transactions are valid and in what order they are recorded. This is where the consensus mechanism plays a critical role.

Goals of Consensus in Blockchain:

  1. Consistency: All honest nodes must agree on the current valid blockchain state.
  2. Fault tolerance: The system should remain correct even if some nodes fail or act maliciously.
  3. Decentralization: The mechanism must avoid reliance on a single authority and eliminate single points of failure.

Common Consensus Mechanisms:

  • Proof of Work (PoW): Miners solve computationally difficult puzzles to propose new blocks. Bitcoin uses PoW to achieve consensus.
  • Proof of Stake (PoS): Validators are chosen to create new blocks based on their stake (holdings).
  • Delegated Proof of Stake (DPoS): Token holders vote for a limited set of validators who produce blocks.
  • Byzantine Fault Tolerant (BFT) protocols: Algorithms designed to tolerate arbitrary (Byzantine) failures, such as PBFT.

Unlike human consensus, which involves reasoning, discussion, and voting, blockchain consensus is purely about achieving data consistency among distributed nodes. The "consensus" is not about whose opinion is correct but rather about agreeing on a single version of the blockchain so that the network can continue to operate.

In Bitcoin, this is possible because transactions are objectively verifiable—everyone can independently check whether a transaction is valid. Thus, consensus boils down to selecting one valid chain as the canonical history, using a mechanism (like PoW + the longest chain rule) that guarantees uniqueness.


Merkle Tree

A Merkle tree (or hash tree), introduced by Ralph Merkle in the 1980s, is a cryptographic data structure used to efficiently and securely verify large sets of data.

Structure and Operation:

  • Each leaf node contains the hash of a data block (e.g., a transaction).
  • Each internal node contains the hash of its two child nodes.
  • The process continues up to the Merkle root, which is a single hash summarizing the entire dataset.

Key Properties:

  • Integrity verification: Any change in the dataset changes the Merkle root.
  • Efficient proofs: A Merkle proof allows verifying whether a transaction is included in a block by only checking a logarithmic number of hashes.
  • Parallelization: Hashing can be computed in parallel for efficiency.

In Blockchains:

Bitcoin includes the Merkle root in the block header. This allows lightweight nodes (SPV clients) to verify the inclusion of a transaction without needing the full block.


Longest Valid Chain Rule

In Bitcoin, consensus is governed by the longest valid chain (more precisely, the chain with the most accumulated proof-of-work). When forks occur, nodes adopt the chain that has the highest cumulative difficulty, ensuring that the network converges on a single canonical chain.


Forking Attack

A forking attack occurs when an attacker intentionally creates a competing chain fork. The attacker may attempt to double-spend coins by privately mining an alternative chain and later releasing it to overtake the honest chain. This is particularly relevant in the case of 51% attacks, where the attacker controls the majority of the mining power.


Orphan Block

An orphan block is a valid block that was mined but not included in the main chain. Orphan blocks occur when two miners produce blocks at nearly the same time. Eventually, the longest chain rule resolves the fork, and one block becomes part of the canonical chain, while the other is discarded.

  • Transactions inside orphan blocks are usually not lost—they are reintroduced into the mempool and included in later blocks.
  • Mining rewards for orphan blocks are invalidated (except in Ethereum’s "uncle blocks," which provide partial rewards).

Coinbase Transaction

The coinbase transaction is the first transaction in each block, created by the miner. It introduces new coins into circulation and includes the block reward plus collected transaction fees.

Features:

  • Has no inputs—it creates new coins from nothing.
  • Contains miner-specific data such as pool identifiers or arbitrary messages (famously, Satoshi included "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks").
  • Rewards must undergo a maturity period (100 blocks in Bitcoin) before being spendable.

This mechanism is the sole method by which new bitcoins are minted.


Sybil Attack

A Sybil attack occurs when an adversary creates a large number of fake identities or nodes in a peer-to-peer network to gain disproportionate influence.

Defense mechanisms include:

  • Proof of Work (PoW): Makes identity creation costly in terms of computational resources.
  • Proof of Stake (PoS): Ties influence to scarce resources (tokens).
  • Identity validation: Some systems rely on trusted authorities or reputation systems to mitigate Sybil attacks.

UTXO (Unspent Transaction Output)

The UTXO model is Bitcoin’s ledger structure. Instead of accounts with balances, Bitcoin tracks ownership through discrete "coins" represented as unspent transaction outputs.

How it works:

  1. Each transaction consumes existing UTXOs as inputs.
  2. It produces new UTXOs as outputs, which can later be spent.
  3. Once a UTXO is consumed, it is removed from the UTXO set and cannot be spent again (preventing double-spending).

Properties:

  • Stateless validation: Each UTXO contains all information needed to verify its validity.
  • Parallelism: Independent transactions can be verified concurrently.
  • Privacy: Users can generate unlimited addresses, reducing traceability.

UTXO Database Fields:

  • Transaction ID (TXID): Hash of the transaction that created the UTXO.
  • Output index: Identifies which output of the transaction is unspent.
  • Value: Amount of bitcoin represented.
  • Locking script (ScriptPubKey): Defines spending conditions, usually requiring a digital signature.

Bitcoin full nodes maintain the UTXO set in optimized data structures (e.g., LevelDB with hash tables and trees) for fast verification. When new blocks are added, nodes update the UTXO set by removing spent outputs and adding newly created ones.

The UTXO model is central to Bitcoin’s scalability, security, and resistance to double-spending.


Building a Modern Blog with Next.js and Markdown

By Dylan3 min read

Building a modern blog doesn't have to be complicated. In this tutorial, I'll walk you through creating a fast, SEO-friendly blog using Next.js 15 and Markdown files.

Why This Tech Stack?

Next.js 15 with App Router

Next.js provides an excellent foundation for blogs:

  • Server-side rendering for better SEO
  • Static generation for blazing-fast performance
  • App Router for intuitive routing and layouts
  • Built-in optimization for images and fonts

Markdown for Content

Using Markdown files offers several advantages:

  • Version control friendly - Track changes with Git
  • Portable - Easy to migrate to any platform
  • Developer-friendly - Write in your favorite editor
  • No database needed - Simplifies deployment

Project Structure

Here's the recommended structure for a Next.js blog:

my-blog/
├── app/
│   ├── layout.tsx         # Global layout
│   ├── page.tsx           # Homepage
│   └── blog/
│       └── [slug]/
│           └── page.tsx   # Dynamic blog post page
├── content/
│   └── blog/
│       └── *.md           # Your Markdown posts
├── components/
│   ├── PostCard.tsx       # Blog post card component
│   └── MarkdownRenderer.tsx
└── lib/
    └── markdown.ts        # Markdown parsing utilities

Key Implementation Details

1. Parsing Markdown with gray-matter

The gray-matter library helps parse frontmatter metadata:

import matter from 'gray-matter';

const { data, content } = matter(fileContents);
// data contains frontmatter
// content contains the markdown body

2. Converting Markdown to HTML

Use remark for Markdown processing:

import { remark } from 'remark';
import html from 'remark-html';

const processedContent = await remark()
  .use(html)
  .process(content);

3. Dynamic Routes with generateStaticParams

Pre-render all blog posts at build time:

export async function generateStaticParams() {
  const posts = await getAllPosts();
  return posts.map((post) => ({
    slug: post.slug,
  }));
}

Performance Optimizations

Image Optimization

Always use Next.js Image component:

import Image from 'next/image';

<Image
  src="/hero.jpg"
  alt="Hero image"
  width={800}
  height={400}
  priority
/>

Metadata for SEO

Implement dynamic metadata for each post:

export async function generateMetadata({ params }) {
  const post = await getPostBySlug(params.slug);
  return {
    title: post.metadata.title,
    description: post.metadata.description,
    openGraph: {
      title: post.metadata.title,
      description: post.metadata.description,
      type: 'article',
    },
  };
}

Styling with TailwindCSS

TailwindCSS v4 provides excellent typography support:

<article className="prose prose-lg mx-auto">
  <div dangerouslySetInnerHTML={{ __html: post.content }} />
</article>

Deployment with Vercel

Deployment is straightforward:

  1. Push your code to GitHub
  2. Connect your repository to Vercel
  3. Deploy with one click
  4. Automatic deployments on every push

Best Practices

  1. Keep posts organized: Use consistent naming (kebab-case)
  2. Optimize images: Use WebP format when possible
  3. Add reading time: Calculate based on word count
  4. Implement search: Use client-side search with Fuse.js
  5. Add RSS feed: Help readers subscribe to your content

Conclusion

Building a blog with Next.js and Markdown provides the perfect balance of simplicity and power. You get excellent performance, SEO benefits, and a great developer experience without the complexity of a traditional CMS.

The best part? Your content lives in version control, making it portable and future-proof.

Happy blogging! 🚀