<?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-04-02T14:32:25+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] 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><entry xml:lang="en"><title type="html">[BITCOIN] Keys and Addresses</title><link href="https://cjrequena.github.io/2019-12-03/bitcoin-keys-and-addresses" rel="alternate" type="text/html" title="[BITCOIN] Keys and Addresses" /><published>2019-12-03T00:00:00+00:00</published><updated>2019-12-03T00:00:00+00:00</updated><id>https://cjrequena.github.io/2019-12-03/bitcoin-keys-and-addresses</id><content type="html" xml:base="https://cjrequena.github.io/2019-12-03/bitcoin-keys-and-addresses"><![CDATA[<div style="text-align:center"><span style="color:red;font-weight: bold">"Our virtues and our failings are inseparable, like force and matter. When they separate, man is no more." </span> <span style="color:black;font-weight: bold">--Nikola Tesla.</span></div>

<p><br />
You may have heard that Bitcoin is based on cryptography, which is a branch of mathematics used extensively in computer security. Cryptography means
“secret writing” in Greek, but the science of cryptography encompasses more than just secret writing, which is referred to as encryption.
Cryptography can also be used to prove knowledge of a secret without revealing that secret (digital signature), or prove the authenticity of data
(digital fingerprint). These types of cryptographic proofs are the mathematical tools critical to bitcoin and used extensively in bitcoin applications.</p>

<p>Ironically, encryption is not an important part of bitcoin, as its communications and transaction data are not encrypted and do not need to be encrypted
to protect the funds.   <a href="https://github.com/bitcoinbook/bitcoinbook/blob/develop/ch04.asciidoc#keys-addresses">mastering bitcoin</a></p>

<p>ECDSA (‘Elliptic Curve Digital Signature Algorithm’) is the cryptography behind private and public keys used in Bitcoin. It consists of combining the math behind finite fields 
and elliptic curves to create one way equations, meaning you can choose your private key “Pick a number between 1 and \(2^{256}\).” and easily calculate your public key 
(some other number). However, You can not take the public key and easily calculate their private key. In fact, for Bitcoin it would take trillions of computers trillions of years 
of continuous guessing of different private keys to figure out which one creates a given public key. <a href="https://medium.com/@blairlmarshall/how-does-ecdsa-work-in-bitcoin-7819d201a3ec">How does ECDSA work in Bitcoin</a></p>

<h1 id="elliptic-curve-cryptography-ecc">Elliptic curve cryptography (ECC)</h1>

<p><strong>Elliptic curve cryptography (ECC)</strong> is based on the discrete logarithm problem that is based on elliptic curves over finite fields (Galois fields).
The main benefit of ECC over other types of public key algorithms is that it needs a smaller key size while providing the same level of security as, f
or example, RSA.</p>

<p>An elliptic curve will simply be the set of points described by the equation:</p>

\[\displaystyle y^{2} \ =\ x^{3} \ +\ ax\ +\ b\ where\ 4a^{3} \ +\ 27b^{2} \ \neq \ 0\]

<p>(this is required to exclude <a href="https://en.wikipedia.org/wiki/Singularity_(mathematics)">singular curves</a>) The equation above is what is called Weierstrass normal
form for elliptic curves.</p>

<p>If we want to explicitly take into account the point at infinity, we can refine our definition of elliptic curve as follows:</p>

\[\left\{( x,y) \ \in \mathbb{R}^{2} \ |\ y^{2} =x^{3} +ax+b,\ 4a^{3} +27b^{2} \neq 0\right\} \ \cup \ \{0\}\]

<h2 id="algebraic-addition">Algebraic addition</h2>

<p>Algebraic formulae are constructed to efficiently compute the geometric arithmetic.</p>

<h3 id="adding-distinct-points-p-and-q">Adding distinct points P and Q</h3>

<p><img src="/assets/images/bitcoin/elliptic_curve_point_addition.png" alt="" /></p>

\[\begin{array}{l}

When\ P=({X_p},{Y_p}) \ and\ Q=({X_q},{Y_q}) \ and \ they \ are \ not \ negative \ of \ each \ other \\  

P + Q = R \\

{X_r}= m^{2} − {X_p} - {X_q} \\

{Y_r} = -{Y_p} + m({X_p} - {X_r}) \\

where \ m= \frac { ({Y_p} - {Y_q}) } { ({X_p} - {X_q}) } \\

\end{array}\]

