update program address docs (#13069)

This commit is contained in:
Jack May 2020-10-21 10:09:12 -07:00 committed by GitHub
parent 608b81b412
commit e10de86440
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 72 additions and 69 deletions

View File

@ -4,65 +4,71 @@ title: Program Derived Addresses
## Problem ## Problem
Programs cannot generate signatures when issuing instructions to Programs cannot generate signatures when issuing instructions to other programs
other programs as defined in the [Cross-Program Invocations](cross-program-invocation.md) as defined in the [Cross-Program Invocations](cross-program-invocation.md)
design. design.
The lack of programmatic signature generation limits the kinds of programs The lack of programmatic signature generation limits the kinds of programs that
that can be implemented in Solana. A program may be given the can be implemented in Solana. A program may be given the authority over an
authority over an account and later want to transfer that authority to another. account and later want to transfer that authority to another. This is impossible
This is impossible today because the program cannot act as the signer in the transaction that gives authority. today because the program cannot act as the signer in the transaction that gives
authority.
For example, if two users want For example, if two users want to make a wager on the outcome of a game in
to make a wager on the outcome of a game in Solana, they must each Solana, they must each transfer their wager's assets to some intermediary that
transfer their wager's assets to some intermediary that will honor will honor their agreement. Currently, there is no way to implement this
their agreement. Currently, there is no way to implement this intermediary intermediary as a program in Solana because the intermediary program cannot
as a program in Solana because the intermediary program cannot transfer the transfer the assets to the winner.
assets to the winner.
This capability is necessary for many DeFi applications since they This capability is necessary for many DeFi applications since they require
require assets to be transferred to an escrow agent until some event assets to be transferred to an escrow agent until some event occurs that
occurs that determines the new owner. determines the new owner.
- Decentralized Exchanges that transfer assets between matching bid and - Decentralized Exchanges that transfer assets between matching bid and ask
ask orders. orders.
- Auctions that transfer assets to the winner. - Auctions that transfer assets to the winner.
- Games or prediction markets that collect and redistribute prizes to - Games or prediction markets that collect and redistribute prizes to the
the winners. winners.
## Proposed Solution ## Proposed Solution
The key to the design is two-fold: The key to the design is two-fold:
1. Allow programs to control specific addresses, called Program-Addresses, in such a way that no external 1. Allow programs to control specific addresses, called program addresses, in
user can generate valid transactions with signatures for those such a way that no external user can generate valid transactions with
addresses. signatures for those addresses.
2. Allow programs to programmatically sign for Program-Addresses that are 2. Allow programs to programmatically sign for programa addresses that are
present in instructions invoked via [Cross-Program Invocations](cross-program-invocation.md). present in instructions invoked via [Cross-Program
Invocations](cross-program-invocation.md).
Given the two conditions, users can securely transfer or assign Given the two conditions, users can securely transfer or assign the authority of
the authority of on-chain assets to Program-Addresses and the program on-chain assets to program addresses and the program can then assign that
can then assign that authority elsewhere at its discretion. authority elsewhere at its discretion.
### Private keys for Program Addresses ### Private keys for program addresses
A Program -Address has no private key associated with it, and generating A Program address does not lie on the ed25519 curve and therefore has no valid
a signature for it is impossible. While it has no private key of private key associated with it, and thus generating a signature for it is
its own, it can issue an instruction that includes the Program-Address as a signer. impossible. While it has no private key of its own, it can be used by a program
to issue an instruction that includes the Program address as a signer.
### Hash-based generated Program Addresses ### Hash-based generated program addresses
All 256-bit values are valid ed25519 curve points and valid ed25519 public Program addresses are deterministically derived from a collection of seeds and a
keys. All are equally secure and equally as hard to break. program id using a 256-bit pre-image resistant hash function. Program address
Based on this assumption, Program Addresses can be deterministically must not lie on the ed25519 curve to ensure there is no associated private key.
derived from a base seed using a 256-bit preimage resistant hash function. During generation an error will be returned if the address is found to lie on
the curve. There is about a 50/50 change of this happening for a given
collection of seeds and program id. If this occurs a different set of seeds or
a seed bump (additional 8 bit seed) can be used to find a valid program address
off the curve.
Deterministic Program Addresses for programs follow a similar derivation Deterministic program addresses for programs follow a similar derivation path as
path as Accounts created with `SystemInstruction::CreateAccountWithSeed` Accounts created with `SystemInstruction::CreateAccountWithSeed` which is
which is implemented with `system_instruction::create_address_with_seed`. implemented with `system_instruction::create_address_with_seed`.
For reference that implementation is as follows: For reference that implementation is as follows:
@ -82,45 +88,42 @@ pub fn create_address_with_seed(
} }
``` ```
Programs can deterministically derive any number of addresses by Programs can deterministically derive any number of addresses by using seeds.
using keywords. These keywords can symbolically identify how the addresses are used. These seeds can symbolically identify how the addresses are used.
From `Pubkey`::
```rust,ignore ```rust,ignore
//! Generate a derived program address /// Generate a derived program address
//! * seeds, symbolic keywords used to derive the key /// * seeds, symbolic keywords used to derive the key
//! * owner, program that the key is derived for /// * program_id, program that the address is derived for
pub fn create_program_address(seeds: &[&str], owner: &Pubkey) -> Result<Pubkey, PubkeyError> { pub fn create_program_address(
let mut hasher = Hasher::default(); seeds: &[&[u8]],
for seed in seeds.iter() { program_id: &Pubkey,
if seed.len() > MAX_SEED_LEN { ) -> Result<Pubkey, PubkeyError>
return Err(PubkeyError::MaxSeedLengthExceeded);
}
hasher.hash(seed.as_ref());
}
hasher.hashv(&[owner.as_ref(), "ProgramDerivedAddress".as_ref()]);
Ok(Pubkey::new(hashv(&[hasher.result().as_ref()]).as_ref()))
}
``` ```
### Using Program Addresses ### Using program addresses
Clients can use the `create_program_address` function to generate Clients can use the `create_program_address` function to generate a destination
a destination address. address.
```rust,ignore ```rust,ignore
//deterministically derive the escrow key // deterministically derive the escrow key
let escrow_pubkey = create_program_address(&[&["escrow"]], &escrow_program_id); let escrow_pubkey = create_program_address(&[&["escrow"]], &escrow_program_id);
// construct a transfer message using that key
let message = Message::new(vec![ let message = Message::new(vec![
token_instruction::transfer(&alice_pubkey, &escrow_pubkey, 1), token_instruction::transfer(&alice_pubkey, &escrow_pubkey, 1),
]); ]);
//transfer 1 token to escrow
// process the message which transfer one 1 token to the escrow
client.send_and_confirm_message(&[&alice_keypair], &message); client.send_and_confirm_message(&[&alice_keypair], &message);
``` ```
Programs can use the same function to generate the same address. Programs can use the same function to generate the same address. In the function
In the function below the program issues a `token_instruction::transfer` from below the program issues a `token_instruction::transfer` from a program address
Program Address as if it had the private key to sign the transaction. as if it had the private key to sign the transaction.
```rust,ignore ```rust,ignore
fn transfer_one_token_from_escrow( fn transfer_one_token_from_escrow(
@ -139,7 +142,7 @@ fn transfer_one_token_from_escrow(
// The runtime deterministically derives the key from the currently // The runtime deterministically derives the key from the currently
// executing program ID and the supplied keywords. // executing program ID and the supplied keywords.
// If the derived key matches a key marked as signed in the instruction // If the derived address matches a key marked as signed in the instruction
// then that key is accepted as signed. // then that key is accepted as signed.
invoke_signed(&instruction, &[&["escrow"]])? invoke_signed(&instruction, &[&["escrow"]])?
} }
@ -147,10 +150,10 @@ fn transfer_one_token_from_escrow(
### Instructions that require signers ### Instructions that require signers
The addresses generated with `create_program_address` are indistinguishable The addresses generated with `create_program_address` are indistinguishable from
from any other public key. The only way for the runtime to verify that the any other public key. The only way for the runtime to verify that the address
address belongs to a program is for the program to supply the keywords used belongs to a program is for the program to supply the seeds used to generate the
to generate the address. address.
The runtime will internally call `create_program_address`, and compare the The runtime will internally call `create_program_address`, and compare the
result against the addresses supplied in the instruction. result against the addresses supplied in the instruction.