Soroban Fees & Limits

Mainnet Phases

Goals

  • Pick conservative network settings so that we can gradually launch Soroban without putting the greater network at risk.
  • Not only validators but also what other nodes like captive core and downstream systems like horizon, Soroban-RPC and other similar systems.
  • We expect a percentage of those systems to fail (completely or partially) with every new phase. Goal is to stagger those failures.
  • Pick limits for the different phases with an understanding that some of them can only be increased over time (without breaking contracts).

Settings per phase:

Note: Phase 2+ limits will be TBD for a while (likely until Phase 1 is live) until we get some benchmark numbers and better understanding of the metering calibration and overall Soroban impact.

Phase 0 numbers are what we currently have minimum values. The maximum setting values depend on the ledger capacity.

Phase 0/1 per-ledger resource limits are the same as per-transaction limits. So it’s possible to have up to ‘Soroban Txn per ledger’ transactions that all add up to the specified limit, or a single transaction that consumes a maximum amount of every resource, or any combination in-between.

Limits

Important relation: VM instantiation cost = 0.4M + 350 * Contract size (the instruction limit should accommodate for at least the maximum allowed contract size)

Network setting

Phase 0

Phase 1

Phase 2/3 - TBD

Soroban Txn per ledger

1

100

Max CPU Instructions per Txn

2.5 million (2M instructions for max Wasm)

100 million (VM instantiation consumes up to 23M for a 64KB Wasm, and 46M for multiple Wasms of 130KB)

Memory limit per Txn

2 MB

40 MB

Ledger entry size (including Wasm entries) per Txn

2 KB

64 KB

Read/Write Ledger entries per Txn

3 read/

2 write

40 read/25 write

Read/Write bytes per Txn

3.2 KB/3.2 KB

130 KB/65 KB

Transaction size

10 KB

70 KB

Persistent entry minimal/initial lifetime

4096 ledgers (~5.68 hours)

120 days

Temporary entry minimal/initial lifetime

16 ledgers

1 day

Max ledger entry expiration bump

61 days

6 months

Events+return value size bytes

200 B

8 KB

Initial fees (protocol 20 upgrade)

Initial fee values are hardcoded as a part of the protocol 20 upgrade. The fees are  used to just introduce some ‘sane’ values to start with and to not make the network vulnerable to spam. These values are documented here for the sake of completeness, but see the following section on phase 1 fees for a more detailed description of the process of coming up with the fees going forward.

Fees (in stroops)

Network setting

Phase 0 (upgrade defaults)

10000 instructions

100 (1’000’000/tx)

Read 1 ledger entry

1000 (20’000/tx)

Write 1 ledger entry

3000 (30’000/tx)

Read 1KB from ledger

1000 (127’000/tx)

1KB of transaction (bandwidth)

500 (34’000/tx)

1KB of transaction (history)

5000 (340’000/tx)

1KB of Events/return value

300 (1’500/tx)

Rent/write fees

Write fees are dependent on the ledger size and have more complex configuration.

Rent payment is a write payment every X ledgers (‘rent period’)

Network setting

Phase 0

“Target” ledger size

14.5 GB (current is ~12.5 GB)

Fee multiplier after reaching the target size

1000

Write 1KB to ledger (empty)

1000

Write 1KB to ledger (current, 12 GB)

0.356 XLM (17.4 XLM/tx)

Write 1KB to ledger (target, 14 GB)

0.4 XLM (2.26 XLM/tx)

Write 1KB to ledger (2x of target, 29 GB)

40 XLM (2260 XLM/tx)

Temp entry rent period

10 months

Persistent entry rent period

1 month

1 KB of temp storage per month

400’000

1 KB of persistent storage per month

4’000’000

Phase 1 fees

In order to make the fee structure more clear starting from phase 1 we’ll follow a more clear process of determining and describing the ‘bounded’ transaction fees (outside of the rent fees):

  • There is a single fee that represents the maximum non-refundable resource fee that can be paid for a transaction (i.e. all the resource fees besides the contract event fees and rent fee). In phase 1 this fee is 0.3 XLM
  • Every non-refundable resource has a ledger limit associated with it. Ledger is constrained by every one of these limits, thus initially we use the same fee weight for most of the resource limits. For example, using a ledger-limit worth of instructions (100M instructions in phase 1) would cost the same as using a ledger-limit worth of ledger entry reads (40 ledger entries in phase 1).
  • The only two exceptions in phase 1 are the transaction size which is weighted 5 times higher and the base write fee which is weighted 3 times higher. The higher weights reflect the added costs of persisting the data: transactions have to be persisted in the cold history storage and every write persists in the bucket list for some time (even when it does not introduce new data).

Fees (in stroops)

Network setting

Phase 1

Phase 2/3 - TBD

10000 instructions

25 (250,000/max tx)

Read 1 ledger entry

6,250 (250,000/max tx)

Write 1 ledger entry

10,000 (250,000/max tx)

Read 1KB from ledger

1,786 (250,000/max tx)

1KB of transaction  size (bandwidth)

1,624 (113,642/max tx)

1KB of transaction size (history)

16,235 (1,136,418/max tx)

1KB of Events/return value (refundable fee - no a part of ‘maximum’ transaction cost threshold)

10,000 (80,000/max tx)

Rent/write fees

The goal of the rent and write fees is to control the ledger growth speed, which is essential for protocol 20 given that the expired persistent entries are not physically removed from the ledger.