<p><strong>Note that m is the slope of the line through P and Q.</strong></p>

<h2 id="doubling-the-point-p">Doubling the point P</h2>

<p><img src="/assets/images/bitcoin/elliptic_curve_scalar_multiplication.png" alt="" /></p>

<p>When P and Q share the same position (X and Y wise), addind two points (P and Q ) that share the same location <strong>is called “Doubling the point P” also referred as adding a point to itself.</strong></p>

\[\begin{array}{l}

When\ {Y_p} \neq 0,\ 2P\ =\ R\ \\

{X_r} = m^{2}  − {2X_p} \\

{Y_r} = -{Y_p} \ +\ m({X_p} \ -\ {X_r}) \\

Where\ m\ =\ \frac{\left( 3Xp^{2} \ +\ a\right)}{( 2Yp\ )} \\

m \ is \ the \ slope \ of \ the \ tangent \ line \ when \ point \ P \ and \ point \ Q \ are \ or \ tend \ to \ be \ equal, \\

then \ deriving \\

\frac{\text{d}y(x)}{\text{d}x}(\sqrt{x^{3} + 7 + a})  =  \frac{\left( 3X^{2} \ +\ a\right)}{( 2Y\ )} \\




\end{array}\]

<p><strong>Recall that a is one of the parameters chosen with the elliptic curve and that m is the tangent on the point P.</strong></p>

<h2 id="elliptic-curve-point-multiplication">Elliptic curve point multiplication</h2>

<p>Elliptic curve point multiplication is the operation of successively adding a point along an elliptic curve to itself repeatedly. It is used in elliptic curve cryptography (ECC) 
as a means of producing a one-way function. The literature presents this operation as scalar multiplication, thus the most common name is elliptic curve scalar multiplication, as 
written in Hessian form of an elliptic curve. <a href="https://en.wikipedia.org/wiki/Elliptic_curve_point_multiplication">wikipedia</a></p>

<p>Point addition and point doubling allow us to define scalar multiplication for elliptic curves such that, xP = R where x is a scalar, P is a point tangent to the curve and R is the 
resulting point from adding P on to itself x times.</p>

<p>The straightforward way of computing a point multiplication is through repeated addition. However, this is a fully exponential approach to computing the multiplication.</p>

<p>There are several algorithms used to calculate the scalar multiplication:</p>

<ul>
  <li>
    <p><a href="https://en.wikipedia.org/wiki/Elliptic_curve_point_multiplication">Elliptic curve point multiplication</a></p>
  </li>
  <li>
    <p><a href="https://eprint.iacr.org/2014/427.pdf">Fast point multiplication algorithms for binary elliptic curveswith and without precomputation</a></p>
  </li>
</ul>

<h1 id="elliptic-curve-digital-signature-algorithm-ecdsa">Elliptic Curve Digital Signature Algorithm <strong>(ECDSA)</strong></h1>

<p><strong>Bitcoin</strong> uses the Elliptic Curve Digital Signature Algorithm <strong>(ECDSA)</strong> based on elliptic curve cryptography. The particular elliptic
curve is known as <a href="https://en.bitcoin.it/wiki/Secp256k1">secp256k1</a>, which is the curve <strong>Elliptic curve cryptography (ECC)</strong>.</p>

\[\displaystyle y^{2} \ =\ x^{3}+7\]

<p>The elliptic curve domain parameters over Fp associated with a Koblitz curve secp256k1 are specified by the sextuple</p>

<p>T = (p,a,b,G,n,h) where the finite field Fp is defined by:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>p = FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F
= 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 24 - 1
</code></pre></div></div>

\[\displaystyle The\ curve\ E:\ y^{2} \ =\ x^{3} +ax+b\ over\ Fp\ is\ defined\ by:\]

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>a = 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
b = 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000007
</code></pre></div></div>

<p>The base point G in compressed form is:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>G = 02 79BE667E F9DCBBAC 55A06295 CE870B07 029BFCDB 2DCE28D9 59F2815B 16F81798
</code></pre></div></div>

