Skip to content

Commit

Permalink
Remove credit-only account handling (solana-labs#6726)
Browse files Browse the repository at this point in the history
* Renaming
- credit-only/credit-debit to read-only/read-write
- debitable to writable

* Remove credit handling, making credit-only accounts read-only

* Update programs to remove deprecated credit-only account designation

* Use readonly and writable instead of underscored types
  • Loading branch information
CriesofCarrots authored Nov 5, 2019
1 parent cea13e9 commit c6931dc
Show file tree
Hide file tree
Showing 20 changed files with 341 additions and 618 deletions.
5 changes: 2 additions & 3 deletions book/src/api-reference/transaction-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

* **num\_credit\_only\_signed\_accounts:** The last

`num_credit_only_signed_accounts` signatures refer to signing
`num_readonly_signed_accounts` signatures refer to signing

credit only accounts. Credit only accounts can be used concurrently

Expand All @@ -24,7 +24,7 @@

* **num\_credit\_only\_unsigned\_accounts:** The last

`num_credit_only_unsigned_accounts` public keys in `account_keys` refer
`num_readonly_unsigned_accounts` public keys in `account_keys` refer

to non-signing credit only accounts

Expand Down Expand Up @@ -60,4 +60,3 @@ A `Transaction` is signed by using an ed25519 keypair to sign the serialization
## Transaction Serialization

`Transaction`s \(and their `message`s\) are serialized and deserialized using the [bincode](https://crates.io/crates/bincode) crate with a non-standard vector serialization that uses only one byte for the length if it can be encoded in 7 bits, 2 bytes if it fits in 14 bits, or 3 bytes if it requires 15 or 16 bits. The vector serialization is defined by Solana's [short-vec](https://github.com/solana-labs/solana/blob/master/sdk/src/short_vec.rs).

2 changes: 1 addition & 1 deletion book/src/proposals/rent.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ Collecting rent on an as-needed basis \(i.e. whenever accounts were loaded/acces

* accounts loaded as "credit only" for a transaction could very reasonably be expected to have rent due,

but would not be debitable during any such transaction
but would not be writable during any such transaction

* a mechanism to "beat the bushes" \(i.e. go find accounts that need to pay rent\) is desirable,

Expand Down
2 changes: 1 addition & 1 deletion book/src/terminology.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ A proof which has the same format as a storage proof, but the sha state is actua

## fee account

The fee account in the transaction is the account pays for the cost of including the transaction in the ledger. This is the first account in the transaction. This account must be declared as Credit-Debit in the transaction since paying for the transaction reduces the account balance.
The fee account in the transaction is the account pays for the cost of including the transaction in the ledger. This is the first account in the transaction. This account must be declared as Read-Write (writable) in the transaction since paying for the transaction reduces the account balance.

## finality

Expand Down
5 changes: 2 additions & 3 deletions book/src/transaction.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# Anatomy of a Transaction

Transactions encode lists of instructions that are executed sequentially, and only committed if all the instructions complete successfully. All account updates are reverted upon the failure of a transaction. Each transaction details the accounts used, including which must sign and which are credit only, a recent blockhash, the instructions, and any signatures.
Transactions encode lists of instructions that are executed sequentially, and only committed if all the instructions complete successfully. All account updates are reverted upon the failure of a transaction. Each transaction details the accounts used, including which must sign and which are read only, a recent blockhash, the instructions, and any signatures.

## Accounts and Signatures

Each transaction explicitly lists all account public keys referenced by the transaction's instructions. A subset of those public keys are each accompanied by a transaction signature. Those signatures signal on-chain programs that the account holder has authorized the transaction. Typically, the program uses the authorization to permit debiting the account or modifying its data.

The transaction also marks some accounts as _credit-only accounts_. The runtime permits credit-only accounts to be credited concurrently. If a program attempts to debit a credit-only account or modify its account data, the transaction is rejected by the runtime.
The transaction also marks some accounts as _read-only accounts_. The runtime permits read-only accounts to be read concurrently. If a program attempts to modify a read-only account, the transaction is rejected by the runtime.

## Recent Blockhash

Expand All @@ -15,4 +15,3 @@ A Transaction includes a recent blockhash to prevent duplication and to give tra
## Instructions

Each instruction specifies a single program account \(which must be marked executable\), a subset of the transaction's accounts that should be passed to the program, and a data byte array instruction that is passed to the program. The program interprets the data array and operates on the accounts specified by the instructions. The program can return successfully, or with an error code. An error return causes the entire transaction to fail immediately.

5 changes: 2 additions & 3 deletions book/src/validator/runtime.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## The Runtime

The runtime is a concurrent transaction processor. Transactions specify their data dependencies upfront and dynamic memory allocation is explicit. By separating program code from the state it operates on, the runtime is able to choreograph concurrent access. Transactions accessing only credit-only accounts are executed in parallel whereas transactions accessing writable accounts are serialized. The runtime interacts with the program through an entrypoint with a well-defined interface. The data stored in an account is an opaque type, an array of bytes. The program has full control over its contents.
The runtime is a concurrent transaction processor. Transactions specify their data dependencies upfront and dynamic memory allocation is explicit. By separating program code from the state it operates on, the runtime is able to choreograph concurrent access. Transactions accessing only read-only accounts are executed in parallel whereas transactions accessing writable accounts are serialized. The runtime interacts with the program through an entrypoint with a well-defined interface. The data stored in an account is an opaque type, an array of bytes. The program has full control over its contents.

The transaction structure specifies a list of public keys and signatures for those keys and a sequential list of instructions that will operate over the states associated with the account keys. For the transaction to be committed all the instructions must execute successfully; if any abort the whole transaction fails to commit.

Expand All @@ -28,7 +28,7 @@ The runtime enforces the following rules:

1. Only the _owner_ program may modify the contents of an account. This means that upon assignment data vector is guaranteed to be zero.
2. Total balances on all the accounts is equal before and after execution of a transaction.
3. After the transaction is executed, balances of credit-only accounts must be greater than or equal to the balances before the transaction.
3. After the transaction is executed, balances of read-only accounts must be equal to the balances before the transaction.
4. All instructions in the transaction executed atomically. If one fails, all account modifications are discarded.

Execution of the program involves mapping the program's public key to an entrypoint which takes a pointer to the transaction, and an array of loaded accounts.
Expand Down Expand Up @@ -62,4 +62,3 @@ To pass messages between programs, the receiving program must accept the message
* \[Continuations and Signals for long running

Transactions\]\([https://github.com/solana-labs/solana/issues/1485](https://github.com/solana-labs/solana/issues/1485)\)

20 changes: 10 additions & 10 deletions core/src/sigverify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ pub enum PacketError {
InvalidShortVec,
InvalidSignatureLen,
MismatchSignatureLen,
PayerNotDebitable,
PayerNotWritable,
}

impl std::convert::From<std::boxed::Box<bincode::ErrorKind>> for PacketError {
Expand Down Expand Up @@ -182,11 +182,11 @@ fn do_get_packet_offsets(
let message_account_keys_len_offset = msg_start_offset + message_header_size;

// This reads and compares the MessageHeader num_required_signatures and
// num_credit_only_signed_accounts bytes. If num_required_signatures is not larger than
// num_credit_only_signed_accounts, the first account is not debitable, and cannot be charged
// num_readonly_signed_accounts bytes. If num_required_signatures is not larger than
// num_readonly_signed_accounts, the first account is not writable, and cannot be charged
// required transaction fees.
if packet.data[msg_start_offset] <= packet.data[msg_start_offset + 1] {
return Err(PacketError::PayerNotDebitable);
return Err(PacketError::PayerNotWritable);
}

// read the length of Message.account_keys (serialized with short_vec)
Expand Down Expand Up @@ -486,8 +486,8 @@ mod tests {
let message = Message {
header: MessageHeader {
num_required_signatures: required_num_sigs,
num_credit_only_signed_accounts: 12,
num_credit_only_unsigned_accounts: 11,
num_readonly_signed_accounts: 12,
num_readonly_unsigned_accounts: 11,
},
account_keys: vec![],
recent_blockhash: Hash::default(),
Expand Down Expand Up @@ -584,12 +584,12 @@ mod tests {
}

#[test]
fn test_fee_payer_is_debitable() {
fn test_fee_payer_is_writable() {
let message = Message {
header: MessageHeader {
num_required_signatures: 1,
num_credit_only_signed_accounts: 1,
num_credit_only_unsigned_accounts: 1,
num_readonly_signed_accounts: 1,
num_readonly_unsigned_accounts: 1,
},
account_keys: vec![],
recent_blockhash: Hash::default(),
Expand All @@ -600,7 +600,7 @@ mod tests {
let packet = sigverify::make_packet_from_transaction(tx.clone());
let res = sigverify::do_get_packet_offsets(&packet, 0);

assert_eq!(res, Err(PacketError::PayerNotDebitable));
assert_eq!(res, Err(PacketError::PayerNotWritable));
}

#[test]
Expand Down
10 changes: 5 additions & 5 deletions programs/budget_api/src/budget_instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ pub enum BudgetInstruction {
fn initialize_account(contract: &Pubkey, expr: BudgetExpr) -> Instruction {
let mut keys = vec![];
if let BudgetExpr::Pay(payment) = &expr {
keys.push(AccountMeta::new_credit_only(payment.to, false));
keys.push(AccountMeta::new(payment.to, false));
}
keys.push(AccountMeta::new(*contract, false));
Instruction::new(
Expand Down Expand Up @@ -146,7 +146,7 @@ pub fn apply_timestamp(
AccountMeta::new(*contract, false),
];
if from != to {
account_metas.push(AccountMeta::new_credit_only(*to, false));
account_metas.push(AccountMeta::new(*to, false));
}
Instruction::new(id(), &BudgetInstruction::ApplyTimestamp(dt), account_metas)
}
Expand All @@ -157,17 +157,17 @@ pub fn apply_signature(from: &Pubkey, contract: &Pubkey, to: &Pubkey) -> Instruc
AccountMeta::new(*contract, false),
];
if from != to {
account_metas.push(AccountMeta::new_credit_only(*to, false));
account_metas.push(AccountMeta::new(*to, false));
}
Instruction::new(id(), &BudgetInstruction::ApplySignature, account_metas)
}

/// Apply account data to a contract waiting on an AccountData witness.
pub fn apply_account_data(witness_pubkey: &Pubkey, contract: &Pubkey, to: &Pubkey) -> Instruction {
let account_metas = vec![
AccountMeta::new_credit_only(*witness_pubkey, false),
AccountMeta::new_readonly(*witness_pubkey, false),
AccountMeta::new(*contract, false),
AccountMeta::new_credit_only(*to, false),
AccountMeta::new(*to, false),
];
Instruction::new(id(), &BudgetInstruction::ApplyAccountData, account_metas)
}
Expand Down
6 changes: 3 additions & 3 deletions programs/librapay_api/src/librapay_instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ pub fn mint(
let ix_data = LoaderInstruction::InvokeMain { data };

let accounts = vec![
AccountMeta::new_credit_only(*program_pubkey, false),
AccountMeta::new_readonly(*program_pubkey, false),
AccountMeta::new(*from_pubkey, true),
AccountMeta::new(*to_pubkey, false),
];
Expand Down Expand Up @@ -65,8 +65,8 @@ pub fn transfer(
let ix_data = LoaderInstruction::InvokeMain { data };

let accounts = vec![
AccountMeta::new_credit_only(*program_pubkey, false),
AccountMeta::new_credit_only(*mint_pubkey, false),
AccountMeta::new_readonly(*program_pubkey, false),
AccountMeta::new_readonly(*mint_pubkey, false),
AccountMeta::new(*from_pubkey, true),
AccountMeta::new(*to_pubkey, false),
];
Expand Down
24 changes: 12 additions & 12 deletions programs/stake_api/src/stake_instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ pub fn initialize(stake_pubkey: &Pubkey, authorized: &Authorized, lockup: &Locku
&StakeInstruction::Initialize(*authorized, *lockup),
vec![
AccountMeta::new(*stake_pubkey, false),
AccountMeta::new_credit_only(sysvar::rent::id(), false),
AccountMeta::new_readonly(sysvar::rent::id(), false),
],
)
}
Expand Down Expand Up @@ -235,7 +235,7 @@ fn metas_with_signer(
}

// signer wasn't in metas, append it after normal parameters
metas.push(AccountMeta::new_credit_only(*signer, true));
metas.push(AccountMeta::new_readonly(*signer, true));

metas
}
Expand All @@ -259,10 +259,10 @@ pub fn authorize(
pub fn redeem_vote_credits(stake_pubkey: &Pubkey, vote_pubkey: &Pubkey) -> Instruction {
let account_metas = vec![
AccountMeta::new(*stake_pubkey, false),
AccountMeta::new_credit_only(*vote_pubkey, false),
AccountMeta::new(*vote_pubkey, false),
AccountMeta::new(crate::rewards_pools::random_id(), false),
AccountMeta::new_credit_only(sysvar::rewards::id(), false),
AccountMeta::new_credit_only(sysvar::stake_history::id(), false),
AccountMeta::new_readonly(sysvar::rewards::id(), false),
AccountMeta::new_readonly(sysvar::stake_history::id(), false),
];
Instruction::new(id(), &StakeInstruction::RedeemVoteCredits, account_metas)
}
Expand All @@ -275,9 +275,9 @@ pub fn delegate_stake(
let account_metas = metas_with_signer(
&[
AccountMeta::new(*stake_pubkey, false),
AccountMeta::new_credit_only(*vote_pubkey, false),
AccountMeta::new_credit_only(sysvar::clock::id(), false),
AccountMeta::new_credit_only(crate::config::id(), false),
AccountMeta::new_readonly(*vote_pubkey, false),
AccountMeta::new_readonly(sysvar::clock::id(), false),
AccountMeta::new_readonly(crate::config::id(), false),
],
authorized_pubkey,
);
Expand All @@ -293,9 +293,9 @@ pub fn withdraw(
let account_metas = metas_with_signer(
&[
AccountMeta::new(*stake_pubkey, false),
AccountMeta::new_credit_only(*to_pubkey, false),
AccountMeta::new_credit_only(sysvar::clock::id(), false),
AccountMeta::new_credit_only(sysvar::stake_history::id(), false),
AccountMeta::new(*to_pubkey, false),
AccountMeta::new_readonly(sysvar::clock::id(), false),
AccountMeta::new_readonly(sysvar::stake_history::id(), false),
],
authorized_pubkey,
);
Expand All @@ -306,7 +306,7 @@ pub fn deactivate_stake(stake_pubkey: &Pubkey, authorized_pubkey: &Pubkey) -> In
let account_metas = metas_with_signer(
&[
AccountMeta::new(*stake_pubkey, false),
AccountMeta::new_credit_only(sysvar::clock::id(), false),
AccountMeta::new_readonly(sysvar::clock::id(), false),
],
authorized_pubkey,
);
Expand Down
6 changes: 3 additions & 3 deletions programs/vest_api/src/vest_instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,8 @@ pub fn set_payee(contract: &Pubkey, old_pubkey: &Pubkey, new_pubkey: &Pubkey) ->
pub fn redeem_tokens(contract: &Pubkey, date_pubkey: &Pubkey, to: &Pubkey) -> Instruction {
let account_metas = vec![
AccountMeta::new(*contract, false),
AccountMeta::new_credit_only(*date_pubkey, false),
AccountMeta::new_credit_only(*to, false),
AccountMeta::new_readonly(*date_pubkey, false),
AccountMeta::new(*to, false),
];
Instruction::new(id(), &VestInstruction::RedeemTokens, account_metas)
}
Expand All @@ -134,7 +134,7 @@ pub fn terminate(contract: &Pubkey, from: &Pubkey, to: &Pubkey) -> Instruction {
AccountMeta::new(*from, true),
];
if from != to {
account_metas.push(AccountMeta::new_credit_only(*to, false));
account_metas.push(AccountMeta::new(*to, false));
}
Instruction::new(id(), &VestInstruction::Terminate, account_metas)
}
8 changes: 4 additions & 4 deletions programs/vote_api/src/vote_instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ fn metas_for_authorized_signer(

// append signer at the end
if !is_own_signer {
account_metas.push(AccountMeta::new_credit_only(*authorized_signer, true))
account_metas.push(AccountMeta::new_readonly(*authorized_signer, true))
// signer
}

Expand Down Expand Up @@ -134,9 +134,9 @@ pub fn vote(vote_pubkey: &Pubkey, authorized_voter_pubkey: &Pubkey, vote: Vote)
authorized_voter_pubkey,
&[
// request slot_hashes sysvar account after vote_pubkey
AccountMeta::new_credit_only(sysvar::slot_hashes::id(), false),
AccountMeta::new_readonly(sysvar::slot_hashes::id(), false),
// request clock sysvar account after that
AccountMeta::new_credit_only(sysvar::clock::id(), false),
AccountMeta::new_readonly(sysvar::clock::id(), false),
],
);

Expand All @@ -152,7 +152,7 @@ pub fn withdraw(
let account_metas = metas_for_authorized_signer(
vote_pubkey,
withdrawer_pubkey,
&[AccountMeta::new_credit_only(*to_pubkey, false)],
&[AccountMeta::new(*to_pubkey, false)],
);

Instruction::new(id(), &VoteInstruction::Withdraw(lamports), account_metas)
Expand Down
Loading

0 comments on commit c6931dc

Please sign in to comment.