<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[448-OG Decentralized Infrastructure Blog]]></title><description><![CDATA[Payments, Networking and Decentralized Infrastructure]]></description><link>https://448.africa</link><image><url>https://cdn.hashnode.com/uploads/logos/62b2367c0572b078ae5172b1/ad2f75b8-608f-4842-9bf7-ae9064060ef6.png</url><title>448-OG Decentralized Infrastructure Blog</title><link>https://448.africa</link></image><generator>RSS for Node</generator><lastBuildDate>Tue, 21 Apr 2026 00:58:42 GMT</lastBuildDate><atom:link href="https://448.africa/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[SVM Series 04: TransactionBatchProcessor]]></title><description><![CDATA[What is TransactionBatchProcessor?
The TransactionBatchProcessor handles validation and execution of sanitized batched transactions within the SVM acting as the central interface for the whole transaction execution pipeline.
// TransactionBatchProces...]]></description><link>https://448.africa/svm-series-04-transactionbatchprocessor</link><guid isPermaLink="true">https://448.africa/svm-series-04-transactionbatchprocessor</guid><category><![CDATA[Solana]]></category><category><![CDATA[SVM]]></category><dc:creator><![CDATA[448-OG]]></dc:creator><pubDate>Tue, 12 Aug 2025 16:11:12 GMT</pubDate><content:encoded><![CDATA[<h2 id="heading-what-is-transactionbatchprocessor">What is TransactionBatchProcessor?</h2>
<p>The <a target="_blank" href="https://docs.rs/solana-svm/latest/solana_svm/transaction_processor/struct.TransactionBatchProcessor.html"><code>TransactionBatchProcessor</code></a> handles validation and execution of <code>sanitized</code> batched transactions within the SVM acting as the central interface for the whole transaction execution pipeline.</p>
<pre><code class="lang-rust"><span class="hljs-comment">// TransactionBatchProcessor struct as declared in SVM code</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">TransactionBatchProcessor</span></span>&lt;FG: solana_program_runtime::loaded_programs::ForkGraph&gt; {
    <span class="hljs-comment">/// Bank slot (i.e. block)</span>
    slot: Slot,

    <span class="hljs-comment">/// Bank epoch</span>
    epoch: Epoch,

    <span class="hljs-comment">/// SysvarCache is a collection of system variables that are</span>
    <span class="hljs-comment">/// accessible from on chain programs. It is passed to SVM from</span>
    <span class="hljs-comment">/// client code (e.g. Bank) and forwarded to process_message.</span>
    sysvar_cache: RwLock&lt;SysvarCache&gt;,

    <span class="hljs-comment">/// Programs required for transaction batch processing</span>
    <span class="hljs-keyword">pub</span> program_cache: Arc&lt;RwLock&lt;ProgramCache&lt;FG&gt;&gt;&gt;,

    <span class="hljs-comment">/// Builtin program ids</span>
    <span class="hljs-keyword">pub</span> builtin_program_ids: RwLock&lt;HashSet&lt;Pubkey&gt;&gt;,

    execution_cost: SVMTransactionExecutionCost,
}
</code></pre>
<h2 id="heading-fields-of-transactionbatchprocessor-struct">Fields of TransactionBatchProcessor struct</h2>
<ol>
<li><p><code>slot</code> - a fixed timeframe when a validator can produce a block (can be as low as 150ms for alpenglow consensus). It’s Rust data type is a <code>u64</code>.</p>
</li>
<li><p><code>epoch</code> - the timeframe when a leader schedule is valid divided into slots. The leader schedule is the mapping of validator public keys to each slot within the given epoch. It’s Rust data type is also a <code>u64</code>.</p>
</li>
<li><p><code>sysvar_cache</code> - defined by the Rust type <a target="_blank" href="https://docs.rs/solana-program-runtime/2.3.7/solana_program_runtime/sysvar_cache/struct.SysvarCache.html"><code>SysvarCache</code></a>, it contains system variables like the <a target="_blank" href="https://docs.rs/solana-clock/latest/solana_clock/struct.Clock.html"><code>Clock</code></a> (network time), <a target="_blank" href="https://docs.rs/solana-epoch-schedule/latest/solana_epoch_schedule/struct.EpochSchedule.html"><code>Epoch Schedule</code></a>, <a target="_blank" href="https://docs.rs/solana-epoch-rewards/latest/solana_epoch_rewards/struct.EpochRewards.html"><code>Epoch Rewards</code></a>, <a target="_blank" href="https://docs.rs/solana-program-runtime/2.3.7/solana_program_runtime/__private/struct.Rent.html"><code>Rent</code></a>, <a target="_blank" href="https://docs.rs/solana-stake-interface/1.2.1/solana_stake_interface/stake_history/struct.StakeHistory.html"><code>Stake History</code></a> and <a target="_blank" href="https://docs.rs/solana-last-restart-slot/latest/solana_last_restart_slot/struct.LastRestartSlot.html"><code>Last Network Restart Slot</code></a>.</p>
</li>
<li><p><code>program_cache</code> - defined by the Rust type <a target="_blank" href="https://docs.rs/solana-program-runtime/2.3.7/solana_program_runtime/loaded_programs/struct.ProgramCache.html"><code>ProgramCache</code></a>, it contains loaded, compiled and verified programs required for transaction batch processing, optimizing shared data across validator forks. It tracks program information such as usage stats, verification status, and handles deployments, evictions, and tombstones for unloadable programs. Executable programs that are frequently used are kept in memory to improve execution speed through cooperative batch loading and eager preloading. The program cache isn’t saved to disk, so it must be rebuilt after each SVM restart.</p>
</li>
<li><p><code>builtin_program_ids</code> - It contains builtin program IDs like <a target="_blank" href="https://docs.rs/solana-sdk-ids/latest/solana_sdk_ids/bpf_loader/index.html"><code>BPF Loader</code></a> that own and execute smart contract programs and program configs like the supported SBF versions (all SBF versions are enabled by default).</p>
</li>
<li><p><code>execution_cost</code> - configures the CUs used by various operations like how much computing a SHA256 hash costs, cost of logging (<code>msg!()</code>), CPI, verifying Ed25519 signatures, CUs used for additional heap allocations above the default and more.</p>
</li>
</ol>
<h2 id="heading-processing-batched-sanitized-transactions">Processing batched sanitized transactions</h2>
<p>The method on <code>TransactionBatchProcessor</code> for processing sanitized transaction batches is <a target="_blank" href="https://docs.rs/solana-svm/latest/solana_svm/transaction_processor/struct.TransactionBatchProcessor.html#method.load_and_execute_sanitized_transactions"><code>TransactionBatchProcessor:: load_and_execute_sanitized_transactions</code></a>. It acts as the entry point to the SVM and takes the following parameters:</p>
<ol>
<li><p><code>callbacks</code>: This parameter allows the transaction processor to load information about accounts required for transaction execution. It requires the value supplied to this argument to implement the <a target="_blank" href="https://docs.rs/solana-svm/latest/solana_svm/transaction_processing_callback/trait.TransactionProcessingCallback.html"><code>TransactionProcessingCallback</code></a> trait which is a supertrait of <a target="_blank" href="https://docs.rs/solana-svm-callback/2.3.7/solana_svm_callback/trait.InvokeContextCallback.html"><code>InvokeContextCallback</code></a> trait (the callback used by <a target="_blank" href="https://docs.rs/solana-program-runtime/latest/solana_program_runtime/invoke_context/struct.InvokeContext.html"><code>solana_program_runtime::invoke_context::InvokeContext</code></a> in SVM to manage the main pipeline from runtime to program execution). By defining this trait developers can maintain full control of their application while ensuring integration with SVM according to the specification. This trait has three methods:</p>
<ul>
<li><p><code>get_account_shared_data()</code> which takes <code>&amp;self</code>, a public key (the address to fetch information for) as parameters and returns an optional <a target="_blank" href="https://docs.rs/solana-account/latest/solana_account/struct.AccountSharedData.html"><code>AccountSharedData</code></a> struct which is the in-memory representation of an Account. An <code>Option::None</code> can be returned if the account does not exist.</p>
</li>
<li><p><code>account_matches_owner</code> which takes <code>&amp;self</code>, a public key and a slice of public keys (<code>&amp;[Pubkey]</code>) representing potential owners of an account. The goal of this method is to get the index of the owner of the <code>public key</code> within the slice of owners <code>&amp;[Pubkey]</code>, therefore, it returns an <code>Option</code> of type <code>usize</code>. An <code>Option::None</code> can be returned if the <code>account</code> public key does not exist in the <code>Bank</code> or if the lamports balance is zero.</p>
</li>
<li><p><code>add_builtin_account</code> which takes a <code>&amp;self</code>, <code>name</code> of type <code>&amp;str</code> and a <code>program_id</code> public key. This method is used to add a program to the available programs in the execution pipeline, for example adding the <code>native loader</code> to the bank, that would load a smart contract program into the execution pipeline.</p>
</li>
</ul>
</li>
<li><p><code>sanitized_txs</code>: This parameter contains a slice of sanitized Solana transactions (<code>&amp;[impl SVMTransaction]</code>). A sanitized Solana transaction can be any Rust type as long as it implements the <a target="_blank" href="https://docs.rs/solana-svm-transaction/latest/solana_svm_transaction/svm_transaction/trait.SVMTransaction.html"><code>SVMTransaction</code></a> trait which is a supertrait of <a target="_blank" href="https://docs.rs/solana-svm-transaction/latest/solana_svm_transaction/svm_message/trait.SVMMessage.html"><code>SVMMessage</code></a>. These traits allow any type implementing them to provide convenience methods that can fetch information such as the fee payer, the first signature, all the signatures in a transaction, number of transaction signatures, the recent blockhash of the transaction, the number of write locks, the account keys and more. An example of a type implementing this trait is <a target="_blank" href="https://docs.rs/solana-transaction/latest/solana_transaction/sanitized/struct.SanitizedTransaction.html"><code>SanitizedTransaction</code></a>.</p>
</li>
<li><p><code>check_results</code> - this parameter contains a list of the results of checking the <a target="_blank" href="https://docs.rs/solana-svm/latest/solana_svm/account_loader/type.TransactionCheckResult.html">validity of a transaction</a>. Some checks performed that produce these results include the validity of a blockhash or nonce, whether an account matches it’s owner and whether the number of sanitized transactions equals the number of transactions that underwent these checks.</p>
</li>
<li><p><code>environment</code> - This parameter is the runtime environment for transaction batch processing instantiated by <a target="_blank" href="https://docs.rs/solana-svm/latest/solana_svm/transaction_processor/struct.TransactionProcessingEnvironment.html"><code>TransactionProcessingEnvironment</code></a> struct. It configures the blockhash to use for the current transaction batch, <a target="_blank" href="https://docs.rs/solana-svm-rent-collector/latest/solana_svm_rent_collector/svm_rent_collector/trait.SVMRentCollector.html">determine rent due for the account and collect rent</a>, the <a target="_blank" href="https://docs.rs/solana-svm-feature-set/latest/solana_svm_feature_set/struct.SVMFeatureSet.html">runtime features</a> to use, lamports per signature for nonce accounts and the total stake for the current epoch.</p>
</li>
<li><p><code>config</code> - this parameter configures customization of transaction processing behavior using <a target="_blank" href="https://docs.rs/solana-svm/latest/solana_svm/transaction_processor/struct.TransactionProcessingConfig.html"><code>TransactionProcessingConfig</code></a> struct. Custom configurations include <a target="_blank" href="https://docs.rs/solana-svm/latest/solana_svm/account_overrides/struct.AccountOverrides.html">account overrides</a>, log message byte size limits, configuring of the <a target="_blank" href="https://docs.rs/solana-svm/latest/solana_svm/transaction_processor/struct.ExecutionRecordingConfig.html">recording capabilities</a> for transaction execution, whether to limit the number of programs loaded for the transaction batch and whether or not to check a program’s modification slot when replenishing a program cache instance.</p>
</li>
</ol>
<p>The <a target="_blank" href="https://docs.rs/solana-svm/latest/solana_svm/transaction_processor/struct.TransactionBatchProcessor.html#method.load_and_execute_sanitized_transactions"><code>load_and_execute_sanitized_transactions</code></a> returns a <a target="_blank" href="https://docs.rs/solana-svm/latest/solana_svm/transaction_processor/struct.LoadAndExecuteSanitizedTransactionsOutput.html"><code>LoadAndExecuteSanitizedTransactionsOutput</code></a> struct which contains the fields:</p>
<ol>
<li><p><code>error_metrics</code> - the <a target="_blank" href="https://docs.rs/solana-svm/latest/solana_svm/transaction_error_metrics/struct.TransactionErrorMetrics.html">error metrics</a> for the processed transactions</p>
</li>
<li><p><code>execute_timings</code> - <a target="_blank" href="https://docs.rs/solana-timings/2.3.7/solana_timings/struct.ExecuteTimings.html">timings for transaction batch execution</a></p>
</li>
<li><p><code>processing_results</code> - a vector containing type alias <a target="_blank" href="https://docs.rs/solana-svm/latest/solana_svm/transaction_processing_result/type.TransactionProcessingResult.html">TransactionProcessingResult</a> indicating whether a transaction executed successfully or the transaction execution failed and needs to be rolled back</p>
</li>
<li><p><code>balance_collector</code> - a <code>Option&lt;</code><a target="_blank" href="https://docs.rs/solana-svm/latest/solana_svm/transaction_balances/struct.BalanceCollector.html"><code>BalanceCollector</code></a><code>&gt;</code> containing balances accumulated for <a target="_blank" href="https://docs.rs/solana-ledger/latest/solana_ledger/blockstore_processor/struct.TransactionStatusSender.html"><code>TransactionStatusSender</code></a> (a channel within the Solana ledger) when transaction balance recording is enabled.</p>
</li>
</ol>
<h2 id="heading-forkgraph-trait">ForkGraph Trait</h2>
<p>The struct <code>TransactionBatchProcessor</code> contains a generic <code>FG</code> which requires the passed type to implement the <a target="_blank" href="https://docs.rs/solana-program-runtime/2.3.7/solana_program_runtime/loaded_programs/trait.ForkGraph.html"><code>ForkGraph</code></a> trait. The trait maps the block’s relationship between two slots returning the <a target="_blank" href="https://docs.rs/solana-program-runtime/2.3.7/solana_program_runtime/loaded_programs/enum.BlockRelation.html">BlockRelation enum</a>.</p>
<pre><code class="lang-rust"><span class="hljs-comment">// Relationship between two fork IDs</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">enum</span> <span class="hljs-title">BlockRelation</span></span> {
    <span class="hljs-comment">// The slot is on the same fork and is an ancestor of the other slot</span>
    Ancestor,
    <span class="hljs-comment">// The two slots are equal and are on the same fork</span>
    Equal,
    <span class="hljs-comment">// The slot is on the same fork and is a descendant of the other slot</span>
    Descendant,
    <span class="hljs-comment">// The slots are on two different forks and may have had a common ancestor at some point</span>
    Unrelated,
    <span class="hljs-comment">// Either one or both of the slots are either older than the latest root, or are in future</span>
    Unknown,
}
</code></pre>
<p>The <code>ForkGraph</code> trait requires the <a target="_blank" href="https://docs.rs/solana-program-runtime/2.3.7/solana_program_runtime/loaded_programs/trait.ForkGraph.html#tymethod.relationship"><code>relationship(&amp;self, a: Slot, b: Slot)</code></a> method to be implemented for the generic type. This method requires the two slots arguments <code>a: Slot</code> and <code>b: Slot</code> to be compared in a manner that returns the relationship (<code>BlockRelation</code> enum) between them. The <code>Slot</code> is just a type alias for a Rust <code>u64</code> representing an <a target="_blank" href="https://solana.com/docs/references/terminology#entry">entry</a> that estimates wallclock duration (a <code>tick</code>) . An example of implementing this trait:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Add `solana-clock` dependency used in SVM ecosystem, it contains the `Slot` type</span>
cargo add solana-clock
</code></pre>
<pre><code class="lang-rust"><span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">SlotRelationships</span></span>;

<span class="hljs-keyword">impl</span> ForkGraph <span class="hljs-keyword">for</span> SlotRelationships {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">relationship</span></span>(&amp;<span class="hljs-keyword">self</span>, slot_a: Slot, slot_b: Slot) -&gt; BlockRelation {
        <span class="hljs-comment">// Since a `Slot` is just a Rust `u64`, and a `u64` implement</span>
        <span class="hljs-comment">// Rust `PartialCmp` and `Cmp`, we can use `.cmp()` method</span>
        <span class="hljs-comment">// on `slot_a` to compare against `slot_b` and derive a relationship</span>
        <span class="hljs-comment">// checking if `slot_a` is less than, equal to or greater than `slot_b`</span>
        <span class="hljs-keyword">match</span> slot_a.cmp(&amp;slot_b) {
            std::cmp::Ordering::Less =&gt; BlockRelation::Ancestor,
            std::cmp::Ordering::Equal =&gt; BlockRelation::Equal,
            std::cmp::Ordering::Greater =&gt; BlockRelation::Descendant,
        }
    }
}
</code></pre>
<p>The <code>TransactionBatchProcessor</code> has some more methods to configure of get information about the transaction execution pipeline that you can <a target="_blank" href="https://docs.rs/solana-svm/latest/solana_svm/transaction_processor/struct.TransactionBatchProcessor.html#method.reset_sysvar_cache">explore</a>.</p>
<p><a target="_blank" href="https://448.africa/svm-series-03-compute-budget-and-syscalls">&lt; Previous Article: SVM Series 03: Compute Budget &amp; Syscalls</a></p>
<h2 id="heading-resources">Resources</h2>
<ol>
<li><p>Understanding Slots, Blocks, and Epochs on Solana<br /> <a target="_blank" href="https://www.helius.dev/blog/solana-slots-blocks-and-epochs">https://www.helius.dev/blog/solana-slots-blocks-and-epochs</a></p>
</li>
<li><p>Solana SVM TransactionBatchProcessor module docs<br /> <a target="_blank" href="https://docs.rs/solana-svm/latest/solana_svm/transaction_processor/struct.TransactionBatchProcessor.html">https://docs.rs/solana-svm/latest/solana_svm/transaction_processor/struct.TransactionBatchProcessor.html</a></p>
</li>
</ol>
]]></content:encoded></item><item><title><![CDATA[SVM Series 03: Compute Budget & Syscalls]]></title><description><![CDATA[The SVM requires compute budget limits and syscalls that programs can call to perform certain tasks.
Compute Budget
What is the Compute Budget & Compute Budget Program?
The compute budget defines the maximum compute units (CU) a transaction can consu...]]></description><link>https://448.africa/svm-series-03-compute-budget-and-syscalls</link><guid isPermaLink="true">https://448.africa/svm-series-03-compute-budget-and-syscalls</guid><category><![CDATA[solana-virtual-machine]]></category><category><![CDATA[Solana]]></category><dc:creator><![CDATA[448-OG]]></dc:creator><pubDate>Thu, 07 Aug 2025 13:45:22 GMT</pubDate><content:encoded><![CDATA[<p>The SVM requires compute budget limits and syscalls that programs can call to perform certain tasks.</p>
<h2 id="heading-compute-budget">Compute Budget</h2>
<h3 id="heading-what-is-the-compute-budget-amp-compute-budget-program">What is the Compute Budget &amp; Compute Budget Program?</h3>
<p>The compute budget defines the maximum compute units (CU) a transaction can consume to prevent resource abuse on the Solana network. The default CUs are 200,000 with a maximum limit of 1.4 million CUs. During program execution, the SVM breaks the transaction logic into <a target="_blank" href="https://github.com/anza-xyz/sbpf/blob/main/doc/bytecode.md">opcodes</a> (BPF instructions) where the VM consumes 1 CU per opcode. Examples of operations that are converted to opcodes are program syscalls, signature verification, locking instructions during transaction sanitization, etc. The compute budget program <code>ComputeBudget111111111111111111111111111111</code> handles requesting more CUs for program execution if the default CUs are not enough.</p>
<h3 id="heading-to-use-the-compute-budget-in-the-svm-api">To use the Compute Budget in the SVM API</h3>
<pre><code class="lang-bash">cargo add solana-compute-budget
</code></pre>
<pre><code class="lang-rust"><span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
    <span class="hljs-comment">// Initialize `ComputeBudget` struct with default paramemters.</span>
    <span class="hljs-comment">// These parameters include:</span>
    <span class="hljs-comment">//    - compute unit limit (defaults to 1.4 million CUs)</span>
    <span class="hljs-comment">//    - Maximum nesting of instructions that can happen during a transaction (defaults to 5)</span>
    <span class="hljs-comment">//    - Maximum cross-program invocation and instructions per transaction (defaults to 64)</span>
    <span class="hljs-comment">//    - Maximum number of slices hashed per syscall (defaults to 20,000)</span>
    <span class="hljs-comment">//    - Maximum SBF to BPF call nesting that can happen within a program (defaults to 64 SBF to BPF to BPF calls)</span>
    <span class="hljs-comment">//    - Size of a stack frame in bytes matching the size specified in the LLVM SBF backend (defaults to 4096)</span>
    <span class="hljs-comment">//    - Maximum cross-program invocation instruction size (default to IPv6 Min MTU size of 1280)</span>
    <span class="hljs-comment">//    - Length of the heap memory region used for program heap </span>
    <span class="hljs-comment">//      (defaults to solana_program_entrypoint::HEAP_LENGTH of 32768 = 1024 * 32) </span>
    <span class="hljs-comment">//    - Loads the default execution costs defined by `solana_program_runtime::execution_budget::SVMTransactionExecutionCost` struct</span>
    <span class="hljs-comment">//      which is defines cost paramemters for operations like loggin, CPI, signature verification and more. </span>
    <span class="hljs-keyword">let</span> compute_budget_config = ComputeBudget::default();    
}
</code></pre>
<p>The <code>SVMTransactionExecutionCost</code> source code parameters are defined at <a target="_blank" href="https://github.com/anza-xyz/agave/blob/86bc9187b3d8988abfa52572c988a11ca7fcc931/program-runtime/src/execution_budget.rs#L90">Solana Program Runtime Modeule #L90</a>.</p>
<h2 id="heading-syscalls">Syscalls</h2>
<h3 id="heading-what-are-syscalls">What are syscalls?</h3>
<p>In SVM, a syscall (short for system call) is a low-level function provided by the Solana VM that programs can invoke to interact with the VM environment. Syscalls are predefined entrypoints into the runtime that ensure only specific actions are allowed during program execution. These operations that are not part of the program itself but are offered by the VM as trusted privileged operations. Examples of a syscall is verifying Ed25519 signatures or logging information.</p>
<h3 id="heading-configuration-parameters-used-in-syscalls-parameters">Configuration parameters used in syscalls parameters</h3>
<p>Defining syscalls in SVM requires some configuration provided by the <a target="_blank" href="https://docs.rs/solana-sbpf/latest/solana_sbpf/vm/struct.Config.html"><code>solana_sbpf::vm::Config</code></a>. This configures VM parameters like maximum call depth, stack frame size, copying read-only data, tracing instructions, which SBF versions are allowed and more.</p>
<p>The <a target="_blank" href="https://crates.io/crates/solana-sbpf">solana-sbpf</a> Rust crate is used to define syscalls and their configuration parameters. An example of this:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># add `solana-program` to your dependencies</span>
<span class="hljs-comment"># it contains `solana-sbpf` crate used to configure the VM</span>
cargo add solana-program-runtime 

cargo add solana-bpf-loader-program <span class="hljs-comment"># Contains the syscalls source code to configure the VM</span>
</code></pre>
<p>In the <code>src/main.rs</code> file part of the <code>Compute Budget</code> code above.</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> solana_program_runtime::{
    <span class="hljs-comment">// `InvokeContext` is used to configure the entire exeuction pipeline</span>
    invoke_context::InvokeContext,
    solana_sbpf::{
        program::BuiltinProgram,
        <span class="hljs-comment">// Rename from `Config` to `SbpfVmConfig` to avoid conflicts with other deps with structs called `Config`</span>
        vm::Config <span class="hljs-keyword">as</span> SbpfVmConfig,
    },
};

    <span class="hljs-comment">// ... previous code from above</span>

    <span class="hljs-comment">// Defining syscalls requires some configuration using `solana_sbpf::vm::Config`.</span>
    <span class="hljs-comment">// This configures maximum call depth, stack frame size, copying read only data, tracing instructions,</span>
    <span class="hljs-comment">// allowed SBF versions, sanitizing user provided values and many more</span>
    <span class="hljs-keyword">let</span> vm_config = SbpfVmConfig {
        <span class="hljs-comment">// configure maximum call depth using that of our compute budget `compute_budget_config`</span>
        max_call_depth: compute_budget_config.max_call_depth,
        <span class="hljs-comment">// configure stack frame size using that of our compute budget `compute_budget_config`</span>
        stack_frame_size: compute_budget_config.stack_frame_size,
        <span class="hljs-comment">// Enable instruction tracing</span>
        enable_instruction_tracing: <span class="hljs-literal">true</span>,
        <span class="hljs-comment">// enable symbol and section labels for BPF (disabled by default)</span>
        enable_symbol_and_section_labels: <span class="hljs-literal">true</span>,
        <span class="hljs-comment">// Reject ELF files containing issues that the verifier did not catch before (up to v0.2.21). Disabled by default</span>
        reject_broken_elfs: <span class="hljs-literal">true</span>,
        <span class="hljs-comment">// Avoid copying read only sections when possible. Enabled by default</span>
        optimize_rodata: <span class="hljs-literal">false</span>,
        <span class="hljs-comment">// Use all other default parameters</span>
        ..<span class="hljs-built_in">Default</span>::default()
    };
</code></pre>
<p>We can now specify the syscalls the compiled program can call during execution using <a target="_blank" href="https://docs.rs/solana-sbpf/latest/solana_sbpf/program/struct.BuiltinProgram.html#method.register_function"><code>solana_sbf::program::BuiltinProgram</code></a> Rust crate. The SVM configuration defined above as <code>vm_config</code> is used to configure the VM. The <code>BuiltinProgram</code> takes a generic parameter, in our case <a target="_blank" href="https://docs.rs/solana-program-runtime/latest/solana_program_runtime/invoke_context/struct.InvokeContext.html"><code>InvokeContext</code></a> which defines the main pipeline from runtime to program execution.</p>
<pre><code class="lang-rust">
    <span class="hljs-comment">// The SVM configuration `vm_config` defined above is used  to configure the VM.</span>
    <span class="hljs-comment">// The `BuiltinProgram` takes a generic parameter, in our case the generic parameter will be</span>
    <span class="hljs-comment">// `solana_program_runtime::invoke_context::InvokeContext`</span>
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> loader: BuiltinProgram&lt;InvokeContext&lt;<span class="hljs-symbol">'_</span>&gt;&gt; = BuiltinProgram::new_loader(vm_config);
</code></pre>
<p>To register a syscall we use the <code>register_function()</code> method on <code>BuiltinProgram&lt;InvokeContext&lt;'_&gt;&gt;</code>. This function expects the name of the syscall and the syscall itself defined in the <a target="_blank" href="https://docs.rs/solana-bpf-loader-program/latest/solana_bpf_loader_program/syscalls/struct.SyscallAbort.html#method.vm"><code>solana_bpf_loader_program::syscalls</code></a> module. For example the <a target="_blank" href="https://docs.rs/solana-msg/latest/solana_msg/macro.msg.html">msg!</a> macro used in Solana programs to log messages is dependent on the <code>sol_log()</code> function which calls the <code>sol_log_</code> syscall in the VM.</p>
<pre><code class="lang-rust"><span class="hljs-comment">// How the `msg!()` macro is defined in the source code</span>
<span class="hljs-meta">#[cfg(feature = <span class="hljs-meta-string">"std"</span>)]</span>
<span class="hljs-meta">#[macro_export]</span>
<span class="hljs-built_in">macro_rules!</span> msg {
    ($msg:expr) =&gt; {
        $crate::sol_log($msg)
    };

    <span class="hljs-comment">// The macro calls `sol_log()` function within the same crate and passes a message</span>
    <span class="hljs-comment">// formatted message using Rust `format!()` macro </span>
    ($($arg:tt)*) =&gt; ($crate::sol_log(&amp;<span class="hljs-built_in">format!</span>($($arg)*))); 
}

<span class="hljs-comment">// How the `sol_log()` function calls the sycall to show the formatted message</span>
<span class="hljs-comment">/// Print a string to the log.</span>
<span class="hljs-meta">#[inline]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">sol_log</span></span>(message: &amp;<span class="hljs-built_in">str</span>) {
    <span class="hljs-meta">#[cfg(target_os = <span class="hljs-meta-string">"solana"</span>)]</span> <span class="hljs-comment">// Only available on the SVM</span>
    <span class="hljs-keyword">unsafe</span> {
        <span class="hljs-comment">// syscall is defined as `sol_log_` in the VM</span>
        syscalls::sol_log_(message.as_ptr(), message.len() <span class="hljs-keyword">as</span> <span class="hljs-built_in">u64</span>);
    }

   <span class="hljs-comment">// ...</span>
}
</code></pre>
<p>We can define our own <code>sol_log_</code> syscall in the VM similar to the above <code>msg!()</code> implementation using the <code>loader</code> variable we defined earlier.</p>
<pre><code class="lang-rust"><span class="hljs-comment">// Import the `SyscallLog` from the `solana_bpf_loader_program::syscalls` module.</span>
<span class="hljs-keyword">use</span> solana_bpf_loader_program::syscalls::SyscallLog;

    loader
        <span class="hljs-comment">// call this method and pass in the syscall function name in our case `sol_log_` </span>
        <span class="hljs-comment">// and `SyscallLog::vm` which provides `vm()` method which is the VM interface that accepts parameters for execution.</span>
        .register_function(<span class="hljs-string">"sol_log_"</span>, SyscallLog::vm)
        .expect(<span class="hljs-string">"Registration of `sol_log_` syscall failed!"</span>); <span class="hljs-comment">//Handle the error</span>
