<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://cjrequena.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://cjrequena.github.io/" rel="alternate" type="text/html" /><updated>2026-09-02T00:05:38+00:00</updated><id>https://cjrequena.github.io/feed.xml</id><title type="html">Carlos Requena</title><subtitle>Carlos Requena. Writing about coding, maths, distributed systems, performance optimisation, blockchain.</subtitle><author><name>Carlos Requena</name><email>carlosjose.requena@gmail.com</email></author><entry xml:lang="en"><title type="html">[BITCOIN] BIP39 Seed Phrase Generation from Physical Randomness</title><link href="https://cjrequena.github.io/2026-08-03/bip39-seed-phrase-generation-from-physical-randomness-en" rel="alternate" type="text/html" title="[BITCOIN] BIP39 Seed Phrase Generation from Physical Randomness" /><published>2026-08-03T00:00:00+00:00</published><updated>2026-08-03T00:00:00+00:00</updated><id>https://cjrequena.github.io/2026-08-03/bip39-seed-phrase-generation-from-physical-randomness-en</id><content type="html" xml:base="https://cjrequena.github.io/2026-08-03/bip39-seed-phrase-generation-from-physical-randomness-en"><![CDATA[<div style="text-align:center">
    <span style="color:red;font-weight: bold">"It isn't the events themselves that disturb people, but only their judgements about them."</span> 
    <span style="color:black;font-weight: bold">--Epictetus</span>
</div>
<p><br /></p>

<blockquote>
  <p><strong>A Technical Reference Guide to Coin Flips and Dice Rolls</strong></p>
</blockquote>

<hr />

<h2 id="index">Index</h2>

<table>
  <thead>
    <tr>
      <th>#</th>
      <th>Section</th>
      <th>What it covers</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>1</td>
      <td><a href="#overview">Overview</a></td>
      <td>The entropy → checksum → words pipeline, and why you might not want to trust a device’s RNG.</td>
    </tr>
    <tr>
      <td>2</td>
      <td><a href="#entropy-sizes">BIP39 Entropy Sizes</a></td>
      <td>Word counts, entropy lengths, checksum lengths, and total bits.</td>
    </tr>
    <tr>
      <td>3</td>
      <td><a href="#word-list">The BIP39 Word List</a></td>
      <td>Why 2048 words means exactly 11 bits per word, and why the language matters.</td>
    </tr>
    <tr>
      <td>4</td>
      <td><a href="#method-coin">Method 1 — Generating Entropy with a Coin</a></td>
      <td>Heads/tails as raw bits, how many flips you need, and what to do about a biased coin.</td>
    </tr>
    <tr>
      <td>5</td>
      <td><a href="#coin-conversion">Coin Flip Conversion Process</a></td>
      <td>Step by step: record, verify, checksum, append, split, map to words — with an offline script.</td>
    </tr>
    <tr>
      <td>6</td>
      <td><a href="#method-dice">Method 2 — Generating Entropy with Dice</a></td>
      <td>~2.585 bits per D6 roll, roll counts, and base-6 recording.</td>
    </tr>
    <tr>
      <td>7</td>
      <td><a href="#dice-to-entropy">Converting Dice Rolls to Entropy</a></td>
      <td>Base-6 conversion versus the recommended SHA-256 of the rolls.</td>
    </tr>
    <tr>
      <td>8</td>
      <td><a href="#dice-bias">Warning: Why Naïve Dice Encoding Is Biased</a></td>
      <td>Why a 3-bit-per-face mapping skews the bit distribution.</td>
    </tr>
    <tr>
      <td>9</td>
      <td><a href="#method-d8-d16">Method 3 — D8 / D16 / D16 Dice</a></td>
      <td>Three throws = 11 bits = one word, the index formula, and the checksum-bearing final word.</td>
    </tr>
    <tr>
      <td>10</td>
      <td><a href="#pipeline">Complete BIP39 Pipeline</a></td>
      <td>End-to-end diagrams for all three methods.</td>
    </tr>
    <tr>
      <td>11</td>
      <td><a href="#security-comparison">Security Comparison</a></td>
      <td>Coin vs D6 vs D8/D16/D16 across entropy, bias, effort, and error risk.</td>
    </tr>
    <tr>
      <td>12</td>
      <td><a href="#mnemonic-to-seed">From Mnemonic to Wallet Seed</a></td>
      <td>What BIP39 does after the words: PBKDF2, the optional passphrase, and the 512-bit seed.</td>
    </tr>
    <tr>
      <td>13</td>
      <td><a href="#checksum-role">The Role of the Checksum</a></td>
      <td>What the checksum does — and what it does not protect.</td>
    </tr>
    <tr>
      <td>14</td>
      <td><a href="#verification">Verify Before You Fund the Wallet</a></td>
      <td>Restore-testing the backup against a second implementation.</td>
    </tr>
    <tr>
      <td>15</td>
      <td><a href="#best-practices">Best Practices</a></td>
      <td>Fair physical sources, staying offline, and never reusing entropy.</td>
    </tr>
    <tr>
      <td>16</td>
      <td><a href="#summary">Summary</a></td>
      <td>The whole process condensed, and how the three methods compare.</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="overview">1. Overview</h2>

<p>A <strong>BIP39 mnemonic phrase</strong> (commonly called a <em>seed phrase</em>) is a human-readable representation of cryptographic entropy. Instead of memorizing 256 random bits, you memorize a short list of ordinary words that encode exactly those bits.</p>

<p>The pipeline that turns physical randomness into a mnemonic is:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Physical randomness
        ↓
Binary entropy
        ↓
Checksum (SHA-256)
        ↓
Entropy + checksum
        ↓
Split into 11-bit groups
        ↓
BIP39 word lookup
        ↓
Mnemonic phrase
</code></pre></div></div>

<p>The physical randomness can come from:</p>

<ul>
  <li><strong>Coin flips</strong></li>
  <li><strong>Dice rolls</strong></li>
  <li><strong>Hardware random number generators</strong></li>
</ul>

<p>The single most important requirement is:</p>

<blockquote>
  <p>The initial entropy must be <strong>unpredictable</strong> and <strong>unbiased</strong>.</p>
</blockquote>

<p>Everything else in this guide is bookkeeping. If the entropy is weak, no amount of correct encoding will save the wallet.</p>

<h3 id="why-bother-with-coins-and-dice-at-all">Why bother with coins and dice at all?</h3>

<p>A hardware wallet’s built-in RNG is almost certainly fine. The reason to do this by hand is that “almost certainly” is a claim you cannot verify: a compromised or subtly broken generator produces output that looks perfectly random to you while being entirely predictable to whoever broke it. This has happened in the field more than once.</p>

<p>Physical randomness moves the trust from the device to a process you can watch. It does not make the wallet <em>more</em> random — 256 bits is 256 bits — it makes the randomness <strong>auditable by you</strong>.</p>

<hr />

<h2 id="entropy-sizes">2. BIP39 Entropy Sizes</h2>

<p>BIP39 defines a fixed set of entropy sizes. The entropy must be a multiple of 32 bits, between 128 and 256 bits, and each size pairs with a checksum whose length is <code class="language-plaintext highlighter-rouge">entropy_bits / 32</code>.</p>

<table>
  <thead>
    <tr>
      <th>Words</th>
      <th>Entropy (ENT)</th>
      <th>Checksum (CS)</th>
      <th>Total Bits</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>12</td>
      <td>128 bits</td>
      <td>4 bits</td>
      <td>132 bits</td>
    </tr>
    <tr>
      <td>15</td>
      <td>160 bits</td>
      <td>5 bits</td>
      <td>165 bits</td>
    </tr>
    <tr>
      <td>18</td>
      <td>192 bits</td>
      <td>6 bits</td>
      <td>198 bits</td>
    </tr>
    <tr>
      <td>21</td>
      <td>224 bits</td>
      <td>7 bits</td>
      <td>231 bits</td>
    </tr>
    <tr>
      <td>24</td>
      <td>256 bits</td>
      <td>8 bits</td>
      <td>264 bits</td>
    </tr>
  </tbody>
</table>

<p>The checksum length follows directly from the entropy length:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>checksum_bits = entropy_bits / 32
</code></pre></div></div>

<p>For example, <code class="language-plaintext highlighter-rouge">128 / 32 = 4</code> and <code class="language-plaintext highlighter-rouge">256 / 32 = 8</code>.</p>

<blockquote>
  <p><strong>12 or 24 words?</strong> 128 bits is already far beyond brute force, and no realistic advance changes that. 24 words buys margin against implementation mistakes and partial backup loss, not against an attacker with a bigger computer. Both are fine; 24 costs you roughly twice the physical work described below.</p>
</blockquote>

<hr />

<h2 id="word-list">3. The BIP39 Word List</h2>

<p>The BIP39 English dictionary contains exactly <strong>2048 words</strong>, and that number is not arbitrary:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>2048 = 2^11
</code></pre></div></div>

<p>Because there are <code class="language-plaintext highlighter-rouge">2^11</code> words, each word encodes exactly <strong>11 bits</strong>. That is why the total bit count always divides evenly by 11:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">132 bits / 11 = 12 words</code></li>
  <li><code class="language-plaintext highlighter-rouge">264 bits / 11 = 24 words</code></li>
</ul>

<p>Two properties of the list are worth knowing before you start writing words down:</p>

<ul>
  <li><strong>The first four letters are unique.</strong> No two words in the English list share their first four letters, so <code class="language-plaintext highlighter-rouge">abandon</code> can be recorded as <code class="language-plaintext highlighter-rouge">aban</code> without ambiguity. Hardware wallets rely on this when they let you type only four characters.</li>
  <li><strong>The language is part of the encoding.</strong> The same index means a different word in the Spanish, French, or Japanese list. A phrase is only recoverable if you know which word list produced it, so unless you have a reason otherwise, use English — it is what every wallet supports.</li>
</ul>

<p>Use the official list from the BIP39 specification. A “similar” list found elsewhere will silently produce a different wallet.</p>

<hr />

<h2 id="method-coin">4. Method 1 — Generating Entropy with a Coin</h2>

<h3 id="41-why-a-coin-works">4.1 Why a Coin Works</h3>

<p>A fair coin has two equally likely outcomes, which maps perfectly onto a single binary digit:</p>

<table>
  <thead>
    <tr>
      <th>Outcome</th>
      <th>Bit</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Heads</td>
      <td><code class="language-plaintext highlighter-rouge">1</code></td>
    </tr>
    <tr>
      <td>Tails</td>
      <td><code class="language-plaintext highlighter-rouge">0</code></td>
    </tr>
  </tbody>
</table>

<p>Each flip therefore provides exactly <strong>1 bit of entropy</strong> — clean, unbiased, and with no conversion math required. This directness is what makes the coin the easiest source to reason about.</p>

<h3 id="42-how-many-flips-you-need">4.2 How Many Flips You Need</h3>

<p>Since each flip is one bit, the number of flips equals the entropy size:</p>

<table>
  <thead>
    <tr>
      <th>Seed length</th>
      <th>Entropy</th>
      <th>Coin flips</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>12 words</td>
      <td>128 bits</td>
      <td>128 flips</td>
    </tr>
    <tr>
      <td>24 words</td>
      <td>256 bits</td>
      <td>256 flips</td>
    </tr>
  </tbody>
</table>

<p>A sequence such as <code class="language-plaintext highlighter-rouge">H T H H T T H T ...</code> becomes the binary string <code class="language-plaintext highlighter-rouge">1 0 1 1 0 0 1 0 ...</code>.</p>

<h3 id="43-if-you-do-not-trust-your-coin">4.3 If You Do Not Trust Your Coin</h3>

<p>Real coins are not perfectly fair. A flipped coin caught in the hand lands the <strong>same side up</strong> it started roughly 50.8% of the time — a physical wobble effect predicted by Diaconis and later confirmed over 350,757 recorded flips. Spinning a coin on a table is far worse, and can be biased by several percent.</p>

<p>A 50.8% bias costs you almost nothing — across all 256 flips it removes less than a <strong>twentieth of one bit</strong> (256 × H(0.508) ≈ 255.95). Two habits shrink it further at no cost: flip properly and let the coin land on the floor rather than catching it, and vary which face starts upward, since the effect is a <em>same-side</em> bias rather than a heads bias. If you would rather not rely on any of that, two fixes remove the bias entirely:</p>

<p><strong>Von Neumann extraction.</strong> Flip in <em>pairs</em> and discard the ties:</p>

<table>
  <thead>
    <tr>
      <th>Pair</th>
      <th>Output</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Heads-Tails</td>
      <td><code class="language-plaintext highlighter-rouge">1</code></td>
    </tr>
    <tr>
      <td>Tails-Heads</td>
      <td><code class="language-plaintext highlighter-rouge">0</code></td>
    </tr>
    <tr>
      <td>Heads-Heads</td>
      <td>discard</td>
    </tr>
    <tr>
      <td>Tails-Tails</td>
      <td>discard</td>
    </tr>
  </tbody>
</table>

<p>Because <code class="language-plaintext highlighter-rouge">HT</code> and <code class="language-plaintext highlighter-rouge">TH</code> have identical probability for <em>any</em> fixed bias, the output bits are perfectly uniform. The cost is throughput: at best you keep one bit per four flips, so a 24-word seed needs around <strong>1024 flips</strong> on average. Correct, and tedious.</p>

<p><strong>Hash the flips.</strong> Record all 256 flips as a string and run it through SHA-256, exactly as the dice method does in <a href="#dice-to-entropy">§7.2</a>. This removes bias without discarding anything, and it is what most tooling does in practice.</p>

<p>Either way, the rule is the same: <strong>do not correct a suspected bias by hand</strong>. Adjusting your own results reintroduces exactly the human non-randomness you were trying to avoid.</p>

<hr />

<h2 id="coin-conversion">5. Coin Flip Conversion Process</h2>

<h3 id="step-1--record-the-flips">Step 1 — Record the flips</h3>

<p>Using <code class="language-plaintext highlighter-rouge">Heads = 1</code> and <code class="language-plaintext highlighter-rouge">Tails = 0</code>, write down every flip in order:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>1011010011011001...
</code></pre></div></div>

<p>This binary sequence <strong>is</strong> your entropy.</p>

<h3 id="step-2--verify-the-length">Step 2 — Verify the length</h3>

<p>Count the bits and confirm they match the target exactly — <code class="language-plaintext highlighter-rouge">128</code> bits for a 12-word mnemonic, <code class="language-plaintext highlighter-rouge">256</code> bits for a 24-word mnemonic. Do not pad, trim, or “round off” the sequence.</p>

<p>Writing the bits in groups of eight makes the count checkable at a glance: 16 groups for 128 bits, 32 groups for 256 bits.</p>

<h3 id="step-3--calculate-the-checksum">Step 3 — Calculate the checksum</h3>

<p>Compute the SHA-256 hash of the raw entropy <strong>bytes</strong> (not the text of the bit string):</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>checksum = first (entropy_bits / 32) bits of SHA-256(entropy)
</code></pre></div></div>

<ul>
  <li>128-bit entropy → take the <strong>first 4 bits</strong> of the hash.</li>
  <li>256-bit entropy → take the <strong>first 8 bits</strong> of the hash.</li>
</ul>

<p>This is the one step you cannot do in your head. Hashing <code class="language-plaintext highlighter-rouge">"1011..."</code> as ASCII text instead of as bytes is the single most common mistake here, and it produces a phrase that is valid-looking but wrong.</p>

<h3 id="step-4--append-the-checksum">Step 4 — Append the checksum</h3>

<p>Concatenate the checksum bits onto the end of the entropy:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Entropy   : 1011010011011001…   (128 or 256 bits)
Checksum  : 0110                 (4 or 8 bits)
Combined  : 1011010011011001…0110
</code></pre></div></div>

<p>The result is <code class="language-plaintext highlighter-rouge">132</code> bits (12 words) or <code class="language-plaintext highlighter-rouge">264</code> bits (24 words). <em>(The short strings above are illustrative — real entropy is 128 or 256 bits long.)</em></p>

<h3 id="step-5--split-into-11-bit-groups">Step 5 — Split into 11-bit groups</h3>

<p>Chop the combined sequence into groups of 11 bits:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>10110100110  →  group 1
11001010101  →  group 2
...
</code></pre></div></div>

<p>Each 11-bit group is a number in the range <code class="language-plaintext highlighter-rouge">0</code> (<code class="language-plaintext highlighter-rouge">00000000000</code>) to <code class="language-plaintext highlighter-rouge">2047</code> (<code class="language-plaintext highlighter-rouge">11111111111</code>).</p>

<h3 id="step-6--map-numbers-to-words">Step 6 — Map numbers to words</h3>

<p>Each number indexes into the BIP39 word list:</p>

<ul>
  <li>Index <code class="language-plaintext highlighter-rouge">0</code> → the <strong>first</strong> word (<code class="language-plaintext highlighter-rouge">abandon</code>)</li>
  <li>Index <code class="language-plaintext highlighter-rouge">2047</code> → the <strong>last</strong> word (<code class="language-plaintext highlighter-rouge">zoo</code>)</li>
</ul>

<p>Read the words out in order and you have your mnemonic.</p>

<h3 id="doing-steps-36-offline">Doing steps 3–6 offline</h3>

<p>Steps 3 through 6 are mechanical, and doing them by hand is error-prone. On an <strong>air-gapped machine you will wipe afterwards</strong>, the whole conversion is a few lines:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">hashlib</span>

<span class="n">bits</span> <span class="o">=</span> <span class="s">"1011010011011001..."</span>          <span class="c1"># your recorded flips, 128 or 256 of them
</span><span class="k">assert</span> <span class="nb">len</span><span class="p">(</span><span class="n">bits</span><span class="p">)</span> <span class="ow">in</span> <span class="p">(</span><span class="mi">128</span><span class="p">,</span> <span class="mi">160</span><span class="p">,</span> <span class="mi">192</span><span class="p">,</span> <span class="mi">224</span><span class="p">,</span> <span class="mi">256</span><span class="p">)</span>

<span class="n">entropy</span>  <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">bits</span><span class="p">,</span> <span class="mi">2</span><span class="p">).</span><span class="n">to_bytes</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">bits</span><span class="p">)</span> <span class="o">//</span> <span class="mi">8</span><span class="p">,</span> <span class="s">"big"</span><span class="p">)</span>
<span class="n">digest</span>   <span class="o">=</span> <span class="n">hashlib</span><span class="p">.</span><span class="n">sha256</span><span class="p">(</span><span class="n">entropy</span><span class="p">).</span><span class="n">digest</span><span class="p">()</span>
<span class="n">checksum</span> <span class="o">=</span> <span class="nb">format</span><span class="p">(</span><span class="nb">int</span><span class="p">.</span><span class="n">from_bytes</span><span class="p">(</span><span class="n">digest</span><span class="p">,</span> <span class="s">"big"</span><span class="p">),</span> <span class="s">"0256b"</span><span class="p">)[:</span> <span class="nb">len</span><span class="p">(</span><span class="n">bits</span><span class="p">)</span> <span class="o">//</span> <span class="mi">32</span><span class="p">]</span>
<span class="n">combined</span> <span class="o">=</span> <span class="n">bits</span> <span class="o">+</span> <span class="n">checksum</span>

<span class="n">indices</span> <span class="o">=</span> <span class="p">[</span><span class="nb">int</span><span class="p">(</span><span class="n">combined</span><span class="p">[</span><span class="n">i</span><span class="p">:</span><span class="n">i</span> <span class="o">+</span> <span class="mi">11</span><span class="p">],</span> <span class="mi">2</span><span class="p">)</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">combined</span><span class="p">),</span> <span class="mi">11</span><span class="p">)]</span>
<span class="k">print</span><span class="p">(</span><span class="n">indices</span><span class="p">)</span>                        <span class="c1"># look these up in the BIP39 English word list
</span></code></pre></div></div>

<p>Never run this — or any BIP39 tool — on a machine that is online, and never paste your bits into a website, however reputable it looks.</p>

<hr />

<h2 id="method-dice">6. Method 2 — Generating Entropy with Dice</h2>

<h3 id="61-dice-entropy">6.1 Dice Entropy</h3>

<p>A six-sided die has 6 equally likely outcomes, so each roll provides:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>log2(6) ≈ 2.585 bits
</code></pre></div></div>

<p>That is more than double a coin flip, so you need far fewer physical actions. Round <strong>up</strong>, so that the rolls are guaranteed to carry at least the required number of bits:</p>

<table>
  <thead>
    <tr>
      <th>Seed length</th>
      <th>Entropy</th>
      <th>Dice rolls (min)</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>12 words</td>
      <td>128 bits</td>
      <td>~50 rolls</td>
    </tr>
    <tr>
      <td>24 words</td>
      <td>256 bits</td>
      <td>~100 rolls</td>
    </tr>
  </tbody>
</table>

<p>(<code class="language-plaintext highlighter-rouge">128 / 2.585 ≈ 49.5 → 50</code>, and <code class="language-plaintext highlighter-rouge">256 / 2.585 ≈ 99.0 → 100</code>.)</p>

<p>Checking it the other way round confirms the margin: 50 rolls produce <code class="language-plaintext highlighter-rouge">6⁵⁰ ≈ 2¹²⁹</code> equally likely sequences, and 100 rolls produce <code class="language-plaintext highlighter-rouge">6¹⁰⁰ ≈ 2²⁵⁸·⁵</code> — comfortably above 128 and 256 bits respectively.</p>

<h3 id="62-recording-the-rolls">6.2 Recording the Rolls</h3>

<p>Map each face to a base-6 digit (<code class="language-plaintext highlighter-rouge">0</code>–<code class="language-plaintext highlighter-rouge">5</code>) so the results can be treated as one large number:</p>

<table>
  <thead>
    <tr>
      <th>Die face</th>
      <th>Base-6 digit</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>1</td>
      <td><code class="language-plaintext highlighter-rouge">0</code></td>
    </tr>
    <tr>
      <td>2</td>
      <td><code class="language-plaintext highlighter-rouge">1</code></td>
    </tr>
    <tr>
      <td>3</td>
      <td><code class="language-plaintext highlighter-rouge">2</code></td>
    </tr>
    <tr>
      <td>4</td>
      <td><code class="language-plaintext highlighter-rouge">3</code></td>
    </tr>
    <tr>
      <td>5</td>
      <td><code class="language-plaintext highlighter-rouge">4</code></td>
    </tr>
    <tr>
      <td>6</td>
      <td><code class="language-plaintext highlighter-rouge">5</code></td>
    </tr>
  </tbody>
</table>

<p>A roll sequence of <code class="language-plaintext highlighter-rouge">3 6 2 1 5 4</code> becomes the digits <code class="language-plaintext highlighter-rouge">2 5 1 0 4 3</code>, i.e. the base-6 number <code class="language-plaintext highlighter-rouge">251043₆</code>.</p>

<hr />

<h2 id="dice-to-entropy">7. Converting Dice Rolls to Entropy</h2>

<p>There are two practical approaches. The second is what most hardware wallets actually use.</p>

<h3 id="71-base-6-conversion-conceptual">7.1 Base-6 Conversion (conceptual)</h3>

<p>Interpret the whole roll sequence as one large base-6 number and convert it to binary. For the small example <code class="language-plaintext highlighter-rouge">251043₆</code>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>2×6⁵ + 5×6⁴ + 1×6³ + 0×6² + 4×6¹ + 3
  = 15552 + 6480 + 216 + 0 + 24 + 3
  = 22275  (decimal)
  = 101011100000011  (binary)
</code></pre></div></div>

<p>This illustrates the idea, but naïvely truncating a base-6 number to a fixed bit length can introduce <strong>slight bias</strong>, because <code class="language-plaintext highlighter-rouge">6ⁿ</code> is never a power of two.</p>

<h3 id="72-sha-256-of-the-rolls-recommended">7.2 SHA-256 of the Rolls (recommended)</h3>

<p>The clean, unbiased, and widely used method is to <strong>hash the recorded rolls</strong>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>entropy = SHA-256("digits from every roll, concatenated")
</code></pre></div></div>

<p>Roll ~50 or ~100 times, write the digits as a single string, hash it with SHA-256, and use the resulting bits as your entropy. Because SHA-256 output is computationally indistinguishable from uniform, this sidesteps base-conversion bias entirely. This is the approach used by tools such as Coldcard and SeedSigner.</p>

<p>Two details matter:</p>

<ul>
  <li><strong>For a 12-word seed, take the first 128 bits</strong> of the 256-bit digest. For 24 words, use all 256 bits.</li>
  <li><strong>Hashing does not create entropy.</strong> SHA-256 always emits 256 bits, but those bits carry only as much randomness as went in. Fifty D6 rolls hashed into a 24-word phrase gives you a 24-word phrase with roughly <strong>129 bits</strong> of real security, not 256. If you want 256 bits, you must roll ~100 times. The output looks identical either way, which is what makes this mistake dangerous.</li>
</ul>

<hr />

<h2 id="dice-bias">8. Warning: Why Naïve Dice Encoding Is Biased</h2>

<p>A die has six states, and six is <strong>not</strong> a power of two:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>6 = 2 × 3     →     6 ≠ 2ⁿ
</code></pre></div></div>

<p>This means you <strong>cannot</strong> just assign each face a 3-bit pattern:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>1 = 000   2 = 001   3 = 010
4 = 011   5 = 100   6 = 101
</code></pre></div></div>

<p>Three bits can represent 8 values, but a die only produces 6. The patterns <code class="language-plaintext highlighter-rouge">110</code> and <code class="language-plaintext highlighter-rouge">111</code> never appear, so this mapping <strong>wastes states and skews the bit distribution</strong>: four of the six faces begin with <code class="language-plaintext highlighter-rouge">0</code>, so the leading bit is <code class="language-plaintext highlighter-rouge">0</code> two-thirds of the time instead of half. Across a whole seed that is a large, systematic loss — an attacker who knows you used this mapping searches a much smaller space than the word count suggests.</p>

<p>Use an unbiased method instead:</p>

<ul>
  <li><strong>SHA-256 of the rolls</strong> (recommended)</li>
  <li><strong>Base-6 → binary conversion</strong> done carefully</li>
  <li><strong>Rejection sampling</strong> — read two rolls as a number <code class="language-plaintext highlighter-rouge">0–35</code>, discard <code class="language-plaintext highlighter-rouge">32–35</code>, and keep the remaining 32 outcomes as a clean 5 bits</li>
  <li><strong>Dice whose face count <em>is</em> a power of two</strong> — a D8 gives a clean 3 bits and a D16 a clean 4 bits, which is exactly what Method 3 below exploits</li>
</ul>

<hr />

<h2 id="method-d8-d16">9. Method 3 — D8 / D16 / D16 Dice (Direct Word Indexing)</h2>

<h3 id="91-why-this-combination-works">9.1 Why This Combination Works</h3>

<p>The whole problem with a D6 is that <code class="language-plaintext highlighter-rouge">6</code> is not a power of two. That problem disappears entirely when every die <strong>is</strong> a power of two:</p>

<table>
  <thead>
    <tr>
      <th>Die</th>
      <th>Faces</th>
      <th>Bits per roll</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>D8</td>
      <td><code class="language-plaintext highlighter-rouge">8 = 2³</code></td>
      <td>3 bits</td>
    </tr>
    <tr>
      <td>D16</td>
      <td><code class="language-plaintext highlighter-rouge">16 = 2⁴</code></td>
      <td>4 bits</td>
    </tr>
  </tbody>
</table>

<p>And:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>3 + 4 + 4 = 11 bits  →  exactly one BIP39 word
</code></pre></div></div>

<p>So <strong>one D8 and two D16 dice, rolled together, select one word directly</strong>. No base conversion, no SHA-256 over the rolls, no rejection sampling, no wasted states. Every outcome maps to exactly one of the 2048 words, and every word is equally likely.</p>

<p>This is the method documented by Blockstream for generating a recovery phrase offline:
<a href="https://help.blockstream.com/generate-recovery-phrase-offline-d8-d16-d16">https://help.blockstream.com/generate-recovery-phrase-offline-d8-d16-d16</a></p>

<h3 id="92-the-dice">9.2 The Dice</h3>

<p>Label the three dice and <strong>always read them in the same order</strong>:</p>

<table>
  <thead>
    <tr>
      <th>Position</th>
      <th>Die</th>
      <th>Range</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>First</td>
      <td>D8</td>
      <td>1–8</td>
    </tr>
    <tr>
      <td>Second</td>
      <td>D16</td>
      <td>1–16</td>
    </tr>
    <tr>
      <td>Third</td>
      <td>D16</td>
      <td>1–16</td>
    </tr>
  </tbody>
</table>

<p>Use three visually distinct dice (different colours) so you can throw all three at once and still read them unambiguously. Order matters — swapping <em>Second</em> and <em>Third</em> gives a different word.</p>

<h3 id="93-the-index-formula">9.3 The Index Formula</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>index = (First − 1) × 2⁸  +  (Second − 1) × 2⁴  +  (Third − 1)
      = (First − 1) × 256 +  (Second − 1) × 16  +  (Third − 1)
</code></pre></div></div>

<p>The range is exactly right, with nothing left over:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>minimum:  (1,1,1)     →  0×256 + 0×16 + 0   =    0    (abandon)
maximum:  (8,16,16)   →  7×256 + 15×16 + 15 = 2047    (zoo)
</code></pre></div></div>

<blockquote>
  <p><strong>Dice numbered from zero.</strong> Some D16 (hex) dice are labelled <code class="language-plaintext highlighter-rouge">0–F</code> and some D8 are labelled <code class="language-plaintext highlighter-rouge">0–7</code>. If a die already starts at <code class="language-plaintext highlighter-rouge">0</code>, use its face value directly and drop the <code class="language-plaintext highlighter-rouge">− 1</code> for that die.</p>
</blockquote>

<p>Seen as bits, the three dice simply fill the 11-bit word index from left to right:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>First  (D8)  → 3 bits   b10 b9 b8
Second (D16) → 4 bits   b7 b6 b5 b4
Third  (D16) → 4 bits   b3 b2 b1 b0
</code></pre></div></div>

<p><strong>Worked example</strong> — you roll <code class="language-plaintext highlighter-rouge">First = 6</code>, <code class="language-plaintext highlighter-rouge">Second = 13</code>, <code class="language-plaintext highlighter-rouge">Third = 2</code>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(6 − 1) × 256  +  (13 − 1) × 16  +  (2 − 1)
= 1280 + 192 + 1
= 1473

binary:  101  1100  0001   →   10111000001
</code></pre></div></div>

<p>Index <code class="language-plaintext highlighter-rouge">1473</code> is the <strong>1474th</strong> word in the BIP39 list, because index <code class="language-plaintext highlighter-rouge">0</code> is the first word (<code class="language-plaintext highlighter-rouge">abandon</code>).</p>

<h3 id="94-how-many-rolls-you-need">9.4 How Many Rolls You Need</h3>

<table>
  <thead>
    <tr>
      <th>Seed length</th>
      <th>Words</th>
      <th>Roll sets</th>
      <th>Total die throws</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>12 words</td>
      <td>12</td>
      <td>12 sets of 3</td>
      <td>36</td>
    </tr>
    <tr>
      <td>24 words</td>
      <td>24</td>
      <td>24 sets of 3</td>
      <td>72</td>
    </tr>
  </tbody>
</table>

<p>Compare that with <code class="language-plaintext highlighter-rouge">256</code> coin flips or <code class="language-plaintext highlighter-rouge">~100</code> D6 rolls plus a hand-verified SHA-256. Each set of three is also <strong>independently checkable</strong>: if you mis-record one word, only that word is wrong, and the rest of the phrase is unaffected.</p>

<h3 id="95-the-last-word-is-not-free">9.5 The Last Word Is Not Free</h3>

<p>This is the one catch, and it is easy to get wrong.</p>

<p>Because this method produces words <em>directly</em>, it bypasses the “entropy → checksum → split” pipeline. Words <code class="language-plaintext highlighter-rouge">1…11</code> (or <code class="language-plaintext highlighter-rouge">1…23</code>) are pure entropy and can be taken exactly as rolled. The <strong>final</strong> word cannot, because part of it is the checksum:</p>

<table>
  <thead>
    <tr>
      <th>Seed length</th>
      <th>Total bits</th>
      <th>Final word = entropy bits + checksum bits</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>12 words</td>
      <td>132</td>
      <td><strong>7</strong> entropy bits + <strong>4</strong> checksum bits</td>
    </tr>
    <tr>
      <td>24 words</td>
      <td>264</td>
      <td><strong>3</strong> entropy bits + <strong>8</strong> checksum bits</td>
    </tr>
  </tbody>
</table>

<p>So roll the last set normally, then keep only the leading bits of that provisional word and let the checksum determine the rest:</p>

<ul>
  <li><strong>12 words</strong> — keep the <strong>first 7 bits</strong> of the provisional 12th word. <code class="language-plaintext highlighter-rouge">2⁴ = 16</code> words share that prefix; exactly <strong>one</strong> of them has a valid checksum.</li>
  <li><strong>24 words</strong> — keep the <strong>first 3 bits</strong> of the provisional 24th word. <code class="language-plaintext highlighter-rouge">2⁸ = 256</code> words share that prefix; exactly <strong>one</strong> of them has a valid checksum.</li>
</ul>

<p>Those leading bits are not decoration — they are real entropy, and they are what completes the count:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>12 words:  11 words × 11 bits + 7 bits = 121 + 7 = 128 bits
24 words:  23 words × 11 bits + 3 bits = 253 + 3 = 256 bits
</code></pre></div></div>

<p>Use an <strong>offline, trusted</strong> BIP39 tool or hardware wallet to work out which candidate is valid. Most hardware wallets do this for you: you type the first 11 (or 23) words and the device only offers valid final words — pick the one matching your rolled prefix.</p>

<p>If you would rather compute it yourself, again on an air-gapped machine:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">hashlib</span>

<span class="n">indices</span> <span class="o">=</span> <span class="p">[</span> <span class="p">...</span> <span class="p">]</span>     <span class="c1"># the 11 or 23 words you rolled, as indices 0–2047
</span><span class="n">last</span>    <span class="o">=</span> <span class="mi">1473</span>        <span class="c1"># the provisional final word, exactly as rolled
</span>
<span class="n">n_ent</span>  <span class="o">=</span> <span class="mi">128</span> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">indices</span><span class="p">)</span> <span class="o">==</span> <span class="mi">11</span> <span class="k">else</span> <span class="mi">256</span>
<span class="n">n_keep</span> <span class="o">=</span> <span class="n">n_ent</span> <span class="o">-</span> <span class="nb">len</span><span class="p">(</span><span class="n">indices</span><span class="p">)</span> <span class="o">*</span> <span class="mi">11</span>        <span class="c1"># 7 bits (12 words) or 3 bits (24 words)
</span><span class="n">n_free</span> <span class="o">=</span> <span class="mi">11</span> <span class="o">-</span> <span class="n">n_keep</span>
<span class="n">prefix</span> <span class="o">=</span> <span class="nb">format</span><span class="p">(</span><span class="n">last</span><span class="p">,</span> <span class="s">"011b"</span><span class="p">)[:</span><span class="n">n_keep</span><span class="p">]</span>

<span class="k">for</span> <span class="n">tail</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">2</span> <span class="o">**</span> <span class="n">n_free</span><span class="p">):</span>
    <span class="n">cand</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">prefix</span> <span class="o">+</span> <span class="nb">format</span><span class="p">(</span><span class="n">tail</span><span class="p">,</span> <span class="s">"0"</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">n_free</span><span class="p">)</span> <span class="o">+</span> <span class="s">"b"</span><span class="p">),</span> <span class="mi">2</span><span class="p">)</span>
    <span class="n">bits</span> <span class="o">=</span> <span class="s">""</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="nb">format</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="s">"011b"</span><span class="p">)</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">indices</span> <span class="o">+</span> <span class="p">[</span><span class="n">cand</span><span class="p">])</span>
    <span class="n">ent</span>  <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">bits</span><span class="p">[:</span><span class="n">n_ent</span><span class="p">],</span> <span class="mi">2</span><span class="p">).</span><span class="n">to_bytes</span><span class="p">(</span><span class="n">n_ent</span> <span class="o">//</span> <span class="mi">8</span><span class="p">,</span> <span class="s">"big"</span><span class="p">)</span>
    <span class="n">cs</span>   <span class="o">=</span> <span class="nb">format</span><span class="p">(</span><span class="nb">int</span><span class="p">.</span><span class="n">from_bytes</span><span class="p">(</span><span class="n">hashlib</span><span class="p">.</span><span class="n">sha256</span><span class="p">(</span><span class="n">ent</span><span class="p">).</span><span class="n">digest</span><span class="p">(),</span> <span class="s">"big"</span><span class="p">),</span> <span class="s">"0256b"</span><span class="p">)[:</span> <span class="n">n_ent</span> <span class="o">//</span> <span class="mi">32</span><span class="p">]</span>
    <span class="k">if</span> <span class="n">bits</span><span class="p">[</span><span class="n">n_ent</span><span class="p">:]</span> <span class="o">==</span> <span class="n">cs</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="s">"valid final index:"</span><span class="p">,</span> <span class="n">cand</span><span class="p">)</span>
