V1.1.0-ANALYSIS-GAS-COST-DETERMINATION
| Field | Value |
|---|---|
| Name | [1.1.0] [Analysis] Gas Cost Determination |
| Slug | 219 |
| Status | deprecated |
| Type | RFC |
| Category | Informational |
| Editor | Thomas Lavaur [email protected] |
| Contributors | Filip Dimitrijevic [email protected] |
Timeline
- 2026-05-28 —
d45eed2— Chore: mirror blochain specs into github/mdbook (#347)
Owner: @Thomas Lavaur
Reviewers: @Mehmet @Daniel Sanchez Quiros @lvaro Castro-Castilla @David Rusu
Revision History
| Version | Changes | Date |
|---|---|---|
| 1.0.0 | Initial revision. | 2025-09-25 |
| 1.1.0 | ? | 2025-10-07 |
Introduction
In Mantle, each Mantle Transaction contains one Ledger Transaction and one or more Operations. These components consume gas, measured through fixed gas units that reflect their execution or storage impact. Logos Blockchain introduces three independent gas markets:
- Execution Gas: measuring computational workload.
- Permanent Storage Gas: measuring cost of fully replicated storage.
- Ephemeral DA Storage Gas: measuring sharded storage in the DA layer.
Gas constants are carefully calibrated to reflect the computational and storage requirements of different operations on the Logos Blockchain. By standardizing gas measurements, the system can accurately charge fees proportional to resource usage, preventing network abuse and incentivizing efficient transaction design.
Overview
We conducted a comprehensive analysis of execution requirements for each Operation type in Mantle Transactions and of Ledger Transaction. This detailed examination allowed us to determine precise gas amounts for each Operation based on the actual computational resources consumed.
The gas constants we established are strategically divided between permanent storage, ephemeral data store on the DA layer and execution components, directly proportional to their respective resource utilization within Mantle Transactions. This separation ensures that gas costs accurately reflect the true computational burden of different operations. Moreover, gas can also be adjusted arbitrarily to incentivize or disincentivize the usage of certain Operations compared to others.
Our methodology involved measuring execution complexity and defining how gas is determined for each Gas Market. This is critical for proper network operation as it directly impacts transaction prioritization and network economics.
Permanent Storage Gas
Permanent Storage is paid directly for the entire signed Mantle Transaction. The Permanent Storage Gas price is included in the Mantle Transaction structure and is used to determine the Permanent Storage fee. 1 Permanent Storage Gas corresponds to 1 byte.
permanent_storage_fee = len(encode(tx_signed)) * permanent_storage_gas_price
Ephemeral Storage Gas
Ephemeral storage is a unique market exclusive to Blobs. For this reason, the DA Storage Gas price is included in the Blob Operation structure and is used to determine the DA Storage fee. 1 DA Storage Gas corresponds to 1 byte.
da_storage_fee = blob_size * DA_storage_gas_price
Execution Gas
Execution is a third general market that represents how costly an operation or a Ledger Transaction is to execute. This cost can be fixed or variable based on the content of the Operation / Transaction. The Execution Gas price is contained in the Mantle Transaction structure and each Operation or Ledger Transaction define its execution gas amount. 1 Execution Gas corresponds to 1,000 CPU cycles.
execution_fee = (tx.ops.get_summed_gas() + tx.ledger_tx.get_gas())
* execution_gas_price
The gas derivation of each Operation and of a Ledger Transaction are:
LEDGER_TRANSACTION_GAS = 590
CHANNEL_INSCRIBE_GAS = 56
CHANNEL_BLOB_GAS = 6356 + 1600 * sample_size
CHANNEL_SET_KEYS = 56
SDP_DECLARE_GAS = 646
SDP_WITHDRAW_GAS = 590
SDP_ACTIVE_GAS = 590
LEADER_CLAIM_GAS = 580
and come from our implementation observations as described in Gas determination from measures. As a reminder, sample_size = blob_size / (1024x31).To get these numbers, we based our calculations on the following measures:
| Operation | Number of CPU cycles |
|---|---|
| ZkSignature batch verification | 3,900,000 + number_of_proof x 590,000 |
| Proof of Claim batch verification | 2,640,000 + number_of_proof x 580,000 |
| Blob sampling batch verification | 5,000,000 + number_of_sample x (315,000 + 80,000 x sample_size ) |
| Eddsa25519 signature verification | 56,000 |
Comparison, list searching, hashes and operation in small fields are neglected. We also supposed that the initialization cost for batch verification is paid by everyone and deduced from the block directly. The user then pay only for the part that is proportional to the number of proofs.
Ledger Transaction
The Execution Gas of the Ledger Transaction compensates for the verification of the ZkSignature proof and the validation of the overall Mantle Transaction balance. This fundamental gas cost ensures proper cryptographic verification and data integrity of both the Ledger Transaction and the Mantle Transaction. It covers the cost of computing the Mantle Transaction hash.
Execution: ~590k CPU cycles.
- Verification of the ZK signature: 590,000 cycles.
- Verification of the balance: negligible.
- Computation of the Mantle Transaction hash: negligible.
Input Gas
Input gas covers the computational cost of verifying that one Note Id exists in the Ledger and is not locked. Additionally, it compensates for the removal of one Note Id from the Ledger.
Execution: negligible.
- Verification that the note is in the ledger: negligible.
- Verification that the note is unlocked: negligible.
- Removing of the note from the ledger: negligible.
Output Gas
Output gas accounts for the computational resources required to verify that one output is well-formed and for its inclusion in the Ledger.
Execution: negligible.
- Verification of the output validity: negligible.
- Insertion of the note in the ledger: negligible.
Operations
Channel Inscription
The validation process includes verifying an Eddsa25519 signature, confirming that the signer is authorized for the specified channel, and checking the chaining sequence of the channel. The execution encompasses creating channel records (if not previously used) and updating the tip of the channel.
Execution: ~56k CPU cycles.
- Verification of the Ed25519 signature: 56,000 cycles.
- Verification of the signer authorization (signer in the list): negligible.
- Verification of channel sequencing (equality check): negligible
- Update the tip of the channel: negligible
Channel Blobs
The validation encompasses several critical security checks: verifying an Eddsa25519 signature, confirming the signer's authorization for the specified channel, and validating the chaining sequence of the channel. The execution process involves creating channel records (if not previously established), updating the channel tip, and executing the sampling operations necessary to verify data availability.
Execution: ~6.356M + sample_size x 1.6M CPU cycles
- Verification of the Ed25519 Signature: 56,000 cycles.
- Verification of the signer authorization (signer in the list): negligible.
- Verification of channel sequencing (equality check): negligible.
- Update the tip of the channel: negligible.
- Verification of twenty sample : 20 x (315,000 + 80,000 x sample_size ) cycles.
Channel Set Keys
This gas amount covers the verification of the Eddsa25519 signature and ensures the operation is well-formed. This represents the computational cost associated with processing key management operations.
- Execution: ~56k CPU cycles.
- Verification of the Ed25519 signature: 56,000 cycles.
- Modification of the key list of the channel: negligible.
SDP Declaration
This gas covers multiple verification processes: confirming ownership of the locked note through ZkSignature verification, validating the zk_id via a second ZkSignature, and establishing ownership of the provider_id through an Eddsa25519 signature. It also includes verification of the declaration format, confirmation of note existence, validation that the note is not already locked, and verification of its amount. Additionally, it accounts for the computational costs associated with the note locking mechanism and declaration management.
Execution: ~ 646k CPU cycles.
- Verification of the Ed25519 signature: 56,000 cycles.
- Verification of the ZK signature: 590,000 cycles.
- Verification that the declaration doesnt already exist: negligible.
- Verification of locator length: negligible.
- Verification of locked note existence: negligible.
- Verification of locked note value: negligible.
- Verification that the note isnt already locked for the service: negligible.
- Locking the note: negligible.
SDP Withdraw
This gas covers a verification process that includes: confirming ownership of the zk_id through ZkSignature verification, validating the existence of the locked note, verifying that the note has exceeded its lock period, and confirming that the declaration exists and has not been previously withdrawn. The validation process also ensures that the withdrawal message's nonce is greater than any previous nonce, preventing replay attacks. During execution, the system updates the declaration's status to withdrawn, removes the declaration from the locked note's associated declarations, andif the note has no remaining declarationsremoves it from the locked notes dictionary.
Execution: ~ 590k CPU cycles.
- Verification that the note exists, is locked and bound to the declaration: negligible.
- Verification that the note can be unlocked: negligible.
- Verification that the declaration exist: negligible.
- Verification of the ZK signature: 590,000 cycles.
- Verification that the declaration wasnt already withdrawn: negligible.
- Verification of nonce incrementation: negligible.
- Update declaration: negligible.
- Remove declaration from locked note: negligible.
- Unlock the note if not linked to any declaration: negligible.
SDP Activation
This gas funds the verification of the zk_id signature through the ZkSignature verification process, validates the existence of the declaration in the system, and ensures that the activation message's nonce is greater than any previous nonce to prevent replay attacks. The validation includes confirming that the declaration ID is present in the declarations dictionary and that the signature corresponds to the declaration's registered zk_id public key.
- Execution: ~590k CPU cycles.
- Verification that the declaration exist: negligible.
- Verification of nonce incrementation: negligible.
- Verification of the ZK signature: 590,000 cycles.
- Evaluation of the activity depends on the service and is neglected here
Leader Claims
This gas covers the verification of reward voucher ownership through a Proof of Claim, confirmation that the voucher nullifier is not already present in the nullifier set, and validation that the rewards root exists in the list of recent voucher Merkle tree roots. The execution process involves adding the voucher nullifier to the nullifier set and increasing the Ledger Transaction balance by the designated leader reward amount.
Execution: ~580k CPU cycles.
- Verification that the voucher nullifier isnt already in the set: negligible.
- Verification that the rewards root is one of the root of the reward tree of the last blocks: negligible.
- Verification of the proof of claim: 580,000 cycles.
- Insertion of the nullifier in the voucher nullifier set: negligible.
Annex
Gas determination from measures
The material used for the benchmarks is the following:
- CPU : 13th Gen Intel(R) Core(TM) i9-13980HX (24 cores / 32 threads)
- RAM : 32GB - Speed: 5600 MT/s
- Motherboard: Micro-Star International Co., Ltd. MS-17S1
- OS : Ubuntu 22.04.5 LTS
- Kernel : 6.8.0-59-generic
Proof of Claim
We found the best linear curve approximating these measures (over 100 iterations):
| Number of Batches | Number of CPU cycles |
|---|---|
| 1 | 2,502,356 |
| 2 | 3,662,746 |
| 3 | 4,216,022 |
| 4 | 4,800,445 |
| 5 | 5,324,304 |
| 6 | 6,091,442 |
| 7 | 6,618,446 |
| 8 | 7,165,629 |
| 9 | 7,692,432 |
| 10 | 8,421,783 |
| 20 | 14,257,450 |
| 30 | 20,131,137 |
| 40 | 25,782,519 |
| 50 | 31,595,523 |
| 60 | 37,286,419 |
| Number of Batches | Number of CPU cycles |
|---|---|
| 70 | 42,901,298 |
| 80 | 48,309,912 |
| 90 | 54,191,072 |
| 100 | 61,082,050 |
| 110 | 66,927,817 |
| 120 | 73,758,494 |
| 130 | 78,816,789 |
| 140 | 84,801,250 |
| 150 | 91,693,824 |
| 160 | 94,248,613 |
| 170 | 99,430,138 |
| 180 | 105,607,812 |
| 190 | 112,379,089 |
| 200 | 116,599,001 |
We got the curve that we decided to approximate to :

ZkSignature
We found the best linear curve approximating these measures (over 1000 iterations):
| Number of Batches | Number of CPU cycles |
|---|---|
| 1 | 4,126,177 |
| 2 | 4,904,084 |
| 3 | 5,538,085 |
| 4 | 6,061,800 |
| 5 | 6,957,754 |
| 6 | 7,421,851 |
| 7 | 8,237,485 |
| 8 | 8,621,986 |
| 9 | 9,115,091 |
| 10 | 10,186,171 |
| 20 | 15,777,800 |
| 30 | 21,456,771 |
| 40 | 27,441,722 |
| 50 | 33,430,729 |
| 60 | 38,986,389 |
| Number of Batches | Number of CPU cycles |
|---|---|
| 70 | 44,708,450 |
| 80 | 50,894,373 |
| 90 | 56,534,430 |
| 100 | 63,606,624 |
| 110 | 70,036,347 |
| 120 | 75,612,096 |
| 130 | 82,048,010 |
| 140 | 87,080,407 |
| 150 | 91,473,391 |
| 160 | 97,862,623 |
| 170 | 104,019,852 |
| 180 | 111,498,103 |
| 190 | 114,814,226 |
| 200 | 119,739,702 |
We got the curve that we decided to approximate to :

Blob Sampling
We measure different scenarios. For each size of sample, we derived a linear equation of the form with the number of samples to verify.
32 KiB blobs (2 sample elements):
| Batch Size | CPU Cycles |
|---|---|
| 10 | 8,529,507 |
| 20 | 13,818,649 |
| 30 | 18,985,695 |
| 40 | 25,089,415 |
| 50 | 30,648,329 |
| 60 | 35,502,866 |
| 70 | 38,892,864 |
| 80 | 43,399,433 |
| 90 | 47,671,839 |
| 100 | 52,314,907 |
| Batch Size | CPU Cycles |
|---|---|
| 110 | 58,208,545 |
| 120 | 62,786,791 |
| 130 | 67,786,161 |
| 140 | 72,179,484 |
| 150 | 76,278,407 |
| 160 | 80,940,080 |
| 170 | 86,766,298 |
| 180 | 90,567,870 |
| 190 | 93,692,283 |
| 200 | 98,343,499 |
The best fitting curve is that we approximated by :

64 KiB blobs (3 sample elements)
| Batch Size | CPU Cycles |
|---|---|
| 10 | 9,239,126 |
| 20 | 15,131,351 |
| 30 | 20,961,330 |
| 40 | 27,594,193 |
| 50 | 32,845,900 |
| 60 | 37,949,973 |
| 70 | 43,022,847 |
| 80 | 48,129,313 |
| 90 | 53,190,914 |
| 100 | 58,218,004 |
| Batch Size | CPU Cycles |
|---|---|
| 110 | 63,390,371 |
| 120 | 68,451,282 |
| 130 | 75,767,779 |
| 140 | 80,669,658 |
| 150 | 85,627,442 |
| 160 | 90,819,416 |
| 170 | 95,532,120 |
| 180 | 100,443,619 |
| 190 | 105,375,207 |
| 200 | 110,394,398 |
The best fitting curve is that we approximated by :

128 KiB blobs (5 sample elements)
| Batch Size | CPU Cycles |
|---|---|
| 10 | 10,964,607 |
| 20 | 20,686,848 |
| 30 | 28,941,578 |
| 40 | 38,295,293 |
| 50 | 45,960,757 |
| 60 | 53,745,474 |
| 70 | 61,650,124 |
| 80 | 69,167,994 |
| 90 | 76,875,286 |
| 100 | 84,404,885 |
| Batch Size | CPU Cycles |
|---|---|
| 110 | 92,380,948 |
| 120 | 99,812,683 |
| 130 | 109,947,874 |
| 140 | 117,477,348 |
| 150 | 124,924,958 |
| 160 | 132,430,262 |
| 170 | 141,098,267 |
| 180 | 148,117,833 |
| 190 | 157,570,978 |
| 200 | 166,188,496 |
The best fitting curve is that we approximated by :

256 KiB blobs (10 sample elements)
| Batch Size | CPU Cycles |
|---|---|
| 10 | 14,785,938 |
| 20 | 26,318,392 |
| 30 | 38,260,143 |
| 40 | 50,502,225 |
| 50 | 61,301,092 |
| 60 | 72,028,954 |
| 70 | 82,362,773 |
| 80 | 93,485,923 |
| 90 | 104,042,321 |
| 100 | 114,602,636 |
| Batch Size | CPU Cycles |
|---|---|
| 110 | 125,615,987 |
| 120 | 136,706,128 |
| 130 | 148,619,389 |
| 140 | 158,348,399 |
| 150 | 168,918,545 |
| 160 | 179,787,233 |
| 170 | 192,484,193 |
| 180 | 203,995,906 |
| 190 | 212,814,837 |
| 200 | 223,817,125 |
The best fitting curve is that we approximated by :

512 KiB blobs (17 sample elements)
| Batch Size | CPU Cycles |
|---|---|
| 10 | 19,822,834 |
| 20 | 36,328,022 |
| 30 | 52,876,723 |
| 40 | 70,217,070 |
| 50 | 86,017,119 |
| 60 | 101,724,856 |
| 70 | 117,470,096 |
| 80 | 133,111,662 |
| 90 | 149,254,798 |
| 100 | 164,761,143 |
| Batch Size | CPU Cycles |
|---|---|
| 110 | 180,287,296 |
| 120 | 195,906,310 |
| 130 | 213,611,965 |
| 140 | 229,460,354 |
| 150 | 245,987,045 |
| 160 | 261,140,370 |
| 170 | 276,891,655 |
| 180 | 293,255,638 |
| 190 | 309,324,730 |
| 200 | 324,752,182 |
The best fitting curve is that we approximated by :

768 KiB blobs (25 sample elements)
| Batch Size | CPU Cycles |
|---|---|
| 10 | 24,802,125 |
| 20 | 46,362,059 |
| 30 | 67,781,105 |
| 40 | 90,334,595 |
| 50 | 111,300,953 |
| 60 | 131,842,378 |
| 70 | 152,872,933 |
| 80 | 173,311,447 |
| 90 | 194,630,157 |
| 100 | 215,504,778 |
| Batch Size | CPU Cycles |
|---|---|
| 110 | 235,840,678 |
| 120 | 257,025,208 |
| 130 | 279,135,548 |
| 140 | 299,488,712 |
| 150 | 319,182,136 |
| 160 | 340,687,653 |
| 170 | 361,057,665 |
| 180 | 379,539,673 |
| 190 | 402,246,965 |
| 200 | 419,518,033 |
The best fitting curve is that we approximated by :

1024 KiB blobs (34 sample elements)
| Batch Size | CPU Cycles |
|---|---|
| 10 | 34,936,346 |
| 20 | 66,539,633 |
| 30 | 97,890,996 |
| 40 | 130,256,521 |
| 50 | 160,952,882 |
| 60 | 191,807,748 |
| 70 | 222,242,226 |
| 80 | 253,226,954 |
| 90 | 283,563,420 |
| 100 | 315,080,511 |
| Batch Size | CPU Cycles |
|---|---|
| 110 | 344,833,795 |
| 120 | 376,006,265 |
| 130 | 409,130,375 |
| 140 | 439,438,063 |
| 150 | 471,270,848 |
| 160 | 501,121,144 |
| 170 | 532,336,865 |
| 180 | 563,566,629 |
| 190 | 592,486,314 |
| 200 | 622,146,228 |
The best fitting curve is that we approximated by :

From all these curves and for simplification, we assumed that the initialization cost is the same for every sample size and equals 5M CPU cycles. Then, we simply linearized again the linear factor of each curve giving us:
| Sample size | Linear factor |
|---|---|
| 2 | 470,000 |
| 3 | 530,000 |
| 5 | 800,000 |
| 10 | 1,100,000 |
| 17 | 1,600,000 |
| 25 | 2,100,000 |
| 34 | 3,100,000 |
Which gives use the linear equation that we approximated by .

This gives us a final sample verification cost (in Execution Gas) of:
The 5000 Execution Gas cost is removed from the Execution Gas limit directly and the rest is applied per Blob Operation individually.