<p>and in uncompressed form is:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>G = 04 79BE667E F9DCBBAC 55A06295 CE870B07 029BFCDB 2DCE28D9 59F2815B 16F81798 483ADA77 26A3C465 5DA4FBFC 0E1108A8 FD17B448 A6855419 9C47D08F FB10D4B8
</code></pre></div></div>

<p>Finally the order n of G and the cofactor are:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>n = FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE BAAEDCE6 AF48A03B BFD25E8C D0364141
h = 01
</code></pre></div></div>

<p><strong>secp256k1</strong> has characteristic p, it is defined over the prime field ℤp. Some other curves in common use have characteristic 2, and are defined over a binary Galois field GF(2n), but secp256k1 is not one of them.</p>

<p>As the a constant is zero, the ax term in the curve equation is always zero, hence the curve equation becomes \(\displaystyle y^{2} \ =\ x^{3}+7\)</p>

<h2 id="private-and-public-keys">Private and Public Keys</h2>

<p>A bitcoin wallet contains a collection of key pairs, each consisting of a private key and a public key. The private key (k) is a number, usually picked at
random. <a href="https://github.com/bitcoinbook/bitcoinbook/blob/develop/ch04.asciidoc#keys-addresses">mastering bitcoin</a></p>

<h3 id="private-keys">Private Keys</h3>

<p>A private key is simply a number, picked at random. Ownership and control over the private key is the root of user control over all funds associated with
the corresponding bitcoin address. The private key is used to create signatures that are required to spend bitcoin by proving ownership of funds used in a
transaction. The private key must remain secret at all times, because revealing it to third parties is equivalent to giving them control over the
bitcoin secured by that key. The private key must also be backed up and protected from accidental loss, because if it’s lost it cannot be recovered and
the funds secured by it are forever lost, too. <a href="https://github.com/bitcoinbook/bitcoinbook/blob/develop/ch04.asciidoc#private-keys">mastering bitcoin</a></p>

<h3 id="generating-a-private-key-from-a-random-number">Generating a private key from a random number</h3>

<p>The first and most important step in generating keys is to find a secure source of entropy, or randomness. Creating a bitcoin key is essentially the same as
“Pick a number between 1 and \(2^{256}\).” The exact method you use to pick that number does not matter as long as it is not predictable or repeatable.
Bitcoin software uses the underlying operating system’s random number generators to produce 256 bits of entropy (randomness). Usually, the OS random number
generator is initialized by a human source of randomness, which is why you may be asked to wiggle your mouse around for a few seconds. <a href="https://github.com/bitcoinbook/bitcoinbook/blob/develop/ch04.asciidoc#generating-a-private-key-from-a-random-number">mastering bitcoin</a></p>

<p>More precisely, the private key can be any number between 0 and n - 1 inclusive, where n is a constant (n = 1.1578 * 1077, slightly less than \(2^{256}\)) defined
as the order of the elliptic curve used in bitcoin. <a href="https://github.com/bitcoinbook/bitcoinbook/blob/develop/ch04.asciidoc#generating-a-private-key-from-a-random-number">mastering bitcoin</a></p>

<h3 id="private-key-wallet-import-format">Private Key Wallet import format</h3>

<p>1 - Take a private key</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0C28FCA386C7A227600B2FE50B7CAE_SAMPLE_PRIVATE_KEY_DO_NOT_IMPORT_11EC86D3BF1FBE471BE89827E19D72AA1D
</code></pre></div></div>

<p>2 - Add a 0x80 byte in front of it for mainnet addresses or 0xef for testnet addresses. Also add a 0x01 byte at the end if the private key will correspond to a compressed public key</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>800C28FCA386C7A227600B2FE50B7C_SAMPLE_PRIVATE_KEY_DO_NOT_IMPORT_AE11EC86D3BF1FBE471BE89827E19D72AA1D
</code></pre></div></div>

<p>3 - Perform SHA-256 hash on the extended key</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>8147786C4D15106333BF278D71DADAF1079EF2D2440A4DDE37D747DED5403592
</code></pre></div></div>

<p>4 - Perform SHA-256 hash on result of SHA-256 hash</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>507A5B8DFED0FC6FE8801743720CEDEC06AA5C6FCA72B07C49964492FB98A714
</code></pre></div></div>