</code></pre></div></div>

<blockquote>
  <p><strong>Do not just re-roll until the last word happens to be valid.</strong> It is technically unbiased (<code class="language-plaintext highlighter-rouge">2⁷ = 128</code> of the 2048 words are valid last words for a 12-word phrase, <code class="language-plaintext highlighter-rouge">2³ = 8</code> for a 24-word phrase), but it needs an average of 16 re-rolls for 12 words and <strong>256</strong> for 24 words — and you still need a checksum tool to know when to stop.</p>
</blockquote>

<h3 id="96-why-this-method-is-worth-the-extra-dice">9.6 Why This Method Is Worth the Extra Dice</h3>

<table>
  <thead>
    <tr>
      <th> </th>
      <th> </th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>No bias, by construction</strong></td>
      <td>8 and 16 are powers of two, so no state is ever wasted or rejected.</td>
    </tr>
    <tr>
      <td><strong>No hashing of entropy</strong></td>
      <td>SHA-256 is only needed for the single final word, not for the entropy itself.</td>
    </tr>
    <tr>
      <td><strong>Fewest physical actions</strong></td>
      <td>72 throws for a 24-word seed, versus ~100 rolls or 256 flips.</td>
    </tr>
    <tr>
      <td><strong>Auditable</strong></td>
      <td>Each word traces back to three recorded numbers you can re-check one at a time.</td>
    </tr>
    <tr>
      <td><strong>Trade-off</strong></td>
      <td>You need specialist dice, and a fair D16 is harder to source and verify than a fair coin.</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="pipeline">10. Complete BIP39 Pipeline</h2>

<h3 id="coin-method">Coin Method</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>256 coin flips
        ↓
256-bit entropy
        ↓
SHA-256  →  8 checksum bits
        ↓
264-bit sequence
        ↓
24 groups of 11 bits
        ↓
24 BIP39 words
</code></pre></div></div>

<h3 id="dice-method">Dice Method</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>~100 dice rolls
        ↓
SHA-256(rolls)  →  256-bit entropy
        ↓
SHA-256  →  8 checksum bits
        ↓
264-bit sequence
        ↓
24 groups of 11 bits
        ↓
24 BIP39 words
</code></pre></div></div>

<h3 id="d8d16d16-method">D8/D16/D16 Method</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>24 sets of (D8, D16, D16)
        ↓
index = (D8−1)×256 + (D16−1)×16 + (D16−1)
        ↓
24 word indices, 0–2047
        ↓
words 1–23 kept as rolled
        ↓
word 24: keep first 3 bits,
last 8 bits = SHA-256 checksum
        ↓
24 BIP39 words
</code></pre></div></div>

<hr />

<h2 id="security-comparison">11. Security Comparison</h2>

<table>
  <thead>
    <tr>
      <th>Property</th>
      <th>Coin</th>
      <th>Dice (D6)</th>
      <th>D8/D16/D16</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Entropy per event</td>
      <td>1 bit</td>
      <td>~2.585 bits</td>
      <td>3–4 bits</td>
    </tr>
    <tr>
      <td>Events for 24 words</td>
      <td>256 flips</td>
      <td>~100 rolls</td>
      <td>72 throws (24 × 3)</td>
    </tr>
    <tr>
      <td>Simplicity of encoding</td>
      <td>Excellent</td>
      <td>Moderate</td>
      <td>Excellent</td>
    </tr>
    <tr>
      <td>Encoding bias risk</td>
      <td>None</td>
      <td>Real, if done naïvely</td>
      <td>None, by construction</td>
    </tr>
    <tr>
      <td>Physical bias risk</td>
      <td>~0.8%, negligible</td>
      <td>Low, with fair dice</td>
      <td>Low, with fair dice</td>
    </tr>
    <tr>
      <td>Hashing required</td>
      <td>Checksum</td>
      <td>Entropy <strong>and</strong> checksum</td>
      <td>Final word only</td>
    </tr>
    <tr>
      <td>Recording burden</td>
      <td>256 bits</td>
      <td>~100 digits</td>
      <td>72 digits, self-grouped</td>
    </tr>
    <tr>
      <td>Chance of human error</td>
      <td>Moderate</td>
      <td>Highest</td>
      <td>Lowest</td>
    </tr>
    <tr>
      <td>Physical speed</td>
      <td>Slower</td>
      <td>Faster</td>
      <td>Fastest</td>
    </tr>
    <tr>
      <td>Mathematical complexity</td>
      <td>Low</td>
      <td>Higher</td>
      <td>Low</td>
    </tr>
    <tr>
      <td>Equipment</td>
      <td>Any coin</td>
      <td>Any die</td>
      <td>Specialist D8/D16 dice</td>
    </tr>
  </tbody>
</table>

<p>All three are secure <strong>when done correctly</strong>. The coin trades speed for simplicity; the D6 trades simplicity for speed; the D8/D16/D16 set buys both back at the cost of needing dice you cannot pick up in any shop.</p>

<hr />

<h2 id="mnemonic-to-seed">12. From Mnemonic to Wallet Seed</h2>

<p>The words are not the wallet. BIP39 defines one more step, which turns the mnemonic into the 512-bit seed that BIP32 uses to derive every key and address:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mnemonic words  +  optional passphrase
        ↓
PBKDF2-HMAC-SHA512
password = mnemonic sentence
salt     = "mnemonic" + passphrase
2048 iterations, 64-byte output
        ↓
512-bit seed
        ↓
BIP32 master key  →  accounts  →  addresses
</code></pre></div></div>

<p>Three consequences are worth understanding before you rely on a passphrase:</p>

<ul>
  <li><strong>The passphrase is not checksummed.</strong> The mnemonic is; the passphrase is not. Any passphrase is “valid”, so a single typo silently derives a completely different, empty wallet — with no error message. If you use one, back it up as carefully as the words, and separately from them.</li>
  <li><strong>Every passphrase gives a real wallet.</strong> This is what makes hidden or decoy wallets possible: the same 24 words plus different passphrases are different wallets, and nothing in the backup reveals how many exist.</li>
  <li><strong>The passphrase is not a substitute for entropy.</strong> 2048 PBKDF2 iterations is a very light stretching by modern standards. A guessable passphrase over a stolen mnemonic is brute-forceable; it protects a lost backup only if it is itself high-entropy.</li>
</ul>

<p>If you skip the passphrase, the salt is simply the string <code class="language-plaintext highlighter-rouge">"mnemonic"</code> — which is the default every wallet uses.</p>

<hr />

<h2 id="checksum-role">13. The Role of the Checksum</h2>

<p>A valid BIP39 phrase carries built-in error detection. If a single word is wrong, the checksum almost always fails and the wallet rejects the phrase as invalid.</p>

<p>“Almost always” is literal: a 24-word phrase has 8 checksum bits, so a random corruption still passes by chance about <code class="language-plaintext highlighter-rouge">1/256</code> of the time, and a 12-word phrase (4 bits) about <code class="language-plaintext highlighter-rouge">1/16</code> of the time. The checksum catches careless mistakes; it is not a guarantee.</p>

<p>It is important to understand what the checksum is <strong>not</strong>: it is not a security feature. It provides only:</p>

<ul>
  <li><strong>Typo detection</strong></li>
  <li><strong>Phrase validation</strong></li>
</ul>

<p>The real security comes entirely from the quality of the <strong>random entropy</strong>. A checksum on predictable entropy protects nothing.</p>

<hr />

<h2 id="verification">14. Verify Before You Fund the Wallet</h2>

<p>A seed phrase you have never restored from is a backup you have never tested. Before sending anything of value:</p>

<ol>
  <li><strong>Check the phrase validates.</strong> Enter it into your offline tool or hardware wallet and confirm the checksum is accepted.</li>
  <li><strong>Wipe and restore.</strong> Reset the device and recover it from the words <em>as you wrote them down</em> — not from what is still on screen. This is the step that catches a mis-copied word, a wrong order, or an illegible character in your backup.</li>
  <li><strong>Confirm the same first address.</strong> After restoring, the first receive address must match what you saw before the wipe. If it does not, check the <strong>derivation path</strong> before panicking — BIP44 (<code class="language-plaintext highlighter-rouge">m/44'/0'/0'</code>), BIP49, BIP84 (<code class="language-plaintext highlighter-rouge">m/84'/0'/0'</code>, native SegWit) and BIP86 (Taproot) produce entirely different addresses from the same seed.</li>
  <li><strong>Cross-check with a second implementation.</strong> Deriving the first address with an independent offline tool confirms you are not depending on one vendor’s bug.</li>
  <li><strong>Send a small test amount first</strong>, and only then the rest.</li>
</ol>

<p>If you used a passphrase, repeat the whole restore <em>with</em> it — an untested passphrase is the most common way people lock themselves out permanently.</p>

<hr />

<h2 id="best-practices">15. Best Practices</h2>

<h3 id="use-a-fair-physical-source">Use a fair physical source</h3>

<p><strong>Good:</strong></p>

<ul>
  <li>A quality, balanced coin</li>
  <li>Casino-grade dice</li>
  <li>Any genuinely random physical process</li>
</ul>

<p><strong>Avoid:</strong></p>

<ul>
  <li>Human-chosen numbers</li>
  <li>Recognizable patterns</li>
  <li>Dates, phone numbers, or “keyboard mashing”</li>
</ul>

<p>Humans are notoriously bad at being random. The whole point of a physical source is to remove your brain from the loop.</p>

<h3 id="keep-entropy-offline">Keep entropy offline</h3>

<p>Generate the entropy:</p>

<ul>
  <li><strong>Offline</strong>, on a trusted air-gapped device</li>
  <li>Away from <strong>cameras</strong> and onlookers</li>
  <li>With <strong>no network access</strong></li>
</ul>

<p>Never use a website to convert your flips or rolls into words, even one that claims to work offline — you cannot verify what the page you actually loaded is doing. The same applies to phone photos, cloud notes, password managers that sync, and printers with storage.</p>

<h3 id="never-reuse-entropy">Never reuse entropy</h3>

<p>Every wallet must have its own unique randomness. Do <strong>not</strong>:</p>

<ul>
  <li>Reuse a seed across wallets</li>
  <li>Modify or “improve” existing words by hand</li>
  <li>Change words to make them more memorable</li>
</ul>

<p>Altering a valid phrase by hand almost always breaks the checksum, and in the rare cases it does not, you have quietly reduced your entropy to something an attacker can search.</p>

<h3 id="record-the-backup-properly">Record the backup properly</h3>

<ul>
  <li>Write the words <strong>numbered and in order</strong> — order is part of the secret.</li>
  <li>Prefer a durable medium (stamped steel) over paper for anything long-lived.</li>
  <li>Note the word list language and the derivation path alongside the backup; neither is secret, and both save you later.</li>
</ul>

<hr />

<h2 id="summary">16. Summary</h2>

<p>The entire process, end to end:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Physical randomness
        ↓
Entropy extraction
        ↓
SHA-256 checksum
        ↓
Append checksum
        ↓
Split into 11-bit numbers
        ↓
Map numbers 0–2047 to words
        ↓
BIP39 mnemonic phrase
        ↓
PBKDF2 (+ optional passphrase)
        ↓
512-bit wallet seed
</code></pre></div></div>

<p>A <strong>coin</strong> yields randomness directly as binary — simple, slow, and hard to get wrong. A <strong>D6</strong> yields more entropy per action but requires careful, unbiased conversion (ideally by hashing the rolls with SHA-256). A <strong>D8 plus two D16</strong> skips the conversion entirely: three throws = 11 bits = one word, with the only special case being the checksum-bearing final word.</p>

<p>Performed correctly, all three produce a mnemonic that is every bit as secure as one from a hardware RNG — with the added assurance that <em>you</em> watched the randomness happen.</p>]]></content><author><name>Carlos Requena</name></author><category term="Bitcoin" /><summary type="html"><![CDATA["It isn't the events themselves that disturb people, but only their judgements about them." --Epictetus]]></summary></entry><entry xml:lang="en"><title type="html">[BITCOIN] Dissecting Bitcoin Block</title><link href="https://cjrequena.github.io/2025-08-27/dissecting-bitcoin-block-en" rel="alternate" type="text/html" title="[BITCOIN] Dissecting Bitcoin Block" /><published>2025-08-27T00:00:00+00:00</published><updated>2025-08-27T00:00:00+00:00</updated><id>https://cjrequena.github.io/2025-08-27/dissecting-bitcoin-block-en</id><content type="html" xml:base="https://cjrequena.github.io/2025-08-27/dissecting-bitcoin-block-en"><![CDATA[<div style="text-align:center">
    <span style="color:red;font-weight: bold">"If you want to find the secrets of the universe, think in terms of energy, frequency and vibration.” </span> 
    <span style="color:black;font-weight: bold">--Nikola Tesla</span>
</div>
<p><br /></p>

<h2 id="overview">Overview</h2>

<p>A <strong>block</strong> is the basic building unit of a <strong>blockchain</strong>, holding a group of verified transactions along with cryptographic references to preceding blocks. Together, they create an unchangeable ledger within the blockchain network.</p>

<p>In essence, each block serves as a digital container that securely and permanently records transaction information for the entire system.</p>

<p>A <strong>block</strong> in Bitcoin is like a page in a ledger that records and secures recent transactions.</p>

<p>Each block is linked to the previous one, forming the <strong>blockchain</strong>.</p>

<hr />

<h2 id="structure-of-a-bitcoin-block">Structure of a Bitcoin Block</h2>

<p>A Bitcoin block has two main parts <strong>The Block Header and The Block Body</strong></p>

<p><strong>Block Header</strong></p>

<p>The metadata of the block, containing:</p>

<ul>
  <li><strong>Version</strong> → Protocol version used to create the block.</li>
  <li><strong>Previous Block Hash</strong> → Cryptographic hash of the previous block, linking the chain.</li>
  <li><strong>Merkle Root</strong> → A hash representing all transactions in the block, built via a <em>Merkle Tree</em>.</li>
  <li><strong>Timestamp</strong> → Approximate creation time of the block.</li>
  <li><strong>Difficulty Target (nBits)</strong> → The target value that the block hash must meet (controls mining difficulty).</li>
  <li><strong>Nonce</strong> → A 32-bit number miners vary to find a valid block hash.</li>
</ul>

<p><strong>Block Body</strong></p>

<ul>
  <li>Contains the <strong>list of transactions</strong> included in the block.</li>
  <li>
    <p>Starts with a <strong>coinbase transaction</strong>:</p>

    <ul>
      <li>The first transaction in every block.</li>
      <li>Rewards the miner with new Bitcoin (block subsidy + transaction fees).</li>
    </ul>
  </li>
</ul>

<hr />

<h2 id="block-constraints">Block Constraints</h2>

<p><strong>Block Size &amp; Limits</strong></p>

<ul>
  <li>Current average block size: ~1–2 MB (due to SegWit optimization).</li>
  <li>Can hold a few thousand transactions depending on size.</li>
</ul>

<p><strong>Block Reward</strong></p>

<ul>
  <li>New bitcoins are created via the <strong>block reward</strong> in the coinbase transaction.</li>
  <li>Halves every <strong>210,000 blocks (~4 years)</strong>.</li>
  <li>Started at <strong>50 BTC</strong> (2009) → now <strong>6.25 BTC</strong> (until 2024 halving → 3.125 BTC).</li>
</ul>

<p><strong>Block Time</strong></p>

<ul>
  <li>Target: <strong>10 minutes</strong> per block.</li>
  <li>Achieved by adjusting difficulty every <strong>2016 blocks (~2 weeks)</strong> so the average time stays near 10 minutes.</li>
</ul>

<p><strong>Block Validation</strong></p>

<ul>
  <li>
    <p>A valid block must:</p>

    <ul>
      <li>Have a hash below the difficulty target (proof-of-work).</li>
      <li>Contain valid, non-duplicate transactions.</li>
      <li>Correctly reference the previous block.</li>
      <li>Correctly compute the Merkle root.</li>
    </ul>
  </li>
</ul>

<p><strong>Blockchain Linking</strong></p>

<ul>
  <li>Each block references the <strong>hash of the previous block</strong>.</li>
  <li>
    <p>This makes the blockchain <strong>immutable</strong>:</p>

    <ul>
      <li>Changing one block invalidates all subsequent blocks (since the hashes break).</li>
    </ul>
  </li>
</ul>

<hr />

<h2 id="block-header">Block Header</h2>

<p>At the top of every Bitcoin block is an <strong>80-byte (160 hex character) block header</strong> that summarizes all the data in the block. This header is crucial for:</p>

<ul>
  <li>Block identification and validation</li>
  <li>Creating the block hash</li>
  <li>Maintaining blockchain integrity through cryptographic linking</li>
</ul>

<blockquote>
  <p>Miners repeatedly hash this block header to try and get a result below the current target. Successfully finding such a hash allows the block to be added to the blockchain, a process known as <strong>mining</strong>.</p>

</blockquote>

<h3 id="block-header-structure">Block Header Structure</h3>

<p>The 80-byte header contains six key fields:</p>

<table>
  <thead>
    <tr>
      <th>Field</th>
      <th>Size (bytes)</th>
      <th>Description</th>
      <th>Endianness</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Version</td>
      <td>4</td>
      <td>Block version number indicating validation rules</td>
      <td><a href="https://learnmeabitcoin.com/technical/general/little-endian/">Little-endian</a></td>
    </tr>
    <tr>
      <td>Previous Block Hash</td>
      <td>32</td>
      <td>SHA-256 hash of the preceding block’s header</td>
      <td><a href="https://learnmeabitcoin.com/technical/general/little-endian/">Little-endian</a></td>
    </tr>
    <tr>
      <td>Merkle Root</td>
      <td>32</td>
      <td>Hash representing all transactions in the block</td>
      <td><a href="https://learnmeabitcoin.com/technical/general/little-endian/">Little-endian</a></td>
    </tr>
    <tr>
      <td>Timestamp</td>
      <td>4</td>
      <td>Unix epoch time when mining began</td>
      <td><a href="https://learnmeabitcoin.com/technical/general/little-endian/">Little-endian</a></td>
    </tr>
    <tr>
      <td>Bits (nBits)</td>
      <td>4</td>
      <td>Compact representation of the difficulty target</td>
      <td><a href="https://learnmeabitcoin.com/technical/general/little-endian/">Little-endian</a></td>
    </tr>
    <tr>
      <td>Nonce</td>
      <td>4</td>
      <td>Counter used in mining to find valid hashes</td>
      <td><a href="https://learnmeabitcoin.com/technical/general/little-endian/">Little-endian</a></td>
    </tr>
  </tbody>
</table>

<h3 id="retrieving-block-header-data">Retrieving Block Header Data</h3>

<p>To get the block header for block height 1 using Blockchain.com’s API:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl <span class="s1">'https://blockchain.info/rawblock/1?format=hex'</span> | <span class="nb">head</span> <span class="nt">-c</span> 160 <span class="o">&gt;</span> block-1.txt
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>010000006fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000982051fd1e4ba744bbbe680e1fee14677ba1a3c3540bf7b1cdb606e857233e0e61bc6649ffff001d01e36299
</code></pre></div></div>

<h3 id="decoding-the-block-header">Decoding the Block Header</h3>

<p>Here’s a Python function to decode a block header from hex format:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">struct</span>
<span class="kn">import</span> <span class="nn">binascii</span>
<span class="kn">import</span> <span class="nn">datetime</span>

<span class="k">def</span> <span class="nf">decode_block_header</span><span class="p">(</span><span class="n">hex_header</span><span class="p">):</span>
    <span class="n">header_bytes</span> <span class="o">=</span> <span class="nb">bytes</span><span class="p">.</span><span class="n">fromhex</span><span class="p">(</span><span class="n">hex_header</span><span class="p">)</span>
    
    <span class="n">version</span> <span class="o">=</span> <span class="n">struct</span><span class="p">.</span><span class="n">unpack</span><span class="p">(</span><span class="s">'&lt;I'</span><span class="p">,</span> <span class="n">header_bytes</span><span class="p">[</span><span class="mi">0</span><span class="p">:</span><span class="mi">4</span><span class="p">])[</span><span class="mi">0</span><span class="p">]</span>
    <span class="n">prev_block</span> <span class="o">=</span> <span class="n">header_bytes</span><span class="p">[</span><span class="mi">4</span><span class="p">:</span><span class="mi">36</span><span class="p">][::</span><span class="o">-</span><span class="mi">1</span><span class="p">].</span><span class="nb">hex</span><span class="p">()</span>
    <span class="n">merkle_root</span> <span class="o">=</span> <span class="n">header_bytes</span><span class="p">[</span><span class="mi">36</span><span class="p">:</span><span class="mi">68</span><span class="p">][::</span><span class="o">-</span><span class="mi">1</span><span class="p">].</span><span class="nb">hex</span><span class="p">()</span>
    <span class="n">timestamp</span> <span class="o">=</span> <span class="n">struct</span><span class="p">.</span><span class="n">unpack</span><span class="p">(</span><span class="s">'&lt;I'</span><span class="p">,</span> <span class="n">header_bytes</span><span class="p">[</span><span class="mi">68</span><span class="p">:</span><span class="mi">72</span><span class="p">])[</span><span class="mi">0</span><span class="p">]</span>
    <span class="n">bits</span> <span class="o">=</span> <span class="n">struct</span><span class="p">.</span><span class="n">unpack</span><span class="p">(</span><span class="s">'&lt;I'</span><span class="p">,</span> <span class="n">header_bytes</span><span class="p">[</span><span class="mi">72</span><span class="p">:</span><span class="mi">76</span><span class="p">])[</span><span class="mi">0</span><span class="p">]</span>
    <span class="n">nonce</span> <span class="o">=</span> <span class="n">struct</span><span class="p">.</span><span class="n">unpack</span><span class="p">(</span><span class="s">'&lt;I'</span><span class="p">,</span> <span class="n">header_bytes</span><span class="p">[</span><span class="mi">76</span><span class="p">:</span><span class="mi">80</span><span class="p">])[</span><span class="mi">0</span><span class="p">]</span>

    <span class="k">return</span> <span class="p">{</span>
        <span class="s">'version'</span><span class="p">:</span> <span class="n">version</span><span class="p">,</span>
        <span class="s">'previous_block_hash'</span><span class="p">:</span> <span class="n">prev_block</span><span class="p">,</span>
        <span class="s">'merkle_root'</span><span class="p">:</span> <span class="n">merkle_root</span><span class="p">,</span>
        <span class="s">'timestamp'</span><span class="p">:</span> <span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="n">timestamp</span><span class="si">}</span><span class="s"> (</span><span class="si">{</span><span class="n">datetime</span><span class="p">.</span><span class="n">fromtimestamp</span><span class="p">(</span><span class="n">timestamp</span><span class="p">,</span> <span class="n">UTC</span><span class="p">).</span><span class="n">strftime</span><span class="p">(</span><span class="s">'%Y-%m-%d %H</span><span class="si">:</span><span class="o">%</span><span class="n">M</span><span class="si">:</span><span class="o">%</span><span class="n">S</span> <span class="o">%</span><span class="n">Z</span><span class="s">')</span><span class="si">}</span><span class="s">)"</span><span class="p">,</span>
        <span class="s">'bits'</span><span class="p">:</span> <span class="n">bits</span><span class="p">,</span>
        <span class="s">'nonce'</span><span class="p">:</span> <span class="n">nonce</span>
    <span class="p">}</span>

<span class="c1">#-----------------------------------------------------------------------------------------------------------
</span><span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
    <span class="c1"># Example usage