</code></pre>
<p>These syscalls have a <code>vm()</code> method that provides the VM interface and a <code>rust()</code> method that provides a Rust interface.</p>
<p>We have learnt how to configure the VM and add syscalls. Explore the <a target="_blank" href="https://docs.rs/solana-bpf-loader-program/latest/solana_bpf_loader_program/syscalls/index.html"><code>syscalls</code></a> of the <a target="_blank" href="https://docs.rs/solana-bpf-loader-program"><code>solana-bpf-loader-program</code></a> Rust crate to learn other syscalls like <code>SyscallLogPubkey</code>, <code>SyscallGetClockSysvar</code> and many more.</p>
<p>The source code for this article can be found at - <a target="_blank" href="https://github.com/448-OG/SVM-Series/tree/master/syscalls">https://github.com/448-OG/SVM-Series/tree/master/syscalls</a></p>
<p><a target="_blank" href="https://448.africa/svm-series-02-svm-feature-activation-and-management">&lt; Previous Article: SVM Series 02: SVM Feature Activation &amp; Management</a></p>
<p><a target="_blank" href="https://448.africa/svm-series-04-transactionbatchprocessor">Next Article: SVM Series 04: TransactionBatchProcessor &gt;</a></p>
<h2 id="heading-resources">Resources</h2>
<ol>
<li><p>Cost model source code<br /> <a target="_blank" href="https://github.com/anza-xyz/agave/blob/d5a84daebd2a7225684aa3f722b330e9d5381e76/cost-model/src/transaction_cost.rs#L121">https://github.com/anza-xyz/agave/blob/d5a84daebd2a7225684aa3f722b330e9d5381e76/cost-model/src/transaction_cost.rs#L121</a></p>
</li>
<li><p>Compute budget source code<br /> <a target="_blank" href="https://github.com/anza-xyz/agave/blob/d5a84daebd2a7225684aa3f722b330e9d5381e76/compute-budget/src/compute_budget.rs#L22">https://github.com/anza-xyz/agave/blob/d5a84daebd2a7225684aa3f722b330e9d5381e76/compute-budget/src/compute_budget.rs#L22</a></p>
</li>
<li><p>Bytecode / ISA<br /> <a target="_blank" href="https://github.com/anza-xyz/sbpf/blob/main/doc/bytecode.md">https://github.com/anza-xyz/sbpf/blob/main/doc/bytecode.md</a></p>
</li>
<li><p>How does the Solana BPF_VM calculate how many Compute units a program consumes?<br /> <a target="_blank" href="https://solana.stackexchange.com/questions/15119/how-does-the-solana-bpf-vm-calculate-how-many-compute-units-a-program-consumes">https://solana.stackexchange.com/questions/15119/how-does-the-solana-bpf-vm-calculate-how-many-compute-units-a-program-consumes</a><br /> <a target="_blank" href="https://github.com/anza-xyz/agave/blob/d5a84daebd2a7225684aa3f722b330e9d5381e76/program-runtime/src/invoke_context.rs#L529">https://github.com/anza-xyz/agave/blob/d5a84daebd2a7225684aa3f722b330e9d5381e76/program-runtime/src/invoke_context.rs#L529</a><br /> <a target="_blank" href="https://github.com/solana-labs/rbpf/blob/4dc039f4ee7409838c7f230558aebf6869c32db9/src/program.rs#L331">https://github.com/solana-labs/rbpf/blob/4dc039f4ee7409838c7f230558aebf6869c32db9/src/program.rs#L331</a><br /> <a target="_blank" href="https://github.com/anza-xyz/agave/blob/d5a84daebd2a7225684aa3f722b330e9d5381e76/programs/bpf_loader/src/lib.rs#L1405">https://github.com/anza-xyz/agave/blob/d5a84daebd2a7225684aa3f722b330e9d5381e76/programs/bpf_loader/src/lib.rs#L1405</a><br /> <a target="_blank" href="https://github.com/solana-labs/rbpf/blob/4dc039f4ee7409838c7f230558aebf6869c32db9/src/vm.rs#L422">https://github.com/solana-labs/rbpf/blob/4dc039f4ee7409838c7f230558aebf6869c32db9/src/vm.rs#L422</a></p>
</li>
<li><p>BPF instructions all consume 1 CU in the interpreter (which must match the JIT results)<br /> <a target="_blank" href="https://github.com/solana-labs/rbpf/blob/f3758ecee89198433422f751beee7f0f52dbcd55/src/interpreter.rs#L162">https://github.com/solana-labs/rbpf/blob/f3758ecee89198433422f751beee7f0f52dbcd55/src/interpreter.rs#L162</a></p>
</li>
<li><p>Solana sycalls module<br /> <a target="_blank" href="https://docs.rs/solana-bpf-loader-program/latest/solana_bpf_loader_program/syscalls/index.html">https://docs.rs/solana-bpf-loader-program/latest/solana_bpf_loader_program/syscalls/index.html</a></p>
</li>
</ol>
]]></content:encoded></item><item><title><![CDATA[SVM Series 02: SVM Feature Activation & Management]]></title><description><![CDATA[What are features?
Feature activation refers to a community-governed process for enabling new non-controversial network primitives on the Solana network through validator voting based on stake weight. An example of this is SIMD 220 which improves val...]]></description><link>https://448.africa/svm-series-02-svm-feature-activation-and-management</link><guid isPermaLink="true">https://448.africa/svm-series-02-svm-feature-activation-and-management</guid><category><![CDATA[Solana]]></category><category><![CDATA[SVM]]></category><dc:creator><![CDATA[448-OG]]></dc:creator><pubDate>Wed, 06 Aug 2025 13:02:26 GMT</pubDate><content:encoded><![CDATA[<h2 id="heading-what-are-features">What are features?</h2>
<p>Feature activation refers to a community-governed process for enabling new non-controversial network primitives on the Solana network through validator voting based on <strong>stake weight</strong>. An example of this is <a target="_blank" href="https://github.com/solana-foundation/solana-improvement-documents/blob/main/proposals/0220-snapshots-use-accounts-lattice-hash.md">SIMD 220</a> which improves validator performance by using Accounts Lattice Hash for snapshots instead of the Merkle-based account hash.</p>
<p>SPL tokens that represent the total active stake on the network are minted and distributed to all validtors based on their stake. Validators then transfer their vote tokens to a certain predetermined address, in the case of SIMD 220 address <a target="_blank" href="https://explorer.solana.com/address/LTsNAP8h1voEVVToMNBNqoiNQex4aqfUrbFhRH3mSQ2">LTsNA...3mSQ2</a> on mainnet-beta. Once vote threshold is met the feature is activated at the beginning of a predetermined epoch. The built-in <code>Feature</code> program present in all validators is responsible for activating new features simultaneously to avoid hard forks that break consensus.</p>
<h2 id="heading-feature-proposal">Feature proposal</h2>
<p>A feature proposal is added to the code base using a <code>feature id</code>. Feature IDs can be accessed using the <a target="_blank" href="https://crates.io/crates/agave-feature-set">agave-feature-set</a> Rust crate. The feature ID is generated in the following steps:</p>
<ol>
<li><p>Create a Solana keypair for the proposal</p>
<pre><code class="lang-sh"> solana-keygen new --outfile &lt;feature-proposal-name&gt;.json --silent --no-passphrase
</code></pre>
</li>
<li><p>Install the (note you need <code>libudev</code> installed) and then run</p>
<pre><code class="lang-sh"> <span class="hljs-comment"># install spl-feature-proposal-cli</span>
 $ cargo install spl-feature-proposal-cli --git https://github.com/solana-program/feature-proposal.git

 <span class="hljs-comment"># Derive the feature ID</span>
 $ spl-feature-proposal address feature-proposal.json
</code></pre>
<p> Deriving the <code>feature ID</code> prints the details; example:</p>
<pre><code class="lang-sh"> Feature Id: AMJPdBjeCf1694FJcGsYNsGZaXogXuSVRVUVTAX28PEi
 Token Mint Address: 3vYBgFztMaEPByNsk8acEjfjLauswW46hm2ZuMkh3WFy
 Acceptance Token Address: EhfPUgpY4sKPqy8i488cXGxwKwMQ7YcMa5CMMHyzn6w9
</code></pre>
<p> where: <code>Feature Id:</code> is the identifier added to the code base for that feature and is also retrieved by <code>solana feature status</code> subcommand of the <code>solana</code> command line tool. Note that only the <code>feature proposal program</code> can activate this feature since there is no private key for the address identified by the <code>Feature id</code>.</p>
</li>
<li><p>Initializing the feature - This is only possible after the feature is deployed to a Solana cluster (devnet, testnet or mainnet-beta). Note that features are first deployed to <code>testnet</code> cluster. Running <code>solana feature status</code> should show this feature's ID.</p>
<pre><code class="lang-bash"> <span class="hljs-comment"># Example from Solana docs. Running this mints SPL tokens for the feature proposal and the </span>
 <span class="hljs-comment"># `feature proposer` is required to finance creating all the </span>
 <span class="hljs-comment"># SPL token accounts (about 0.00204 SOL per account) for all validators</span>
 $ spl-feature-proposal propose feature-proposal.
</code></pre>
<pre><code class="lang-bash"> <span class="hljs-comment"># The output of the above command example from Solana docs</span>
 Feature Id: HQ3baDfNU7WKCyWvtMYZmi51YPs7vhSiLn1ESYp3jhiA
 Token Mint Address: ALvA7Lv9jbo8JFhxqnRpjWWuR3aD12uCb5KBJst4uc3d 
 Distributor Token Address: GK55hNft4TGc3Hg4KzbjEmju8VfaNuXK8jQNDTZKcsNF 
 Acceptance Token Address: AdqKm3mSJf8AtTWjfpA5ZbJszWQPcwyLA2XkRyLbf3Di 
 Number of validators: 376 
 Tokens to be minted: 134575791.53064314 
 Tokens required <span class="hljs-keyword">for</span> acceptance: 90165780.3255309 (67%) 
 Token distribution file: feature-proposal.csv 
 JSON RPC URL: http://api.mainnet-beta.solana.com

 Distribute the proposal tokens to all validators by running: 
     $ solana-tokens distribute-spl-tokens --from GK55hNft4TGc3Hg4KzbjEmju8VfaNuXK8jQNDTZKcsNF --input-csv feature-proposal.csv --db-path db.8CyUVvio --fee-payer ~/.config/solana/id.json --owner &lt;FEATURE_PROPOSAL_KEYPAIR&gt; 
     $ solana-tokens spl-token-balances --mint ALvA7Lv9jbo8JFhxqnRpjWWuR3aD12uCb5KBJst4uc3d --input-csv feature-proposal.csv

 Once the distribution is complete, request validators vote <span class="hljs-keyword">for</span> the proposal. To vote, validators should first look up their token account address: 
     $ spl-token --owner ~/validator-keypair.json accounts ALvA7Lv9jbo8JFhxqnRpjWWuR3aD12uCb5KBJst4uc3d 
 and <span class="hljs-keyword">then</span> submit their vote by running: 
     $ spl-token --owner ~/validator-keypair.json transfer &lt;TOKEN_ACCOUNT_ADDRESS&gt; ALL AdqKm3mSJf8AtTWjfpA5ZbJszWQPcwyLA2XkRyLbf3Di

 Periodically the votes must be tallied by running: 
     $ spl-feature-proposal tally 8CyUVvio2oYAP28ZkMBPHq88ikhRgWet6i4NYsCW5Cxa
 Tallying is permissionless and may be run by anybody.
 Once this feature proposal is accepted, the HQ3baDfNU7WKCyWvtMYZmi51YPs7vhSiLn1ESYp3jhiA feature will be activated at the next epoch.

 Add --confirm flag to initiate the feature proposal
</code></pre>
</li>
<li><p>Tally the votes - anyone can tally the votes to enable the feature to be automatically activated at the start of the next epoch</p>
<pre><code class="lang-bash">  $ spl-feature-proposal tally
</code></pre>
</li>
</ol>
<h2 id="heading-using-features-in-svm-api">Using features in SVM API</h2>
<p>In this series we will use a mock <code>Bank</code> to coordinate the SVM execution pipeline. The <a target="_blank" href="https://crates.io/crates/agave-feature-set">agave-feature-set</a> Rust crate will be used to activate features for transaction processing.</p>
<h3 id="heading-featureset-struct">FeatureSet struct</h3>
<p>Feature set is defined by the struct <code>FeatureSet</code> which contains a list of activated features in the <code>active</code> field and deactivated features in the <code>inactive</code> field.</p>
<pre><code class="lang-rust"><span class="hljs-meta">#[derive(Debug, Clone, Eq, PartialEq)]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">FeatureSet</span></span> {
    active: AHashMap&lt;Pubkey, <span class="hljs-built_in">u64</span>&gt;,
    inactive: AHashSet&lt;Pubkey&gt;,
}
</code></pre>
<h3 id="heading-default-implementation-for-featureset-struct">Default implementation for FeatureSet struct</h3>
<p>Instantiating the <code>FeatureSet</code> struct using default method <code>FeatureSet::default()</code> makes all features inactive.</p>
<pre><code class="lang-rust">
<span class="hljs-comment">// Default implementation for `FeatureSet`</span>
<span class="hljs-keyword">impl</span> <span class="hljs-built_in">Default</span> <span class="hljs-keyword">for</span> FeatureSet {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">default</span></span>() -&gt; <span class="hljs-keyword">Self</span> {
        <span class="hljs-keyword">Self</span> {
            <span class="hljs-comment">// All features disabled</span>
            active: AHashMap::new(),
            inactive: AHashSet::from_iter((*FEATURE_NAMES).keys().cloned()),
        }
    }
}
</code></pre>
<p>The <code>*FEATURE_NAMES</code> is used to load all features since they are defined by <a target="_blank" href="https://docs.rs/agave-feature-set/latest/agave_feature_set/static.FEATURE_NAMES.html"><code>agave_feature_set::FEATURE_NAMES</code></a> constant which is a can be described as <code>HashMap&lt;Public Key of the feature, the description of the feature&gt;</code>.</p>
<p>Let’s explore this by creating a new Rust project and add the <code>agave-feature-set</code> crate</p>
<pre><code class="lang-bash">cargo new explore-feature-set
</code></pre>
<pre><code class="lang-bash"><span class="hljs-comment"># Add agave-feature-set to Cargo.toml</span>
cargo add agave-feature-set
</code></pre>
<h3 id="heading-looping-through-the-available-features-for-svm-api">Looping through the available features for SVM API</h3>
<p>In the <code>src/main.rs</code> folder loop through the feature names</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> agave_feature_set::FEATURE_NAMES;

<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
    <span class="hljs-comment">// Loop through the available features for the SVM version</span>
    <span class="hljs-keyword">for</span> (feature_name: &amp;solana_pubkey::Pubkey, feature_description: &amp;&amp;<span class="hljs-built_in">str</span>) <span class="hljs-keyword">in</span> FEATURE_NAMES.iter() {
        <span class="hljs-built_in">println!</span>(<span class="hljs-string">"{feature_name} - {feature_description"</span>,);
    }
}
</code></pre>
<h3 id="heading-instantiating-the-defaults-for-featureset">Instantiating the defaults for FeatureSet</h3>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> agave_feature_set::FeatureSet;

<span class="hljs-keyword">let</span> feature_set_api = FeatureSet::default();
</code></pre>
<h3 id="heading-methods-on-featureset">Methods on FeatureSet</h3>
<p><code>FeatureSet</code> methods on can activate or deactivate a feature by providing it’s public key. An example is activating <code>SIMD 256</code> which raises the block limit to <code>60M</code> . <code>agave-feature-set</code> crate provides constant modules that have a method <code>id()</code> which contains the <code>Public Key</code> for the feature activation. For SIMD 256, the module is <code>agave_feature_set::raise_block_limits_to_60m</code> .</p>
<p>The <code>activate()</code> method requires the <code>feature public key</code> and the <code>slot</code> that the feature will be activated.</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> agave_feature_set::FeatureSet;

<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> feature_manager = FeatureSet::default();

    <span class="hljs-comment">// Activate SIMD 256 from slot zero</span>
    feature_manager.activate(&amp;agave_feature_set::raise_block_limits_to_60m::id(), <span class="hljs-number">0</span>);

    <span class="hljs-comment">// To deactivate a feature, example  SIMD 256</span>
    feature_manager.deactivate(&amp;agave_feature_set::raise_block_limits_to_60m::id());

    <span class="hljs-comment">// Some more useful methods are</span>
    <span class="hljs-comment">//</span>

    <span class="hljs-comment">// To check whether a feature is active, example  SIMD 256</span>
    feature_manager.is_active(&amp;agave_feature_set::raise_block_limits_to_60m::id());

    <span class="hljs-comment">// To check the slot when a certain feature was activated, example  SIMD 256</span>
    feature_manager.activated_slot(&amp;agave_feature_set::raise_block_limits_to_60m::id());

    <span class="hljs-comment">// To get all active features</span>
    feature_manager.active();

    <span class="hljs-comment">// To get all inactive features</span>
    feature_manager.inactive();

    <span class="hljs-comment">// To get all enabled features that trigger full inflation</span>
    feature_manager.full_inflation_features_enabled();

    <span class="hljs-comment">// To instantiate a `FeatureSet` struct with all features enabled at once</span>
    <span class="hljs-keyword">let</span> feature_manager = FeatureSet::all_enabled();
}
</code></pre>
<p>These methods can be used to instantiate a <code>Bank</code> with the features required in your SVM application.</p>
<p>The source code for this article can be found at - <a target="_blank" href="https://github.com/448-OG/SVM-Series/tree/master/svm-featues">https://github.com/448-OG/SVM-Series/tree/master/svm-featues</a></p>
<p><a target="_blank" href="https://448.africa/svm-series">&lt; Previous Article - SVM Series 01: Introduction</a></p>
<p><a target="_blank" href="https://448.africa/svm-series-03-compute-budget-and-syscalls">Next Article - SVM Series 03: Compute Budget &amp; Syscalls &gt;</a></p>
<h2 id="heading-resources">Resources</h2>
<ol>
<li><p>Feature Proposal Program’s source code - <a target="_blank" href="https://github.com/solana-program/feature-proposal">https://github.com/solana-program/feature-proposal</a></p>
</li>
<li><p><code>solana-feature-gate-interface</code> - crate used within validator client to provide mechanism for features to be simultaneously activated across the network.<br /> <a target="_blank" href="https://crates.io/crates/solana-feature-gate-interface">https://crates.io/crates/solana-feature-gate-interface</a></p>
</li>
<li><p><code>solana feature activate</code> - subcommand part of the <code>solana</code> command line tool used to activate features. Run <code>solana feature --help</code> to show other arguments.</p>
</li>
</ol>
]]></content:encoded></item><item><title><![CDATA[SVM Series]]></title><description><![CDATA[Deep dive into Solana Virtual Machine (SVM). Some knowledge of Solana architecture like Ledger,Bank,AccountsDB and transactions is required to go through this series. An overview of the SVM API used in this series of articles can be found at Anza’s S...]]></description><link>https://448.africa/svm-series</link><guid isPermaLink="true">https://448.africa/svm-series</guid><category><![CDATA[Solana]]></category><category><![CDATA[solana blockchain development ]]></category><dc:creator><![CDATA[448-OG]]></dc:creator><pubDate>Wed, 06 Aug 2025 08:39:17 GMT</pubDate><content:encoded><![CDATA[<p>Deep dive into Solana Virtual Machine (SVM). Some knowledge of Solana architecture like <code>Ledger</code>,<code>Bank</code>,<code>AccountsDB</code> and transactions is required to go through this series. An overview of the SVM API used in this series of articles can be found at <a target="_blank" href="https://www.anza.xyz/blog/anzas-new-svm-api">Anza’s SVM API blog</a>.</p>
<h2 id="heading-articles-in-this-series">Articles in this series</h2>
<ol>
<li><p>Introduction to SVM, a summary of SVM API blog (this article)</p>
</li>
<li><p><a target="_blank" href="https://448.africa/svm-series-02-svm-feature-activation-and-management">SVM Series 02: SVM Feature Activation &amp; Management</a></p>
</li>
<li><p><a target="_blank" href="https://448.africa/svm-series-03-compute-budget-and-syscalls">SVM Series 03: Compute Budget &amp; Syscalls</a></p>
</li>
<li><p><a target="_blank" href="https://448.africa/svm-series-04-transactionbatchprocessor">SVM Series 04: TransactionBatchProcessor</a></p>
</li>
</ol>
<h2 id="heading-introduction-to-svm-a-summary-of-svm-api-blog">Introduction to SVM, a summary of SVM API blog</h2>
<p>The Solana Virtual Machine is the entire transaction processing pipeline from validator’s runtime to executing Solana eBPF programs.</p>
<p>The <code>Bank</code> (contained in the <code>Ledger</code>) coordinates the networks state during any given slot by processing transactions, packing them into a block. Validators replaying a block attempt to rebuild a matching instance of the <code>Bank</code>.</p>
<ul>
<li><p>Transactions are processed in batches</p>
</li>
<li><p>Each transactions contains one or multiple instructions</p>
</li>
<li><p>Each instruction contains information to load accounts and determine write locks</p>
</li>
<li><p>Read locks allow parallel data access across Bank instances</p>
</li>
<li><p>Transactions are <code>sanitized</code> before they are processed</p>
</li>
<li><p>De-duplication of account keys from a transaction’s instruction is done during sanitization</p>
</li>
<li><p>After accounts are loaded, SVM loads the executable program for each instruction and provisions an eBPF virtual machine to execute the program, returning that result</p>
</li>
<li><p>Caching is used to store the machine code from the translated program byte-code until recomputing the program byte-code is needed or when the cache is full</p>
</li>
</ul>
<p>All of these processes are coordinated by the Bank within the SVM.</p>
<h2 id="heading-agave-svm-api">Agave SVM API</h2>
<blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1754468536756/3bc1b8ab-6ac5-4586-931f-2579fba3df6a.jpeg" alt class="image--center mx-auto" /></p>
<p>Credit: Anza’s Blog</p>
</blockquote>
<p>The <a target="_blank" href="https://crates.io/crates/solana-svm">solana-svm</a> Rust crate is used to build SVM applications in a protocol compliant manner. The <a target="_blank" href="https://docs.rs/solana-svm/latest/solana_svm/transaction_processor/struct.TransactionBatchProcessor.html">TransactionBatchProcessor</a> struct is the central interface of SVM which processes batches of sanitized transactions using components in the transaction pipeline. During this series we will break down each components.</p>
<pre><code class="lang-rust"><span class="hljs-comment">// From the `solana-svm` crate.</span>
<span class="hljs-comment">// The method `load_and_execute_sanitized_transactions()` on this struct is used</span>
<span class="hljs-comment">// to process batched transactions.</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">TransactionBatchProcessor</span></span>&lt;FG: ForkGraph&gt; {
  <span class="hljs-comment">/// Bank slot (i.e. block)</span>
  slot: Slot,
  <span class="hljs-comment">/// Bank epoch</span>
  epoch: Epoch,
  <span class="hljs-comment">/// SysvarCache is a collection of system variables that are</span>
  <span class="hljs-comment">/// accessible from on chain programs. It is passed to SVM from</span>
  <span class="hljs-comment">/// client code (e.g. Bank) and forwarded to the MessageProcessor.</span>
  <span class="hljs-keyword">pub</span> sysvar_cache: RwLock&lt;SysvarCache&gt;,
  <span class="hljs-comment">/// Programs required for transaction batch processing</span>
  <span class="hljs-keyword">pub</span> program_cache: Arc&lt;RwLock&lt;ProgramCache&lt;FG&gt;&gt;&gt;,
  <span class="hljs-comment">/// Builtin program ids</span>
  <span class="hljs-keyword">pub</span> builtin_program_ids: RwLock&lt;HashSet&lt;Pubkey&gt;&gt;,
}
</code></pre>
<p>You can read an overview of this API on Anza’s blog - <a target="_blank" href="https://www.anza.xyz/blog/anzas-new-svm-api">https://www.anza.xyz/blog/anzas-new-svm-api</a></p>
<h2 id="heading-source-code">Source Code</h2>
<p>The source code for each article can be found at <a target="_blank" href="https://github.com/448-OG/SVM-Series/tree/syscalls">https://github.com/448-OG/SVM-Series/</a></p>
<p><a target="_blank" href="https://448.africa/svm-series-03-compute-budget-and-syscalls">Next Article: SVM Series 02: SVM Feature Activation &amp; Management &gt;</a></p>
]]></content:encoded></item><item><title><![CDATA[Token Accounts - Solana SPL Token]]></title><description><![CDATA[An account in Solana is an contiguous area of memory occupied by some bytes where these bytes represent state. In this article we will look at Token Accounts as specified in the Token Extensions (Token 2022).
Token accounts are used to store the info...]]></description><link>https://448.africa/token-accounts-solana-spl-token</link><guid isPermaLink="true">https://448.africa/token-accounts-solana-spl-token</guid><category><![CDATA[Solana Token Extensions]]></category><dc:creator><![CDATA[448-OG]]></dc:creator><pubDate>Thu, 18 Jul 2024 09:00:00 GMT</pubDate><content:encoded><![CDATA[<p>An account in Solana is an contiguous area of memory occupied by some bytes where these bytes represent state. In this article we will look at Token Accounts as specified in the Token Extensions <code>(Token 2022)</code>.</p>
<p>Token accounts are used to store the information about a token. It has the following 8 fields.</p>
<blockquote>
<ol>
<li><p><code>Mint Public Key</code> - This is the Public Key of the Mint associated with this account</p>
</li>
<li><p><code>Owner Public Key</code> - Represents the Public Key of the Owner of the account</p>
</li>
<li><p><code>Amount</code> - The amount of tokens</p>
</li>
<li><p><code>Optional Delegate Public Key</code> - If there is a Public Key authorized to manage a delegated amount</p>
</li>
<li><p><code>Account State</code> - Whether an account is not initialized, is initialized or if the account is frozen</p>
</li>
<li><p><code>Optional Is Native</code> - Shows the rent-exempt amount if this is a native token if the value is provided</p>
</li>
<li><p><code>Delegated Amount</code> - The amount the Delegate Public Key can manage</p>
</li>
<li><p><code>Optional Close Authority</code> - The public key of authorized to close the account if it is provided.</p>
</li>
</ol>
</blockquote>
<h4 id="heading-lets-write-some-rust-code-to-implement-the-structure-of-the-token-account-this-tutorial-assumes-you-have-installed-the-rust-stable-toolchain-version-gt-1780-at-time-of-writing-this">Let's write some Rust code to implement the structure of the token account. This tutorial assumes you have installed the Rust stable toolchain <code>(version &gt;= 1.78.0 at time of writing this)</code></h4>
<ul>
<li><p>Create a new rust <code>cargo project</code></p>
<pre><code class="lang-sh">  $ cargo new token-account-layout 

  <span class="hljs-comment"># Switch to the project directory</span>
  $ <span class="hljs-built_in">cd</span> token-account-layout
</code></pre>
</li>
<li><p>Inside the <code>Cargo.toml</code> file, we then import <code>rand</code> crate that will generate random 32 bytes to simulate a Public Key since onchain there is no random number generation capability.</p>
<pre><code class="lang-TOML">  <span class="hljs-section">[package]</span>
  <span class="hljs-attr">name</span> = <span class="hljs-string">"token-account-layout"</span>
  <span class="hljs-attr">version</span> = <span class="hljs-string">"0.1.0"</span>
  <span class="hljs-attr">edition</span> = <span class="hljs-string">"2021"</span>

  <span class="hljs-section">[dependencies]</span>
  <span class="hljs-attr">rand</span> = <span class="hljs-string">"0.8.5"</span> <span class="hljs-comment">#&lt;-- Add this dependency</span>
</code></pre>
</li>
</ul>
<p><strong>In the</strong> <a target="_blank" href="http://main.rs"><code>main.rs</code></a> file</p>
<p><strong><em>Note that Solana uses memory alignment to improve performance since modern CPUs perform better if they are reading or writing to aligned memory. You can do your own research about memory alignment.</em></strong></p>
<p>In an optional value of the Token Account, due to memory alignment Solana will represent the whether a field is optional using 4 bytes:</p>
<pre><code class="lang-plaintext">where:
    The value exists `Option::Some`  = [1u8, 0, 0, 0]
    The value doesn't exist `Option::None` = [0u8;4]
</code></pre>
<h4 id="heading-add-the-rust-code-to-represent-a-padded-optional-value">Add the rust code to represent a padded optional value.</h4>
<pre><code class="lang-rust"><span class="hljs-comment">/// If the value is Option::Some(value)</span>
<span class="hljs-keyword">const</span> OPTION_IS_SOME: [<span class="hljs-built_in">u8</span>; <span class="hljs-number">4</span>] = [<span class="hljs-number">1u8</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>];
</code></pre>
<h4 id="heading-the-account-size-is-of-165-bytes-in-length-define-this-constant-in-the-code">The Account Size is of <code>165 bytes</code> in length. Define this constant in the code</h4>
<pre><code class="lang-rust"><span class="hljs-comment">/// The length of the contiguous chunk of memory representing a token account.</span>
<span class="hljs-keyword">const</span> TOKEN_2022_ACCOUNT_LEN: <span class="hljs-built_in">usize</span> = <span class="hljs-number">165</span>;
</code></pre>
<h5 id="heading-an-image-representing-the-account-structure">An image representing the account structure</h5>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1723394679743/ea491885-6f2b-4bb7-890b-99b7577bbeb3.png" alt class="image--center mx-auto" /></p>
<p><code>Source: Solana Cookbook</code></p>
<h4 id="heading-each-byte-range-corresponds-to-a-particular-field-in-a-token-account-lets-define-these-ranges-as-constants">Each byte range corresponds to a particular field in a Token account. Let's define these ranges as constants</h4>
<pre><code class="lang-rust"><span class="hljs-comment">/// Import `RangeInclusive` from rust core library</span>
<span class="hljs-keyword">use</span> core::ops::RangeInclusive;

<span class="hljs-comment">/// Mint's Ed25519 Public key of 32 bytes in length</span>
<span class="hljs-keyword">const</span> MINT_ACC_RANGE: RangeInclusive&lt;<span class="hljs-built_in">usize</span>&gt; = <span class="hljs-number">0</span>..=<span class="hljs-number">31</span>;

<span class="hljs-comment">/// Owner's Ed25519 Public key of 32 bytes in length</span>
<span class="hljs-keyword">const</span> MINT_OWNER_RANGE: RangeInclusive&lt;<span class="hljs-built_in">usize</span>&gt; = <span class="hljs-number">32</span>..=<span class="hljs-number">63</span>;

<span class="hljs-comment">/// Eight bytes that hold an amount of type u64</span>
<span class="hljs-keyword">const</span> AMOUNT_RANGE: RangeInclusive&lt;<span class="hljs-built_in">usize</span>&gt; = <span class="hljs-number">64</span>..=<span class="hljs-number">71</span>;

<span class="hljs-comment">/// 4 bytes of a Option + Ed25519 Public key of 32 bytes in length</span>
<span class="hljs-keyword">const</span> DELEGATE_RANGE: RangeInclusive&lt;<span class="hljs-built_in">usize</span>&gt; = <span class="hljs-number">72</span>..=<span class="hljs-number">107</span>;

<span class="hljs-comment">/// One byte representing the Account state</span>
<span class="hljs-keyword">const</span> STATE_RANGE: <span class="hljs-built_in">usize</span> = <span class="hljs-number">108</span>;

<span class="hljs-comment">/// 4 Bytes Option + 8 bytes amount of type u64</span>
<span class="hljs-comment">/// representing current amount of rent exempt</span>
<span class="hljs-comment">// amount of a native token</span>
<span class="hljs-keyword">const</span> IS_NATIVE_RANGE: RangeInclusive&lt;<span class="hljs-built_in">usize</span>&gt; = <span class="hljs-number">109</span>..=<span class="hljs-number">120</span>;

<span class="hljs-comment">/// 8 bytes of an amount of type u64 the delegate</span>
<span class="hljs-comment">/// can manage</span>
<span class="hljs-keyword">const</span> DELEGATED_AMOUNT_RANGE: RangeInclusive&lt;<span class="hljs-built_in">usize</span>&gt; = <span class="hljs-number">121</span>..=<span class="hljs-number">128</span>;

<span class="hljs-comment">/// 4 bytes of a Option Type representation + Ed25519 Public key of 32 bytes in length</span>
<span class="hljs-keyword">const</span> CLOSE_AUTHORITY_RANGE: RangeInclusive&lt;<span class="hljs-built_in">usize</span>&gt; = <span class="hljs-number">129</span>..=<span class="hljs-number">164</span>;
</code></pre>
<h4 id="heading-next-we-define-a-struct-to-hold-the-ed25519-public-key-not-that-solana-public-keys-can-be-on-the-ed25519-curve-or-off-the-curve">Next, we define a struct to hold the Ed25519 public key (not that Solana public keys can be on the Ed25519 curve or off the curve)</h4>
<pre><code class="lang-rust"><span class="hljs-comment">/// Derive `Clone`, `Copy` to allow copying and cloning the Struct.</span>
<span class="hljs-comment">/// Derive `Default` to allow definition of a zero filled 32byte array.</span>
<span class="hljs-comment">/// Derive `PartialEq` to allow comparing of two structs</span>
<span class="hljs-meta">#[derive(Clone, Copy, Debug, Default, PartialEq)]</span>
<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Ed25519PublicKey</span></span>([<span class="hljs-built_in">u8</span>; <span class="hljs-number">32</span>]);

<span class="hljs-keyword">impl</span> Ed25519PublicKey {
    <span class="hljs-comment">// generate 32 bytes random numbers</span>
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">new_random</span></span>() -&gt; <span class="hljs-keyword">Self</span> {
        <span class="hljs-keyword">use</span> rand::{thread_rng, Rng};

        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> buffer = [<span class="hljs-number">0u8</span>; <span class="hljs-number">32</span>];
        thread_rng().fill(&amp;<span class="hljs-keyword">mut</span> buffer[..]);

        <span class="hljs-keyword">Self</span>(buffer)
    }

    <span class="hljs-comment">/// Convert to 32 bytes</span>
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">to_bytes</span></span>(&amp;<span class="hljs-keyword">self</span>) -&gt; [<span class="hljs-built_in">u8</span>; <span class="hljs-number">32</span>] {
        <span class="hljs-keyword">self</span>.<span class="hljs-number">0</span>
    }
}