<p>5 - Take the first 4 bytes of the second SHA-256 hash, this is the checksum</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>507A5B8D
</code></pre></div></div>

<p>6 - Add the 4 checksum bytes from point 5 at the end of the extended key from point 2</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>800C28FCA386C7A227600B2FE50B7CAE11EC8_SAMPLE_PRIVATE_KEY_DO_NOT_IMPORT_6D3BF1FBE471BE89827E19D72AA1D507A5B8D
</code></pre></div></div>

<p>7 - Convert the result from a byte string into a base58 string using Base58Check encoding. This is the Wallet Import Format</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>5HueCGU8rMjxEXxiPuD5BDk_SAMPLE_PRIVATE_KEY_DO_NOT_IMPORT_u4MkFqeZyd4dZ1jvhTVqvbTLvyTJ
</code></pre></div></div>

<h4 id="sample-java-code">Sample Java Code</h4>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="k">try</span> <span class="o">{</span>
      <span class="c1">// 1 - Take a private key</span>
      <span class="nc">String</span> <span class="n">privateKey</span> <span class="o">=</span> <span class="s">"0C28FCA386C7A227600B2FE50B7CAE11EC86D3BF1FBE471BE89827E19D72AA1D"</span><span class="o">;</span>

      <span class="c1">// 2 - Add a 0x80 byte in front of it for mainnet addresses or 0xef for testnet addresses.</span>
      <span class="c1">// Also add a 0x01 byte at the end if the private key will correspond to a compressed public key</span>
      <span class="nc">String</span> <span class="n">privateKeyWIF</span> <span class="o">=</span> <span class="s">"80"</span> <span class="o">+</span> <span class="n">privateKey</span><span class="o">;</span>

      <span class="c1">// 3 - Perform SHA-256 hash on the extended key</span>
      <span class="nc">MessageDigest</span> <span class="n">sha256</span> <span class="o">=</span> <span class="nc">MessageDigest</span><span class="o">.</span><span class="na">getInstance</span><span class="o">(</span><span class="s">"SHA-256"</span><span class="o">);</span>
      <span class="kt">byte</span><span class="o">[]</span> <span class="n">sha1</span> <span class="o">=</span> <span class="n">sha256</span><span class="o">.</span><span class="na">digest</span><span class="o">(</span><span class="nc">DatatypeConverter</span><span class="o">.</span><span class="na">parseHexBinary</span><span class="o">(</span><span class="n">privateKeyWIF</span><span class="o">));</span>
      <span class="c1">//log.info("Sha1: {}", bytesToHex(sha1).toUpperCase());</span>

      <span class="c1">// 4 - Perform SHA-256 hash on result of SHA-256 hash</span>
      <span class="kt">byte</span><span class="o">[]</span> <span class="n">sha2</span> <span class="o">=</span> <span class="n">sha256</span><span class="o">.</span><span class="na">digest</span><span class="o">(</span><span class="n">sha1</span><span class="o">);</span>
      <span class="c1">//log.info("Sha2: {}", bytesToHex(sha2).toUpperCase());</span>

      <span class="c1">// 5 - Take the first 4 bytes of the second SHA-256 hash, this is the checksum</span>
      <span class="nc">String</span> <span class="n">checksum</span> <span class="o">=</span> <span class="n">bytesToHex</span><span class="o">(</span><span class="n">sha2</span><span class="o">).</span><span class="na">substring</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="mi">8</span><span class="o">).</span><span class="na">toUpperCase</span><span class="o">();</span>
      <span class="c1">//log.info("Checksum: {}", checksum);</span>

      <span class="c1">// 6 - Add the 4 checksum bytes from point 5 at the end of the extended key from point 2</span>
      <span class="n">privateKeyWIF</span> <span class="o">=</span> <span class="n">privateKeyWIF</span> <span class="o">+</span> <span class="n">checksum</span><span class="o">;</span>
      <span class="c1">//log.info("Private Key + Checksum: {}", privateKeyWIF.toUpperCase());</span>

      <span class="c1">// 7 - Convert the result from a byte string into a base58 string using Base58Check encoding. This is the Wallet Import Format</span>
      <span class="n">privateKeyWIF</span> <span class="o">=</span> <span class="nc">Base58</span><span class="o">.</span><span class="na">encode</span><span class="o">(</span><span class="n">hexToBytes</span><span class="o">(</span><span class="n">privateKeyWIF</span><span class="o">));</span>
      <span class="c1">//log.info("Private Key WIF: {}", privateKeyWIF);</span>
    <span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">NoSuchAlgorithmException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
      <span class="n">e</span><span class="o">.</span><span class="na">printStackTrace</span><span class="o">();</span>
      <span class="k">return</span> <span class="kc">null</span><span class="o">;</span>
    <span class="o">}</span>