</span>    <span class="n">hex_header</span> <span class="o">=</span> <span class="s">'010000006fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000982051fd1e4ba744bbbe680e1fee14677ba1a3c3540bf7b1cdb606e857233e0e61bc6649ffff001d01e36299'</span>
    <span class="n">decoded</span> <span class="o">=</span> <span class="n">decode_block_header</span><span class="p">(</span><span class="n">hex_header</span><span class="p">)</span>

    <span class="k">for</span> <span class="n">key</span><span class="p">,</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">decoded</span><span class="p">.</span><span class="n">items</span><span class="p">():</span>
        <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="n">key</span><span class="si">}</span><span class="s">: </span><span class="si">{</span><span class="n">value</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>

<span class="c1">#-----------------------------------------------------------------------------------------------------------
</span><span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">"__main__"</span><span class="p">:</span>
    <span class="n">main</span><span class="p">()</span>
</code></pre></div></div>

<p><strong>Example Output</strong></p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">version</span><span class="pi">:</span> <span class="m">1</span>
<span class="na">previous_block_hash</span><span class="pi">:</span> <span class="s">000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f</span>
<span class="na">merkle_root</span><span class="pi">:</span> <span class="s">0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098</span>
<span class="na">timestamp</span><span class="pi">:</span> <span class="s">1231469665 (2009-01-09 02:54:25)</span>
<span class="na">bits</span><span class="pi">:</span> <span class="m">486604799</span>
<span class="na">nonce</span><span class="pi">:</span> <span class="m">2573394689</span>
</code></pre></div></div>

<h3 id="key-notes">Key Notes</h3>

<ul>
  <li>All integer fields are stored in <strong>little-endian</strong> format</li>
  <li>Hash fields (Previous Block Hash and Merkle Root) need byte reversal for proper display</li>
  <li>The timestamp represents when mining began, not necessarily when the block was found</li>
</ul>

<hr />

<h2 id="block-body">Block Body</h2>

<p>The <strong>block body</strong> contains the transactions that the block commits to. It immediately follows the 80-byte block header.</p>

<p>The block body (unlike the header) is variable length and encodes all spending activity included by miners in that block.</p>

<p>The block body is where all the actual bitcoin transfers happen - the header just contains metadata and proof-of-work, while the body contains the economic activity.</p>

<h3 id="block-body-structure">Block Body Structure</h3>

<table>
  <thead>
    <tr>
      <th>Field</th>
      <th>Example</th>
      <th>Size</th>
      <th>Format</th>
      <th>Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Tx Count</td>
      <td>01</td>
      <td>variable</td>
      <td><a href="https://learnmeabitcoin.com/technical/general/compact-size/" title="Compact Size | CompactSize Unsigned Integers">Compact Size</a></td>
      <td>Indicates the number of transactions.</td>
    </tr>
    <tr>
      <td>Version</td>
      <td>02000000</td>
      <td>4 bytes</td>
      <td><a href="https://learnmeabitcoin.com/technical/general/little-endian/" title="Little-Endian | A Backwards Byte Order used in Bitcoin">Little Endian</a></td>
      <td>The version number for the transaction. Used to enable new features.</td>
    </tr>
    <tr>
      <td>Marker</td>
      <td>00</td>
      <td>1 byte</td>
      <td> </td>
      <td>Used to indicate a segwit transaction. Must be 00.</td>
    </tr>
    <tr>
      <td>Flag</td>
      <td>01</td>
      <td>1 byte</td>
      <td> </td>
      <td>Used to indicate a segwit transaction. Must be 01 or greater.</td>
    </tr>
    <tr>
      <td>Input Count</td>
      <td>01</td>
      <td>variable</td>
      <td><a href="https://learnmeabitcoin.com/technical/general/compact-size/" title="Compact Size | CompactSize Unsigned Integers">Compact Size</a></td>
      <td>Indicates the number of inputs.</td>
    </tr>
    <tr>
      <td>TXID</td>
      <td>[TX1D]</td>
      <td>32 bytes</td>
      <td><a href="https://learnmeabitcoin.com/technical/general/byte-order/#natural-byte-order" title="Byte Order | Transaction Hashes and Block Hashes in Bitcoin">Natural Byte Order</a></td>
      <td>The TXID of the transaction containing the output you want to spend.</td>
    </tr>
    <tr>
      <td>VOUT</td>
      <td>01000000</td>
      <td>4 bytes</td>
      <td><a href="https://learnmeabitcoin.com/technical/general/little-endian/" title="Little-Endian | A Backwards Byte Order used in Bitcoin">Little Endian</a></td>
      <td>The index number of the output you want to spend.</td>
    </tr>
    <tr>
      <td>ScriptSig Size</td>
      <td>6b</td>
      <td>variable</td>
      <td><a href="https://learnmeabitcoin.com/technical/general/compact-size/" title="Compact Size | CompactSize Unsigned Integers">Compact Size</a></td>
      <td>The size in bytes of the upcoming ScriptSig.</td>
    </tr>
    <tr>
      <td>ScriptSig</td>
      <td>[script]</td>
      <td>variable</td>
      <td><a href="https://learnmeabitcoin.com/technical/script/" title="Bitcoin Script | A Mini Programming Language">Script</a></td>
      <td>The unlocking code for the output you want to spend.</td>
    </tr>
    <tr>
      <td>Sequence</td>
      <td>fdfffff</td>
      <td>4 bytes</td>
      <td><a href="https://learnmeabitcoin.com/technical/general/little-endian/" title="Little-Endian | A Backwards Byte Order used in Bitcoin">Little Endian</a></td>
      <td>Set whether the transaction can be replaced or when it can be mined.</td>
    </tr>
    <tr>
      <td>Output Count</td>
      <td>02</td>
      <td>variable</td>
      <td><a href="https://learnmeabitcoin.com/technical/general/compact-size/" title="Compact Size | CompactSize Unsigned Integers">Compact Size</a></td>
      <td>Indicates the number of outputs.</td>
    </tr>
    <tr>
      <td>Amount</td>
      <td>e99e060000000000</td>
      <td>8 bytes</td>
      <td><a href="https://learnmeabitcoin.com/technical/general/little-endian/" title="Little-Endian | A Backwards Byte Order used in Bitcoin">Little Endian</a></td>
      <td>The value of the output in satoshis.</td>
    </tr>
    <tr>
      <td>ScriptPubKey Size</td>
      <td>19</td>
      <td>variable</td>
      <td><a href="https://learnmeabitcoin.com/technical/general/compact-size/" title="Compact Size | CompactSize Unsigned Integers">Compact Size</a></td>
      <td>The size in bytes of the upcoming ScriptPubKey.</td>
    </tr>
    <tr>
      <td>ScriptPubKey</td>
      <td>[script]</td>
      <td>variable</td>
      <td><a href="https://learnmeabitcoin.com/technical/script/" title="Bitcoin Script | A Mini Programming Language">Script</a></td>
      <td>The locking code for this output.</td>
    </tr>
    <tr>
      <td>Witness Items</td>
      <td>02</td>
      <td>variable</td>
      <td><a href="https://learnmeabitcoin.com/technical/general/compact-size/" title="Compact Size | CompactSize Unsigned Integers">Compact Size</a></td>
      <td>The number of items to be pushed on to the stack as part of the unlocking code.</td>
    </tr>
    <tr>
      <td>Size</td>
      <td>47</td>
      <td>variable</td>
      <td><a href="https://learnmeabitcoin.com/technical/general/compact-size/" title="Compact Size | CompactSize Unsigned Integers">Compact Size</a></td>
      <td>The size of the upcoming stack item.</td>
    </tr>
    <tr>
      <td>Item</td>
      <td>304…b01</td>
      <td>variable</td>
      <td>Bytes</td>
      <td>The data to be pushed on to the stack.</td>
    </tr>
    <tr>
      <td>Locktime</td>
      <td>00000000</td>
      <td>4 bytes</td>
      <td><a href="https://learnmeabitcoin.com/technical/general/little-endian/" title="Little-Endian | A Backwards Byte Order used in Bitcoin">Little Endian</a></td>
      <td>Set a time or height after which the transaction can be mined.</td>
    </tr>
  </tbody>
</table>

<h3 id="transaction-serialization-legacy">Transaction Serialization (legacy)</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[version: 4 bytes LE]
[input_count: varint]
  for each input:
    [prev_txid: 32 bytes (little-endian in storage)]
    [prev_index: 4 bytes LE]
    [scriptSig_length: varint]
    [scriptSig: scriptSig_length bytes]
    [sequence: 4 bytes LE]
[output_count: varint]
  for each output:
    [value: 8 bytes LE]        # satoshis
    [pk_script_length: varint]
    [pk_script: pk_script_length bytes]
[locktime: 4 bytes LE]

</code></pre></div></div>

<blockquote>
  <p>Notes </p>

  <ul>
    <li><code class="language-plaintext highlighter-rouge">prev_txid</code> is stored in byte-order used within the block (usually little-endian in raw bytes); when displayed by explorers the bytes are reversed to big-endian hex.</li>
    <li><code class="language-plaintext highlighter-rouge">value</code> is an unsigned 8-byte little-endian integer of satoshis.</li>
    <li><code class="language-plaintext highlighter-rouge">sequence</code> historically used for RBF / timelocks; typically <code class="language-plaintext highlighter-rouge">0xffffffff</code>.</li>
  </ul>
</blockquote>

<h3 id="transaction-serialization-segwit---bip141">Transaction Serialization (SegWit - BIP141)</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[version: 4 bytes LE]
[marker: 1 byte == 0x00]
[flag:   1 byte == 0x01]
[input_count: varint]
  for each input: (same fields as legacy *but* scriptSig is usually small or empty)
[output_count: varint]
  for each output: (same as legacy)
[witnesses for each input]
[locktime: 4 bytes LE]

</code></pre></div></div>

<blockquote>
  <p>Notes </p>

  <ul>
    <li>SegWit transactions add a 2-byte header after <code class="language-plaintext highlighter-rouge">version</code></li>
    <li>for each stack element: <code class="language-plaintext highlighter-rouge">[witness_item_len: varint] [witness_item: bytes]</code></li>
    <li>The presence of SegWit is detected when <code class="language-plaintext highlighter-rouge">marker == 0x00</code> and <code class="language-plaintext highlighter-rouge">flag != 0x00</code> immediately after the version.</li>
  </ul>
</blockquote>

<h3 id="retrieving-block-body-data">Retrieving Block Body Data</h3>

<p>To get the block body for block height 1 using Blockchain.com’s API:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl <span class="s1">'https://blockchain.info/rawblock/1?format=hex'</span> | <span class="nb">tail</span> <span class="nt">-c</span> +161 <span class="o">&gt;</span> block-1-body.txt
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0704ffff001d0104ffffffff0100f2052a0100000043410496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858eeac00000000
</code></pre></div></div>

<hr />

<h2 id="decoding-the-genesis-block">Decoding the genesis block.</h2>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">json</span>
<span class="kn">import</span> <span class="nn">struct</span>
<span class="kn">import</span> <span class="nn">requests</span>
<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">TypedDict</span>


<span class="k">class</span> <span class="nc">BlockHeader</span><span class="p">(</span><span class="n">TypedDict</span><span class="p">):</span>
    <span class="s">"""Type definition for decoded block header data."""</span>

    <span class="n">version</span><span class="p">:</span> <span class="nb">int</span>
    <span class="n">previous_block_hash</span><span class="p">:</span> <span class="nb">str</span>
    <span class="n">merkle_root</span><span class="p">:</span> <span class="nb">str</span>
    <span class="n">timestamp</span><span class="p">:</span> <span class="nb">int</span>
    <span class="n">bits</span><span class="p">:</span> <span class="nb">int</span>
    <span class="n">nonce</span><span class="p">:</span> <span class="nb">int</span>


<span class="k">class</span> <span class="nc">TransactionInput</span><span class="p">(</span><span class="n">TypedDict</span><span class="p">):</span>
    <span class="s">"""Type definition for decoded block tx input data."""</span>

    <span class="n">previous_tx_hash</span><span class="p">:</span> <span class="nb">str</span>
    <span class="n">previous_output_index</span><span class="p">:</span> <span class="nb">int</span>
    <span class="n">script_sig</span><span class="p">:</span> <span class="nb">str</span>
    <span class="n">script_sig_length</span><span class="p">:</span> <span class="nb">str</span>
    <span class="n">sequence</span><span class="p">:</span> <span class="nb">str</span>
    <span class="n">is_coinbase</span><span class="p">:</span> <span class="nb">bool</span>


<span class="k">class</span> <span class="nc">TransactionOutput</span><span class="p">(</span><span class="n">TypedDict</span><span class="p">):</span>
    <span class="s">"""Type definition for decoded block transaction output data."""</span>

    <span class="n">value_satoshi</span><span class="p">:</span> <span class="nb">int</span>
    <span class="n">value_btc</span><span class="p">:</span> <span class="nb">float</span>
    <span class="n">script_pubkey</span><span class="p">:</span> <span class="nb">str</span>
    <span class="n">script_pubkey_length</span><span class="p">:</span> <span class="nb">int</span>


<span class="k">class</span> <span class="nc">WitnessItem</span><span class="p">(</span><span class="n">TypedDict</span><span class="p">):</span>
    <span class="s">"""Type definition for a single witness item."""</span>
    <span class="n">data</span><span class="p">:</span> <span class="nb">str</span>
    <span class="n">length</span><span class="p">:</span> <span class="nb">int</span>
    <span class="nb">type</span><span class="p">:</span> <span class="nb">str</span>
    <span class="n">description</span><span class="p">:</span> <span class="nb">str</span>


<span class="k">class</span> <span class="nc">TransactionWitness</span><span class="p">(</span><span class="n">TypedDict</span><span class="p">):</span>
    <span class="s">"""Type definition for witness data of a single input."""</span>
    <span class="n">input_index</span><span class="p">:</span> <span class="nb">int</span>
    <span class="n">witness_count</span><span class="p">:</span> <span class="nb">int</span>
    <span class="n">witness_items</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="n">WitnessItem</span><span class="p">]</span>
    <span class="n">witness_type</span><span class="p">:</span> <span class="nb">str</span>
    <span class="n">total_witness_size</span><span class="p">:</span> <span class="nb">int</span>


<span class="k">class</span> <span class="nc">Transaction</span><span class="p">(</span><span class="n">TypedDict</span><span class="p">):</span>
    <span class="n">version</span><span class="p">:</span> <span class="nb">int</span>
    <span class="n">tx_type</span><span class="p">:</span> <span class="nb">str</span>
    <span class="n">has_witness</span><span class="p">:</span> <span class="nb">bool</span>
    <span class="n">tx_input_count</span><span class="p">:</span> <span class="nb">int</span>
    <span class="n">tx_inputs</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="n">TransactionInput</span><span class="p">]</span>
    <span class="n">tx_output_count</span><span class="p">:</span> <span class="nb">int</span>
    <span class="n">tx_outputs</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="n">TransactionOutput</span><span class="p">]</span>
    <span class="n">lock_time</span><span class="p">:</span> <span class="nb">int</span>
    <span class="n">size_bytes</span><span class="p">:</span> <span class="nb">int</span>
    <span class="n">total_output_value_satoshi</span><span class="p">:</span> <span class="nb">int</span>
    <span class="n">total_output_value_btc</span><span class="p">:</span> <span class="nb">float</span>
    <span class="n">tx_witnesses</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="n">TransactionWitness</span><span class="p">]</span>


<span class="k">class</span> <span class="nc">BlockDecoder</span><span class="p">:</span>
    <span class="s">"""
    A comprehensive Bitcoin block decoder that handles both Legacy and SegWit transactions.
    Provides methods to decode block headers, block bodies, and complete blocks.
    """</span>

    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="s">"""Initialize the Bitcoin block decoder."""</span>
        <span class="k">pass</span>

    <span class="c1"># --------------------------------------------------------------------------------------------
</span>    <span class="k">def</span> <span class="nf">decode_full_block</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">block</span><span class="p">):</span>
        <span class="s">"""
        """</span>
        <span class="k">try</span><span class="p">:</span>
            <span class="c1"># First 80 bytes (160 hex characters) are the header
</span>            <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">block</span><span class="p">)</span> <span class="o">&lt;</span> <span class="mi">160</span><span class="p">:</span>
                <span class="k">raise</span> <span class="nb">ValueError</span><span class="p">(</span><span class="s">"Block data too short to contain a valid header"</span><span class="p">)</span>

            <span class="n">header</span> <span class="o">=</span> <span class="n">block</span><span class="p">[:</span><span class="mi">160</span><span class="p">]</span>
            <span class="n">body</span> <span class="o">=</span> <span class="n">block</span><span class="p">[</span><span class="mi">160</span><span class="p">:]</span>

            <span class="n">decoded_header</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">decode_block_header</span><span class="p">(</span><span class="n">header</span><span class="p">)</span>
            <span class="n">decoded_body</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">decode_block_body</span><span class="p">(</span><span class="n">body</span><span class="p">)</span>

            <span class="k">return</span> <span class="p">{</span>
                <span class="s">'block_hash'</span><span class="p">:</span> <span class="bp">self</span><span class="p">.</span><span class="n">calculate_block_hash</span><span class="p">(</span><span class="n">header</span><span class="p">),</span>
                <span class="s">'header'</span><span class="p">:</span> <span class="n">decoded_header</span><span class="p">,</span>
                <span class="s">'body'</span><span class="p">:</span> <span class="n">decoded_body</span><span class="p">,</span>
                <span class="s">'total_block_size_bytes'</span><span class="p">:</span> <span class="nb">len</span><span class="p">(</span><span class="n">block</span><span class="p">)</span> <span class="o">//</span> <span class="mi">2</span><span class="p">,</span>
                <span class="s">'header_size_bytes'</span><span class="p">:</span> <span class="mi">80</span><span class="p">,</span>
                <span class="s">'body_size_bytes'</span><span class="p">:</span> <span class="nb">len</span><span class="p">(</span><span class="n">body</span><span class="p">)</span> <span class="o">//</span> <span class="mi">2</span>
            <span class="p">}</span>

        <span class="k">except</span> <span class="nb">Exception</span> <span class="k">as</span> <span class="n">ex</span><span class="p">:</span>
            <span class="k">raise</span> <span class="nb">ValueError</span><span class="p">({</span>
                <span class="s">'error'</span><span class="p">:</span> <span class="sa">f</span><span class="s">"Failed to decode full block: </span><span class="si">{</span><span class="nb">str</span><span class="p">(</span><span class="n">ex</span><span class="p">)</span><span class="si">}</span><span class="s">"</span><span class="p">,</span>
                <span class="s">'raw_hex_length'</span><span class="p">:</span> <span class="nb">len</span><span class="p">(</span><span class="n">block</span><span class="p">)</span>
            <span class="p">})</span>

    <span class="c1"># --------------------------------------------------------------------------------------------
