pub struct Keypair(ed25519_dalek::Keypair);
# solana config get //其中Keypair Path: /xxxxx/.config/solana/id.json 则为默认存储solana-keygen new的私钥地址
// 将https://www.sollet.io/# 中的私钥导出,存入Keypair Path: /xxxxx/.config/solana/id.json 中
# solana-keygen pubkey //显示的地址与 https://www.sollet.io/# 中的地址一致。
# solana address //显示的地址与 https://www.sollet.io/# 中的地址一致。
# solana config set --url https://api.testnet.solana.com //配置连接测试网
# solana airdrop 1 //获取1SOL 测试token
# solana balance //获取token余额
// 强制生成新的key
# solana-keygen new --no-passphrase --force
Bitcoin and Ethereum use Secp256k1, NEO uses secp256r1, Cardano and Solana Ed25519.
In any case, the overall process goes like this:
Private-key → ed25519-elliptic-curve-magic → toBase58 → Address
An account is essentially a file with an address (pubkey) that lives on the Solana blockchain. If you need to store data on chain it gets stored in an account. Accounts live in the memory of the network of validators. An account must pay rent (see below) in order to persist on chain.
Solana中的account分为:
Solana中的stake account 用于 delegate tokens to validators,来赚取奖励。
stake account的创建和维护不同于传统的wallet address,wallet address又名system account。
system account仅支持收发SOL,而stake account支持delegate token所需的复杂操作。
不同于以太坊和比特币,为了keep accounts alive,Solana中引入了称为rent的storage cost。
这种定期收取租金的做法有效地迫使Validator不要乐观地将过期账户存储到冷库中,从而节省存储成本,这对账户所有者不利,并可能导致他们的交易比其他人拖延更长的时间。另一方面,这可以防止恶意用户创建大量垃圾帐户,加重验证程序的负担。
当前主网和测试网的fixed rent fee为19.055441478439427 lamports per byte-epoch。一个epoch对应约2天。(1 lamport=10^{-9} SOL)
Rent计算中会包含account metadata(address, owner, lamports等等)的size,因此,最小的account,其rent计算的大小为128bytes,对应一个epoch的租金为2439 lamports。
而对于具有15000bytes的account,其每个epoch的租金为0.000288276SOL,2年的租金为0.10529088 SOL。
对于wallet address(又名system account),拥有该地址私钥的holder可控制该钱包。
每个stake account都有唯一的地址,可通过命令行或network explorer工具来查看账户信息。但是,stake account可以没有对应的私钥,即使有关联的私钥,也没法控制该stake account。
仅在 使用命令行方式创建stake account 时,才会有对应stake account address的keypair file,创建该keypair file的主要目的也仅仅是用于保证所创建的stake account address是新的且unique的。
特定类型的account可有一种或多种关联的signing authority。account authority用于对该账号控制的特定交易进行签名。
而在其他区块链系统中,控制account address对应keypair的holder可控制该account的所有行为。Solana的设计有所不同,借助不同的authority来控制account的不同行为。
每个stake account有2种不同的signing authority,用于控制基于该stake account的不同行为:
其中,stake authority主要用于对以下操作进行签名:
withdraw authority主要用于对以下操作进行签名:
当stake account创建时,就已设置了stake authority和withdraw authority,后续跟根据需要修改,stake authority 和 withdraw authority可为相同的地址,也可为2个不同的地址。其中withdraw authority keypair对账号的控制权更强,因为它可用于:
因此,当管理stake account时,保护withdraw authority keypair至关重要。
$ ./solana stake-account E238XEFHdVXP5svYwa46R3gutLS5uyvgk4DGaUsPqmeM
Balance: 180064.987050082 SOL
Rent Exempt Reserve: 0.00228288 SOL
Delegated Stake: 180064.984767202 SOL
Active Stake: 180064.984767202 SOL
Delegated Vote Account Address: 13DmkMhdpmJJu7nU2ozAyPiKuopZbYShMHV3JAA7YVYC
Stake Authority: CbGav5iwgvGhJt8fJgha2ekE5pPguAisYwtcU23sHaZP
Withdraw Authority: CbGav5iwgvGhJt8fJgha2ekE5pPguAisYwtcU23sHaZP
借助$ ./solana validators
可查看到当前Solana网络中所有Validators的identity和vote account。
每个stake account一次仅允许delegate给一个validator。该stake account中的tokens要么全部delegated,要么全部un-delegated,要么在称为delegated或un-delegated的过程中。若要将你的token的一部分(而不是全部)delegate给a validator,或者同时delegate给多个validators,则必须创建多个stake accounts。
可基于拥有token的wallet address来创建多个stake accounts,或者,创建一个大的stake account,然后借助stake authority来将该account切分为多个account,每个account的金额可自行设定。
可对多个stake account分配相同的stake authority和withdraw authority。
2个具有相同stake authority和lockup的stake authority可merge为一个单独的stake account。满足以下条件时,可进行merge操作:
以下场景时,voter pubkey和vote credits应匹配:
除以上条件和场景之外的其他情况,merge操作都将失败。
当a stake account is delegated 或 a delegation is deactivated,该操作都不会立刻生效。
delegation和deactivation将需要几个epochs来完成。
同时,在单个epoch中,可delegated或deactivated的总stake也有限制,以防止网络中总体stake发生大幅突变。由于warmup和cooldown取决于网络中其他参与者的行为,具体的生效周期将很难预测。
详细的warmup和cooldown timing规则可参看:https://docs.solana.com/cluster/stake-delegation-and-rewards#stake-warmup-cooldown-withdrawal。
stake accounts有lockup,用于防止其拥有的tokens在特定的日期或epoch之前被withdraw。
当lockup时,stake account仍然可以:
但是,不支持对其进行withdraw into a wallet address操作。
A lockup can only be added when a stake account is first created, but it can be modified later, by the lockup authority or custodian, the address of which is also set when the account is created.
与Solana中的其他类型的account类似,balance为0 SOL的stake account将不再track。当一个stake account未delegated,且其拥有的所有token都被withdraw to a wallet address时,该account address将被destroyed,未来将需要手工re-created for the address to be used again。
在Solana中,若想成为Validator,则需要创建vote account。可通过solana-create-vote-account
来创建vote account。
除vote account address本身外,vote account的其他方面均可修改:
solana-vote-update-validator
来修改validator identity。solana-vote-authorize-voter
来修改vote authority。solana--vote-authorize-withdrawer
来修改withdraw authority。solana-vote-update-commission
来修改commission。vote account address 的创建方式有2种:
vote account address不需要对任何交易进行签名,仅用于look up the account information。
当某人需要delegate tokens in a stake account时,在该delegation command中需指定the vote account address of the validator to whom the token-holder wants to delegate。
validator identity为system account,用于 pay for all the vote transaction fees submitted to the vote account。
由于validator is expected to vote on most valid blocks it receives, validator identity is frequently (可能每秒多次) signing transactions and paying fees。因此,需要validator identity keypair需要以热钱包(keypair file)的方式存储于validator进程所运行的系统上。
通常,热钱包的安全性要低于离线或冷钱包,validator operator应在identity account中选择存储小额够一定期限内(数周或数月)用于投票的费用。这将有助于控制因节点硬盘或文件系统故障等导致的资金丢失风险。
validator的identity account应定期topped off from a more secure wallet。
当vote account创建时,需提供validator identity。
vote authority keypair用于sign each vote transaction the validator node wants to submit to the cluster。
vote authority没必要与validator identity不同。因为vote authority和identity account雷士,均需要频繁的对交易签名,因此,没必要在validator进程所在的文件系统中再保存一个hot keypair。
vote authority可设置为与validator identity account一样。当两者一样时,在每个vote transaction中仅需要一个签名,来sign the vote and pay the transaction fee。由于Solana中的transaction fee是根据签名个数来评估的,使用一个签名相比于使用2个不同的账号进行2次签名,交易费用可节约一半。
可在vote account创建时设置vote authority,若未明确指出,其默认为与validator identity一样。可通过solana-vote-authorize-voter
来修改。
不过,vote authority在每个epoch最多可修改一次,且在下个epoch才生效。为了平滑的在epoch边界过度vote signing,可在solana-validator中附带–authorized-voter参数来明确指定。
withdraw authority keypair通过solana-withdraw-from-vote-account
命令来withdraw funds from a vote account。validator获得的任何网络激励都将存入vote account中,且仅可通过withdraw authority keypair签名来获取。
需要使用withdraw authority keypair来对以下交易进行签名:
由于vote account的balance会增加,因此需要将withdraw authority keypair以离线或冷钱包的方式保存,因为其并不需要频繁的对交易进行签名。
可使用solana--vote-authorize-withdrawer
命令来修改withdraw authority。
commission为:the percent of network rewards earned by a validator that are deposited into the validator’s vote account。剩余的rewards将分发给all of the stake accounts delegated to that vote account, proportional to the active stake weight of each stake account。
如,若a vote account的commission为10%,则all rewards earned by that validator in a given epoch的10%将在下一个epoch的第一个block中直接存入到the vote account,而剩下的90%将直接作为active stake存入各delegated stake accounts。
为了吸引更多的stake delegations,validator可设置更低的commission值。由于运行和维护validator节点需要一定的成本,应设置一个合理高的commission值来覆盖其运维成本。
可在创建vote account时附加–commission来在设置commission值,若未明确指定,该值默认为100%,即所有奖励直接存入vote account,而没有奖励会分发给delegated stake accounts中。
可通过solana-vote-update-commission
来修改commission,该值取值范围为0~100,--commision 10
表示为10% commission。
对于live validator,rotating the vote account authority keys需要以下特殊操作,详细参见:https://docs.solana.com/running-validator/vote-accounts#key-rotation。
在Solana中,智能合约统称为program。每个链上program其本质就是个account,只是其标记为“Executable: true”,意味着它是an executable file。program一旦部署在链上,就可read并通过instructions来交互。
native program,为网络中必须运行的特殊program,主要有:【详细参见:Solana native programs】
token program:为实现不同于native SOL token的 fungible或non-fungible token的program。
associated token accounts:若an account holds any token other than the native Solana token, it will have an associated token account for each type of token it holds。
instruction:what is called in order to execute a function of a program。
Sysvar:为an account which enforces certain variables of the network such as epoch, rent, validator rewards, etc…
Program Derived Addresses (PDAs):PDAs enable the transfer of an account’s ownership from one program to another. This is useful for situations that require an escrow account such as auctions, DEXs, swaps, etc…
Cross Program Invocation:Calling a program from another program. This is helpful for more complex on chain actions. Such as executing an instruction of an associated token account program during a token swap。
为了防止replay,Solana交易中包含了一个nonce field,里面存储了a recent blockhash value。交易中包含的blockhash若为2分钟前的,则判定为too old,将被网络拒绝入链。
但是对于一些custodial service,其需要更长的事件来为交易签名,因此,需要设计一种机制来满足线下参与者。
新增的nonce field需满足以下要求:
基于contract的解决方案为:
client可在交易的recent_blockhash
field 中 “stash” a nonce value for future use,这类似于the Compare and Swap atomic instruction,implemented by some CPU ISAs。
当使用durable nonce时,client必须首先从account data中查询该值。交易的构建过程中需额外引入:
recent_blockhash
fieldAdvanceNonceAccount
instruction is the first issued in the transaction详细的合约机制为:
Start
Create Account
state = Uninitialized
NonceInstruction
if state == Uninitialized
if account.balance < rent_exempt
error InsufficientFunds
state = Initialized
elif state != Initialized
error BadState
if sysvar.recent_blockhashes.is_empty()
error EmptyRecentBlockhashes
if !sysvar.recent_blockhashes.contains(stored_nonce)
error NotReady
stored_hash = sysvar.recent_blockhashes[0]
success
WithdrawInstruction(to, lamports)
if state == Uninitialized
if !signers.contains(owner)
error MissingRequiredSignatures
elif state == Initialized
if !sysvar.recent_blockhashes.contains(stored_nonce)
error NotReady
if lamports != account.balance && lamports + rent_exempt > account.balance
error InsufficientFunds
account.balance -= lamports
to.balance += lamports
success
希望使用该feature的client需在system program下创建一个nonce account。该account将在Uninitialized
state with no stored hash, and thus unusable。
为了初始化新创建的nonce account,需借助InitializeNonceAccount
指令。该指令的输入参数为:the Pubkey
of the account’s authority。
nonce account必须为rent-exempt的,以满足该feature的data-persistence要求,因此,需确保在初始化时存入足够的lamports。初始化成功后,the cluster’s most recent blockhash is stored along with specified nonce authority Pubkey
。
AdvanceNonceAccount
指令用于管理nonce account的stored nonce value。其存储了the cluster’s most recent blockhash in the account’s state data, failing if that matches the value already stored there。这种check可防止同一区块内的replay交易。
由于nonce account必须是rent-exempt的,因此,需要用一个custom withdraw指令来从该nonce account中移出资金。WithdrawNonceAccount
指令的输入参数只有一个,即the lamports to withdraw,同时enforces rent-exemption by preventing the account’s balance from falling below the rent-exempt minimum。An exception to this check is if the final balance would be zero lamports, which makes the account eligible for deletion. This account closure detail has an additional requirement that the stored nonce value must not match the cluster’s most recent blockhash, as per AdvanceNonceAccount.
nonce account的nonce authority可使用AuthorizeNonceAccount
指令来修改,输入参数只有一个:the Pubkey
of the new authority。执行该指令将grants full control over the account and its balance to the new authority。
AdvanceNonceAccount
, WithdrawNonceAccount
and AuthorizeNonceAccount
all require the current nonce authority for the account to sign the transaction.
具体的nonce account Runtime Support见:https://docs.solana.com/implemented-proposals/durable-tx-nonces#runtime-support
nonce account的authority可optionally be assigned to another account。若更换新的authority,则将接管之前authority的所有权限,包括the account creator。该feature有助于创建更复杂的account ownership arrangements,以及派生account addresses not associated with a keypair。
以下指令均支持--nonce-authority
参数:
Durable transaction nonce是为了解决交易中recent_blockhash
lifetime较短问题,便于线下参与者参与签名等操作。
为了保证keypair完全线下,可采用纸钱包指令替换:
solana-keygen new -o nonce-keypair.json
solana create-nonce-account nonce-keypair.json 1
查询the stored nonce value:
solana nonce nonce-keypair.json
更新nonce值:
solana new-nonce nonce-keypair.json
显示nonce account:
solana nonce-account nonce-keypair.json
从nonce account中提取资金:
solana withdraw-from-nonce-account nonce-keypair.json ~/.config/solana/id.json 0.5
为nonce account分配新的authority:
solana authorize-nonce-account nonce-keypair.json nonce-authority.json
假设Alice想使用durable nonce来给Bob支付0.01SOL:
1)创建账号:
$ solana-keygen new -o alice.json
$ solana-keygen new -o nonce.json
$ solana-keygen new -o bob.json
2)给Alice充钱:
$ solana airdrop -k alice.json 1
1 SOL
3)为Alice创建nonce account:
$ solana create-nonce-account -k alice.json nonce.json 0.1
3KPZr96BTsL3hqera9up82KAU462Gz31xjqJ6eHUAjF935Yf8i1kmfEbo6SVbNaACKE5z6gySrNjVRvmS8DcPuwV
4)模拟签名时间很长的转账交易——转账失败:
$ solana pay -k alice.json --blockhash expiredDTaxfagttWjQweib42b6ZHADSx94Tw8gHx3W7 bob.json 0.01
[2020-01-02T18:48:28.462911000Z ERROR solana_cli::cli] Io(Custom { kind: Other, error: "Transaction \"33gQQaoPc9jWePMvDAeyJpcnSPiGUAdtVg8zREWv4GiKjkcGNufgpcbFyRKRrA25NkgjZySEeKue5rawyeH5TzsV\" failed: None" })
Error: Io(Custom { kind: Other, error: "Transaction \"33gQQaoPc9jWePMvDAeyJpcnSPiGUAdtVg8zREWv4GiKjkcGNufgpcbFyRKRrA25NkgjZySEeKue5rawyeH5TzsV\" failed: None" })
5)借助Alice的nonce中存储的blockhash可成功转账:
$ solana nonce-account nonce.json
balance: 0.1 SOL
minimum balance required: 0.00136416 SOL
nonce: F7vmkY3DTaxfagttWjQweib42b6ZHADSx94Tw8gHx3W7
$ solana pay -k alice.json --blockhash F7vmkY3DTaxfagttWjQweib42b6ZHADSx94Tw8gHx3W7 --nonce nonce.json bob.json 0.01
HR1368UKHVZyenmH7yVz5sBAijV6XAPeWbEiXEGVYQorRMcoijeNAbzZqEZiH8cDB8tk65ckqeegFjK8dHwNFgQ
6)验证转账结果和nonce account值更新:
$ solana balance -k bob.json
0.01 SOL
$ solana nonce-account nonce.json
balance: 0.1 SOL
minimum balance required: 0.00136416 SOL
nonce: 6bjroqDcZgTv6Vavhqf81oBHTv3aMnX19UTB51YhAZnN
通过$spl-token create-account TOKENADDRESS
创建的即为token account。
Before the user can receive tokens, their associated token account must be created on-chain, requiring a small amount of SOL to mark the account as rent-exempt.
$ spl-token create-account 2ceBgDjUmYRMi2nWgU4WyknrSjYEZircNjxuK5BzSnda
Creating account B5siXgxo3GcmkvHJwfqtTpyZcT4ZPuDWaYE4RrDab6qX
Signature: 5akVkmWVjFCzaTrVr9uk2dMYdAzPBVQiCufF61oagKLCUY59ZYFwmr6VAei7KshbAabRQy12iMaqy1GhcWJaD84G
$ solana balance B5siXgxo3GcmkvHJwfqtTpyZcT4ZPuDWaYE4RrDab6qX
0.00203928 SOL
There’s no restriction on who can create a user’s associated token account. It could either be created by the wallet on behalf of the user or funded by a 3rd party through an airdrop campaign.
可即时清理关闭账号,从而实现对账号中余额的回收,详细见:https://spl.solana.com/token#closing-accounts。
根据Associated Token Account Program :
对于相同的mint,一个用户可能对应有任意多个token account,这使得其他用户很难知道which account they should send tokens to and introduces friction into many other asepcts of token management。
为此,需引入deterministically 方法来derive a token account key from a user’s main System account address and a token mint address,使得用户可创建a main token account for each token he owns。将这些account 称为 Associated Token Accounts。
此外,还支持用户给另一没有该mint token account的用户发送token。与system transfer不同,for a token transfer to succeed the recipient must have a token account with the compatible mint already, and somebody needs to fund that token account. If the recipient must fund it first, it makes things like airdrop compaigns difficult and just generally increases the friction of token transfers. AToken 允许发送者来创建 接收者的associated token account,使得token transfer可正常运行。
The associated token account for a given wallet address is simply na program-derived account consisting of the wallet address itself and the token mint.
客户端可调用create_associated_token_address
Rust函数来派生wallet’s associated token account。所创建的associated token account仍然完全由钱包控制,与钱包自己创建的效果是一样的。
[1] Solana Stake Account Structure
[2] Solana Delegate Stake
[3] Solana Development Tutorial: Program 101
[4] Solana Development Tutorial: Environment setup
[5] [How to] create a Solana Address & delegate your SOL tokens using the Terminal (CLI) on your Mac
[6] Solana Vanity Address using GPUs
[7] Solana Clusters
[8] Vote account management
[9] Solana Programming Concepts
[10] Durable Transaction Nonces
[11] Durable Transaction Nonces Proposal