</code></pre></div></div>

<h3 id="generating-public-key-and-address">Generating Public Key and Address</h3>

<p>0 - Having a private ECDSA key</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>18e14a7b6a307f426a94f8114701e7c8e774e7f9a47e2c2035db29a206321725
</code></pre></div></div>

<p>1 - Take the corresponding public key generated with it (33 bytes, 1 byte 0x02 (y-coord is even), and 32 bytes corresponding to X coordinate)</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0250863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b2352
</code></pre></div></div>

<p>2 - Perform SHA-256 hashing on the public key</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0b7c28c9b7290c98d7438e70b3d3f7c848fbd7d1dc194ff83f4f7cc9b1378e98
</code></pre></div></div>

<p>3 - Perform RIPEMD-160 hashing on the result of SHA-256</p>

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

<p>4 - Add version byte in front of RIPEMD-160 hash (0x00 for Main Network)</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>00f54a5851e9372b87810a8e60cdd2e7cfd80b6e31
</code></pre></div></div>

<p>5 - Perform SHA-256 hash on the extended RIPEMD-160 result</p>

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

<p>6 - Perform SHA-256 hash on the result of the previous SHA-256 hash</p>

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

<p>7 - Take the first 4 bytes of the second SHA-256 hash. This is the address checksum</p>

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

<p>8 - Add the 4 checksum bytes from stage 7 at the end of extended RIPEMD-160 hash from stage 4. This is the 25-byte binary Bitcoin Address.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>00f54a5851e9372b87810a8e60cdd2e7cfd80b6e31c7f18fe8
</code></pre></div></div>

<p>9 - Convert the result from a byte string into a base58 string using Base58Check encoding. This is the most commonly used Bitcoin Address format</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>1PMycacnJaSqwwJqjawXBErnLsZ7RkXUAs
</code></pre></div></div>