</span>    <span class="o">@</span><span class="nb">staticmethod</span>
    <span class="k">def</span> <span class="nf">decode_block_header</span><span class="p">(</span><span class="n">header</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">BlockHeader</span><span class="p">:</span>
        <span class="s">"""

        """</span>
        <span class="c1"># Validate input
</span>        <span class="n">match</span> <span class="n">header</span><span class="p">:</span>
            <span class="n">case</span> <span class="nb">str</span><span class="p">()</span> <span class="k">if</span> <span class="n">header</span><span class="p">.</span><span class="n">strip</span><span class="p">():</span>
                <span class="n">header</span> <span class="o">=</span> <span class="n">header</span><span class="p">.</span><span class="n">strip</span><span class="p">().</span><span class="n">lower</span><span class="p">()</span>
            <span class="n">case</span> <span class="n">_</span><span class="p">:</span>
                <span class="k">raise</span> <span class="nb">ValueError</span><span class="p">(</span><span class="s">"Header must be a non-empty string"</span><span class="p">)</span>

        <span class="c1"># Validate hex string length (80 bytes = 160 hex characters)
</span>        <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">header</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">160</span><span class="p">:</span>
            <span class="k">raise</span> <span class="nb">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s">"Header must be exactly 160 hex characters, got </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">header</span><span class="p">)</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>

        <span class="c1"># Validate hex string format and convert to bytes
</span>        <span class="k">try</span><span class="p">:</span>
            <span class="n">header_bytes</span> <span class="o">=</span> <span class="nb">bytes</span><span class="p">.</span><span class="n">fromhex</span><span class="p">(</span><span class="n">header</span><span class="p">)</span>
        <span class="k">except</span> <span class="nb">ValueError</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
            <span class="k">raise</span> <span class="nb">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s">"Invalid hex string: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s">"</span><span class="p">)</span> <span class="k">from</span> <span class="n">e</span>

        <span class="k">try</span><span class="p">:</span>
            <span class="p">(</span><span class="n">version</span><span class="p">,)</span> <span class="o">=</span> <span class="n">struct</span><span class="p">.</span><span class="n">unpack</span><span class="p">(</span><span class="s">"&lt;I"</span><span class="p">,</span> <span class="n">header_bytes</span><span class="p">[</span><span class="mi">0</span><span class="p">:</span><span class="mi">4</span><span class="p">])</span>
            <span class="n">previous_block_hash</span> <span class="o">=</span> <span class="n">header_bytes</span><span class="p">[</span><span class="mi">4</span><span class="p">:</span><span class="mi">36</span><span class="p">][::</span><span class="o">-</span><span class="mi">1</span><span class="p">].</span><span class="nb">hex</span><span class="p">()</span>
            <span class="n">merkle_root</span> <span class="o">=</span> <span class="n">header_bytes</span><span class="p">[</span><span class="mi">36</span><span class="p">:</span><span class="mi">68</span><span class="p">][::</span><span class="o">-</span><span class="mi">1</span><span class="p">].</span><span class="nb">hex</span><span class="p">()</span>
            <span class="p">(</span><span class="n">timestamp</span><span class="p">,)</span> <span class="o">=</span> <span class="n">struct</span><span class="p">.</span><span class="n">unpack</span><span class="p">(</span><span class="s">"&lt;I"</span><span class="p">,</span> <span class="n">header_bytes</span><span class="p">[</span><span class="mi">68</span><span class="p">:</span><span class="mi">72</span><span class="p">])</span>
            <span class="p">(</span><span class="n">bits</span><span class="p">,)</span> <span class="o">=</span> <span class="n">struct</span><span class="p">.</span><span class="n">unpack</span><span class="p">(</span><span class="s">"&lt;I"</span><span class="p">,</span> <span class="n">header_bytes</span><span class="p">[</span><span class="mi">72</span><span class="p">:</span><span class="mi">76</span><span class="p">])</span>
            <span class="p">(</span><span class="n">nonce</span><span class="p">,)</span> <span class="o">=</span> <span class="n">struct</span><span class="p">.</span><span class="n">unpack</span><span class="p">(</span><span class="s">"&lt;I"</span><span class="p">,</span> <span class="n">header_bytes</span><span class="p">[</span><span class="mi">76</span><span class="p">:</span><span class="mi">80</span><span class="p">])</span>
        <span class="k">except</span> <span class="nb">ValueError</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
            <span class="k">raise</span> <span class="n">struct</span><span class="p">.</span><span class="n">error</span><span class="p">(</span><span class="sa">f</span><span class="s">"Failed to unpack header data: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s">"</span><span class="p">)</span> <span class="k">from</span> <span class="n">e</span>

        <span class="n">block_header</span><span class="p">:</span> <span class="n">BlockHeader</span> <span class="o">=</span> <span class="p">{</span>
            <span class="s">"version"</span><span class="p">:</span> <span class="n">version</span><span class="p">,</span>
            <span class="s">"previous_block_hash"</span><span class="p">:</span> <span class="n">previous_block_hash</span><span class="p">,</span>
            <span class="s">"merkle_root"</span><span class="p">:</span> <span class="n">merkle_root</span><span class="p">,</span>
            <span class="s">"timestamp"</span><span class="p">:</span> <span class="n">timestamp</span><span class="p">,</span>
            <span class="s">"bits"</span><span class="p">:</span> <span class="n">bits</span><span class="p">,</span>
            <span class="s">"nonce"</span><span class="p">:</span> <span class="n">nonce</span><span class="p">,</span>
        <span class="p">}</span>
        <span class="k">return</span> <span class="n">block_header</span>

    <span class="c1"># --------------------------------------------------------------------------------------------
</span>    <span class="o">@</span><span class="nb">staticmethod</span>
    <span class="k">def</span> <span class="nf">calculate_block_hash</span><span class="p">(</span><span class="n">header</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
        <span class="s">"""
        Calculate the block hash from the header.

        Args:
            header (str): Block header as hex string

        Returns:
            str: Block hash (double SHA-256, reversed)
        """</span>
        <span class="k">try</span><span class="p">:</span>
            <span class="kn">import</span> <span class="nn">hashlib</span>
            <span class="n">header_bytes</span> <span class="o">=</span> <span class="nb">bytes</span><span class="p">.</span><span class="n">fromhex</span><span class="p">(</span><span class="n">header</span><span class="p">)</span>
            <span class="n">hash1</span> <span class="o">=</span> <span class="n">hashlib</span><span class="p">.</span><span class="n">sha256</span><span class="p">(</span><span class="n">header_bytes</span><span class="p">).</span><span class="n">digest</span><span class="p">()</span>
            <span class="n">hash2</span> <span class="o">=</span> <span class="n">hashlib</span><span class="p">.</span><span class="n">sha256</span><span class="p">(</span><span class="n">hash1</span><span class="p">).</span><span class="n">digest</span><span class="p">()</span>
            <span class="k">return</span> <span class="n">hash2</span><span class="p">[::</span><span class="o">-</span><span class="mi">1</span><span class="p">].</span><span class="nb">hex</span><span class="p">()</span>  <span class="c1"># Reverse byte order
</span>        <span class="k">except</span> <span class="nb">Exception</span> <span class="k">as</span> <span class="n">ex</span><span class="p">:</span>
            <span class="k">raise</span> <span class="nb">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s">"Error calculating hash: </span><span class="si">{</span><span class="nb">str</span><span class="p">(</span><span class="n">ex</span><span class="p">)</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>

    <span class="c1"># --------------------------------------------------------------------------------------------
</span>    <span class="k">def</span> <span class="nf">decode_block_body</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">body</span><span class="p">:</span> <span class="nb">str</span><span class="p">):</span>
        <span class="s">"""
        """</span>

        <span class="c1"># Validate data
</span>        <span class="n">match</span> <span class="n">body</span><span class="p">:</span>
            <span class="n">case</span> <span class="nb">str</span><span class="p">()</span> <span class="k">if</span> <span class="n">body</span><span class="p">.</span><span class="n">strip</span><span class="p">():</span>
                <span class="n">body</span> <span class="o">=</span> <span class="n">body</span><span class="p">.</span><span class="n">strip</span><span class="p">().</span><span class="n">lower</span><span class="p">()</span>
            <span class="n">case</span> <span class="n">_</span><span class="p">:</span>
                <span class="k">raise</span> <span class="nb">ValueError</span><span class="p">(</span><span class="s">"Block body data must be a non-empty string"</span><span class="p">)</span>

        <span class="c1"># Validate hex string format and convert to bytes
</span>        <span class="k">try</span><span class="p">:</span>
            <span class="n">body_bytes</span><span class="p">:</span> <span class="nb">bytes</span> <span class="o">=</span> <span class="nb">bytes</span><span class="p">.</span><span class="n">fromhex</span><span class="p">(</span><span class="n">body</span><span class="p">)</span>
        <span class="k">except</span> <span class="nb">ValueError</span> <span class="k">as</span> <span class="n">ex</span><span class="p">:</span>
            <span class="k">raise</span> <span class="nb">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s">"Invalid hex string: </span><span class="si">{</span><span class="n">ex</span><span class="si">}</span><span class="s">"</span><span class="p">)</span> <span class="k">from</span> <span class="n">ex</span>

        <span class="k">try</span><span class="p">:</span>
            <span class="n">offset</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">0</span>
            <span class="n">transactions</span> <span class="o">=</span> <span class="p">[]</span>
            <span class="n">total_inputs</span> <span class="o">=</span> <span class="mi">0</span>
            <span class="n">total_outputs</span> <span class="o">=</span> <span class="mi">0</span>
            <span class="n">total_value_satoshi</span> <span class="o">=</span> <span class="mi">0</span>
            <span class="n">has_segwit_txs</span> <span class="o">=</span> <span class="bp">False</span>
            <span class="n">coinbase_count</span> <span class="o">=</span> <span class="mi">0</span>

            <span class="c1"># Transaction count (varint)
</span>            <span class="n">tx_count</span><span class="p">,</span> <span class="n">offset</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">decode_varint</span><span class="p">(</span><span class="n">body_bytes</span><span class="p">,</span> <span class="n">offset</span><span class="p">)</span>

            <span class="c1"># Extract and retrieve the list of raw hex txs.
</span>            <span class="n">raw_txs</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">extract_raw_txs</span><span class="p">(</span><span class="n">body_bytes</span><span class="p">.</span><span class="nb">hex</span><span class="p">())</span>

            <span class="k">for</span> <span class="n">raw_tx</span> <span class="ow">in</span> <span class="n">raw_txs</span><span class="p">:</span>
                <span class="k">try</span><span class="p">:</span>
                    <span class="n">tx</span><span class="p">:</span> <span class="n">Transaction</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">decode_raw_tx</span><span class="p">(</span><span class="n">raw_tx</span><span class="p">)</span>
                    <span class="n">transactions</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">tx</span><span class="p">)</span>
                    <span class="n">total_inputs</span> <span class="o">+=</span> <span class="n">tx</span><span class="p">[</span><span class="s">'tx_input_count'</span><span class="p">]</span>
                    <span class="n">total_outputs</span> <span class="o">+=</span> <span class="n">tx</span><span class="p">[</span><span class="s">'tx_output_count'</span><span class="p">]</span>
                    <span class="n">total_value_satoshi</span> <span class="o">+=</span> <span class="n">tx</span><span class="p">[</span><span class="s">'total_output_value_satoshi'</span><span class="p">]</span>

                    <span class="c1"># Check if any transaction is SegWit
</span>                    <span class="k">if</span> <span class="n">tx</span><span class="p">[</span><span class="s">'has_witness'</span><span class="p">]:</span>
                        <span class="n">has_segwit_txs</span> <span class="o">=</span> <span class="bp">True</span>

                    <span class="c1"># Count coinbase transactions
</span>                    <span class="k">if</span> <span class="nb">any</span><span class="p">(</span><span class="n">inp</span><span class="p">[</span><span class="s">'is_coinbase'</span><span class="p">]</span> <span class="k">for</span> <span class="n">inp</span> <span class="ow">in</span> <span class="n">tx</span><span class="p">[</span><span class="s">'tx_inputs'</span><span class="p">]):</span>
                        <span class="n">coinbase_count</span> <span class="o">+=</span> <span class="mi">1</span>

                <span class="k">except</span> <span class="nb">Exception</span> <span class="k">as</span> <span class="n">ex</span><span class="p">:</span>
                    <span class="k">raise</span> <span class="nb">Exception</span><span class="p">(</span><span class="sa">f</span><span class="s">"Error decoding raw_tx </span><span class="si">{</span><span class="n">raw_tx</span><span class="si">}</span><span class="s">: </span><span class="si">{</span><span class="n">ex</span><span class="si">}</span><span class="s">"</span><span class="p">)</span> <span class="k">from</span> <span class="n">ex</span>

            <span class="k">return</span> <span class="p">{</span>
                <span class="s">'transaction_count'</span><span class="p">:</span> <span class="n">tx_count</span><span class="p">,</span>
                <span class="s">'transactions_decoded'</span><span class="p">:</span> <span class="nb">len</span><span class="p">([</span><span class="n">tx</span> <span class="k">for</span> <span class="n">tx</span> <span class="ow">in</span> <span class="n">transactions</span> <span class="k">if</span> <span class="s">'error'</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">tx</span><span class="p">]),</span>
                <span class="s">'transactions_failed'</span><span class="p">:</span> <span class="nb">len</span><span class="p">([</span><span class="n">tx</span> <span class="k">for</span> <span class="n">tx</span> <span class="ow">in</span> <span class="n">transactions</span> <span class="k">if</span> <span class="s">'error'</span> <span class="ow">in</span> <span class="n">tx</span><span class="p">]),</span>
                <span class="s">'block_type'</span><span class="p">:</span> <span class="s">'SegWit Block'</span> <span class="k">if</span> <span class="n">has_segwit_txs</span> <span class="k">else</span> <span class="s">'Legacy Block'</span><span class="p">,</span>
                <span class="s">'has_segwit_transactions'</span><span class="p">:</span> <span class="n">has_segwit_txs</span><span class="p">,</span>
                <span class="s">'coinbase_transactions'</span><span class="p">:</span> <span class="n">coinbase_count</span><span class="p">,</span>
                <span class="s">'total_inputs'</span><span class="p">:</span> <span class="n">total_inputs</span><span class="p">,</span>
                <span class="s">'total_outputs'</span><span class="p">:</span> <span class="n">total_outputs</span><span class="p">,</span>
                <span class="s">'total_output_value_satoshis'</span><span class="p">:</span> <span class="n">total_value_satoshi</span><span class="p">,</span>
                <span class="s">'total_output_value_btc'</span><span class="p">:</span> <span class="n">total_value_satoshi</span> <span class="o">/</span> <span class="mf">100000000.0</span><span class="p">,</span>
                <span class="s">'block_body_size_bytes'</span><span class="p">:</span> <span class="nb">len</span><span class="p">(</span><span class="n">body_bytes</span><span class="p">),</span>
                <span class="s">'transactions'</span><span class="p">:</span> <span class="n">transactions</span>
            <span class="p">}</span>

        <span class="k">except</span> <span class="nb">Exception</span> <span class="k">as</span> <span class="n">ex</span><span class="p">:</span>
            <span class="k">raise</span> <span class="nb">Exception</span><span class="p">(</span><span class="sa">f</span><span class="s">"Error decoding block body </span><span class="si">{</span><span class="n">ex</span><span class="si">}</span><span class="s">"</span><span class="p">)</span> <span class="k">from</span> <span class="n">ex</span>

    <span class="c1"># -------------------------------------------------------------------------------------------------
</span>    <span class="k">def</span> <span class="nf">decode_raw_tx</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">tx</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Transaction</span><span class="p">:</span>
        <span class="s">"""
        """</span>

        <span class="c1"># Validate data
</span>        <span class="n">match</span> <span class="n">tx</span><span class="p">:</span>
            <span class="n">case</span> <span class="nb">str</span><span class="p">()</span> <span class="k">if</span> <span class="n">tx</span><span class="p">.</span><span class="n">strip</span><span class="p">():</span>
                <span class="n">tx</span> <span class="o">=</span> <span class="n">tx</span><span class="p">.</span><span class="n">strip</span><span class="p">().</span><span class="n">lower</span><span class="p">()</span>
            <span class="n">case</span> <span class="n">_</span><span class="p">:</span>
                <span class="k">raise</span> <span class="nb">ValueError</span><span class="p">(</span><span class="s">"Transaction data must be a non-empty string"</span><span class="p">)</span>

        <span class="c1"># Validate hex string format and convert to bytes
</span>        <span class="k">try</span><span class="p">:</span>
            <span class="n">tx_bytes</span><span class="p">:</span> <span class="nb">bytes</span> <span class="o">=</span> <span class="nb">bytes</span><span class="p">.</span><span class="n">fromhex</span><span class="p">(</span><span class="n">tx</span><span class="p">)</span>
        <span class="k">except</span> <span class="nb">ValueError</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
            <span class="k">raise</span> <span class="nb">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s">"Invalid hex string: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s">"</span><span class="p">)</span> <span class="k">from</span> <span class="n">e</span>

        <span class="k">try</span><span class="p">:</span>
            <span class="n">offset</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">0</span>

            <span class="c1"># Version (4 bytes)
</span>            <span class="n">version</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="n">struct</span><span class="p">.</span><span class="n">unpack</span><span class="p">(</span><span class="s">'&lt;I'</span><span class="p">,</span> <span class="n">tx_bytes</span><span class="p">[</span><span class="n">offset</span><span class="p">:</span><span class="n">offset</span> <span class="o">+</span> <span class="mi">4</span><span class="p">])[</span><span class="mi">0</span><span class="p">]</span>
            <span class="n">offset</span> <span class="o">+=</span> <span class="mi">4</span>

            <span class="c1"># Check for SegWit marker and flag
</span>            <span class="n">has_witness</span> <span class="o">=</span> <span class="bp">False</span>
            <span class="k">if</span> <span class="n">offset</span> <span class="o">+</span> <span class="mi">1</span> <span class="o">&lt;</span> <span class="nb">len</span><span class="p">(</span><span class="n">tx_bytes</span><span class="p">)</span> <span class="ow">and</span> <span class="n">tx_bytes</span><span class="p">[</span><span class="n">offset</span><span class="p">]</span> <span class="o">==</span> <span class="mh">0x00</span> <span class="ow">and</span> <span class="n">tx_bytes</span><span class="p">[</span><span class="n">offset</span> <span class="o">+</span> <span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="mh">0x01</span><span class="p">:</span>
                <span class="n">has_witness</span> <span class="o">=</span> <span class="bp">True</span>
                <span class="n">offset</span> <span class="o">+=</span> <span class="mi">2</span>  <span class="c1"># Skip marker (0x00) and flag (0x01)
</span>
            <span class="c1"># Decode inputs
</span>            <span class="n">tx_inputs</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="n">TransactionInput</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
            <span class="c1"># Input count (varint)
</span>            <span class="n">tx_input_count</span><span class="p">,</span> <span class="n">offset</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">decode_varint</span><span class="p">(</span><span class="n">tx_bytes</span><span class="p">,</span> <span class="n">offset</span><span class="p">)</span>
            <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">tx_input_count</span><span class="p">):</span>
                <span class="n">tx_inputs</span><span class="p">,</span> <span class="n">offset</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">decode_transaction_inputs_from_raw_tx</span><span class="p">(</span><span class="n">tx_bytes</span><span class="p">.</span><span class="nb">hex</span><span class="p">())</span>

            <span class="c1"># Decode outputs
</span>            <span class="n">tx_outputs</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="n">TransactionOutput</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
            <span class="c1"># Output count (varint)
</span>            <span class="n">tx_output_count</span><span class="p">,</span> <span class="n">offset</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">decode_varint</span><span class="p">(</span><span class="n">tx_bytes</span><span class="p">,</span> <span class="n">offset</span><span class="p">)</span>
            <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">tx_output_count</span><span class="p">):</span>
                <span class="n">tx_outputs</span><span class="p">,</span> <span class="n">offset</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">decode_transaction_outputs_from_raw_tx</span><span class="p">(</span><span class="n">tx_bytes</span><span class="p">.</span><span class="nb">hex</span><span class="p">())</span>

            <span class="c1"># Decode witnesses
</span>            <span class="n">tx_witnesses</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="n">TransactionWitness</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
            <span class="k">if</span> <span class="n">has_witness</span><span class="p">:</span>
                <span class="c1"># Witness count (varint)
</span>                <span class="n">tx_witness_count</span><span class="p">,</span> <span class="n">offset</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">decode_varint</span><span class="p">(</span><span class="n">tx_bytes</span><span class="p">,</span> <span class="n">offset</span><span class="p">)</span>
                <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">tx_witness_count</span><span class="p">):</span>
                    <span class="n">tx_witnesses</span><span class="p">,</span> <span class="n">offset</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">decode_transaction_witnesses_from_raw_tx</span><span class="p">(</span><span class="n">tx_bytes</span><span class="p">.</span><span class="nb">hex</span><span class="p">())</span>

            <span class="c1"># Lock time (4 bytes)
</span>            <span class="n">lock_time</span> <span class="o">=</span> <span class="n">struct</span><span class="p">.</span><span class="n">unpack</span><span class="p">(</span><span class="s">'&lt;I'</span><span class="p">,</span> <span class="n">tx_bytes</span><span class="p">[</span><span class="n">offset</span><span class="p">:</span><span class="n">offset</span> <span class="o">+</span> <span class="mi">4</span><span class="p">])[</span><span class="mi">0</span><span class="p">]</span>
            <span class="n">offset</span> <span class="o">+=</span> <span class="mi">4</span>

            <span class="c1"># Calculate total output value
</span>            <span class="n">total_output_value</span> <span class="o">=</span> <span class="nb">sum</span><span class="p">(</span><span class="n">tx_output</span><span class="p">[</span><span class="s">'value_satoshi'</span><span class="p">]</span> <span class="k">for</span> <span class="n">tx_output</span> <span class="ow">in</span> <span class="n">tx_outputs</span><span class="p">)</span>

            <span class="n">decoded_tx</span><span class="p">:</span> <span class="n">Transaction</span> <span class="o">=</span> <span class="p">{</span>
                <span class="s">'version'</span><span class="p">:</span> <span class="n">version</span><span class="p">,</span>
                <span class="s">'tx_type'</span><span class="p">:</span> <span class="s">'SegWit'</span> <span class="k">if</span> <span class="n">has_witness</span> <span class="k">else</span> <span class="s">'Legacy'</span><span class="p">,</span>
                <span class="s">'has_witness'</span><span class="p">:</span> <span class="n">has_witness</span><span class="p">,</span>
                <span class="s">'tx_input_count'</span><span class="p">:</span> <span class="n">tx_input_count</span><span class="p">,</span>
                <span class="s">'tx_inputs'</span><span class="p">:</span> <span class="n">tx_inputs</span><span class="p">,</span>
                <span class="s">'tx_output_count'</span><span class="p">:</span> <span class="n">tx_output_count</span><span class="p">,</span>
                <span class="s">'tx_outputs'</span><span class="p">:</span> <span class="n">tx_outputs</span><span class="p">,</span>
                <span class="s">'lock_time'</span><span class="p">:</span> <span class="n">lock_time</span><span class="p">,</span>
                <span class="s">'size_bytes'</span><span class="p">:</span> <span class="n">offset</span><span class="p">,</span>
                <span class="s">'total_output_value_satoshi'</span><span class="p">:</span> <span class="n">total_output_value</span><span class="p">,</span>
                <span class="s">'total_output_value_btc'</span><span class="p">:</span> <span class="n">total_output_value</span> <span class="o">/</span> <span class="mf">100000000.0</span><span class="p">,</span>
                <span class="s">'tx_witnesses'</span><span class="p">:</span> <span class="n">tx_witnesses</span>
            <span class="p">}</span>

        <span class="k">except</span> <span class="nb">ValueError</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
            <span class="k">raise</span> <span class="n">struct</span><span class="p">.</span><span class="n">error</span><span class="p">(</span><span class="sa">f</span><span class="s">"Failed to unpack transaction data: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s">"</span><span class="p">)</span> <span class="k">from</span> <span class="n">e</span>

        <span class="k">return</span> <span class="n">decoded_tx</span>

    <span class="c1"># --------------------------------------------------------------------------------------------
</span>    <span class="k">def</span> <span class="nf">extract_raw_txs</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">body</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">offset</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">0</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">list</span><span class="p">[</span><span class="nb">str</span><span class="p">]:</span>
        <span class="s">"""
        """</span>

        <span class="c1"># Validate data
</span>        <span class="n">match</span> <span class="n">body</span><span class="p">:</span>
            <span class="n">case</span> <span class="nb">str</span><span class="p">()</span> <span class="k">if</span> <span class="n">body</span><span class="p">.</span><span class="n">strip</span><span class="p">():</span>
                <span class="n">body</span> <span class="o">=</span> <span class="n">body</span><span class="p">.</span><span class="n">strip</span><span class="p">().</span><span class="n">lower</span><span class="p">()</span>
            <span class="n">case</span> <span class="n">_</span><span class="p">:</span>
                <span class="k">raise</span> <span class="nb">ValueError</span><span class="p">(</span><span class="s">"Block body data must be a non-empty string"</span><span class="p">)</span>

        <span class="c1"># Validate hex string format and convert to bytes
</span>        <span class="k">try</span><span class="p">:</span>
            <span class="n">body_bytes</span><span class="p">:</span> <span class="nb">bytes</span> <span class="o">=</span> <span class="nb">bytes</span><span class="p">.</span><span class="n">fromhex</span><span class="p">(</span><span class="n">body</span><span class="p">)</span>
        <span class="k">except</span> <span class="nb">ValueError</span> <span class="k">as</span> <span class="n">ex</span><span class="p">:</span>
            <span class="k">raise</span> <span class="nb">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s">"Invalid hex string: </span><span class="si">{</span><span class="n">ex</span><span class="si">}</span><span class="s">"</span><span class="p">)</span> <span class="k">from</span> <span class="n">ex</span>

        <span class="n">txs</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>

        <span class="k">try</span><span class="p">:</span>
            <span class="c1"># read transaction count
</span>            <span class="n">tx_count</span><span class="p">,</span> <span class="n">offset</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">decode_varint</span><span class="p">(</span><span class="n">body_bytes</span><span class="p">,</span> <span class="n">offset</span><span class="p">)</span>

            <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">tx_count</span><span class="p">):</span>
                <span class="n">start_offset</span> <span class="o">=</span> <span class="n">offset</span>

                <span class="c1"># --- parse just enough to find tx end ---
</span>                <span class="n">version</span> <span class="o">=</span> <span class="n">body_bytes</span><span class="p">[</span><span class="n">offset</span><span class="p">:</span><span class="n">offset</span> <span class="o">+</span> <span class="mi">4</span><span class="p">]</span>
                <span class="n">offset</span> <span class="o">+=</span> <span class="mi">4</span>

                <span class="n">has_witness</span> <span class="o">=</span> <span class="bp">False</span>
                <span class="k">if</span> <span class="n">body_bytes</span><span class="p">[</span><span class="n">offset</span><span class="p">]</span> <span class="o">==</span> <span class="mh">0x00</span> <span class="ow">and</span> <span class="n">body_bytes</span><span class="p">[</span><span class="n">offset</span> <span class="o">+</span> <span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="mh">0x01</span><span class="p">:</span>
                    <span class="n">has_witness</span> <span class="o">=</span> <span class="bp">True</span>
                    <span class="n">offset</span> <span class="o">+=</span> <span class="mi">2</span>

                <span class="c1"># inputs
</span>                <span class="n">tx_inputs_count</span><span class="p">,</span> <span class="n">offset</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">decode_varint</span><span class="p">(</span><span class="n">body_bytes</span><span class="p">,</span> <span class="n">offset</span><span class="p">)</span>

                <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">tx_inputs_count</span><span class="p">):</span>
                    <span class="n">offset</span> <span class="o">+=</span> <span class="mi">32</span>  <span class="c1"># prev txid
</span>                    <span class="n">offset</span> <span class="o">+=</span> <span class="mi">4</span>  <span class="c1"># index
</span>                    <span class="n">script_len</span><span class="p">,</span> <span class="n">offset</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">decode_varint</span><span class="p">(</span><span class="n">body_bytes</span><span class="p">,</span> <span class="n">offset</span><span class="p">)</span>
                    <span class="n">offset</span> <span class="o">+=</span> <span class="n">script_len</span>
                    <span class="n">offset</span> <span class="o">+=</span> <span class="mi">4</span>  <span class="c1"># sequence
</span>
                <span class="c1"># outputs
</span>                <span class="n">tx_outputs_count</span><span class="p">,</span> <span class="n">offset</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">decode_varint</span><span class="p">(</span><span class="n">body_bytes</span><span class="p">,</span> <span class="n">offset</span><span class="p">)</span>
                <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">tx_outputs_count</span><span class="p">):</span>
                    <span class="n">offset</span> <span class="o">+=</span> <span class="mi">8</span>  <span class="c1"># value
</span>                    <span class="n">script_len</span><span class="p">,</span> <span class="n">offset</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">decode_varint</span><span class="p">(</span><span class="n">body_bytes</span><span class="p">,</span> <span class="n">offset</span><span class="p">)</span>
                    <span class="n">offset</span> <span class="o">+=</span> <span class="n">script_len</span>

                <span class="c1"># witnesses
</span>                <span class="k">if</span> <span class="n">has_witness</span><span class="p">:</span>
                    <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">tx_inputs_count</span><span class="p">):</span>
                        <span class="n">n_stack</span><span class="p">,</span> <span class="n">offset</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">decode_varint</span><span class="p">(</span><span class="n">body_bytes</span><span class="p">,</span> <span class="n">offset</span><span class="p">)</span>
                        <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">n_stack</span><span class="p">):</span>
                            <span class="n">item_len</span><span class="p">,</span> <span class="n">offset</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">decode_varint</span><span class="p">(</span><span class="n">body_bytes</span><span class="p">,</span> <span class="n">offset</span><span class="p">)</span>
                            <span class="n">offset</span> <span class="o">+=</span> <span class="n">item_len</span>

                <span class="c1"># locktime
</span>                <span class="n">offset</span> <span class="o">+=</span> <span class="mi">4</span>

                <span class="c1"># slice raw tx
</span>                <span class="n">tx_end</span> <span class="o">=</span> <span class="n">offset</span>
                <span class="n">txs</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">body_bytes</span><span class="p">[</span><span class="n">start_offset</span><span class="p">:</span><span class="n">tx_end</span><span class="p">].</span><span class="nb">hex</span><span class="p">())</span>
        <span class="k">except</span> <span class="nb">ValueError</span> <span class="k">as</span> <span class="n">ex</span><span class="p">:</span>
            <span class="k">raise</span> <span class="nb">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s">"Error extracting raw txs: </span><span class="si">{</span><span class="n">ex</span><span class="si">}</span><span class="s">"</span><span class="p">)</span> <span class="k">from</span> <span class="n">ex</span>

        <span class="k">return</span> <span class="n">txs</span>

    <span class="c1"># --------------------------------------------------------------------------------------------
</span>    <span class="k">def</span> <span class="nf">decode_transaction_inputs_from_raw_tx</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">tx</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">offset</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">0</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">tuple</span><span class="p">[</span><span class="nb">list</span><span class="p">[</span><span class="n">TransactionInput</span><span class="p">],</span> <span class="nb">int</span><span class="p">]:</span>
        <span class="s">"""
        """</span>

        <span class="c1"># Validate and convert input
</span>        <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">tx</span><span class="p">,</span> <span class="nb">str</span><span class="p">)</span> <span class="ow">or</span> <span class="ow">not</span> <span class="n">tx</span><span class="p">.</span><span class="n">strip</span><span class="p">():</span>
            <span class="k">raise</span> <span class="nb">ValueError</span><span class="p">(</span><span class="s">"Transaction must be a non-empty string"</span><span class="p">)</span>

        <span class="k">try</span><span class="p">:</span>
            <span class="n">tx_bytes</span> <span class="o">=</span> <span class="nb">bytes</span><span class="p">.</span><span class="n">fromhex</span><span class="p">(</span><span class="n">tx</span><span class="p">.</span><span class="n">strip</span><span class="p">())</span>
        <span class="k">except</span> <span class="nb">ValueError</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
            <span class="k">raise</span> <span class="nb">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s">"Invalid hex string: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s">"</span><span class="p">)</span> <span class="k">from</span> <span class="n">e</span>

        <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">tx_bytes</span><span class="p">)</span> <span class="o">&lt;</span> <span class="mi">10</span><span class="p">:</span>  <span class="c1"># Minimum transaction size
</span>            <span class="k">raise</span> <span class="nb">ValueError</span><span class="p">(</span><span class="s">"Transaction too short to be valid"</span><span class="p">)</span>

        <span class="k">try</span><span class="p">:</span>
            <span class="c1"># Skip version (4 bytes)
</span>            <span class="n">offset</span> <span class="o">+=</span> <span class="mi">4</span>

            <span class="c1"># Check for SegWit marker and flag
</span>            <span class="n">has_witness</span> <span class="o">=</span> <span class="bp">False</span>
            <span class="k">if</span> <span class="n">offset</span> <span class="o">+</span> <span class="mi">1</span> <span class="o">&lt;</span> <span class="nb">len</span><span class="p">(</span><span class="n">tx_bytes</span><span class="p">)</span> <span class="ow">and</span> <span class="n">tx_bytes</span><span class="p">[</span><span class="n">offset</span><span class="p">]</span> <span class="o">==</span> <span class="mh">0x00</span> <span class="ow">and</span> <span class="n">tx_bytes</span><span class="p">[</span><span class="n">offset</span> <span class="o">+</span> <span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="mh">0x01</span><span class="p">:</span>
                <span class="n">has_witness</span> <span class="o">=</span> <span class="bp">True</span>
                <span class="n">offset</span> <span class="o">+=</span> <span class="mi">2</span>  <span class="c1"># Skip marker (0x00) and flag (0x01)
</span>
            <span class="c1"># Input count
</span>            <span class="n">tx_inputs_count</span><span class="p">,</span> <span class="n">offset</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">decode_varint</span><span class="p">(</span><span class="n">tx_bytes</span><span class="p">,</span> <span class="n">offset</span><span class="p">)</span>

            <span class="n">tx_inputs</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="n">TransactionInput</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>

            <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">tx_inputs_count</span><span class="p">):</span>
                <span class="n">prev_tx_hash</span> <span class="o">=</span> <span class="n">tx_bytes</span><span class="p">[</span><span class="n">offset</span><span class="p">:</span><span class="n">offset</span> <span class="o">+</span> <span class="mi">32</span><span class="p">][::</span><span class="o">-</span><span class="mi">1</span><span class="p">].</span><span class="nb">hex</span><span class="p">()</span>
                <span class="n">offset</span> <span class="o">+=</span> <span class="mi">32</span>

                <span class="n">prev_output_index</span> <span class="o">=</span> <span class="n">struct</span><span class="p">.</span><span class="n">unpack</span><span class="p">(</span><span class="s">"&lt;I"</span><span class="p">,</span> <span class="n">tx_bytes</span><span class="p">[</span><span class="n">offset</span><span class="p">:</span><span class="n">offset</span> <span class="o">+</span> <span class="mi">4</span><span class="p">])[</span><span class="mi">0</span><span class="p">]</span>
                <span class="n">offset</span> <span class="o">+=</span> <span class="mi">4</span>

                <span class="n">script_len</span><span class="p">,</span> <span class="n">offset</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">decode_varint</span><span class="p">(</span><span class="n">tx_bytes</span><span class="p">,</span> <span class="n">offset</span><span class="p">)</span>

                <span class="n">script_sig</span> <span class="o">=</span> <span class="n">tx_bytes</span><span class="p">[</span><span class="n">offset</span><span class="p">:</span><span class="n">offset</span> <span class="o">+</span> <span class="n">script_len</span><span class="p">].</span><span class="nb">hex</span><span class="p">()</span>
                <span class="n">offset</span> <span class="o">+=</span> <span class="n">script_len</span>

                <span class="n">sequence</span> <span class="o">=</span> <span class="n">struct</span><span class="p">.</span><span class="n">unpack</span><span class="p">(</span><span class="s">"&lt;I"</span><span class="p">,</span> <span class="n">tx_bytes</span><span class="p">[</span><span class="n">offset</span><span class="p">:</span><span class="n">offset</span> <span class="o">+</span> <span class="mi">4</span><span class="p">])[</span><span class="mi">0</span><span class="p">]</span>
                <span class="n">offset</span> <span class="o">+=</span> <span class="mi">4</span>

                <span class="n">is_coinbase</span> <span class="o">=</span> <span class="p">(</span><span class="n">prev_tx_hash</span> <span class="o">==</span> <span class="s">"00"</span> <span class="o">*</span> <span class="mi">32</span> <span class="ow">and</span> <span class="n">prev_output_index</span> <span class="o">==</span> <span class="mh">0xFFFFFFFF</span><span class="p">)</span>

                <span class="n">tx_inputs</span><span class="p">.</span><span class="n">append</span><span class="p">({</span>
                    <span class="s">"previous_tx_hash"</span><span class="p">:</span> <span class="n">prev_tx_hash</span><span class="p">,</span>
                    <span class="s">"previous_output_index"</span><span class="p">:</span> <span class="n">prev_output_index</span><span class="p">,</span>
                    <span class="s">"script_sig"</span><span class="p">:</span> <span class="n">script_sig</span><span class="p">,</span>
                    <span class="s">"script_sig_length"</span><span class="p">:</span> <span class="nb">hex</span><span class="p">(</span><span class="n">script_len</span><span class="p">),</span>
                    <span class="s">"sequence"</span><span class="p">:</span> <span class="nb">hex</span><span class="p">(</span><span class="n">sequence</span><span class="p">),</span>
                    <span class="s">"is_coinbase"</span><span class="p">:</span> <span class="n">is_coinbase</span><span class="p">,</span>
                <span class="p">})</span>
        <span class="k">except</span> <span class="p">(</span><span class="n">struct</span><span class="p">.</span><span class="n">error</span><span class="p">,</span> <span class="nb">IndexError</span><span class="p">)</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
            <span class="k">raise</span> <span class="nb">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s">"Failed to decode transaction: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s">"</span><span class="p">)</span> <span class="k">from</span> <span class="n">e</span>
        <span class="k">return</span> <span class="n">tx_inputs</span><span class="p">,</span> <span class="n">offset</span>

    <span class="c1"># -------------------------------------------------------------------------------------------------
</span>    <span class="k">def</span> <span class="nf">decode_transaction_outputs_from_raw_tx</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">tx</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">offset</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">0</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">tuple</span><span class="p">[</span><span class="nb">list</span><span class="p">[</span><span class="n">TransactionOutput</span><span class="p">],</span> <span class="nb">int</span><span class="p">]:</span>
        <span class="s">"""
        """</span>

        <span class="c1"># Validate and convert input
</span>        <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">tx</span><span class="p">,</span> <span class="nb">str</span><span class="p">)</span> <span class="ow">or</span> <span class="ow">not</span> <span class="n">tx</span><span class="p">.</span><span class="n">strip</span><span class="p">():</span>
            <span class="k">raise</span> <span class="nb">ValueError</span><span class="p">(</span><span class="s">"Transaction must be a non-empty string"</span><span class="p">)</span>

        <span class="k">try</span><span class="p">:</span>
            <span class="n">tx_bytes</span> <span class="o">=</span> <span class="nb">bytes</span><span class="p">.</span><span class="n">fromhex</span><span class="p">(</span><span class="n">tx</span><span class="p">.</span><span class="n">strip</span><span class="p">())</span>
        <span class="k">except</span> <span class="nb">ValueError</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
            <span class="k">raise</span> <span class="nb">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s">"Invalid hex string: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s">"</span><span class="p">)</span> <span class="k">from</span> <span class="n">e</span>

        <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">tx_bytes</span><span class="p">)</span> <span class="o">&lt;</span> <span class="mi">10</span><span class="p">:</span>  <span class="c1"># Minimum transaction size
</span>            <span class="k">raise</span> <span class="nb">ValueError</span><span class="p">(</span><span class="s">"Transaction too short to be valid"</span><span class="p">)</span>

        <span class="k">try</span><span class="p">:</span>
            <span class="c1"># Skip version (4 bytes)
</span>            <span class="n">offset</span> <span class="o">+=</span> <span class="mi">4</span>

            <span class="c1"># Check for SegWit marker and flag
</span>            <span class="n">has_witness</span> <span class="o">=</span> <span class="bp">False</span>
            <span class="k">if</span> <span class="n">offset</span> <span class="o">+</span> <span class="mi">1</span> <span class="o">&lt;</span> <span class="nb">len</span><span class="p">(</span><span class="n">tx_bytes</span><span class="p">)</span> <span class="ow">and</span> <span class="n">tx_bytes</span><span class="p">[</span><span class="n">offset</span><span class="p">]</span> <span class="o">==</span> <span class="mh">0x00</span> <span class="ow">and</span> <span class="n">tx_bytes</span><span class="p">[</span><span class="n">offset</span> <span class="o">+</span> <span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="mh">0x01</span><span class="p">:</span>
                <span class="n">has_witness</span> <span class="o">=</span> <span class="bp">True</span>
                <span class="n">offset</span> <span class="o">+=</span> <span class="mi">2</span>  <span class="c1"># Skip marker (0x00) and flag (0x01)
</span>
            <span class="c1"># Input count and skip inputs
</span>            <span class="n">tx_inputs_count</span><span class="p">,</span> <span class="n">offset</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">decode_varint</span><span class="p">(</span><span class="n">tx_bytes</span><span class="p">,</span> <span class="n">offset</span><span class="p">)</span>

            <span class="c1"># Skip all inputs
</span>            <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">tx_inputs_count</span><span class="p">):</span>
                <span class="c1"># Skip previous tx hash (32 bytes) + output index (4 bytes)
</span>                <span class="n">offset</span> <span class="o">+=</span> <span class="mi">36</span>

                <span class="c1"># Skip script sig
</span>                <span class="n">script_pubkey_length</span><span class="p">,</span> <span class="n">offset</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">decode_varint</span><span class="p">(</span><span class="n">tx_bytes</span><span class="p">,</span> <span class="n">offset</span><span class="p">)</span>
                <span class="n">offset</span> <span class="o">+=</span> <span class="n">script_pubkey_length</span>

                <span class="c1"># Skip sequence (4 bytes)
</span>                <span class="n">offset</span> <span class="o">+=</span> <span class="mi">4</span>

            <span class="c1"># Output count
</span>            <span class="n">tx_outputs_count</span><span class="p">,</span> <span class="n">offset</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">decode_varint</span><span class="p">(</span><span class="n">tx_bytes</span><span class="p">,</span> <span class="n">offset</span><span class="p">)</span>

            <span class="n">tx_outputs</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="n">TransactionOutput</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>

            <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">tx_outputs_count</span><span class="p">):</span>
                <span class="k">if</span> <span class="n">offset</span> <span class="o">+</span> <span class="mi">8</span> <span class="o">&gt;</span> <span class="nb">len</span><span class="p">(</span><span class="n">tx_bytes</span><span class="p">):</span>
                    <span class="k">raise</span> <span class="nb">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s">"Insufficient data for output </span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s"> value"</span><span class="p">)</span>

                <span class="c1"># Value (8 bytes, little-endian)
</span>                <span class="n">value_satoshi</span> <span class="o">=</span> <span class="n">struct</span><span class="p">.</span><span class="n">unpack</span><span class="p">(</span><span class="s">"&lt;Q"</span><span class="p">,</span> <span class="n">tx_bytes</span><span class="p">[</span><span class="n">offset</span><span class="p">:</span><span class="n">offset</span> <span class="o">+</span> <span class="mi">8</span><span class="p">])[</span><span class="mi">0</span><span class="p">]</span>
                <span class="n">offset</span> <span class="o">+=</span> <span class="mi">8</span>

                <span class="c1"># Script length and script
</span>                <span class="n">script_pubkey_length</span><span class="p">,</span> <span class="n">offset</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">decode_varint</span><span class="p">(</span><span class="n">tx_bytes</span><span class="p">,</span> <span class="n">offset</span><span class="p">)</span>

                <span class="k">if</span> <span class="n">offset</span> <span class="o">+</span> <span class="n">script_pubkey_length</span> <span class="o">&gt;</span> <span class="nb">len</span><span class="p">(</span><span class="n">tx_bytes</span><span class="p">):</span>
                    <span class="k">raise</span> <span class="nb">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s">"Insufficient data for output </span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s"> script"</span><span class="p">)</span>

                <span class="n">script_pubkey</span> <span class="o">=</span> <span class="n">tx_bytes</span><span class="p">[</span><span class="n">offset</span><span class="p">:</span><span class="n">offset</span> <span class="o">+</span> <span class="n">script_pubkey_length</span><span class="p">].</span><span class="nb">hex</span><span class="p">()</span>
                <span class="n">offset</span> <span class="o">+=</span> <span class="n">script_pubkey_length</span>

                <span class="n">block_tx_output</span><span class="p">:</span> <span class="n">TransactionOutput</span> <span class="o">=</span> <span class="p">{</span>
                    <span class="s">"value_satoshi"</span><span class="p">:</span> <span class="n">value_satoshi</span><span class="p">,</span>
                    <span class="s">"value_btc"</span><span class="p">:</span> <span class="n">value_satoshi</span> <span class="o">/</span> <span class="mf">100000000.0</span><span class="p">,</span>
                    <span class="s">"script_pubkey"</span><span class="p">:</span> <span class="n">script_pubkey</span><span class="p">,</span>
                    <span class="s">"script_pubkey_length"</span><span class="p">:</span> <span class="n">script_pubkey_length</span>
                <span class="p">}</span>

                <span class="n">tx_outputs</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">block_tx_output</span><span class="p">)</span>

        <span class="k">except</span> <span class="p">(</span><span class="n">struct</span><span class="p">.</span><span class="n">error</span><span class="p">,</span> <span class="nb">IndexError</span><span class="p">)</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
            <span class="k">raise</span> <span class="nb">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s">"Failed to decode transaction: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s">"</span><span class="p">)</span> <span class="k">from</span> <span class="n">e</span>

        <span class="k">return</span> <span class="n">tx_outputs</span><span class="p">,</span> <span class="n">offset</span>

    <span class="k">def</span> <span class="nf">decode_transaction_witnesses_from_raw_tx</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">tx</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">tuple</span><span class="p">[</span><span class="nb">list</span><span class="p">[</span><span class="n">TransactionWitness</span><span class="p">],</span> <span class="nb">int</span><span class="p">]:</span>
        <span class="s">"""
        """</span>
        <span class="c1"># Validate and convert input
</span>        <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">tx</span><span class="p">,</span> <span class="nb">str</span><span class="p">)</span> <span class="ow">or</span> <span class="ow">not</span> <span class="n">tx</span><span class="p">.</span><span class="n">strip</span><span class="p">():</span>
            <span class="k">raise</span> <span class="nb">ValueError</span><span class="p">(</span><span class="s">"Transaction must be a non-empty string"</span><span class="p">)</span>

        <span class="k">try</span><span class="p">:</span>
            <span class="n">tx_bytes</span> <span class="o">=</span> <span class="nb">bytes</span><span class="p">.</span><span class="n">fromhex</span><span class="p">(</span><span class="n">tx</span><span class="p">.</span><span class="n">strip</span><span class="p">())</span>
        <span class="k">except</span> <span class="nb">ValueError</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
            <span class="k">raise</span> <span class="nb">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s">"Invalid hex string: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s">"</span><span class="p">)</span> <span class="k">from</span> <span class="n">e</span>

        <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">tx_bytes</span><span class="p">)</span> <span class="o">&lt;</span> <span class="mi">10</span><span class="p">:</span>  <span class="c1"># Minimum transaction size
</span>            <span class="k">raise</span> <span class="nb">ValueError</span><span class="p">(</span><span class="s">"Transaction too short to be valid"</span><span class="p">)</span>

        <span class="n">offset</span> <span class="o">=</span> <span class="mi">0</span>

        <span class="k">try</span><span class="p">:</span>
            <span class="c1"># Skip version (4 bytes)
</span>            <span class="n">offset</span> <span class="o">+=</span> <span class="mi">4</span>

            <span class="c1"># Check for SegWit marker + flag
</span>            <span class="k">if</span> <span class="ow">not</span> <span class="p">(</span><span class="n">offset</span> <span class="o">+</span> <span class="mi">1</span> <span class="o">&lt;</span> <span class="nb">len</span><span class="p">(</span><span class="n">tx_bytes</span><span class="p">)</span> <span class="ow">and</span>
                    <span class="n">tx_bytes</span><span class="p">[</span><span class="n">offset</span><span class="p">]</span> <span class="o">==</span> <span class="mh">0x00</span> <span class="ow">and</span>
                    <span class="n">tx_bytes</span><span class="p">[</span><span class="n">offset</span> <span class="o">+</span> <span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="mh">0x01</span><span class="p">):</span>
                <span class="k">raise</span> <span class="nb">ValueError</span><span class="p">(</span><span class="s">"Transaction is not SegWit format (no witness marker/flag)"</span><span class="p">)</span>

            <span class="n">offset</span> <span class="o">+=</span> <span class="mi">2</span>  <span class="c1"># Skip marker and flag
</span>
            <span class="c1"># Input count
</span>            <span class="n">input_count</span><span class="p">,</span> <span class="n">offset</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">decode_varint</span><span class="p">(</span><span class="n">tx_bytes</span><span class="p">,</span> <span class="n">offset</span><span class="p">)</span>

            <span class="c1"># Skip all inputs
</span>            <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">input_count</span><span class="p">):</span>
                <span class="c1"># Skip previous tx hash (32 bytes) + output index (4 bytes)
</span>                <span class="n">offset</span> <span class="o">+=</span> <span class="mi">36</span>

                <span class="c1"># Skip script sig
</span>                <span class="n">script_len</span><span class="p">,</span> <span class="n">offset</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">decode_varint</span><span class="p">(</span><span class="n">tx_bytes</span><span class="p">,</span> <span class="n">offset</span><span class="p">)</span>
                <span class="n">offset</span> <span class="o">+=</span> <span class="n">script_len</span>

                <span class="c1"># Skip sequence (4 bytes)
</span>                <span class="n">offset</span> <span class="o">+=</span> <span class="mi">4</span>

            <span class="c1"># Skip outputs
</span>            <span class="n">output_count</span><span class="p">,</span> <span class="n">offset</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">decode_varint</span><span class="p">(</span><span class="n">tx_bytes</span><span class="p">,</span> <span class="n">offset</span><span class="p">)</span>

            <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">output_count</span><span class="p">):</span>
                <span class="c1"># Skip value (8 bytes)
</span>                <span class="n">offset</span> <span class="o">+=</span> <span class="mi">8</span>

                <span class="c1"># Skip script pubkey
</span>                <span class="n">script_len</span><span class="p">,</span> <span class="n">offset</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">decode_varint</span><span class="p">(</span><span class="n">tx_bytes</span><span class="p">,</span> <span class="n">offset</span><span class="p">)</span>
                <span class="n">offset</span> <span class="o">+=</span> <span class="n">script_len</span>

            <span class="c1"># Now decode witness data
</span>            <span class="n">witnesses</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="n">TransactionWitness</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>

            <span class="k">for</span> <span class="n">input_index</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">input_count</span><span class="p">):</span>
                <span class="c1"># Number of witness items for this input
</span>                <span class="n">witness_count</span><span class="p">,</span> <span class="n">offset</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">decode_varint</span><span class="p">(</span><span class="n">tx_bytes</span><span class="p">,</span> <span class="n">offset</span><span class="p">)</span>

                <span class="n">witness_items</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="n">WitnessItem</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
                <span class="n">total_witness_size</span> <span class="o">=</span> <span class="mi">0</span>

                <span class="c1"># Decode each witness item
</span>                <span class="k">for</span> <span class="n">item_index</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">witness_count</span><span class="p">):</span>
                    <span class="c1"># Length of this witness item
</span>                    <span class="n">item_len</span><span class="p">,</span> <span class="n">offset</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">decode_varint</span><span class="p">(</span><span class="n">tx_bytes</span><span class="p">,</span> <span class="n">offset</span><span class="p">)</span>

                    <span class="k">if</span> <span class="n">offset</span> <span class="o">+</span> <span class="n">item_len</span> <span class="o">&gt;</span> <span class="nb">len</span><span class="p">(</span><span class="n">tx_bytes</span><span class="p">):</span>
                        <span class="k">raise</span> <span class="nb">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s">"Insufficient data for witness item </span><span class="si">{</span><span class="n">item_index</span><span class="si">}</span><span class="s"> of input </span><span class="si">{</span><span class="n">input_index</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>

                    <span class="c1"># Extract witness item data
</span>                    <span class="n">item_data</span> <span class="o">=</span> <span class="n">tx_bytes</span><span class="p">[</span><span class="n">offset</span><span class="p">:</span><span class="n">offset</span> <span class="o">+</span> <span class="n">item_len</span><span class="p">]</span>
                    <span class="n">offset</span> <span class="o">+=</span> <span class="n">item_len</span>

                    <span class="c1"># Analyze the witness item
</span>                    <span class="n">witness_item</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">decode_witness_item</span><span class="p">(</span><span class="n">item_data</span><span class="p">,</span> <span class="n">item_index</span><span class="p">,</span> <span class="n">witness_count</span><span class="p">)</span>
                    <span class="n">witness_items</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">witness_item</span><span class="p">)</span>
                    <span class="n">total_witness_size</span> <span class="o">+=</span> <span class="n">item_len</span>

                <span class="c1"># Determine witness type
</span>                <span class="n">witness_type</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">determine_witness_type</span><span class="p">(</span><span class="n">witness_count</span><span class="p">,</span> <span class="n">witness_items</span><span class="p">)</span>

                <span class="n">witnesses</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">TransactionWitness</span><span class="p">(</span>
                    <span class="n">input_index</span><span class="o">=</span><span class="n">input_index</span><span class="p">,</span>
                    <span class="n">witness_count</span><span class="o">=</span><span class="n">witness_count</span><span class="p">,</span>
                    <span class="n">witness_items</span><span class="o">=</span><span class="n">witness_items</span><span class="p">,</span>
                    <span class="n">witness_type</span><span class="o">=</span><span class="n">witness_type</span><span class="p">,</span>
                    <span class="n">total_witness_size</span><span class="o">=</span><span class="n">total_witness_size</span><span class="p">,</span>
                <span class="p">))</span>

        <span class="k">except</span> <span class="p">(</span><span class="n">struct</span><span class="p">.</span><span class="n">error</span><span class="p">,</span> <span class="nb">IndexError</span><span class="p">)</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
            <span class="k">raise</span> <span class="nb">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s">"Failed to decode transaction witnesses: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s">"</span><span class="p">)</span> <span class="k">from</span> <span class="n">e</span>

        <span class="k">return</span> <span class="n">witnesses</span><span class="p">,</span> <span class="n">offset</span>

    <span class="c1"># -------------------------------------------------------------------------------------------------
</span>    <span class="k">def</span> <span class="nf">decode_witness_item</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">data</span><span class="p">:</span> <span class="nb">bytes</span><span class="p">,</span> <span class="n">index</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">witness_count</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">WitnessItem</span><span class="p">:</span>
        <span class="s">"""
        """</span>
        <span class="n">hex_data</span> <span class="o">=</span> <span class="n">data</span><span class="p">.</span><span class="nb">hex</span><span class="p">()</span>
        <span class="n">length</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>

        <span class="c1"># Empty witness item
</span>        <span class="k">if</span> <span class="n">length</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
            <span class="k">return</span> <span class="n">WitnessItem</span><span class="p">(</span>
                <span class="n">data</span><span class="o">=</span><span class="s">""</span><span class="p">,</span>
                <span class="n">length</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span>
                <span class="nb">type</span><span class="o">=</span><span class="s">"EMPTY"</span><span class="p">,</span>
                <span class="n">description</span><span class="o">=</span><span class="s">"Empty witness item"</span>
            <span class="p">)</span>

        <span class="c1"># For P2WPKH (2 items: signature + pubkey)
</span>        <span class="k">if</span> <span class="n">witness_count</span> <span class="o">==</span> <span class="mi">2</span><span class="p">:</span>
            <span class="k">if</span> <span class="n">index</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
                <span class="c1"># First item should be signature (typically 70-72 bytes with DER encoding + sighash)
</span>                <span class="k">if</span> <span class="mi">70</span> <span class="o">&lt;=</span> <span class="n">length</span> <span class="o">&lt;=</span> <span class="mi">73</span><span class="p">:</span>
                    <span class="n">sighash_type</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="k">if</span> <span class="n">length</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="k">else</span> <span class="mi">0</span>
                    <span class="n">sighash_desc</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">get_sighash_description</span><span class="p">(</span><span class="n">sighash_type</span><span class="p">)</span>
                    <span class="k">return</span> <span class="n">WitnessItem</span><span class="p">(</span>
                        <span class="n">data</span><span class="o">=</span><span class="n">hex_data</span><span class="p">,</span>
                        <span class="n">length</span><span class="o">=</span><span class="n">length</span><span class="p">,</span>
                        <span class="nb">type</span><span class="o">=</span><span class="s">"SIGNATURE"</span><span class="p">,</span>
                        <span class="n">description</span><span class="o">=</span><span class="sa">f</span><span class="s">"ECDSA signature (</span><span class="si">{</span><span class="n">length</span><span class="si">}</span><span class="s"> bytes) - </span><span class="si">{</span><span class="n">sighash_desc</span><span class="si">}</span><span class="s">"</span>
                    <span class="p">)</span>
                <span class="k">else</span><span class="p">:</span>
                    <span class="k">return</span> <span class="n">WitnessItem</span><span class="p">(</span>
                        <span class="n">data</span><span class="o">=</span><span class="n">hex_data</span><span class="p">,</span>
                        <span class="n">length</span><span class="o">=</span><span class="n">length</span><span class="p">,</span>
                        <span class="nb">type</span><span class="o">=</span><span class="s">"SIGNATURE"</span><span class="p">,</span>
                        <span class="n">description</span><span class="o">=</span><span class="sa">f</span><span class="s">"ECDSA signature (</span><span class="si">{</span><span class="n">length</span><span class="si">}</span><span class="s"> bytes) - non-standard length"</span>
                    <span class="p">)</span>
            <span class="k">elif</span> <span class="n">index</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span>
                <span class="c1"># Second item should be public key (33 bytes compressed or 65 bytes uncompressed)
</span>                <span class="k">if</span> <span class="n">length</span> <span class="o">==</span> <span class="mi">33</span><span class="p">:</span>
                    <span class="k">return</span> <span class="n">WitnessItem</span><span class="p">(</span>
                        <span class="n">data</span><span class="o">=</span><span class="n">hex_data</span><span class="p">,</span>
                        <span class="n">length</span><span class="o">=</span><span class="n">length</span><span class="p">,</span>
                        <span class="nb">type</span><span class="o">=</span><span class="s">"PUBLIC_KEY"</span><span class="p">,</span>
                        <span class="n">description</span><span class="o">=</span><span class="s">"Compressed public key (33 bytes)"</span>
                    <span class="p">)</span>
                <span class="k">elif</span> <span class="n">length</span> <span class="o">==</span> <span class="mi">65</span><span class="p">:</span>
                    <span class="k">return</span> <span class="n">WitnessItem</span><span class="p">(</span>
                        <span class="n">data</span><span class="o">=</span><span class="n">hex_data</span><span class="p">,</span>
                        <span class="n">length</span><span class="o">=</span><span class="n">length</span><span class="p">,</span>
                        <span class="nb">type</span><span class="o">=</span><span class="s">"PUBLIC_KEY"</span><span class="p">,</span>
                        <span class="n">description</span><span class="o">=</span><span class="s">"Uncompressed public key (65 bytes)"</span>
                    <span class="p">)</span>
                <span class="k">else</span><span class="p">:</span>
                    <span class="k">return</span> <span class="n">WitnessItem</span><span class="p">(</span>
                        <span class="n">data</span><span class="o">=</span><span class="n">hex_data</span><span class="p">,</span>
                        <span class="n">length</span><span class="o">=</span><span class="n">length</span><span class="p">,</span>
                        <span class="nb">type</span><span class="o">=</span><span class="s">"PUBLIC_KEY"</span><span class="p">,</span>
                        <span class="n">description</span><span class="o">=</span><span class="sa">f</span><span class="s">"Public key (</span><span class="si">{</span><span class="n">length</span><span class="si">}</span><span class="s"> bytes) - non-standard length"</span>
                    <span class="p">)</span>

        <span class="c1"># For P2WSH (multisig or script)
</span>        <span class="k">elif</span> <span class="n">witness_count</span> <span class="o">&gt;</span> <span class="mi">2</span><span class="p">:</span>
            <span class="k">if</span> <span class="n">index</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
                <span class="c1"># First item is typically empty for multisig due to OP_CHECKMULTISIG bug
</span>                <span class="k">if</span> <span class="n">length</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
                    <span class="k">return</span> <span class="n">WitnessItem</span><span class="p">(</span>
                        <span class="n">data</span><span class="o">=</span><span class="n">hex_data</span><span class="p">,</span>
                        <span class="n">length</span><span class="o">=</span><span class="n">length</span><span class="p">,</span>
                        <span class="nb">type</span><span class="o">=</span><span class="s">"EMPTY"</span><span class="p">,</span>
                        <span class="n">description</span><span class="o">=</span><span class="s">"Empty item (OP_CHECKMULTISIG dummy)"</span>
                    <span class="p">)</span>
            <span class="k">elif</span> <span class="n">index</span> <span class="o">==</span> <span class="n">witness_count</span> <span class="o">-</span> <span class="mi">1</span><span class="p">:</span>
                <span class="c1"># Last item is typically the redeem script
</span>                <span class="k">return</span> <span class="n">WitnessItem</span><span class="p">(</span>
                    <span class="n">data</span><span class="o">=</span><span class="n">hex_data</span><span class="p">,</span>
                    <span class="n">length</span><span class="o">=</span><span class="n">length</span><span class="p">,</span>
                    <span class="nb">type</span><span class="o">=</span><span class="s">"REDEEM_SCRIPT"</span><span class="p">,</span>
                    <span class="n">description</span><span class="o">=</span><span class="sa">f</span><span class="s">"Witness script/redeem script (</span><span class="si">{</span><span class="n">length</span><span class="si">}</span><span class="s"> bytes)"</span>
                <span class="p">)</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="c1"># Middle items are typically signatures
</span>                <span class="k">if</span> <span class="mi">70</span> <span class="o">&lt;=</span> <span class="n">length</span> <span class="o">&lt;=</span> <span class="mi">73</span><span class="p">:</span>
                    <span class="n">sighash_type</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="k">if</span> <span class="n">length</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="k">else</span> <span class="mi">0</span>
                    <span class="n">sighash_desc</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">get_sighash_description</span><span class="p">(</span><span class="n">sighash_type</span><span class="p">)</span>
                    <span class="k">return</span> <span class="n">WitnessItem</span><span class="p">(</span>
                        <span class="n">data</span><span class="o">=</span><span class="n">hex_data</span><span class="p">,</span>
                        <span class="n">length</span><span class="o">=</span><span class="n">length</span><span class="p">,</span>
                        <span class="nb">type</span><span class="o">=</span><span class="s">"SIGNATURE"</span><span class="p">,</span>
                        <span class="n">description</span><span class="o">=</span><span class="sa">f</span><span class="s">"ECDSA signature (</span><span class="si">{</span><span class="n">length</span><span class="si">}</span><span class="s"> bytes) - </span><span class="si">{</span><span class="n">sighash_desc</span><span class="si">}</span><span class="s">"</span>
                    <span class="p">)</span>
                <span class="k">else</span><span class="p">:</span>
                    <span class="k">return</span> <span class="n">WitnessItem</span><span class="p">(</span>
                        <span class="n">data</span><span class="o">=</span><span class="n">hex_data</span><span class="p">,</span>
                        <span class="n">length</span><span class="o">=</span><span class="n">length</span><span class="p">,</span>
                        <span class="nb">type</span><span class="o">=</span><span class="s">"SIGNATURE"</span><span class="p">,</span>
                        <span class="n">description</span><span class="o">=</span><span class="sa">f</span><span class="s">"ECDSA signature (</span><span class="si">{</span><span class="n">length</span><span class="si">}</span><span class="s"> bytes) - non-standard length"</span>
                    <span class="p">)</span>

        <span class="c1"># Single witness item (unusual)
</span>        <span class="k">elif</span> <span class="n">witness_count</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span>
            <span class="k">return</span> <span class="n">WitnessItem</span><span class="p">(</span>
                <span class="n">data</span><span class="o">=</span><span class="n">hex_data</span><span class="p">,</span>
                <span class="n">length</span><span class="o">=</span><span class="n">length</span><span class="p">,</span>
                <span class="nb">type</span><span class="o">=</span><span class="s">"UNKNOWN"</span><span class="p">,</span>
                <span class="n">description</span><span class="o">=</span><span class="sa">f</span><span class="s">"Single witness item (</span><span class="si">{</span><span class="n">length</span><span class="si">}</span><span class="s"> bytes) - possibly custom script"</span>
            <span class="p">)</span>

        <span class="c1"># Default case
</span>        <span class="k">return</span> <span class="n">WitnessItem</span><span class="p">(</span>
            <span class="n">data</span><span class="o">=</span><span class="n">hex_data</span><span class="p">,</span>
            <span class="n">length</span><span class="o">=</span><span class="n">length</span><span class="p">,</span>
            <span class="nb">type</span><span class="o">=</span><span class="s">"UNKNOWN"</span><span class="p">,</span>
            <span class="n">description</span><span class="o">=</span><span class="sa">f</span><span class="s">"Unknown witness data (</span><span class="si">{</span><span class="n">length</span><span class="si">}</span><span class="s"> bytes)"</span>
        <span class="p">)</span>

    <span class="c1"># -------------------------------------------------------------------------------------------------
</span>    <span class="o">@</span><span class="nb">staticmethod</span>
    <span class="k">def</span> <span class="nf">determine_witness_type</span><span class="p">(</span><span class="n">witness_count</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">witness_items</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="n">WitnessItem</span><span class="p">],</span> <span class="o">/</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
        <span class="s">"""
        Determine the overall witness type based on witness items.

        Args:
            witness_count: Number of witness items
            witness_items: List of analyzed witness items

        Returns:
            String describing the witness type
        """</span>
        <span class="n">match</span> <span class="n">witness_count</span><span class="p">:</span>
            <span class="n">case</span> <span class="mi">0</span><span class="p">:</span>
                <span class="k">return</span> <span class="s">"NO_WITNESS"</span>
            <span class="n">case</span> <span class="mi">1</span><span class="p">:</span>
                <span class="k">return</span> <span class="s">"CUSTOM_SCRIPT"</span>
            <span class="n">case</span> <span class="mi">2</span><span class="p">:</span>
                <span class="c1"># P2WPKH pattern: signature + pubkey
</span>                <span class="k">if</span> <span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">witness_items</span><span class="p">)</span> <span class="o">==</span> <span class="mi">2</span> <span class="ow">and</span>
                        <span class="n">witness_items</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">get</span><span class="p">(</span><span class="s">"type"</span><span class="p">)</span> <span class="o">==</span> <span class="s">"SIGNATURE"</span> <span class="ow">and</span>
                        <span class="n">witness_items</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">get</span><span class="p">(</span><span class="s">"type"</span><span class="p">)</span> <span class="o">==</span> <span class="s">"PUBLIC_KEY"</span><span class="p">):</span>
                    <span class="k">return</span> <span class="s">"P2WPKH"</span>
                <span class="k">else</span><span class="p">:</span>
                    <span class="k">return</span> <span class="s">"UNKNOWN_2_ITEM"</span>
            <span class="n">case</span> <span class="n">count</span> <span class="k">if</span> <span class="n">count</span> <span class="o">&gt;</span> <span class="mi">2</span><span class="p">:</span>
                <span class="c1"># P2WSH multisig pattern: empty + signatures + script
</span>                <span class="k">if</span> <span class="p">(</span><span class="n">witness_items</span> <span class="ow">and</span>
                        <span class="n">witness_items</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">get</span><span class="p">(</span><span class="s">"type"</span><span class="p">)</span> <span class="o">==</span> <span class="s">"EMPTY"</span> <span class="ow">and</span>
                        <span class="n">witness_items</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">].</span><span class="n">get</span><span class="p">(</span><span class="s">"type"</span><span class="p">)</span> <span class="o">==</span> <span class="s">"REDEEM_SCRIPT"</span><span class="p">):</span>
                    <span class="n">sig_count</span> <span class="o">=</span> <span class="nb">sum</span><span class="p">(</span><span class="mi">1</span> <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">witness_items</span><span class="p">[</span><span class="mi">1</span><span class="p">:</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
                                    <span class="k">if</span> <span class="n">item</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">"type"</span><span class="p">)</span> <span class="o">==</span> <span class="s">"SIGNATURE"</span><span class="p">)</span>
                    <span class="k">return</span> <span class="sa">f</span><span class="s">"P2WSH_MULTISIG_</span><span class="si">{</span><span class="n">sig_count</span><span class="si">}</span><span class="s">_OF_N"</span>
                <span class="k">elif</span> <span class="n">witness_items</span> <span class="ow">and</span> <span class="n">witness_items</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">].</span><span class="n">get</span><span class="p">(</span><span class="s">"type"</span><span class="p">)</span> <span class="o">==</span> <span class="s">"REDEEM_SCRIPT"</span><span class="p">:</span>
                    <span class="k">return</span> <span class="s">"P2WSH_CUSTOM_SCRIPT"</span>
                <span class="k">else</span><span class="p">:</span>
                    <span class="k">return</span> <span class="sa">f</span><span class="s">"COMPLEX_WITNESS_</span><span class="si">{</span><span class="n">count</span><span class="si">}</span><span class="s">_ITEMS"</span>
            <span class="n">case</span> <span class="n">_</span><span class="p">:</span>
                <span class="k">return</span> <span class="s">"UNKNOWN_WITNESS"</span>

    <span class="c1"># -------------------------------------------------------------------------------------------------
</span>    <span class="o">@</span><span class="nb">staticmethod</span>
    <span class="k">def</span> <span class="nf">get_sighash_description</span><span class="p">(</span><span class="n">sighash_type</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="o">/</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
        <span class="s">"""
        Get description of sighash type.

        Args:
            sighash_type: Sighash type byte

        Returns:
            Human-readable description of sighash type
        """</span>
        <span class="n">base_type</span> <span class="o">=</span> <span class="n">sighash_type</span> <span class="o">&amp;</span> <span class="mh">0x1f</span>
        <span class="n">anyonecanpay</span> <span class="o">=</span> <span class="nb">bool</span><span class="p">(</span><span class="n">sighash_type</span> <span class="o">&amp;</span> <span class="mh">0x80</span><span class="p">)</span>

        <span class="n">match</span> <span class="n">base_type</span><span class="p">:</span>
            <span class="n">case</span> <span class="mh">0x01</span><span class="p">:</span>
                <span class="n">base_desc</span> <span class="o">=</span> <span class="s">"SIGHASH_ALL"</span>
            <span class="n">case</span> <span class="mh">0x02</span><span class="p">:</span>
                <span class="n">base_desc</span> <span class="o">=</span> <span class="s">"SIGHASH_NONE"</span>
            <span class="n">case</span> <span class="mh">0x03</span><span class="p">:</span>
                <span class="n">base_desc</span> <span class="o">=</span> <span class="s">"SIGHASH_SINGLE"</span>
            <span class="n">case</span> <span class="n">_</span><span class="p">:</span>
                <span class="n">base_desc</span> <span class="o">=</span> <span class="sa">f</span><span class="s">"SIGHASH_UNKNOWN(</span><span class="si">{</span><span class="n">base_type</span><span class="si">:</span><span class="mi">02</span><span class="n">x</span><span class="si">}</span><span class="s">)"</span>

        <span class="k">if</span> <span class="n">anyonecanpay</span><span class="p">:</span>
            <span class="k">return</span> <span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="n">base_desc</span><span class="si">}</span><span class="s"> | SIGHASH_ANYONECANPAY"</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="k">return</span> <span class="n">base_desc</span>

    <span class="c1"># --------------------------------------------------------------------------------------------
</span>    <span class="o">@</span><span class="nb">staticmethod</span>
    <span class="k">def</span> <span class="nf">decode_varint</span><span class="p">(</span><span class="n">data</span><span class="p">:</span> <span class="nb">bytes</span><span class="p">,</span> <span class="n">offset</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">tuple</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="nb">int</span><span class="p">]:</span>
        <span class="s">"""
        Decode a variable-length integer from the data starting at offset.

        Args:
            data (bytes): The byte data
            offset (int): Starting position

        Returns:
            tuple: (value, new_offset)
        """</span>
        <span class="n">first_byte</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="n">offset</span><span class="p">]</span>
        <span class="k">if</span> <span class="n">first_byte</span> <span class="o">&lt;</span> <span class="mh">0xFD</span><span class="p">:</span>
            <span class="k">return</span> <span class="n">first_byte</span><span class="p">,</span> <span class="n">offset</span> <span class="o">+</span> <span class="mi">1</span>
        <span class="k">elif</span> <span class="n">first_byte</span> <span class="o">==</span> <span class="mh">0xFD</span><span class="p">:</span>
            <span class="k">return</span> <span class="n">struct</span><span class="p">.</span><span class="n">unpack</span><span class="p">(</span><span class="s">"&lt;H"</span><span class="p">,</span> <span class="n">data</span><span class="p">[</span><span class="n">offset</span> <span class="o">+</span> <span class="mi">1</span><span class="p">:</span> <span class="n">offset</span> <span class="o">+</span> <span class="mi">3</span><span class="p">])[</span><span class="mi">0</span><span class="p">],</span> <span class="n">offset</span> <span class="o">+</span> <span class="mi">3</span>
        <span class="k">elif</span> <span class="n">first_byte</span> <span class="o">==</span> <span class="mh">0xFE</span><span class="p">:</span>
            <span class="k">return</span> <span class="n">struct</span><span class="p">.</span><span class="n">unpack</span><span class="p">(</span><span class="s">"&lt;I"</span><span class="p">,</span> <span class="n">data</span><span class="p">[</span><span class="n">offset</span> <span class="o">+</span> <span class="mi">1</span><span class="p">:</span> <span class="n">offset</span> <span class="o">+</span> <span class="mi">5</span><span class="p">])[</span><span class="mi">0</span><span class="p">],</span> <span class="n">offset</span> <span class="o">+</span> <span class="mi">5</span>
        <span class="k">elif</span> <span class="n">first_byte</span> <span class="o">==</span> <span class="mh">0xFF</span><span class="p">:</span>
            <span class="k">return</span> <span class="n">struct</span><span class="p">.</span><span class="n">unpack</span><span class="p">(</span><span class="s">"&lt;Q"</span><span class="p">,</span> <span class="n">data</span><span class="p">[</span><span class="n">offset</span> <span class="o">+</span> <span class="mi">1</span><span class="p">:</span> <span class="n">offset</span> <span class="o">+</span> <span class="mi">9</span><span class="p">])[</span><span class="mi">0</span><span class="p">],</span> <span class="n">offset</span> <span class="o">+</span> <span class="mi">9</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="k">raise</span> <span class="nb">ValueError</span><span class="p">(</span><span class="s">"Invalid varint prefix byte"</span><span class="p">)</span>


<span class="c1"># -------------------------------------------------------------------------------------------------
</span><span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
    <span class="n">block_decoder</span><span class="p">:</span> <span class="n">BlockDecoder</span> <span class="o">=</span> <span class="n">BlockDecoder</span><span class="p">()</span>

    <span class="c1"># set block height here
</span>    <span class="n">block_height</span> <span class="o">=</span> <span class="mi">0</span>  <span class="c1"># change this to any block height you want
</span>
    <span class="n">url</span> <span class="o">=</span> <span class="sa">f</span><span class="s">"https://blockchain.info/rawblock/</span><span class="si">{</span><span class="n">block_height</span><span class="si">}</span><span class="s">?format=hex"</span>
    <span class="n">resp</span> <span class="o">=</span> <span class="n">requests</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="n">url</span><span class="p">)</span>

    <span class="k">if</span> <span class="n">resp</span><span class="p">.</span><span class="n">status_code</span> <span class="o">==</span> <span class="mi">200</span><span class="p">:</span>
        <span class="n">block</span> <span class="o">=</span> <span class="n">resp</span><span class="p">.</span><span class="n">text</span><span class="p">.</span><span class="n">strip</span><span class="p">()</span>  <span class="c1"># raw block hex
</span>        <span class="n">block_bytes</span> <span class="o">=</span> <span class="nb">bytes</span><span class="p">.</span><span class="n">fromhex</span><span class="p">(</span><span class="n">block</span><span class="p">)</span>
        <span class="n">decoded_block</span> <span class="o">=</span> <span class="n">block_decoder</span><span class="p">.</span><span class="n">decode_full_block</span><span class="p">(</span><span class="n">block_bytes</span><span class="p">.</span><span class="nb">hex</span><span class="p">())</span>
        <span class="k">print</span><span class="p">(</span><span class="n">json</span><span class="p">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">decoded_block</span><span class="p">,</span> <span class="n">indent</span><span class="o">=</span><span class="mi">2</span><span class="p">))</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="s">"Error:"</span><span class="p">,</span> <span class="n">resp</span><span class="p">.</span><span class="n">status_code</span><span class="p">,</span> <span class="n">resp</span><span class="p">.</span><span class="n">text</span><span class="p">)</span>


<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">"__main__"</span><span class="p">:</span>
    <span class="n">main</span><span class="p">()</span>
</code></pre></div></div>]]></content><author><name>Carlos Requena</name></author><category term="Bitcoin" /><summary type="html"><![CDATA["If you want to find the secrets of the universe, think in terms of energy, frequency and vibration.” --Nikola Tesla]]></summary></entry><entry xml:lang="es"><title type="html">Princicipios Vitales de Ray Dalio</title><link href="https://cjrequena.github.io/2022-09-13/principles-es" rel="alternate" type="text/html" title="Princicipios Vitales de Ray Dalio" /><published>2022-09-13T00:00:00+00:00</published><updated>2022-09-13T00:00:00+00:00</updated><id>https://cjrequena.github.io/2022-09-13/principles-es</id><content type="html" xml:base="https://cjrequena.github.io/2022-09-13/principles-es"><![CDATA[<div style="text-align:center">
    <span style="color:firebrick;font-weight: bold"> 
        Las grandes cosas se consiguen en base a pequeños principios.
    </span>
</div>

<h1 id="piensa-por-ti-mismo-para-decidir"><strong>Piensa por ti mismo para decidir.</strong></h1>

<ol>
  <li>Lo que quieres.</li>
  <li>Lo que es verdad.</li>
  <li>Lo que hay que hacer para obtener (1) a la luz de (2)</li>
</ol>

<p>Hazlo con humildad y apertura de miras para tener en cuenta las mejores ideas de las que dispones.</p>

<p>Busca siempre patrones de las cosas que te afectan, para entender las relaciones causa-efecto que las impulsan
y extraer principios que te sirvan para afrontarlas de forma eficaz.</p>

<h1 id="1-admite-y-afronta-la-realidad">1. Admite y afronta la realidad.</h1>
<h2 id="11-sé-hiperrealista">1.1 Sé hiperrealista.</h2>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">a. </span> 
Sueños + realidad + determinación = una vida de éxito.
</h4>

<h2 id="12-la-verdad-y-una-comprensión-acertada-de-la-realidad-es-la-base-primordial-de-cualquier-resultado-positivo">1.2 La verdad y una comprensión acertada de la realidad es la base primordial de cualquier resultado positivo.</h2>

<h2 id="13-ten-la-mente-radicalmente-abierta-actúa-con-total-transparencia">1.3 Ten la mente radicalmente abierta. Actúa con total transparencia.</h2>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">a. </span> 
La transparencia y la apertura de miras radicales son imprescindibles para aprender rápido y cambiar de verdad.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">b. </span> 
No dejes que el miedo al qué dirán se interponga en tu camino.  
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick;">c. </span> 
La sinceridad y la transparencia radical atraerán tareas y relaciones más significativas.
</h4>

<h2 id="14-observa-la-naturaleza-para-comprender-el-funcionamiento-de-la-realidad">1.4 Observa la naturaleza para comprender el funcionamiento de la realidad.</h2>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">a. </span> 
No te obsesiones con tu visión de cómo deberían ser las cosas, o no aprenderás como son en realidad.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">b. </span> 
Para ser bueno, un hecho debe operar en consonancia con las leyes de la realidad y contribuir al desarrollo.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">c. </span> 
La evolución es la fuerza más poderosa del universo, la única permanente y la que lo impulsa todo.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">d. </span> 
Renuévate o muere.
</h4>

<h2 id="15-la-evolución-es-el-mayor-logro-y-la-mayor-recompensa-que-puede-haber-en-la-vida">1.5 La evolución es el mayor logro y la mayor recompensa que puede haber en la vida.</h2>
<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">a. </span> 
Los incentivos del individuo han de estar alineados con los objetivos del grupo.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">b. </span> 
La realidad opera en beneficio del conjunto, no del individuo.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">c. </span> 
La adaptación mediante el ensayo y error rápidos es de un valor incalculable.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">d. </span> 
Eres todo y nada a la vez. Decide que quieres ser.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">e. </span> 
Lo que eres depende de tu punto de vista.
</h4>

<h2 id="16-entiende-las-lecciones-de-la-naturaleza">1.6 Entiende las lecciones de la naturaleza.</h2>
<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">a. </span> 
Maximiza tu progreso.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">b. </span> 
Recuerda que sin sacrificio no hay progreso.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">c. </span> 
Para fortalecerse, la ley natural dicta que uno ha de exceder sus limites, y eso duele.
</h4>

<h2 id="17-dolor--reflexión---progreso">1.7 Dolor + reflexión =  progreso</h2>
<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">a. </span> 
No rehúyas el dolor, ábrele los brazos.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">b. </span> 
Acepta el amor exigente.
</h4>

<h2 id="18-sopesa-las-consecuencias-de-segundo-y-tercer-orden">1.8 Sopesa las consecuencias de segundo y tercer orden.</h2>

<h2 id="19-atente-a-las-consecuencias-de-tus-actos">1.9 Atente a las consecuencias de tus actos.</h2>

<h2 id="110-observa-la-maquinaria-desde-arriba">1.10 Observa la maquinaria desde arriba.</h2>
<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">a. </span> 
Piensa en tí mismo como una máquina dentro de otra, y sé consciente de la capacidad para alterar ambas y obtener
mejores resultados.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">b. </span> 
Comparando los resultados y los objetivos, puedes decidir cómo modificar la maquinaria.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">c. </span> 
Distingue entre tú como diseñador de tu maquinaria y como operario de esta.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">d. </span> 
El craso error de la mayoría de las personas es que no se ven a sí mismas ni a los demás de forma objetiva, y eso
les lleva a tropezar repetidamente con las debilidades propias y ajenas.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">e. </span> 
Son triunfadores quienes pueden sobreponerse a sí mismos, para mirar las cosas con objetividad y aprovecharse de ellas
a fin de propiciar un cambio.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">f. </span> 
Pedir ayuda a aquellos cuyas fuerzas se complementan con tus debilidades es una habilidad que ha de desarrollarse a toda
costa, por cuanto implicará la construcción de barreras que te impedirán hacer lo que no debas.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">g. </span> 
Como es difícil observarse a uno mismo objetivamente, has de confiar en la opinión de los demás y en cualquier hecho
demostrable.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">h. </span> 
Con una mente lo bastante abierta y decidida, puedes lograr prácticamente cualquier objetivo.
</h4>

<h1 id="2-utiliza-el-proceso-de-5-pasos-para-obtener-lo-que-quieras-de-la-vida"><strong>2. Utiliza el proceso de 5 pasos para obtener lo que quieras de la vida.</strong></h1>

<h2 id="21-ten-objetivos-claros">2.1 Ten objetivos claros.</h2>
<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">a. </span> 
Prioriza: Cuando se puede lograr prácticamente todo, es imposible conseguir nada.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">b. </span> 
No confundas metas con deseos.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">c. </span> 
Decidir lo que quieres en la vida consiste en conciliar objetivos y deseos.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">d. </span> 
No confundas las señales de éxito con el propio éxito.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">e. </span> 
No descartes un objetivo por considerarlo inalcanzable.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">f. </span> 
Recuerda que con un liston alto se desarrollan grandes capacidades.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">g. </span> 
Nada te detendrá si eres a) flexible b) autónomo.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">h. </span> 
Aceptar cómo lidiar con tus tropiezos es tan importante como seguir adelante.
</h4>

<h2 id="22-identifica-y-no-tolores-los-problemas">2.2 Identifica y no tolores los problemas.</h2>
<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">a. </span> 
Considera los problemas dolorosos como mejoras en potencia que te hacen señas evidentes.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">b. </span> 
No evites afrontar los problemas porque provienen de realidades desagradables que no es grato afrontar.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">c. </span> 
Identifica los problemas de manera especifica.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">d. </span> 
No confundas la causa de un problema con el problema en si mismo.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">e. </span> 
Distingue los problemas grandes de los pequeños.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">f. </span> 
Una vez identificado el problema, no lo toleres.
</h4>

<h2 id="23-diagnostica-los-problemas-para-llegar-a-sus-causas-últimas">2.3 Diagnostica los problemas para llegar a sus causas últimas.</h2>
<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">a. </span> 
Primero debes saber qué pasa y luego decidir qué vas a hacer.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">b. </span> 
Distingue las causas primeras de las causas últimas.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">c. </span> 
Admite que si conoces a alguien (tambien a ti mismo) sabrás qué esperar de él.
</h4>

<h2 id="24-traza-un-plan">2.4 Traza un plan.</h2>
<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">a. </span> 
Retrocede antes de avanzar.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">b. </span> 
Considera los problemas como una serie de resultados producidos por una maquina.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">c. </span> 
Recuerda que normalmente hay muchos caminos para llegar a un mismo fin.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">d. </span> 
Piensa en un plan como en un guión cinematográfico que muestre qué debe hacer cada uno a los largo del tiempo.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">e. </span> 
Considera poner tu plan por escrito, para que todos lo vean y usen como baremo de tu progreso.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">f. </span> 
Reconoce que no necesitas demasiado tiempo para diseñar un buen plan.
</h4>

<h2 id="25-transforma-las-estrategias-en-resultados">2.5 Transforma las estrategias en resultados.</h2>
<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">a. </span> 
Los buenos planificadores que no ponen en práctica sus ideas van sin rumbo.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">b. </span> 
Los buenos habitos de trabajo se subestiman demasiado.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">c. </span> 
Establece parámetros claros para asegurarte de que sigues el plan.
</h4>

<h2 id="26-recuerda-que-las-flaquezas-no-importan-si-les-encuentras-soluciones">2.6 Recuerda que las flaquezas no importan si les encuentras soluciones.</h2>
<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">a. </span> 
Busca patrones en los errores e identifica qué paso. 
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">b. </span> 
Cada cual tiene un obstáculo principal que se interpone entre él y él éxito; debes encontrar el tuyo y afrontarlo debidamente.
</h4>

<h2 id="27-comprende-tu-esquema-mental-y-tu-humildad-así-como-los-ajenos">2.7 Comprende tu esquema mental y tu humildad, así como los ajenos.</h2>

<h1 id="3-sé-radicalmente-abierto-de-miras"><strong>3. Sé radicalmente abierto de miras.</strong></h1>

<h2 id="31-reconoce-las-dos-barreras">3.1 Reconoce las dos barreras.</h2>
<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">a. </span> 
Entiende la barrera del ego.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">b. </span> 
Los dos yos y su lucha por el control.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">c. </span> 
Entiende la barrera del punto ciego.
</h4>

<h2 id="32-practica-una-apertura-de-miras-radical">3.2 Practica una apertura de miras radical.</h2>
<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">a. </span> 
Cree sinceramente que, quizá, deconozcas cuál es el mejor camino, y reconoce que la capacidad de aceptar esa ignorancia es mas importante que todo lo que sepas.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">b. </span> 
Reconoce que las decisiones se toman en dos etapas: primero se recopila toda la información relevante y luego se decide.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">c. </span> 
No te preocupes por la apariencias, sino por el objetivo.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">d. </span> 
Reconoce que es imposible producir sin aprender.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">e. </span> 
Reconoce que, para ponerte efectivamente en la piel del otro y ver el mundo desde su perspectiva, has de de proceder a una suspención temporal del juicio: solo desde la empatía podrás evaluar correctamente una perspectiva ajena.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">f. </span> 
Recuerda que buscas la mejor respuesta, no la mejor respuesta que puedas llegar por tu cuenta.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">g. </span> 
Deja claro si estás discutiendo o si quieres aprender y endenter. Piensa en qué opción es mejor, según tu credibilidad propia y la de los demás.
</h4>

<h2 id="33-aprecia-el-arte-del-desacuerdo-reflexivo">3.3 Aprecia el arte del desacuerdo reflexivo.</h2>

<h2 id="34-triangula-tu-perspectiva-con-gente-creíble-dispuesta-a-discrepar">3.4 Triangula tu perspectiva con gente creíble dispuesta a discrepar.</h2>
<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">a. </span> 
Hacer planes para que el peor caso factible sea lo mejor posible.
</h4>

<h2 id="35-reconoce-los-sintomas-de-la-cerrazón-y-la-apertura-de-miras-y-préstales-atención">3.5 Reconoce los sintomas de la cerrazón y la apertura de miras y préstales atención.</h2>

<h2 id="36-entiende-cómo-se-puede-llegar-a-ser-radicalmente-abierto-de-miras">3.6 Entiende cómo se puede llegar a ser radicalmente abierto de miras.</h2>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">a. </span> 
Utiliza el dolor con regularidad como guía hacia unas reflexiones de calidad.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">b. </span> 
Haz de la apertura de miras una constumbre.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">c. </span> 
Conoce tus puntos ciegos.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">d. </span> 
Si varias personas creíbles te dicen que estas obrando mal, y eres el único que no lo ve así, da por supuesto que seguramente no estés siendo neutral.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">e. </span> 
Medita.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">f. </span> 
Básate en los hechos y anima a los demás a que hagan los mismo.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">g. </span> 
Haz todo lo que esté en tus manos para ayudar a los demás a ser tambien abiertos de miras.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">h. </span> 
Utilza una herramienta de decisión basada en los hechos.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">i. </span> 
Comprende cuándo es mejor rendirse y tener fe en tu sistema de toma de decisiones.
</h4>

<h1 id="4-entiende-que-las-personas-funcionan-de-formas-muy-distintas"><strong>4. Entiende que las personas funcionan de formas muy distintas.</strong></h1>

<h2 id="41-entiende-el-poder-que-se-deriva-de-comprender-cómo-funcionas-tú-y-los-demás">4.1 Entiende el poder que se deriva de comprender cómo funcionas tú y los demás.</h2>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">a. </span> 
Naces con atributos que pueden ser una ayuda o un escollo, según cómo los utilices.
</h4>

<h2 id="42-el-trabajo-y-las-relaciones-significativas-no-son-solo-cosas-bonitas-que-escoges-sino-que-las-llevas-programadas-genéticamente">4.2 El trabajo y las relaciones significativas no son solo cosas bonitas que escoges, sino que las llevas programadas genéticamente.</h2>

<h2 id="43-entiende-las-grandes-batallas-mentales-y-cómo-controlarlas-para-obtener-lo-que-quieres">4.3 Entiende las grandes batallas mentales y cómo controlarlas para obtener lo que quieres.</h2>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">a. </span> 
Entiende que la mente consciente está enzarzada en una batalla con la mente inconsciente.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">b. </span> 
Sé consciente de que la luca más constante que existe es la de los sentimientos y el pensamiento.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">c. </span> 
Compagina los sentimientos y el pensamiento.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">d. </span> 
Escoge bien tus hábitos.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">e. </span> 
Instruye al yo inferior de forma afable y persistente para desarrollar buenos hábitos.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">f. </span> 
Entiende la diferencia entre el hemisferio derecho y el izquierdo, y el pensamiento derivado de cada uno.
</h4>

<h4 style="color: firebrick; margin-left: 33px">
<span style="color:firebrick">g. </span> 
Entiende lo mucho y lo poco que el cerebro puede cambiar.
</h4>]]></content><author><name>Carlos Requena</name></author><category term="Principles" /><summary type="html"><![CDATA[Las grandes cosas se consiguen en base a pequeños principios.]]></summary></entry><entry xml:lang="en"><title type="html">[AWS] Tagging Resources</title><link href="https://cjrequena.github.io/2020-10-01/aws-tagging-resources-en" rel="alternate" type="text/html" title="[AWS] Tagging Resources" /><published>2020-10-01T00:00:00+00:00</published><updated>2020-10-01T00:00:00+00:00</updated><id>https://cjrequena.github.io/2020-10-01/aws-tagging-resources-en</id><content type="html" xml:base="https://cjrequena.github.io/2020-10-01/aws-tagging-resources-en"><![CDATA[<div style="text-align:center"><span style="color:red;font-weight: bold">"A witty saying proves nothing." </span> <span style="color:black;font-weight: bold">--Voltaire</span></div>
<p><br /></p>

