Skip to main content

账户

在交易之间存储状态#

如果程序需要在交易之间存储状态,则可以使用accounts进行存储。 帐户类似于Linux等操作系统中的文件。 就像文件一样,帐户可以保存任意数据,并且该数据会在程序的生存期内持续存在。 帐户也像文件一样,包含元数据,该元数据告诉运行时允许谁访问数据以及如何访问数据。

与文件不同,该帐户包含文件生存期内的元数据。 该存在时间用“代币”表示,即称为lamports的许多局部原生代币。 帐户保存在验证节点的内存中,并支付“rent”留在那里。 每个验证节点都会定期扫描所有帐户并收取租金。 任何掉落到零零花的账户都将被清除。 如果帐户包含足够数量的Lamport,也可以标记为rent-exempt

与Linux用户使用路径查找文件的方式相同,Solana客户端使用address查找帐户。 该地址是一个256位公共密钥。

签名者#

交易可以包括与交易所引用的账户的公共密钥相对应的数字签名。 当存在相应的数字签名时,它表示该帐户的私钥持有人已签名并因此“授权”了该交易,因此该帐户称为signer。 帐户是否为签名者将作为帐户元数据的一部分传达给程序。 然后,程序可以使用该信息来制定权限决策。

只读#

事务可以指示它引用的某些帐户被视为只读帐户,以便能够在事务之间进行并行帐户处理。 运行时允许多个程序同时读取只读帐户。 如果程序尝试修改只读帐户,则运行时将拒绝该事务。

可执行#

如果某个帐户在其元数据中被标记为“可执行”,则将其视为可以通过将帐户的公钥包含在指令的程序ID中来执行的程序。 在成功的程序部署过程中,拥有该帐户的加载程序将帐户标记为可执行文件。 例如,在BPF程序部署期间,一旦加载程序确定帐户数据中的BPF字节码有效,则加载程序会将程序帐户永久标记为可执行文件。 一旦可执行,运行时将强制该帐户的数据(程序) 是不可变的。

创建#

为了创建一个帐户,客户端生成一个keypair并使用SystemProgram::CreateAccount指令注册其公共密钥,并预先分配了固定的存储大小(以字节为单位)。 当前帐户数据的最大大小为10MB。

帐户地址可以是任意的256位值,并且高级用户可以使用一些机制来创建派生地址(SystemProgram::CreateAccountWithSeedPubkey::CreateProgramAddress)。

从未通过系统程序创建的帐户也可以传递到程序。 当指令引用以前尚未创建的帐户时,程序将通过系统程序拥有的帐户,该帐户具有0个Lamport和0个数据。 但是,该帐户将反映它是否是该交易的签名者,因此可以用作授权。 在这种情况下,授权机构向程序传达与帐户的公共密钥相关联的私有密钥的持有者对交易进行了签名。 该程序可能知道该帐户的公钥,也可能将其记录在另一个帐户中,并表示对该程序控制或执行的资产或操作具有某种所有权或授权。

程序的所有权和分配#

创建的帐户由称为System程序的内置程序初始化为owned,并适当地称为system account。 帐户包含“所有者”元数据。 所有者是一个程序ID。 如果运行时的ID与所有者匹配,则运行时将授予该程序对该帐户的写访问权限。 对于System程序,运行时允许客户端转移Lamport,并且重要的是转移帐户所有权,这意味着将所有者更改为其他程序ID。 如果某个帐户不属于某个程序,则仅允许该程序读取其数据并将该帐户记入贷方。

承租#

使帐户在Solana上保持活动状态会产生称为rent的存储成本,因为集群必须积极维护数据以处理其上的任何将来的事务。 这与比特币和以太坊不同,在比特币和以太坊中,存储帐户不会产生任何费用。

租金是在当前时期通过事务在第一次访问(包括初始帐户创建) 时通过运行时从帐户余额中扣除的,如果没有交易,则在每个时期一次。 该费用目前是固定费率,以字节乘以时期为单位。 该费用将来可能会更改。

为了简化租金计算,租金始终是在一个完整的时期内收取的。 租金不是按比例分配的,这意味着部分时期既不收费也不退款。 这意味着,在创建帐户时,收取的首笔租金不是针对当前的部分时期,而是针对下一个完整的时期而预先收取的租金。 随后的租金收取是未来的进一步时期。 另一方面,如果一个已出租的帐户的余额降到另一个租金费用的中间时期以下,则该帐户将在当前时期继续存在,并在即将到来的时期开始时立即被清除。

如果帐户保持最低余额,则可以免交租金。 此免租金描述如下。

租金计算#

注意:租金率将来可能会改变。

在撰写本文时,在testnet和mainnet-beta群集上,固定租金为每字节纪元19.055441478439427兰特。 一个epoch的目标是2天(对于devnet,租金为每字节纪元 0.3608183131797095 lamports,长度为54m36s长)。

计算得出该值的目标是每兆字节天0.01 SOL(与每兆字节年3.56SOL完全匹配):

租金:19.055441478439427=10_000_000(0.01SOL)*365(一年中大约一天)/(1024*1024)(1MiB)/(365.25/2)(一年中的纪元)

租金计算以f64精度完成,最终结果在Lamports中被截断为u64

租金计算包括帐户大小的帐户元数据(地址、所有者、lamports等)。 因此,用于租金计算的最小帐户为128字节。

例如,创建的帐户初始转移了10,000 lamports,并且没有其他数据。 租金会在创建时立即从中扣除,从而产生7,561 lamports的余款:

租金:2,439=19.055441478439427(租金)*128字节(最小帐户大小)*1(纪元)
帐户余额:7,561=10,000(转让的兰特)-2,439(此帐户的时期租金)

即使没有活动,帐户余额也将在下一个时期减少到5,122 lamports:

帐户余额:5,122=7,561(当前余额) -2,439(该帐户的租金,用于某个时期)

因此,如果转移的兰特小于或等于2439,则最小尺寸帐户将在创建后立即删除。

免租金#

另外,通过存入至少2年的租金,可以使一个帐户完全免收租金。 每次帐户余额减少时都会进行检查,一旦余额低于最低金额,便会立即从租金中扣除。

运行时要求程序可执行帐户免租金,以免被清除。

注意:请使用getMinimumBalanceForRentExemptionRPC端点计算特定帐户大小的最小余额。 以下计算仅是说明性的。

例如,一个程序可执行文件的大小为15,000字节,则需要105,290,880 lamports(=〜0.105SOL) 的余额才能免租:

105,290,880=19.055441478439427(手续费率)*(128+15_000)(包括元数据的帐户大小)*((365.25/2)*2)(以2年为周期)