<span class="hljs-keyword">impl</span> <span class="hljs-built_in">From</span>&lt;&amp;[<span class="hljs-built_in">u8</span>]&gt; <span class="hljs-keyword">for</span> Ed25519PublicKey {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">from</span></span>(bytes: &amp;[<span class="hljs-built_in">u8</span>]) -&gt; <span class="hljs-keyword">Self</span> {
        <span class="hljs-keyword">let</span> valid_bytes: [<span class="hljs-built_in">u8</span>; <span class="hljs-number">32</span>] = bytes
            .try_into()
            .expect(<span class="hljs-string">"Invalid slice length for Ed25519 public key. 32 bytes are required"</span>);

        <span class="hljs-keyword">Self</span>(valid_bytes)
    }
}
</code></pre>
<h4 id="heading-in-solana-a-token-account-state-can-be-uninitialized-initialized-or-frozen">In Solana, a token account state can be <code>Uninitialized</code>, <code>Initialized</code> or <code>Frozen</code>.</h4>
<pre><code class="lang-rust"><span class="hljs-comment">/// The state of a token account</span>
<span class="hljs-meta">#[derive(Clone, Copy, Debug, Default, PartialEq)]</span>
<span class="hljs-class"><span class="hljs-keyword">enum</span> <span class="hljs-title">Token2022AccountState</span></span> {
    <span class="hljs-comment">/// not yet initialized</span>
    <span class="hljs-meta">#[default]</span>
    Uninitialized = <span class="hljs-number">0</span>,
    <span class="hljs-comment">/// is initialized allowing actions by the owner or delegate</span>
    Initialized = <span class="hljs-number">1</span>,
    <span class="hljs-comment">/// Account is frozen by the mint freeze authority preventing</span>
    <span class="hljs-comment">/// Any actions from the account owner or delegate</span>
    Frozen = <span class="hljs-number">2</span>,
}

<span class="hljs-comment">/// The `Token2022AccountState` is converted to</span>
<span class="hljs-comment">/// a byte representation by the numbers described</span>
<span class="hljs-comment">/// in its fields, like `Uninitialized = 0` </span>
<span class="hljs-comment">/// using `Token2022AccountState::Uninitialized as u8`</span>
<span class="hljs-comment">/// converts that field to `0`</span>
<span class="hljs-keyword">impl</span> <span class="hljs-built_in">From</span>&lt;<span class="hljs-built_in">u8</span>&gt; <span class="hljs-keyword">for</span> Token2022AccountState {
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">from</span></span>(value: <span class="hljs-built_in">u8</span>) -&gt; <span class="hljs-keyword">Self</span> {
        <span class="hljs-keyword">match</span> value {
            <span class="hljs-number">0</span> =&gt; Self::Uninitialized,
            <span class="hljs-number">1</span> =&gt; Self::Initialized,
            <span class="hljs-number">2</span> =&gt; Self::Frozen,
            _ =&gt; <span class="hljs-built_in">panic!</span>(<span class="hljs-string">"The byte value passed is not supported"</span>),
        }
    }
}
</code></pre>
<h4 id="heading-construct-the-token-account-struct">Construct the Token Account struct</h4>
<pre><code class="lang-rust">
<span class="hljs-meta">#[derive(Clone, Copy, Debug, Default, PartialEq)]</span>
<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Token2022Account</span></span> {
    <span class="hljs-comment">/// The mint associated with this account</span>
    mint: Ed25519PublicKey,
    <span class="hljs-comment">/// The owner of this account.</span>
    owner: Ed25519PublicKey,
    <span class="hljs-comment">/// The amount of tokens this account holds.</span>
    amount: <span class="hljs-built_in">u64</span>,
    <span class="hljs-comment">/// If `delegate` is `Some` then `delegated_amount` represents</span>
    <span class="hljs-comment">/// the amount authorized by the delegate</span>
    delegate: <span class="hljs-built_in">Option</span>&lt;Ed25519PublicKey&gt;,
    <span class="hljs-comment">/// The account's state</span>
    state: Token2022AccountState,
    <span class="hljs-comment">/// If is_some, this is a native token, and the value logs the rent-exempt reserve. An Account</span>
    <span class="hljs-comment">/// is required to be rent-exempt, so the value is used by the Processor to ensure that wrapped</span>
    <span class="hljs-comment">/// SOL accounts do not drop below this threshold.</span>
    is_native: <span class="hljs-built_in">Option</span>&lt;<span class="hljs-built_in">u64</span>&gt;,
    <span class="hljs-comment">/// The amount delegated</span>
    delegated_amount: <span class="hljs-built_in">u64</span>,
    <span class="hljs-comment">/// Optional authority to close the account.</span>
    close_authority: <span class="hljs-built_in">Option</span>&lt;Ed25519PublicKey&gt;,
}
</code></pre>
<h4 id="heading-create-helper-methods-to-reuse-code">Create helper methods to reuse code</h4>
<pre><code class="lang-rust"><span class="hljs-keyword">impl</span> Token2022Account {
    <span class="hljs-comment">/// Converts bytes to an amount</span>
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">to_amount</span></span>(bytes: &amp;[<span class="hljs-built_in">u8</span>]) -&gt; <span class="hljs-built_in">u64</span> {
        <span class="hljs-comment">// Little-endian is used</span>
        <span class="hljs-built_in">u64</span>::from_le_bytes(
            bytes
                .try_into()
                .expect(<span class="hljs-string">"Invalid slice length for amount. 8 bytes are required"</span>),
        )
    }

    <span class="hljs-comment">/// Converts the bytes of an optional public key to Option&lt;Ed25519PublicKey&gt;</span>
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">to_optional_pubkey</span></span>(bytes: &amp;[<span class="hljs-built_in">u8</span>]) -&gt; <span class="hljs-built_in">Option</span>&lt;Ed25519PublicKey&gt; {
        <span class="hljs-comment">// if the first byte is zero then the public key is None</span>
        <span class="hljs-keyword">if</span> bytes[<span class="hljs-number">0</span>] == <span class="hljs-number">0</span> {
            <span class="hljs-built_in">Option</span>::<span class="hljs-literal">None</span>
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-comment">// Skip the first 4 bytes.</span>
            <span class="hljs-comment">// Since we implemented `From&lt;[u8]&gt; for Ed25519PublicKey`</span>
            <span class="hljs-comment">// using the `into()` method here auto-converts the bytes to</span>
            <span class="hljs-comment">// Ed25519PublicKey </span>
            <span class="hljs-built_in">Option</span>::<span class="hljs-literal">Some</span>(bytes[<span class="hljs-number">4</span>..].into())
        }
    }

    <span class="hljs-comment">/// Converts an optional amount to a `Option&lt;u64&gt;`</span>
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">to_optional_amount</span></span>(bytes: &amp;[<span class="hljs-built_in">u8</span>]) -&gt; <span class="hljs-built_in">Option</span>&lt;<span class="hljs-built_in">u64</span>&gt; {
        <span class="hljs-comment">// if the first byte is 0 then the value is None</span>
        <span class="hljs-keyword">if</span> bytes[<span class="hljs-number">0</span>] == <span class="hljs-number">0</span> {
            <span class="hljs-built_in">Option</span>::<span class="hljs-literal">None</span>
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-comment">// skip the first 4 bytes</span>
            <span class="hljs-built_in">Option</span>::<span class="hljs-literal">Some</span>(Self::to_amount(&amp;bytes[<span class="hljs-number">4</span>..]))
        }
    }
}
</code></pre>
<h4 id="heading-with-the-impl-we-create-methods-to-pack-self-and-unpack-bytes-to-self">With the <code>impl</code> we create methods to pack <code>Self</code> and unpack bytes to <code>Self</code></h4>
<pre><code class="lang-rust"><span class="hljs-keyword">impl</span> {
    <span class="hljs-comment">// ... previous code here</span>

    <span class="hljs-comment">/// An optional public key consists of 36 bytes where</span>
    <span class="hljs-comment">/// 32 bytes public key and a byte representing whether</span>
    <span class="hljs-comment">/// it is Option::Some which is represented by `1` or</span>
    <span class="hljs-comment">/// if it is Option::None which is represented by `0`.</span>
    <span class="hljs-comment">/// However due to memory alignment, 3 bytes padding is added </span>
    <span class="hljs-comment">/// (1 byte optional representation + 3 bytes padding)</span>
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">pack_optional_pubkey</span></span>(option_pubkey: <span class="hljs-built_in">Option</span>&lt;&amp;Ed25519PublicKey&gt;) -&gt; [<span class="hljs-built_in">u8</span>; <span class="hljs-number">36</span>] {
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> buffer = [<span class="hljs-number">0u8</span>; <span class="hljs-number">36</span>];

        <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> <span class="hljs-literal">Some</span>(pubkey) = option_pubkey {
            <span class="hljs-comment">// The byte range of the Option representation with 3 bytes padding</span>
            buffer[<span class="hljs-number">0</span>..=<span class="hljs-number">3</span>].copy_from_slice(&amp;OPTION_IS_SOME);
            <span class="hljs-comment">// Add the 32 bytes for the public key after the padding</span>
            buffer[<span class="hljs-number">4</span>..=<span class="hljs-number">35</span>].copy_from_slice(&amp;pubkey.to_bytes());
        }

        buffer
    }


    <span class="hljs-comment">/// Pack the Token2022Account struct (Self)</span>
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">pack</span></span>(&amp;<span class="hljs-keyword">self</span>) -&gt; [<span class="hljs-built_in">u8</span>; <span class="hljs-number">165</span>] {
        <span class="hljs-comment">// Initialize an empty buffer with 165 bytes of zeroes</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> buffer = [<span class="hljs-number">0u8</span>; TOKEN_2022_ACCOUNT_LEN];

        <span class="hljs-comment">// The range within the buffer for the `mint public key`</span>
        buffer[MINT_ACC_RANGE].copy_from_slice(&amp;<span class="hljs-keyword">self</span>.mint.to_bytes());

        <span class="hljs-comment">// The range within the buffer for the `owner public key`</span>
        buffer[MINT_OWNER_RANGE].copy_from_slice(&amp;<span class="hljs-keyword">self</span>.owner.to_bytes());

        <span class="hljs-comment">// The range within the buffer for the `8 bytes amount`</span>
        buffer[AMOUNT_RANGE].copy_from_slice(&amp;<span class="hljs-keyword">self</span>.amount.to_le_bytes());

        <span class="hljs-comment">// The range within the buffer for the `optional delegate public key`</span>
        buffer[DELEGATE_RANGE].copy_from_slice(&amp;Self::pack_optional_pubkey(<span class="hljs-keyword">self</span>.delegate.as_ref()));

        <span class="hljs-comment">// The range within the buffer for the `token account state`</span>
        buffer[STATE_RANGE] = <span class="hljs-keyword">self</span>.state <span class="hljs-keyword">as</span> <span class="hljs-built_in">u8</span>;

        <span class="hljs-comment">// The range within the buffer for the `is_native optional amount`</span>
        <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> <span class="hljs-literal">Some</span>(amount) = <span class="hljs-keyword">self</span>.is_native.as_ref() {
            <span class="hljs-comment">// Define a buffer with 1 byte Option representation</span>
            <span class="hljs-comment">// 3 bytes padding for the Option representation</span>
            <span class="hljs-comment">// and 8 bytes amount</span>
            <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> inner_buffer = [<span class="hljs-number">0u8</span>; <span class="hljs-number">12</span>];
            <span class="hljs-comment">// Load the optional bytes with the amount</span>
            inner_buffer[<span class="hljs-number">0</span>..=<span class="hljs-number">3</span>].clone_from_slice(&amp;OPTION_IS_SOME);
            <span class="hljs-comment">// Add the 8 bytes amount</span>
            inner_buffer[<span class="hljs-number">4</span>..].copy_from_slice(&amp;amount.to_le_bytes());
            <span class="hljs-comment">// Copy this buffer into the buffer for the packed amount</span>
            <span class="hljs-comment">// within the range</span>
            buffer[IS_NATIVE_RANGE].copy_from_slice(&amp;inner_buffer)
        }

        <span class="hljs-comment">// The range within the buffer for the `8 bytes delegate amount`</span>
        <span class="hljs-comment">// which the delegate authority can manage</span>
        buffer[DELEGATED_AMOUNT_RANGE].copy_from_slice(&amp;<span class="hljs-keyword">self</span>.delegated_amount.to_le_bytes());

        <span class="hljs-comment">// The range within the buffer for the `optional close authority public key`</span>
        buffer[CLOSE_AUTHORITY_RANGE]
            .copy_from_slice(&amp;Self::pack_optional_pubkey(<span class="hljs-keyword">self</span>.close_authority.as_ref()));

        buffer
    }

    <span class="hljs-comment">/// Code to unpack 165  bytes to `Token2022Account`</span>
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">unpack_account_data</span></span>(packed: [<span class="hljs-built_in">u8</span>; TOKEN_2022_ACCOUNT_LEN]) -&gt; <span class="hljs-keyword">Self</span> {
        <span class="hljs-comment">// Since we derived default for `Token2022Account` we can then</span>
        <span class="hljs-comment">// we instantiate a `Token2022Account` with default values</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> account = Token2022Account::default();

        <span class="hljs-comment">// Since `From&lt;u8&gt; for Ed25519PublicKey` is implemented,</span>
        <span class="hljs-comment">// use `.into()` method to auto-convert the byte range to an Ed25519PublicKey</span>
        account.mint = packed[MINT_ACC_RANGE].into();

        <span class="hljs-comment">// Same as above</span>
        account.owner = packed[MINT_OWNER_RANGE].into();

        <span class="hljs-comment">// Parse a byte slice to u64</span>
        account.amount = Self::to_amount(&amp;packed[AMOUNT_RANGE]);

        <span class="hljs-comment">// Parse a byte slice to an optional public key</span>
        account.delegate = Self::to_optional_pubkey(&amp;packed[DELEGATE_RANGE]);

        <span class="hljs-comment">// Parse a byte into the `AccountState` using `.into()` method</span>
        <span class="hljs-comment">// since `From&lt;u8&gt;` is implemented for `Token2022AccountState`</span>
        account.state = packed[STATE_RANGE].into();

        <span class="hljs-comment">// Parse a byte slice to an optional u64 amount</span>
        account.is_native = Self::to_optional_amount(&amp;packed[IS_NATIVE_RANGE]);

        <span class="hljs-comment">// Parse a byte slice into optional u64 amount</span>
        account.delegated_amount = Self::to_amount(&amp;packed[DELEGATED_AMOUNT_RANGE]);

        <span class="hljs-comment">// Parse a byte slice inot an optional public key</span>
        account.close_authority = Self::to_optional_pubkey(&amp;packed[CLOSE_AUTHORITY_RANGE]);

        account
    }
}
</code></pre>
<h4 id="heading-lastly-test-the-code-by-comparing-the-packed-bytes-to-the-original">Lastly test the code by comparing the packed bytes to the original.</h4>
<pre><code class="lang-rust"><span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
    <span class="hljs-keyword">let</span> account = Token2022Account {
        mint: Ed25519PublicKey::new_random(),
        owner: Ed25519PublicKey::new_random(),
        amount: <span class="hljs-number">4</span>,
        delegate: <span class="hljs-built_in">Option</span>::<span class="hljs-literal">Some</span>(Ed25519PublicKey::new_random()),
        state: Token2022AccountState::Frozen,
        <span class="hljs-comment">// If is_some, this is a native token, and the value logs the rent-exempt reserve. An Account</span>
        <span class="hljs-comment">// is required to be rent-exempt, so the value is used by the Processor to ensure that wrapped</span>
        <span class="hljs-comment">// SOL accounts do not drop below this threshold.</span>
        is_native: <span class="hljs-built_in">Option</span>::<span class="hljs-literal">Some</span>(<span class="hljs-number">2</span>),
        delegated_amount: <span class="hljs-number">1</span>,
        close_authority: <span class="hljs-built_in">Option</span>::<span class="hljs-literal">Some</span>(Ed25519PublicKey::new_random()),
    };

    <span class="hljs-keyword">let</span> packed = account.pack();
    <span class="hljs-keyword">let</span> unpacked = Token2022Account::unpack_account_data(packed);
    <span class="hljs-built_in">assert_eq!</span>(&amp;account, &amp;unpacked);
}
</code></pre>
<p>That's it! A custom implementation of packing and unpacking a Token Account based on Solana's memory layout.</p>
<blockquote>
<p>CAUTION: This code is not production grade or optimized, it is meant to illustrate the byte ranges of a region of memory containing a Solana Token Account</p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[Blinded Diffie–Hellman–Merkle for Ecash Mints]]></title><description><![CDATA[The source code — https://github.com/448-OG/Blinded-Diffie-Hellman-merkle/blob/master/src/main.rs

In 1982 David Chaum conceived the idea of anonymous cryptographic electronic cash using cryptographic proofs to mint electronic and melt electronic tok...]]></description><link>https://448.africa/blinded-diffiehellmanmerkle-for-ecash-mints</link><guid isPermaLink="true">https://448.africa/blinded-diffiehellmanmerkle-for-ecash-mints</guid><category><![CDATA[ecash]]></category><category><![CDATA[blinded-diffie-hellman]]></category><category><![CDATA[Bitcoin]]></category><dc:creator><![CDATA[448-OG]]></dc:creator><pubDate>Mon, 13 May 2024 09:00:00 GMT</pubDate><content:encoded><![CDATA[<blockquote>
<p>The source code — <a target="_blank" href="https://github.com/448-OG/Blinded-Diffie-Hellman-merkle/blob/master/src/main.rs">https://github.com/448-OG/Blinded-Diffie-Hellman-merkle/blob/master/src/main.rs</a></p>
</blockquote>
<p>In 1982 David Chaum conceived the idea of anonymous cryptographic electronic cash using cryptographic proofs to mint electronic and melt electronic tokens.</p>
<p>The security proofs were guaranteed using blinded digital signature schemes that provided unlinkability between withdrawal and spending transactions. The concept of blind signatures can be explained by a scenario where a provider wants an entity to commit to a certain proof even though that entity does not know the proof. The provider can then reveal the proof later or send it to another provider who can reveal the proof to the entity.</p>
<p>Ecash has gained popularity in Bitcoin in projects like Cashu and Fedimint due to their anonymity and scalability properties.</p>
<p>In this article we will look at how to construct a simple Ecash token using Blinded Diffie–Hellman–Merkle key exchange.</p>
<p>Diffie–Hellman–Merkle key is a protocol for exchanging secrets between parties over a public channel where at least one of the party’s public keys is known.</p>
<p><img src="https://upload.wikimedia.org/wikipedia/commons/c/c8/DiffieHellman.png" alt="Diffie-Hellman-Key-Exchange" /></p>
<h3 id="heading-our-algorithm-for-blinded-diffie-hellman-merkle-key-exchange-with-comprise-of">Our algorithm for Blinded Diffie-Hellman-Merkle key exchange with comprise of:</h3>
<ol>
<li><p>a secret key and a public key for the mint</p>
</li>
<li><p>a secret key for the provider</p>
</li>
<li><p>a nonce generated by the provider</p>
</li>
<li><p>an algorithm to transform our secret into a point on an elliptic curve (blinding factor)</p>
</li>
<li><p>an algorithm to blind the provider secret (blinded message)</p>
</li>
<li><p>an algorithm to generate a blinded signature from the blinded message</p>
</li>
<li><p>an algorithm to unblind the token from the blinded signature</p>
</li>
</ol>
<h3 id="heading-the-steps-to-generate-the-token-are">The steps to generate the token are:</h3>
<p><strong><em>Where we assume:</em></strong></p>
<blockquote>
<ul>
<li><p>Bob is the Mint</p>
</li>
<li><p>Alice is the Provider</p>
</li>
<li><p>Eve is another Provider that can redeem the tokens generated by Alice by sending the tokens to Bob</p>
</li>
<li><p>Generator represented by G is a known point on the elliptic curve, in our case the Ristretto Point on Curve25519 algorithm</p>
</li>
<li><p>hash_to_curve() is an algorithm that takes a 32 byte secret, hashes it with a cryptographically secure hashing algorithm like SHA256 and computes a point on the elliptic curve using the result of the hashed bytes. The hashing algorithm blinds the secret because one cannot guess the secret from the hash.This is known as preimage resistance.</p>
</li>
</ul>
</blockquote>
<ol>
<li><p>Bob generates a secret key <code>k</code> from some 32 random bytes and then multiplies that by a generator <code>G</code> to generate a public key <code>K</code> and let’s all providers know <code>K</code></p>
<blockquote>
<p>K = k * G</p>
</blockquote>
</li>
<li><p>Alice generates a <code>secret key</code> yielding 32 bytes</p>
</li>
<li><p>Alice generates a <code>random nonce</code> as the <code>blinding_factor</code></p>
</li>
<li><p>Alice generates a point on the elliptic curve by running the hash to curve algorithm with her the secret key</p>
<blockquote>
<p>hash_to_curve_result = hash_to_curve(sha512_hash(secret))</p>
</blockquote>
</li>
<li><p>Alice then computes a <code>blinded_message</code> by multiplying the <code>blinding_factor</code> by <code>G</code> and then adding it to the <code>elliptic curve point of the hashed secret hash_to_curve</code></p>
<blockquote>
<p>blinded_message = hash_to_curve_result + blinding_factor * G</p>
</blockquote>
</li>
<li><p>Alice then sends the <code>blinded_message</code> to Bob</p>
</li>
<li><p>Bob who computes the <code>blinded_signature</code> by multiplying the blinded message with his secret <code>k</code></p>
<blockquote>
<p>blinded_signature = blinded_message * k</p>
</blockquote>
</li>
<li><p>Bob then responds to Alice with the <code>blinded_signature</code></p>
</li>
<li><p>Alice computes the <code>unblinded_secret</code> by multiplying the blinding_factor with Bob’s <code>K</code> (public key) and the subtracting this from the <code>blinded_signature</code></p>
<blockquote>
<p>token = blinded_signature — binding_factor * K</p>
</blockquote>
</li>
<li><p>Alice can now share her secret <code>s</code> and token secret with Carol</p>
</li>
<li><p>Carol can redeem the token by sending the secret <code>s</code> and <code>token</code> to Bob</p>
</li>
<li><p>Bob verifies that the token is authentic by running the <code>hash_to_curve()</code> algorithm with the secret key generated by Alice and passed to Carol</p>
<blockquote>
<p>hash_to_curve_result = hash_to_curve(sha512_hash(secret))</p>
</blockquote>
</li>
<li><p>Bob then multiplies the <code>hash_to_curve</code> with his own secret key <code>k</code></p>
<blockquote>
<p>hash_to_curve_result * k</p>
</blockquote>
</li>
<li><p>Bob then compares the result of the previous step with the token and rejects the token if the result of the comparison is false</p>
<blockquote>
<p>assert( (hash_to_curve_result * k) == token )</p>
</blockquote>
</li>
</ol>
<p>Let’s implement these steps using the Rust programming language. We assume you have already installed Rust programming language toolchain and its cargo project manager.</p>
<p>Using the commandline create a new Rust project using cargo and switch to that directory</p>
<pre><code class="lang-sh">$ cargo new Blinded-Diffie-Hellman-Merkle --name blinded-dhm <span class="hljs-comment">#Create a new project</span>

$ <span class="hljs-built_in">cd</span> Blinded-Diffie-Hellman-Merkle <span class="hljs-comment"># Switch to the directory</span>
</code></pre>
<p>Inside the <code>Cargo.toml</code> add the dependencies for cryptographically secure random number generation (rand) , elliptic curves) and hashing (sha2)</p>
<pre><code class="lang-TOML"><span class="hljs-section">[dependencies]</span>
<span class="hljs-attr">curve25519-dalek</span> = { version = <span class="hljs-string">"4.1.2"</span>, features = [
    <span class="hljs-string">"rand_core"</span>,
    <span class="hljs-string">"digest"</span>,
    <span class="hljs-string">"precomputed-tables"</span>,
] }
<span class="hljs-attr">rand</span> = <span class="hljs-string">"0.8.5"</span>
<span class="hljs-attr">sha2</span> = <span class="hljs-string">"0.10.8"</span>
</code></pre>
<p>In curve25519-dalek - the feature rand_core enables generation of random bytes from the operating system - the feature digest enables the SHA512 hashing algorithm when calling hash to curve -precomputed-tables enables faster multiplication of scalar points with points on the elliptic curve</p>
<p>Inside the <a target="_blank" href="http://main.rs"><code>main.rs</code></a> file, lets create the code for our algorithm</p>
<ol>
<li><p>Import all the data types and traits we will use</p>
<pre><code class="lang-rust"> <span class="hljs-keyword">use</span> curve25519_dalek::{ristretto::RistrettoPoint, scalar::Scalar, traits::Identity};
 <span class="hljs-keyword">use</span> rand::rngs::OsRng;
 <span class="hljs-keyword">use</span> sha2::Sha512;
 <span class="hljs-keyword">use</span> std::ops::{Mul, Sub};
</code></pre>
</li>
<li><p>Next, create a struct <code>MintCrypto</code> to perform cryptographic operations for the mint.</p>
<pre><code class="lang-rust">     <span class="hljs-comment">/// Cryptographic operations for the mint (Bob)</span>
     <span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">MintCrypto</span></span> {
         <span class="hljs-comment">// the secret key for a particular Ecash denomination</span>
         secret: Scalar,
         <span class="hljs-comment">// the public key for the Ecash denomination</span>
         <span class="hljs-comment">// specific to the secret key above</span>
         public: RistrettoPoint,
     }

     <span class="hljs-keyword">impl</span> MintCrypto {
         <span class="hljs-comment">/// Instantiate our struct</span>
     <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">new</span></span>() -&gt; <span class="hljs-keyword">Self</span> {
         <span class="hljs-comment">// generate a secret key and store it in a `Scalar`</span>
         <span class="hljs-keyword">let</span> secret = Scalar::random(&amp;<span class="hljs-keyword">mut</span> OsRng);
         <span class="hljs-comment">// Generate the public key</span>
         <span class="hljs-keyword">let</span> public = RistrettoPoint::identity().mul(&amp;secret);

         <span class="hljs-keyword">Self</span> { secret, public }
     }

     <span class="hljs-comment">/// Generate a blinded token to return to Alice</span>
     <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">blinded_token</span></span>(&amp;<span class="hljs-keyword">self</span>, blinded_message: RistrettoPoint) -&gt; RistrettoPoint {
         blinded_message.mul(<span class="hljs-keyword">self</span>.secret)
     }

     <span class="hljs-comment">/// Prove that the unblinded token is valid</span>
     <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">proof</span></span>(&amp;<span class="hljs-keyword">self</span>, unblinded_token: UnblindedToken) -&gt; <span class="hljs-built_in">bool</span> {
         <span class="hljs-comment">// Compute the point on elliptic curve</span>
         <span class="hljs-keyword">let</span> hash_to_curve =
             RistrettoPoint::hash_from_bytes::&lt;Sha512&gt;(unblinded_token.secret.as_bytes());
         <span class="hljs-comment">// Check if multiplying the elliptic curve point</span>
         <span class="hljs-comment">// equals the token</span>
         <span class="hljs-keyword">self</span>.secret.mul(hash_to_curve) == unblinded_token.proof
     }

     <span class="hljs-comment">/// Fetch the public key of the mint</span>
     <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">public_key</span></span>(&amp;<span class="hljs-keyword">self</span>) -&gt; RistrettoPoint {
         <span class="hljs-keyword">self</span>.public
     }
 }
</code></pre>
</li>
<li><p>Next, create a struct <code>UnblindedToken</code> which contains the secret key of Alice and the token issued by the mint. <code>UnblindedToken</code> is what is shared with Carol.</p>
<pre><code class="lang-rust">     <span class="hljs-comment">/// Contains the unblinded token from the mint and providers secret key</span>
     <span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">UnblindedToken</span></span> {
         <span class="hljs-comment">/// Provider's secret key</span>
         <span class="hljs-keyword">pub</span> secret: Scalar,
         <span class="hljs-comment">/// The unblinded token from the mint</span>
         <span class="hljs-keyword">pub</span> proof: RistrettoPoint,
     }
</code></pre>
</li>
<li><p>Next, we create the cryptographic primitives for the provider</p>
<pre><code class="lang-rust"> <span class="hljs-comment">/// Cryptographic operations for the Provider (Alice)</span>
 <span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">ProviderCrypto</span></span> {
     <span class="hljs-comment">// The secret known to the provider</span>
     secret: Scalar,
     <span class="hljs-comment">// A random nonce that guarantees each mint token is unique (nonce)</span>
     blinding_factor: Scalar,
     <span class="hljs-comment">// The blinded message</span>
     blinded_message: RistrettoPoint,
     <span class="hljs-comment">// The public key of the mint which can be for a particular token's denomination</span>
     ecash_token_public: RistrettoPoint,
 }

 <span class="hljs-keyword">impl</span> ProviderCrypto {
     <span class="hljs-comment">/// instantiate the struct by passing in the public key of the mint</span>
     <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">new</span></span>(ecash_token_public: RistrettoPoint) -&gt; <span class="hljs-keyword">Self</span> {
         <span class="hljs-comment">// Generate 32 cryptographically secure bytes</span>
         <span class="hljs-keyword">let</span> secret = Scalar::random(&amp;<span class="hljs-keyword">mut</span> OsRng);
         <span class="hljs-comment">// Generate 32  cryptographically secure bytes (nonce)</span>
         <span class="hljs-keyword">let</span> blinding_factor = Scalar::random(&amp;<span class="hljs-keyword">mut</span> OsRng);
         <span class="hljs-comment">// Run the `secret` first through a SHA512 hash and then generate a point on the elliptic curve</span>
         <span class="hljs-keyword">let</span> hash_to_curve_result = RistrettoPoint::hash_from_bytes::&lt;Sha512&gt;(secret.as_bytes());
         <span class="hljs-comment">// Generate a `blinded_message` that is unique by adding the `hash_to_curve_result`</span>
         <span class="hljs-comment">// to a point on the elliptic curve generated by the multiplying the `blinding_factor` by a generator `G`</span>
         <span class="hljs-keyword">let</span> blinded_message =
             hash_to_curve_result + (RistrettoPoint::identity().mul(&amp;blinding_factor));

         <span class="hljs-keyword">Self</span> {
             secret,
             blinding_factor,
             blinded_message,
             ecash_token_public,
         }
     }

     <span class="hljs-comment">/// Unblind a token from the mint</span>
     <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">unblind</span></span>(&amp;<span class="hljs-keyword">self</span>, token: RistrettoPoint) -&gt; UnblindedToken {
         <span class="hljs-comment">// Performs the unblinding operation `token - blinding_factor * K` where `K` is the public key of the mint</span>
         <span class="hljs-keyword">let</span> proof = token.sub(<span class="hljs-keyword">self</span>.blinding_factor.mul(<span class="hljs-keyword">self</span>.ecash_token_public));

         UnblindedToken {
             secret: <span class="hljs-keyword">self</span>.secret,
             proof,
         }
     }

     <span class="hljs-comment">/// Get the unblinded token and provider secret</span>
     <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">blinded_message</span></span>(&amp;<span class="hljs-keyword">self</span>) -&gt; RistrettoPoint {
         <span class="hljs-keyword">self</span>.blinded_message
     }
 }
</code></pre>
</li>
<li><p>Lastly, in the main function, we use our data structures to generate and verify a token</p>
<pre><code class="lang-rust">     <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
     <span class="hljs-comment">// Generate primitives for the mint</span>
     <span class="hljs-keyword">let</span> mint = MintCrypto::new();

     <span class="hljs-comment">// Generate primitives for the provider</span>
     <span class="hljs-keyword">let</span> provider = ProviderCrypto::new(mint.public_key());

     <span class="hljs-comment">// The mint generates a blinded token from the provider's `blinded_message`</span>
     <span class="hljs-keyword">let</span> blinded_token = mint.blinded_token(provider.blinded_message());

     <span class="hljs-comment">// The provider unblinds the token</span>
     <span class="hljs-keyword">let</span> unblinded_token = provider.unblind(blinded_token);

     <span class="hljs-comment">// The mint proves whether the token is valid or not</span>
     <span class="hljs-built_in">assert!</span>(mint.proof(unblinded_token));
 }