<h1 id="aws-tagging-resources">[AWS] Tagging Resources</h1>
<p>Amazon Web Services allows customers to assign metadata to their AWS resources in the form of tags. Each tag is a simple label consisting of a customer-defined key and an optional 
value that can make it easier to manage, search for, and filter resources by purpose, owner, environment, or other criteria. AWS tags can be used for many purposes.</p>

<blockquote>
  <div style="text-align:left"><span style="color:red;font-weight: bold">Important</span></div>
  <p>Do not add personally identifiable information (PII) or other confidential or sensitive information in tags. Tags are accessible to many AWS services, including billing. Tags are 
not intended to be used for private or sensitive data.</p>
</blockquote>

<h1 id="best-practices">Best practices</h1>
<p><strong>As you create a tagging strategy for AWS resources, follow best practices:</strong></p>

<ul>
  <li>
    <p>Do not store personally identifiable information (PII) or other confidential or sensitive information in tags.</p>
  </li>
  <li>
    <p>Use a standardized, case-sensitive format for tags, and apply it consistently across all resource types.</p>
  </li>
  <li>
    <p>Consider tag guidelines that support multiple purposes, like managing resource access control, cost tracking, automation, and organization.</p>
  </li>
  <li>
    <p>Use automated tools to help manage resource tags. <a href="https://docs.aws.amazon.com/ARG/latest/userguide/">AWS Resource Groups</a> and the <a href="https://docs.aws.amazon.com/resourcegroupstagging/latest/APIReference/">Resource Groups Tagging API</a> enable programmatic control of tags, making it easier to automatically manage, search, and filter tags and resources.</p>
  </li>
  <li>
    <p>Use too many tags rather than too few tags.</p>
  </li>
  <li>
    <p>Remember that it is easy to change tags to accommodate changing business requirements, but consider the consequences of future changes. For example, changing access control tags means you must also update the policies that reference those tags and control access to your resources.</p>
  </li>