Initially, write fees are set up in such a way that 1 year of renting persistent storage for Soroban is equivalent in cost to creating a new entry in ‘classic’ Stellar (which costs 0.5 XLM per ~100 bytes of ledger storage).

The plan is to set up the fees in such a way that the ledger size would get at most 50% growth during a year. The initial “target” size is set based on the 2 month projection of this growth. The values will then be updated if necessary in order to reduce the fees and allow for the further ledger growth as long as the growth rate stays within the projected range.

Rent payment is a write payment every X ledgers (‘rent period’)

Network setting

Phase 1

“Target” ledger size

13 GB (current size is 12GB, 2 month target with up to 6GB/year projected growth)

Fee multiplier after reaching the target size

1000

Write 1KB to ledger, stroops (empty)

-1,234,673 (the write cost is always positive; this value is used only for the effective write fee computations)

Write 1KB to ledger, stroops (current, 12 GB)

11,539 (750,000/max tx)

Write 1KB to ledger, stroops (target, 13 GB)

115,390 (7,500,000/max tx)

Write 1KB to ledger (2x of target, 26 GB) - we don’t anticipate this to be reached any time soon

11.5 XLM (736 XLM/max tx)

Temp entry rent period, ledgers

2,804

Persistent entry rent period, ledgers

1,402

Minimum persistent entry TTL, ledgers

2,073,600 (120 days)

Minimum temp entry TTL, ledgers

17,280  (~1 day)

When a transaction only updates the entry without extending the rent or increasing the entry size, the write fees will be low and in line with the other resource fees. When a new entry is written to the ledger or the old entry has size and/or TTL increased, the rent fees need to be paid.

Phase 1 Examples

Here are some examples to put things in perspective (the fees are computed at ‘current’ ledger size and would grow as ledger size increases):

Upload a new 64KB Wasm (includes 120 day rent payment)

109.2 XLM

1 year of 64KB Wasm storage rent

327.7 XLM

Bump 64KB Wasm rent by 1 day

0.91 XLM

Modify 64 KB contract data entry without increasing the size

0.075 XLM

Create 100 byte contract data entry, e.g. user balance (includes 120 day rent payment)

0.17 XLM

1 year of 100 byte storage rent

0.512 XLM

Modify 100 byte contract data entry without increasing the size

1150 stroops

Phase 0: when first turning on pubnet (1 week)

This phase is not intended to be publicly usable or useful for any real projects. At this point Testnet should be at high enough capacity for users to continue testing and developing

Goals

  • Smoke-test all the systems
  • Execute only very basic contracts for the purpose of testing
  • Upload network configuration upgrades via contract calls

Phase 1: Useful contracts, 1 “largest” transaction/ledger (~3 weeks)

In this phase users can deploy and test their contracts on the mainnet, but there is no expectation that their dapps can be used ‘in production’ due to low ledger limits.

What we are trying to control for:

  • Uncertainty over bespoke deployments
  • We don't know and can't test for all combinations of deployments. Uncertainty on CPU/RAM/Disk Space/IOPS
  • Unknown spare capacity for core nodes (validators, watcher nodes).
  • Unknown spare capacity for Horizon deployments (captive-core, ingestion).
  • Unknown spare capacity for other deployments (Horizon alternatives, StellarExpert, etc)
  • Uncertainty on metering (if for example the variance for execution time is 10x we could have ledgers ranging from 500 milliseconds to five seconds which is unacceptable)
  • As a consequence we probably want to set limits as to target processing about 1 "worst case transaction possible" (so ledger wide limits are equal to transaction level limits)
  • Junk or spam transactions or data on ledger
  • Resource fees should probably be priced to deter those type of things. In particular we have to make sure that things are several magnitudes more expensive than both classic and (pick a number: 10 years ?) AWS. We may want to take into account some information we got recently that the cost to operate history archives is abnormally high because of bandwidth (so amount of data stored in archives).
  • Out of control ledger growth
  • Pick a target: 1 extra GB at first on top of the existing ledger
  • Ensure that temporary storage is much cheaper then permanent one
  • Ensure that policies on pubnet play well with the lack of ESS (probably means requiring longer minPersistentEntryExpiration ?)
  • On testnet we may have to do the opposite so that app devs can actually find and debug issues related to state expiration (faster expiration -> more likely to run into issues)
  • Amount of data produced
  • Number of events and overall metadata size that needs to be processed by downstream systems

 

Phase 2: Increasing single contract limits (0-3 weeks)

 This is to account for the user needs based on their experience with phase 1.

Goals

  • This phase should focus on increasing limits for a single transaction (If needed, as to enable a wider range of scenarios) -- if there is no such need, skip to "phase 3"
  • We may also allow for splitting up the ledger capacity among a few transactions (so that we get more than one transaction per ledger, without increasing the overall ledger capacity to be a lot greater than the worst transaction we want to allow)
  • Adjust classic capacity as needed
  • Adjust market price of resources

 

Phase 3+: every 3-4 weeks after that

 This where users can start public usage of their dapps (probably still at small scale initially)

Goals

  • Increase the overall capacity per ledger (more tps).
  • This is the main way we will manage capacity issues in the extended network, so in some cases we may propose to reduce the capacity at the ledger level.
  • Adjust classic capacity as needed
  • Adjust market price of resources