<h4 id="sample-java-code-1">Sample Java Code</h4>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">try</span> <span class="o">{</span>
      <span class="c1">// 0 - Having a private ECDSA key 18e14a7b6a307f426a94f8114701e7c8e774e7f9a47e2c2035db29a206321725</span>

      <span class="c1">// 1.- Take the Public key</span>
      <span class="nc">String</span> <span class="n">publicKey</span> <span class="o">=</span> <span class="s">"0250863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b2352"</span><span class="o">;</span>

      <span class="c1">// 2.-  Perform SHA-256 hashing on the public key. [https://en.bitcoin.it/wiki/SHA-256]</span>
      <span class="c1">// The public key will be converted to binary before hashing.</span>
      <span class="c1">// This is the way things are hashed internally in bitcoin. (e.g. when creating a transaction ID)</span>
      <span class="nc">MessageDigest</span> <span class="n">sha256</span> <span class="o">=</span> <span class="nc">MessageDigest</span><span class="o">.</span><span class="na">getInstance</span><span class="o">(</span><span class="s">"SHA-256"</span><span class="o">);</span>
      <span class="kt">byte</span><span class="o">[]</span> <span class="n">sha1</span> <span class="o">=</span> <span class="n">sha256</span><span class="o">.</span><span class="na">digest</span><span class="o">(</span><span class="nc">DatatypeConverter</span><span class="o">.</span><span class="na">parseHexBinary</span><span class="o">(</span><span class="n">publicKey</span><span class="o">));</span>
      <span class="c1">//byte[] s1 = sha256.digest(bitcoinPublicKey.getBytes(StandardCharsets.UTF_8));</span>
      <span class="n">log</span><span class="o">.</span><span class="na">info</span><span class="o">(</span><span class="s">"Sha1: {}"</span><span class="o">,</span> <span class="n">bytesToHex</span><span class="o">(</span><span class="n">sha1</span><span class="o">).</span><span class="na">toUpperCase</span><span class="o">());</span>

      <span class="c1">// 3.- Perform RIPEMD-160 hashing on the result of SHA-256 [https://en.bitcoin.it/wiki/RIPEMD-160]</span>
      <span class="nc">MessageDigest</span> <span class="n">ripeMD160Digest</span> <span class="o">=</span> <span class="nc">MessageDigest</span><span class="o">.</span><span class="na">getInstance</span><span class="o">(</span><span class="s">"RipeMD160"</span><span class="o">,</span> <span class="s">"BC"</span><span class="o">);</span>
      <span class="kt">byte</span><span class="o">[]</span> <span class="n">ripeMD</span> <span class="o">=</span> <span class="n">ripeMD160Digest</span><span class="o">.</span><span class="na">digest</span><span class="o">(</span><span class="n">sha1</span><span class="o">);</span>
      <span class="n">log</span><span class="o">.</span><span class="na">info</span><span class="o">(</span><span class="s">"RipeMD160: {}"</span><span class="o">,</span> <span class="n">bytesToHex</span><span class="o">(</span><span class="n">ripeMD</span><span class="o">).</span><span class="na">toUpperCase</span><span class="o">());</span>

      <span class="c1">// 4.- Add version byte in front of RIPEMD-160 hash (0x00 for Main Network)</span>
      <span class="kt">byte</span><span class="o">[]</span> <span class="n">ripeMDExtended</span> <span class="o">=</span> <span class="n">hexToBytes</span><span class="o">(</span><span class="s">"00"</span> <span class="o">+</span> <span class="n">bytesToHex</span><span class="o">(</span><span class="n">ripeMD</span><span class="o">));</span>
      <span class="n">log</span><span class="o">.</span><span class="na">info</span><span class="o">(</span><span class="s">"RipeMD160Extended: {}"</span><span class="o">,</span> <span class="n">bytesToHex</span><span class="o">(</span><span class="n">ripeMDExtended</span><span class="o">).</span><span class="na">toUpperCase</span><span class="o">());</span>

      <span class="c1">// 5.- Perform SHA-256 hash on the extended RIPEMD-160 result</span>
      <span class="kt">byte</span><span class="o">[]</span> <span class="n">sha2</span> <span class="o">=</span> <span class="n">sha256</span><span class="o">.</span><span class="na">digest</span><span class="o">(</span><span class="n">ripeMDExtended</span><span class="o">);</span>
      <span class="n">log</span><span class="o">.</span><span class="na">info</span><span class="o">(</span><span class="s">"Sha2: {}"</span><span class="o">,</span> <span class="n">bytesToHex</span><span class="o">(</span><span class="n">sha2</span><span class="o">).</span><span class="na">toUpperCase</span><span class="o">());</span>

      <span class="c1">// 6.- Perform SHA-256 hash on the result of the previous SHA-256 hash</span>
      <span class="kt">byte</span><span class="o">[]</span> <span class="n">sha3</span> <span class="o">=</span> <span class="n">sha256</span><span class="o">.</span><span class="na">digest</span><span class="o">(</span><span class="n">sha2</span><span class="o">);</span>
      <span class="n">log</span><span class="o">.</span><span class="na">info</span><span class="o">(</span><span class="s">"Sha3: {}"</span><span class="o">,</span> <span class="n">bytesToHex</span><span class="o">(</span><span class="n">sha3</span><span class="o">).</span><span class="na">toUpperCase</span><span class="o">());</span>

      <span class="c1">// 7.- Take the first 4 bytes of the previous hash SHA-256 hash. This is the address checksum</span>
      <span class="nc">String</span> <span class="n">checksum</span> <span class="o">=</span> <span class="n">bytesToHex</span><span class="o">(</span><span class="n">sha3</span><span class="o">).</span><span class="na">substring</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="mi">8</span><span class="o">).</span><span class="na">toUpperCase</span><span class="o">();</span>
      <span class="n">log</span><span class="o">.</span><span class="na">info</span><span class="o">(</span><span class="s">"Checksum: {}"</span><span class="o">,</span> <span class="n">checksum</span><span class="o">);</span>

      <span class="c1">// 8.- Add the 4 checksum bytes from stage 7 at the end of extended RIPEMD-160 hash from stage 4. This is the 25-byte binary Bitcoin Address.</span>
      <span class="c1">//    byte[] sumBytes = new byte[25];</span>
      <span class="c1">//    System.arraycopy(ripeMDExtended, 0, sumBytes, 0, 21);</span>
      <span class="c1">//    System.arraycopy(sha3, 0, sumBytes, 21, 4);</span>
      <span class="nc">String</span> <span class="n">ripeMDExtendedAndChecksum</span> <span class="o">=</span> <span class="n">bytesToHex</span><span class="o">(</span><span class="n">ripeMDExtended</span><span class="o">)</span> <span class="o">+</span> <span class="n">checksum</span><span class="o">;</span>
      <span class="n">log</span><span class="o">.</span><span class="na">info</span><span class="o">(</span><span class="s">"RipeMDExtended + Checksum: {}"</span><span class="o">,</span> <span class="n">ripeMDExtendedAndChecksum</span><span class="o">.</span><span class="na">toUpperCase</span><span class="o">());</span>

      <span class="c1">// 9.- Convert the result from a byte string into a base58 string using Base58Check encoding. This is the most commonly used Bitcoin Address format</span>
      <span class="c1">//bitcoinAddress = Base58.encode(sumBytes);</span>
      <span class="nc">String</span> <span class="n">address</span> <span class="o">=</span> <span class="nc">Base58</span><span class="o">.</span><span class="na">encode</span><span class="o">(</span><span class="n">hexToBytes</span><span class="o">(</span><span class="n">ripeMDExtendedAndChecksum</span><span class="o">));</span>
      <span class="n">log</span><span class="o">.</span><span class="na">info</span><span class="o">(</span><span class="s">"Address: {}"</span><span class="o">,</span> <span class="n">address</span><span class="o">);</span>
    <span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">NoSuchAlgorithmException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
      <span class="n">e</span><span class="o">.</span><span class="na">printStackTrace</span><span class="o">();</span>
    <span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">NoSuchProviderException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
      <span class="n">e</span><span class="o">.</span><span class="na">printStackTrace</span><span class="o">();</span>
    <span class="o">}</span>