</ul>

<h1 id="best-practices-for-naming-tags">Best Practices for Naming Tags</h1>

<h2 id="adopt-a-standardized-approach-for-tag-names">Adopt a Standardized Approach for Tag Names</h2>

<p>Keep in mind that names for AWS tags are case sensitive so ensure that they are used consistently. For example, the tags CostCenter and costcenter are different, so one might be configured as a cost allocation tag for financial analysis and reporting and the other one might not be. Similarly, the <strong>Name</strong> tag appears in the AWS Console for many resources, but the name tag does not.</p>

<p>A number of tags are predefined by AWS or created automatically by various AWS services. Many AWS-defined tags are named using all lowercase, with hyphens separating words in the name, and prefixes to identify the source service for the tag.</p>

<p><strong>For example:</strong></p>

<ul>
  <li>
    <p><strong>aws:ec2spot:fleet-request-id</strong> identifies the Amazon EC2 Spot Instance Request that launched the instance</p>
  </li>
  <li>
    <p><strong>aws:cloudformation:stack-name</strong> identifies the AWS CloudFormation stack that created the resource</p>
  </li>
  <li>
    <p><strong>lambda-console:blueprint</strong> identifies blueprint used as a template for an AWS Lambda function</p>
  </li>
  <li>
    <p><strong>elasticbeanstalk:environment-name</strong> identifies the application that created the resource</p>
  </li>
</ul>

<blockquote>
  <div style="text-align:left"><span style="color:red;font-weight: bold">Important</span></div>
  <p>Consider naming your tags using all lowercase, with hyphens separating words, and a prefix identifying the organization name or abbreviated name.</p>
</blockquote>

<p><br />
<strong>For example:</strong></p>

<ul>
  <li>
    <p><strong>anycompany:cost-center</strong> to identify the internal Cost Center code</p>
  </li>
  <li>
    <p><strong>anycompany:environment-type</strong> to identifywhether the environment is development, test, or production</p>
  </li>
  <li>
    <p><strong>anycompany:application-id</strong> to identify the application the resource was created for</p>
  </li>
</ul>

<p>The prefix ensures that tags are clearly identified as having been defined by your organization and not by AWS or athird-party tool that you may be using. Using all lowercase with hyphens for separators avoids confusion about how to capitalize a tag name. For example, anycompany:project-idis simpler to rememberthan ANYCOMPANY:ProjectID, anycompany:projectID, or Anycompany:ProjectId</p>

<h2 id="standardize-names-for-aws-resources">Standardize Names for AWS Resources</h2>
<p><a href="https://cjrequena.com/2020-06-05/aws-naming-conventions-en">[AWS] Naming Conventions Best Practices</a></p>

<h1 id="tagging-categories">Tagging categories</h1>
<h2 id="technical-tags">Technical Tags:</h2>
<ol>
  <li><strong>name</strong>: Used to give a descriptive name to the resource. For example, “web-server-prod” or “db-dev”.</li>
  <li><strong>owner</strong>: Specifies the person or team responsible for the resource. This can be an individual’s name, team name, or email address.</li>
  <li><strong>availability-zone</strong>: Specifies the availability zone or region where the resource is located.</li>
  <li><strong>service</strong>: Indicates the AWS service associated with the resource, such as “ec2”, “s3”, “rds”, etc.</li>
  <li><strong>lifecycle</strong>: Specifies the lifecycle stage of the resource, such as “active”, “inactive”, “archived”.</li>
  <li><strong>version</strong>: Indicates the version of the resource if applicable.</li>
  <li><strong>created-date</strong>: Specifies the date when the resource was created.</li>
  <li><strong>last-modified-date</strong>: Specifies the date when the resource was last modified.</li>
  <li><strong>resource-id</strong>: Unique identifier for the resource.</li>
  <li><strong>environment-type</strong>: Specifies the type of environment, such as “test”, “qa”, or “production”.</li>
</ol>

<h2 id="tags-for-automation">Tags for Automation:</h2>
<ol>
  <li><strong>automated</strong>: Indicates whether the resource is managed by automation tools. Values can be “yes” or “no”.</li>
  <li><strong>auto-scaling-group</strong>: Indicates the auto-scaling group associated with the resource.</li>
  <li><strong>automation-tool</strong>: Specifies the automation tool used to manage the resource, such as “cloudformation”, “terraform”, etc.</li>
  <li><strong>scheduled-automation</strong>: Indicates whether the resource is part of scheduled automation tasks. Values can be “yes” or “no”.</li>
  <li><strong>continuous-integration</strong>: Indicates whether the resource is integrated with a continuous integration (CI) system.</li>
  <li><strong>automated-backup</strong>: Specifies whether automated backups are enabled for the resource.</li>
  <li><strong>auto-shutdown</strong>: Indicates whether the resource has an automated shutdown schedule.</li>
  <li><strong>auto-recovery</strong>: Specifies whether the resource is configured for automatic recovery in case of failure.</li>
  <li><strong>auto-scaling-policy</strong>: Indicates the auto-scaling policy associated with the resource.</li>
  <li><strong>automated-monitoring</strong>: Specifies whether automated monitoring is enabled for the resource.</li>
</ol>

<h2 id="business-tags">Business Tags:</h2>
<ol>
  <li><strong>cost-center</strong>: Associates the resource with a specific cost center or project code for financial tracking and allocation.</li>
  <li><strong>department</strong>: Indicates the department or business unit that owns or uses the resource. Useful for chargebacks and cost allocation.</li>
  <li><strong>project</strong>: Associates the resource with a specific project or initiative within the organization.</li>
  <li><strong>business-unit</strong>: Specifies the business unit that the resource belongs to.</li>
  <li><strong>customer-id</strong>: Identifies the customer or client associated with the resource.</li>
  <li><strong>revenue-center</strong>: Associates the resource with a specific revenue center or profit center.</li>
  <li><strong>business-criticality</strong>: Indicates the business criticality of the resource, such as “high”, “medium”, or “low”.</li>
  <li><strong>contract-id</strong>: Specifies the contract ID related to the resource.</li>
  <li><strong>service-level-agreement</strong>: Indicates the service level agreement (SLA) associated with the resource.</li>
  <li><strong>business-impact</strong>: Specifies the potential business impact of the resource being unavailable.</li>
</ol>

<h2 id="security-tags">Security Tags:</h2>
<ol>
  <li><strong>security-classification</strong>: Specifies the security classification or sensitivity level of the resource, such as “public”, “internal”, “confidential”.</li>
  <li><strong>compliance</strong>: Specifies the compliance status of the resource, such as “hipaa”, “pci-dss”, “gdpr”, etc.</li>
  <li><strong>backup</strong>: Indicates whether the resource is included in regular backups or not. Values can be “yes” or “no”.</li>
  <li><strong>encryption</strong>: Indicates whether the resource data is encrypted at rest and/or in transit.</li>
  <li><strong>access-control-list</strong>: Specifies the access control list (ACL) associated with the resource.</li>
  <li><strong>security-group</strong>: Indicates the security group associated with the resource.</li>
  <li><strong>firewall-rule</strong>: Specifies the firewall rule associated with the resource.</li>
  <li><strong>vulnerability</strong>: Indicates the vulnerability status of the resource, such as “vulnerable”, “patched”, etc.</li>
  <li><strong>data-classification</strong>: Specifies the data classification level of the resource, such as “sensitive”, “confidential”, etc.</li>
  <li><strong>security-policy</strong>: Indicates the security policy applied to the resource.</li>
</ol>

<h2 id="tags-for-classification">Tags for Classification:</h2>
<ol>
  <li><strong>environment</strong>: Indicates the environment the resource belongs to, such as “production”, “development”, or “staging”.</li>
  <li><strong>application</strong>: Identifies the application or project to which the resource belongs. Useful for multi-application environments.</li>
  <li><strong>region</strong>: Specifies the AWS region where the resource is located.</li>
  <li><strong>zone</strong>: Indicates the availability zone within a region where the resource is located.</li>
  <li><strong>role</strong>: Specifies the role or function of the resource within the system architecture.</li>
  <li><strong>service-type</strong>: Specifies the type of service provided by the resource, such as “web”, “database”, etc.</li>
  <li><strong>deployment-stage</strong>: Indicates the deployment stage of the resource, such as “alpha”, “beta”, “release-candidate”, etc.</li>
  <li><strong>cost-allocation</strong>: Specifies the cost allocation tag for financial tracking purposes.</li>
  <li><strong>cost-savings</strong>: Indicates whether the resource is part of a cost-saving initiative. Values can be “yes” or “no”.</li>
  <li><strong>expiration-date</strong>: Specifies the date when the resource should be reviewed or decommissioned. Useful for managing resource lifecycle.</li>
</ol>

<h1 id="tagging-use-cases">Tagging Use Cases</h1>
<h2 id="tags-for-aws-console-organization-and-resource-groups">Tags for AWS Console Organization and Resource Groups</h2>