</code></pre>
</li>
</ol>
<p>That’s it. We have created an algorithm for generating Ecash tokens using the blinded Diffie-Hellman-Merkle algorithm.</p>
<h4 id="heading-references">References</h4>
<ol>
<li><p><a target="_blank" href="https://en.wikipedia.org/wiki/Ecash">https://en.wikipedia.org/wiki/Ecash</a></p>
</li>
<li><p><a target="_blank" href="http://www.hit.bme.hu/~buttyan/courses/BMEVIHIM219/2009/Chaum.BlindSigForPayment.1982.PDF">http://www.hit.bme.hu/~buttyan/courses/BMEVIHIM219/2009/Chaum.BlindSigForPayment.1982.PDF</a></p>
</li>
<li><p><a target="_blank" href="https://gist.github.com/callebtc/557e4cc15f9e43d7474c7cb3d31ee8ed">https://gist.github.com/callebtc/557e4cc15f9e43d7474c7cb3d31ee8ed</a></p>
</li>
<li><p><a target="_blank" href="https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange">https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange</a></p>
</li>
<li><p><a target="_blank" href="https://en.wikipedia.org/wiki/Curve25519">https://en.wikipedia.org/wiki/Curve25519</a></p>
</li>
<li><p><a target="_blank" href="https://en.wikipedia.org/wiki/Montgomery_curve">https://en.wikipedia.org/wiki/Montgomery_curve</a></p>
</li>
<li><p><a target="_blank" href="https://ristretto.group/">https://ristretto.group/</a></p>
</li>
</ol>
]]></content:encoded></item><item><title><![CDATA[Parsing Input scriptSig in Bitcoin Transactions Using Rust Programming Language]]></title><description><![CDATA[In the previous article, we saw how we can parse bytes from a hex encoded transaction into a transaction structure (version, inputs, outputs and lock time).
Previous Articles.

Parsing Bitcoin Transactions in Rust Programming Language Standard Librar...]]></description><link>https://448.africa/parsing-input-scriptsig-in-bitcoin-transactions-using-rust-programming-language-6a2f02916981</link><guid isPermaLink="true">https://448.africa/parsing-input-scriptsig-in-bitcoin-transactions-using-rust-programming-language-6a2f02916981</guid><dc:creator><![CDATA[448-OG]]></dc:creator><pubDate>Wed, 10 Apr 2024 07:37:26 GMT</pubDate><content:encoded><![CDATA[<p>In the previous article, we saw how we can parse bytes from a hex encoded transaction into a transaction structure (version, inputs, outputs and lock time).</p>
<h4 id="heading-previous-articles"><strong>Previous Articles.</strong></h4>
<ol>
<li>Parsing Bitcoin Transactions in Rust Programming Language Standard Library — <a target="_blank" href="https://448.africa/parsing-bitcoin-transactions-in-rust-programming-language-standard-library-20c06a23a564">https://448.africa/parsing-bitcoin-transactions-in-rust-programming-language-standard-library-20c06a23a564</a></li>
</ol>
<p>In this article we will look at parsing input <code>scriptSig</code> bytes as a Bitcoin script.</p>
<h3 id="heading-understanding-bitcoin-script">Understanding Bitcoin Script</h3>
<p>Bitcoin script is a simple, stack-based, Forth-like programming language used in the Bitcoin protocol for transaction processing. It’s not Turing-complete, meaning it doesn’t have loops, which is a design choice to prevent attacks on the network like infinite loops and logic bombs that would be evaluated in a way that causes denial of service attacks.</p>
<p>Each Bitcoin transaction includes a script that validates the conditions under which the transaction can be redeemed. The script is processed from left to right, and if it completes without any errors and the final result is <code>true</code>, the transaction is considered valid.</p>
<h3 id="heading-most-common-bitcoin-scripts">Most Common Bitcoin Scripts</h3>
<p>Bitcoin’s primary focus is sending bitcoins from one address to one or many addresses. This means that most scripts are created to allow one or multiple wallets to spend bitcoins. The Bitcoin core network has 5 standard scripts that are known to all nodes and miners. The standard scripts and their <em>Assembly Protocol (ASM)</em> representation:<br /> — <strong>Note that all the bytes should appear as hex</strong></p>
<ol>
<li><p>Pay to Public Key (P2PK) — This is rarely used.<br /> <code>&lt;Public Key&gt; OP_CHECKSIG</code></p>
</li>
<li><p>Pay to Public Key Hash (P2PKH)<br /> <code>OP_DUP OP_HASH160 &lt;PublicKey Hash&gt; OP_EQUAL OP_CHECKSIG</code></p>
</li>
<li><p>Pay to Multi-signature (P2MS) — limited to 15 keys<br /> <code>M &lt;Public Key 1&gt; &lt;Public Key 2&gt; … &lt;Public Key N&gt; N OP_CHECKMULTISIG</code> — where <code>M</code> is the threshold and <code>N</code> is the number of signatures</p>
</li>
<li><p>Pay to Script Hash (P2SH)<br /> <code>OP_HASH160 &lt;20 bytes of the hash&gt; OP_EQUAL</code></p>
</li>
<li><p>Pay to Witness Public Key Hash (P2WPKH)<br /> <code>OP_0 *&lt;20-byte hash&gt;*</code></p>
</li>
<li><p>Pay to Witness Script Hash (P2WSH)<br /> <code>OP_0 &lt;32-byte hash&gt;</code></p>
</li>
<li><p>Pay to Tap Root (P2TR)<br /> <code>OP_1 &lt;32-byte hash&gt;</code></p>
</li>
<li><p>Data Output (OP_RETURN)<br /> <code>OP_RETURN &lt;data&gt;</code></p>
</li>
</ol>
<p>We will look at decoding our previous script data into these standard scripts in Rust.</p>
<h4 id="heading-detecting-the-script-type">Detecting the script type</h4>
<p>At the time of writing there are 8 standard scripts which makes it very easy to identify the type of script by parsing the first or first and second OPCODE NOTE that the <code>*</code> in <code>OP_PUSHBYTES_*</code>means the number of bytes:</p>
<ol>
<li><p>P2PK — <code>OP_PUSHBYTES_65</code></p>
</li>
<li><p>P2PKH — <code>OP_DUP</code></p>
</li>
<li><p>P2MS — <code>OP_1 — OP_16 OP_PUSHBYTES_*</code></p>
</li>
<li><p>P2SH — <code>OP_HASH160</code></p>
</li>
<li><p>P2WPKH — <code>OP_0 OP_PUSHBYTES_20</code></p>
</li>
<li><p>P2WSH — <code>OP_0 OP_PUSHBYTES_32</code></p>
</li>
<li><p>P2TR — <code>OP_1 OP_PUSHBYTES_32</code></p>
</li>
<li><p>Data (OP_RETURN) — <code>OP_RETURN</code></p>
</li>
</ol>
<p>Now we will create a module called <code>scripts</code> in the <code>scripts.rs</code> file and import it to the <code>main.rs</code> file.</p>
<pre><code class="lang-rust"><span class="hljs-comment">//... main.rs previous code here</span>
<span class="hljs-keyword">mod</span> scripts;
<span class="hljs-keyword">pub</span> <span class="hljs-keyword">use</span> scripts::*;

<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
    <span class="hljs-comment">// .. previous code from previous tutorial</span>
}
</code></pre>
<p>In our <code>scripts.rs</code> file we will import standard library types for addition , I/O and error handling. We will convert all our errors to <code>std::io::Error</code></p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> std::{
    io::{<span class="hljs-keyword">self</span>, Cursor, Error, ErrorKind, Read},
    ops::Add,
};
</code></pre>
<p>We will create methods to parse the standard <code>scriptSig</code> inside the impl block of <code>StandardScripts</code> struct</p>
<pre><code class="lang-rust"><span class="hljs-comment">/// Handles scriptSig parsing</span>
<span class="hljs-meta">#[derive(Debug, Clone, Copy)]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">StandardScripts</span></span>;

<span class="hljs-keyword">impl</span> StandardScripts {}
</code></pre>
<p>We will parse based on the following:</p>
<p>If:</p>
<ul>
<li><p>First OPCODE is <code>OP_PUSHBYTES_65</code> then parse as <code>P2PK</code></p>
</li>
<li><p>First OPCODE is <code>OP_DUP</code> then parse as <code>P2PKH</code></p>
</li>
<li><p>First OPCODE is <code>OP_RETURN</code> then parse as <code>Data(OP_RETURN)</code></p>
</li>
<li><p>First OPCODE is <code>OP_0</code> and second OPCODE is <code>OP_PUSHBYTES_20</code> then parse as <code>P2WPKH</code></p>
</li>
<li><p>First OPCODE is <code>OP_0</code> and second OPCODE is <code>OP_PUSHBYTES_32</code> then parse as <code>P2WSH</code></p>
</li>
<li><p>First OP_CODE is between <code>OP_1</code> and <code>OP_16</code> and second OPCODE is <code>OP_PUSHBYTES_32</code> then parse as <code>P2TR</code></p>
</li>
<li><p>First OP_CODE is between <code>OP_1</code> and <code>OP_16</code> and second OPCODE is <code>OP_PUSHBYTES_</code>* then try parsing as <code>P2MS</code> else return an <code>std::io::Error</code> with <code>ErrorKind::InvalidData</code> with a helpful error message.</p>
</li>
</ul>
<p>Let’s define the OPCODES to parse</p>
<pre><code class="lang-rust"><span class="hljs-comment">/// Supported OPCODEs for standard scripts in scriptSig</span>
<span class="hljs-meta">#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]</span>
<span class="hljs-meta">#[allow(non_camel_case_types)]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">enum</span> <span class="hljs-title">Opcode</span></span> {
    OP_HASH160,
    OP_CHECKSIG,
    OP_EQUAL,
    OP_EQUALVERIFY,
    OP_CHECKMULTISIG,
    OP_DUP,
    OP_RETURN,
    OP_0,
    OP_1,
    <span class="hljs-comment">/// Handles OP_2 to OP_16</span>
    Num(<span class="hljs-built_in">u8</span>),
    <span class="hljs-comment">/// Handles all OP_PUSHBYTES_*</span>
    PushBytes(<span class="hljs-built_in">u8</span>),
    <span class="hljs-comment">/// Useful in error handling for unsupported opcodes</span>
    UnsupportedOpcode,
}

<span class="hljs-keyword">impl</span> Opcode {
    <span class="hljs-comment">/// Parse an opcode from a hex decoded byte</span>
    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">from_byte</span></span>(byte: <span class="hljs-built_in">u8</span>) -&gt; <span class="hljs-keyword">Self</span> {
        <span class="hljs-keyword">match</span> byte {
            <span class="hljs-number">169</span> =&gt; Self::OP_HASH160,
            <span class="hljs-comment">/// All OP_PUSHBYTES_*</span>
            <span class="hljs-number">1</span>..=<span class="hljs-number">75</span> =&gt; Self::PushBytes(byte),
            <span class="hljs-number">172</span> =&gt; Self::OP_CHECKSIG,
            <span class="hljs-number">135</span> =&gt; Self::OP_EQUAL,
            <span class="hljs-number">136</span> =&gt; Self::OP_EQUALVERIFY,
            <span class="hljs-number">174</span> =&gt; Self::OP_CHECKMULTISIG,
            <span class="hljs-number">118</span> =&gt; Self::OP_DUP,
            <span class="hljs-number">106</span> =&gt; Self::OP_RETURN,
            <span class="hljs-number">0</span> =&gt; Self::OP_0,
            <span class="hljs-number">81</span> =&gt; Self::OP_1,
            <span class="hljs-comment">/// All OP_2 - OP_16</span>
            <span class="hljs-number">82</span>..=<span class="hljs-number">96</span> =&gt; {
                <span class="hljs-keyword">let</span> to_num = <span class="hljs-keyword">match</span> byte {
                <span class="hljs-number">82</span> =&gt; <span class="hljs-number">2u8</span>,
                <span class="hljs-number">83</span> =&gt; <span class="hljs-number">3</span>,
                <span class="hljs-number">84</span> =&gt; <span class="hljs-number">4</span>,
                <span class="hljs-number">85</span> =&gt; <span class="hljs-number">5</span>,
                <span class="hljs-number">86</span> =&gt; <span class="hljs-number">6</span>,
                <span class="hljs-number">87</span> =&gt; <span class="hljs-number">7</span>,
                <span class="hljs-number">88</span> =&gt; <span class="hljs-number">8</span>,
                <span class="hljs-number">89</span> =&gt; <span class="hljs-number">9</span>,
                <span class="hljs-number">90</span> =&gt; <span class="hljs-number">10</span>,
                <span class="hljs-number">91</span> =&gt; <span class="hljs-number">11</span>,
                <span class="hljs-number">92</span> =&gt; <span class="hljs-number">12</span>,
                <span class="hljs-number">93</span> =&gt; <span class="hljs-number">13</span>,
                <span class="hljs-number">94</span> =&gt; <span class="hljs-number">14</span>,
                <span class="hljs-number">95</span> =&gt; <span class="hljs-number">15</span>,
                <span class="hljs-number">96</span> =&gt; <span class="hljs-number">16</span>,
                _ =&gt; <span class="hljs-keyword">return</span> Self::UnsupportedOpcode,
            };
            Self::Num(to_num)
        }
        _ =&gt; Self::UnsupportedOpcode,
        }    
    }

    <span class="hljs-comment">/// Handles reading OP_PUSHBYTES_*</span>
    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">read_bytes</span></span>(&amp;<span class="hljs-keyword">self</span>, bytes: &amp;<span class="hljs-keyword">mut</span> Cursor&lt;&amp;[<span class="hljs-built_in">u8</span>]&gt;) -&gt; io::<span class="hljs-built_in">Result</span>&lt;<span class="hljs-built_in">Vec</span>&lt;<span class="hljs-built_in">u8</span>&gt;&gt; {
        <span class="hljs-comment">// Store all parsed bytes for `OP_PUSHBYTES_*`</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> buffer = <span class="hljs-built_in">Vec</span>::&lt;<span class="hljs-built_in">u8</span>&gt;::new();

        <span class="hljs-keyword">match</span> <span class="hljs-keyword">self</span> {
            Self::PushBytes(byte_len) =&gt; {
            <span class="hljs-comment">// Gets the current position and adds the length of the</span>
            <span class="hljs-keyword">let</span> new_position = (bytes.position() <span class="hljs-keyword">as</span> <span class="hljs-built_in">usize</span>).add(*byte_len <span class="hljs-keyword">as</span> <span class="hljs-built_in">usize</span>);
            <span class="hljs-comment">// Read the byte slice from the current cursor position the byte length</span>
            buffer.extend_from_slice(&amp;bytes.get_ref()[bytes.position() <span class="hljs-keyword">as</span> <span class="hljs-built_in">usize</span>..new_position]);
            <span class="hljs-comment">// Set the cursor position to the previous cursor position + the byte length</span>
            bytes.set_position(new_position <span class="hljs-keyword">as</span> <span class="hljs-built_in">u64</span>);

            <span class="hljs-literal">Ok</span>(buffer)
        }
        _ =&gt; <span class="hljs-literal">Err</span>(io::Error::new(
            ErrorKind::Unsupported,
            <span class="hljs-string">"This operation is not supported"</span>,
            )),
        }
    }
}
</code></pre>
<p>Next we implement the trait <code>TryFrom</code> for our <code>Opcode</code> enum so that we can convert it easily to a Rust <code>String</code></p>
<pre><code class="lang-rust"><span class="hljs-keyword">impl</span> TryFrom <span class="hljs-keyword">for</span> <span class="hljs-built_in">String</span> {
    <span class="hljs-comment">// All errors are converted to std::io::Error</span>
    <span class="hljs-class"><span class="hljs-keyword">type</span> <span class="hljs-title">Error</span></span> = io::Error;

    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">try_from</span></span>(value: Opcode) -&gt; <span class="hljs-built_in">Result</span>&lt;<span class="hljs-keyword">Self</span>, Self::Error&gt; {
        <span class="hljs-keyword">let</span> opcode = <span class="hljs-keyword">match</span> value {
            Opcode::OP_HASH160 =&gt; <span class="hljs-string">"OP_HASH160"</span>,
            Opcode::PushBytes(bytes_len) =&gt; {
                <span class="hljs-keyword">return</span> <span class="hljs-literal">Ok</span>(<span class="hljs-built_in">String</span>::from(<span class="hljs-string">"OP_PUSHBYTES_"</span>).add(bytes_len.to_string().as_str()))
            }
            Opcode::OP_CHECKSIG =&gt; <span class="hljs-string">"OP_CHECKSIG"</span>,
            Opcode::OP_EQUAL =&gt; <span class="hljs-string">"OP_EQUAL"</span>,
            Opcode::OP_EQUALVERIFY =&gt; <span class="hljs-string">"OP_EQUALVERIFY"</span>,
            Opcode::OP_CHECKMULTISIG =&gt; <span class="hljs-string">"OP_CHECKMULTISIG"</span>,
            Opcode::OP_DUP =&gt; <span class="hljs-string">"OP_DUP"</span>,
            Opcode::OP_RETURN =&gt; <span class="hljs-string">"OP_RETURN"</span>,    
            Opcode::OP_0 =&gt; <span class="hljs-string">"OP_0"</span>,
            Opcode::OP_1 =&gt; <span class="hljs-string">"OP_1"</span>,
            Opcode::Num(value) =&gt; <span class="hljs-keyword">return</span> <span class="hljs-literal">Ok</span>(<span class="hljs-built_in">String</span>::from(<span class="hljs-string">"OP_"</span>).add(value.to_string().as_str())),
            Opcode::UnsupportedOpcode =&gt; {
                <span class="hljs-keyword">return</span> <span class="hljs-literal">Err</span>(io::Error::new(
                    ErrorKind::InvalidData,
                    <span class="hljs-string">"Unsupported Opcode. Opcode not part of Bitcoin Core standard scripts"</span>,
                    ))
                }
             };

         <span class="hljs-literal">Ok</span>(opcode.into())
    }
}
</code></pre>
<p>Next we create a struct with methods to build our scriptSig into a String</p>
<pre><code class="lang-rust"><span class="hljs-meta">#[derive(Debug, Default)]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">ScriptBuilder</span></span>(<span class="hljs-built_in">Vec</span>&lt;<span class="hljs-built_in">String</span>&gt;);