</code></pre></div></div>

<p>The source code can be found on github. <a href="https://github.com/cjrequena/bitcoin-keypair-generator-sample">bitcoin-keypair-generator-sample</a></p>

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

<ul>
  <li><a href="https://github.com/bitcoinbook/bitcoinbook">Mastering Bitcoin</a></li>
  <li><a href="https://andrea.corbellini.name/2015/05/17/elliptic-curve-cryptography-a-gentle-introduction/">Elliptic Curve Cryptography: a gentle introduction</a></li>
  <li><a href="https://hackernoon.com/what-is-the-math-behind-elliptic-curve-cryptography-f61b25253da3">What is the math behind elliptic curve cryptography?</a></li>
  <li><a href="https://hackernoon.com/elliptic-curve-crypto-point-doubling-b98508d40a88">Elliptic Curve Crypto ,Point Doubling</a></li>
  <li><a href="https://www.johndcook.com/blog/2018/08/14/bitcoin-elliptic-curves/">Bitcoin key mechanism and elliptic curves over finite fields</a></li>
  <li><a href="https://andrea.corbellini.name/ecc/interactive/reals-mul.html">Elliptic Curve scalar multiplication</a></li>
  <li><a href="https://en.bitcoin.it/wiki/Wallet_import_format">Bitcoin Wallet Input Format</a></li>
  <li><a href="https://en.bitcoin.it/wiki/Technical_background_of_version_1_Bitcoin_addresses">Bitcoin Adress</a></li>
  <li><a href="https://www.certicom.com/content/certicom/en/22-elliptic-curve-addition-an-algebraic-approach.html">Elliptic Curve Addition: An Algebraic Approach</a></li>
</ul>]]></content><author><name>Carlos Requena</name></author><category term="Bitcoin" /><summary type="html"><![CDATA["Our virtues and our failings are inseparable, like force and matter. When they separate, man is no more." --Nikola Tesla.]]></summary></entry></feed>