<ul>
  <li><strong>organize-resources:</strong> Use tags to group and categorize resources based on their purpose, project, environment, or any other relevant attribute. This makes it easier to navigate and manage your resources within the AWS Management Console.</li>
  <li><strong>resource-group-classification:</strong> Leverage tags to create resource groups based on specific criteria, such as tagging all production resources together or grouping resources belonging to a specific department or business unit.</li>
</ul>

<h2 id="tags-for-cost-allocation">Tags for Cost Allocation</h2>

<ul>
  <li><strong>cost-tracking:</strong> Assign tags to AWS resources to identify the associated costs and allocate them to specific cost centers, departments, projects, or customers. This enables you to track and analyze your AWS spending accurately.</li>
  <li><strong>cost-allocation-reports:</strong> Utilize tags to filter and generate detailed cost allocation reports using AWS Cost Explorer or Cost and Usage Reports. These reports can provide insights into cost breakdowns based on different tag values.</li>
</ul>

<h2 id="tags-for-automation-1">Tags for Automation</h2>

<ul>
  <li><strong>automated-resource-management:</strong> Use tags to trigger automation scripts, workflows, or AWS Lambda functions for managing resources automatically. For example, you can use tags to automatically start or stop EC2 instances based on predefined schedules or resource utilization.</li>
  <li><strong>automated-backup-and-recovery:</strong> Tagging resources can be useful in automated backup and recovery scenarios. By assigning specific tags to resources, you can create backup policies or automation scripts that target resources with those tags for backup or recovery operations.</li>
</ul>

<h2 id="tags-for-operations-support">Tags for Operations Support</h2>

<ul>
  <li><strong>resource-monitoring-and-alerts:</strong> Assign tags to resources to facilitate monitoring and alerting systems. Tags can be used to set up monitoring dashboards, define alarm rules, or enable automated actions based on resource state changes or performance metrics.</li>
  <li><strong>incident-response-and-troubleshooting:</strong> Tags can assist in incident response and troubleshooting by providing additional context or categorization for resources. During an incident, tags can help identify affected resources, their interdependencies, or associated configurations.</li>
</ul>

<h2 id="tags-for-access-control">Tags for Access Control</h2>

<ul>
  <li><strong>access-control-policies:</strong> Use tags to define fine-grained access control policies through AWS Identity and Access Management (IAM). Tags can be used as condition keys in IAM policies, allowing you to grant or restrict access to resources based on their tag values.</li>
  <li><strong>resource-sharing-and-cross-account-access:</strong> Leverage tags to control resource sharing and enable cross-account access. You can use tags to specify which resources are accessible to other AWS accounts or specific IAM roles based on tag-based permissions.</li>
</ul>

<h2 id="tags-for-security-risk-management">Tags for Security Risk Management</h2>

<ul>
  <li><strong>security-group-and-nacl-rules:</strong> Assign tags to security groups and network ACLs (NACLs) to manage and audit security policies effectively. Tags can help categorize or identify the purpose of security rules, allowing you to track and analyze security configurations and potential risks.</li>
  <li><strong>asset-inventory-and-vulnerability-management:</strong> Utilize tags to maintain an inventory of your AWS assets and support vulnerability management practices. Tags can help identify resources that require regular security assessments, vulnerability scanning, or patch management.</li>
</ul>]]></content><author><name>Carlos Requena</name></author><category term="[AWS] Amazon Web Services" /><summary type="html"><![CDATA["A witty saying proves nothing." --Voltaire]]></summary></entry><entry xml:lang="en"><title type="html">[AWS] Creating a VPC without using the wizard</title><link href="https://cjrequena.github.io/2020-06-23/aws-vpc-without-wizard-en" rel="alternate" type="text/html" title="[AWS] Creating a VPC without using the wizard" /><published>2020-06-23T00:00:00+00:00</published><updated>2020-06-23T00:00:00+00:00</updated><id>https://cjrequena.github.io/2020-06-23/aws-vpc-without-wizard-en</id><content type="html" xml:base="https://cjrequena.github.io/2020-06-23/aws-vpc-without-wizard-en"><![CDATA[<div style="text-align:center"><span style="color:red;font-weight: bold">"A thought is an idea in transit.." </span> <span style="color:black;font-weight: bold">--Pythagoras</span></div>

<h1 id="creating-a-vpc-without-using-the-wizard">Creating a VPC without using the wizard</h1>

<p>In this post we are going to create a VPC with a private and public subnet without using the wizard to get into VPC in detail and to know how it works 
internally.</p>

<p>You also can create your VPC using the wizard following the AWS tutorial 
<a href="https://docs.aws.amazon.com/batch/latest/userguide/create-public-private-vpc.html">Creating a VPC with Public and Private Subnets for Your Compute Environments</a></p>

<center style="color:black;font-weight: bold"> Target Model Architecture Diagram</center>

<p><img src="/assets/images/aws/vpc-lab.png" alt="" /></p>

<p><br /></p>
<ol>
  <li>
    <p>Open the AWS console and go to <strong>Services → Networking &amp; Content Delivery</strong> section and make click on VPC.</p>
  </li>
  <li>
    <p>On the left menu, in the <strong>VIRTUAL PRIVATE CLOUD</strong> section, click on <strong>Your VPCs</strong> option.</p>
  </li>
  <li>
    <p>Click on the button that says <strong>Create VPC</strong> on the top side.</p>
  </li>
  <li>
    <p>Fill the form that appears with the data below.</p>

    <p><strong>Name tag:</strong> vpc-us-east-1-test-lab  <br />
 <strong>IPv4 CIDR block:</strong> 10.0.0.0/16 <br />
 <strong>IPv6 CIDR block:</strong> Amazon provided IPv6 CIDR block  <br />
 <strong>Tenancy:</strong> Default</p>

    <blockquote>

      <p><span style="color:silver;">Note</span>
 Be aware of the VPC description that appears in the form.
 A VPC is an isolated portion of the AWS cloud populated by AWS objects, such as Amazon EC2 instances. You must specify an IPv4 address range for your VPC. Specify the IPv4 address range as a Classless Inter-Domain Routing (CIDR) block; for example, 10.0.0.0/16. You cannot specify an IPv4 CIDR block larger than /16. You can optionally associate an IPv6 CIDR block with the VPC.</p>
    </blockquote>

    <blockquote>

      <p><span style="color:silver;">Note</span>
 By default, when you create a custom VPC, the following components are created.</p>
      <ul>
        <li>A router</li>
        <li>A main route table</li>
        <li>A main ACL</li>
        <li>A main Security Group</li>
      </ul>
    </blockquote>
  </li>
  <li>
    <p>On the VPC section, verify that the VPC was created successfully and then make click on <strong>Subnets</strong> on the left menu.</p>
  </li>
  <li>
    <p>Click on the button that says <strong>Create subnet</strong> on the top side.</p>
  </li>
  <li>
    <p>Fill the form that appears with the data below.</p>

    <p><strong>Name tag:</strong> subnet-us-east-1a-public-test-lab <br />
 <strong>VPC:</strong> vpc-us-east-1-test-lab   <br />
 <strong>Availability Zone:</strong> us-east-1a  <br />
 <strong>IPv4 CIDR block:</strong> 10.0.1.0/24  <br />
 <strong>IPv6 CIDR block:</strong> Don’t Assign IPv6</p>
  </li>
  <li>
    <p>Repeat the steps 5 and 6 in order to create a second subnet.</p>
  </li>
  <li>
    <p>Fill the form that appears with the data below.</p>

    <p><strong>Name tag:</strong> subnet-us-east-1b-private-test-lab<br />
 <strong>VPC:</strong> vpc-us-east-1-test-lab   <br />
 <strong>Availability Zone:</strong>  us-east-1b  <br />
 <strong>IPv4 CIDR block:</strong> 10.0.2.0/24  <br />
 <strong>IPv6 CIDR block:</strong> Don’t Assign</p>
  </li>
  <li>
    <p>Go to the <strong>Subnet</strong> section and select <strong>subnet-us-east-1b-private-test-lab</strong>, then click on Actions button on the top side, then click on Modify auto-assign 
IP settings and finally select Auto-assign IPv4 option.</p>
  </li>
  <li>
    <p>Go to the <strong>VPC Dashboard</strong> section and on the left menu click on <strong>Internet Gateways</strong> and then click on <strong>Create internet gateway</strong> on the top side.</p>
  </li>
  <li>
    <p>Fill the form that appears with the data below.</p>

    <p><strong>Name tag:</strong> igw-vpc-us-east-1-test-lab</p>
  </li>
  <li>
    <p>Attach the internet gateway to the VPC <strong>vpc-us-east-1-test-lab</strong></p>
  </li>
  <li>
    <p>Go to the <strong>VPC Dashboard</strong> section and on the left menu click on <strong>Route Tables</strong> and then click on <strong>Create route table</strong> on the top side.</p>
  </li>
  <li>
    <p>Fill the form that appears with the data below.</p>

    <p><strong>Name tag:</strong> rtb-subnet-us-east-1a-public-test-lab <br />
<strong>VPC:</strong> vpc-us-east-1-test-lab</p>
  </li>
  <li>
    <p>Repeat the steps 14 and 15 in order to create a route table for the private subnet.</p>

    <p><strong>Name tag:</strong> rtb-subnet-us-east-1b-private-test-lab<br />
<strong>VPC:</strong> vpc-us-east-1-test-lab</p>
  </li>
  <li>
    <p>Select the route table <strong>rtb-subnet-us-east-1a-public-test-lab</strong> and on the bottom side select routes and then click on the 
Edit routes button.</p>
  </li>
  <li>
    <p>Add the following rules and then click save.</p>

    <table>
      <thead>
        <tr>
          <th>Destination</th>
          <th>Target</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>0.0.0.0/0</td>
          <td>igw-vpc-us-east-1-test-lab</td>
        </tr>
        <tr>
          <td>::/0</td>
          <td>igw-vpc-us-east-1-test-lab</td>
        </tr>
        <tr>
          <td> </td>
          <td> </td>
        </tr>
      </tbody>
    </table>
  </li>
  <li>
    <p>Select the route table <strong>rtb-subnet-us-east-1a-public-test-lab</strong> and on the bottom side select <strong>subnet associations</strong> and then click on Edit subnet associations, 
select <strong>subnet-us-east-1a-public-test-lab and save.</strong></p>
  </li>
  <li>
    <p>Create a <strong>NAT gateway</strong> associated with the subnet <strong>subnet-us-east-1a-public-test-lab</strong> and add a tag name as <strong>ng-subnet-us-east-1a-public-test-lab</strong></p>
  </li>
  <li>
    <p>Select the route table <strong>rtb-subnet-us-east-1b-private-test-lab</strong> and on the bottom side select routes and then click on the Edit routes button.</p>
  </li>
  <li>
    <p>Add the following rules and then click save.</p>

    <table>
      <thead>
        <tr>
          <th>Destination</th>
          <th>Target</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>0.0.0.0/0</td>
          <td>ng-subnet-us-east-1a-public-test-lab</td>
        </tr>
        <tr>
          <td> </td>
          <td> </td>
        </tr>
      </tbody>
    </table>
  </li>
  <li>
    <p>Select the route table <strong>rtb-subnet-us-east-1b-private-test-lab</strong> and on the bottom side select subnet associations and then click on Edit subnet
associations, select <strong>subnet-us-east-1b-private-test-lab</strong> and save.</p>
  </li>
  <li>
    <p>Go to the <strong>VPC Dashboard</strong> section and on the left menu click on <strong>Network ACLs</strong> and then click on <strong>Create network ACL</strong> on the top side.</p>
  </li>
  <li>
    <p>Create two ACL one for the public subnet and another for the private subnet.</p>

    <p><strong>[ACL-1]</strong> <br />
<strong>Name tag:</strong> acl-subnet-us-east-1a-public-test-lab <br />
<strong>VPC:</strong> vpc-us-east-1-test-lab</p>

    <p><strong>[ACL-2]</strong> <br />
<strong>Name tag:</strong> acl-subnet-us-east-1b-private-test-lab<br />
<strong>VPC:</strong> vpc-us-east-1-test-lab</p>
  </li>
  <li>
    <p>Associate each ACL with its corresponding subnet.</p>
  </li>
  <li>
    <p>Add to each ACL the rules you need.</p>
  </li>
  <li>
    <p>Create two Security Groups one for the public subnet and another for the private subnet.</p>

    <p><strong>[SG-1]</strong> <br />
<strong>Security group name:</strong> sg-subnet-us-east-1a-public-test-lab <br />
<strong>Description:</strong> Any description  <br />
<strong>VPC:</strong>  vpc-us-east-1-test-lab</p>

    <p><strong>[SG-2]</strong> <br />
<strong>Security group name:</strong> sg-subnet-us-east-1b-private-test-lab <br />
<strong>Description:</strong> Any description  <br />
<strong>VPC:</strong>  vpc-us-east-1-test-lab</p>
  </li>
</ol>

<p><br /></p>
<blockquote>

  <p><span style="color:silver;">References and Resources</span></p>
  <ul>
    <li><a href="https://docs.aws.amazon.com/vpc/latest/userguide/what-is-amazon-vpc.html">Amazon Virtual Private Cloud Documentation</a></li>
    <li><a href="https://cjrequena.com/2019-02-07/aws-vpc-en">Amazon Virtual Private Cloud VPC</a></li>
    <li><a href="https://cidr.xyz/">CIDR</a></li>
  </ul>
</blockquote>]]></content><author><name>Carlos Requena</name></author><category term="[AWS] Amazon Web Services" /><summary type="html"><![CDATA["A thought is an idea in transit.." --Pythagoras]]></summary></entry><entry xml:lang="en"><title type="html">[AWS] Naming Conventions Best Practices</title><link href="https://cjrequena.github.io/2020-06-05/aws-naming-conventions-en" rel="alternate" type="text/html" title="[AWS] Naming Conventions Best Practices" /><published>2020-06-05T00:00:00+00:00</published><updated>2020-06-05T00:00:00+00:00</updated><id>https://cjrequena.github.io/2020-06-05/aws-naming-conventions-en</id><content type="html" xml:base="https://cjrequena.github.io/2020-06-05/aws-naming-conventions-en"><![CDATA[<div style="text-align:center"><span style="color:red;font-weight: bold">"Our true nationality is mankind." </span> <span style="color:black;font-weight: bold">--H. G. Wells</span></div>

<h1 id="aws-naming-conventions-best-practices">AWS Naming Conventions Best Practices</h1>

<p>A naming convention is a well-defined set of rules useful for choosing the name of an AWS resource. Ensure that your AWS resources are using appropriate naming conventions for 
tagging in order to manage them more efficiently and adhere to AWS resource tagging best practices.</p>

<p>Naming (tagging) your AWS resources consistently have several advantages such as providing additional information about the resource location and usage, promoting consistency within the selected AWS region, distinguishing fast similar resources stacks from one another, avoiding naming collisions,
improving clarity in cases of potential ambiguity and enhancing aesthetic and professional appearance.</p>

<hr />
<h2 id="default-pattern-components">Default Pattern Components</h2>

<p><strong>{RegionCode}</strong>   <br />
<code class="language-plaintext highlighter-rouge">(us-east-1|us-west-1|us-west-2|eu-west-1|eu-central-1|ap-northeast-1|ap-northeast-2|ap-southeast-1|ap-southeast-2|sa-east-1)</code></p>

<p><strong>{AvailabilityZoneCode}</strong><br />
<code class="language-plaintext highlighter-rouge">([1-2]{1})([a-c]{1})</code></p>

<p><strong>{EnvironmentCode}</strong>  <br />
<code class="language-plaintext highlighter-rouge">(dev|test|stg|prod)</code></p>

<p><strong>{ApplicationCode}</strong>   <br />
<code class="language-plaintext highlighter-rouge">([a-z0-9\-]+)</code></p>

<p><strong>{SubnetRouteCode}</strong> <br />
<code class="language-plaintext highlighter-rouge">(public|private)</code></p>

<p><strong>{ResourceCode}</strong> <br />
<code class="language-plaintext highlighter-rouge">(ec2|alb|nlb)</code></p>

<hr />
<h2 id="vpc-naming-conventions">VPC Naming Conventions</h2>

<p><strong>Default Pattern Format</strong></p>

<p><code class="language-plaintext highlighter-rouge">vpc-{RegionCode}-{EnvironmentCode}-{ApplicationCode}</code></p>

<p><strong>RegExp</strong></p>

<p><code class="language-plaintext highlighter-rouge">^vpc-(us-east-1|us-west-1|us-west-2|eu-west-1|eu-central-1|ap-northeast-1|ap-northeast-2|ap-southeast-1|ap-southeast-2|sa-east-1)-(dev|test|stg|prod)-([a-z0-9\-]+)$</code></p>

<p><strong>Examples</strong></p>

<p><span style="color:silver;">
vpc-us-east-1-prod-bigdataappstack
<br />
vpc-us-west-2-prod-webappstack
</span></p>

<hr />
<h2 id="subnet-naming-conventions">Subnet Naming Conventions</h2>

<p><strong>Default Pattern Format</strong>    <br />
<code class="language-plaintext highlighter-rouge">subnet-{RegionCode}-{AvailabilityZoneCode}-{SubnetRouteCode}-{EnvironmentCode}-{ApplicationStackCode}</code></p>

<p><strong>RegExp</strong>    <br />
<code class="language-plaintext highlighter-rouge">^subnet-(us-east-1|us-west-1|us-west-2|eu-west-1|eu-central-1|ap-northeast-1|ap-northeast-2|ap-southeast-1|ap-southeast-2|sa-east-1)-([1-2]{1})([a-c]{1})-(public|private)-(dev|test|stg|prod)-([a-z0-9\-]+)$</code></p>

<p><strong>Examples</strong>          <br />
<span style="color:silver;">
subnet-us-east-1-2a-public-prod-webappstack
<br />
subnet-us-west-1-2b-private-prod-databasestack
</span></p>

<hr />
<h2 id="security-group-naming-conventions">Security Group Naming Conventions</h2>

<p><strong>Default Pattern Format</strong>    <br />
<code class="language-plaintext highlighter-rouge">sgr_{ResourceCode}_{RegionCode}_{EnvironmentCode}-{ApplicationCode}</code></p>

<p><strong>RegExp</strong>    <br />
<code class="language-plaintext highlighter-rouge">^sgr_(ec2|alb|nlb)_(us-east-1|us-west-1|us-west-2|eu-west-1|eu-central-1|ap-northeast-1|ap-northeast-2|ap-southeast-1|ap-southeast-2|sa-east-1)_(dev|test|stg|prod)_([a-z0-9\-]+)$</code></p>

<p><strong>Examples</strong>      <br />
<span style="color:silver;">
sgr_ec2_us-west-1_dev_sample-app-instance-1
</span></p>

<hr />
<h2 id="ec2-instance-naming-conventions">EC2 Instance Naming Conventions</h2>

<p><strong>Default Pattern Format</strong>    <br />
<code class="language-plaintext highlighter-rouge">ec2_{RegionCode}_{AvailabilityZoneCode}_{EnvironmentCode}_{ApplicationCode}</code></p>

<p><strong>RegExp</strong>    <br />
<code class="language-plaintext highlighter-rouge">^ec2_(us-east-1|us-west-1|us-west-2|eu-west-1|eu-central-1|ap-northeast-1|ap-northeast-2|ap-southeast-1|ap-southeast-2|sa-east-1)_([1-2]{1})([a-c]{1})_(dev|test|stg|prod)_([a-z0-9\-]+)$</code></p>

<p><strong>Examples</strong>      <br />
<span style="color:silver;">
ec2_us-east-1_2a_prod_tomcat
<br />
ec2_us-west-1_2b_prod_nodejs 
</span></p>

<hr />
<h2 id="pem-key-naming-conventions">PEM Key Naming Conventions</h2>

<p><strong>Default Pattern Format</strong>    <br />
<code class="language-plaintext highlighter-rouge">key-RegionCode-EnvironmentCode-ApplicationCode</code></p>

<p><strong>RegExp</strong>    <br />
<code class="language-plaintext highlighter-rouge">^key-(us-east-1|us-west-1|us-west-2|eu-west-1|eu-central-1|ap-northeast-1|ap-northeast-2|ap-southeast-1|ap-southeast-2|sa-east-1)-(dev|test|stg|prod)-([a-z0-9\-]+)$</code></p>

<p><strong>Examples</strong>      <br />
<span style="color:silver;">
key-us-east-1-prod-web-server
<br />
key-us-west-1-prod-database 
</span></p>

<hr />
<h2 id="ecs-cluster-naming-conventions">ECS Cluster Naming Conventions</h2>

<p><strong>Default Pattern Format</strong>    <br />
<code class="language-plaintext highlighter-rouge">ecs-cluster_{RegionCode}_{EnvironmentCode}_{ApplicationCode}</code></p>

<p><strong>RegExp</strong>    <br />
<code class="language-plaintext highlighter-rouge">^ecs-cluster_(us-east-1|us-west-1|us-west-2|eu-west-1|eu-central-1|ap-northeast-1|ap-northeast-2|ap-southeast-1|ap-southeast-2|sa-east-1)_(dev|test|stg|prod)_([a-z0-9\-]+)$</code></p>

<p><strong>Examples</strong>      <br />
<span style="color:silver;">
ecs-cluster_us-east-1_prod_tomcat
<br />
ecs-cluster_us-east-1_prod_micro-app
</span></p>

<h2 id="ecs-task-definition-naming-conventions">ECS Task Definition Naming Conventions</h2>

<p><strong>Default Pattern Format</strong>    <br />
<code class="language-plaintext highlighter-rouge">ecstd-{RegionCode}-{EnvironmentCode}-{ApplicationCode}-{Vesion}</code></p>

<p><strong>RegExp</strong>    <br />
<code class="language-plaintext highlighter-rouge">^ecstd-(us-east-1|us-west-1|us-west-2|eu-west-1|eu-central-1|ap-northeast-1|ap-northeast-2|ap-southeast-1|ap-southeast-2|sa-east-1)-(dev|test|stg|prod)-([a-z0-9\-]+)-v1$</code></p>

<p><strong>Examples</strong>      <br />
<span style="color:silver;">
ecstd-us-east-1-prod-tomcat-v1
<br />
ecstd-us-east-1-prod-micro_app-v1
</span></p>

<h2 id="ecs-service-naming-conventions">ECS Service Naming Conventions</h2>

<p><strong>Default Pattern Format</strong>    <br />
<code class="language-plaintext highlighter-rouge">ecs-service_{RegionCode}_{EnvironmentCode}_{ApplicationCode}</code></p>

<p><strong>RegExp</strong>    <br />
<code class="language-plaintext highlighter-rouge">^ecs-service_(us-east-1|us-west-1|us-west-2|eu-west-1|eu-central-1|ap-northeast-1|ap-northeast-2|ap-southeast-1|ap-southeast-2|sa-east-1)_(dev|test|stg|prod)_([a-z0-9\-]+)$</code></p>

<p><strong>Examples</strong>      <br />
<span style="color:silver;">
ecs-service_us-east-1_prod_tomcat
<br />
ecs-service_us-east-1_prod_micro-app
</span></p>

<p><br /></p>
<blockquote>

  <p><span style="color:silver;">References</span></p>
  <ul>
    <li><a href="https://www.cloudconformity.com/knowledge-base/aws/VPC/vpc-naming-conventions.html#">Cloud Conformity VPCs</a></li>
    <li><a href="https://www.cloudconformity.com/knowledge-base/aws/EC2/ec2-instance-naming-conventions.html#">Cloud Conformity EC2</a></li>
  </ul>
</blockquote>]]></content><author><name>Carlos Requena</name></author><category term="[AWS] Amazon Web Services" /><summary type="html"><![CDATA["Our true nationality is mankind." --H. G. Wells]]></summary></entry><entry xml:lang="en"><title type="html">Apache Kafka Architecture &amp;amp; Fundamentals Q&amp;amp;A</title><link href="https://cjrequena.github.io/2020-06-03/apache-kafka-architecture-questions-en" rel="alternate" type="text/html" title="Apache Kafka Architecture &amp;amp; Fundamentals Q&amp;amp;A" /><published>2020-06-03T00:00:00+00:00</published><updated>2020-06-03T00:00:00+00:00</updated><id>https://cjrequena.github.io/2020-06-03/apache-kafka-architecture-questions-en</id><content type="html" xml:base="https://cjrequena.github.io/2020-06-03/apache-kafka-architecture-questions-en"><![CDATA[<div style="text-align:center"><span style="color:red;font-weight: bold">"To copy others is necessary, but to copy oneself is pathetic" </span> <span style="color:black;font-weight: bold">--Pablo Picasso.</span></div>

<h1 id="apache-kafka-architecture--fundamentals-qa">Apache Kafka Architecture &amp; Fundamentals Q&amp;A</h1>

<p><strong>These are the answers and questions from a tech talk led by <a href="https://www.confluent.io/">Confluent</a> about Apache Kafka Architecture and Fundamentals.</strong><object data="/assets/pdf/slides-apache-kafka-architecture-fundamentals.pdf" type="application/x-pdf" title="Slides Apache Kafka Architecture and Fundamentals" width="500" height="720">
    <a href="/assets/pdf/slides-apache-kafka-architecture-fundamentals.pdf">Slides Apache Kafka Architecture and Fundamentals</a>
</object>
<br /><br /></p>

<p><strong>How reliable is the data ingest to Kafka from the producer(s)?</strong><br />
Data can be acknowledged in the broker and also in copies (replicas) on other brokers. You have your choice of no ack, ack from the receiving broker, or ack once that one and all of the broker copies have successfully received the message.</p>

<p><br />
<strong>Does Kafka require Hadoop cluster infrastructure like MapReduce, HDFS, etc.?</strong>  <br />
No, a Kafka cluster of brokers requires only Kafka, and for now, Zookeeper</p>

<p><br />
<strong>Can we store in local storage or also on data lake storage?</strong>   <br />
Kafka can store on both - in memory initially and persisted on disk at an adjustable time after.</p>

<p><br />
<strong>Is the retention time the same for all brokers in a cluster? Or Can we set a different retention time for each broker?</strong><br />
Retention time can be set per topic, not per broker.</p>

<p><br />
<strong>Is there any way to keep the data rather than a generic retention time configuration setting? For example, if there is a slower moving set of topics compared to higher velocity data</strong> <br />
Yes - retention times are uniquely configurable based on the particular Kafka architectural design.</p>

<p><br />
<strong>If data expires within Broker’s local storage then does it mean it get lost? Suppose it has not been read/consumed by “all” the consumers of that data</strong><br />
Kafka doesn’t really support the concept of a specific piece of data having been consumed. It may be consumed by multiple consumers - or if your retention period is short and 
no consumers are consuming from the topic it is in, yes a particular record could be deleted without ever being consumed.</p>

<p><br />
<strong>Kafka brokers needs a separated master?</strong></p>

<p>I’m not sure what you mean by this question. Brokers work cooperatively in a cluster. At this time, they use Zookeeper for some coordination, although that requirement will be 
removed in the future.</p>

<p><br />
<strong>Are there local disks SSD or hard drives?</strong> <br />
Local disks for the broker can be of any type.</p>

<p><br />
<strong>Can some other components be used instead of Zookeeper?</strong>   <br />
No but Zookeeper is set to be deprecated at some point - please see KIP 500: https://www.confluent.io/blog/removing-zookeeper-dependency-in-kafka/</p>

<p><br />
<strong>Can Kafka be used in on-premise setup? If so what is the minimum system requirements/how many servers are required to configure Kafka?</strong><br />
Kafka can be run on as few as one server, but three would commonly be ideal for failover support.</p>

<p><br />
<strong>Is it kind of a layer in between source and target to stream the data directly without doing any data transformation?</strong> <br />
I’m a little unclear on the intent of this question. Yes, data can pass through Kafka without any transformation. Because the producers of the data and the consumers of the data 
are decoupled, and data is persisted on the cluster, data can be consumed by multiple different consumers over time. So data could be transported to many targets.</p>

<p><br />
<strong>If a message is successfully consumed, it is stored till the retention time any way?</strong>  <br />
Yes! Once received, messages are immutable until the retention period expires.</p>

<p><br />
<strong>Does the data stay on local storage for 5 days ?</strong>  <br />
The retention time, the time that data is preserved on local storage, is configurable by topic - so data could stay on one topic for 5 days and another for a much longer or 
shorter time. It is not uncommon to have transient data - that is just being passed through Kafka, to be retained for only a few hours. Some businesses store data on some topics 
for much longer - weeks, months, years or forever - depending on their business needs.</p>

<p><br /></p>

<p><strong>Is there a limit to the number of topics that a Broker node can handle?</strong>   <br />
There are best practices - but this is more of a logical limit, i.e., how many topics to keep track of. There needs to be enough, but not too many depending on the applications 
using Kafka.</p>

<p><br /></p>

<p><strong>Is Zookeeper platformed within a Kafka instance or do I have to stand up and operate a separate zookeeper instance to keep my cluster operational?</strong><br />
Yes, Zookeeper needs to be stood up when installing Kafka currently - but as Joe said it will be going away per KIP 500. Please see: https://www.confluent.io/blog/removing-zookeeper-dependency-in-kafka/</p>

<p><br /></p>

<p><strong>Can we have authorization enabled for consumer connecting using rest proxy having SASL_SSL security with SCRAM mechanism.?</strong><br />
This mechanism is for authentication - for authorization, you need to use ACLs (Access Control Lists) or the new RBAC (Role Based Access Control) which is a feature of the Confluent Platform, not open source Kafka.</p>

<p><br /></p>

<p><strong>Can kafka be used as permanent data store?</strong><br />
Yes! Kafka can be used as a permanent store, ksqlDB allows it to even be used as a form of a database!</p>

<p><br /></p>

<p><strong>Can we use a 3rd party enterprise metadata instead of the zookeeper?</strong>  <br />
At this time, Zookeeper is required. In the near future, Kafka clusters will be self managing and the Zookeeper requirement will be removed - but will not need any other 3rd party tools.</p>

<p><br /></p>

<p><strong>What does adding consumers mean? Does adding consumer mean adding a new node to the cluster?</strong>  <br />
Adding consumers means adding more applications that are reading from the cluster (brokers).</p>

<p><br /></p>

<p><strong>When kafka store data on local disk , what is preferred 1) one disk with 15tb of size or 2) 15 disks with 1tb size each?</strong>  <br />
OF course, that depends. Kafka is a distributed event system, so you can have multiple Kafka Brokers and then each will need to have its own local disk or disks.</p>

<p><br /></p>

<p><strong>Is it common to have a consumer that is also a producer? For example, a process that takes incoming messages and “enriches” them for later consumption by a different process?</strong><br />
Yes, it is common - in fact, any stream processing application both consumes data from Kafka and then producers transformed data back to Kafka.</p>