<span class="hljs-keyword">impl</span> ScriptBuilder {
    <span class="hljs-comment">/// Initialize `Self` with defaults</span>
    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">new</span></span>() -&gt; <span class="hljs-keyword">Self</span> {
        Self::default()
    }

    <span class="hljs-comment">/// This will receive an `Opcode` and convert it</span>
    <span class="hljs-comment">/// into a String since we implemented</span>
    <span class="hljs-comment">/// `TryFrom for String`</span>
    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">push_opcode</span></span>(&amp;<span class="hljs-keyword">mut</span> <span class="hljs-keyword">self</span>, opcode: Opcode) -&gt; io::<span class="hljs-built_in">Result</span>&lt;&amp;<span class="hljs-keyword">mut</span> <span class="hljs-keyword">Self</span>&gt; {
        <span class="hljs-keyword">let</span> opcode_string: <span class="hljs-built_in">String</span> = opcode.try_into()?;
        <span class="hljs-keyword">self</span>.<span class="hljs-number">0</span>.push(opcode_string);

        <span class="hljs-literal">Ok</span>(<span class="hljs-keyword">self</span>)
    }

    <span class="hljs-comment">/// This will convert our bytes into hex and</span>
    <span class="hljs-comment">/// push the opcode `OP_PUSHBYTES_*`</span>
    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">push_bytes</span></span>(&amp;<span class="hljs-keyword">mut</span> <span class="hljs-keyword">self</span>, bytes: &amp;[<span class="hljs-built_in">u8</span>]) -&gt; io::<span class="hljs-built_in">Result</span>&lt;&amp;<span class="hljs-keyword">mut</span> <span class="hljs-keyword">Self</span>&gt; {
        <span class="hljs-keyword">self</span>.<span class="hljs-number">0</span>.push(hex::encode(bytes));

        <span class="hljs-literal">Ok</span>(<span class="hljs-keyword">self</span>)
    }

    <span class="hljs-comment">/// Next we collect the Vector of Strings</span>
    <span class="hljs-comment">/// into one String</span>
    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">build</span></span>(<span class="hljs-keyword">self</span>) -&gt; <span class="hljs-built_in">String</span> {
        <span class="hljs-keyword">self</span>.<span class="hljs-number">0</span>
            .into_iter()
            .map(|<span class="hljs-keyword">mut</span> part| {
                part.push(<span class="hljs-string">' '</span>);
                part
            })
            .collect::&lt;<span class="hljs-built_in">String</span>&gt;()
            .trim()
            .into()
    }  
}
</code></pre>
<p>Next we implement the parsing methods for our <code>StandardScripts</code> struct</p>
<p>We implement the <code>parse</code> method to detect the scriptSig</p>
<pre><code class="lang-rust"><span class="hljs-keyword">impl</span> StandardScripts {
    <span class="hljs-comment">/// Decides which scriptSig to parse</span>
    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">parse</span></span>(bytes: &amp;<span class="hljs-keyword">mut</span> Cursor&lt;&amp;[<span class="hljs-built_in">u8</span>]&gt;) -&gt; io::<span class="hljs-built_in">Result</span>&lt;<span class="hljs-built_in">String</span>&gt; {
        <span class="hljs-comment">// Get the first OPCODE</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> opcode_buffer = [<span class="hljs-number">0u8</span>; <span class="hljs-number">1</span>];
        bytes.read_exact(&amp;<span class="hljs-keyword">mut</span> opcode_buffer)?;
        <span class="hljs-comment">// Convert our byte into an `Opcode`</span>
        <span class="hljs-keyword">let</span> first_opcode = Opcode::from_byte(opcode_buffer[<span class="hljs-number">0</span>]);

        <span class="hljs-keyword">match</span> first_opcode {
            <span class="hljs-comment">// If `OP_PUSHBYTES_65` then parse as P2PK</span>
            Opcode::PushBytes(<span class="hljs-number">65</span>) =&gt; Self::parse_p2pk(bytes),
            <span class="hljs-comment">// If `OP_DUP` then parse as P2PKH</span>
            Opcode::OP_DUP =&gt; Self::parse_p2pkh(bytes),
            <span class="hljs-comment">// If `OP_HASH160` then parse as P2PK</span>
            Opcode::OP_HASH160 =&gt; Self::parse_p2sh(bytes),
            <span class="hljs-comment">// If `OP_RETURN` then parse as Data(OP_RETURN)</span>
            Opcode::OP_RETURN =&gt; Self::parse_data(bytes),
            <span class="hljs-comment">// If `OP_0` as first OPCODE and OP_PUSHBYTES_20 is second OPCODE then parse as P2WPKH</span>
            <span class="hljs-comment">// Else if `OP_0` as first OPCODE and OP_PUSHBYTES_32 is second OPCODE then parse as P2WSH</span>
            <span class="hljs-comment">// Else return an an error if `OP_0` is first OPCODE</span>
            Opcode::OP_0 =&gt; {
                bytes.read_exact(&amp;<span class="hljs-keyword">mut</span> opcode_buffer)?;
                <span class="hljs-keyword">let</span> second_opcode = Opcode::from_byte(opcode_buffer[<span class="hljs-number">0</span>]);
                <span class="hljs-keyword">if</span> second_opcode.eq(&amp;Opcode::PushBytes(<span class="hljs-number">20</span>)) {
                    Self::parse_p2wpkh(bytes)
                } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> second_opcode.eq(&amp;Opcode::PushBytes(<span class="hljs-number">32</span>)) {
                    Self::parse_p2wsh(bytes)
                } <span class="hljs-keyword">else</span> {
                    <span class="hljs-keyword">return</span> Self::to_io_error(
                    <span class="hljs-string">"Invalid Script. Expected OP_PUSHBYTES_20 or OP_PUSHBYTES_32 after OP_0"</span>,
                    );
                }
            }
            _ =&gt; {
                <span class="hljs-comment">// If `OP_1` as first OPCODE and OP_PUSHBYTES_32 is second OPCODE then parse as P2TR</span>
                <span class="hljs-comment">// Else try parsing as P2MS</span>

                bytes.read_exact(&amp;<span class="hljs-keyword">mut</span> opcode_buffer)?;
                <span class="hljs-keyword">let</span> second_opcode = Opcode::from_byte(opcode_buffer[<span class="hljs-number">0</span>]);

                <span class="hljs-keyword">if</span> first_opcode.eq(&amp;Opcode::OP_1) &amp;&amp; second_opcode.eq(&amp;Opcode::PushBytes(<span class="hljs-number">32</span>)) {
                    Self::parse_p2tr(bytes)
                } <span class="hljs-keyword">else</span> {
                    <span class="hljs-comment">// Reset current position of cursor to the beginning</span>
                    bytes.set_position(bytes.position() - <span class="hljs-number">2</span>);
                    Self::parse_p2ms(bytes)
                }
            }
        }
    }
}
</code></pre>
<p>Next, we create a method to handle errors since they are common whereby they return a <code>std::io::Error</code> with <code>ErrorKind</code> and custom message.</p>
<pre><code class="lang-rust"><span class="hljs-keyword">impl</span> StandardScripts {
    <span class="hljs-comment">// ..previous methods here</span>

    <span class="hljs-comment">// Error Handling returning an `io::Result` to avoid</span>
    <span class="hljs-comment">// having to add `Err()` whenever we call this method.</span>
    <span class="hljs-comment">// Our message is unique so we add that as argument</span>
    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">to_io_error</span></span>(message: &amp;<span class="hljs-built_in">str</span>) -&gt; io::<span class="hljs-built_in">Result</span>&lt;<span class="hljs-built_in">String</span>&gt; {
        <span class="hljs-literal">Err</span>(io::Error::new(ErrorKind::InvalidData, message))
    }
}
</code></pre>
<ol>
<li>Method to parse P2PK</li>
</ol>
<pre><code class="lang-rust"><span class="hljs-keyword">impl</span> StandardScripts {
    <span class="hljs-comment">/// Parse as P2PK</span>
    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">parse_p2pk</span></span>(bytes: &amp;<span class="hljs-keyword">mut</span> Cursor&lt;&amp;[<span class="hljs-built_in">u8</span>]&gt;) -&gt; io::<span class="hljs-built_in">Result</span>&lt;<span class="hljs-built_in">String</span>&gt; {
        <span class="hljs-comment">// Cursor is already at second byte to we parse</span>
        <span class="hljs-comment">// 65 bytes from that position to get the</span>
        <span class="hljs-comment">// Uncompressed Public Key</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> public_key_bytes = [<span class="hljs-number">0u8</span>; <span class="hljs-number">65</span>];
        bytes.read_exact(&amp;<span class="hljs-keyword">mut</span> public_key_bytes)?;
        <span class="hljs-comment">// Next we parse OP_CHECKSIG</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> op_checksig_byte = [<span class="hljs-number">0u8</span>; <span class="hljs-number">1</span>];
        bytes.read_exact(&amp;<span class="hljs-keyword">mut</span> op_checksig_byte)?;
        <span class="hljs-keyword">let</span> op_checksig = Opcode::from_byte(op_checksig_byte[<span class="hljs-number">0</span>]);

        <span class="hljs-keyword">if</span> op_checksig.ne(&amp;Opcode::OP_CHECKSIG) {
            <span class="hljs-keyword">return</span> <span class="hljs-literal">Err</span>(Error::new(
                ErrorKind::InvalidData,
                <span class="hljs-string">"Invalid Data. Expected OP_CHECKSIG as last byte of the script."</span>,
            ));
        }

        <span class="hljs-comment">// Lastly, we build our script</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> script_builder = ScriptBuilder::new();
        script_builder
        .push_opcode(Opcode::PushBytes(<span class="hljs-number">65</span>))?
        .push_bytes(&amp;public_key_bytes)?
        .push_opcode(Opcode::OP_CHECKSIG)?;

        <span class="hljs-literal">Ok</span>(script_builder.build())
    }
}
</code></pre>
<p>2. Method to parse P2PKH</p>
<pre><code class="lang-rust"><span class="hljs-keyword">impl</span> StandardScripts {
    <span class="hljs-comment">// .. previous methods here</span>
    <span class="hljs-comment">/// Parse P2PKH</span>
    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">parse_p2pkh</span></span>(bytes: &amp;<span class="hljs-keyword">mut</span> Cursor&lt;&amp;[<span class="hljs-built_in">u8</span>]&gt;) -&gt; io::<span class="hljs-built_in">Result</span>&lt;<span class="hljs-built_in">String</span>&gt; {
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> opcode_buffer = [<span class="hljs-number">0u8</span>; <span class="hljs-number">1</span>];

        bytes.read_exact(&amp;<span class="hljs-keyword">mut</span> opcode_buffer)?;
        <span class="hljs-comment">// Parse second OPCODE as OP_HASH160</span>
        <span class="hljs-keyword">let</span> should_be_ophash160 = Opcode::from_byte(opcode_buffer[<span class="hljs-number">0</span>]);
        <span class="hljs-keyword">if</span> should_be_ophash160.ne(&amp;Opcode::OP_HASH160) {
            <span class="hljs-keyword">return</span> <span class="hljs-literal">Err</span>(Error::new(
                ErrorKind::InvalidData,
                <span class="hljs-string">"Invalid Data. Expected OP_HASH160 as second byte of the script."</span>,
            ));
        }

        bytes.read_exact(&amp;<span class="hljs-keyword">mut</span> opcode_buffer)?;
            <span class="hljs-comment">// Parse third OPCODE as `OP_PUSHBYTES_20`</span>
            <span class="hljs-keyword">let</span> should_be_op_pushbytes20 = Opcode::from_byte(opcode_buffer[<span class="hljs-number">0</span>]);
            <span class="hljs-keyword">if</span> should_be_op_pushbytes20.ne(&amp;Opcode::PushBytes(<span class="hljs-number">20</span>)) {
                <span class="hljs-keyword">return</span> <span class="hljs-literal">Err</span>(Error::new(
                ErrorKind::InvalidData,
                    <span class="hljs-string">"Invalid Data. Expected OP_PUSHBYTES_20 as third byte of the script."</span>,
                ));
             }

            <span class="hljs-comment">// Get the 20 bytes of the Hash160</span>
            <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> hash160_bytes = [<span class="hljs-number">0u8</span>; <span class="hljs-number">20</span>];
            bytes.read_exact(&amp;<span class="hljs-keyword">mut</span> hash160_bytes)?;

            <span class="hljs-comment">// Parse the next byte as OP_EQUALVERIFY</span>
            bytes.read_exact(&amp;<span class="hljs-keyword">mut</span> opcode_buffer)?;
            <span class="hljs-keyword">let</span> should_be_opequalverify = Opcode::from_byte(opcode_buffer[<span class="hljs-number">0</span>]);
            <span class="hljs-keyword">if</span> should_be_opequalverify.ne(&amp;Opcode::OP_EQUALVERIFY) {
                <span class="hljs-keyword">return</span> <span class="hljs-literal">Err</span>(Error::new(
                    ErrorKind::InvalidData,
                        <span class="hljs-string">"Invalid Data. Expected OP_EQUALVERIFY after reading 20 bytes after third byte of the script."</span>,
                ));
            }

            <span class="hljs-comment">// Parse the next byte as OP_CHECKSIG</span>
            bytes.read_exact(&amp;<span class="hljs-keyword">mut</span> opcode_buffer)?;
            <span class="hljs-keyword">let</span> should_be_opchecksing = Opcode::from_byte(opcode_buffer[<span class="hljs-number">0</span>]);
            <span class="hljs-keyword">if</span> should_be_opchecksing.ne(&amp;Opcode::OP_CHECKSIG) {
                <span class="hljs-keyword">return</span> <span class="hljs-literal">Err</span>(Error::new(
                    ErrorKind::InvalidData,
                    <span class="hljs-string">"Invalid Data. Expected OP_CHECKSIG after reading OP_EQUALVERIFY byte in the script."</span>,
                ));
            }

            <span class="hljs-comment">// Build our script into a Sctring</span>
            <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> script_builder = ScriptBuilder::new();
            script_builder
                .push_opcode(Opcode::OP_DUP)?
                .push_opcode(Opcode::OP_HASH160)?
                .push_opcode(Opcode::PushBytes(<span class="hljs-number">20</span>))?
                .push_bytes(&amp;hash160_bytes)?
                .push_opcode(Opcode::OP_EQUALVERIFY)?
                .push_opcode(Opcode::OP_CHECKSIG)?;

                <span class="hljs-literal">Ok</span>(script_builder.build())
            }
}
</code></pre>
<p>3. Method to parse P2SH</p>
<pre><code class="lang-rust"><span class="hljs-keyword">impl</span> StandardScripts {
<span class="hljs-comment">// .. Previous methods here</span>
   <span class="hljs-comment">/// Parse P2SH</span>
    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">parse_p2sh</span></span>(bytes: &amp;<span class="hljs-keyword">mut</span> Cursor&lt;&amp;[<span class="hljs-built_in">u8</span>]&gt;) -&gt; io::<span class="hljs-built_in">Result</span>&lt;<span class="hljs-built_in">String</span>&gt; {
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> script_buffer = [<span class="hljs-number">0u8</span>; <span class="hljs-number">1</span>];

        bytes.read_exact(&amp;<span class="hljs-keyword">mut</span> script_buffer)?;

        <span class="hljs-comment">// Second OPCODE should be OP_PUSHBYTES_20</span>
        <span class="hljs-keyword">let</span> second_opcode = Opcode::from_byte(script_buffer[<span class="hljs-number">0</span>]);
        <span class="hljs-keyword">if</span> second_opcode.ne(&amp;Opcode::PushBytes(<span class="hljs-number">20</span>)) {
            <span class="hljs-keyword">return</span> Self::to_io_error(
                <span class="hljs-string">"Invalid Data. Expected an OP_PUSHBYTES_20 opcode after OP_HASH160"</span>,
            );
        }

        <span class="hljs-comment">// Read the 20 bytes of HASH160</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> bytes_20_buffer = [<span class="hljs-number">0u8</span>; <span class="hljs-number">20</span>];
        bytes.read_exact(&amp;<span class="hljs-keyword">mut</span> bytes_20_buffer)?;

        bytes.read_exact(&amp;<span class="hljs-keyword">mut</span> script_buffer)?;
        <span class="hljs-keyword">let</span> last_opcode = Opcode::from_byte(script_buffer[<span class="hljs-number">0</span>]);
        <span class="hljs-keyword">if</span> last_opcode.ne(&amp;Opcode::OP_EQUAL) {
            <span class="hljs-keyword">return</span> Self::to_io_error(
                <span class="hljs-string">"Invalid Data. Expected an OP_EQUAL opcode after reading 20 bytes"</span>,
            );
        }

        <span class="hljs-comment">// Build the script into a String</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> script_builder = ScriptBuilder::new();
        script_builder
            .push_opcode(Opcode::OP_HASH160)?
            .push_opcode(Opcode::PushBytes(<span class="hljs-number">20</span>))?
            .push_bytes(&amp;bytes_20_buffer)?
            .push_opcode(Opcode::OP_EQUAL)?;

        <span class="hljs-literal">Ok</span>(script_builder.build())
    }
}
</code></pre>
<p>4. Parse Data(OP_RETURN)</p>
<pre><code class="lang-rust"><span class="hljs-keyword">impl</span> StandardScripts {
    <span class="hljs-comment">//.. Previous code here</span>
    <span class="hljs-comment">// Parse OP_RETURN</span>
    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">parse_data</span></span>(bytes: &amp;<span class="hljs-keyword">mut</span> Cursor&lt;&amp;[<span class="hljs-built_in">u8</span>]&gt;) -&gt; io::<span class="hljs-built_in">Result</span>&lt;<span class="hljs-built_in">String</span>&gt; {
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> script_buffer = [<span class="hljs-number">0u8</span>; <span class="hljs-number">1</span>];

        bytes.read_exact(&amp;<span class="hljs-keyword">mut</span> script_buffer)?;
        <span class="hljs-comment">// Get second OPCODE which is `OP_PUSHBYTES_*`</span>
        <span class="hljs-keyword">let</span> second_opcode = Opcode::from_byte(script_buffer[<span class="hljs-number">0</span>]);
        <span class="hljs-comment">/// Read the number of bytes specified by second OPCODE</span>
        <span class="hljs-keyword">let</span> data_bytes = second_opcode.read_bytes(bytes)?;

        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> script_builder = ScriptBuilder::new();
        script_builder
        .push_opcode(Opcode::OP_RETURN)?
        .push_opcode(second_opcode)?
        .push_bytes(&amp;data_bytes)?;

        <span class="hljs-literal">Ok</span>(script_builder.build())
    }
}
</code></pre>
<p>5. Parse P2WPKH</p>
<pre><code class="lang-rust"><span class="hljs-keyword">impl</span> StandardScripts {
    <span class="hljs-comment">//.. Previous code here</span>
    <span class="hljs-comment">/// Parse P2WPKH</span>
    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">parse_p2wpkh</span></span>(bytes: &amp;<span class="hljs-keyword">mut</span> Cursor&lt;&amp;[<span class="hljs-built_in">u8</span>]&gt;) -&gt; io::<span class="hljs-built_in">Result</span>&lt;<span class="hljs-built_in">String</span>&gt; {
        <span class="hljs-comment">/// Read the next 20 bytes</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> pubkey_hash_bytes = [<span class="hljs-number">0u8</span>; <span class="hljs-number">20</span>];
        bytes.read_exact(&amp;<span class="hljs-keyword">mut</span> pubkey_hash_bytes)?;

        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> scripts = ScriptBuilder::new();
        scripts
        .push_opcode(Opcode::OP_0)?
        .push_opcode(Opcode::PushBytes(<span class="hljs-number">20</span>))?
        .push_bytes(&amp;pubkey_hash_bytes)?;

        <span class="hljs-literal">Ok</span>(scripts.build())
    }
}
</code></pre>
<p>6. Parse P2WSH</p>
<pre><code class="lang-rust"><span class="hljs-keyword">impl</span> StandardScripts {
    <span class="hljs-comment">//.. Previous code here</span>
    <span class="hljs-comment">/// Parse P2WSH</span>
    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">parse_p2wsh</span></span>(bytes: &amp;<span class="hljs-keyword">mut</span> Cursor&lt;&amp;[<span class="hljs-built_in">u8</span>]&gt;) -&gt; io::<span class="hljs-built_in">Result</span>&lt;<span class="hljs-built_in">String</span>&gt; {
        <span class="hljs-comment">// Parse next 32 bytes</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> hash_bytes = [<span class="hljs-number">0u8</span>; <span class="hljs-number">32</span>];
        bytes.read_exact(&amp;<span class="hljs-keyword">mut</span> hash_bytes)?;

        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> scripts = ScriptBuilder::new();
        scripts
        .push_opcode(Opcode::OP_0)?
        .push_opcode(Opcode::PushBytes(<span class="hljs-number">32</span>))?
        .push_bytes(&amp;hash_bytes)?;

        <span class="hljs-literal">Ok</span>(scripts.build())
    }
}
</code></pre>
<p>7. Parse P2TR</p>
<pre><code class="lang-rust"><span class="hljs-keyword">impl</span> StandardScripts {
    <span class="hljs-comment">//.. Previous code here</span>
    <span class="hljs-comment">/// Parse P2TR</span>
    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">parse_p2tr</span></span>(bytes: &amp;<span class="hljs-keyword">mut</span> Cursor&lt;&amp;[<span class="hljs-built_in">u8</span>]&gt;) -&gt; io::<span class="hljs-built_in">Result</span>&lt;<span class="hljs-built_in">String</span>&gt; {
        <span class="hljs-comment">// Parse next 32 bytes</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> hash_bytes = [<span class="hljs-number">0u8</span>; <span class="hljs-number">32</span>];
        bytes.read_exact(&amp;<span class="hljs-keyword">mut</span> hash_bytes)?;

        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> scripts = ScriptBuilder::new();
        scripts
        .push_opcode(Opcode::Num(<span class="hljs-number">1</span>))?
        .push_opcode(Opcode::PushBytes(<span class="hljs-number">32</span>))?
        .push_bytes(&amp;hash_bytes)?;

        <span class="hljs-literal">Ok</span>(scripts.build())
    }
}
</code></pre>
<p>8. Parse P2MS</p>
<pre><code class="lang-rust"><span class="hljs-keyword">impl</span> StandardScripts {
    <span class="hljs-comment">// .. previous code here</span>

    <span class="hljs-comment">/// Parse a P2MS.</span>
    <span class="hljs-comment">/// Also checks to see if the number of public keys parsed is equal to number of public keys requires</span>
    <span class="hljs-comment">/// or if the parsed public keys are less than the threshold</span>
    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">parse_p2ms</span></span>(bytes: &amp;<span class="hljs-keyword">mut</span> Cursor&lt;&amp;[<span class="hljs-built_in">u8</span>]&gt;) -&gt; io::<span class="hljs-built_in">Result</span>&lt;<span class="hljs-built_in">String</span>&gt; {
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> opcode_buffer = [<span class="hljs-number">0u8</span>; <span class="hljs-number">1</span>];
        bytes.read_exact(&amp;<span class="hljs-keyword">mut</span> opcode_buffer)?;
        <span class="hljs-keyword">let</span> threshold_opcode = Opcode::from_byte(opcode_buffer[<span class="hljs-number">0</span>]);

        <span class="hljs-keyword">match</span> threshold_opcode {
                Opcode::Num(_) | Opcode::OP_1 =&gt; {
                    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> script_builder = ScriptBuilder::new();
                    script_builder.push_opcode(threshold_opcode)?;
                    <span class="hljs-comment">// The number of public keys parsed</span>
                    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> pubkey_count = <span class="hljs-number">0u8</span>;
                    <span class="hljs-comment">// The number of public keys specified in the scriptSig</span>
                    <span class="hljs-keyword">let</span> parsed_pubkey_count: <span class="hljs-built_in">u8</span>;
                    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> pushbytes_buffer = <span class="hljs-built_in">Vec</span>::&lt;<span class="hljs-built_in">u8</span>&gt;::new();

                    <span class="hljs-keyword">loop</span> {
                        bytes.read_exact(&amp;<span class="hljs-keyword">mut</span> opcode_buffer)?;
                        <span class="hljs-keyword">let</span> current_opcode = Opcode::from_byte(opcode_buffer[<span class="hljs-number">0</span>]);

                        <span class="hljs-keyword">match</span> current_opcode {
                            Opcode::Num(value) =&gt; {
                            parsed_pubkey_count = value;
                            script_builder.push_opcode(current_opcode)?;
                            <span class="hljs-comment">//Break the loop if a `OP_1 to OP_16` is encountered</span>
                            <span class="hljs-keyword">break</span>;
                        }
                }
                Opcode::PushBytes(value) =&gt; {
                    <span class="hljs-keyword">let</span> new_position = bytes.position() <span class="hljs-keyword">as</span> <span class="hljs-built_in">usize</span> + value <span class="hljs-keyword">as</span> <span class="hljs-built_in">usize</span>;
                    <span class="hljs-keyword">let</span> read_bytes =
                    &amp;bytes.get_ref()[bytes.position() <span class="hljs-keyword">as</span> <span class="hljs-built_in">usize</span>..new_position];
                    pushbytes_buffer.extend_from_slice(read_bytes);

                    script_builder
                        .push_opcode(current_opcode)?
                        .push_bytes(&amp;pushbytes_buffer)?;

                    pushbytes_buffer.clear();
                    bytes.set_position(new_position <span class="hljs-keyword">as</span> <span class="hljs-built_in">u64</span>);
                    pubkey_count = pubkey_count.add(<span class="hljs-number">1</span>);
                }
                _ =&gt; {
                    <span class="hljs-keyword">return</span> Self::to_io_error(
                        <span class="hljs-string">"Invalid Script. Expected a PUSH_BYTES_* or OP_1..16"</span>,
                    )
                }
            }
        }

        <span class="hljs-keyword">if</span> pubkey_count.ne(&amp;parsed_pubkey_count) {
            <span class="hljs-keyword">return</span> Self::to_io_error(
                <span class="hljs-string">"Invalid Script. The number of public keys for multisignature is less than or greater than the script requirements."</span>,
            );
        }

        <span class="hljs-keyword">match</span> threshold_opcode {
            Opcode::Num(threshold_inner) =&gt; {
                <span class="hljs-keyword">if</span> parsed_pubkey_count.lt(&amp;threshold_inner) {
                    <span class="hljs-keyword">return</span> Self::to_io_error(
                        <span class="hljs-string">"Invalid Script. The number of public keys for multisignature is less the threshold."</span>,
                    );
                }
            }
            _ =&gt; (),
        }

        <span class="hljs-comment">// Parse next byte and check if it is OP_CHECKMULTISIG opcode</span>
        bytes.read_exact(&amp;<span class="hljs-keyword">mut</span> opcode_buffer)?;
        <span class="hljs-keyword">let</span> opcheck_multisig = Opcode::from_byte(opcode_buffer[<span class="hljs-number">0</span>]);

        <span class="hljs-keyword">if</span> opcheck_multisig.ne(&amp;Opcode::OP_CHECKMULTISIG) {
            <span class="hljs-keyword">return</span> Self::to_io_error(
                <span class="hljs-string">"Invalid Script. OP_CHECKMULTISIG opcode should be next"</span>,
            );
            }
            script_builder.push_opcode(Opcode::OP_CHECKMULTISIG)?;

            <span class="hljs-literal">Ok</span>(script_builder.build())
        }
        _ =&gt; Self::to_io_error(<span class="hljs-string">"Invalid Script."</span>),
        }
    }
}
</code></pre>
<p>Lastly, we need to test that our code works inside the main function in <code>main.rs</code> file and we assert that each outcome is successful using the <code>.is_ok()</code> method on <code>std::io::Result</code></p>
<pre><code class="lang-rust"><span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
    <span class="hljs-comment">// .. Previous code here</span>

    <span class="hljs-keyword">let</span> p2pk_bytes = hex!(<span class="hljs-string">"410000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ac"</span>);
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> p2pk = Cursor::new(p2pk_bytes.as_ref());
    <span class="hljs-keyword">let</span> outcome = StandardScripts::parse(&amp;<span class="hljs-keyword">mut</span> p2pk);
    <span class="hljs-built_in">assert!</span>(outcome.is_ok());
    dbg!(&amp;outcome.unwrap());

    <span class="hljs-keyword">let</span> p2pkh_bytes = hex!(<span class="hljs-string">"76a914000000000000000000000000000000000000000088ac"</span>);
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> p2pkh = Cursor::new(p2pkh_bytes.as_ref());
    <span class="hljs-keyword">let</span> outcome = StandardScripts::parse(&amp;<span class="hljs-keyword">mut</span> p2pkh);
    <span class="hljs-built_in">assert!</span>(outcome.is_ok());
    dbg!(&amp;outcome.unwrap());

    <span class="hljs-keyword">let</span> p2sh_bytes = hex!(<span class="hljs-string">"a914748284390f9e263a4b766a75d0633c50426eb87587"</span>);
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> p2sh = Cursor::new(p2sh_bytes.as_ref());
    <span class="hljs-keyword">let</span> outcome = StandardScripts::parse(&amp;<span class="hljs-keyword">mut</span> p2sh);
    <span class="hljs-built_in">assert!</span>(outcome.is_ok());
    dbg!(&amp;outcome.unwrap());

    <span class="hljs-keyword">let</span> op_return_bytes = hex!(<span class="hljs-string">"6a0b68656c6c6f20776f726c64"</span>);
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> op_return = Cursor::new(op_return_bytes.as_ref());
    <span class="hljs-keyword">let</span> outcome = StandardScripts::parse(&amp;<span class="hljs-keyword">mut</span> op_return);
    <span class="hljs-built_in">assert!</span>(outcome.is_ok());
    dbg!(&amp;outcome.unwrap());

    <span class="hljs-keyword">let</span> p2wpkh_bytes = hex!(<span class="hljs-string">"00140000000000000000000000000000000000000000"</span>);
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> p2wpkh = Cursor::new(p2wpkh_bytes.as_ref());
    <span class="hljs-keyword">let</span> outcome = StandardScripts::parse(&amp;<span class="hljs-keyword">mut</span> p2wpkh);
    <span class="hljs-built_in">assert!</span>(outcome.is_ok());
    dbg!(&amp;outcome.unwrap());

    <span class="hljs-keyword">let</span> p2wsh_bytes = hex!(<span class="hljs-string">"00200000000000000000000000000000000000000000000000000000000000000000"</span>);
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> p2wsh = Cursor::new(p2wsh_bytes.as_ref());
    <span class="hljs-keyword">let</span> outcome = StandardScripts::parse(&amp;<span class="hljs-keyword">mut</span> p2wsh);
    <span class="hljs-built_in">assert!</span>(outcome.is_ok());
    dbg!(&amp;outcome.unwrap());

    <span class="hljs-keyword">let</span> p2tr_bytes = hex!(<span class="hljs-string">"51200000000000000000000000000000000000000000000000000000000000000000"</span>);
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> p2tr = Cursor::new(p2tr_bytes.as_ref());
    <span class="hljs-keyword">let</span> outcome = StandardScripts::parse(&amp;<span class="hljs-keyword">mut</span> p2tr);
    <span class="hljs-built_in">assert!</span>(outcome.is_ok());
    dbg!(&amp;outcome.unwrap());

    <span class="hljs-keyword">let</span> p2ms_3_bytes = hex!(<span class="hljs-string">"524104d81fd577272bbe73308c93009eec5dc9fc319fc1ee2e7066e17220a5d47a18314578be2faea34b9f1f8ca078f8621acd4bc22897b03daa422b9bf56646b342a24104ec3afff0b2b66e8152e9018fe3be3fc92b30bf886b3487a525997d00fd9da2d012dce5d5275854adc3106572a5d1e12d4211b228429f5a7b2f7ba92eb0475bb14104b49b496684b02855bc32f5daefa2e2e406db4418f3b86bca5195600951c7d918cdbe5e6d3736ec2abf2dd7610995c3086976b2c0c7b4e459d10b34a316d5a5e753ae"</span>);
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> p2ms_3 = Cursor::new(p2ms_3_bytes.as_ref());
    <span class="hljs-keyword">let</span> outcome = StandardScripts::parse(&amp;<span class="hljs-keyword">mut</span> p2ms_3);
    <span class="hljs-built_in">assert!</span>(outcome.is_ok());
    dbg!(&amp;outcome.unwrap());

    <span class="hljs-keyword">let</span> p2ms_2_bytes = hex!(<span class="hljs-string">"51210000000000000000000000000000000000000000000000000000000000000000002100000000000000000000000000000000000000000000000000000000000000000052ae"</span>);
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> p2ms_2 = Cursor::new(p2ms_2_bytes.as_ref());
    <span class="hljs-keyword">let</span> outcome = StandardScripts::parse(&amp;<span class="hljs-keyword">mut</span> p2ms_2);
    <span class="hljs-built_in">assert!</span>(outcome.is_ok());
    dbg!(&amp;outcome.unwrap());
}
</code></pre>
<p>That’s it. We have successfully parsed the input <code>scriptSig</code> part.</p>
<h4 id="heading-references">References</h4>
<ol>
<li><p>Repository — <a target="_blank" href="https://github.com/448-OG/BitcoinTransactions">https://github.com/448-OG/BitcoinTransactions</a></p>
</li>
<li><p><a target="_blank" href="https://wiki.bitcoinsv.io/index.php/Opcodes_used_in_Bitcoin_Script">https://wiki.bitcoinsv.io/index.php/Opcodes_used_in_Bitcoin_Script</a></p>
</li>
<li><p><a target="_blank" href="https://learnmeabitcoin.com/technical/transaction/input/scriptsig/">https://learnmeabitcoin.com/technical/transaction/input/scriptsig/</a></p>
</li>
<li><p>Bitcoin scripts — <a target="_blank" href="https://github.com/jimmysong/programmingbitcoin/blob/master/ch13.asciidoc">https://github.com/jimmysong/programmingbitcoin/blob/master/ch13.asciidoc</a></p>
</li>
</ol>
]]></content:encoded></item><item><title><![CDATA[Parsing Bitcoin Transactions in Rust Programming Language Standard Library]]></title><description><![CDATA[A series of articles on bitcoin transactions — Part 1
Bitcoin transactions are used to transfer value or inscribe data onchain in an immutable way. In this series of articles we will discuss how to encode and decode a raw hex transaction, contructing...]]></description><link>https://448.africa/parsing-bitcoin-transactions-in-rust-programming-language-standard-library-20c06a23a564</link><guid isPermaLink="true">https://448.africa/parsing-bitcoin-transactions-in-rust-programming-language-standard-library-20c06a23a564</guid><dc:creator><![CDATA[448-OG]]></dc:creator><pubDate>Fri, 08 Mar 2024 08:55:32 GMT</pubDate><content:encoded><![CDATA[<p><strong>A series of articles on bitcoin transactions — Part 1</strong></p>
<p>Bitcoin transactions are used to transfer value or inscribe data onchain in an immutable way. In this series of articles we will discuss how to encode and decode a raw hex transaction, contructing a Bitcoin transaction and scripts.</p>
<h3 id="heading-part-1-hex-encoded-bitcoin-transactions">Part 1. Hex Encoded Bitcoin Transactions</h3>
<p>Bitcoin transactions can be encoded in raw hexadecimal format. The hexadecimal format is base16 which is represented by characters <code>0–9</code> and <code>A-F</code>which create the hex alphabet <code>0123456789ABCDEF</code>. Each character represents two bytes of data.</p>
<p>Let’s look at how to decode the bitcoin transaction<br /><code>010000000269adb42422fb021f38da0ebe12a8d2a14c0fe484bcb0b7cb365841871f2d5e24000000006a4730440220199a6aa56306cebcdacd1eba26b55eaf6f92eb46eb90d1b7e7724bacbe1d19140220101c0d46e033361c60536b6989efdd6fa692265fcda164676e2f49885871038a0121039ac8bac8f6d916b8a85b458e087e0cd07e6a76a6bfdde9bb766b17086d9a5c8affffffff69adb42422fb021f38da0ebe12a8d2a14c0fe484bcb0b7cb365841871f2d5e24010000006b48304502210084ec4323ed07da4af6462091b4676250c377527330191a3ff3f559a88beae2e2022077251392ec2f52327cb7296be89cc001516e4039badd2ad7bbc950c4c1b6d7cc012103b9b554e25022c2ae549b0c30c18df0a8e0495223f627ae38df0992efb4779475ffffffff0118730100000000001976a9140ce17649c1306c291ca9e587f8793b5b06563cea88ac00000000</code></p>
<p>We will be using the Rust standard library without any external crates.</p>
<p>First create a cargo project.</p>
<p>cargo new Bitcoin-Tx-Hex --name btc-tx-hex</p>
<p>This creates a crate called <code>btc-tx-hex in the directory called Bitcoin-Tx-Hex.</code></p>
<p>In the <code>main.rs</code> file create a variable called <code>raw_tx</code> to represent our hex encoded transaction.</p>
<pre><code class="lang-rust"><span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
<span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> raw_tx = <span class="hljs-string">"010000000269adb42422fb021f38da0ebe12a8d2a14c0fe484bcb0b7cb365841871f2d5e24000000006a4730440220199a6aa56306cebcdacd1eba26b55eaf6f92eb46eb90d1b7e7724bacbe1d19140220101c0d46e033361c60536b6989efdd6fa692265fcda164676e2f49885871038a0121039ac8bac8f6d916b8a85b458e087e0cd07e6a76a6bfdde9bb766b17086d9a5c8affffffff69adb42422fb021f38da0ebe12a8d2a14c0fe484bcb0b7cb365841871f2d5e24010000006b48304502210084ec4323ed07da4af6462091b4676250c377527330191a3ff3f559a88beae2e2022077251392ec2f52327cb7296be89cc001516e4039badd2ad7bbc950c4c1b6d7cc012103b9b554e25022c2ae549b0c30c18df0a8e0495223f627ae38df0992efb4779475ffffffff0118730100000000001976a9140ce17649c1306c291ca9e587f8793b5b06563cea88ac00000000"</span>;
}
</code></pre>
<p>Bitcoin hex encoded transactions have four concatenated parts</p>
<p><code>version | inputs | outputs | locktime</code></p>
<h4 id="heading-version">Version</h4>
<p>The Bitcoin version is represented in four bytes which is a <code>u32</code> in Rust. Create a new module called <code>version.rs</code> and import it into the <code>main.rs</code> file.</p>
<pre><code class="lang-rust"><span class="hljs-keyword">mod</span> version;
<span class="hljs-keyword">pub</span> <span class="hljs-keyword">use</span> version::*;

<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
    <span class="hljs-comment">//... previous code</span>
}
</code></pre>
<p>In our <code>version.rs</code> file let’s create a struct to parse our version</p>
<pre><code class="lang-rust"><span class="hljs-comment">/// Bitcoin transactions version one and two are supported</span>
<span class="hljs-comment">/// by Bitcoin core. A node must pre-configure a transaction</span>
<span class="hljs-comment">/// version higher than version 2 and this transaction is</span>
<span class="hljs-comment">/// not guaranteed to be propagated by all Bitcoin core.</span>
<span class="hljs-meta">#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Default)]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">enum</span> <span class="hljs-title">TxVersion</span></span> {
    <span class="hljs-comment">/// This will be treated as the default version</span>
    <span class="hljs-comment">/// when calling TxVersion::default()</span>
    <span class="hljs-meta">#[default]</span>
    One,
    <span class="hljs-comment">/// The Bitcoin transaction version two which allows</span>
    <span class="hljs-comment">/// using the OPCODE `OP_CHECKSEQUENCEVERIFY` which allows</span>
    <span class="hljs-comment">/// setting relative locktime for spending outputs.</span>
    Two,
    <span class="hljs-comment">/// Custom transaction version which is considered non-standard,</span>
    <span class="hljs-comment">/// must be set by the Bitcoin node operator and is not guaranteed</span>
    <span class="hljs-comment">/// to be accepted by other nodes running Bitcoin core software</span>
    Custom(<span class="hljs-built_in">u32</span>),
}
</code></pre>
<p>Next we implement our encoder and decoder; to and from bytes for the <code>TxVersion</code> . The version is in <code>little-endian</code> format which is also called <code>reverse byte order</code> .</p>
<pre><code class="lang-rust"><span class="hljs-keyword">impl</span> TxVersion {
    <span class="hljs-comment">/// This converts our version to bytes.</span>
    <span class="hljs-comment">/// Since version number is four bytes little-endian we use `u32::to_le_bytes()`</span>
    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">to_bytes</span></span>(&amp;<span class="hljs-keyword">self</span>) -&gt; [<span class="hljs-built_in">u8</span>; <span class="hljs-number">4</span>] {
        <span class="hljs-keyword">match</span> <span class="hljs-keyword">self</span> {
        Self::One =&gt; <span class="hljs-number">1u32</span>.to_le_bytes(),
        Self::Two =&gt; <span class="hljs-number">2u32</span>.to_le_bytes(),
        Self::Custom(version) =&gt; version.to_le_bytes(),
        }
    }

    <span class="hljs-comment">/// This converts from bytes to `Self`</span>
    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">from_bytes</span></span>(bytes: [<span class="hljs-built_in">u8</span>; <span class="hljs-number">4</span>]) -&gt; <span class="hljs-keyword">Self</span> {
        <span class="hljs-keyword">let</span> parsed = <span class="hljs-built_in">u32</span>::from_le_bytes(bytes);

        <span class="hljs-keyword">match</span> parsed {
            <span class="hljs-number">1u32</span> =&gt; Self::One,
            <span class="hljs-number">2u32</span> =&gt; Self::Two,
            _ =&gt; Self::Custom(parsed),
        }
    }
}
</code></pre>
<p>Next we write a simple test to check the correctness of our parser.</p>
<pre><code class="lang-rust"><span class="hljs-meta">#[cfg(test)]</span>
<span class="hljs-keyword">mod</span> tx_sanity_checks {
    <span class="hljs-keyword">use</span> crate::TxVersion;

    <span class="hljs-meta">#[test]</span>
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">tx_version</span></span>() {
        <span class="hljs-built_in">assert_eq!</span>([<span class="hljs-number">1u8</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>], TxVersion::One.to_bytes());
        <span class="hljs-built_in">assert_eq!</span>([<span class="hljs-number">2u8</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>], TxVersion::Two.to_bytes());
        <span class="hljs-built_in">assert_eq!</span>([<span class="hljs-number">30u8</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>], TxVersion::Custom(<span class="hljs-number">30</span>).to_bytes());

        <span class="hljs-built_in">assert_eq!</span>(TxVersion::One, TxVersion::from_bytes([<span class="hljs-number">1u8</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>]));
        <span class="hljs-built_in">assert_eq!</span>(TxVersion::Two, TxVersion::from_bytes([<span class="hljs-number">2u8</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>]));
        <span class="hljs-built_in">assert_eq!</span>(
        TxVersion::Custom(<span class="hljs-number">30</span>),
        TxVersion::from_bytes([<span class="hljs-number">30u8</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>])
        );
    }
}
</code></pre>
<p>Let’s run our test with the command</p>
<p><code>cargo test --verbose --all-features</code></p>
<p>Our test passes with the following output</p>
<pre><code class="lang-bash"><span class="hljs-comment"># ... Other log data here</span>
<span class="hljs-comment"># Below is the part we are interested in</span>
running 1 <span class="hljs-built_in">test</span>
<span class="hljs-built_in">test</span> version::tx_sanity_checks::tx_version ... ok
</code></pre>
<p>After parsing the version, we need to get the number of outputs in the output section. To do this, we parse the first byte into a Bitcoin <code>VarInt</code> .</p>
<h4 id="heading-varint">VarInt</h4>
<p>A <strong>VarInt</strong> (short for “Variable Integer”) is a crucial format used in Bitcoin to indicate the lengths of fields within transactions, blocks, and peer-to-peer network data. Learn more about <code>VarInt</code> at <a target="_blank" href="https://web.archive.org/web/20230331170203/https://learnmeabitcoin.com/technical/varint">https://web.archive.org/web/20230331170203/https://learnmeabitcoin.com/technical/varint</a></p>
<p><strong>NOTE:</strong> That a <strong>VarInt</strong> of <code>8 bytes</code> is beyond the maximum block size of a Bitcoin block and therefore never used in a Bitcoin transaction.</p>
<p>In our Rust VarInt parser, we will use a <code>std::io::Cursor</code> to read either 0, 2, 4 or 8 bytes from the current position in our byte length field.</p>
<p><strong>Reading</strong>:</p>
<ul>
<li><p>0 bytes will be treated as a <code>u8</code></p>
</li>
<li><p>2 bytes will be treated as a <code>u16</code></p>
</li>
<li><p>4 bytes will be treated as a <code>u32</code></p>
</li>
<li><p>8 bytes will be treated as a <code>u64</code></p>
</li>
</ul>
<p><strong>Where:</strong></p>
<ul>
<li><p>0 bytes is represented by a <code>u8</code> of <code>&lt;= 252</code></p>
</li>
<li><p>2 bytes is represented by a <code>u8</code> of <code>253</code></p>
</li>
<li><p>4 bytes is represented by a <code>u8</code> of <code>254</code></p>
</li>
<li><p>8 bytes is represented by a <code>u8</code> of <code>255</code></p>
</li>
</ul>
<p>Create a new module in our <code>src</code> directory called <code>varint.rs then in</code> then import our module in the <code>src/main.rs</code> file.</p>
<pre><code class="lang-rust"><span class="hljs-comment">// ... Previous imports here</span>
<span class="hljs-keyword">mod</span> varint;
<span class="hljs-keyword">pub</span> <span class="hljs-keyword">use</span> varint::*;

<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
    <span class="hljs-comment">// ... Previous code here</span>
}
</code></pre>
<p>In our <code>src/varint.rs</code> file.</p>
<pre><code class="lang-rust"><span class="hljs-comment">// We are using a Cursor to have a position</span>
<span class="hljs-comment">// of up to the index that the bytes have been</span>
<span class="hljs-comment">// read. This is convinient instead of using</span>
<span class="hljs-comment">// a counter to keep track of everything</span>
<span class="hljs-comment">// which can be cumbersome since we need to</span>
<span class="hljs-comment">// keep track of the length of bytes t</span>
<span class="hljs-keyword">use</span> std::io::{<span class="hljs-keyword">self</span>, Cursor, Read};

<span class="hljs-comment">/// We create a `VarInt` struct to hold methods for calculating</span>
<span class="hljs-comment">/// the number of bytes in the `VarInt``</span>
<span class="hljs-meta">#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">VarInt</span></span>;

