2020-11-03 12:53:17 -08:00
|
|
|
---
|
|
|
|
title: "Accounts"
|
|
|
|
---
|
|
|
|
|
|
|
|
## Storing State between Transactions
|
|
|
|
|
|
|
|
If the program needs to store state between transactions, it does so using
|
|
|
|
_accounts_. Accounts are similar to files in operating systems such as Linux.
|
|
|
|
Like a file, an account may hold arbitrary data and that data persists beyond
|
|
|
|
the lifetime of a program. Also like a file, an account includes metadata that
|
|
|
|
tells the runtime who is allowed to access the data and how.
|
|
|
|
|
|
|
|
Unlike a file, the account includes metadata for the lifetime of the file. That
|
|
|
|
lifetime is expressed in "tokens", which is a number of fractional native
|
|
|
|
tokens, called _lamports_. Accounts are held in validator memory and pay
|
2020-11-13 10:18:04 -08:00
|
|
|
["rent"](#rent) to stay there. Each validator periodically scans all accounts
|
2021-04-30 01:20:56 -07:00
|
|
|
and collects rent. Any account that drops to zero lamports is purged. Accounts
|
2021-02-16 08:58:33 -08:00
|
|
|
can also be marked [rent-exempt](#rent-exemption) if they contain a sufficient
|
2020-11-13 10:18:04 -08:00
|
|
|
number of lamports.
|
2020-11-03 12:53:17 -08:00
|
|
|
|
|
|
|
In the same way that a Linux user uses a path to look up a file, a Solana client
|
2020-11-13 10:18:04 -08:00
|
|
|
uses an _address_ to look up an account. The address is a 256-bit public key.
|
2020-11-03 12:53:17 -08:00
|
|
|
|
|
|
|
## Signers
|
|
|
|
|
|
|
|
Transactions may include digital [signatures](terminology.md#signature)
|
|
|
|
corresponding to the accounts' public keys referenced by the transaction. When a
|
|
|
|
corresponding digital signature is present it signifies that the holder of the
|
|
|
|
account's private key signed and thus "authorized" the transaction and the
|
|
|
|
account is then referred to as a _signer_. Whether an account is a signer or not
|
|
|
|
is communicated to the program as part of the account's metadata. Programs can
|
|
|
|
then use that information to make authority decisions.
|
|
|
|
|
|
|
|
## Read-only
|
|
|
|
|
2020-11-13 10:18:04 -08:00
|
|
|
Transactions can [indicate](transactions.md#message-header-format) that some of
|
|
|
|
the accounts it references be treated as _read-only accounts_ in order to enable
|
|
|
|
parallel account processing between transactions. The runtime permits read-only
|
|
|
|
accounts to be read concurrently by multiple programs. If a program attempts to
|
|
|
|
modify a read-only account, the transaction is rejected by the runtime.
|
2020-11-03 12:53:17 -08:00
|
|
|
|
|
|
|
## Executable
|
|
|
|
|
2020-11-13 10:18:04 -08:00
|
|
|
If an account is marked "executable" in its metadata then it is considered a
|
|
|
|
program which can be executed by including the account's public key an
|
|
|
|
instruction's [program id](transactions.md#program-id). Accounts are marked as
|
|
|
|
executable during a successful program deployment process by the loader that
|
2021-04-30 01:20:56 -07:00
|
|
|
owns the account. For example, during BPF program deployment, once the loader
|
2020-11-13 10:18:04 -08:00
|
|
|
has determined that the BPF bytecode in the account's data is valid, the loader
|
2021-04-30 01:20:56 -07:00
|
|
|
permanently marks the program account as executable. Once executable, the
|
2020-11-13 10:18:04 -08:00
|
|
|
runtime enforces that the account's data (the program) is immutable.
|
2020-11-03 12:53:17 -08:00
|
|
|
|
|
|
|
## Creating
|
|
|
|
|
|
|
|
To create an account a client generates a _keypair_ and registers its public key
|
|
|
|
using the `SystemProgram::CreateAccount` instruction with preallocated a fixed
|
|
|
|
storage size in bytes. The current maximum size of an account's data is 10
|
|
|
|
megabytes.
|
|
|
|
|
|
|
|
An account address can be any arbitrary 256 bit value, and there are mechanisms
|
|
|
|
for advanced users to create derived addresses
|
|
|
|
(`SystemProgram::CreateAccountWithSeed`,
|
2020-11-13 10:18:04 -08:00
|
|
|
[`Pubkey::CreateProgramAddress`](calling-between-programs.md#program-derived-addresses)).
|
2020-11-03 12:53:17 -08:00
|
|
|
|
|
|
|
Accounts that have never been created via the system program can also be passed
|
|
|
|
to programs. When an instruction references an account that hasn't been
|
|
|
|
previously created the program will be passed an account that is owned by the
|
|
|
|
system program, has zero lamports, and zero data. But, the account will reflect
|
|
|
|
whether it is a signer of the transaction or not and therefore can be used as an
|
|
|
|
authority. Authorities in this context convey to the program that the holder of
|
|
|
|
the private key associated with the account's public key signed the transaction.
|
|
|
|
The account's public key may be known to the program or recorded in another
|
|
|
|
account and signify some kind of ownership or authority over an asset or
|
|
|
|
operation the program controls or performs.
|
|
|
|
|
|
|
|
## Ownership and Assignment to Programs
|
|
|
|
|
|
|
|
A created account is initialized to be _owned_ by a built-in program called the
|
|
|
|
System program and is called a _system account_ aptly. An account includes
|
2020-11-13 10:18:04 -08:00
|
|
|
"owner" metadata. The owner is a program id. The runtime grants the program
|
|
|
|
write access to the account if its id matches the owner. For the case of the
|
2020-11-03 12:53:17 -08:00
|
|
|
System program, the runtime allows clients to transfer lamports and importantly
|
2020-11-13 10:18:04 -08:00
|
|
|
_assign_ account ownership, meaning changing owner to different program id. If
|
2020-11-03 12:53:17 -08:00
|
|
|
an account is not owned by a program, the program is only permitted to read its
|
|
|
|
data and credit the account.
|
|
|
|
|
2021-01-25 15:36:11 -08:00
|
|
|
## Verifying validity of unmodified, reference-only accounts
|
|
|
|
|
|
|
|
For security purposes, it is recommended that programs check the validity of any
|
|
|
|
account it reads but does not modify.
|
|
|
|
|
|
|
|
The security model enforces that an account's data can only be modified by the
|
2021-04-30 01:20:56 -07:00
|
|
|
account's `Owner` program. Doing so allows the program to trust that the data
|
|
|
|
passed to them via accounts they own will be in a known and valid state. The
|
2021-01-25 15:36:11 -08:00
|
|
|
runtime enforces this by rejecting any transaction containing a program that
|
2021-04-30 01:20:56 -07:00
|
|
|
attempts to write to an account it does not own. But, there are also cases
|
2021-01-25 15:36:11 -08:00
|
|
|
where a program may merely read an account they think they own and assume the
|
2021-04-30 01:20:56 -07:00
|
|
|
data has only been written by themselves and thus is valid. But anyone can
|
2021-01-25 15:36:11 -08:00
|
|
|
issues instructions to a program, and the runtime does not know that those
|
2021-04-30 01:20:56 -07:00
|
|
|
accounts are expected to be owned by the program. Therefore a malicious user
|
2021-01-25 15:36:11 -08:00
|
|
|
could create accounts with arbitrary data and then pass these accounts to the
|
2021-04-30 01:20:56 -07:00
|
|
|
program in the place of a valid account. The arbitrary data could be crafted in
|
2021-01-25 15:36:11 -08:00
|
|
|
a way that leads to unexpected or harmful program behavior.
|
|
|
|
|
|
|
|
To check an account's validity, the program should either check the account's
|
|
|
|
address against a known value or check that the account is indeed owned
|
|
|
|
correctly (usually owned by the program itself).
|
|
|
|
|
2021-04-30 01:20:56 -07:00
|
|
|
One example is when programs read a sysvar. Unless the program checks the
|
2021-01-25 15:36:11 -08:00
|
|
|
address or owner, it's impossible to be sure whether it's a real and valid
|
|
|
|
sysvar merely by successful deserialization. Accordingly, the Solana SDK [checks
|
|
|
|
the sysvar's validity during
|
|
|
|
deserialization](https://github.com/solana-labs/solana/blob/a95675a7ce1651f7b59443eb146b356bc4b3f374/sdk/program/src/sysvar/mod.rs#L65).
|
|
|
|
|
|
|
|
If the program always modifies the account in question, the address/owner check
|
|
|
|
isn't required because modifying an unowned (could be the malicious account with
|
|
|
|
the wrong owner) will be rejected by the runtime, and the containing transaction
|
|
|
|
will be thrown out.
|
|
|
|
|
2020-11-03 12:53:17 -08:00
|
|
|
## Rent
|
|
|
|
|
|
|
|
Keeping accounts alive on Solana incurs a storage cost called _rent_ because the
|
|
|
|
cluster must actively maintain the data to process any future transactions on
|
|
|
|
it. This is different from Bitcoin and Ethereum, where storing accounts doesn't
|
|
|
|
incur any costs.
|
|
|
|
|
|
|
|
The rent is debited from an account's balance by the runtime upon the first
|
|
|
|
access (including the initial account creation) in the current epoch by
|
|
|
|
transactions or once per an epoch if there are no transactions. The fee is
|
|
|
|
currently a fixed rate, measured in bytes-times-epochs. The fee may change in
|
|
|
|
the future.
|
|
|
|
|
|
|
|
For the sake of simple rent calculation, rent is always collected for a single,
|
|
|
|
full epoch. Rent is not pro-rated, meaning there are neither fees nor refunds
|
|
|
|
for partial epochs. This means that, on account creation, the first rent
|
|
|
|
collected isn't for the current partial epoch, but collected up front for the
|
|
|
|
next full epoch. Subsequent rent collections are for further future epochs. On
|
|
|
|
the other end, if the balance of an already-rent-collected account drops below
|
|
|
|
another rent fee mid-epoch, the account will continue to exist through the
|
|
|
|
current epoch and be purged immediately at the start of the upcoming epoch.
|
|
|
|
|
|
|
|
Accounts can be exempt from paying rent if they maintain a minimum balance. This
|
|
|
|
rent-exemption is described below.
|
|
|
|
|
|
|
|
### Calculation of rent
|
|
|
|
|
|
|
|
Note: The rent rate can change in the future.
|
|
|
|
|
|
|
|
As of writing, the fixed rent fee is 19.055441478439427 lamports per byte-epoch
|
2020-11-11 17:46:24 -08:00
|
|
|
on the testnet and mainnet-beta clusters. An [epoch](terminology.md#epoch) is
|
2020-11-03 12:53:17 -08:00
|
|
|
targeted to be 2 days (For devnet, the rent fee is 0.3608183131797095 lamports
|
|
|
|
per byte-epoch with its 54m36s-long epoch).
|
|
|
|
|
|
|
|
This value is calculated to target 0.01 SOL per mebibyte-day (exactly matching
|
|
|
|
to 3.56 SOL per mebibyte-year):
|
|
|
|
|
|
|
|
```text
|
|
|
|
Rent fee: 19.055441478439427 = 10_000_000 (0.01 SOL) * 365(approx. day in a year) / (1024 * 1024)(1 MiB) / (365.25/2)(epochs in 1 year)
|
|
|
|
```
|
|
|
|
|
|
|
|
And rent calculation is done with the `f64` precision and the final result is
|
|
|
|
truncated to `u64` in lamports.
|
|
|
|
|
|
|
|
The rent calculation includes account metadata (address, owner, lamports, etc)
|
|
|
|
in the size of an account. Therefore the smallest an account can be for rent
|
|
|
|
calculations is 128 bytes.
|
|
|
|
|
|
|
|
For example, an account is created with the initial transfer of 10,000 lamports
|
|
|
|
and no additional data. Rent is immediately debited from it on creation,
|
|
|
|
resulting in a balance of 7,561 lamports:
|
|
|
|
|
|
|
|
```text
|
|
|
|
Rent: 2,439 = 19.055441478439427 (rent rate) * 128 bytes (minimum account size) * 1 (epoch)
|
|
|
|
Account Balance: 7,561 = 10,000 (transfered lamports) - 2,439 (this account's rent fee for an epoch)
|
|
|
|
```
|
|
|
|
|
|
|
|
The account balance will be reduced to 5,122 lamports at the next epoch even if
|
|
|
|
there is no activity:
|
|
|
|
|
|
|
|
```text
|
|
|
|
Account Balance: 5,122 = 7,561 (current balance) - 2,439 (this account's rent fee for an epoch)
|
|
|
|
```
|
|
|
|
|
|
|
|
Accordingly, a minimum-size account will be immediately removed after creation
|
|
|
|
if the transferred lamports are less than or equal to 2,439.
|
|
|
|
|
|
|
|
### Rent exemption
|
|
|
|
|
|
|
|
Alternatively, an account can be made entirely exempt from rent collection by
|
|
|
|
depositing at least 2 years-worth of rent. This is checked every time an
|
|
|
|
account's balance is reduced and rent is immediately debited once the balance
|
|
|
|
goes below the minimum amount.
|
|
|
|
|
|
|
|
Program executable accounts are required by the runtime to be rent-exempt to
|
|
|
|
avoid being purged.
|
|
|
|
|
|
|
|
Note: Use the [`getMinimumBalanceForRentExemption` RPC
|
2020-11-11 17:46:24 -08:00
|
|
|
endpoint](developing/clients/jsonrpc-api.md#getminimumbalanceforrentexemption) to calculate the
|
2020-11-03 12:53:17 -08:00
|
|
|
minimum balance for a particular account size. The following calculation is
|
|
|
|
illustrative only.
|
|
|
|
|
|
|
|
For example, a program executable with the size of 15,000 bytes requires a
|
|
|
|
balance of 105,290,880 lamports (=~ 0.105 SOL) to be rent-exempt:
|
|
|
|
|
|
|
|
```text
|
|
|
|
105,290,880 = 19.055441478439427 (fee rate) * (128 + 15_000)(account size including metadata) * ((365.25/2) * 2)(epochs in 2 years)
|
|
|
|
```
|
2021-04-14 20:56:29 -07:00
|
|
|
|
|
|
|
Rent can also be estimated via the [`solana rent` CLI subcommand](cli/usage.md#solana-rent)
|
|
|
|
|
|
|
|
```text
|
|
|
|
$ solana rent 15000
|
|
|
|
Rent per byte-year: 0.00000348 SOL
|
|
|
|
Rent per epoch: 0.000288276 SOL
|
|
|
|
Rent-exempt minimum: 0.10529088 SOL
|
|
|
|
```
|
|
|
|
|
|
|
|
Note: Rest assured that, should the storage rent rate need to be increased at some
|
|
|
|
point in the future, steps will be taken to ensure that accounts that are rent-exempt
|
|
|
|
before the increase will remain rent-exempt afterwards
|