<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>bap2pecs</title>
        <link>https://paragraph.com/@0xb2p</link>
        <description>twitter: @0xb2p
github: @bap2pecs</description>
        <lastBuildDate>Wed, 08 Apr 2026 05:00:51 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <image>
            <title>bap2pecs</title>
            <url>https://storage.googleapis.com/papyrus_images/2d7eb3aef61bfb248e1596774d8b13db8c776cbdc9343f2a2ca68b20cfd0e437.png</url>
            <link>https://paragraph.com/@0xb2p</link>
        </image>
        <copyright>All rights reserved</copyright>
        <item>
            <title><![CDATA[How to fix ERR_SSL_VERSION_OR_CIPHER_MISMATCH]]></title>
            <link>https://paragraph.com/@0xb2p/how-to-fix-err-ssl-version-or-cipher-mismatch</link>
            <guid>xJygR8T9mgOuX3nz5aQZ</guid>
            <pubDate>Tue, 06 Feb 2024 16:15:50 GMT</pubDate>
            <description><![CDATA[I was setting up SSL for a domain using cloudflare along with nginx-acme and nginx-proxy but I got error ERR_SSL_VERSION_OR_CIPHER_MISMATCH when testing. Checking the container logs, everything looks alright. By using SSL Labs toolkit, it shows error “Failed to communicate with the secure server”:Looking it up, I found https://community.cloudflare.com/t/failed-to-communicate-with-the-secure-server/186871 which links to https://developers.cloudflare.com/ssl/troubleshooting/version-cipher-misma...]]></description>
            <content:encoded><![CDATA[<p>I was setting up SSL for a domain using cloudflare along with <code>nginx-acme</code> and <code>nginx-proxy</code> but I got error <code>ERR_SSL_VERSION_OR_CIPHER_MISMATCH</code> when testing.</p><p>Checking the container logs, everything looks alright.</p><p>By using SSL Labs <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.ssllabs.com/ssltest">toolkit</a>, it shows error “Failed to communicate with the secure server”:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/33f4d1d7a6b9868c8ff304a3cf99e05018feea54ab33bb4f286b440893dfd73b.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>Looking it up, I found</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://community.cloudflare.com/t/failed-to-communicate-with-the-secure-server/186871">https://community.cloudflare.com/t/failed-to-communicate-with-the-secure-server/186871</a></p><p>which links to</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://developers.cloudflare.com/ssl/troubleshooting/version-cipher-mismatch">https://developers.cloudflare.com/ssl/troubleshooting/version-cipher-mismatch</a></p><p>Then I found the root cause was I was using a multi-level subdomain:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/2be459c3de95cca3300eccfe7e3da0f30d9f430a9536a3e26f04b56d7472ecfe.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>One easy way to fix it is to merge the multiple levels from <code>&lt;subdomain1&gt;.&lt;subdomain2&gt;</code> to <code>&lt;subdomain1&gt;-&lt;subdomain2&gt;</code>.</p><p>But sometimes we do need multi-level subdomains. For example, when we deploy L2s for our clients. We want them to get resource URLs such as:</p><ul><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://myappchain.rpc.snapcha.in">https://myappchain.rpc.snapcha.in</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://myappchain.explorer.snapcha.in">https://myappchain.explorer.snapcha.in</a></p></li><li><p>…</p></li></ul><p>In that case, we will use Cloudflare’s <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://developers.cloudflare.com/ssl/edge-certificates/advanced-certificate-manager/">Advanced Certificates</a> add-on feature that covers more than one level of subdomain.</p><p>One we purchased the package, we need to order those advanced certificates such as:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/9b3f608f101d6a039770fb317cd11aa534d1e19a4d0f43940f43283af03e1ec4.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>Then we can use the feature to issue certs when it becomes active:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/fcc5e9962c4da4f607abbfe0e170772f2b8fd22c866868ef93908a86b401535f.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure>]]></content:encoded>
            <author>0xb2p@newsletter.paragraph.com (bap2pecs)</author>
        </item>
        <item>
            <title><![CDATA[Sui Study Notes: The Whitepaper]]></title>
            <link>https://paragraph.com/@0xb2p/sui-study-notes-the-whitepaper</link>
            <guid>xJigI6LDddZ2Aw0Tk5hC</guid>
            <pubDate>Tue, 31 Jan 2023 19:57:53 GMT</pubDate>
            <description><![CDATA[Disclaimer: This study note serves as a personal reminder rather than a comprehensive list of all the concepts in the whitepaper.Programming ModelGlobal object pool: In Sui, persistent storage is supported via Sui’s global object pool rather than the account-based global storage of core MoveMove vs. the Sui MoveModules, Types and AbilitiesObjects and Ownershipobjects are first-class citizens of the systempackage code objects, and struct data objectsTransactions: public tx (i.e. publish a pack...]]></description>
            <content:encoded><![CDATA[<p><em>Disclaimer</em>: This study note serves as a personal reminder rather than a comprehensive list of all the concepts in the whitepaper.</p><h2 id="h-programming-model" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Programming Model</h2><ul><li><p>Global object pool: In Sui, persistent storage is supported via Sui’s global object pool rather than the account-based global storage of core Move</p><ul><li><p>Move vs. the Sui Move</p></li></ul></li><li><p>Modules, Types and Abilities</p></li><li><p>Objects and Ownership</p><ul><li><p>objects are first-class citizens of the system</p></li><li><p>package code objects, and struct data objects</p></li></ul></li><li><p>Transactions: public tx (i.e. publish a package), call tx (i.e. call a package)</p></li><li><p>Transaction Effects, Events, Create/Update/Wrap/Delete</p></li></ul><h2 id="h-the-sui-system" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">The Sui System</h2><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/e151e59b766af1254bca7ad75f5d7cb722aa823a82d7f9f1e1b9876e8d6f97da.png" alt="Outline of interactions to commit a transaction" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">Outline of interactions to commit a transaction</figcaption></figure><ul><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://arxiv.org/pdf/2003.11506.pdf">FastPay</a> + Delegated Proof-of-Stake</p><ul><li><p>requires 2/3 stake from honest authorities</p></li><li><p>liveness and eventual delivery: at least one honest party acts as a <em>relay</em> for each certificate between authorities</p></li></ul></li><li><p>object reference, transaction certificate, effect certificate</p></li><li><p>persistent stores on authorities: 4 key-value maps</p></li><li><p>causality &amp; parallelism</p></li><li><p>owned objects vs. shared objects</p><blockquote><p>execution for transactions involving read-only and owned objects requires only consistent broadcast and a single certificate to proceed; and Byzantine agreement is only required for transactions involving shared objects (using <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://arxiv.org/pdf/2105.11827.pdf">a high-throughput consensus system</a>)</p></blockquote></li><li><p>full client (replica) and light client</p></li></ul><h2 id="h-scaling-and-latency" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Scaling and Latency</h2><blockquote><p>To ensure that more resources result in increased capacity quasi-linearly, the Sui design aggressively reduces bottlenecks and points of synchronization requiring global locks within authorities. Processing transactions is cleanly separated into two phases, namely (1) ensuring the transaction has exclusive access to the owned or shared objects at a specific version, and (2) then subsequently executing the transaction and committing its effects.</p></blockquote><h2 id="h-discussions" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Discussions</h2><p>In my view, the most significant innovations of Sui are:</p><ul><li><p>split the common “fire-and-forget” mode of broadcasting transactions in traditional blockchain networks to the two phases: 1) collect enough signatures from validators; 2) create the certificate and broadcast.</p></li><li><p>object-based global storage rather than account-based</p></li><li><p>differentiate the processes for handling single-owner objects from those for handling shared objects.</p></li></ul><p>By combining these elements, the system realizes high throughput, low latency, and horizontal scalability.</p><p>However, effective utilization of the system demands careful design of the data model and operations by developers. For instance, the suitability of using the single-owner object model for creating a standard ERC-20 token is not immediately apparent.</p>]]></content:encoded>
            <author>0xb2p@newsletter.paragraph.com (bap2pecs)</author>
        </item>
        <item>
            <title><![CDATA[Optimism Bedrock: Study Notes]]></title>
            <link>https://paragraph.com/@0xb2p/optimism-bedrock-study-notes</link>
            <guid>ANn73yWHzC8SRA3XUTRW</guid>
            <pubDate>Mon, 30 Jan 2023 04:14:07 GMT</pubDate>
            <description><![CDATA[Disclaimer: My goal is to learn the OP Bedrock protocol quickly so I can understand the code more easily to be able to plug in with my own DA layer to the OP stack. So I only read the things I think that can be helpful. The goal is not to understand every piece of the details.Study Stepsread Introducing the OP Stackwatch the talks given by OP Labs’ Karl Floersch and Kelvin Fichter at Devcon 6read the following specs: Introduction, Overview, Deposits, Rollup Node, Batch Submitter, System Confi...]]></description>
            <content:encoded><![CDATA[<p><em>Disclaimer</em>: My goal is to learn the OP Bedrock protocol <strong>quickly</strong> so I can understand the code more easily to be able to plug in with my own DA layer to the OP stack. So I only read the things I think that can be helpful. The goal is not to understand every piece of the details.</p><h2 id="h-study-steps" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Study Steps</h2><ol><li><p>read <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://optimism.mirror.xyz/fLk5UGjZDiXFuvQh6R_HscMQuuY9ABYNF7PI76-qJYs">Introducing the OP Stack</a></p></li><li><p>watch the talks given by OP Labs’ <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://youtu.be/HiU-g8XHi5s">Karl Floersch</a> and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.youtube.com/watch?v=jnVjhp41pcc">Kelvin Fichter</a> at Devcon 6</p></li><li><p>read the following specs: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum-optimism/optimism/blob/develop/specs/introduction.md">Introduction</a>, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum-optimism/optimism/blob/develop/specs/overview.md">Overview</a>, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum-optimism/optimism/blob/develop/specs/deposits.md">Deposits</a>, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum-optimism/optimism/blob/develop/specs/rollup-node.md">Rollup Node</a>, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum-optimism/optimism/blob/develop/specs/batcher.md">Batch Submitter</a>, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum-optimism/optimism/blob/develop/specs/system_config.md">System Config</a>, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum-optimism/optimism/blob/develop/specs/derivation.md">L2 Chain Derivation</a>(*)</p></li></ol><p>*: for the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum-optimism/optimism/blob/develop/specs/derivation.md">derivation</a> spec, I started to skip lots of the details from section <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum-optimism/optimism/blob/develop/specs/derivation.md#batch-queue">Batch Queue</a></p><p>It should take ~2-3 days to study everything on this list.</p><h2 id="h-high-level" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">High-level</h2><ul><li><p>The OP stack is modular and minimal. It’s easy to swap with your own e.g. consensus, DA layers. The <em>Superchain</em> vision is able to scale horizontally.</p></li><li><p>Example: Metis forked OP and customized the DA layer with a DA committee</p></li><li><p>The 3 primary layers</p><ul><li><p>Consensus</p><ul><li><p>DA: an array of byte strings. not necessary a ledger</p></li><li><p>Derivation: takes the DA layer and the current state of the rollup and produces Engine API payloads</p></li></ul></li><li><p>Execution: state transition</p></li><li><p>Settlement: a view that another chain has over your chain</p></li></ul></li></ul><h2 id="h-key-interactions" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Key Interactions</h2><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/4844b9d3543b947256f692c989d867adb4eedd41f767717f54160e56cf61b1fd.png" alt="Deposit" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">Deposit</figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/2dcb4980d3729a43d74dda0c62710c537b87dea7d6e49853000be44aacb3da1b.png" alt="Withdraw" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">Withdraw</figcaption></figure><p>Note: step 4 is related to the concept of <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum-optimism/optimism/blob/develop/specs/glossary.md#finalized-l2-head">finalized L2 head</a>.</p><h2 id="h-overview" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Overview</h2><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/e7610ff761d0be2edcc06d48c7a58cdfda228b2393add281a6132cd331c7e1d4.png" alt="Components" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">Components</figcaption></figure><p>The <code>L2OutputOracle</code> is a L1 contract to store rollup states (i.e. <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum-optimism/optimism/blob/develop/specs/glossary.md#l2-output-root">L2 output roots</a>) and manage withdrawals. It will be helpful to think of it as the <em>rollup output</em> store and <code>DepositFeed</code> and <code>BatchInbox</code> as the <em>rollup input</em> store. So the L1 is simply the DA layer for storing rollup inputs and outputs, and the L2 is the computing layer.</p><p><code>DepositFeed</code> is for a special transaction type (i.e. <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum-optimism/optimism/blob/develop/specs/glossary.md#deposited-transaction">Deposited Transaction</a>) on L2 defined by the Optimism protocol. <code>BatchInbox</code> is for the other normal L2 transactions (i.e. only transaction inputs) that are batch-submitted to L1.</p><p>It’s also useful to know that the <code>BatchInbox</code> is a regular EOA address (note: for saving gas cost by not executing any EVM code). The sequencer submits L2 transaction batches included in the <em>calldata</em> of the L1 transaction to the address.</p><h2 id="h-key-concepts" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Key Concepts</h2><ul><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum-optimism/optimism/blob/develop/specs/overview.md#block-derivation">Block Derivation</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum-optimism/optimism/blob/develop/specs/overview.md#epochs-and-the-sequencing-window">Epochs and the Sequencing Window</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum-optimism/optimism/blob/develop/specs/deposits.md">Deposited Transactions</a>: This is a new transaction type on L2 defined by the protocol.</p><ul><li><p>It’s important to understand that when tokens are deposited from L1 to L2, it’s technically “depositing the transactions to the L2“. The tokens are locked on L1 and then minted on L2.</p></li><li><p>deposited transactions do not need a signature and rely on <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum-optimism/optimism/blob/develop/specs/deposits.md#validation-and-authorization-of-deposited-transactions">other mechanisms</a> for authorization and validation</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum-optimism/optimism/blob/develop/specs/deposits.md#l1-attributes-deposited-transaction">L1 attributes deposited transaction</a> and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum-optimism/optimism/blob/develop/specs/deposits.md#user-deposited-transactions">user-deposited transactions</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum-optimism/optimism/blob/develop/specs/deposits.md#l1-attributes-depositor-account">L1 Attributes Depositor Account</a>: an EOA with unknown private key.</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum-optimism/optimism/blob/develop/specs/deposits.md#l1-attributes-predeployed-contract">L1 Attributes Predeployed Contract</a>: it’s important to know that the contract will be called in the first transaction of every L2 block (<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum-optimism/optimism/pull/4779">source</a>). Every L2 block has an <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum-optimism/optimism/blob/develop/specs/glossary.md#l1-attributes-deposited-transaction">L1 attributes tx</a>.</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum-optimism/optimism/blob/develop/specs/deposits.md#address-aliasing">Address Aliasing</a></p></li></ul></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum-optimism/optimism/blob/develop/specs/derivation.md#batch-submission">Batch Submission</a></p><ul><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum-optimism/optimism/blob/develop/specs/glossary.md#data-availability-provider">Data Availability Provider</a> (e.g. Ethereum calldata)</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum-optimism/optimism/blob/develop/specs/glossary.md#sequencer-batch">Sequencer Batch</a>: each batch represents the inputs needed to build one L2 block</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum-optimism/optimism/blob/develop/specs/glossary.md#batcher-transaction">Batcher Transaction</a>: a transaction submitted by a <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum-optimism/optimism/blob/develop/specs/glossary.md#batcher">batcher</a> to a data availability provider</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum-optimism/optimism/blob/develop/specs/glossary.md#channel">Channel</a> and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum-optimism/optimism/blob/develop/specs/glossary.md#channel-frame">Channel Frame</a></p></li><li><p>The diagram below illustrates these concepts as a whole</p></li></ul></li></ul><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/9d07a521a6980428e54311ae50b2fdb16ba150564019082d32a459cf35468cb8.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><ul><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum-optimism/optimism/blob/develop/specs/glossary.md#l2-chain-derivation">L2 Chain Derivation</a></p><ul><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum-optimism/optimism/blob/develop/specs/glossary.md#l2-derivation-inputs">L2 Derivation Inputs</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum-optimism/optimism/blob/develop/specs/system_config.md">System Config</a>: <code>batcherHash</code> stores the current authorized batcher sender(s)</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum-optimism/optimism/blob/develop/specs/glossary.md#payload-attributes">Payload Attributes</a>: object to be passed to the execution engine</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum-optimism/optimism/blob/develop/specs/glossary.md#l2-chain-inception">L2 Chain Inception</a>: the L1 block number where the L2 genesis starts</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum-optimism/optimism/blob/develop/specs/glossary.md#finalized-l2-head">Finalized L2 Head</a>, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum-optimism/optimism/blob/develop/specs/glossary.md#safe-l2-head">Safe L2 Head</a>, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum-optimism/optimism/blob/develop/specs/glossary.md#unsafe-l2-block">Unsafe L2 Head</a>, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum-optimism/optimism/blob/develop/specs/glossary.md#unsafe-block-consolidation">Unsafe Block Consolidation</a></p><ul><li><p>it’s important to distinguish the difference of finalizing the L2 head with the concept of <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum-optimism/optimism/blob/develop/specs/glossary.md#finalization-period">finalization period</a>. The former form of finalization only affects inputs while the later affects Optimistic-rollup outputs.</p></li></ul></li></ul></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum-optimism/optimism/blob/develop/specs/glossary.md#fork-choice-rule">Fork Choice Rule</a>: to determine the blockchain head</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum-optimism/optimism/blob/develop/specs/glossary.md#time-slot">Time Slot</a>: every 2 second per L2 block</p></li></ul>]]></content:encoded>
            <author>0xb2p@newsletter.paragraph.com (bap2pecs)</author>
        </item>
        <item>
            <title><![CDATA[Filecoin/FVM: Study Notes]]></title>
            <link>https://paragraph.com/@0xb2p/filecoin-fvm-study-notes</link>
            <guid>ZMYiJG2yEn20GqCPe6yM</guid>
            <pubDate>Mon, 30 Jan 2023 02:04:29 GMT</pubDate>
            <description><![CDATA[Study Stepsread https://docs.filecoin.io/about/basics/introduction/read The Filecoin Virtual Machine: Everything You Need to Knowread https://docs.filecoin.io/about/basics/filecoin-faq/read How Filecoin storage and retrieval workswatch Space Warp Summit 🛸 Understanding the FVM - Raul Kripalaniwatch Space Warp Summit 🛸 Programming on the FEVM - Zak AyeshHigh-levelFilecoin is built on top of the same software powering IPFS protocol but they are different networksFilecoin is different from IPF...]]></description>
            <content:encoded><![CDATA[<h2 id="h-study-steps" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Study Steps</h2><ol><li><p>read <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.filecoin.io/about/basics/introduction/">https://docs.filecoin.io/about/basics/introduction/</a></p></li><li><p>read <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://hackernoon.com/the-filecoin-virtual-machine-everything-you-need-to-know">The Filecoin Virtual Machine: Everything You Need to Know</a></p></li><li><p>read <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.filecoin.io/about/basics/filecoin-faq/">https://docs.filecoin.io/about/basics/filecoin-faq/</a></p></li><li><p>read <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://filecoin.io/blog/posts/how-storage-and-retrieval-deals-work-on-filecoin/">How Filecoin storage and retrieval works</a></p></li><li><p>watch <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.youtube.com/watch?v=9m3oSxtAivs">Space Warp Summit 🛸 Understanding the FVM - Raul Kripalani</a></p></li><li><p>watch <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.youtube.com/watch?v=KcZbXSoUxz4">Space Warp Summit 🛸 Programming on the FEVM - Zak Ayesh</a></p></li></ol><h2 id="h-high-level" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">High-level</h2><ul><li><p>Filecoin is built on top of the same software powering IPFS protocol but they are different networks</p></li><li><p>Filecoin is different from IPFS because it has an incentive layer on top to incentivize contents to be reliably stored and accessed</p></li><li><p>FVM has the additional ability to access verified proof of stored data within the virtual machine’s native environment</p></li></ul><h2 id="h-key-concepts" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Key Concepts</h2><ul><li><p>The Filecoin blockchain</p><ul><li><p>Tipsets, Blocks, Messages</p></li><li><p>Actors (smart contract): 11 built-in actors</p></li><li><p>Nodes: chain verifier nodes, client nodes, storage provider nodes, and retrieval provider nodes. Any node participating in the Filecoin network should provide the chain verification service as a minimum.</p></li><li><p>Consensus</p><ul><li><p>like proof-of-stake, Filecoin uses proof-of-storage for the leader election</p></li><li><p>relies on <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://drand.love/">DRAND</a> for randomness</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.filecoin.io/about/basics/introduction/#block-production-process">Block production process</a></p><ul><li><p>30 secs each epoch/round</p></li><li><p>finality: 900 epochs (~7.5hr)</p></li></ul></li></ul></li><li><p>Addresses: <code>f410</code> represents Ethereum addresses</p></li><li><p>Proofs</p><ul><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://spec.filecoin.io/#section-glossary.seal">Sealing</a>: Proof of Replication (PoRep)</p></li><li><p>Proof of Spacetime (PoSt)</p><ul><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://spec.filecoin.io/#section-algorithms.pos.post.winningpost">WinningPoSt</a> &amp; <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://spec.filecoin.io/#section-algorithms.pos.post.windowpost">WindowPoSt</a>: be aware of the subtle differences</p></li><li><p>every sector is audited at least once every 24 hours</p></li></ul></li><li><p>Collateral and Slashing</p></li></ul></li></ul></li><li><p>Storage &amp; Retrieval</p><ul><li><p>Storage and Retrieval markets</p><ul><li><p>Filecoin plus and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://spec.filecoin.io/#section-algorithms.verified_clients">verified clients</a></p></li><li><p>Storage on-ramps</p><ul><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://web3.storage/">web3.storage</a>: automate data replication over multiple SPs</p></li></ul></li><li><p>Basic retrieval &amp; <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://strn.network/">Saturn</a></p></li></ul></li><li><p>Storage and Retrieval Providers</p></li><li><p>Deals</p></li><li><p>Sectors: basic units of provable storage</p><ul><li><p><code>32 GiB</code> and <code>64 GiB</code> sector sizes are supported.</p></li></ul></li></ul></li><li><p>Compute-over-data &amp; Compute-over-state</p><ul><li><p>FVM is computer-over-state (i.e. metadata of the stored data such as cids)</p><ul><li><p>It manipulates the metadata of the stored data deal. It does not manipulate the data stored in that deal.</p></li></ul></li><li><p>FVM is built on top of Filecoin’s network. There is no additional chain.</p></li><li><p>FVM is WASM native and virtual machine-agnostic</p></li><li><p>FEVM is virtualized as a runtime (i.e. an actor) on top of FVM</p><ul><li><p>compatible with any EVM tools</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/Zondax/filecoin-solidity">Filecoin Solidity libraries</a>: to interact with built-in actors</p></li></ul></li><li><p>delayed execution: messages/transactions included in one epoch won’t be executed until the next epoch. So it takes about ~1min before you can see the state change.</p></li></ul></li></ul><h2 id="h-caveats" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Caveats</h2><ul><li><p>Storage</p><ul><li><p>The network doesn’t guarantee the data availability. If your SP (storage provide) loses your data, they will get slashed but your data is permanently lost. So it’s recommended to make deals with multiple SPs for redundancy. But again, there is no guarantee.</p></li><li><p>Right now, verifiers to verify clients and allocate DataCap are chosen in <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.filecoin.io/about/basics/filecoin-faq/#who-will-be-selected-to-be-verifiers-to-verify-clients-on-the-network">a centralized way</a>.</p></li><li><p>Right now, the Filecoin network <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.filecoin.io/about/basics/filecoin-faq/#how-do-you-update-data-stored-on-filecoin">does not allow modifying the data</a> once a deal is made.</p></li></ul></li><li><p>Deals</p><ul><li><p>Currently a deal in Filecoin has a minimum duration of 180 days</p></li><li><p>You might want to decide on a specific provider based on their reputation or power in the network. But reputation metrics for miners are not part of the Filecoin protocol yet.</p></li><li><p>to create a deal, it’s a non-trivial process (e.g. you need to download and install the Lotus client)</p></li></ul></li><li><p>Retrieval</p><ul><li><p>Similar as storage, to avoid extortion, always ensure you store your data with a fairly decentralized set of storage providers (and note: it’s pretty difficult for a storage provider to be sure they are the only person storing a particular piece of data, especially if you encrypt the data).</p></li><li><p>Basic retrieval is slow (i.e. the unsealing process is non-trivial) and can take <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.filecoin.io/about/basics/filecoin-faq/#even-though-filecoin-will-be-backed-up-to-our-normal-ipfs-pinning-layer-we-still-need-to-know-how-quickly-we-can-access-data-from-the-filecoin-network-how-fast-will-retrieval-be-from-the-filecoin-network">hours</a>. The core team is working on it this year to achieve sub-millisecond speed. Right now you can use <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://strn.network/">Saturn</a> which is a CDN layer built on top of Filecoin.</p></li><li><p>Retrieval deals, unlike storage deals, happen mostly off-chain facilitated by payment channels. Depending on whether the miner has the data in their <em>block-store</em> or not, they might need to first <em>unseal</em> it.</p></li></ul></li><li><p>FVM &amp; FEVM</p><ul><li><p>No Ethereum gas accounting: metering and execution halt based on Filecoin rules</p></li></ul></li></ul><h2 id="h-discussions" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Discussions</h2><p>My goal of studying Filecoin/FVM is to figure out whether I can use Filecoin as the DA layer for a rollup using the OP stack. Specifically, I am looking for a <em>decentralized, affordable, reliable</em> and <em>scalable</em> DA layer. My conclusion is although it’s pretty decentralized and affordable, it’s not reliable in regards to <em>usability</em> and <em>security</em>.</p><p>The biggest issue is data(*) stored in the Filecoin network <strong>cannot be modified</strong>. But a DA layer for a rollup needs to constantly update the data (i.e. receive deposit transactions and transaction batches, update <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum-optimism/optimism/blob/develop/specs/glossary.md#l2-output-root">L2 Output Root</a>).</p><p>Security is another major concern. The DA layer for a rollup can be much more valuable economically than the collateral from the SPs. So it’s <strong>hard to protect against extortions</strong> on retrieval. Given the nature of a rollup, it’s very likely the DA layer needs to be public which implies everyone will know the SPs that are storing the data. Thus, the encryption approach mentioned <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.filecoin.io/about/basics/filecoin-faq/#how-do-i-know-that-my-storage-provider-will-not-charge-prohibitively-high-costs-for-data-retrieval">here</a> won’t work and an extortion can still happen if the SPs collude together.</p><p>Slow native retrieval data is a less important concern. But it will influence the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum-optimism/optimism/blob/develop/specs/glossary.md#L2-chain-derivation">L2 chain derivation</a> process. <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://strn.network/">Saturn</a> can be used to workaround the problem but that also means an additional trust dependency is added.</p><p>Note that the discussion is focused on using the Filecoin network’s storage as the DA layer, mainly for it’s cheap storage cost. However, the Filecoin blockchain itself can also be the DA layer but that does not give many advantages over other L1s. The 7.5-hour finality time and 30-sec epoch are just too slow even comparing to the benchmark Ethereum network.</p><p><em>*: “data” here does not include the data on the blockchain.</em></p><h2 id="h-references" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">References</h2><ul><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://spec.filecoin.io/">Filecoin Spec</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/filecoin-project/community/discussions/585#top">FVM Space Warp ETHGlobal Hackathon Cheat Sheet</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://filscan.io/statistics/map">Nodes geo-distribution</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://spec.filecoin.io/systems/filecoin_token/token_allocation/filtokenallocation.png">Token distribution</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://fvm.filecoin.io/#roadmap-4">FVM roadmap</a></p></li></ul><h2 id="h-appendix-unanswered-questions" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Appendix: Unanswered Questions</h2><p><em>Note: I am not going to spend more time on the list as I have already figured out that Filecoin won’t be a good DA layer for what I need.</em></p><p>General</p><ol><li><p>Is the revenue of the Filecion ecosystem mainly from the storage/retrieval markets? What&apos;s the size of the revenue? Is there a dashboard for the data?</p></li><li><p>For SP, how much is the required collateral? There are some formulas on the spec but I&apos;d like to know some estimated dollar values.</p></li><li><p>What&apos;s the current sector fault rate? Is there a dashboard to track? Where can I find any example of enforced slash transactions? Is the fault fee paid back to the sector data owner?</p></li></ol><p>Technical</p><ol><li><p>Does PoSt uses data availability sampling to prove the data?</p></li><li><p>In FVM, is the state storage and transaction history persistent? are there any mechanisms for state expiry and old data pruning?</p></li><li><p>It seems that there aren&apos;t any orders for the blocks inside one tipset. Then how to enforce transaction orders inside those parallel blocks?</p></li><li><p>What&apos;s the maximum allowed number of blocks in a tipset? What&apos;s the block size limit and the implies TPS?</p></li><li><p>Does the FVM transactions (e.g. contract call) have the same priority as other types of messages (e.g. <code>ProveCommitSector</code>) from the miner&apos;s perspective?</p></li><li><p>How to prove the stored/retrieved data is the original one and not tampered, if the owner does not keep a copy?</p></li><li><p>How to determine the assigned weight to a tipset?</p></li></ol>]]></content:encoded>
            <author>0xb2p@newsletter.paragraph.com (bap2pecs)</author>
        </item>
        <item>
            <title><![CDATA[Quick Study of the OP Tokenomics]]></title>
            <link>https://paragraph.com/@0xb2p/quick-study-of-the-op-tokenomics</link>
            <guid>CQbhdh3kcUrXYWBM8Big</guid>
            <pubDate>Wed, 25 Jan 2023 22:22:22 GMT</pubDate>
            <description><![CDATA[Tokenomicshttps://community.optimism.io/docs/governance/economics/ The above page is the official documentation about the Economics of the OP ecosystem. It also has a nice diagram (see below) to demonstrate the economics.However, it does not clearly picture where the token holders fit in. The only thing mentioned in the page is:Value accrues to tokenholders through the productive re-deployment of sequencer revenue. Sequencer revenue is primarily directed to fund public goods, which creates ec...]]></description>
            <content:encoded><![CDATA[<h2 id="h-tokenomics" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Tokenomics</h2><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://community.optimism.io/docs/governance/economics/">https://community.optimism.io/docs/governance/economics/</a></p><p>The above page is the official documentation about the Economics of the OP ecosystem. It also has a nice diagram (see below) to demonstrate the economics.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/f8f7b4a34f8995677d871c775d4fb26b85bed0e13a2fe60e32f627e18bbec1f3.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>However, it does not clearly picture where the token holders fit in. The only thing mentioned in the page is:</p><blockquote><ul><li><p>Value accrues to <strong>tokenholders</strong> through the productive re-deployment of sequencer revenue. Sequencer revenue is primarily directed to fund public goods, which creates ecosystem value and drives demand for blockspace.</p></li></ul></blockquote><p>This part is a bit vague to me as I cannot see a link between the distribution of sequence revenue and how value accrues to token holders. In the diagram above, the revenue is distributed to the retroactive Public Good Funding (RetroPGF), which goes to the builders, not the token holders.</p><p>As far as I know, the token right now does not have any other use cases other than governance.</p><p>However, there are some discussion happening in the official discord. The screenshot below implies that when the sequencer is decentralized, the revenue could be allocated to places other than the RetroPGF. So maybe they will have a staking system by then to distribute some revenue to the token holders.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/b6af1835dbb4381fee6c0189c8975ca2ee66e5de162930004512ec3b866507f6.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><h2 id="h-token-distribution" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Token Distribution</h2><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://community.optimism.io/docs/governance/allocations/">https://community.optimism.io/docs/governance/allocations/</a></p><p>Overall, it looks healthy to me.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/3fa9f9f8e782957d5d2170f235fbd33dcdebc63b31ca097a495746bea271c4e7.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/10166e20d52da58f20f59e597e36279c4f9e0d23f45cee4972e5d8c6882a8fea.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><h2 id="h-valuation" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Valuation</h2><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://dune.com/optimismfnd/optimism-l1-batch-submission-fees-security-costs">https://dune.com/optimismfnd/optimism-l1-batch-submission-fees-security-costs</a></p><p>The above dashboard has some statistics for the Optimism fees. The <em>sequencer fee margin section</em> is the actual profit (i.e. <code>revenue - cost</code>). In the below screenshot, we can see that the 30-day average profit is 13.63 ETH.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/76ac77f57a4a0004d2e60f72b53a25b21b569354cb7ccf8ad0e432e1dbd02b0e.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>Given a 100x PE ratio, with the current ETH price being $1605, we can do a raw estimation of the valuation of the ecosystem to be:</p><pre data-type="codeBlock" text="13.63 * 365 * 1605 * 100 ~= $800 million
"><code><span class="hljs-number">13.63</span> <span class="hljs-operator">*</span> <span class="hljs-number">365</span> <span class="hljs-operator">*</span> <span class="hljs-number">1605</span> <span class="hljs-operator">*</span> <span class="hljs-number">100</span> <span class="hljs-operator">~</span><span class="hljs-operator">=</span> $800 million
</code></pre><p>The market cap implies by the current token price is $532 million while the fully diluted valuation is at $1 billion.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/cd396448878a2badd09eb0c636f207707da0edf437d029db1bbee7ac5ccc71d3.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><h2 id="h-discussions" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Discussions</h2><p>The token price of OP is too high even considering my raw estimation with a very generous PE ratio.</p><p>More importantly, the token itself is just a governance token with no other utilities, at least at the moment. In general, I don’t recommend to invest in any governance tokens.</p><p>However, I am bullish on the Optimism ecosystem for the following reasons:</p><ul><li><p>Ethereum community has the consensus on the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ethereum-magicians.org/t/a-rollup-centric-ethereum-roadmap/4698">rollup-centric roadmap</a></p></li><li><p>Optimism is one of the first rollup projects that are deployed and has a large market share</p></li><li><p>The upcoming Optimism Bedrock upgrade and the OP stack release are very exciting!</p></li><li><p>I sense a growing trend of the mind share of the OP ecosystem among developers (probably related to the OP stack!)</p></li></ul><p>In summary, I think a good timing to invest in the OP token is when:</p><ul><li><p>the token has more utilities</p></li><li><p>the sequencer model changes to decentralized and distribute revenue to token holders directly</p></li><li><p>the token price drops to a point where the derived market cap is much lower comparing to the valuation derived from the revenue</p></li></ul><p>So my advice is to look out for the governance proposals and follow closely with the community updates if you want to find some alphas in the market.</p>]]></content:encoded>
            <author>0xb2p@newsletter.paragraph.com (bap2pecs)</author>
        </item>
        <item>
            <title><![CDATA[My 2022 Summary]]></title>
            <link>https://paragraph.com/@0xb2p/my-2022-summary</link>
            <guid>I7uAV9aPWr3IgrTHCBdj</guid>
            <pubDate>Wed, 11 Jan 2023 03:16:46 GMT</pubDate>
            <description><![CDATA[HighlightsIn 2022, I entered my thirties.I left my job in August to pursue my passion for web3 technology.I explored different options to generate cash flows in DeFi sector.ETHSF winner and got accepted by a top web3 accelerator.DeFiI developed a prototype system for hunting airdrops of crypto projects. Ultimately, I decided to abandon the project, recognizing that the pursuit of money was not something that inspired me.I discovered a cash-printing DeFi project and became deeply involved with...]]></description>
            <content:encoded><![CDATA[<h2 id="h-highlights" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Highlights</h2><ul><li><p>In 2022, I entered my thirties.</p></li><li><p>I left my job in August to pursue my passion for web3 technology.</p></li><li><p>I explored different options to generate cash flows in DeFi sector.</p></li><li><p>ETHSF winner and got accepted by a top web3 accelerator.</p></li></ul><h2 id="h-defi" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">DeFi</h2><ul><li><p>I developed a prototype system for hunting airdrops of crypto projects. Ultimately, I decided to abandon the project, recognizing that the pursuit of money was not something that inspired me.</p></li><li><p>I discovered a cash-printing DeFi project and became deeply involved with its community and team. I provided meaningful input in the direction of the project. Additionally, I built a sophisticated monitoring system to maximize profits and generate earning reports.</p></li><li><p>I was so fortunate to have narrowly avoided being impacted by the LUNA crash and the FTX collapse.</p></li><li><p>I explored MEV with the intention of generating a cash flow, but I soon abandoned the project due to the same aforementioned reason. However, I managed to create and open source two tools for MEV as a side-effect: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/bap2pecs/ethereum-account-generator">Ethereum-Account-Generator</a> (for generating accounts with leading zeros to save on gas fees) and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/bap2pecs/ethereum-private-rpc">Ethereum-Private-RPC</a> (which can give you an advantage when it comes to MEV).</p></li><li><p>I conducted an in-depth analysis of various protocols for ETH staking and wrote a script to report earnings and track APYs of various pools to optimize profits.</p></li><li><p>I started a private business to generate revenues from DeFi protocols through staking. However, the protocol was heavily affected by the FTX/Alameda collapse.</p></li></ul><h2 id="h-career" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Career</h2><ul><li><p>I started to consider leaving my job at Meta in late 2021 to start my own business. I officially resigned in August 2022.</p></li><li><p>When I quit my job, I intended to first explore the web3 space and conduct research. I anticipated it would take roughly a year before I found a tangible project to work on. However, after seeing a tweet from a speaker at EthCC about their successful ETHGlobal hackathon project, I was inspired to apply for ETHSF. I chose an idea from my list and assembled a team to work on it. Despite having little sleep, we put in a tremendous amount of effort and, ultimately, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ethglobal.com/showcase/snapchain-kp408">our project</a> was chosen as one of the 13 finalists out of 284 teams.</p></li><li><p>After the hackathon, I conducted further research and validation and successfully applied to a top web3 accelerator (1% admission rate), raising funding at a $7M pre-seed valuation.</p></li></ul><h2 id="h-key-take-aways" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Key take-aways</h2><ul><li><p>Looking back, I should have left Meta in May, when I had already lost my enthusiasm for my job. The last three months at Meta were difficult for me, both mentally and in terms of productivity.</p></li><li><p>I learned a lot about myself. I came to the realization that, <strong>at my core, I am a builder</strong>. As a result, chasing after money is not something that will bring me true fulfillment.</p></li><li><p>I have learnt an important lesson to <strong>never invest money that I cannot afford to lose</strong> in high-risk investments.</p></li><li><p>In the web3 world, one has to <strong>dive deeper</strong> into the protocols and actively keep track of the latest developments and governance proposals to find the alphas.</p></li><li><p>By <strong>being open</strong> to new possibilities, I experienced serendipitous moments that led me to some amazing opportunities. If I had continued to pursue my plan of independently exploring the web3 space without raising capital, my progress will be much slower than it is currently.</p></li><li><p><strong>Focus on the right things</strong>. At the ETHSF hackathon, I did not have any expectations of taking home a prize, and I made sure to communicate this to my teammates. We kept our attention on creating a strong project, which ultimately earned us a spot as finalists.</p></li><li><p>A few people suggested that without a co-founder, it would be difficult to secure funding or gain acceptance into accelerator programs. Yet, <strong>finding the right co-founder is akin to finding one&apos;s perfect partner</strong> and thus, I chose not to rush the process. Instead, I applied as a solo founder and, through sheer hard work and dedication, was able to make it work.</p></li></ul><h2 id="h-2023-goals" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">2023 Goals</h2><ul><li><p>Build MVP &amp; showcase in demo day</p></li><li><p>Find product-market fit</p></li><li><p>Build founding team</p></li></ul>]]></content:encoded>
            <author>0xb2p@newsletter.paragraph.com (bap2pecs)</author>
        </item>
        <item>
            <title><![CDATA[Demystify SAFE]]></title>
            <link>https://paragraph.com/@0xb2p/demystify-safe</link>
            <guid>Yj1oZdy1qj5VJmhCl3BV</guid>
            <pubDate>Mon, 09 Jan 2023 18:19:18 GMT</pubDate>
            <description><![CDATA[Simple Agreement for Future Equity (SAFE) was introduced by YC to help startups for early-stage fundraising. However, the legal and financing terms used in the agreement can be overwhelming to founders that are not familiar with the process. I am gonna use Safe: Valuation Cap, no Discount as an example to clarify a little bit. The first thing you need to understand is that the agreement is for future equities. Meaning that you don’t need to go through the complicated process of getting all ot...]]></description>
            <content:encoded><![CDATA[<p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.ycombinator.com/documents">Simple Agreement for Future Equity (SAFE)</a> was introduced by YC to help startups for early-stage fundraising.</p><p>However, the legal and financing terms used in the agreement can be overwhelming to founders that are not familiar with the process. I am gonna use <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.ycombinator.com/assets/ycdc/Postmoney%20Safe%20-%20Valuation%20Cap%20Only%20v1.1-cb4934724e32a5864fd43ca894e51c8c081ecef136409c2e94f00d92168230ec.docx">Safe: Valuation Cap, no Discount</a> as an example to clarify a little bit.</p><p>The first thing you need to understand is that the agreement is for <strong>future equities</strong>. Meaning that you don’t need to go through the complicated process of getting all other investors to sign documents or issuing new stocks to the new SAFE investor. This is also why SAFE is becoming the industry standard.</p><p>The second thing you should know is that there are 3 major types of events that will “activate” the agreement and lead to certain implications. Then the agreement will be terminated automatically.</p><h2 id="h-equity-financing" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Equity Financing</h2><p>In human words, this refers to a formal round of fundraising in exchange of stocks. When it happens, the SAFE investor will receive some stocks as well. The amount equals to the valuation divided by the SAFE investment. The valuation will be chosen as the smaller of the formal round valuation and the SAFE valuation (i.e. Post-Money Valuation Cap).</p><p>For example, if the SAFE valuation cap is $10M and the purchase amount is $1M, then the SAFE investor will receive 10% of the company&apos;s equity if a formal round of funding is closed at a valuation of $50M. However, if the formal round of funding is closed at a valuation of $5M, the SAFE investor&apos;s equity stake will increase to 20%.</p><h2 id="h-liquidity-event" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Liquidity Event</h2><p>This usually happens when the company IPOs or is acquired by other companies. When such events happens, instead of receiving stocks, the SAFE investor receive some money.</p><p>The amount is determined by the valuation when the event happens. If the valuation is smaller than the SAFE valuation, the SAFE investor gets their money back, fully. Otherwise, the amount will increase in proportional to the valuation increase.</p><p>As an illustration, if the pre-money valuation cap of the SAFE is set at $10M and the purchase amount is $1M, then the SAFE investor is entitled to $5M when the company is acquired with a $50M valuation.</p><h2 id="h-dissolution-event" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Dissolution Event</h2><p>In the event of a company closure initiated by the founders, SAFE investors are entitled to receive a full return of their investment.</p><p>Nevertheless, the investors&apos; return will be contingent upon the amount of funds the company has remaining. If the company lacks sufficient funds, they will receive only a fraction of their initial investment, the magnitude of which will be determined by the &quot;Liquidation Priority&quot; as stipulated in Section 1(d).</p><p>In essence, investors have a higher preference than founders because commonly, founders own Common Stock while investors own Preferred Stock or a SAFE.</p><p>If, for instance, the SAFE valuation cap is $10M, and the purchase amount is $1M, with an additional investor who owns 10% Preferred Stock, then the remaining funds of $100 upon dissolution should yield $50 to the SAFE investor.</p>]]></content:encoded>
            <author>0xb2p@newsletter.paragraph.com (bap2pecs)</author>
        </item>
        <item>
            <title><![CDATA[How to use chatGPT to write code snippet]]></title>
            <link>https://paragraph.com/@0xb2p/how-to-use-chatgpt-to-write-code-snippet</link>
            <guid>ZvFYLEANABHibSFFbr83</guid>
            <pubDate>Tue, 03 Jan 2023 19:43:42 GMT</pubDate>
            <description><![CDATA[Recently, I heard many people saying how they used chatGPT to help them write code. So I decided to try it myself.Simple taskI decided to ask chatGPT to write a small helper function that has specific requirements. A perfect example immediately came up to my mind. This is a util function I needed in the ETHSF hackathon. I assigned it to one of my teammates and it took a few back-and-forths commits to get it right. The time between the first and last commit is 4 hours. So let’s assign the same...]]></description>
            <content:encoded><![CDATA[<p>Recently, I heard many people saying how they used <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://chat.openai.com/">chatGPT</a> to help them write code. So I decided to try it myself.</p><h2 id="h-simple-task" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Simple task</h2><p>I decided to ask chatGPT to write a small helper function that has specific requirements.</p><p>A perfect example immediately came up to my mind. <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/bap2pecs/Snapchain/blob/main/backend/src/geth/replaceStringArray.js">This</a> is a util function I needed in the ETHSF hackathon. I assigned it to one of my teammates and it took <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/bap2pecs/Snapchain/commits/main/backend/src/geth/replaceStringArray.js">a few back-and-forths commits</a> to get it right. The time between the first and last commit is <strong>4 hours</strong>.</p><p>So let’s assign the same task to chatGPT. My initial message to it:</p><pre data-type="codeBlock" text="/*
arr is an array of strings. examples:
[
  &apos;--syncmode=full&apos;,
  &apos;--datadir=&lt;datadir&gt;&apos;,
  &apos;--nodekey=&lt;nodekey&gt;&apos;,
  &apos;--port=&lt;port&gt;&apos;,
  &apos;--http&apos;,
  &apos;--http.addr=0.0.0.0&apos;,
  &apos;--http.port=&lt;httpport&gt;&apos;,
  &apos;--networkid=&lt;networkid&gt;&apos;,
  &apos;--mine&apos;,
  &apos;--miner.threads=1&apos;,
  &apos;--miner.gasprice=1&apos;,
  &apos;--unlock=&lt;unlock&gt;&apos;,
  &apos;--password=&lt;password&gt;&apos;,
  &apos;--allow-insecure-unlock&apos;
]
[ &apos;&lt;httpport&gt;:&lt;httpport&gt;&apos;, &apos;&lt;port&gt;:&lt;port&gt;&apos; ]
[ &apos;&lt;datadir&gt;:&lt;datadir&gt;&apos; ]
pairs is an object to specify how to do the replacement. example:
{
  &apos;&lt;datadir&gt;&apos;: &apos;/path/to/datadir&apos;,
  &apos;&lt;nodekey&gt;&apos;: &apos;/path/to/nodekey/file&apos;,
}
example return:
[ &apos;&lt;datadir&gt;:&lt;datadir&gt;&apos; ] =&gt; [&apos;/path/to/datadir:/path/to/datadir&apos;]
should return a new array of strings that applies the replacements
*/
export function replaceStringArray(arr, pairs) {
}

please implement the `replaceStringArray` function based on the requirement above it
"><code>/*
arr <span class="hljs-built_in">is</span> an array <span class="hljs-keyword">of</span> strings. examples:
[
  <span class="hljs-comment">'--syncmode=full',</span>
  <span class="hljs-comment">'--datadir=&#x3C;datadir>',</span>
  <span class="hljs-comment">'--nodekey=&#x3C;nodekey>',</span>
  <span class="hljs-comment">'--port=&#x3C;port>',</span>
  <span class="hljs-comment">'--http',</span>
  <span class="hljs-comment">'--http.addr=0.0.0.0',</span>
  <span class="hljs-comment">'--http.port=&#x3C;httpport>',</span>
  <span class="hljs-comment">'--networkid=&#x3C;networkid>',</span>
  <span class="hljs-comment">'--mine',</span>
  <span class="hljs-comment">'--miner.threads=1',</span>
  <span class="hljs-comment">'--miner.gasprice=1',</span>
  <span class="hljs-comment">'--unlock=&#x3C;unlock>',</span>
  <span class="hljs-comment">'--password=&#x3C;password>',</span>
  <span class="hljs-comment">'--allow-insecure-unlock'</span>
]
[ <span class="hljs-comment">'&#x3C;httpport>:&#x3C;httpport>', '&#x3C;port>:&#x3C;port>' ]</span>
[ <span class="hljs-comment">'&#x3C;datadir>:&#x3C;datadir>' ]</span>
pairs <span class="hljs-built_in">is</span> an <span class="hljs-type">object</span> <span class="hljs-keyword">to</span> specify how <span class="hljs-keyword">to</span> <span class="hljs-keyword">do</span> the replacement. example:
{
  <span class="hljs-comment">'&#x3C;datadir>': '/path/to/datadir',</span>
  <span class="hljs-comment">'&#x3C;nodekey>': '/path/to/nodekey/file',</span>
}
example <span class="hljs-keyword">return</span>:
[ <span class="hljs-comment">'&#x3C;datadir>:&#x3C;datadir>' ] => ['/path/to/datadir:/path/to/datadir']</span>
should <span class="hljs-keyword">return</span> a <span class="hljs-built_in">new</span> array <span class="hljs-keyword">of</span> strings that applies the replacements
*/
export <span class="hljs-keyword">function</span> replaceStringArray(arr, pairs) {
}

please implement the `replaceStringArray` <span class="hljs-keyword">function</span> based <span class="hljs-keyword">on</span> the requirement above it
</code></pre><p>Then I got the response:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/e12d39f62dcb51ba1953bb8a031dd3b19c052399e9625b67c858117dbaccaf18.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>It also gave some test input and output to help me verify the correctness:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/2a53fc6288cde7156f54b7049fdd4bf24c32297689f63410e856f35f0c980308.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>However, there is a bug and I pointed out:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/39ee38cfd765a6ac901b0f483a18560890d533a6ca95e19b2dff2dac2e2f5d01.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>chatGPT tried to fix it:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/f83da618534acd07bbad70d84dbe29713a0a40524f674a34daf2c7503471dd57.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>Unfortunately, chatGPT misunderstood the requirement. It’s worth noting that <strong>it’s my mistake</strong> that I didn’t specify clearly that it should “<em>replace all</em>” in the requirements. So I clarified it and this time it gave the right solution:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/e9133c38819ab736ed6ba0bf6c783fe3a64f2e2778056148b16650fb89d1d965.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>However, I noticed that it differs from <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/bap2pecs/Snapchain/blob/main/backend/src/geth/replaceStringArray.js#L38">my solution</a> where <code>replaceAll</code> is used. But it uses regular expression. So I asked it:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/1c44c3bd23ad51c25bab82da0990eb4967416fd12ffc31d1a8083924135142d7.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>chatGPT nicely explained its choice and helped me learn this new knowledge.</p><p>Then I asked it to optimize the code:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/8a84dfb5b4687508d29c7eb194c7776bffdca34fa86bb1c166e9081a015ba927.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>And chatGPT gave a few suggestions:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/cb0838f266bf6a18f3531c1c5e33f2cb1c3d2a4316f2e68aa86c0b72d5a04a7d.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><h2 id="h-conclusions" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Conclusions</h2><p>chatGPT is an effective tool for quickly finding solutions to coding problems, saving developers valuable time and effort.</p><p>However, if you don’t specify the requirements clearly, it might misunderstand and give solutions that have bugs in it.This also implies that you should know how to solve the coding question yourself and verify the solution carefully. It’s <strong>dangerous</strong> to blindly trust the solution given by it.</p><p>It’s also worth noting that if you find the bug and described it clearly to chatGPT, it can fix it.</p><p>It’s also interesting that if you have a different solution in mind, you can ask chatGPT why it’s not chosen. You might be surprised and learn something new.</p><p>You can also ask chatGPT to optimize the code. You can even repeat that for a few times until you feel the code is too hard to maintain.</p>]]></content:encoded>
            <author>0xb2p@newsletter.paragraph.com (bap2pecs)</author>
        </item>
        <item>
            <title><![CDATA[How to spin up your own PoA EVM chain?]]></title>
            <link>https://paragraph.com/@0xb2p/how-to-spin-up-your-own-poa-evm-chain</link>
            <guid>skHZBglSmo4evQuu94g7</guid>
            <pubDate>Sat, 29 Oct 2022 03:58:12 GMT</pubDate>
            <description><![CDATA[We will set up 1 bootnode and 2 geth nodes in 3 different servers. They will form the network for the EVM chain. All the nodes will run in containers.My setupI created 3 droplets on digitalocean (CentOS; shared CPU; 1GB 1Core)install and start docker (with the compose plugin) in all dropletsStep 1: set up bootnode (droplet A)first create boot.keymkdir /root/devnet/ &#x26;&#x26; docker run -d --rm -v /root:/root ethereum/client-go:alltools-latest bootnode --genkey=/root/devnet/boot.key then cr...]]></description>
            <content:encoded><![CDATA[<p>We will set up 1 bootnode and 2 geth nodes in 3 different servers. They will form the network for the EVM chain. All the nodes will run in containers.</p><h3 id="h-my-setup" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">My setup</h3><ul><li><p>I created 3 droplets on digitalocean (CentOS; shared CPU; 1GB 1Core)</p></li><li><p>install and start <code>docker</code> (with the <code>compose</code> plugin) in all droplets</p></li></ul><h3 id="h-step-1-set-up-bootnode-droplet-a" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Step 1: set up bootnode (droplet A)</h3><p>first create <code>boot.key</code></p><pre data-type="codeBlock" text="mkdir /root/devnet/ &amp;&amp; docker run -d --rm -v /root:/root ethereum/client-go:alltools-latest bootnode --genkey=/root/devnet/boot.key
"><code>mkdir <span class="hljs-operator">/</span>root<span class="hljs-operator">/</span>devnet<span class="hljs-operator">/</span> <span class="hljs-operator">&#x26;</span><span class="hljs-operator">&#x26;</span> docker run <span class="hljs-operator">-</span>d <span class="hljs-operator">-</span><span class="hljs-operator">-</span>rm <span class="hljs-operator">-</span>v <span class="hljs-operator">/</span>root:<span class="hljs-operator">/</span>root ethereum<span class="hljs-operator">/</span>client<span class="hljs-operator">-</span>go:alltools<span class="hljs-operator">-</span>latest bootnode <span class="hljs-operator">-</span><span class="hljs-operator">-</span>genkey<span class="hljs-operator">=</span><span class="hljs-operator">/</span>root<span class="hljs-operator">/</span>devnet<span class="hljs-operator">/</span>boot.key
</code></pre><p>then create a compose file and run <code>docker compose up -d</code>:</p><pre data-type="codeBlock" text="services:
  bootnode:
    image: ethereum/client-go:alltools-latest
    container_name: bootnode
    command:
      [
        &apos;bootnode&apos;,
        &apos;--nodekey=/root/devnet/boot.key&apos;,
        &apos;-addr=:30303&apos;,
        &apos;-verbosity=5&apos;,
      ]
    ports:
      - &apos;30303:30303/udp&apos;
    restart: always
    volumes:
      - /root:/root
"><code>services:
  bootnode:
    image: ethereum<span class="hljs-operator">/</span>client<span class="hljs-operator">-</span>go:alltools<span class="hljs-operator">-</span>latest
    container_name: bootnode
    command:
      [
        <span class="hljs-string">'bootnode'</span>,
        <span class="hljs-string">'--nodekey=/root/devnet/boot.key'</span>,
        <span class="hljs-string">'-addr=:30303'</span>,
        <span class="hljs-string">'-verbosity=5'</span>,
      ]
    ports:
      <span class="hljs-operator">-</span> <span class="hljs-string">'30303:30303/udp'</span>
    restart: always
    volumes:
      <span class="hljs-operator">-</span> <span class="hljs-operator">/</span>root:<span class="hljs-operator">/</span>root
</code></pre><p>in <code>docker compose log</code>, you will see a encode URL like this:</p><pre data-type="codeBlock" text="enode://&lt;REDACTED&gt;@127.0.0.1:0?discport=30303
"><code>enode://&#x3C;REDACTED>@127.0.0.1:0?<span class="hljs-attr">discport</span>=<span class="hljs-number">30303</span>
</code></pre><p>replace <code>127.0.0.1:0</code> with <code>&lt;the public IP&gt;:30303</code> and take it down some where. We will refer it as <code>encodeURL</code> later.</p><h3 id="h-step-2-create-account-droplet-b-and-c" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Step 2: create account (droplet B and C)</h3><pre data-type="codeBlock" text="echo 123456 &gt; /root/devnet/password.txt
docker run -d --rm -v /root:/root ethereum/client-go:alltools-latest geth account new --password /root/devnet/password.txt
"><code>echo <span class="hljs-number">123456</span> <span class="hljs-operator">></span> <span class="hljs-operator">/</span>root<span class="hljs-operator">/</span>devnet<span class="hljs-operator">/</span>password.txt
docker run <span class="hljs-operator">-</span>d <span class="hljs-operator">-</span><span class="hljs-operator">-</span>rm <span class="hljs-operator">-</span>v <span class="hljs-operator">/</span>root:<span class="hljs-operator">/</span>root ethereum<span class="hljs-operator">/</span>client<span class="hljs-operator">-</span>go:alltools<span class="hljs-operator">-</span>latest geth account <span class="hljs-keyword">new</span> <span class="hljs-operator">-</span><span class="hljs-operator">-</span>password <span class="hljs-operator">/</span>root<span class="hljs-operator">/</span>devnet<span class="hljs-operator">/</span>password.txt
</code></pre><p>then you can find the address by <code>ls /root/.ethereum/keystore/</code></p><p>you will see a file: <code>UTC--2022-10-28…--&lt;address&gt;</code> where you can extract the address.</p><h3 id="h-step-3-create-genesis-file" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Step 3: create genesis file</h3><p>you can run this command in any server to create the genesis file (Note: don’t forget to export the file to <code>/root/devnet/devnet.json</code>)</p><pre data-type="codeBlock" text="docker run -it --rm -v /root:/root ethereum/client-go:alltools-latest puppeth
"><code>docker run <span class="hljs-operator">-</span>it <span class="hljs-operator">-</span><span class="hljs-operator">-</span>rm <span class="hljs-operator">-</span>v <span class="hljs-operator">/</span>root:<span class="hljs-operator">/</span>root ethereum<span class="hljs-operator">/</span>client<span class="hljs-operator">-</span>go:alltools<span class="hljs-operator">-</span>latest puppeth
</code></pre><p>you should provide the two addresses generated in previous step for these questions:</p><ul><li><p>Which accounts are allowed to seal?</p></li><li><p>Which accounts should be pre-funded?</p></li></ul><p>then modify the &quot;nonce&quot; field to be a random value as recommended <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum/go-ethereum/#defining-the-private-genesis-state">here</a></p><p>last, copy the genesis file to both droplet B and C</p><h3 id="h-step-4-init-genesis-block-and-start-the-node-droplet-b-and-c" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Step 4: init genesis block and start the node (droplet B and C)</h3><pre data-type="codeBlock" text="docker run -d --rm -v /root:/root ethereum/client-go:alltools-latest geth init /root/devnet/devnet.json
"><code>docker run <span class="hljs-operator">-</span>d <span class="hljs-operator">-</span><span class="hljs-operator">-</span>rm <span class="hljs-operator">-</span>v <span class="hljs-operator">/</span>root:<span class="hljs-operator">/</span>root ethereum<span class="hljs-operator">/</span>client<span class="hljs-operator">-</span>go:alltools<span class="hljs-operator">-</span>latest geth init <span class="hljs-operator">/</span>root<span class="hljs-operator">/</span>devnet<span class="hljs-operator">/</span>devnet.json
</code></pre><p>then create a compose file and run <code>docker compose up -d</code>:</p><pre data-type="codeBlock" text="services:
  geth:
    image: ethereum/client-go
    container_name: geth
    command:
      [
        &apos;--syncmode=full&apos;,
        &apos;--bootnodes=&lt;encodeURL&gt;&apos;,
        &apos;--port=30303&apos;,
        &apos;--http&apos;,
        &apos;--http.addr=0.0.0.0&apos;,
        &apos;--networkid=&lt;read from the genesis file&gt;&apos;,
        &apos;--mine&apos;,
        &apos;--miner.threads=1&apos;,
        &apos;--miner.gasprice=1&apos;,
        &apos;--unlock=&lt;step2 generated address&gt;&apos;,
        &apos;--password=/root/devnet/password.txt&apos;,
        &apos;--allow-insecure-unlock&apos;,
      ]
    ports:
      - &apos;8545:8545&apos;
      - &apos;30303:30303&apos;
    restart: always
    volumes:
      - /root:/root
"><code>services:
  geth:
    image: ethereum<span class="hljs-operator">/</span>client<span class="hljs-operator">-</span>go
    container_name: geth
    command:
      [
        <span class="hljs-string">'--syncmode=full'</span>,
        <span class="hljs-string">'--bootnodes=&#x3C;encodeURL>'</span>,
        <span class="hljs-string">'--port=30303'</span>,
        <span class="hljs-string">'--http'</span>,
        <span class="hljs-string">'--http.addr=0.0.0.0'</span>,
        <span class="hljs-string">'--networkid=&#x3C;read from the genesis file>'</span>,
        <span class="hljs-string">'--mine'</span>,
        <span class="hljs-string">'--miner.threads=1'</span>,
        <span class="hljs-string">'--miner.gasprice=1'</span>,
        <span class="hljs-string">'--unlock=&#x3C;step2 generated address>'</span>,
        <span class="hljs-string">'--password=/root/devnet/password.txt'</span>,
        <span class="hljs-string">'--allow-insecure-unlock'</span>,
      ]
    ports:
      <span class="hljs-operator">-</span> <span class="hljs-string">'8545:8545'</span>
      <span class="hljs-operator">-</span> <span class="hljs-string">'30303:30303'</span>
    restart: always
    volumes:
      <span class="hljs-operator">-</span> <span class="hljs-operator">/</span>root:<span class="hljs-operator">/</span>root
</code></pre><h3 id="h-step-5-verify" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Step 5: verify</h3><p>in the bootnode server, run <code>docker compose log</code> you should see:</p><pre data-type="codeBlock" text="bootnode  | TRACE[10-29|03:28:44.657] &lt;&lt; FINDNODE/v4                           id=&lt;REDACTED&gt; addr=&lt;REDACTED&gt;  err=nil
bootnode  | TRACE[10-29|03:28:44.657] &gt;&gt; NEIGHBORS/v4                          id=&lt;REDACTED&gt; addr=&lt;REDACTED&gt;  err=nil
"><code>bootnode  <span class="hljs-operator">|</span> TRACE[<span class="hljs-number">10</span><span class="hljs-number">-29</span><span class="hljs-operator">|</span>03:<span class="hljs-number">28</span>:<span class="hljs-number">44.657</span>] <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">&#x3C;</span> FINDNODE<span class="hljs-operator">/</span>v4                           id<span class="hljs-operator">=</span><span class="hljs-operator">&#x3C;</span>REDACTED<span class="hljs-operator">></span> addr<span class="hljs-operator">=</span><span class="hljs-operator">&#x3C;</span>REDACTED<span class="hljs-operator">></span>  err<span class="hljs-operator">=</span>nil
bootnode  <span class="hljs-operator">|</span> TRACE[<span class="hljs-number">10</span><span class="hljs-number">-29</span><span class="hljs-operator">|</span>03:<span class="hljs-number">28</span>:<span class="hljs-number">44.657</span>] <span class="hljs-operator">></span><span class="hljs-operator">></span> NEIGHBORS<span class="hljs-operator">/</span>v4                          id<span class="hljs-operator">=</span><span class="hljs-operator">&#x3C;</span>REDACTED<span class="hljs-operator">></span> addr<span class="hljs-operator">=</span><span class="hljs-operator">&#x3C;</span>REDACTED<span class="hljs-operator">></span>  err<span class="hljs-operator">=</span>nil
</code></pre><p>in the other servers, you should see:</p><pre data-type="codeBlock" text="geth  | INFO [10-29|00:32:41.507] Looking for peers                        peercount=1 tried=0 static=0
geth  | INFO [10-29|00:32:43.326] Successfully sealed new block            number=42 sealhash=&lt;REDACTED&gt; hash=&lt;REDACTED&gt; elapsed=14.483s
geth  | INFO [10-29|00:32:43.326] 🔨 mined potential block                  number=42 hash=&lt;REDACTED&gt;
geth  | INFO [10-29|00:32:43.327] Commit new sealing work                  number=43 sealhash=&lt;REDACTED&gt; uncles=0 txs=0 gas=0 fees=0 elapsed=&quot;269.928µs&quot;
"><code>geth  <span class="hljs-operator">|</span> INFO [<span class="hljs-number">10</span><span class="hljs-number">-29</span><span class="hljs-operator">|</span>00:<span class="hljs-number">32</span>:<span class="hljs-number">41.507</span>] Looking <span class="hljs-keyword">for</span> peers                        peercount<span class="hljs-operator">=</span><span class="hljs-number">1</span> tried<span class="hljs-operator">=</span><span class="hljs-number">0</span> static<span class="hljs-operator">=</span><span class="hljs-number">0</span>
geth  <span class="hljs-operator">|</span> INFO [<span class="hljs-number">10</span><span class="hljs-number">-29</span><span class="hljs-operator">|</span>00:<span class="hljs-number">32</span>:<span class="hljs-number">43.326</span>] Successfully sealed <span class="hljs-keyword">new</span> <span class="hljs-built_in">block</span>            number<span class="hljs-operator">=</span><span class="hljs-number">42</span> sealhash<span class="hljs-operator">=</span><span class="hljs-operator">&#x3C;</span>REDACTED<span class="hljs-operator">></span> hash<span class="hljs-operator">=</span><span class="hljs-operator">&#x3C;</span>REDACTED<span class="hljs-operator">></span> elapsed<span class="hljs-operator">=</span><span class="hljs-number">14</span>.483s
geth  <span class="hljs-operator">|</span> INFO [<span class="hljs-number">10</span><span class="hljs-number">-29</span><span class="hljs-operator">|</span>00:<span class="hljs-number">32</span>:<span class="hljs-number">43.326</span>] 🔨 mined potential <span class="hljs-built_in">block</span>                  number<span class="hljs-operator">=</span><span class="hljs-number">42</span> hash<span class="hljs-operator">=</span><span class="hljs-operator">&#x3C;</span>REDACTED<span class="hljs-operator">></span>
geth  <span class="hljs-operator">|</span> INFO [<span class="hljs-number">10</span><span class="hljs-number">-29</span><span class="hljs-operator">|</span>00:<span class="hljs-number">32</span>:<span class="hljs-number">43.327</span>] Commit <span class="hljs-keyword">new</span> sealing work                  number<span class="hljs-operator">=</span><span class="hljs-number">43</span> sealhash<span class="hljs-operator">=</span><span class="hljs-operator">&#x3C;</span>REDACTED<span class="hljs-operator">></span> uncles<span class="hljs-operator">=</span><span class="hljs-number">0</span> txs<span class="hljs-operator">=</span><span class="hljs-number">0</span> gas<span class="hljs-operator">=</span><span class="hljs-number">0</span> fees<span class="hljs-operator">=</span><span class="hljs-number">0</span> elapsed<span class="hljs-operator">=</span><span class="hljs-string">"269.928µs"</span>
</code></pre><p>you can also run:</p><pre data-type="codeBlock" text="docker run -it --rm -v /root:/root ethereum/client-go:alltools-latest geth attach
&gt; eth.blockNumber
"><code>docker run <span class="hljs-operator">-</span>it <span class="hljs-operator">-</span><span class="hljs-operator">-</span>rm <span class="hljs-operator">-</span>v <span class="hljs-operator">/</span>root:<span class="hljs-operator">/</span>root ethereum<span class="hljs-operator">/</span>client<span class="hljs-operator">-</span>go:alltools<span class="hljs-operator">-</span>latest geth attach
<span class="hljs-operator">></span> eth.blockNumber
</code></pre><p>and you will see the <code>blockNumber</code> increasing.</p><p>congrats on spinning up your own EVM chain!</p><h3 id="h-references" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">References:</h3><ul><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://hackernoon.com/setup-your-own-private-proof-of-authority-ethereum-network-with-geth-9a0a3750cda8">Setup your own private Proof-of-Authority Ethereum network with Geth</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum/go-ethereum#operating-a-private-network">Operating a private network</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://geth.ethereum.org/docs/interface/private-network">Go Ethereum: Private Networks</a></p></li></ul>]]></content:encoded>
            <author>0xb2p@newsletter.paragraph.com (bap2pecs)</author>
        </item>
        <item>
            <title><![CDATA[Small tips for sending out Ethereum transactions]]></title>
            <link>https://paragraph.com/@0xb2p/small-tips-for-sending-out-ethereum-transactions</link>
            <guid>qcGZjLMQEc2XKDUgdv4Y</guid>
            <pubDate>Fri, 14 Oct 2022 19:39:59 GMT</pubDate>
            <description><![CDATA[Yesterday I sent out a transaction by manually specifying a very low max gas price on Metamask. Then I regretted doing that because my transaction stuck for hours. So I tried to increase the gas price but I kept getting this “replacement transaction underpriced” error. Later I found out the problem was that I need to increase the “priority fee” as well. Simply increasing max gas price is not enough. Another interesting finding when I was trying to directly interact with the contract on Ethers...]]></description>
            <content:encoded><![CDATA[<p>Yesterday I sent out a transaction by manually specifying a very low max gas price on Metamask. Then I regretted doing that because my transaction stuck for hours.</p><p>So I tried to increase the gas price but I kept getting this “replacement transaction underpriced” error.</p><p>Later I found out the problem was that I need to increase the “priority fee” as well. Simply increasing max gas price is not enough.</p><p>Another interesting finding when I was trying to directly interact with the contract on Etherscan (although failed with the same error) is that <code>0x0</code> and <code>0x</code> are different values for <code>bytes</code> fields. If you want to pass in empty value for the <code>bytes</code> type parameter, you should input <code>0x</code> instead of <code>0x0</code>.</p>]]></content:encoded>
            <author>0xb2p@newsletter.paragraph.com (bap2pecs)</author>
        </item>
        <item>
            <title><![CDATA[Tips Using Chrome DevTools to Analyze Requests]]></title>
            <link>https://paragraph.com/@0xb2p/tips-using-chrome-devtools-to-analyze-requests</link>
            <guid>5xhDXJBW6agfh3s2iZAo</guid>
            <pubDate>Wed, 05 Oct 2022 00:13:55 GMT</pubDate>
            <description><![CDATA[Sometimes, you use Chrome’s DevTools to analyze network requests and you may want to copy the URL and request payload into your code to construct your own request. The problem is the payload can get very complicated. It’s tiring to type it yourself. Recently, I found our Chrome has a nice feature which allows you to copy the entire payload object:The copied string is a JavaScript object so you can paste directly into your JavaScript code without any modifications.]]></description>
            <content:encoded><![CDATA[<p>Sometimes, you use Chrome’s DevTools to analyze network requests and you may want to copy the URL and request payload into your code to construct your own request.</p><p>The problem is the payload can get very complicated. It’s tiring to type it yourself. Recently, I found our Chrome has a nice feature which allows you to copy the entire payload object:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/9b25ba8fceaeb812990d82363f609a505627fef1472a5a29e773e9ceeffe96f6.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>The copied string is a JavaScript object so you can paste directly into your JavaScript code without any modifications.</p>]]></content:encoded>
            <author>0xb2p@newsletter.paragraph.com (bap2pecs)</author>
        </item>
        <item>
            <title><![CDATA[Web Scraping with Puppeteer and Cheerio]]></title>
            <link>https://paragraph.com/@0xb2p/web-scraping-with-puppeteer-and-cheerio</link>
            <guid>qYw1ChZxqwHgaUjpVb52</guid>
            <pubDate>Tue, 04 Oct 2022 23:54:38 GMT</pubDate>
            <description><![CDATA[Cheerio can parse HTMLs while Puppeteer lets you run browser automation. They work pretty well together. Let’s look at an example. Say I want to parse some data from stake.rocketpool.net, simply doing an http request and parse the result with Cheerio won’t work because it needs to execute some code in a browser to fetch the data. By examining how the page loads, I noticed that class="loaded" will be added to the <body> tag when it finishes loading.So you can write the code as:To select a cert...]]></description>
            <content:encoded><![CDATA[<p><code>Cheerio</code> can parse HTMLs while <code>Puppeteer</code> lets you run browser automation. They work pretty well together.</p><p>Let’s look at an example. Say I want to parse some data from <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://stake.rocketpool.net">stake.rocketpool.net</a>, simply doing an http request and parse the result with <code>Cheerio</code> won’t work because it needs to execute some code in a browser to fetch the data.</p><p>By examining how the page loads, I noticed that <code>class=&quot;loaded&quot;</code> will be added to the <code>&lt;body&gt;</code> tag when it finishes loading.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/c024e0af4a2e8d296aef8a2739dca26f8c1a97b30853661afcc1c98152b9819f.gif" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>So you can write the code as:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/f3ce39266771e01a670fefc84d085a1d0adb37f186a165e47e3116a439775509.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>To select a certain element in the HTML, you can test it out in chrome first:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/550764e5a4317c912ed600529a9b84e040fa47f00c544473a62a3149c09702a5.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>Then you can write the code using the <code>Cheerio</code> APIs:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/f3ed0714a998b2c8acb112f8254a0a9ce26356923f473a6c529d7464fe81adde.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p><code>Puppeteer</code> also allows you perform complex tasks. Here is an example where it inputs some text in the page and lets you parse the updated HTML:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/3262fe1bf40c718468a7127db3f4ce14b7d3b8cf440b64095c12b28ac80bd3d4.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>Sometimes, it’s not easy to figure out the right selector for <code>waitForSelector</code>. A general solution (i.e. it won’t always work) is:</p><pre data-type="codeBlock" text="await page.goto(url, { waitUntil: &apos;networkidle0&apos; });
"><code><span class="hljs-keyword">await</span> page.<span class="hljs-keyword">goto</span>(url, { waitUntil: <span class="hljs-string">'networkidle0'</span> });
</code></pre><h2 id="h-limitations" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Limitations</h2><p>Web scrapping isn’t the antidote for all situations. It’s slower, more complicated and less reliable (e.g. sometimes you will get the “Navigation timeout” error) than making http requests directly. Thus, in some cases, you might want to consider making http requests directly (using libraries such as <code>axios</code>) if it’s easy to identify the corresponding network request by analyzing the requests using the browser’s developer tools.</p><p>Some sites might also give you the HTML containing the data you want from making plain http requests. So you can use <code>Cheerio</code> directly to parse it. Here is an example:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/1820db505031605530d725985d66b7d2acb6ddd5742ed9c87345ae45173f503c.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p><code>Puppeteer</code> also does not work well with docker. You can check out the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/puppeteer/puppeteer/blob/main/docs/troubleshooting.md#running-puppeteer-in-docker">guide</a> if you want to dive into the rabbit hole.</p>]]></content:encoded>
            <author>0xb2p@newsletter.paragraph.com (bap2pecs)</author>
        </item>
    </channel>
</rss>