<span class="hljs-keyword">impl</span> VarInt {
    <span class="hljs-comment">/// This converts our VarInt byte into the number of bytes that we need to parse</span>
    <span class="hljs-keyword">pub</span> <span class="hljs-keyword">const</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">parse</span></span>(byte: <span class="hljs-built_in">u8</span>) -&gt; <span class="hljs-built_in">usize</span> {
        <span class="hljs-keyword">match</span> byte {
            <span class="hljs-comment">// 0 to 252 is treated as a Rust u8 which is 1 byte long</span>
            <span class="hljs-number">0</span>..=<span class="hljs-number">252</span> =&gt; <span class="hljs-number">1</span>,
            <span class="hljs-comment">// 253 is treated as a Rust u16 which is 2 bytes long</span>
            <span class="hljs-number">253</span> =&gt; <span class="hljs-number">2</span>,
            <span class="hljs-comment">// 253 is treated as a Rust u32 which is 4 bytes long</span>
            <span class="hljs-number">254</span> =&gt; <span class="hljs-number">4</span>,
            <span class="hljs-comment">// 253 is treated as a Rust u64 which is 8 bytes long</span>
            <span class="hljs-number">255</span> =&gt; <span class="hljs-number">8</span>,
        }
    }

    <span class="hljs-comment">/// Given a Cursor of bytes, we read the current or next number of bytes</span>
    <span class="hljs-comment">/// then convert them into an integer</span>
    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">integer</span></span>(byte_len: <span class="hljs-built_in">usize</span>, bytes: &amp;<span class="hljs-keyword">mut</span> Cursor&lt;&amp;[<span class="hljs-built_in">u8</span>]&gt;) -&gt; io::<span class="hljs-built_in">Result</span>&lt;<span class="hljs-built_in">usize</span>&gt; {
        <span class="hljs-keyword">let</span> outcome = <span class="hljs-keyword">match</span> byte_len {
                <span class="hljs-number">1</span> =&gt; {
                <span class="hljs-comment">// NOTE - Since we are reading one value and the Cursor always advances</span>
                <span class="hljs-comment">// by the number of bytes read, we reset the cursor to the last position</span>
                <span class="hljs-comment">// in order to parse that one byte. First we get the current cursor</span>
                <span class="hljs-comment">// position using `bytes.position()` and then subtract 1</span>
                bytes.set_position(bytes.position() - <span class="hljs-number">1</span>);

                <span class="hljs-comment">// A u8 has array length of 1</span>
                <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> buffer = [<span class="hljs-number">0u8</span>; <span class="hljs-number">1</span>];
                <span class="hljs-comment">// Read exactly one byte</span>
                bytes.read_exact(&amp;<span class="hljs-keyword">mut</span> buffer)?;

                buffer[<span class="hljs-number">0</span>] <span class="hljs-keyword">as</span> <span class="hljs-built_in">usize</span>
            }
            <span class="hljs-number">2</span> =&gt; {
                <span class="hljs-comment">// A u16 has array length of 2</span>
                <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> buffer = [<span class="hljs-number">0u8</span>; <span class="hljs-number">2</span>];
                <span class="hljs-comment">// Read exactly two bytes</span>
                bytes.read_exact(&amp;<span class="hljs-keyword">mut</span> buffer)?;

                <span class="hljs-built_in">u16</span>::from_le_bytes(buffer) <span class="hljs-keyword">as</span> <span class="hljs-built_in">usize</span>
            }
            <span class="hljs-number">4</span> =&gt; {
                <span class="hljs-comment">// A u32 has array length of 4</span>
                <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> buffer = [<span class="hljs-number">0u8</span>; <span class="hljs-number">4</span>];
                <span class="hljs-comment">// Read exactly four bytes</span>
                bytes.read_exact(&amp;<span class="hljs-keyword">mut</span> buffer)?;

                <span class="hljs-built_in">u32</span>::from_le_bytes(buffer) <span class="hljs-keyword">as</span> <span class="hljs-built_in">usize</span>
            }
            <span class="hljs-number">8</span> =&gt; {
                <span class="hljs-comment">// A u32 has array length of 8</span>
                <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> buffer = [<span class="hljs-number">0u8</span>; <span class="hljs-number">8</span>];
                <span class="hljs-comment">// Read exactly eight bytes</span>
                bytes.read_exact(&amp;<span class="hljs-keyword">mut</span> buffer)?;

                <span class="hljs-built_in">u64</span>::from_le_bytes(buffer) <span class="hljs-keyword">as</span> <span class="hljs-built_in">usize</span>
            }
            _ =&gt; {
                    <span class="hljs-comment">// All other values are not supported and we return an error to</span>
                    <span class="hljs-comment">// indicate this</span>
                    <span class="hljs-keyword">return</span> <span class="hljs-literal">Err</span>(std::io::Error::new(
                    std::io::ErrorKind::NotFound,
                    <span class="hljs-string">"The byte length specified is not supported"</span>,
                    ));
                }
            };

        <span class="hljs-literal">Ok</span>(outcome)
    }
}
</code></pre>
<p>In the same file, we write tests to check if our <code>VarInt</code> is being parsed correctly or does the parse resolve to an error</p>
<pre><code class="lang-rust"><span class="hljs-meta">#[cfg(test)]</span>
<span class="hljs-keyword">mod</span> varint_sanity_checks {
    <span class="hljs-keyword">use</span> crate::VarInt;
    <span class="hljs-keyword">use</span> std::io::{Cursor, Read};

    <span class="hljs-meta">#[test]</span>
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">varint_zero_to_252</span></span>() {
        <span class="hljs-keyword">let</span> bytes = [<span class="hljs-number">0u8</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">1</span>];
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> bytes = Cursor::new(bytes.as_slice());

        <span class="hljs-comment">// Simulate version bytes by skipping 4 bytes</span>
        bytes.set_position(<span class="hljs-number">4</span>);

        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> varint_byte = [<span class="hljs-number">0u8</span>; <span class="hljs-number">1</span>];
        bytes.read_exact(&amp;<span class="hljs-keyword">mut</span> varint_byte).unwrap();
        <span class="hljs-keyword">let</span> varint_byte_len = VarInt::parse(varint_byte[<span class="hljs-number">0</span>]);
        <span class="hljs-keyword">let</span> varint_len = VarInt::integer(varint_byte_len, &amp;<span class="hljs-keyword">mut</span> bytes);
        <span class="hljs-built_in">assert!</span>(varint_len.is_ok());
        <span class="hljs-built_in">assert_eq!</span>(<span class="hljs-number">1usize</span>, varint_len.unwrap());
    }

    <span class="hljs-meta">#[test]</span>
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">varint_253</span></span>() {
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> bytes = <span class="hljs-built_in">vec!</span>[<span class="hljs-number">0u8</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">253</span>];
        <span class="hljs-keyword">let</span> placeholder_bytes = [<span class="hljs-number">1u8</span>; <span class="hljs-number">257</span>];
        bytes.extend_from_slice(&amp;placeholder_bytes);
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> bytes = Cursor::new(bytes.as_slice());

        <span class="hljs-comment">// Simulate version bytes by skipping 4 bytes</span>
        bytes.set_position(<span class="hljs-number">4</span>);

        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> varint_byte = [<span class="hljs-number">0u8</span>; <span class="hljs-number">1</span>];
        bytes.read_exact(&amp;<span class="hljs-keyword">mut</span> varint_byte).unwrap();
        <span class="hljs-keyword">let</span> varint_byte_len = VarInt::parse(varint_byte[<span class="hljs-number">0</span>]);
        <span class="hljs-keyword">let</span> varint_len = VarInt::integer(varint_byte_len, &amp;<span class="hljs-keyword">mut</span> bytes);
        <span class="hljs-built_in">assert!</span>(varint_len.is_ok());
        <span class="hljs-built_in">assert_eq!</span>(<span class="hljs-number">257usize</span>, varint_len.unwrap());    
    }

    <span class="hljs-meta">#[test]</span>
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">varint_254</span></span>() {
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> bytes = <span class="hljs-built_in">vec!</span>[<span class="hljs-number">0u8</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">254</span>];
        <span class="hljs-keyword">let</span> placeholder_bytes = [<span class="hljs-number">1u8</span>; <span class="hljs-number">40</span>];
        bytes.extend_from_slice(&amp;placeholder_bytes);
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> bytes = Cursor::new(bytes.as_slice());

        <span class="hljs-comment">// Simulate version bytes by skipping 4 bytes</span>
        bytes.set_position(<span class="hljs-number">4</span>);

        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> varint_byte = [<span class="hljs-number">0u8</span>; <span class="hljs-number">1</span>];
        bytes.read_exact(&amp;<span class="hljs-keyword">mut</span> varint_byte).unwrap();
        <span class="hljs-keyword">let</span> varint_byte_len = VarInt::parse(varint_byte[<span class="hljs-number">0</span>]);
        <span class="hljs-keyword">let</span> varint_len = VarInt::integer(varint_byte_len, &amp;<span class="hljs-keyword">mut</span> bytes);
        <span class="hljs-built_in">assert!</span>(varint_len.is_ok());
        <span class="hljs-built_in">assert_eq!</span>(<span class="hljs-number">16843009usize</span>, varint_len.unwrap());
    }    

    <span class="hljs-meta">#[test]</span>
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">varint_255</span></span>() {
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> bytes = <span class="hljs-built_in">vec!</span>[<span class="hljs-number">0u8</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">255</span>];
        <span class="hljs-keyword">let</span> placeholder_bytes = [<span class="hljs-number">1u8</span>; <span class="hljs-number">40</span>];
        bytes.extend_from_slice(&amp;placeholder_bytes);
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> bytes = Cursor::new(bytes.as_slice());

        <span class="hljs-comment">// Simulate version bytes by skipping 4 bytes</span>
        bytes.set_position(<span class="hljs-number">4</span>);

        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> varint_byte = [<span class="hljs-number">0u8</span>; <span class="hljs-number">1</span>];
        bytes.read_exact(&amp;<span class="hljs-keyword">mut</span> varint_byte).unwrap();
        <span class="hljs-keyword">let</span> varint_byte_len = VarInt::parse(varint_byte[<span class="hljs-number">0</span>]);
        <span class="hljs-keyword">let</span> varint_len = VarInt::integer(varint_byte_len, &amp;<span class="hljs-keyword">mut</span> bytes);
        <span class="hljs-built_in">assert!</span>(varint_len.is_ok());
        <span class="hljs-built_in">assert_eq!</span>(<span class="hljs-number">72340172838076673usize</span>, varint_len.unwrap());
    }
}
</code></pre>
<p>Next we create our transaction parser by creating a module called <code>tx.rs</code> in the <code>src</code> directory and then registering our module in the <code>src/main.rs</code> file.</p>
<pre><code class="lang-rust"><span class="hljs-comment">// ... Previous imports here</span>

<span class="hljs-keyword">mod</span> tx;
<span class="hljs-keyword">pub</span> <span class="hljs-keyword">use</span> tx::*;

<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
    <span class="hljs-comment">//... Previous code here</span>
}
</code></pre>
<p>In our <code>src/tx.rs</code> file</p>
<p>Bitcoin transaction have inputs and outputs so we create structs to represent them.</p>
<pre><code class="lang-rust"><span class="hljs-comment">/// Our transaction inputs</span>
<span class="hljs-meta">#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">TxInput</span></span> {
    <span class="hljs-comment">// The SHA256 bytes of the previous transaction ID</span>
    <span class="hljs-comment">// of the unspent UTXO</span>
    previous_tx_id: [<span class="hljs-built_in">u8</span>; <span class="hljs-number">32</span>],
    <span class="hljs-comment">// Previous index of the previous transaction output</span>
    previous_output_index: <span class="hljs-built_in">u32</span>,
    <span class="hljs-comment">// The scriptSig</span>
    signature_script: <span class="hljs-built_in">Vec</span>&lt;<span class="hljs-built_in">u8</span>&gt;,
    <span class="hljs-comment">// The sequence number</span>
    sequence_number: <span class="hljs-built_in">u32</span>,
}

<span class="hljs-comment">/// Transaction outputs</span>
<span class="hljs-meta">#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">TxOutput</span></span> {
    <span class="hljs-comment">// Amount in satoshis</span>
    amount: <span class="hljs-built_in">u64</span>,
    <span class="hljs-comment">// The locking script which gives conditions for spending the bitcoins</span>
    locking_script: <span class="hljs-built_in">Vec</span>&lt;<span class="hljs-built_in">u8</span>&gt;,
}
</code></pre>
<p>Now we combine the <code>TxInput</code>, <code>TxOutput</code> , <code>VarInt</code> and <code>TxVersion</code> as part of the transaction struct</p>
<pre><code class="lang-rust"><span class="hljs-comment">// Import our modules</span>
<span class="hljs-keyword">use</span> crate::{TxVersion, VarInt};
<span class="hljs-keyword">use</span> std::io::{Cursor, Read, <span class="hljs-keyword">self</span>};

<span class="hljs-comment">/// The structure of the Bitcoin transaction</span>
<span class="hljs-meta">#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Default)]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">BtcTx</span></span> {
    <span class="hljs-comment">// The version of the Bitcoin transaction</span>
    version: TxVersion,
    <span class="hljs-comment">// A transaction can have multiple inputs</span>
    inputs: <span class="hljs-built_in">Vec</span>,
    <span class="hljs-comment">// A transaction can have multiple outputs</span>
    outputs: <span class="hljs-built_in">Vec</span>,
    <span class="hljs-comment">// The locktime for the transaction parsed</span>
    <span class="hljs-comment">// from 4 bytes into a u32</span>
    locktime: <span class="hljs-built_in">u32</span>,
}
</code></pre>
<p>Next we implement methods to parse our version, inputs, outputs and locktime into our <code>BtcTx</code></p>
<pre><code class="lang-rust"><span class="hljs-keyword">impl</span> BtcTx {
    <span class="hljs-comment">/// Convert hex bytes into a Transaction struct. This calls all other</span>
    <span class="hljs-comment">/// methods to parse the version, inputs, outputs and locktime.</span>
    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">from_hex_bytes</span></span>(bytes: <span class="hljs-keyword">impl</span> <span class="hljs-built_in">AsRef</span>&lt;[<span class="hljs-built_in">u8</span>]&gt;) -&gt; io::<span class="hljs-built_in">Result</span>&lt;<span class="hljs-keyword">Self</span>&gt; {
        <span class="hljs-comment">// Instantiate a new cursor to hold the bytes.</span>
        <span class="hljs-comment">// The cursor's position advances whenever we read</span>
        <span class="hljs-comment">// bytes allowing us to simplify the logic</span>
        <span class="hljs-comment">// instead of using a counter to keep track of bytes read</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> bytes = Cursor::new(bytes.as_ref());

        <span class="hljs-comment">// The version number is always a 4 byte array</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> version_bytes = [<span class="hljs-number">0u8</span>; <span class="hljs-number">4</span>];
        <span class="hljs-comment">// Read exactly 4 bytes and advance the cursor to the 4th byte</span>
        bytes.read_exact(&amp;<span class="hljs-keyword">mut</span> version_bytes)?;
        <span class="hljs-comment">// Get the transaction version from the bytes</span>
        <span class="hljs-keyword">let</span> version = TxVersion::from_bytes(version_bytes);        

        <span class="hljs-comment">// Get a vector of inputs by calling the `Self::get_inputs()` method</span>
        <span class="hljs-keyword">let</span> inputs = BtcTx::get_inputs(&amp;<span class="hljs-keyword">mut</span> bytes)?;
        <span class="hljs-comment">// Get a vector of outputs by calling the `Self::get_outputs()` method</span>
        <span class="hljs-keyword">let</span> outputs = BtcTx::get_outputs(&amp;<span class="hljs-keyword">mut</span> bytes)?;
        <span class="hljs-comment">// Get a vector of inputs by calling the `Self::locktime()` method</span>
        <span class="hljs-keyword">let</span> locktime = BtcTx::locktime(&amp;<span class="hljs-keyword">mut</span> bytes)?;    

        <span class="hljs-literal">Ok</span>(BtcTx {
            version,
            inputs,
            outputs,
            locktime,
        })
    }

    <span class="hljs-comment">/// Get all inputs from the current position of the `Cursor`.</span>
    <span class="hljs-comment">/// This method decodes the number of inputs by first decoding the</span>
    <span class="hljs-comment">/// `varint` and then looping number of inputs calling</span>
    <span class="hljs-comment">/// `Self::input_decoder()` on each iteration.</span>
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">get_inputs</span></span>(bytes: &amp;<span class="hljs-keyword">mut</span> Cursor&lt;&amp;[<span class="hljs-built_in">u8</span>]&gt;) -&gt; io::<span class="hljs-built_in">Result</span>&lt;<span class="hljs-built_in">Vec</span>&gt; {
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> varint_len = [<span class="hljs-number">0u8</span>];
        bytes.read_exact(&amp;<span class="hljs-keyword">mut</span> varint_len)?;

        <span class="hljs-keyword">let</span> varint_byte_len = VarInt::parse(varint_len[<span class="hljs-number">0</span>]);
        <span class="hljs-keyword">let</span> no_of_inputs = VarInt::integer(varint_byte_len, bytes)?;

        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> inputs = <span class="hljs-built_in">Vec</span>::::new();

        (<span class="hljs-number">0</span>..no_of_inputs).into_iter().for_each(|_| {
        inputs.push(BtcTx::input_decoder(bytes).unwrap());
        });

        <span class="hljs-literal">Ok</span>(inputs)
    }    

    <span class="hljs-comment">// Decodes an input from current `Cursor` position.</span>
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">input_decoder</span></span>(bytes: &amp;<span class="hljs-keyword">mut</span> Cursor&lt;&amp;[<span class="hljs-built_in">u8</span>]&gt;) -&gt; io::<span class="hljs-built_in">Result</span> {
        <span class="hljs-comment">// The previous transaction ID is always a SHA256 hash converted to a 32 byte array</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> previous_tx_id = [<span class="hljs-number">0u8</span>; <span class="hljs-number">32</span>];
        <span class="hljs-comment">// Read exactly 32 bytes and advance the cursor to the end of the 32 byte array</span>
        bytes.read_exact(&amp;<span class="hljs-keyword">mut</span> previous_tx_id)?;
        <span class="hljs-comment">// The transaction ID in hex format is in network byte order so we reverse</span>
        <span class="hljs-comment">// it to little endian</span>
        previous_tx_id.reverse();

        <span class="hljs-comment">//Previous transaction index is 4 bytes long which is a Rust u32</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> previous_tx_index_bytes = [<span class="hljs-number">0u8</span>; <span class="hljs-number">4</span>];
        bytes.read_exact(&amp;<span class="hljs-keyword">mut</span> previous_tx_index_bytes)?;
        <span class="hljs-comment">// Convert the read 4 bytes to a u32</span>
        <span class="hljs-keyword">let</span> previous_output_index = <span class="hljs-built_in">u32</span>::from_le_bytes(previous_tx_index_bytes);

        <span class="hljs-comment">// Get the length of the scriptSig</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> signature_script_size = [<span class="hljs-number">0u8</span>];
        bytes.read_exact(&amp;<span class="hljs-keyword">mut</span> signature_script_size)?;
        <span class="hljs-comment">// Parse the length VarInt</span>
        <span class="hljs-keyword">let</span> varint_byte_len = VarInt::parse(signature_script_size[<span class="hljs-number">0</span>]);
        <span class="hljs-comment">// Get the length by converting VarInt into an integer by calling `integer`</span>
        <span class="hljs-keyword">let</span> integer_from_varint = VarInt::integer(varint_byte_len, bytes)?;

        <span class="hljs-comment">// Buffer to hold the signature script</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> signature_script = <span class="hljs-built_in">Vec</span>::&lt;<span class="hljs-built_in">u8</span>&gt;::new();
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> sig_buf = [<span class="hljs-number">0u8</span>; <span class="hljs-number">1</span>];
        <span class="hljs-comment">// Since we are using a cursor, we iterate in order to advance</span>
        <span class="hljs-comment">// the cursor in each iteration</span>
        (<span class="hljs-number">0</span>..integer_from_varint).for_each(|_| {
        bytes.read_exact(&amp;<span class="hljs-keyword">mut</span> sig_buf).unwrap();

        signature_script.extend_from_slice(&amp;sig_buf);
        });

        <span class="hljs-comment">// The sequence number is a u32 (4 bytes long)</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> sequence_num_bytes = [<span class="hljs-number">0u8</span>; <span class="hljs-number">4</span>];
        bytes.read_exact(&amp;<span class="hljs-keyword">mut</span> sequence_num_bytes)?;
        <span class="hljs-comment">// Convert the sequence number to a integer</span>
        <span class="hljs-keyword">let</span> sequence_number = <span class="hljs-built_in">u32</span>::from_le_bytes(sequence_num_bytes);    

        <span class="hljs-literal">Ok</span>(TxInput {
            previous_tx_id,
            previous_output_index,
            signature_script,
            sequence_number,
        })
    }    

    <span class="hljs-comment">/// Get the outputs after all inputs have been parsed.</span>
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">get_outputs</span></span>(bytes: &amp;<span class="hljs-keyword">mut</span> Cursor&lt;&amp;[<span class="hljs-built_in">u8</span>]&gt;) -&gt; io::<span class="hljs-built_in">Result</span>&lt;<span class="hljs-built_in">Vec</span>&gt; {
        <span class="hljs-comment">// Get the number of outputs by reading our VarInt</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> num_of_output_bytes = [<span class="hljs-number">0u8</span>; <span class="hljs-number">1</span>];
        bytes.read_exact(&amp;<span class="hljs-keyword">mut</span> num_of_output_bytes)?;
        <span class="hljs-keyword">let</span> var_int_byte_length = VarInt::parse(num_of_output_bytes[<span class="hljs-number">0</span>]);
        <span class="hljs-comment">// Convert our VarInt to an integer</span>
        <span class="hljs-keyword">let</span> num_of_outputs = VarInt::integer(var_int_byte_length, bytes)?;

        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> outputs = <span class="hljs-built_in">Vec</span>::::new();

        <span class="hljs-comment">// Iterate over number of outputs</span>
        (<span class="hljs-number">0</span>..num_of_outputs).into_iter().for_each(|_| {
        <span class="hljs-comment">// The first value of the output is the amount in satoshis</span>
        <span class="hljs-comment">// which is 8 bytes long (Rust u64)</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> satoshis_as_bytes = [<span class="hljs-number">0u8</span>; <span class="hljs-number">8</span>];
        bytes.read_exact(&amp;<span class="hljs-keyword">mut</span> satoshis_as_bytes).unwrap();
        <span class="hljs-comment">// Get the number of satoshis in decimal</span>
        <span class="hljs-keyword">let</span> satoshis = <span class="hljs-built_in">u64</span>::from_le_bytes(satoshis_as_bytes);    

        <span class="hljs-comment">// Get the exact size of the locking script</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> locking_script_len = [<span class="hljs-number">0u8</span>; <span class="hljs-number">1</span>];
        bytes.read_exact(&amp;<span class="hljs-keyword">mut</span> locking_script_len).unwrap();
        <span class="hljs-comment">// Parse the length into a varint</span>
        <span class="hljs-keyword">let</span> script_byte_len = VarInt::parse(locking_script_len[<span class="hljs-number">0</span>]);
        <span class="hljs-comment">// Convert our VarInt to an integer</span>
        <span class="hljs-keyword">let</span> script_len = VarInt::integer(script_byte_len, bytes).unwrap();
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> script = <span class="hljs-built_in">Vec</span>::&lt;<span class="hljs-built_in">u8</span>&gt;::new();

        <span class="hljs-comment">// For the length of the script, read each byte and advance the cursor in each iteration</span>
        (<span class="hljs-number">0</span>..script_len).for_each(|_| {
            <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> current_byte = [<span class="hljs-number">0u8</span>; <span class="hljs-number">1</span>];

            bytes.read_exact(&amp;<span class="hljs-keyword">mut</span> current_byte).unwrap();
            script.extend_from_slice(¤t_byte);
        });

        <span class="hljs-comment">// Construct our Transaction Output struct and then push it to the outputs vec</span>
        outputs.push(TxOutput {
                amount: satoshis,
                locking_script: script,
            });
        });

        <span class="hljs-literal">Ok</span>(outputs)
    }

    <span class="hljs-comment">// Lastly, after parsing our version, inputs and outputs we parse the locktime</span>
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">locktime</span></span>(bytes: &amp;<span class="hljs-keyword">mut</span> Cursor&lt;&amp;[<span class="hljs-built_in">u8</span>]&gt;) -&gt; io::<span class="hljs-built_in">Result</span>&lt;<span class="hljs-built_in">u32</span>&gt; {
        <span class="hljs-comment">// The locktime is 4 bytes long</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> locktime_bytes = [<span class="hljs-number">0u8</span>; <span class="hljs-number">4</span>];
        bytes.read_exact(&amp;<span class="hljs-keyword">mut</span> locktime_bytes)?;

        <span class="hljs-comment">// Convert the locktime into an integer</span>
        <span class="hljs-literal">Ok</span>(<span class="hljs-built_in">u32</span>::from_le_bytes(locktime_bytes))
    }
}
</code></pre>
<p>We can now utilize our code to decode a hex transaction. First add the <code>hex-conservative</code> crate into the <code>Cargo.toml</code> manifest file since creating a library to parse hex into bytes is beyond the scope of this article.</p>
<p>Lastly, we use our parse to parse the transaction hex string we introduced at the beginning of the article.</p>
<pre><code class="lang-rust"><span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
    <span class="hljs-keyword">let</span> raw_tx = hex!(<span class="hljs-string">"010000000269adb42422fb021f38da0ebe12a8d2a14c0fe484bcb0b7cb365841871f2d5e24000000006a4730440220199a6aa56306cebcdacd1eba26b55eaf6f92eb46eb90d1b7e7724bacbe1d19140220101c0d46e033361c60536b6989efdd6fa692265fcda164676e2f49885871038a0121039ac8bac8f6d916b8a85b458e087e0cd07e6a76a6bfdde9bb766b17086d9a5c8affffffff69adb42422fb021f38da0ebe12a8d2a14c0fe484bcb0b7cb365841871f2d5e24010000006b48304502210084ec4323ed07da4af6462091b4676250c377527330191a3ff3f559a88beae2e2022077251392ec2f52327cb7296be89cc001516e4039badd2ad7bbc950c4c1b6d7cc012103b9b554e25022c2ae549b0c30c18df0a8e0495223f627ae38df0992efb4779475ffffffff0118730100000000001976a9140ce17649c1306c291ca9e587f8793b5b06563cea88ac00000000"</span>);
    <span class="hljs-keyword">let</span> tx_decode = BtcTx::from_hex_bytes(raw_tx);

    dbg!(tx_decode.unwrap());
}
</code></pre>
<p>That’s it. We have decoded a raw Bitcoin hex encoded transaction.</p>
<p>In the next article, we will look into converting hash bytes into SHA256 strings and converting our script bytes into a Bitcoin Script.</p>
<p><strong>References</strong></p>
<ol>
<li><p><code>VarInt</code> — <a target="_blank" href="https://web.archive.org/web/20230331170203/https://learnmeabitcoin.com/technical/varint">https://web.archive.org/web/20230331170203/https://learnmeabitcoin.com/technical/varint</a></p>
</li>
<li><p>The code for this article — <a target="_blank" href="https://github.com/448-OG/BitcoinTransactions">https://github.com/448-OG/BitcoinTransactions</a></p>
</li>
<li><p>Compact Size — <a target="_blank" href="https://learnmeabitcoin.com/technical/general/compact-size/">https://learnmeabitcoin.com/technical/general/compact-size/</a></p>
</li>
</ol>
]]></content:encoded></item><item><title><![CDATA[Implementing a Base58Check Encoder in Rust]]></title><description><![CDATA[Source Code - https://github.com/448-OG/Btrust-Deliverables/blob/master/base58check/src/main.rs
Base58Check is a binary-to-text encoding algorithm that allows us to convert byte arrays into human-readable strings that are resistant to errors. These b...]]></description><link>https://448.africa/implementing-a-base58check-encoder-in-rust</link><guid isPermaLink="true">https://448.africa/implementing-a-base58check-encoder-in-rust</guid><category><![CDATA[Bitcoin]]></category><category><![CDATA[base58check]]></category><dc:creator><![CDATA[448-OG]]></dc:creator><pubDate>Thu, 15 Feb 2024 09:00:00 GMT</pubDate><content:encoded><![CDATA[<p>Source Code - <a target="_blank" href="https://github.com/448-OG/Btrust-Deliverables/blob/master/base58check/src/main.rs\">https://github.com/448-OG/Btrust-Deliverables/blob/master/base58check/src/main.rs</a></p>
<p>Base58Check is a binary-to-text encoding algorithm that allows us to convert byte arrays into human-readable strings that are resistant to errors. These byte arrays can be public keys, digests of hash functions and even private keys.</p>
<p>The algorithm used to convert bytes to Base58Check is the Base58 algorithm. We will first look at the Base58 algorithm and later combine it to create the Base58Check algorithm.</p>
<p>Base58Check is primarily used for encoding Bitcoin addresses, but it can be more broadly applied to any data that needs to be represented in a compact, user-friendly format that excludes characters like <code>0</code>, <code>O</code>, <code>I</code>, and <code>l</code> that can look similar in certain fonts. This prevents confusion and ensures readability.</p>
<p>As illustrated above, the Base58 avoids characters that can create confusion reducing the alphabet of allowed characters to 58 which are <code>123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz</code></p>
<p>To convert a decimal value to Base58 we use the modulus function until no remainders are left. Using modulus function makes sure we circle around when we reach the maximum number of characters which is 58. Each remainder corresponds to the character at the index in the Base58 alphabet, for example remainder <code>10</code> equals to the character <code>A</code></p>
<p>Example the decimal number <code>1024</code></p>
<pre><code class="lang-plaintext">base10 = 1024

1025 % 58 = 38 &lt;- Ignoring the fractional part
17 % 58 = 17

The numbers are 17 and 38 respectively
So we look for the characters at index 17 and 38 in the Base58 alphabet

123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz
                 |                    |
             index 17 is `J`      index 38 is `f`

Therefore:
Base58 = `Jf`
</code></pre>
<p>To convert back to decimal from Base58 string you take each character and lookup it’s index in the Bas58 alphabet and multiply it by how many <code>58s</code> that position represents and then you add all the values together.</p>
<pre><code class="lang-plaintext">Base58 = `Jf`

J = index 17 in the Base58 alphabet
f = index 38 in the Base58 alphabet

To get the index at character we start with the last one as index 0 moving backwards
J = index 1 in the Base58 string
f = index 0 in the Base58 string

f = 38 * 58^0 = 38
J = 17 * 58^1 = 986
Decimal = 38 + 989 = 1024
</code></pre>
<p>In our code, we will use bytes instead of decimals in order to allow conversions from any value that can be converted to and from bytes like public and private keys.</p>
<p>Let’s create a new cargo project.</p>
<pre><code class="lang-sh">$ cargo new base58
</code></pre>
<p>Switch to the project directory.</p>
<pre><code class="lang-sh"><span class="hljs-built_in">cd</span> base58
</code></pre>
<p>We need to add some dependencies in the <code>Cargo.toml</code> file</p>
<pre><code class="lang-TOML"><span class="hljs-section">[dependencies]</span>
<span class="hljs-attr">sha</span> = <span class="hljs-string">"0.10.8"</span>
<span class="hljs-attr">rand_chacha</span> = <span class="hljs-string">"0.3.1"</span>
<span class="hljs-attr">rand_core</span> = { version = <span class="hljs-string">"0.6.4"</span>, features = [<span class="hljs-string">"getrandom"</span>]}
<span class="hljs-attr">bitcoin</span> =  { version = <span class="hljs-string">"0.31.1"</span>, features = [<span class="hljs-string">"std"</span>, <span class="hljs-string">"rand-std"</span>] }
</code></pre>
<p>Let’s import the data types into our <a target="_blank" href="http://main.rs"><code>main.rs</code></a> file</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> bitcoin::base58;
<span class="hljs-keyword">use</span> rand_chacha::ChaCha20Rng;
<span class="hljs-keyword">use</span> rand_core::{RngCore, SeedableRng};
<span class="hljs-keyword">use</span> sha2::{Digest, Sha256};
<span class="hljs-keyword">use</span> std::collections::VecDeque;

<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {}
</code></pre>
<p>We import the base58 type from the bitcoin crate to compare the output of our custom <code>base58</code> to the output of the mostly use Rust bitcoin crate. This is done to check for correctness in converting to <code>base58</code> from bytes and vice versa.</p>
<p><code>rand_chacha</code> and <code>rand_core</code> crates are used to generate random bytes while <code>sha2</code> will be used to create our checksum for <code>Base58Check</code> algorithm.</p>
<p>Next we create our code for random byte generation. We use a const generic N so that we can pass the number of bytes we want to generate.</p>
<pre><code class="lang-rust"><span class="hljs-comment">/// Our random byte generator</span>
<span class="hljs-meta">#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Entropy</span></span>&lt;<span class="hljs-keyword">const</span> N: <span class="hljs-built_in">usize</span>&gt;([<span class="hljs-built_in">u8</span>; N]);

<span class="hljs-keyword">impl</span>&lt;<span class="hljs-keyword">const</span> N: <span class="hljs-built_in">usize</span>&gt; Entropy&lt;N&gt; {
    <span class="hljs-comment">/// Generate our random bytes</span>
    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">generate</span></span>() -&gt; <span class="hljs-keyword">Self</span> {
        <span class="hljs-comment">// Create a chacha based </span>
        <span class="hljs-comment">// cryptographically secure psuedo-random</span>
        <span class="hljs-comment">// number generator.</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> rng = ChaCha20Rng::from_entropy();
        <span class="hljs-comment">// Initialize an empty byte array of `N`</span>
        <span class="hljs-comment">// number of bytes</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> buffer = [<span class="hljs-number">0u8</span>; N];
        <span class="hljs-comment">// Fill our buffer with randomly generated bytes</span>
        rng.fill_bytes(&amp;<span class="hljs-keyword">mut</span> buffer);

        <span class="hljs-keyword">Self</span>(buffer)
    }
}
</code></pre>
<p>Next we write code to parse bytes to Base58 encoding.</p>
<pre><code class="lang-rust"><span class="hljs-comment">/// Add our base58 alphabet</span>
<span class="hljs-keyword">const</span> ALPHABET: &amp;<span class="hljs-built_in">str</span> = <span class="hljs-string">"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"</span>;