<p><br /></p>

<p><strong>If we request to produce or consume.. will it go to zookeeper or broker?</strong>  <br />
All clients - producers and consumers - communicate only with Kafka Brokers.</p>

<p><br /></p>

<p><strong>Can a message be consumed more than once by the same consumer?</strong><br />
Generally an individual consumer will only consume any message one time - however, a consumer can set its consumer offset - the point at which it is reading from a topic - and 
could then re-read any number of messages.</p>

<p><br /></p>

<p><strong>How is KAFKA different from a Message Queue MQ Series or ESB solutions?</strong>   <br />
The main difference is independence between the producer of messages and consumers of messages. The broker is in the middle as an independent handler of either 1) producer write or 2) 
consumer read requests in a given transaction.</p>

<p><br /></p>

<p><strong>What are the data formats that are supported by Kafka? Also where does the transformations happen for business rules?</strong> <br />
Kafka supports many data formats - there are many serializers of data types to include string, long, int, etc. Also there are many Schema formats to include Avro, Protobuf, 
and JSON Schema.</p>

<p><br /></p>

<p><strong>Any chance of message will be lost in Kafka?</strong>  <br />
It is possible for a message to be lost when produced to Kafka - you should look at the producer ACK configuration settings. If a producer sets ACKS=0, then it will just send a 
message and not care if it is received by a Broker or not.</p>

<p><br /></p>

<p><strong>I understand that the storage is always held by Zookeeper. Is it true or Can I set for instance Oracle as the persistence?</strong><br />
Message data in a Kafka cluster is only persisted on local Kafka Broker storage. It is not held by Zookeeper nor can you persist it to Oracle. You could, of course use Connect to 
move data from Kafka storage to Oracle if you wish.</p>

<p><br /></p>

<p><strong>Any scenarios where we don’t need Zookeeper or we should always use it? We have an environment implemented by consultants that does not use Zookeeper. There are also some articles 
on the Internet that talks about not using Zookeeper.</strong>   <br />
With the current release of Kafka, you must use Zookeeper. That requirement will be removed in a future release as Kafka clusters move to self management.</p>

<p><br /></p>

<p><strong>If a broker dies, is the producer data on broker lost, or is it replicated on other brokers as well so it is never lost?</strong>  <br />
When you create a topic, you define the amount of replication that topic requires. It is typical to have 3 replicas for a topic - which means that even if 2 brokers crash you 
can continue to produce to and consume from your topic without data loss.</p>

<p><br /></p>

<p><strong>Is retention time the only way to have data removed/dropped from the cluster or can it be set in a way that if a consumer has consumed the data then it can be dropped from the cluster?</strong>  <br />
Kafka doesn’t keep track of whether data has been consumed or not - there can be multiple consumers doing different tasks with the same data, or one consumer may choose to re-consume 
an entire topic - so retention time controls how long data will be stored on Kafka - on a per topic basis.</p>

<p><br /></p>

<p><strong>Can I add in Kafka code to enrich new data with some topic? Or need do outside in another process?</strong><br />
Yes! This is perfect for a Streams application if more than just a minimal addition is being done.</p>

<p><br /></p>

<p><strong>Would it be possible to stream the messages of size 25MB via kafka? Any limitations?</strong>  <br />
The default maximum message size on Kafka is 1 MB. While you can configure Kafka to use larger messages, it is not optimal to do so.</p>

<p><br /></p>

<p><strong>Can two producers write to the same Topic? Or is Topic specific to a Producer?</strong>  <br />
Yes - that is part of the beauty of Kafka! Multiple producers. And the same with consumers too! :-)</p>

<p><br /></p>

<p><strong>Is the kafka architecture based generally enough to handle multiple use cases, or is the architecture very bespoke depending on each customer use case?</strong>   <br />
Excellent question! For basic applications, it is general enough - but for more complicated ones, that for example may need to scale, it would need to become bespoke. Rather, the 
larger the Kafka architecture the more bespoke it generally needs to be.</p>

<p><br /></p>

<p><strong>What data producers will not connect to kafka?</strong><br />
To produce to Kafka, your producer needs to conform to Kafka protocols. The native APIs are Java based, but there are libraries for many other languages. If you are not able to 
use any of the available languages, you can send data to Kafka through the REST Proxy, which can communicate with any process that can send an HTTP REST request. You can also use 
Kafka Connect to move data from many standard data sources into Kafka.</p>

<p><br /></p>

<p><strong>Does data also split the data in between multiple partitions?</strong> <br />
A Kafka Producer will be able to send data to any partition of a topic - from the metadata it receives from a Kafka Broker, it knows where the leader broker is for each partition of 
a topic and it uses a partitioner to determine which partition to send data to.</p>

<p><br /></p>

<p><strong>How to decide the partition size for a topic ? What happens if we resize the topic once it is created with “N” partitions?</strong><br />
Great question that has a lot behind it. There are some White Papers and/or blog posts on the Confluent and Kafka websites that help address this. Much of what Joe is explaining is 
the basis for that! Yes, it’s possible to resize as an operation, but with some caveats.</p>

<p><br /></p>

<p><strong>If I need to post transactions extracted from 500 tables into kafka, 1.is that a good idea to create 500 topics for each table, to make sure the consumers reads it in the same 
insertion order</strong> <br />
Good point! Order is something that requires overhead to enforce in Kafka. So yes, you may end up needing to create individual topics to ensure order. But for what you reference, 
please check out Kafka Connect which may be able help handle that better.</p>

<p><br /></p>

<p><strong>Presenter mentioned that partitions are striped across brokers, but I thought broker cluster used leader and standby replicas? Are the brokers not replicated, but working in concert?</strong><br />
Each topic may be broken into a number of partitions - you define the number when you create a topic. Those partitions can reside on different brokers - and each broker will receive 
data appropriate for its own partitions. Partitions can also be replicated - so each partition will have a leader broker and some number of follower brokers.</p>

<p><br />
<strong>Are there any advantages of using just one single topic, collecting all those 500 table messages? I am afraid this would mix up the insertion order when consumers read 500 tables 
data from one single topic.</strong> <br />
Yes, to ensure order for sure you can use single topics each having single partitions. But there may be a way to design your application, depending on its needs, that could be more 
efficient - please check out the white papers and blog entries on confluent.io!</p>

<p><br /></p>

<p><strong>Compaction retention policy does or does not allow for mutation of messages?</strong>  <br />
Messages are not mutated once they arrive at a Kafka broker - that is an inherent part of the design - all messages are immutable. However, messages can be removed from a topic if 
it is compacted - but the content of the message will not change.</p>

<p><br /></p>

<p><strong>Can I change the sequences of the messages in the logs?</strong>   <br />
No - and yes. No you can’t change what’s been written to a log as it’s immutable. But you can further process what’s been written into a log, where you read it - and maybe 
even process it or add to it from say a DB - then write it to a different log. Pretty cool?! This is known as a Streams application.</p>

<p><br /></p>

<p><strong>So, the data written by producers need to be schema less right ? And consumer needs to understand that format right?</strong>  <br />
The data needs to be serialized to Kafka on the way in (produce), and deserialized on the way out (consume). You can use schemas to help control this.</p>

<p><br /></p>

<p><strong>How many offsets we can have in a stream?</strong> <br />
The offset number for a message in a partition is a 64 bit number, so you can have 2 to the 64th power number of messages in a partition. You can define your topic to have many 
partitions. A stream can have as many messages as the underlying topic.</p>

<p><br /></p>

<p><strong>Can I run Kafka on raspberry pi with small memory foot print. What is it’s memory foot print. I assuming memory foot print is configurable .please confirm.</strong>   <br />
Yes! Kafka will run on Raspberry Pi. Sorry I don’t have the memory requirements, you should be able to find them at https://kafka.apache.org/ and please also check out 
http://confluent.io !</p>

<p><br /></p>

<p><strong>Is there a chance of messages being out of sync, means the timestamp is not in order?</strong> <br />
As a producer you can define what the timestamp is - you could use the event time, when the event actually took place, or the time the message is produced by the producer or the 
ingest time, when the message is written by the Broker. So, yes, you could have messages in a topic that have timestamps that are out of order.</p>

<p><br /></p>

<p><strong>Is a log file equivalent to a segment? Partition has 1 to n log files</strong> <br />
Raphael, yes! log file = segment.</p>

<p><br /></p>

<p><strong>How to avoid multiple deliveries of same messages?</strong><br />
Simply you can turn on idempotence in your Kafka client code. You can also use Exactly Once Semantics - also known as EOS: https://www.confluent.io/blog/exactly-once-semantics-are-possible-heres-how-apache-kafka-does-it/</p>

<p><br /></p>

<p><strong>Can we use Kafka to process a large cuantiti of daily images, pdf documents as messages and storage?</strong>  <br />
Because the default message size is 1 MD in Kafka, it is not unusual to have image or pdf data directly in the messages. That said, you could chunk large messages - but then you are 
responsible for correctly reassembling them. Or, you can pass references in a message to images or pdf documents that are stored externally.</p>

<p><br /></p>

<p><strong>How do you typically handle duplicate messages? Let’s say we need to do some operation say write to a DB, but a consumer can receive the same message twice..And we aren’t able to 
know whether the item is already written to the DB or not when we receive the duplicate msg.</strong><br />
Please check this out - explains a lot of what I think you may want to know: https://www.confluent.io/blog/exactly-once-semantics-are-possible-heres-how-apache-kafka-does-it/</p>

<p><br /></p>

<p><strong>Are there any limitations if we use Python ? Does streaming support Python?</strong>   <br />
Python is a supported language for writing Kafka producer and consumer code. However Java is the closest to Kafka’s source code.</p>]]></content><author><name>Carlos Requena</name></author><category term="Apache Kafka" /><summary type="html"><![CDATA["To copy others is necessary, but to copy oneself is pathetic" --Pablo Picasso.]]></summary></entry><entry xml:lang="en"><title type="html">[AWS] How to create a billing alarm</title><link href="https://cjrequena.github.io/2020-04-30/aws-billing-alarm-en" rel="alternate" type="text/html" title="[AWS] How to create a billing alarm" /><published>2020-04-30T00:00:00+00:00</published><updated>2020-04-30T00:00:00+00:00</updated><id>https://cjrequena.github.io/2020-04-30/aws-billing-alarm-en</id><content type="html" xml:base="https://cjrequena.github.io/2020-04-30/aws-billing-alarm-en"><![CDATA[<p><span style="color:red"><strong>“To know that we know what we know, and to know that we do not know what we do not know, that is true knowledge.”</strong></span>
<span style="color:black;font-weight: bold">–Nicolaus Copernicus</span></p>

<h1 id="how-to-create-an-aws-billing-alarm">How to create an AWS billing alarm</h1>

<ol>
  <li>Set the billing preference, check and enable the option to receive billing alerts.</li>
  <li>Go to Cloud Watch console.</li>
  <li>Change the region, make sure your AWS region is settled to US EAST (N. Virginia).</li>
  <li>Create an alarm, click on Alarms on the left side of the panel and in the dashboard that pops up click on the orange button that says <strong>“Create alarm”</strong>.</li>
  <li>Select a metric, in the panel that pops up, click the button that says <strong>“Select metric”</strong>. This will pop up a window that allows you to choose which
type of service you would like to use. <strong>Select Billing</strong></li>
  <li>Select the service, in the next window you can choose the total estimated charged on your account.</li>
  <li>Select the period of time that the alarm will be activated.</li>
  <li>Set the threshold.</li>
  <li>Create a notification using SNS, you just click on <strong>Create new topic</strong> give it a name and enter the email where you want to receive the notification.</li>
  <li>Add a description.</li>
  <li>Click on Preview and create</li>
</ol>]]></content><author><name>Carlos Requena</name></author><category term="[AWS] Amazon Web Services" /><summary type="html"><![CDATA[“To know that we know what we know, and to know that we do not know what we do not know, that is true knowledge.” –Nicolaus Copernicus]]></summary></entry><entry xml:lang="en"><title type="html">[AWS] Simple Storage Service S3</title><link href="https://cjrequena.github.io/2020-04-24/aws-s3-en" rel="alternate" type="text/html" title="[AWS] Simple Storage Service S3" /><published>2020-04-24T00:00:00+00:00</published><updated>2020-04-24T00:00:00+00:00</updated><id>https://cjrequena.github.io/2020-04-24/aws-s3-en</id><content type="html" xml:base="https://cjrequena.github.io/2020-04-24/aws-s3-en"><![CDATA[<p><span style="color:red"><strong>“Emergencies have always been the pretext on which the safeguards of individual liberty have been eroded.”</strong></span>
<span style="color:black;font-weight: bold">–Friedrich August von Hayek</span></p>

<h1 id="simple-storage-service-s3">Simple Storage Service (S3)</h1>

<p>Amazon Simple Storage Service (Amazon S3) is an object storage service that offers industry-leading scalability, data availability, security, 
and performance. This means customers of all sizes and industries can use it to store and protect any amount of data for a range of use cases, 
such as websites, mobile applications, backup and restore, archive, enterprise applications, IoT devices, and big data analytics.</p>

<p>Amazon S3 provides easy-to-use management features so you can organize your data and configure finely-tuned access controls to meet your specific 
business, organizational, and compliance requirements.</p>

<p>Amazon S3 is designed for 99.999999999% (11 9’s) of durability, and stores data for millions of applications for companies all around the world.</p>

<p>You can use S3 to store and retrieve any amount of data at any time, from anywhere on the web.</p>

<h2 id="the-basics-of-s3-are">The basics of S3 are</h2>

<ul>
  <li>S3 is object-based and allow you to upload files.</li>
  <li>Files can be from 0 Bytes to 5TB</li>
  <li>There is unlimited storage</li>
  <li>Files are store in buckets. Think about bucket as folders.</li>
  <li>S3 is a universal namespace, this means that the name of the bucket must be unique globally.</li>
  <li>When you upload a file to S3, you will receive a http 200 code if the upload was successful</li>
</ul>

<h2 id="s3-objects">S3 Objects</h2>

<p>Think of objects just as files. Objects consist of the following:</p>

<ul>
  <li><strong>Key:</strong> This is simply the name of the object.</li>
  <li><strong>Value:</strong> This is simply the data and is made up of a sequence of Bytes.</li>
  <li><strong>VersionId:</strong> Used for versioning</li>
  <li><strong>Metadata:</strong>   Data about the data you are storing</li>
  <li><strong>Sub-resources:</strong>  ACLs, torrent</li>
</ul>

<h2 id="s3-data-consistency">S3 data consistency</h2>

<ul>
  <li>
    <p><strong>Read after write consistency for PUTS of new objects</strong>, this means that if you upload a file for first time you will be able to read it immediately.</p>
  </li>
  <li>
    <p><strong>Eventual consistency for overwrite PUTS and DELETES</strong>, this means that if you upload or update or delete an existing file and try to read it immediately
you may get the older version or you may not, basically changes to objects can take a little bit of time to propagate.</p>
  </li>
</ul>

<h2 id="s3-features">S3 features</h2>

<ul>
  <li>Tired storage availability (S3 standard, S3-IA, S3-OneZone-IA, S3 Intelligent Tiering, S3 Glacier, S3 Glacier deep archive).</li>
  <li>Lifecycle management.</li>
  <li>Versioning.</li>
  <li>Encryption.</li>
  <li>MFA for delete.</li>
  <li>Secure your data using access control lists ACLs and bucket policies.</li>
</ul>

<h2 id="s3-storage-classes-and-tiers">S3 storage classes and tiers.</h2>

<ul>
  <li>
    <p><strong>S3 Standard:</strong> 99.99% availability and 99.99999999999% durability, store your objects redundantly across multiple devices in multiple facilities
and is designed to sustain the loss of two facilities concurrently.</p>
  </li>
  <li>
    <p><strong>S3-IA Infrequent Access:</strong> Is for data that is less frequently accessed but requires rapid access when needed. It has a lower fee than S3 Standard,
but you will be charged a retrieval fee.</p>
  </li>
  <li>
    <p><strong>S3 One Zone Infrequent Access:</strong> For where you want a low-cost option for infrequently accessed data, but that does not require the multiple availability
zone data resilience.</p>
  </li>
  <li>
    <p><strong>S3 Intelligent-Tiering:</strong> Designed to optimize costs by automatically moving data to the most cost-effective access tier, without performance impact
or operational overhead.</p>
  </li>
  <li>
    <p><strong>S3 Glacier:</strong> Is a secure, durable and low-cost storage class for data archiving. You can reliably store any amount of data at costs that are competitive
with or cheaper than on-premise solutions. Retrieval times is configurable from minutes to hours.</p>
  </li>
  <li>
    <p><strong>S3 Glacier Deep Archiving:</strong> Is the amazon S3 lower-cost storage class where a retrieval time of 12 hours is acceptable.</p>
  </li>
</ul>

<h2 id="s3-performance">S3 performance</h2>
<p>Your application can achieve at least 3,500 PUT/COPY/POST/DELETE or 5,500 GET/HEAD requests per second per partitioned
prefix. There are no limits to the number of prefixes in a bucket. You can increase your read or write performance by 
using parallelization. For example, if you create 10 prefixes in an Amazon S3 bucket to parallelize reads, you could 
scale your read performance to 55,000 read requests per second. Similarly, you can scale write operations by writing 
to multiple prefixes.</p>

<p><a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/optimizing-performance.html">Optimizing Amazon S3 performance</a></p>

<h2 id="s3-security-and-encryption">S3 Security and Encryption</h2>

<p>By default, all newly created bucket are private, you can setup access control to your bucket using:</p>

<ul>
  <li>Bucket policies at bucket level.</li>
  <li>Access Control List ACLs at objects level.</li>
</ul>

<p>S3 buckets can be configured to create access logs which log all requests made to the S3 bucket. This can be sent to another bucket and even another
bucket in another account.</p>

<h3 id="encryption-in-transit">Encryption in transit</h3>

<p>Encryption in transit is achieved by SSL/TLS</p>

<h3 id="encryption-at-rest-server-side">Encryption at rest (Server Side)</h3>

<ul>
  <li><strong>S3 Manage Keys SS3-S3:</strong> Where Amazon manages all the keys</li>
  <li><strong>AWS Key Management Service SSE-KMS:</strong> Where you and Amazon manage the keys</li>
  <li><strong>Server Side Encryption</strong> Where you provide the KEY-SSE-C and give to Amazon your own keys that you manage.</li>
</ul>

<h3 id="encryption-at-rest-client-side">Encryption at rest (Client Side)</h3>

<p>Where you upload your files already encrypted using your own keys.</p>

<h2 id="s3-versioning">S3 Versioning</h2>

<ul>
  <li>Stores all versions of an object (Including all writes and even if you delete an object)</li>
  <li>Once enabled, versioning cannot be disabled but only suspended.</li>
  <li>Versioning is integrated with lifecycle rules.</li>
  <li>Versioning has MFA capabilities, which uses multi-factor authentication to provide an additional layer of security.</li>
</ul>

<h2 id="s3-lifecycle-management">S3 Lifecycle management</h2>

<p>Uses lifecycle rules to manage your objects, which define how Amazon S3 manages objects during lifetime. Lifecycle rules enable you to automatically
transition objects among the different storage classes and tier from S3 to Glacier. Using a lifecycle rule you can automatically expire objects based
on your retention needs or clean up incomplete multi-parts uploads.</p>

<h2 id="sharing-s3-buckets-and-objects-across-accounts">Sharing S3 buckets and objects across accounts.</h2>

<p>There three ways to share buckes across accounts.</p>

<ul>
  <li><strong>Using bucket policies and IAM</strong> Applies across the entire bucket and provide programmatic access only.</li>
  <li><strong>Using ACLs and IAM</strong> Applies to individual objects and provide programmatic access only.</li>
  <li><strong>Cross-Account IAM Roles</strong> Provides programmatic and console access.</li>
  <li>See <a href="https://docs.aws.amazon.com/AmazonS3/latest/dev/example-walkthroughs-managing-access.html">Example walkthroughs: Managing access to your amazon S3 resources</a></li>
</ul>

<h2 id="s3-cross-region-replication">S3 Cross region replication</h2>

<p>Replication enables automatic, asynchronous copying of objects across Amazon S3 buckets. Buckets that are configured for object replication can be owned by the same AWS account or by different accounts. You can copy objects between different AWS Regions or within the same Region.</p>

<ul>
  <li>Versioning must be enabled on both the source and the destination buckets.</li>
  <li>Files in an existing bucket are not replicated automatically.</li>
  <li>All subsequent updated files will be replicated automatically.</li>
  <li>Delete markers are not replicated.</li>
  <li>Deleting individual versions or delete markers will not be replicated.</li>
</ul>

<p>To enable object replication, you add a replication configuration to your source bucket. The minimum configuration must provide the following:</p>

<ul>
  <li>The destination bucket where you want Amazon S3 to replicate objects</li>
  <li>An AWS Identity and Access Management (IAM) role that Amazon S3 can assume to replicate objects on your behalf</li>
</ul>

<h2 id="s3-transfer-acceleration">S3 Transfer acceleration.</h2>

<p>S3 transfer acceleration uses the Cloud Front edge network to accelerate your uploads to S3 instead of uploading directly to your S3 bucket, you can
use a distinct URL to upload your files to an edge location which then transfer that files to S3 using the Amazon enhanced network.</p>

<p>Enables fast, easy and secure transfer of files over long distances between your clients and an S3 bucket. S3 transfer acceleration takes advantage of Amazon
CloudFront globally distributed edge locations as the data arrives at an edge location and then is routed to an S3 bucket over an optimized network path.</p>

<p>You will get a distinct URL to upload your files, example: buckt-name.s3-accelerate.amazonaws.com</p>

<h2 id="how-is-s3-billed">How is S3 billed</h2>

<ul>
  <li>For storage.</li>
  <li>For requests.</li>
  <li>For storage management.</li>
  <li>For data transfer.</li>
  <li>For transfer acceleration.</li>
  <li>For cross-region replication.</li>
</ul>]]></content><author><name>Carlos Requena</name></author><category term="[AWS] Amazon Web Services" /><summary type="html"><![CDATA[“Emergencies have always been the pretext on which the safeguards of individual liberty have been eroded.” –Friedrich August von Hayek]]></summary></entry><entry xml:lang="en"><title type="html">[AWS] Identity and Access Management IAM</title><link href="https://cjrequena.github.io/2020-04-06/aws-iam-en" rel="alternate" type="text/html" title="[AWS] Identity and Access Management IAM" /><published>2020-04-06T00:00:00+00:00</published><updated>2020-04-06T00:00:00+00:00</updated><id>https://cjrequena.github.io/2020-04-06/aws-iam-en</id><content type="html" xml:base="https://cjrequena.github.io/2020-04-06/aws-iam-en"><![CDATA[<p><span style="color:red"><strong>“The real tragedy of the poor is the poverty of their aspirations.”</strong></span>
<span style="color:black;font-weight: bold">–Adam Smith.</span></p>

<h1 id="aws-identity-and-access-management-iam">AWS Identity and Access Management (IAM)</h1>
<p>Is a web service that helps you securely control access to AWS resources. You use IAM to control who is authenticated (signed in) and authorized (has permissions) 
to use resources. IAM allows you to manage users and their level of access to the aws console.</p>

<h2 id="iam-key-terminology">IAM Key terminology</h2>

<ul>
  <li><strong>Users</strong> End user such as people, employees of an organization, etc.</li>
  <li><strong>Groups</strong> A collection of users. Each user in the group will inherit the permissions of the group.</li>
  <li><strong>Policies</strong> Policies are made of documents, called policy documents. These documents are in JSON format and they give permissions as to what a user/group is able
to do.</li>
  <li><strong>Roles</strong> You create roles a then assign them to AWS resources.</li>
</ul>

<h2 id="iam-tips">IAM Tips</h2>

<ul>
  <li>IAM is universal. It does not apply to regions at this time.</li>
  <li>The root account is simply the account created when first setup your AWS account. It has complete admin access.</li>
  <li>New users has NO permissions when first created.</li>
  <li>New users are assigned and Access Key and an Secret Key when first created.</li>
  <li>You cannot use the access key and the secret key to login into the console.</li>
  <li>You can view the access key and the secret key once, if you lose it you have to regenerate them.</li>
  <li>Always set up Multifactor Authentication especially for the root account.</li>
  <li>You can create and customise your own password rotation policies.</li>
</ul>

<h2 id="iam-best-practices">IAM Best practices</h2>
<ul>
  <li>
    <p><strong>Lock Away Your AWS Account Root User Access Keys</strong> You use an access key (an access key ID and secret access key) to make programmatic requests to AWS. However, do not use 
your AWS account root user access key. The access key for your AWS account root user gives full access to all your resources for all AWS services, including your billing information. 
You cannot reduce the permissions associated with your AWS account root user access key.</p>
  </li>
  <li>
    <p><strong>Create Individual IAM Users</strong> Don’t use your AWS account root user credentials to access AWS, and don’t give your credentials to anyone else. Instead, create individual users 
for anyone who needs access to your AWS account. Create an IAM user for yourself as well, give that user administrative permissions, and use that IAM user for all your work. 
For information about how to do this, see <a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/getting-started_create-admin-group.html">Creating Your First IAM Admin User and Group.</a></p>
  </li>
  <li>
    <p><strong>Use Groups to Assign Permissions to IAM Users</strong> Instead of defining permissions for individual IAM users, it’s usually more convenient 
to create groups that relate to job functions (administrators, developers, accounting, etc.). Next, define the relevant permissions for each 
group. Finally, assign IAM users to those groups.</p>
  </li>
  <li>
    <p><strong>Grant Least Privilege</strong> When you create IAM policies, follow the standard security advice of granting least privilege, or granting only
the permissions required to perform a task. Determine what users (and roles) need to do and then craft policies that allow them to perform only 
those tasks.</p>
  </li>
  <li>
    <p><strong>Get Started Using Permissions with AWS Managed Policies</strong> To get started quickly, you can use AWS managed policies to give your employees 
the permissions they need to get started. These policies are already available in your account and are maintained and updated by AWS. For more 
information about AWS managed policies, see <a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_managed-vs-inline.html#aws-managed-policies">AWS Managed Policies.</a></p>
  </li>
  <li>
    <p><strong>Use Customer Managed Policies Instead of Inline Policies</strong> For custom policies, we recommend that you use managed policies instead of inline 
policies. A key advantage of using these policies is that you can view all of your managed policies in one place in the console. You can also 
view this information with a single AWS CLI or AWS API operation. Inline policies are policies that exist only on an IAM identity 
(user, group, or role). Managed policies are separate IAM resources that you can attach to multiple identities. For more information, 
see <a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_managed-vs-inline.html">Managed Policies and Inline Policies.</a></p>
  </li>
  <li>
    <p><strong>Use Access Levels to Review IAM Permissions</strong> When you review a policy, you can view the policy summary that includes a summary 
of the access level for each service within that policy. AWS categorizes each service action into one of five access levels based on 
what each action does: List, Read, Write, Permissions management, or Tagging. You can use these access levels to determine which actions 
to include in your policies.</p>
  </li>
  <li>
    <p><strong>Configure a Strong Password Policy for Your Users</strong> If you allow users to change their own passwords, require that they create 
strong passwords and that they rotate their passwords periodically. On the Account Settings page of the IAM console, you can create a 
password policy for your account. You can use the password policy to define password requirements, such as minimum length, whether it 
requires non-alphabetic characters, how frequently it must be rotated, and so on. 
For more information, see Setting an <a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_passwords_account-policy.html">Account Password Policy for IAM Users.</a></p>
  </li>
  <li>
    <p><strong>Enable MFA</strong> For extra security, we recommend that you require multi-factor authentication (MFA) for all users in your account.</p>
  </li>
  <li>
    <p><strong>Use Roles for Applications That Run on Amazon EC2 Instances</strong> Applications that run on an Amazon EC2 instance need credentials 
in order to access other AWS services. To provide credentials to the application in a secure way, use IAM roles. A role is an entity 
that has its own set of permissions, but that isn’t a user or group.</p>
  </li>
  <li>
    <p><strong>Use Roles to Delegate Permissions</strong> Don’t share security credentials between accounts to allow users from another AWS account to 
access resources in your AWS account. Instead, use IAM roles. You can define a role that specifies what permissions the IAM users in the 
other account are allowed. You can also designate which AWS accounts have the IAM users that are allowed to assume the role.</p>
  </li>
  <li>
    <p><strong>Do Not Share Access Keys</strong> Access keys provide programmatic access to AWS. Do not embed access keys within unencrypted code or 
share these security credentials between users in your AWS account. For applications that need access to AWS, configure the program to 
retrieve temporary security credentials using an IAM role. To allow your users individual programmatic access, create an IAM user with 
personal access keys.</p>
  </li>
  <li>
    <p><strong>Rotate Credentials Regularly</strong> Change your own passwords and access keys regularly, and make sure that all IAM users in your 
account do as well.</p>
  </li>
  <li>
    <p><strong>Remove Unnecessary Credentials</strong> Remove IAM user credentials (passwords and access keys) that are not needed.</p>
  </li>
  <li>
    <p><strong>Use Policy Conditions for Extra Security</strong> To the extent that it’s practical, define the conditions under which your IAM policies 
allow access to a resource. For example, you can write conditions to specify a range of allowable IP addresses that a request must come from. 
You can also specify that a request is allowed only within a specified date range or time range. You can also set conditions that require 
the use of SSL or MFA (multi-factor authentication). For example, you can require that a user has authenticated with an MFA device in order 
to be allowed to terminate an Amazon EC2 instance. 
For more information, see <a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_condition.html">IAM JSON Policy Elements: Condition in the IAM Policy Elements Reference.</a></p>
  </li>
  <li>
    <p><strong>Monitor Activity in Your AWS Account</strong> You can use logging features in AWS to determine the actions users have taken in your 
account and the resources that were used. The log files show the time and date of actions, the source IP for an action, which actions 
failed due to inadequate permissions, and more.</p>
  </li>
  <li>
    <p><a href="https://www.youtube.com/watch?time_continue=1734&amp;v=_wiGpBQGCjU&amp;feature=emb_logo">Video Presentation About IAM Best Practices</a></p>
  </li>
</ul>

<h2 id="references">References</h2>

<ul>
  <li><a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/introduction.html">AWS Identity And Access Management</a></li>
</ul>]]></content><author><name>Carlos Requena</name></author><category term="[AWS] Amazon Web Services" /><summary type="html"><![CDATA[“The real tragedy of the poor is the poverty of their aspirations.” –Adam Smith.]]></summary></entry></feed>