<span class="hljs-comment">/// Converts our bytes to base58. </span>
<span class="hljs-comment">/// It takes a byte slice</span>
<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">to_base58</span></span>(base58_bytes: &amp;[<span class="hljs-built_in">u8</span>]) -&gt; <span class="hljs-built_in">String</span> {
    <span class="hljs-comment">// We use a `VecDeque` so that we don't have to</span>
    <span class="hljs-comment">// call `.reverse()` function on our `Vec`</span>
    <span class="hljs-comment">// since this can be an expensive operation.</span>
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> base58_char = VecDeque::&lt;<span class="hljs-built_in">char</span>&gt;::new();

    <span class="hljs-comment">// We create a new String to hold our final base58 string</span>
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> outcome = <span class="hljs-built_in">String</span>::new();

    <span class="hljs-comment">// We iterate checking for `0` bytes that appear at the</span>
    <span class="hljs-comment">// beginning of our array since they are supposed</span>
    <span class="hljs-comment">// to be prefixed by `1`. We then push a `1` for </span>
    <span class="hljs-comment">// every 0 byte we find.</span>
    <span class="hljs-keyword">for</span> _ <span class="hljs-keyword">in</span> base58_bytes.iter().take_while(|&amp;&amp;x| x == <span class="hljs-number">0</span>) {
        outcome.push(<span class="hljs-string">'1'</span>);
    }

    <span class="hljs-comment">// This will be the result of every modulo operation</span>
    <span class="hljs-comment">// holding the quotient of our division</span>
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> decimal = <span class="hljs-number">0usize</span>;

    <span class="hljs-comment">// We multiply by 256 since bytes are in</span>
    <span class="hljs-comment">// base 2 and our division to base58 is in</span>
    <span class="hljs-comment">// base 10. This is done by using left shift</span>
    <span class="hljs-comment">// to multiply since 2^8 is equal to 256.</span>
    <span class="hljs-comment">// we then assign the result to `decimal` variable</span>
    <span class="hljs-keyword">for</span> value <span class="hljs-keyword">in</span> base58_bytes {
        decimal = (decimal &lt;&lt; <span class="hljs-number">8</span>) | *value <span class="hljs-keyword">as</span> <span class="hljs-built_in">usize</span>;
    }

    <span class="hljs-comment">// We know split the alphabet and collect the individual</span>
    <span class="hljs-comment">// characters so that we can get the index</span>
    <span class="hljs-keyword">let</span> index_alphabet = ALPHABET.chars().collect::&lt;<span class="hljs-built_in">Vec</span>&lt;<span class="hljs-built_in">char</span>&gt;&gt;();

    <span class="hljs-comment">// We iterate over decimal variable</span>
    <span class="hljs-comment">// dividing by `58` and getting the remainder.</span>
    <span class="hljs-comment">// We then lookup the character at the index</span>
    <span class="hljs-comment">// of that remainder and then we push that character</span>
    <span class="hljs-comment">// to our vecdeque pushing it to the front.</span>
    <span class="hljs-comment">// We halt the loop when `decimal` variable equals 0</span>
    <span class="hljs-keyword">while</span> decimal != <span class="hljs-number">0</span> {
        <span class="hljs-comment">// This is equivalent to diving and getting the</span>
        <span class="hljs-comment">// remainder while allowing compilers to</span>
        <span class="hljs-comment">// optimize for speed.</span>
        <span class="hljs-keyword">let</span> (quotient, remainder) = (decimal / <span class="hljs-number">58</span>, decimal % <span class="hljs-number">58</span>);

        base58_char.push_front(index_alphabet[remainder <span class="hljs-keyword">as</span> <span class="hljs-built_in">usize</span>]);
        decimal = quotient;
    }

    <span class="hljs-comment">// We know iterate over our characters and add them</span>
    <span class="hljs-comment">// to the `outcome` variable which might</span>
    <span class="hljs-comment">// contain leading zeros represented by `1`s</span>
    outcome += base58_char.iter().collect::&lt;<span class="hljs-built_in">String</span>&gt;().as_str();

    outcome
}
</code></pre>
<p>Next we create our base58 decoder.</p>
<pre><code class="lang-rust"><span class="hljs-comment">/// This decodes a base58 string into bytes</span>
<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">from_base58</span></span>(base58_str: &amp;<span class="hljs-built_in">str</span>) -&gt; <span class="hljs-built_in">Vec</span>&lt;<span class="hljs-built_in">u8</span>&gt; {
    <span class="hljs-comment">// Initialize a variable to hold the decimal equivalent of the base58 string</span>
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> decimal = <span class="hljs-number">0usize</span>;

    <span class="hljs-comment">// Create a vector of characters from the base58 alphabet</span>
    <span class="hljs-keyword">let</span> index_alphabet: <span class="hljs-built_in">Vec</span>&lt;_&gt; = ALPHABET.chars().collect();

    <span class="hljs-comment">// Initialize a variable to count the number of leading zeros in the base58 string</span>
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> leading_zeros_total = <span class="hljs-number">0usize</span>;

    <span class="hljs-comment">// Initialize a vector to hold the outcome of the decoding</span>
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> outcome = <span class="hljs-built_in">Vec</span>::&lt;<span class="hljs-built_in">u8</span>&gt;::new();

    <span class="hljs-comment">// Convert the base58 string into a vector of characters</span>
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> split_chars = base58_str.chars().collect::&lt;<span class="hljs-built_in">Vec</span>&lt;<span class="hljs-built_in">char</span>&gt;&gt;();

    <span class="hljs-comment">// Count the number of leading zeros in the base58 string and add a corresponding number of zeros to the outcome</span>
    <span class="hljs-keyword">for</span> _ <span class="hljs-keyword">in</span> split_chars.iter().take_while(|&amp;x| x == &amp;<span class="hljs-string">'1'</span>) {
        leading_zeros_total += <span class="hljs-number">1</span>;
        outcome.push(<span class="hljs-number">0</span>);
    }

    <span class="hljs-comment">// Remove the leading zeros from the base58 string</span>
    split_chars.drain(<span class="hljs-number">0</span>..leading_zeros_total);

    <span class="hljs-comment">// Convert each character in the base58 string to its decimal equivalent and add it to the decimal variable</span>
    <span class="hljs-keyword">for</span> current_char <span class="hljs-keyword">in</span> split_chars {
        <span class="hljs-keyword">let</span> value = index_alphabet
            .iter()
            .position(|&amp;in_alphabet| in_alphabet == current_char)
            .unwrap();
        decimal = (decimal * <span class="hljs-number">58</span>) + value;
    }

    <span class="hljs-comment">// Initialize a vector to hold the bytes of the decimal</span>
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> bytes = <span class="hljs-built_in">Vec</span>::&lt;<span class="hljs-built_in">u8</span>&gt;::new();

    <span class="hljs-comment">// This loop continues as long as the decimal value is greater than 0</span>
    <span class="hljs-keyword">while</span> decimal &gt; <span class="hljs-number">0</span> {
        <span class="hljs-comment">// The division operation (decimal / 256) gives the quotient</span>
        <span class="hljs-comment">// The modulus operation (decimal % 256) gives the remainder</span>
        <span class="hljs-comment">// These two values are stored in the variables 'quotient' and 'remainder' respectively</span>
        <span class="hljs-keyword">let</span> (quotient, remainder) = (decimal / <span class="hljs-number">256</span>, decimal % <span class="hljs-number">256</span>);

        <span class="hljs-comment">// The remainder (which is the result of the modulus operation) is converted to an 8-bit unsigned integer (u8)</span>
        <span class="hljs-comment">// and then pushed onto the 'bytes' vector. This is because each byte represents a value between 0 and 255 (inclusive),</span>
        <span class="hljs-comment">// which is the range of possible remainders from the modulus operation.</span>
        bytes.push(remainder <span class="hljs-keyword">as</span> <span class="hljs-built_in">u8</span>);

        <span class="hljs-comment">// The 'decimal' variable is updated to the 'quotient' from the division operation.</span>
        <span class="hljs-comment">// This effectively reduces the 'decimal' value by a factor of 256 in each iteration of the loop,</span>
        <span class="hljs-comment">// preparing it for the next iteration where the process repeats.</span>
        decimal = quotient;
    }

    <span class="hljs-comment">// Reverse the bytes to get them in the correct order</span>
    bytes.reverse();

    <span class="hljs-comment">// Add the bytes to the outcome</span>
    outcome.extend_from_slice(&amp;bytes);

    <span class="hljs-comment">// Return the outcome</span>
    outcome
}
</code></pre>
<p>Bitcoin uses Base58Check which is an enhanced version of Base58 algorithm. Base58Check has some advantages like a version number and error detection due to the addition of four bytes checksum from the double hashing of a prefix byte and the payload using the SHA256 hash function.</p>
<p>Let add code to create our Base58Check algorithm.</p>
<pre><code class="lang-rust"><span class="hljs-meta">#[derive(Debug, Default)]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Base58Check</span></span> {
    <span class="hljs-comment">// Will hold our prefix</span>
    prefix: <span class="hljs-built_in">Vec</span>&lt;<span class="hljs-built_in">u8</span>&gt;,
    <span class="hljs-comment">// Our bytes</span>
    payload: <span class="hljs-built_in">Vec</span>&lt;<span class="hljs-built_in">u8</span>&gt;,
    <span class="hljs-comment">// 4 byte result of double hashing</span>
    checksum: <span class="hljs-built_in">Vec</span>&lt;<span class="hljs-built_in">u8</span>&gt;,
}
</code></pre>
<p>Next we implement our initialization function.</p>
<pre><code class="lang-rust"><span class="hljs-keyword">impl</span> Base58Check {
  <span class="hljs-comment">// Initialize Self with defaults since we derive default on our struct</span>
   <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">new</span></span>() -&gt; <span class="hljs-keyword">Self</span> {
      Self::default()
  }
}
</code></pre>
<p>We need a way to add our prefix and payload</p>
<pre><code class="lang-rust"><span class="hljs-keyword">impl</span> Base58Check {
    <span class="hljs-comment">/// We call this method to add our prefix</span>
    <span class="hljs-comment">/// taking a byte slice as argument to allow any prefix</span>
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">add_prefix</span></span>(<span class="hljs-keyword">mut</span> <span class="hljs-keyword">self</span>, prefix: &amp;[<span class="hljs-built_in">u8</span>]) -&gt; <span class="hljs-keyword">Self</span> {
        <span class="hljs-keyword">self</span>.prefix.extend_from_slice(prefix);

        <span class="hljs-keyword">self</span>
    }

    <span class="hljs-comment">/// Method to add byte payload Self</span>
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">add_payload</span></span>(<span class="hljs-keyword">mut</span> <span class="hljs-keyword">self</span>, payload: &amp;[<span class="hljs-built_in">u8</span>]) -&gt; <span class="hljs-keyword">Self</span> {
        <span class="hljs-keyword">self</span>.payload.extend_from_slice(payload);

        <span class="hljs-keyword">self</span>
    }
}
</code></pre>
<p>To generate our checksum, we first pass our prefix and payload to a SHA256 hashing function and then using our SHA256 hashing function we hash the result of the digest of the hash function (double hashing).</p>
<pre><code class="lang-rust"><span class="hljs-keyword">impl</span> Base58Check {
  <span class="hljs-comment">// This takes a mutable self and assigns the result</span>
  <span class="hljs-comment">// of the payload to `checksum` field in `Self`</span>
  <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">calc_checksum</span></span>(<span class="hljs-keyword">mut</span> <span class="hljs-keyword">self</span>) -&gt; <span class="hljs-keyword">Self</span> {
        <span class="hljs-comment">// Initialize our sha256 hashing function</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> hasher = Sha256::new();
        <span class="hljs-comment">// Hash the prefix</span>
        hasher.update(&amp;<span class="hljs-keyword">self</span>.prefix);
        <span class="hljs-comment">// Hash our payload</span>
        hasher.update(&amp;<span class="hljs-keyword">self</span>.payload);

        <span class="hljs-comment">// Get the result of the digest</span>
        <span class="hljs-keyword">let</span> first_hash = hasher.finalize();

        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> hasher = Sha256::new();
        <span class="hljs-comment">// Hash the hash</span>
        hasher.update(first_hash.as_slice());
        <span class="hljs-keyword">let</span> double_hash = hasher.finalize();

        <span class="hljs-comment">// Take the first four bytes and add them as the checksum</span>
        <span class="hljs-keyword">self</span>.checksum.extend_from_slice(&amp;double_hash[<span class="hljs-number">0</span>..<span class="hljs-number">4</span>]);

        <span class="hljs-keyword">self</span>
    }
}
</code></pre>
<p>Our last method for our struct with generate a vector of bytes that we can pass to our base58 encoder.</p>
<pre><code class="lang-rust"><span class="hljs-keyword">impl</span> Base58Check {
  <span class="hljs-comment">// This method just combines all fields of `Self`</span>
  <span class="hljs-comment">// into one vector by draining the other vectors</span>
  <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">build</span></span>(<span class="hljs-keyword">mut</span> <span class="hljs-keyword">self</span>) -&gt; <span class="hljs-built_in">Vec</span>&lt;<span class="hljs-built_in">u8</span>&gt; {
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> outcome = <span class="hljs-built_in">Vec</span>::&lt;<span class="hljs-built_in">u8</span>&gt;::new();
        outcome.extend(<span class="hljs-keyword">self</span>.prefix.drain(..));
        outcome.extend(<span class="hljs-keyword">self</span>.payload.drain(..));
        outcome.extend(<span class="hljs-keyword">self</span>.checksum.drain(..));

        outcome
    }
}
</code></pre>
<p>Now let’s test our code in the main function.</p>
<pre><code class="lang-rust"><span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
    <span class="hljs-comment">// Generate some random bytes</span>
    <span class="hljs-keyword">let</span> private_key = Entropy::&lt;<span class="hljs-number">4</span>&gt;::generate().<span class="hljs-number">0</span>;
    <span class="hljs-comment">// Intialize our Base58Check struct</span>
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> bytes = Base58Check::new()
        <span class="hljs-comment">// Add our prefix</span>
        .add_prefix(&amp;[<span class="hljs-number">0u8</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>])
        <span class="hljs-comment">// Add the payload</span>
        .add_payload(&amp;private_key)
        <span class="hljs-comment">// Calculate the checksum</span>
        .calc_checksum()
        <span class="hljs-comment">// Combine all our bytes (prefix + payload + checksum)</span>
        .build();
    <span class="hljs-keyword">let</span> custom_conversion = to_base58(&amp;<span class="hljs-keyword">mut</span> bytes);

    <span class="hljs-comment">// Assert that the base58 string generated</span>
    <span class="hljs-comment">// equals to the the base58 string </span>
    <span class="hljs-comment">// generated by the bitcoin crate</span>
    <span class="hljs-built_in">assert_eq!</span>(base58::encode(&amp;bytes).to_string(), custom_conversion);

    <span class="hljs-keyword">let</span> to_custom_vec = from_base58(&amp;custom_conversion);
    <span class="hljs-built_in">assert_eq!</span>(
        to_custom_vec,
        base58::decode(&amp;base58::encode(&amp;bytes)).unwrap()
    );
}
</code></pre>
<p>That’s it! We have implemented a Base58Check encoder and decoder</p>
<h4 id="heading-references">References</h4>
<ol>
<li><a target="_blank" href="https://learnmeabitcoin.com/technical/base58">https://learnmeabitcoin.com/technical/base58</a></li>
</ol>
]]></content:encoded></item><item><title><![CDATA[Wallet Backup and Recovery]]></title><description><![CDATA[Source code — https://github.com/448-OG/Btrust-Deliverables/tree/master/bip39-simple
Seed phrases exist because private keys are big numbers and it’s hard for anyone to memorize them. For example the bytes below as hex.

3AF660000011144004F890FF

The...]]></description><link>https://448.africa/wallet-backup-and-recovery</link><guid isPermaLink="true">https://448.africa/wallet-backup-and-recovery</guid><category><![CDATA[Bitcoin]]></category><dc:creator><![CDATA[448-OG]]></dc:creator><pubDate>Thu, 01 Feb 2024 09:00:00 GMT</pubDate><content:encoded><![CDATA[<p>Source code — <a target="_blank" href="https://github.com/448-OG/Btrust-Deliverables/tree/master/bip39-simple">https://github.com/448-OG/Btrust-Deliverables/tree/master/bip39-simple</a></p>
<p>Seed phrases exist because private keys are big numbers and it’s hard for anyone to memorize them. For example the bytes below as hex.</p>
<blockquote>
<p>3AF660000011144004F890FF</p>
</blockquote>
<p>The hex characters above have repeating characters like <code>00000</code> and <code>4400</code> making it easy for someone to miss or add a character. When you’re dealing with digital wallets and cryptocurrencies, it’s really important to get everything right. If you make a mistake with your wallet’s private key, you could end up with an empty wallet. This is because even a small error can create a completely different key, leading to a different wallet.</p>
<p>This is where BIP39 comes in. It replaces complicated keys with a set of simple words, known as a mnemonic phrase. This makes it easier to manage your keys without making mistakes. It’s like turning a hard-to-remember password into a memorable sentence.</p>
<p>So, instead of dealing with complex and error-prone keys, you just need to remember your unique set of words. Several backup and recovery mechanisms have been proposed such as <code>BIP39</code>, <code>Electrum v2</code>, <code>Aezeed</code>, <code>Muun</code> and <code>SLIP39</code>.</p>
<p>In this article we will look at <code>Bitcoin Improvement Proposal 39 (BIP39)</code> and write some Rust code to create and recover a seed using a mnemonic.</p>
<p><code>BIP39</code> is a technique that turns complex wallet recovery codes into a sequence of simple, readable words, known as a mnemonic. Here’s how it works:</p>
<ol>
<li><p>The list of words used to create the mnemonic is designed so that typing just the first four letters of a word is enough to clearly identify it.</p>
</li>
<li><p>The list avoids similar word pairs like <code>“build”</code> and <code>“built”</code>, or <code>“quick”</code> and <code>“quickly”</code>. These pairs can make the mnemonic harder to remember and more likely to be guessed incorrectly.</p>
</li>
<li><p>The words are sorted in a specific order. This makes it quicker and easier to find a particular word when you need it. It also allows for the use of a ‘trie’ (a type of search tree), which can help to compress the data.</p>
</li>
<li><p>The specification also requires that native characters used to be encoded in UTF-8 using <code>Normalization Form Compatibility Decomposition (NFKD)</code></p>
</li>
</ol>
<p>Here are the steps to create a BIP39 mnemonic:</p>
<ol>
<li><p>Create random bytes using a Cryptographically Secure Pseudo Random Number Generator. The bytes range between 128 bits (16bytes) to 256 bits (32 bytes) to generate 12–24 words.</p>
</li>
<li><p>Create a checksum, which is the first (length of entropy in bits/32) bits of the SHA256 of the entropy.</p>
</li>
<li><p>Append this checksum to the end of the initial entropy.</p>
</li>
<li><p>Split the result into groups of 11 bits.</p>
</li>
<li><p>Convert these bits into their decimal representation.</p>
</li>
<li><p>These decimal representations vary from 0–2047 and work as an index to a mnemonic word list. Choose words corresponding to these indices from the word list. For this tutorial we will use the most popular one which is English word list. Download the word list from <a target="_blank" href="https://github.com/bitcoin/bips/blob/master/bip-0039/english.txt">https://github.com/bitcoin/bips/blob/master/bip-0039/english.txt</a></p>
</li>
</ol>
<p>Remember, the mnemonic generated from these steps can be used to recover your wallet, so it’s crucial to keep it safe and secure.</p>
<p>This tutorial assumes you have installed Rust Programming Language toolchain which comes bundled with cargo build and dependency management tool.</p>
<p>Let’s create a cargo project called bip39-simple</p>
<pre><code class="lang-sh">$ cargo new bip39-simple
</code></pre>
<p>Switch to that project directory</p>
<pre><code class="lang-sh">$ <span class="hljs-built_in">cd</span> bip39-simple
</code></pre>
<p>Add dependencies to Cargo.toml file</p>
<pre><code class="lang-TOML"><span class="hljs-section">[dependencies]</span>
<span class="hljs-attr">rand_chacha</span> = <span class="hljs-string">"*"</span>
<span class="hljs-attr">rand_core</span> = { version = <span class="hljs-string">"*"</span>, features = [<span class="hljs-string">"getrandom"</span>] }
<span class="hljs-attr">sha2</span> = <span class="hljs-string">"*"</span>
<span class="hljs-attr">pbkdf2</span> = { version = <span class="hljs-string">"0.12.2"</span>, features = [
    <span class="hljs-string">"simple"</span>,
] }
</code></pre>
<p>We add the <code>getrandom</code> feature to <code>rand_core</code> in order to get random bytes using the operating system cryptographically secure random number generator. <code>sha2</code> crate will be used to create a checksum from the <code>SHA256</code> hash of the random bytes generated.</p>
<p>In our <a target="_blank" href="http://main.rs"><code>main.rs</code></a> file we import these dependencies and bring some data types into scope</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> pbkdf2::pbkdf2_hmac;
<span class="hljs-keyword">use</span> rand_chacha::ChaCha20Rng;
<span class="hljs-keyword">use</span> rand_core::{RngCore, SeedableRng};
<span class="hljs-keyword">use</span> sha2::{Digest, Sha256, Sha512};
<span class="hljs-keyword">use</span> std::{
    fs::File,
    io::{<span class="hljs-keyword">self</span>, prelude::*},
    path::{Path, PathBuf},
};
</code></pre>
<p>The <code>PBKDF2</code> key derivation function requires that an iteration count and a salt. The <code>BIP39</code> standardized document requires that if a user includes a passphrase in the creation of a seed, that passphrase be appended to the word mnemonic and if there is no seed then we append an empty string <code>""</code> instead. The specification also requires an iteration count of <code>2048</code>. So we add two constants to hold these values.</p>
<pre><code class="lang-rust"><span class="hljs-comment">/// Number of iterations to be run by the PBKDF2 for key derivation</span>
<span class="hljs-keyword">pub</span> <span class="hljs-keyword">const</span> ITERATION_COUNT: <span class="hljs-built_in">u32</span> = <span class="hljs-number">2048</span>;
<span class="hljs-comment">/// The word used as a prefix for the salt for our key derivation function</span>
<span class="hljs-keyword">pub</span> <span class="hljs-keyword">const</span> SALT_PREFIX: &amp;<span class="hljs-built_in">str</span> = <span class="hljs-string">"mnemonic"</span>;
</code></pre>
<p>We need a way to generate random bytes so we introduce the a way to generate these bytes in a manner that a user can generate varying length of bytes (in our case between 128 to 256 bytes)</p>
<pre><code class="lang-rust"><span class="hljs-comment">// This struct takes a constant `N` as a generic</span>
<span class="hljs-comment">// enabling one to specify a variable length for the bytes generated</span>
<span class="hljs-meta">#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Entropy</span></span>&lt;<span class="hljs-keyword">const</span> N: <span class="hljs-built_in">usize</span>&gt;([<span class="hljs-built_in">u8</span>; N]);

<span class="hljs-keyword">impl</span>&lt;<span class="hljs-keyword">const</span> N: <span class="hljs-built_in">usize</span>&gt; Entropy&lt;N&gt; {
    <span class="hljs-comment">// This method generates the bytes </span>
    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">generate</span></span>() -&gt; <span class="hljs-keyword">Self</span> {
        <span class="hljs-comment">// Instantiate our cryptographically secure random byte generation algorithm</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> rng = ChaCha20Rng::from_entropy();
        <span class="hljs-comment">// Create a zero filled buffer to hold our bytes</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> buffer = [<span class="hljs-number">0u8</span>; N];
        <span class="hljs-comment">// Fill our buffer with random bytes</span>
        rng.fill_bytes(&amp;<span class="hljs-keyword">mut</span> buffer);

        <span class="hljs-comment">// Return our buffer</span>
        <span class="hljs-keyword">Self</span>(buffer)
    }
}
</code></pre>
<p>Next we need to create a struct that can hold methods to generate our mnemonic, create our seed and recover our seed.</p>
<pre><code class="lang-rust"><span class="hljs-meta">#[derive(Debug, Default)]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Bip39Generator</span></span> {
    <span class="hljs-comment">// This holds all our indexes that we will use to fetch</span>
    <span class="hljs-comment">// our word from the word list </span>
    <span class="hljs-comment">// with each index corresponding to an index</span>
    <span class="hljs-comment">// from our wordlist contained in a Vec&lt;word&gt;</span>
    mnemonic_index: <span class="hljs-built_in">Vec</span>&lt;<span class="hljs-built_in">u16</span>&gt;,
    <span class="hljs-comment">// This field holds the random bytes with our checksum</span>
    <span class="hljs-comment">// bytes appended to the end</span>
    appended: <span class="hljs-built_in">Vec</span>&lt;<span class="hljs-built_in">u8</span>&gt;,
    <span class="hljs-comment">// This contains a path to our wordlist file</span>
    path: PathBuf,
}
</code></pre>
<p>Let’s create a method to instantiate our Bip39Generator struct.</p>
<pre><code class="lang-rust"><span class="hljs-keyword">impl</span> Bip39Generator {
  <span class="hljs-comment">// This method takes an argument `path_to_wordlist` which</span>
  <span class="hljs-comment">// is a path to the wordlist we downloaded</span>
  <span class="hljs-comment">// where the path is anything that implements the trait</span>
  <span class="hljs-comment">// AsRef&lt;Path&gt; meaning we pass any data type as convert it </span>
  <span class="hljs-comment">// to a path using the `.as_ref()` method as long as that</span>
  <span class="hljs-comment">// data type implements the `AsRef&lt;Path&gt;` trait.</span>
  <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">new</span></span>(path_to_wordlist: <span class="hljs-keyword">impl</span> <span class="hljs-built_in">AsRef</span>&lt;Path&gt;) -&gt; <span class="hljs-keyword">Self</span> {
      <span class="hljs-keyword">Self</span> {
          <span class="hljs-comment">// Convert `path_to_wordlist` argument to a path</span>
          <span class="hljs-comment">// using `.as_ref()` method and convert it</span>
          <span class="hljs-comment">// to a `std::path::PathBuf` using the `.to_path_buf()`</span>
          path: path_to_wordlist.as_ref().to_path_buf(),
           <span class="hljs-comment">// All other fields can hold default values</span>
          <span class="hljs-comment">// and we can call this method since </span>
          <span class="hljs-comment">// we derived `Default` values using `#[derive(Default)]` </span>
          <span class="hljs-comment">// on our struct </span>
          ..<span class="hljs-built_in">Default</span>::default()
      }
  }
}
</code></pre>
<p>Next we create a method to load our word list from the file we download containing our English word list</p>
<p>Note the <code>...</code> is not part of Rust syntax but to show previous code we implemented.</p>
<pre><code class="lang-rust"><span class="hljs-keyword">impl</span> Bip39Generator {
  ...

<span class="hljs-comment">// This method takes in a mutable `Self`</span>
<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">load_wordlist</span></span>(&amp;<span class="hljs-keyword">mut</span> <span class="hljs-keyword">self</span>) -&gt; io::<span class="hljs-built_in">Result</span>&lt;<span class="hljs-built_in">Vec</span>&lt;<span class="hljs-built_in">String</span>&gt;&gt; {
        <span class="hljs-comment">// open the file using the path we passed</span>
        <span class="hljs-comment">// when instantiating our struct </span>
        <span class="hljs-comment">// using `Bip39Generator::new()`</span>
        <span class="hljs-keyword">let</span> file = File::open(&amp;<span class="hljs-keyword">self</span>.path)?;
        <span class="hljs-comment">// Create a buffer so that we can efficiently readd</span>
        <span class="hljs-comment">// our file</span>
        <span class="hljs-keyword">let</span> reader: io::BufReader&lt;File&gt; = io::BufReader::new(file);

        <span class="hljs-comment">// Create a Vector to hold our wordlist</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> wordlist = <span class="hljs-built_in">Vec</span>::&lt;<span class="hljs-built_in">String</span>&gt;::new();

        <span class="hljs-comment">// Read each line</span>
        <span class="hljs-keyword">for</span> line <span class="hljs-keyword">in</span> reader.lines() {
          <span class="hljs-comment">// Push each word to our `wordlist` vector</span>
          <span class="hljs-comment">// handling any I/O errors using `?`</span>
            wordlist.push(line?);
        }

        <span class="hljs-comment">// Return our vector of word list</span>
        <span class="hljs-literal">Ok</span>(wordlist)
    }
}
</code></pre>
<p>We need to generate a checksum to append to our randomly generated bytes in order to generate a mnemonic</p>
<pre><code class="lang-rust"><span class="hljs-keyword">impl</span> Bip39Generator {
  ...
  <span class="hljs-comment">// Here we pass our generated random bytes as `entropy` argument</span>
   <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">generate_checksum</span></span>&lt;<span class="hljs-keyword">const</span> N: <span class="hljs-built_in">usize</span>&gt;(&amp;<span class="hljs-keyword">mut</span> <span class="hljs-keyword">self</span>, entropy: [<span class="hljs-built_in">u8</span>; N]) -&gt; &amp;<span class="hljs-keyword">mut</span> <span class="hljs-keyword">Self</span> {
      <span class="hljs-comment">// BIP39 spec requires a seed to be generated</span>
      <span class="hljs-comment">// using a SHA256 Psuedo Random Function (PRF)</span>
      <span class="hljs-comment">// so we instantiate a SHA256 hashing function.</span>
      <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> hasher = Sha256::new();

      <span class="hljs-comment">// We now pass our random bytes into our SHA256 PRF</span>
      hasher.update(entropy.as_slice());

      <span class="hljs-comment">// We now get our finalized value. Using</span>
      <span class="hljs-comment">// SHA256 always ensures that despite being</span>
      <span class="hljs-comment">// able to use variable length of random bytes</span>
      <span class="hljs-comment">// we always get back a 256 bit (32 byte) value.</span>
      <span class="hljs-keyword">let</span> entropy_hash = hasher.finalize();

      <span class="hljs-comment">// Since we get a 32 byte value we multiply by</span>
      <span class="hljs-comment">// `8` to get number of bits since 1 byte == 8 bits</span>
      <span class="hljs-keyword">let</span> bits_of_entropy = entropy.len() * <span class="hljs-number">8</span>;
      <span class="hljs-comment">// We get our `n` bits for our checksum from the</span>
      <span class="hljs-comment">// length of the random bits (entropy) </span>
      <span class="hljs-comment">// where `n` is calculated as the </span>
      <span class="hljs-comment">// `length of our random bits / 32`</span>
      <span class="hljs-keyword">let</span> bits_of_checksum = bits_of_entropy / <span class="hljs-number">32</span>;
      <span class="hljs-comment">// We then use bit shifting to get</span>
      <span class="hljs-comment">// bits of checksum from our</span>
      <span class="hljs-comment">// 256 bit hash in variable `entropy_hash`</span>
      <span class="hljs-keyword">let</span> significant = entropy_hash[<span class="hljs-number">0</span>] &gt;&gt; bits_of_checksum;

      <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> appended = entropy.to_vec();
      <span class="hljs-comment">// We then append our checksum to our random</span>
      appended.push(significant);

      <span class="hljs-comment">// We now assign our appended bytes to the `appended`</span>
      <span class="hljs-comment">// field of our `Bip39Generator` struct which is `Self`</span>
      <span class="hljs-keyword">self</span>.appended = appended;

      <span class="hljs-keyword">self</span>
  }
}
</code></pre>
<p>The next step is to get the index of the words to be used in our mnemonic. This step involves splitting our <code>random bytes with the appended checksum into groups of 11 bits</code>.</p>
<pre><code class="lang-rust"><span class="hljs-keyword">impl</span> Bip39Generator {
  ...

  <span class="hljs-comment">// We pass a mutable to self since we want to</span>
  <span class="hljs-comment">// add the result of this computation to `Self`</span>
  <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">compute</span></span>(&amp;<span class="hljs-keyword">mut</span> <span class="hljs-keyword">self</span>) -&gt; &amp;<span class="hljs-keyword">mut</span> <span class="hljs-keyword">Self</span> {
    <span class="hljs-comment">// This vector will hold the binary </span>
    <span class="hljs-comment">// representation of each byte in the `appended` vector.</span>
      <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> bits = <span class="hljs-built_in">vec!</span>[];

      <span class="hljs-comment">// This line starts a loop that iterates over each byte in the `self.appended` vector.</span>
      <span class="hljs-keyword">for</span> &amp;byte <span class="hljs-keyword">in</span> <span class="hljs-keyword">self</span>.appended.iter() {
          <span class="hljs-comment">// This line starts a nested loop that </span>
          <span class="hljs-comment">// counts backwards from 7 to 0. </span>
          <span class="hljs-comment">// The variable `i` represents the position of </span>
          <span class="hljs-comment">// the bit we're interested in within </span>
          <span class="hljs-comment">// the current byte.</span>
          <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> (<span class="hljs-number">0</span>..<span class="hljs-number">8</span>).rev() {
          <span class="hljs-comment">/*
            This line does three things:
             - `byte &gt;&gt; i`: This is a right bitwise shift operation. 
                            It moves the bits in `byte` `i` places to the right. 
                            The bit at position `i` is now at position 0.
             - `(byte &gt;&gt; i) &amp; 1u8`: This is a bitwise AND operation with `1u8` (which is `1` in binary). 
                                    This operation effectively masks all the bits in `byte` except for the one at position 0.
             - `bits.push((byte &gt;&gt; i) &amp; 1u8 == 1);`: This pushes `true` if the bit at position 0 is `1` 
                                                      and `false` otherwise into the `bits` vector.
            */</span>            
              bits.push((byte &gt;&gt; i) &amp; <span class="hljs-number">1u8</span> == <span class="hljs-number">1</span>);
          }
      }

      <span class="hljs-comment">// This line starts a loop that iterates over </span>
      <span class="hljs-comment">// the `bits` vector in chunks of 11 bits.</span>
      <span class="hljs-keyword">for</span> chunk <span class="hljs-keyword">in</span> bits.chunks(<span class="hljs-number">11</span>) {
          <span class="hljs-comment">// This line checks if the current chunk has </span>
          <span class="hljs-comment">// exactly 11 bits. If it does, the code inside </span>
          <span class="hljs-comment">// the if statement is executed.</span>
          <span class="hljs-keyword">if</span> chunk.len() == <span class="hljs-number">11</span> {
              <span class="hljs-comment">// This line initializes a mutable </span>
              <span class="hljs-comment">// variable named `value` and sets it to 0. </span>
              <span class="hljs-comment">// This variable will hold the decimal </span>
              <span class="hljs-comment">// representation of the current 11-bit chunk.</span>
              <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> value: <span class="hljs-built_in">u16</span> = <span class="hljs-number">0</span>;

              <span class="hljs-comment">// This line starts a nested loop that iterates</span>
              <span class="hljs-comment">// over each bit in the current chunk. </span>
              <span class="hljs-comment">// The variable `i` is the index of the current</span>
              <span class="hljs-comment">//  bit, and `bit` is the value of the current bit.</span>
              <span class="hljs-keyword">for</span> (i, &amp;bit) <span class="hljs-keyword">in</span> chunk.iter().enumerate() {
                  <span class="hljs-comment">// This line checks if the current bit </span>
                  <span class="hljs-comment">// is `1` (true). If it is, it shifts `1` </span>
                  <span class="hljs-comment">// to the left by `(10 - i)` places </span>
                  <span class="hljs-comment">// (this effectively gives `1` a value of `2^(10 - i)`) </span>
                  <span class="hljs-comment">// and then performs a bitwise OR operation with `value`. </span>
                  <span class="hljs-comment">// This has the effect of adding `2^(10 - i)` to `value`.</span>
                  <span class="hljs-keyword">if</span> bit {
                      value |= <span class="hljs-number">1u16</span> &lt;&lt; (<span class="hljs-number">10</span> - i);
                  }
              }
              <span class="hljs-comment">// This line pushes the decimal </span>
              <span class="hljs-comment">// representation of the current 11-bit chunk </span>
              <span class="hljs-comment">// into the `self.mnemonic_index` vector.</span>
              <span class="hljs-keyword">self</span>.mnemonic_index.push(value);
          }
      }

      <span class="hljs-keyword">self</span>
  }
}
</code></pre>
<p>Now that we can get our mnemonic</p>
<pre><code class="lang-rust"><span class="hljs-keyword">impl</span> Bip39Generator {
  ...

    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">mnemonic</span></span>&lt;<span class="hljs-keyword">const</span> N: <span class="hljs-built_in">usize</span>&gt;(&amp;<span class="hljs-keyword">mut</span> <span class="hljs-keyword">self</span>) -&gt; io::<span class="hljs-built_in">Result</span>&lt;<span class="hljs-built_in">String</span>&gt; {
        <span class="hljs-comment">// This generates the number of random bits we need</span>
        <span class="hljs-keyword">let</span> entropy = Entropy::&lt;{ N }&gt;::generate();

        <span class="hljs-comment">// Next, let's generate our checksum</span>
        <span class="hljs-keyword">self</span>.generate_checksum::&lt;N&gt;(entropy.<span class="hljs-number">0</span>);

        <span class="hljs-comment">// Next we compute the decimal numbers we will use</span>
        <span class="hljs-comment">// to get our wordlist</span>
        <span class="hljs-keyword">self</span>.compute();

        <span class="hljs-comment">// Load the wordlist into memory</span>
        <span class="hljs-keyword">let</span> wordlist = <span class="hljs-keyword">self</span>.load_wordlist()?;

        <span class="hljs-comment">// Iterate through the decimal numbers</span>
        <span class="hljs-comment">// and for each decimal number get the word</span>
        <span class="hljs-comment">// in it's index in the wordlist (wordlist[index from decimal number]</span>
        <span class="hljs-keyword">let</span> mnemonic = <span class="hljs-keyword">self</span>
            .mnemonic_index
            .iter()
            <span class="hljs-comment">// Enumerate to get the current count in our interation</span>
            .enumerate()
            .map(|(index, line_number)| {
                <span class="hljs-comment">// Convert our decimal index (line_numer) to </span>
                <span class="hljs-comment">// a usize since Rust is very strict in that</span>
                <span class="hljs-comment">// you can only index an array using a usize</span>
                <span class="hljs-comment">// so we dereference and cast using `as usize`</span>
                <span class="hljs-keyword">let</span> word = (&amp;wordlist[*line_number <span class="hljs-keyword">as</span> <span class="hljs-built_in">usize</span>]).clone() + <span class="hljs-string">" "</span>;  <span class="hljs-comment">// Add a space in each word</span>
                <span class="hljs-comment">// Since indexes start at zero we add `1`</span>
                <span class="hljs-comment">// to make them human readable (humans mostly count from 1)</span>
                <span class="hljs-keyword">let</span> index = index + <span class="hljs-number">1</span>;

                <span class="hljs-comment">// Check if we have our index is less than</span>
                <span class="hljs-comment">// 10 so we add a padding to make printing</span>
                <span class="hljs-comment">// to console neat</span>
                <span class="hljs-keyword">let</span> indexed = <span class="hljs-keyword">if</span> index &lt; <span class="hljs-number">10</span> {
                    <span class="hljs-built_in">String</span>::new() + <span class="hljs-string">" "</span> + index.to_string().as_str()
                } <span class="hljs-keyword">else</span> {
                    index.to_string()
                };

                <span class="hljs-comment">// Print our index and each word. This </span>
                <span class="hljs-comment">// will show the user the words in each</span>
                <span class="hljs-comment">// line but with a number. eg</span>
                <span class="hljs-comment">//  9. foo</span>
                <span class="hljs-comment">// 10. bar</span>
                <span class="hljs-built_in">println!</span>(<span class="hljs-string">"{}. {}"</span>, indexed, &amp;word);

                <span class="hljs-comment">// Return the word</span>
                word
            })
            .collect::&lt;<span class="hljs-built_in">String</span>&gt;(); <span class="hljs-comment">// Combine all strings into one</span>

        <span class="hljs-comment">// Trim the last space in the and return the mnemonic</span>
        <span class="hljs-literal">Ok</span>(mnemonic.trim().to_owned())
    }
}
</code></pre>
<p>Now we can generate a seed from our mnemonic</p>
<pre><code class="lang-rust"><span class="hljs-keyword">impl</span> Bip39Generator {
...

  <span class="hljs-comment">// We pass our mnemonic and an optional passphrase</span>
    <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">seed</span></span>(mnemonic: &amp;<span class="hljs-built_in">str</span>, passphrase: <span class="hljs-built_in">Option</span>&lt;&amp;<span class="hljs-built_in">str</span>&gt;) -&gt; io::<span class="hljs-built_in">Result</span>&lt;<span class="hljs-built_in">Vec</span>&lt;<span class="hljs-built_in">u8</span>&gt;&gt; {
        <span class="hljs-comment">// We check if there is a passphrase provided.</span>
        <span class="hljs-comment">// if there is one we prefix our salt with the passphrase</span>
        <span class="hljs-keyword">let</span> salt = <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> <span class="hljs-literal">Some</span>(passphrase_required) = passphrase {
            <span class="hljs-built_in">String</span>::new() + SALT_PREFIX + passphrase_required
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-built_in">String</span>::from(SALT_PREFIX)
        };

        <span class="hljs-comment">// We want to generate a 512bit seed</span>
        <span class="hljs-comment">// so we create a buffer to hold this.</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> wallet_seed = [<span class="hljs-number">0u8</span>; <span class="hljs-number">64</span>]; <span class="hljs-comment">// 512 bits == 64 bytes</span>

        <span class="hljs-comment">// We generate a key and push all the bytes to the `wallet_seed` buffer</span>
        pbkdf2_hmac::&lt;Sha512&gt;(
            mnemonic.as_bytes(),
            salt.as_bytes(),
            ITERATION_COUNT,
            &amp;<span class="hljs-keyword">mut</span> wallet_seed,
        );

        <span class="hljs-comment">// We return our seed</span>
        <span class="hljs-literal">Ok</span>(wallet_seed.to_vec())
    }
}
</code></pre>
<p>Create methods to get a seed secured with a passphrase and one without. These methods call <code>seed()</code> which is a private method.</p>
<pre><code class="lang-rust"><span class="hljs-keyword">impl</span> Bip39Generator {
...
   <span class="hljs-comment">/// Generates a seed without a passphrase</span>
    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">insecure_seed</span></span>(mnemonic: &amp;<span class="hljs-built_in">str</span>) -&gt; io::<span class="hljs-built_in">Result</span>&lt;<span class="hljs-built_in">Vec</span>&lt;<span class="hljs-built_in">u8</span>&gt;&gt; {
        Self::seed(mnemonic, <span class="hljs-literal">None</span>)
    }

    <span class="hljs-comment">/// Generates a seed with a passphrase</span>
    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">secure_seed</span></span>(mnemonic: &amp;<span class="hljs-built_in">str</span>, passphrase: &amp;<span class="hljs-built_in">str</span>) -&gt; io::<span class="hljs-built_in">Result</span>&lt;<span class="hljs-built_in">Vec</span>&lt;<span class="hljs-built_in">u8</span>&gt;&gt; {
        Self::seed(mnemonic, <span class="hljs-literal">Some</span>(passphrase))
    }
}
</code></pre>
<p>Now in the main function we can instantiate our seed generator to generate and recover our seed</p>
<pre><code class="lang-rust"><span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
    <span class="hljs-comment">// Instantiate a mnemonic generator with the location of the wordlist</span>
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> generator = Bip39Generator::new(<span class="hljs-string">"english.txt"</span>);
    <span class="hljs-comment">// Generate the mnemonic</span>
    <span class="hljs-keyword">let</span> mnemonic = generator.mnemonic::&lt;<span class="hljs-number">16</span>&gt;().unwrap();

    <span class="hljs-built_in">println!</span>(<span class="hljs-string">"Your mnemonic is: {}"</span>, &amp;mnemonic);

    <span class="hljs-comment">// Recover a wallet by running the mnemonic through seed generator without a passphrase</span>
    <span class="hljs-keyword">let</span> insecure_seed = Bip39Generator::insecure_seed(&amp;mnemonic);

    <span class="hljs-keyword">let</span> passphrase = <span class="hljs-string">"BitCoin_iZ_Awesome"</span>;
    <span class="hljs-comment">// Recover a wallet by running the mnemonic through seed generator without a passphrase</span>
    <span class="hljs-keyword">let</span> secure_seed = Bip39Generator::secure_seed(&amp;mnemonic, passphrase);

    <span class="hljs-comment">// test that the seed generation succeeds</span>
    <span class="hljs-built_in">assert!</span>(&amp;secure_seed.is_ok(),);
    <span class="hljs-built_in">assert!</span>(&amp;insecure_seed.is_ok(),);
}
</code></pre>
<p>That’s it. We have made life easier for humans :) Cheers!</p>
]]></content:encoded></item><item><title><![CDATA[Understanding the data storage of Solana Program Derived Addresses]]></title><description><![CDATA[Decentralized applications need to store data immutable onchain. Solana is no different, that’s why we get Program Derived Addresses (PDAs). Creating a PDA is done through system_instruction::SystemInstruction::CreateAccountWithSeed which derives the...]]></description><link>https://448.africa/understanding-the-data-storage-of-solana-program-derived-addresses</link><guid isPermaLink="true">https://448.africa/understanding-the-data-storage-of-solana-program-derived-addresses</guid><category><![CDATA[Rust, Solana, Web3]]></category><dc:creator><![CDATA[448-OG]]></dc:creator><pubDate>Wed, 22 Jun 2022 10:56:31 GMT</pubDate><content:encoded><![CDATA[<p>Decentralized applications need to store data immutable onchain. Solana is no different, that’s why we get Program Derived Addresses (PDAs). Creating a PDA is done through <code>system_instruction::SystemInstruction::CreateAccountWithSeed</code> which derives the PDA public key from a base, mostly the program public key and a seed which is a string of Rust UTF8 characters.</p>
<h4 id="heading-how-a-solana-pda-initialized">How a Solana PDA initialized</h4>
<p>The initialized storage is an array of the maximum memory size the data structure takes up in memory. Storing a data structure like a username as a Rust <code>String</code> would require <code>24 bytes</code> of memory allocated on the Solana blockchain. The bigger the data structure the higher the rent needed to pay for onchain storage. Calculating the maximum size a data structure would take up can be done using the Rust function <code>core::mem::size_of::&lt;T&gt;()</code> where <code>T</code> is the data structure.</p>
<pre><code class="lang-rust">core::mem::size_of::&lt;<span class="hljs-built_in">String</span>&gt;(); <span class="hljs-comment">//24 bytes</span>
</code></pre>
<p>When <code>system_instruction::SystemInstruction::CreateAccountWithSeed</code> is called with the size of the String (24 bytes), will allocate an empty array of 24 bytes <code>[u8; 24]</code>.</p>
<pre><code class="lang-rust">[<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>]
</code></pre>
<p>For large data structures serialize/ deserialize libraries are used to handle the conversion of data structures to and from bytes.</p>
<hr />
<blockquote>
<p><strong>A BIT OF GLASS:</strong> Solana uses Rust for programming onchain programs and the most popular serialization framework is <code>serde</code>. Unfortunately, <code>serde</code> uses too many CPU cycles to serialize and deserialize making it expensive to convert data to and from bytes on Solana’s limited BPF smart contract execution stack. <code>borsh</code> crate is the go to serialization library for Solana.</p>
</blockquote>
<hr />
<p>Suppose we need to create an end-to-end encrypted messaging Dapp that stores a user’s Diffie-Hellman public keys onchain in the user’s PDA address. The data structure in Rust would look like this:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> borsh::{BorshSerialize, BorshDeserialize};

<span class="hljs-meta">#[derive(Debug, BorshSerialize, BorshDeserialize, Default)]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">MessagingAccount</span></span> {
   username: <span class="hljs-built_in">String</span>,
   dh_keys: <span class="hljs-built_in">Vec</span>&lt;[<span class="hljs-built_in">u8</span>; <span class="hljs-number">32</span>]&gt;,
}
</code></pre>
<p>Calculating the size using <code>core::mem::size_of::&lt;MessagingAccount&gt;()</code> will return a maximum size of <code>48 bytes</code> that can be stored in memory. Creating a PDA on Solana using <code>system_instruction::SystemInstruction::CreateAccountWithSeed</code> will initialize a zeroed array of 48 bytes (<code>[u8; 48]</code>) which can be represented as:</p>
<pre><code class="lang-rust">[<span class="hljs-number">0u8</span>; core::mem::size_of::&lt;MessagingAccount&gt;()]
</code></pre>
<p>Using <code>solana_program::msg</code> to log the PDA would show the initialized account as</p>
<pre><code class="lang-rust">AccountInfo {
       key: pda_address,
       owner: program_id,
       is_signer: <span class="hljs-literal">false</span>,
       is_writable: <span class="hljs-literal">true</span>,
       executable: <span class="hljs-literal">false</span>,
       ..,
       data.len: <span class="hljs-number">48</span>,
       data: <span class="hljs-number">000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000</span>,
   .. }
</code></pre>
<p>The data part of the <code>AccountInfo</code> above shows that <code>000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000</code> which is hex for the 48 bytes of the zeroed storage initialized when the PDA account was created <code>[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]</code></p>
<p>We can deserialize the data structure onchain as follows:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// – Code snippet –</span>
entrypoint!(process_instruction);

   <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">process_instruction</span></span>(
       program_id: &amp;Pubkey,
       accounts: &amp;[AccountInfo],
       instruction_data: &amp;[<span class="hljs-built_in">u8</span>],
   ) -&gt; ProgramResult {
       <span class="hljs-keyword">let</span> accounts_iter = &amp;<span class="hljs-keyword">mut</span> accounts.iter();

       <span class="hljs-keyword">let</span> pda_account = next_account_info(accounts_iter)?;
       <span class="hljs-keyword">let</span> pda_data = MessagingAccount::try_from_slice(instruction_data)?;
   }
</code></pre>
<p>Calling the smart contract code will return a <code>borsh</code> error</p>
<pre><code class="lang-rust"><span class="hljs-literal">Err</span>(
    Custom {
        kind: InvalidData,
        error: <span class="hljs-string">"Not all bytes read"</span>,
    },
)
</code></pre>
<p>The error returned is because <code>borsh</code> tries to deserialize the PDA account based on the data size encoded in the <code>borsh specification - https://borsh.io/</code>, in our case <code>MessagingAccount::default</code> which is <code>[0, 0, 0, 0, 0, 0, 0, 0]</code> which is an array of <code>8 bytes</code> while the initialized PDA store is an array of <code>48 bytes</code>.</p>
<h3 id="heading-what-to-do">What To Do?</h3>
<p>A simple way to solve this issue is to pack and unpack bytes using a storage format. The storage format will contain a <code>marker</code> to indicate the length of the valid bytes. The marker is of type <code>usize</code> which has a maximum of <code>8 bytes</code> which can be calculated by <code>core::mem::size_of::&lt;usize&gt;().len()</code> The data storage format can be defined as:</p>
<pre><code class="lang-sh">MARKER (8 bytes) | DATA (variable byte length) | Zeros (filled with zeroes)
</code></pre>
<h5 id="heading-to-serialize-the-data-into-the-storage-format">To Serialize the data into the storage format</h5>
<ol>
<li><p>calculate the size of the valid bytes serialized by borsh: <code>MessagingAccount::try_to_vec()?.len()</code></p>
</li>
<li><p>Get the size of the storage length of the pda account: <code>pda_account.data.len()</code></p>
</li>
<li><p>Add the <code>MARKER</code> length to the serialized data length: <code>8 + MessagingAccount::try_to_vec()?.len()</code></p>
</li>
<li><p>Check if the length of the <code>MARKER + MessagingAccount::try_to_vec()?.len()</code> is greater than the length of the <code>pda_account</code> data storage.</p>
</li>
<li><p>If the size of the <code>MARKER + MessagingAccount::try_to_vec()?.len()</code> os greater, return an error informing the user that the data cannot be written to the Solana PDA storage because it exceeded the capacity of the PDA account.</p>
</li>
<li><p>If the data is less than or equal to the capacity of the PDA account storage, concate the <code>MARKER</code> with the bytes of the serialized data and then if the concatenated data is still less than the capacity of the PDA account storage, fill the remaining space with zeroes.</p>
</li>
<li><p>Write the data into the PDA storage</p>
</li>
</ol>
<h5 id="heading-to-deserialize-the-data-storage-format">To deserialize the data storage format</h5>
<ol>
<li><p>Get the first 8 bytes and convert them to a <code>MARKER</code> : <code>usize::from_le_bytes(bytes_stored[0..8]</code></p>
</li>
<li><p>Skip the first 8 bytes as indicated by the marker and then fetch the rest of the bytes up to the index indicated by the marker: <code>let data = bytes_stored.iter().skip(8).take(MARKER).collect::&lt;Vec&lt;u8&gt;&gt;();</code></p>
</li>
<li><p>Deserialize the data using borsh: <code>MessagingAccount.try_from_slice(&amp;data)?;</code></p>
</li>
</ol>
<h5 id="heading-transforming-the-pseudocode-above-to-code">Transforming the pseudocode above to code:</h5>
<p>The code contains comments that explain each step.</p>
<ul>
<li>Create code to handle the errors</li>
</ul>
<pre><code class="lang-rust"><span class="hljs-comment">/// The result type that encompasses the `AccountStoreError`</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">type</span> <span class="hljs-title">AccountStoreResult</span></span>&lt;T&gt; = <span class="hljs-built_in">Result</span>&lt;T, AccountStoreError&gt;;

<span class="hljs-meta">#[derive(Debug)]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">enum</span> <span class="hljs-title">AccountStoreError</span></span> {
    <span class="hljs-comment">/// The buffer cannot acommodate the size of the `MARKER` which is `8 bytes`</span>
    BufferTooSmallForMarker = <span class="hljs-number">0</span>,
    <span class="hljs-comment">/// The buffer cannot acommodate the size of the data and the  `MARKER`</span>
    BufferTooSmallForData = <span class="hljs-number">1</span>,
    <span class="hljs-comment">/// The deserialized bytes do not contain a `MARKER`</span>
    CorruptedMarker = <span class="hljs-number">2</span>,
    <span class="hljs-comment">/// The data provided does not contain enough data length as specified by the `MARKER`</span>
    CorruptedStorage = <span class="hljs-number">3</span>,
    <span class="hljs-comment">/// The error provided is invalid</span>
    InvalidError = <span class="hljs-number">4</span>,
}
</code></pre>
<ul>
<li>Create a data structure to handle these operations:</li>
</ul>
<pre><code class="lang-rust">      <span class="hljs-keyword">pub</span> <span class="hljs-keyword">const</span> MARKER_SIZE: <span class="hljs-built_in">usize</span> = <span class="hljs-number">8</span>;

      <span class="hljs-meta">#[derive(Debug)]</span>
      <span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">AccountStore</span></span>&lt;T&gt; {
          <span class="hljs-keyword">pub</span> data: T,
      }
</code></pre>
<ul>
<li>Create a method to calculate the size needed for a generic data structure to be stored onchain with our storage format. The <code>impl {}</code> block to take a generic parameter <code>T</code> that must implement <code>BorshSerialize</code>, <code>BorshDeserialize</code> and <code>core::fmt::Debug</code>.</li>
</ul>
<pre><code class="lang-rust"><span class="hljs-keyword">impl</span>&lt;T&gt; AccountStore&lt;T&gt;
<span class="hljs-keyword">where</span>
    T: BorshDeserialize + BorshSerialize + <span class="hljs-built_in">Default</span> + <span class="hljs-built_in">Sized</span>,
{
    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">size_of</span></span>() -&gt; <span class="hljs-built_in">usize</span> {
        core::mem::size_of::&lt;T&gt;() + MARKER_SIZE
    }
}
</code></pre>
<p>The <code>size_of()</code> method calculates the size of the data structure specified as <code>T</code> and adds <code>8 bytes</code> to accommodate the marker information.</p>
<ul>
<li>Create a method to pack the data Create a method called <code>pack()</code> to convert the data into the storage format and write it to a provided buffer</li>
</ul>
<pre><code class="lang-rust"><span class="hljs-keyword">impl</span> {
  <span class="hljs-comment">// -- Code snippet --</span>
   <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">pack</span></span>(&amp;<span class="hljs-keyword">self</span>, buffer: &amp;<span class="hljs-keyword">mut</span> [<span class="hljs-built_in">u8</span>]) -&gt; AccountStoreResult&lt;<span class="hljs-built_in">usize</span>&gt; {
        <span class="hljs-comment">// Get the length of the PDA account storage size</span>
        <span class="hljs-keyword">let</span> buffer_length = buffer.len();

        <span class="hljs-comment">// Check if the size of the `MARKER` is less than the size  of the `buffer_length`</span>
        <span class="hljs-keyword">if</span> buffer_length &lt; MARKER_SIZE {
            <span class="hljs-comment">// If the size is smaller, return an error indicating this to the user</span>
            <span class="hljs-keyword">return</span> <span class="hljs-literal">Err</span>(AccountStoreError::BufferTooSmallForMarker);
        }
        <span class="hljs-comment">// Serialize the user data using `borsh`</span>
        <span class="hljs-keyword">let</span> data = <span class="hljs-keyword">self</span>.data.try_to_vec().unwrap(); <span class="hljs-comment">//HANDLE THIS BORSH ERROR AS YOU WISH</span>
                                                    <span class="hljs-comment">// Get the data length</span>
        <span class="hljs-keyword">let</span> data_length = data.len();

        <span class="hljs-comment">// Check if the sum of the size of the `data_length` and the `MARKER_SIZE` is</span>
        <span class="hljs-comment">// greater than the `buffer_length`</span>
        <span class="hljs-keyword">if</span> buffer_length &lt; data_length + MARKER_SIZE {
            <span class="hljs-keyword">return</span> <span class="hljs-literal">Err</span>(AccountStoreError::BufferTooSmallForData);
        }

        <span class="hljs-comment">// Copy the `data_length` to the buffer as the `MARKER`</span>
        buffer[<span class="hljs-number">0</span>..=<span class="hljs-number">7</span>].copy_from_slice(&amp;data_length.to_le_bytes());

        <span class="hljs-comment">// Copy the data into the buffer.</span>
        <span class="hljs-comment">// If the data is smaller than the buffer then the space filled with</span>
        <span class="hljs-comment">// zeroes is left intact</span>
        buffer[<span class="hljs-number">8</span>..=data_length + <span class="hljs-number">7</span>].copy_from_slice(&amp;data);

        <span class="hljs-literal">Ok</span>(data_length + <span class="hljs-number">8usize</span>)
    }
}
</code></pre>
<ul>
<li>Create a method <code>unpack()</code> to read the storage format</li>
</ul>
<pre><code class="lang-rust"><span class="hljs-keyword">impl</span> {
  <span class="hljs-comment">// -- Code snippet --</span>


    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">unpack</span></span>(buffer: &amp;[<span class="hljs-built_in">u8</span>]) -&gt; AccountStoreResult&lt;AccountStore&lt;T&gt;&gt; {
        <span class="hljs-comment">// Get the length of the PDA account storage</span>
        <span class="hljs-keyword">let</span> buffer_length = buffer.len();

        <span class="hljs-comment">// Check if the size of the `MARKER` is less than the size  of the `buffer_length`</span>
        <span class="hljs-keyword">if</span> buffer_length &lt; MARKER_SIZE {
            <span class="hljs-keyword">return</span> <span class="hljs-literal">Err</span>(AccountStoreError::BufferTooSmallForMarker);
        }

        <span class="hljs-comment">// Convert the `MARKER` bytes to and array of `[u8; 8] `</span>
        <span class="hljs-comment">// since `usize::from_le_bytes` only accepts `[u8; 8]`</span>
        <span class="hljs-keyword">let</span> marker: [<span class="hljs-built_in">u8</span>; <span class="hljs-number">8</span>] = <span class="hljs-keyword">match</span> buffer[<span class="hljs-number">0</span>..MARKER_SIZE].try_into() {
            <span class="hljs-literal">Ok</span>(value) =&gt; value,
            <span class="hljs-literal">Err</span>(_) =&gt; <span class="hljs-keyword">return</span> <span class="hljs-literal">Err</span>(AccountStoreError::CorruptedMarker),
        };
        <span class="hljs-comment">// Get the last index of the valid data</span>
        <span class="hljs-keyword">let</span> byte_length = <span class="hljs-built_in">usize</span>::from_le_bytes(marker);

        <span class="hljs-comment">// Check if the last index of the valid buffer is greater than the PDA storage size</span>
        <span class="hljs-keyword">if</span> byte_length &gt; buffer_length {
            <span class="hljs-keyword">return</span> <span class="hljs-literal">Err</span>(AccountStoreError::CorruptedStorage);
        }

        <span class="hljs-comment">// Collect the valid data by skipping the `MARKER_SIZE` of `8 bytes`</span>
        <span class="hljs-comment">// and iterating the rest of the bytes until the index marked by the `byte_length`</span>
        <span class="hljs-keyword">let</span> data = buffer
            .iter()
            .skip(<span class="hljs-number">8</span>)
            .take(byte_length)
            .map(|byte| *byte)
            .collect::&lt;<span class="hljs-built_in">Vec</span>&lt;<span class="hljs-built_in">u8</span>&gt;&gt;();

        <span class="hljs-keyword">if</span> byte_length != <span class="hljs-number">0</span> {
            <span class="hljs-keyword">let</span> data = T::try_from_slice(&amp;data).unwrap(); <span class="hljs-comment">// Handle error as you see fit</span>
            <span class="hljs-literal">Ok</span>(AccountStore { data })
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-comment">// If the `byte_length` is zero it means that no previous</span>
            <span class="hljs-comment">// data had been written to the PDA account previously</span>
            <span class="hljs-comment">// so return the `Default` representation of the data structure represented</span>
            <span class="hljs-comment">// by the generic `T`</span>
            <span class="hljs-literal">Ok</span>(AccountStore { data: T::default() })
        }
    }
}
</code></pre>
<ul>
<li>Lastly, create a method to add data to the store</li>
</ul>
<pre><code class="lang-rust"><span class="hljs-keyword">impl</span> {
  <span class="hljs-comment">// -- snippet --</span>
<span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">add_data</span></span>(&amp;<span class="hljs-keyword">mut</span> <span class="hljs-keyword">self</span>, data: T) -&gt; &amp;<span class="hljs-keyword">mut</span> <span class="hljs-keyword">Self</span> {
        <span class="hljs-keyword">self</span>.data = data;

        <span class="hljs-keyword">self</span>
    }
}
</code></pre>
<h5 id="heading-utilizing-our-storage-library-to-serialize-and-deserialize-the-pdaaccountdata">Utilizing our storage library to serialize and deserialize the <code>pda_account.data</code></h5>
<ul>
<li>Unpack the Solana PDA data <code>pda_account.data</code> using <code>unpack()</code> method and <code>add_data()</code> to add some data eg. from a Solana <code>Instruction</code></li>
</ul>
<pre><code class="lang-rust"><span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> data = AccountStore::MessagingAccount&gt;::unpack(&amp;pda_account.data.as_ref().borrow()).unwrap();

<span class="hljs-keyword">let</span> user_data = MessagingAccount {
    username: <span class="hljs-string">"SolanaSeaMonster"</span>.into(),
    dh_keys: <span class="hljs-built_in">vec!</span>[[<span class="hljs-number">1u8</span>; <span class="hljs-number">32</span>], [<span class="hljs-number">2u8</span>; <span class="hljs-number">32</span>]],
};

data.add_data(user_data);
</code></pre>
<ul>
<li>Packing the data and writing it back to the Solana PDA account using <code>pack()</code> method.</li>
</ul>
<pre><code class="lang-rust">data.pack(&amp;<span class="hljs-keyword">mut</span> &amp;<span class="hljs-keyword">mut</span> pda_account.data.borrow_mut()[..]).unwrap();
</code></pre>
<p>Since a Solana PDA account storage is a Rust <code>RefCell&lt;Rc&lt;[u8; T&gt;&gt;</code>, the <code>&amp;variable_name.as_ref().borrow()</code> is used to access the data and convert it into a <code>&amp;[u8]</code> as required by the <code>unpack()</code> method and the <code>&amp;mut &amp;mut variable_name.data.borrow_mut()[..]</code> is used to write data.</p>
<p>Now you know how the PDA storage concept works and how you can create your own lightweight storage format to read and write the data.</p>
<p>That's it.</p>
<p>Keep chewing glass.</p>
]]></content:encoded></item></channel></rss>