Rename tokens to lamports in sdk/
This commit is contained in:
parent
bd237a2d6f
commit
53f09c44f3
|
@ -120,7 +120,7 @@ Returns all information associated with the account of provided Pubkey
|
|||
##### Results:
|
||||
The result field will be a JSON object with the following sub fields:
|
||||
|
||||
* `tokens`, number of tokens assigned to this account, as a signed 64-bit integer
|
||||
* `lamports`, number of lamports assigned to this account, as a signed 64-bit integer
|
||||
* `owner`, array of 32 bytes representing the program this account has been assigned to
|
||||
* `userdata`, array of bytes representing any userdata associated with the account
|
||||
* `executable`, boolean indicating if the account contains a program (and is strictly read-only)
|
||||
|
@ -132,7 +132,7 @@ The result field will be a JSON object with the following sub fields:
|
|||
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"getAccountInfo", "params":["2gVkYWexTHR5Hb2aLeQN3tnngvWzisFKXDUPrgMHpdST"]}' http://localhost:8899
|
||||
|
||||
// Result
|
||||
{"jsonrpc":"2.0","result":{"executable":false,"loader":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"owner":[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"tokens":1,"userdata":[3,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,20,0,0,0,0,0,0,0,50,48,53,48,45,48,49,45,48,49,84,48,48,58,48,48,58,48,48,90,252,10,7,28,246,140,88,177,98,82,10,227,89,81,18,30,194,101,199,16,11,73,133,20,246,62,114,39,20,113,189,32,50,0,0,0,0,0,0,0,247,15,36,102,167,83,225,42,133,127,82,34,36,224,207,130,109,230,224,188,163,33,213,13,5,117,211,251,65,159,197,51,0,0,0,0,0,0]},"id":1}
|
||||
{"jsonrpc":"2.0","result":{"executable":false,"loader":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"owner":[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"lamports":1,"userdata":[3,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,20,0,0,0,0,0,0,0,50,48,53,48,45,48,49,45,48,49,84,48,48,58,48,48,58,48,48,90,252,10,7,28,246,140,88,177,98,82,10,227,89,81,18,30,194,101,199,16,11,73,133,20,246,62,114,39,20,113,189,32,50,0,0,0,0,0,0,0,247,15,36,102,167,83,225,42,133,127,82,34,36,224,207,130,109,230,224,188,163,33,213,13,5,117,211,251,65,159,197,51,0,0,0,0,0,0]},"id":1}
|
||||
```
|
||||
|
||||
---
|
||||
|
@ -204,11 +204,11 @@ curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "m
|
|||
---
|
||||
|
||||
### requestAirdrop
|
||||
Requests an airdrop of tokens to a Pubkey
|
||||
Requests an airdrop of lamports to a Pubkey
|
||||
|
||||
##### Parameters:
|
||||
* `string` - Pubkey of account to receive tokens, as base-58 encoded string
|
||||
* `integer` - token quantity, as a signed 64-bit integer
|
||||
* `string` - Pubkey of account to receive lamports, as base-58 encoded string
|
||||
* `integer` - lamports, as a signed 64-bit integer
|
||||
|
||||
##### Results:
|
||||
* `string` - Transaction Signature of airdrop, as base-58 encoded string
|
||||
|
@ -271,7 +271,7 @@ Subscribe to an account to receive notifications when the userdata for a given a
|
|||
|
||||
##### Notification Format:
|
||||
```bash
|
||||
{"jsonrpc": "2.0","method": "accountNotification", "params": {"result": {"executable":false,"loader":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"owner":[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"tokens":1,"userdata":[3,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,20,0,0,0,0,0,0,0,50,48,53,48,45,48,49,45,48,49,84,48,48,58,48,48,58,48,48,90,252,10,7,28,246,140,88,177,98,82,10,227,89,81,18,30,194,101,199,16,11,73,133,20,246,62,114,39,20,113,189,32,50,0,0,0,0,0,0,0,247,15,36,102,167,83,225,42,133,127,82,34,36,224,207,130,109,230,224,188,163,33,213,13,5,117,211,251,65,159,197,51,0,0,0,0,0,0]},"subscription":0}}
|
||||
{"jsonrpc": "2.0","method": "accountNotification", "params": {"result": {"executable":false,"loader":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"owner":[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"lamports":1,"userdata":[3,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,20,0,0,0,0,0,0,0,50,48,53,48,45,48,49,45,48,49,84,48,48,58,48,48,58,48,48,90,252,10,7,28,246,140,88,177,98,82,10,227,89,81,18,30,194,101,199,16,11,73,133,20,246,62,114,39,20,113,189,32,50,0,0,0,0,0,0,0,247,15,36,102,167,83,225,42,133,127,82,34,36,224,207,130,109,230,224,188,163,33,213,13,5,117,211,251,65,159,197,51,0,0,0,0,0,0]},"subscription":0}}
|
||||
```
|
||||
|
||||
---
|
||||
|
|
|
@ -574,7 +574,7 @@ mod tests {
|
|||
// ProgramErrors should still be recorded
|
||||
results[0] = Err(BankError::ProgramError(
|
||||
1,
|
||||
ProgramError::ResultWithNegativeTokens,
|
||||
ProgramError::ResultWithNegativeLamports,
|
||||
));
|
||||
BankingStage::record_transactions(&transactions, &results, &poh_recorder).unwrap();
|
||||
let (_, entries) = entry_receiver.recv().unwrap();
|
||||
|
|
|
@ -476,7 +476,7 @@ mod tests {
|
|||
entries.push(entry);
|
||||
|
||||
// Add a second Transaction that will produce a
|
||||
// ProgramError<0, ResultWithNegativeTokens> error when processed
|
||||
// ProgramError<0, ResultWithNegativeLamports> error when processed
|
||||
let keypair2 = Keypair::new();
|
||||
let tx = SystemTransaction::new_account(&keypair, keypair2.pubkey(), 42, blockhash, 0);
|
||||
let entry = Entry::new(&last_entry_hash, 1, vec![tx]);
|
||||
|
|
|
@ -32,12 +32,12 @@ impl LeaderConfirmationService {
|
|||
// Hold an accounts_db read lock as briefly as possible, just long enough to collect all
|
||||
// the vote states
|
||||
bank.vote_accounts().for_each(|(_, account)| {
|
||||
total_stake += account.tokens;
|
||||
total_stake += account.lamports;
|
||||
let vote_state = VoteState::deserialize(&account.userdata).unwrap();
|
||||
if let Some(stake_and_state) = vote_state
|
||||
.votes
|
||||
.back()
|
||||
.map(|vote| (vote.slot, account.tokens))
|
||||
.map(|vote| (vote.slot, account.lamports))
|
||||
{
|
||||
slots_and_stakes.push(stake_and_state);
|
||||
}
|
||||
|
@ -145,7 +145,7 @@ mod tests {
|
|||
let blockhash = bank.last_blockhash();
|
||||
|
||||
// Create a total of 10 vote accounts, each will have a balance of 1 (after giving 1 to
|
||||
// their vote account), for a total staking pool of 10 tokens.
|
||||
// their vote account), for a total staking pool of 10 lamports.
|
||||
let vote_accounts: Vec<_> = (0..10)
|
||||
.map(|i| {
|
||||
// Create new validator to vote
|
||||
|
@ -153,7 +153,7 @@ mod tests {
|
|||
let voting_keypair = Keypair::new();
|
||||
let voting_pubkey = voting_keypair.pubkey();
|
||||
|
||||
// Give the validator some tokens
|
||||
// Give the validator some lamports
|
||||
bank.transfer(2, &mint_keypair, validator_keypair.pubkey(), blockhash)
|
||||
.unwrap();
|
||||
new_vote_account(&validator_keypair, &voting_pubkey, &bank, 1);
|
||||
|
|
|
@ -49,14 +49,17 @@ pub fn num_ticks_left_in_slot(bank: &Bank, tick_height: u64) -> u64 {
|
|||
mod tests {
|
||||
use super::*;
|
||||
use crate::staking_utils;
|
||||
use solana_sdk::genesis_block::{GenesisBlock, BOOTSTRAP_LEADER_TOKENS};
|
||||
use solana_sdk::genesis_block::{GenesisBlock, BOOTSTRAP_LEADER_LAMPORTS};
|
||||
use solana_sdk::signature::{Keypair, KeypairUtil};
|
||||
|
||||
#[test]
|
||||
fn test_leader_schedule_via_bank() {
|
||||
let pubkey = Keypair::new().pubkey();
|
||||
let (genesis_block, _mint_keypair) =
|
||||
GenesisBlock::new_with_leader(BOOTSTRAP_LEADER_TOKENS, pubkey, BOOTSTRAP_LEADER_TOKENS);
|
||||
let (genesis_block, _mint_keypair) = GenesisBlock::new_with_leader(
|
||||
BOOTSTRAP_LEADER_LAMPORTS,
|
||||
pubkey,
|
||||
BOOTSTRAP_LEADER_LAMPORTS,
|
||||
);
|
||||
let bank = Bank::new(&genesis_block);
|
||||
|
||||
let ids_and_stakes: Vec<_> = staking_utils::delegated_stakes(&bank).into_iter().collect();
|
||||
|
@ -72,9 +75,12 @@ mod tests {
|
|||
#[test]
|
||||
fn test_leader_scheduler1_basic() {
|
||||
let pubkey = Keypair::new().pubkey();
|
||||
let genesis_block =
|
||||
GenesisBlock::new_with_leader(BOOTSTRAP_LEADER_TOKENS, pubkey, BOOTSTRAP_LEADER_TOKENS)
|
||||
.0;
|
||||
let genesis_block = GenesisBlock::new_with_leader(
|
||||
BOOTSTRAP_LEADER_LAMPORTS,
|
||||
pubkey,
|
||||
BOOTSTRAP_LEADER_LAMPORTS,
|
||||
)
|
||||
.0;
|
||||
let bank = Bank::new(&genesis_block);
|
||||
assert_eq!(slot_leader_at(bank.slot(), &bank), pubkey);
|
||||
}
|
||||
|
|
|
@ -292,8 +292,8 @@ impl RpcSol for RpcSolImpl {
|
|||
.get_transaction_count()
|
||||
}
|
||||
|
||||
fn request_airdrop(&self, meta: Self::Metadata, id: String, tokens: u64) -> Result<String> {
|
||||
trace!("request_airdrop id={} tokens={}", id, tokens);
|
||||
fn request_airdrop(&self, meta: Self::Metadata, id: String, lamports: u64) -> Result<String> {
|
||||
trace!("request_airdrop id={} lamports={}", id, lamports);
|
||||
let pubkey = verify_pubkey(id)?;
|
||||
|
||||
let blockhash = meta
|
||||
|
@ -302,11 +302,13 @@ impl RpcSol for RpcSolImpl {
|
|||
.unwrap()
|
||||
.bank()?
|
||||
.last_blockhash();
|
||||
let transaction = request_airdrop_transaction(&meta.drone_addr, &pubkey, tokens, blockhash)
|
||||
.map_err(|err| {
|
||||
info!("request_airdrop_transaction failed: {:?}", err);
|
||||
Error::internal_error()
|
||||
})?;;
|
||||
let transaction =
|
||||
request_airdrop_transaction(&meta.drone_addr, &pubkey, lamports, blockhash).map_err(
|
||||
|err| {
|
||||
info!("request_airdrop_transaction failed: {:?}", err);
|
||||
Error::internal_error()
|
||||
},
|
||||
)?;;
|
||||
|
||||
let data = serialize(&transaction).map_err(|err| {
|
||||
info!("request_airdrop: serialize error: {:?}", err);
|
||||
|
@ -517,7 +519,7 @@ mod tests {
|
|||
"jsonrpc":"2.0",
|
||||
"result":{
|
||||
"owner": [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
|
||||
"tokens": 20,
|
||||
"lamports": 20,
|
||||
"userdata": [],
|
||||
"executable": false
|
||||
},
|
||||
|
|
|
@ -106,6 +106,6 @@ pub fn request_airdrop_transaction(
|
|||
let key = Keypair::new();
|
||||
let to = Keypair::new().pubkey();
|
||||
let blockhash = Hash::default();
|
||||
let tx = SystemTransaction::new_account(&key, to, 50, blockhash, 0);
|
||||
let tx = SystemTransaction::new_account(&key, to, lamports, blockhash, 0);
|
||||
Ok(tx)
|
||||
}
|
||||
|
|
|
@ -323,7 +323,7 @@ mod tests {
|
|||
"params": {
|
||||
"result": {
|
||||
"owner": budget_program_id,
|
||||
"tokens": 1,
|
||||
"lamports": 1,
|
||||
"userdata": expected_userdata,
|
||||
"executable": executable,
|
||||
|
||||
|
@ -359,7 +359,7 @@ mod tests {
|
|||
"params": {
|
||||
"result": {
|
||||
"owner": budget_program_id,
|
||||
"tokens": 51,
|
||||
"lamports": 51,
|
||||
"userdata": expected_userdata,
|
||||
"executable": executable,
|
||||
},
|
||||
|
@ -393,7 +393,7 @@ mod tests {
|
|||
"params": {
|
||||
"result": {
|
||||
"owner": budget_program_id,
|
||||
"tokens": 1,
|
||||
"lamports": 1,
|
||||
"userdata": expected_userdata,
|
||||
"executable": executable,
|
||||
},
|
||||
|
|
|
@ -185,7 +185,7 @@ mod tests {
|
|||
subscriptions.check_account(&alice.pubkey(), &account);
|
||||
let string = transport_receiver.poll();
|
||||
if let Async::Ready(Some(response)) = string.unwrap() {
|
||||
let expected = format!(r#"{{"jsonrpc":"2.0","method":"accountNotification","params":{{"result":{{"executable":false,"owner":[129,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"tokens":1,"userdata":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},"subscription":0}}}}"#);
|
||||
let expected = format!(r#"{{"jsonrpc":"2.0","method":"accountNotification","params":{{"result":{{"executable":false,"lamports":1,"owner":[129,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"userdata":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},"subscription":0}}}}"#);
|
||||
assert_eq!(expected, response);
|
||||
}
|
||||
|
||||
|
|
|
@ -493,13 +493,13 @@ mod tests {
|
|||
let keypair0 = Keypair::new();
|
||||
let keypair1 = Keypair::new();
|
||||
let keypairs = vec![&keypair0, &keypair1];
|
||||
let tokens = 5;
|
||||
let lamports = 5;
|
||||
let fee = 2;
|
||||
let blockhash = Hash::default();
|
||||
|
||||
let keys = vec![keypair0.pubkey(), keypair1.pubkey()];
|
||||
|
||||
let system_instruction = SystemInstruction::Move { tokens };
|
||||
let system_instruction = SystemInstruction::Move { lamports };
|
||||
|
||||
let program_ids = vec![system_program::id(), solana_budget_api::id()];
|
||||
|
||||
|
|
|
@ -121,20 +121,20 @@ impl ThinClient {
|
|||
/// Creates, signs, and processes a Transaction. Useful for writing unit-tests.
|
||||
pub fn transfer(
|
||||
&self,
|
||||
tokens: u64,
|
||||
lamports: u64,
|
||||
keypair: &Keypair,
|
||||
to: Pubkey,
|
||||
blockhash: &Hash,
|
||||
) -> io::Result<Signature> {
|
||||
debug!(
|
||||
"transfer: tokens={} from={:?} to={:?} blockhash={:?}",
|
||||
tokens,
|
||||
"transfer: lamports={} from={:?} to={:?} blockhash={:?}",
|
||||
lamports,
|
||||
keypair.pubkey(),
|
||||
to,
|
||||
blockhash
|
||||
);
|
||||
let now = Instant::now();
|
||||
let transaction = SystemTransaction::new_account(keypair, to, tokens, *blockhash, 0);
|
||||
let transaction = SystemTransaction::new_account(keypair, to, lamports, *blockhash, 0);
|
||||
let result = self.transfer_signed(&transaction);
|
||||
solana_metrics::submit(
|
||||
influxdb::Point::new("thinclient")
|
||||
|
@ -184,8 +184,8 @@ impl ThinClient {
|
|||
let account: Account =
|
||||
serde_json::from_value(account_json).expect("deserialize account");
|
||||
trace!("Response account {:?} {:?}", pubkey, account);
|
||||
trace!("get_balance {:?}", account.tokens);
|
||||
Ok(account.tokens)
|
||||
trace!("get_balance {:?}", account.lamports);
|
||||
Ok(account.lamports)
|
||||
})
|
||||
.map_err(|error| {
|
||||
debug!("Response account {}: None (error: {:?})", pubkey, error);
|
||||
|
@ -563,8 +563,8 @@ mod tests {
|
|||
|
||||
let mut tr2 = SystemTransaction::new_account(&alice, bob_pubkey, 501, blockhash, 0);
|
||||
let mut instruction2 = deserialize(tr2.userdata(0)).unwrap();
|
||||
if let SystemInstruction::Move { ref mut tokens } = instruction2 {
|
||||
*tokens = 502;
|
||||
if let SystemInstruction::Move { ref mut lamports } = instruction2 {
|
||||
*lamports = 502;
|
||||
}
|
||||
tr2.instructions[0].userdata = serialize(&instruction2).unwrap();
|
||||
let signature = client.transfer_signed(&tr2).unwrap();
|
||||
|
@ -587,7 +587,7 @@ mod tests {
|
|||
|
||||
let mut client = mk_client(&leader_data);
|
||||
|
||||
// Create the validator account, transfer some tokens to that account
|
||||
// Create the validator account, transfer some lamports to that account
|
||||
let validator_keypair = Keypair::new();
|
||||
let blockhash = client.get_recent_blockhash();
|
||||
let signature = client
|
||||
|
@ -660,9 +660,9 @@ mod tests {
|
|||
info!("test_thin_client blockhash: {:?}", blockhash);
|
||||
|
||||
let starting_alice_balance = client.poll_get_balance(&alice.pubkey()).unwrap();
|
||||
info!("Alice has {} tokens", starting_alice_balance);
|
||||
info!("Alice has {} lamports", starting_alice_balance);
|
||||
|
||||
info!("Give Bob 500 tokens");
|
||||
info!("Give Bob 500 lamports");
|
||||
let signature = client
|
||||
.transfer(500, &alice, bob_keypair.pubkey(), &blockhash)
|
||||
.unwrap();
|
||||
|
@ -671,7 +671,7 @@ mod tests {
|
|||
let bob_balance = client.poll_get_balance(&bob_keypair.pubkey());
|
||||
assert_eq!(bob_balance.unwrap(), 500);
|
||||
|
||||
info!("Take Bob's 500 tokens away");
|
||||
info!("Take Bob's 500 lamports away");
|
||||
let signature = client
|
||||
.transfer(500, &bob_keypair, alice.pubkey(), &blockhash)
|
||||
.unwrap();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//! The `drone` module provides an object for launching a Solana Drone,
|
||||
//! which is the custodian of any remaining tokens in a mint.
|
||||
//! which is the custodian of any remaining lamports in a mint.
|
||||
//! The Solana Drone builds and send airdrop transactions,
|
||||
//! checking requests against a request cap for a given time time_slice
|
||||
//! and (to come) an IP rate limit.
|
||||
|
@ -48,7 +48,7 @@ pub const DRONE_PORT: u16 = 9900;
|
|||
#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
|
||||
pub enum DroneRequest {
|
||||
GetAirdrop {
|
||||
tokens: u64,
|
||||
lamports: u64,
|
||||
to: Pubkey,
|
||||
blockhash: Hash,
|
||||
},
|
||||
|
@ -108,16 +108,16 @@ impl Drone {
|
|||
trace!("build_airdrop_transaction: {:?}", req);
|
||||
match req {
|
||||
DroneRequest::GetAirdrop {
|
||||
tokens,
|
||||
lamports,
|
||||
to,
|
||||
blockhash,
|
||||
} => {
|
||||
if self.check_request_limit(tokens) {
|
||||
self.request_current += tokens;
|
||||
if self.check_request_limit(lamports) {
|
||||
self.request_current += lamports;
|
||||
solana_metrics::submit(
|
||||
influxdb::Point::new("drone")
|
||||
.add_tag("op", influxdb::Value::String("airdrop".to_string()))
|
||||
.add_field("request_amount", influxdb::Value::Integer(tokens as i64))
|
||||
.add_field("request_amount", influxdb::Value::Integer(lamports as i64))
|
||||
.add_field(
|
||||
"request_current",
|
||||
influxdb::Value::Integer(self.request_current as i64),
|
||||
|
@ -125,10 +125,10 @@ impl Drone {
|
|||
.to_owned(),
|
||||
);
|
||||
|
||||
info!("Requesting airdrop of {} to {:?}", tokens, to);
|
||||
info!("Requesting airdrop of {} to {:?}", lamports, to);
|
||||
|
||||
let create_instruction = SystemInstruction::CreateAccount {
|
||||
tokens,
|
||||
lamports,
|
||||
space: 0,
|
||||
program_id: system_program::id(),
|
||||
};
|
||||
|
@ -193,18 +193,18 @@ impl Drop for Drone {
|
|||
pub fn request_airdrop_transaction(
|
||||
drone_addr: &SocketAddr,
|
||||
id: &Pubkey,
|
||||
tokens: u64,
|
||||
lamports: u64,
|
||||
blockhash: Hash,
|
||||
) -> Result<Transaction, Error> {
|
||||
info!(
|
||||
"request_airdrop_transaction: drone_addr={} id={} tokens={} blockhash={}",
|
||||
drone_addr, id, tokens, blockhash
|
||||
"request_airdrop_transaction: drone_addr={} id={} lamports={} blockhash={}",
|
||||
drone_addr, id, lamports, blockhash
|
||||
);
|
||||
// TODO: make this async tokio client
|
||||
let mut stream = TcpStream::connect_timeout(drone_addr, Duration::new(3, 0))?;
|
||||
stream.set_read_timeout(Some(Duration::new(10, 0)))?;
|
||||
let req = DroneRequest::GetAirdrop {
|
||||
tokens,
|
||||
lamports,
|
||||
blockhash,
|
||||
to: *id,
|
||||
};
|
||||
|
@ -355,7 +355,7 @@ mod tests {
|
|||
let to = Keypair::new().pubkey();
|
||||
let blockhash = Hash::default();
|
||||
let request = DroneRequest::GetAirdrop {
|
||||
tokens: 2,
|
||||
lamports: 2,
|
||||
to,
|
||||
blockhash,
|
||||
};
|
||||
|
@ -376,7 +376,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
instruction,
|
||||
SystemInstruction::CreateAccount {
|
||||
tokens: 2,
|
||||
lamports: 2,
|
||||
space: 0,
|
||||
program_id: Pubkey::default()
|
||||
}
|
||||
|
@ -392,9 +392,9 @@ mod tests {
|
|||
fn test_process_drone_request() {
|
||||
let to = Keypair::new().pubkey();
|
||||
let blockhash = Hash::new(&to.as_ref());
|
||||
let tokens = 50;
|
||||
let lamports = 50;
|
||||
let req = DroneRequest::GetAirdrop {
|
||||
tokens,
|
||||
lamports,
|
||||
blockhash,
|
||||
to,
|
||||
};
|
||||
|
@ -404,7 +404,7 @@ mod tests {
|
|||
|
||||
let keypair = Keypair::new();
|
||||
let expected_instruction = SystemInstruction::CreateAccount {
|
||||
tokens,
|
||||
lamports,
|
||||
space: 0,
|
||||
program_id: system_program::id(),
|
||||
};
|
||||
|
|
|
@ -10,10 +10,10 @@ use std::sync::mpsc::channel;
|
|||
fn test_local_drone() {
|
||||
let keypair = Keypair::new();
|
||||
let to = Keypair::new().pubkey();
|
||||
let tokens = 50;
|
||||
let lamports = 50;
|
||||
let blockhash = Hash::new(&to.as_ref());
|
||||
let expected_instruction = SystemInstruction::CreateAccount {
|
||||
tokens,
|
||||
lamports,
|
||||
space: 0,
|
||||
program_id: system_program::id(),
|
||||
};
|
||||
|
@ -31,6 +31,6 @@ fn test_local_drone() {
|
|||
run_local_drone(keypair, sender);
|
||||
let drone_addr = receiver.recv().unwrap();
|
||||
|
||||
let result = request_airdrop_transaction(&drone_addr, &to, tokens, blockhash);
|
||||
let result = request_airdrop_transaction(&drone_addr, &to, lamports, blockhash);
|
||||
assert_eq!(expected_tx, result.unwrap());
|
||||
}
|
||||
|
|
|
@ -12,10 +12,10 @@ use std::error;
|
|||
* - one token for the transaction fee
|
||||
* - one second token to keep the node identity public key valid
|
||||
*/
|
||||
//pub const BOOTSTRAP_LEADER_TOKENS: u64 = 3;
|
||||
//pub const BOOTSTRAP_LEADER_LAMPORTS: u64 = 3;
|
||||
// TODO: Until https://github.com/solana-labs/solana/issues/2355 is resolved the bootstrap leader
|
||||
// needs N tokens as its vote account gets re-created on every node restart, costing it tokens
|
||||
pub const BOOTSTRAP_LEADER_TOKENS: u64 = 1_000_000;
|
||||
pub const BOOTSTRAP_LEADER_LAMPORTS: u64 = 1_000_000;
|
||||
|
||||
fn main() -> Result<(), Box<dyn error::Error>> {
|
||||
let matches = App::new("solana-genesis")
|
||||
|
@ -70,7 +70,7 @@ fn main() -> Result<(), Box<dyn error::Error>> {
|
|||
let (mut genesis_block, _mint_keypair) = GenesisBlock::new_with_leader(
|
||||
num_tokens,
|
||||
bootstrap_leader_keypair.pubkey(),
|
||||
BOOTSTRAP_LEADER_TOKENS,
|
||||
BOOTSTRAP_LEADER_LAMPORTS,
|
||||
);
|
||||
genesis_block.mint_id = mint_keypair.pubkey();
|
||||
genesis_block.bootstrap_leader_vote_account_id = bootstrap_leader_vote_account_keypair.pubkey();
|
||||
|
|
|
@ -147,7 +147,7 @@ fn serialize_parameters(
|
|||
v.write_u64::<LittleEndian>(info.signer_key().is_some() as u64)
|
||||
.unwrap();
|
||||
v.write_all(info.unsigned_key().as_ref()).unwrap();
|
||||
v.write_u64::<LittleEndian>(info.account.tokens).unwrap();
|
||||
v.write_u64::<LittleEndian>(info.account.lamports).unwrap();
|
||||
v.write_u64::<LittleEndian>(info.account.userdata.len() as u64)
|
||||
.unwrap();
|
||||
v.write_all(&info.account.userdata).unwrap();
|
||||
|
@ -167,9 +167,9 @@ fn deserialize_parameters(keyed_accounts: &mut [KeyedAccount], buffer: &[u8]) {
|
|||
for info in keyed_accounts.iter_mut() {
|
||||
start += mem::size_of::<u64>(); // skip signer_key boolean
|
||||
start += mem::size_of::<Pubkey>(); // skip pubkey
|
||||
info.account.tokens = LittleEndian::read_u64(&buffer[start..]);
|
||||
info.account.lamports = LittleEndian::read_u64(&buffer[start..]);
|
||||
|
||||
start += mem::size_of::<u64>() // skip tokens
|
||||
start += mem::size_of::<u64>() // skip lamports
|
||||
+ mem::size_of::<u64>(); // skip length tag
|
||||
let end = start + info.account.userdata.len();
|
||||
info.account.userdata.clone_from_slice(&buffer[start..end]);
|
||||
|
|
|
@ -27,8 +27,8 @@ fn apply_signature(
|
|||
if let Some(key) = keyed_accounts[0].signer_key() {
|
||||
if &payment.to == key {
|
||||
budget_state.pending_budget = None;
|
||||
keyed_accounts[1].account.tokens -= payment.tokens;
|
||||
keyed_accounts[0].account.tokens += payment.tokens;
|
||||
keyed_accounts[1].account.lamports -= payment.tokens;
|
||||
keyed_accounts[0].account.lamports += payment.tokens;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
@ -37,8 +37,8 @@ fn apply_signature(
|
|||
return Err(BudgetError::DestinationMissing);
|
||||
}
|
||||
budget_state.pending_budget = None;
|
||||
keyed_accounts[1].account.tokens -= payment.tokens;
|
||||
keyed_accounts[2].account.tokens += payment.tokens;
|
||||
keyed_accounts[1].account.lamports -= payment.tokens;
|
||||
keyed_accounts[2].account.lamports += payment.tokens;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -68,8 +68,8 @@ fn apply_timestamp(
|
|||
return Err(BudgetError::DestinationMissing);
|
||||
}
|
||||
budget_state.pending_budget = None;
|
||||
keyed_accounts[1].account.tokens -= payment.tokens;
|
||||
keyed_accounts[2].account.tokens += payment.tokens;
|
||||
keyed_accounts[1].account.lamports -= payment.tokens;
|
||||
keyed_accounts[2].account.lamports += payment.tokens;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -86,8 +86,8 @@ fn apply_debits(
|
|||
BudgetInstruction::InitializeAccount(expr) => {
|
||||
let expr = expr.clone();
|
||||
if let Some(payment) = expr.final_payment() {
|
||||
keyed_accounts[1].account.tokens = 0;
|
||||
keyed_accounts[0].account.tokens += payment.tokens;
|
||||
keyed_accounts[1].account.lamports = 0;
|
||||
keyed_accounts[0].account.lamports += payment.tokens;
|
||||
Ok(())
|
||||
} else {
|
||||
let existing = BudgetState::deserialize(&keyed_accounts[1].account.userdata).ok();
|
||||
|
@ -97,8 +97,8 @@ fn apply_debits(
|
|||
} else {
|
||||
let mut budget_state = BudgetState::default();
|
||||
budget_state.pending_budget = Some(expr);
|
||||
keyed_accounts[1].account.tokens += keyed_accounts[0].account.tokens;
|
||||
keyed_accounts[0].account.tokens = 0;
|
||||
keyed_accounts[1].account.lamports += keyed_accounts[0].account.lamports;
|
||||
keyed_accounts[0].account.lamports = 0;
|
||||
budget_state.initialized = true;
|
||||
budget_state.serialize(&mut keyed_accounts[1].account.userdata)
|
||||
}
|
||||
|
@ -146,8 +146,8 @@ fn apply_debits(
|
|||
}
|
||||
|
||||
/// Budget DSL contract interface
|
||||
/// * accounts[0] - The source of the tokens
|
||||
/// * accounts[1] - The contract context. Once the contract has been completed, the tokens can
|
||||
/// * accounts[0] - The source of the lamports
|
||||
/// * accounts[1] - The contract context. Once the contract has been completed, the lamports can
|
||||
/// be spent from this account .
|
||||
pub fn process_instruction(
|
||||
keyed_accounts: &mut [KeyedAccount],
|
||||
|
@ -318,8 +318,8 @@ mod test {
|
|||
Hash::default(),
|
||||
);
|
||||
process_transaction(&tx, &mut accounts).unwrap();
|
||||
assert_eq!(accounts[from_account].tokens, 0);
|
||||
assert_eq!(accounts[contract_account].tokens, 1);
|
||||
assert_eq!(accounts[from_account].lamports, 0);
|
||||
assert_eq!(accounts[contract_account].lamports, 1);
|
||||
let budget_state = BudgetState::deserialize(&accounts[contract_account].userdata).unwrap();
|
||||
assert!(budget_state.is_pending());
|
||||
|
||||
|
@ -335,9 +335,9 @@ mod test {
|
|||
process_transaction(&tx, &mut accounts),
|
||||
Err(BudgetError::DestinationMissing)
|
||||
);
|
||||
assert_eq!(accounts[from_account].tokens, 0);
|
||||
assert_eq!(accounts[contract_account].tokens, 1);
|
||||
assert_eq!(accounts[to_account].tokens, 0);
|
||||
assert_eq!(accounts[from_account].lamports, 0);
|
||||
assert_eq!(accounts[contract_account].lamports, 1);
|
||||
assert_eq!(accounts[to_account].lamports, 0);
|
||||
|
||||
let budget_state = BudgetState::deserialize(&accounts[contract_account].userdata).unwrap();
|
||||
assert!(budget_state.is_pending());
|
||||
|
@ -352,9 +352,9 @@ mod test {
|
|||
Hash::default(),
|
||||
);
|
||||
process_transaction(&tx, &mut accounts).unwrap();
|
||||
assert_eq!(accounts[from_account].tokens, 0);
|
||||
assert_eq!(accounts[contract_account].tokens, 0);
|
||||
assert_eq!(accounts[to_account].tokens, 1);
|
||||
assert_eq!(accounts[from_account].lamports, 0);
|
||||
assert_eq!(accounts[contract_account].lamports, 0);
|
||||
assert_eq!(accounts[to_account].lamports, 1);
|
||||
|
||||
let budget_state = BudgetState::deserialize(&accounts[contract_account].userdata).unwrap();
|
||||
assert!(!budget_state.is_pending());
|
||||
|
@ -364,9 +364,9 @@ mod test {
|
|||
process_transaction(&tx, &mut accounts),
|
||||
Err(BudgetError::ContractNotPending)
|
||||
);
|
||||
assert_eq!(accounts[from_account].tokens, 0);
|
||||
assert_eq!(accounts[contract_account].tokens, 0);
|
||||
assert_eq!(accounts[to_account].tokens, 1);
|
||||
assert_eq!(accounts[from_account].lamports, 0);
|
||||
assert_eq!(accounts[contract_account].lamports, 0);
|
||||
assert_eq!(accounts[to_account].lamports, 1);
|
||||
}
|
||||
#[test]
|
||||
fn test_cancel_transfer() {
|
||||
|
@ -393,22 +393,22 @@ mod test {
|
|||
Hash::default(),
|
||||
);
|
||||
process_transaction(&tx, &mut accounts).unwrap();
|
||||
assert_eq!(accounts[from_account].tokens, 0);
|
||||
assert_eq!(accounts[contract_account].tokens, 1);
|
||||
assert_eq!(accounts[from_account].lamports, 0);
|
||||
assert_eq!(accounts[contract_account].lamports, 1);
|
||||
let budget_state = BudgetState::deserialize(&accounts[contract_account].userdata).unwrap();
|
||||
assert!(budget_state.is_pending());
|
||||
|
||||
// Attack! try to put the tokens into the wrong account with cancel
|
||||
// Attack! try to put the lamports into the wrong account with cancel
|
||||
let tx =
|
||||
BudgetTransaction::new_signature(&to, contract.pubkey(), to.pubkey(), Hash::default());
|
||||
// unit test hack, the `from account` is passed instead of the `to` account to avoid
|
||||
// creating more account vectors
|
||||
process_transaction(&tx, &mut accounts).unwrap();
|
||||
// nothing should be changed because apply witness didn't finalize a payment
|
||||
assert_eq!(accounts[from_account].tokens, 0);
|
||||
assert_eq!(accounts[contract_account].tokens, 1);
|
||||
assert_eq!(accounts[from_account].lamports, 0);
|
||||
assert_eq!(accounts[contract_account].lamports, 1);
|
||||
// this is the `to.pubkey()` account
|
||||
assert_eq!(accounts[pay_account].tokens, 0);
|
||||
assert_eq!(accounts[pay_account].lamports, 0);
|
||||
|
||||
// Now, cancel the transaction. from gets her funds back
|
||||
let tx = BudgetTransaction::new_signature(
|
||||
|
@ -418,9 +418,9 @@ mod test {
|
|||
Hash::default(),
|
||||
);
|
||||
process_transaction(&tx, &mut accounts).unwrap();
|
||||
assert_eq!(accounts[from_account].tokens, 1);
|
||||
assert_eq!(accounts[contract_account].tokens, 0);
|
||||
assert_eq!(accounts[pay_account].tokens, 0);
|
||||
assert_eq!(accounts[from_account].lamports, 1);
|
||||
assert_eq!(accounts[contract_account].lamports, 0);
|
||||
assert_eq!(accounts[pay_account].lamports, 0);
|
||||
|
||||
// try to replay the cancel contract
|
||||
let tx = BudgetTransaction::new_signature(
|
||||
|
@ -433,9 +433,9 @@ mod test {
|
|||
process_transaction(&tx, &mut accounts),
|
||||
Err(BudgetError::ContractNotPending)
|
||||
);
|
||||
assert_eq!(accounts[from_account].tokens, 1);
|
||||
assert_eq!(accounts[contract_account].tokens, 0);
|
||||
assert_eq!(accounts[pay_account].tokens, 0);
|
||||
assert_eq!(accounts[from_account].lamports, 1);
|
||||
assert_eq!(accounts[contract_account].lamports, 0);
|
||||
assert_eq!(accounts[pay_account].lamports, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -171,13 +171,13 @@ impl BudgetTransaction {
|
|||
|
||||
/// Verify only the payment plan.
|
||||
pub fn verify_plan(tx: &Transaction) -> bool {
|
||||
if let Some(SystemInstruction::CreateAccount { tokens, .. }) =
|
||||
if let Some(SystemInstruction::CreateAccount { lamports, .. }) =
|
||||
Self::system_instruction(tx, 0)
|
||||
{
|
||||
if let Some(BudgetInstruction::InitializeAccount(expr)) =
|
||||
BudgetTransaction::instruction(&tx, 1)
|
||||
{
|
||||
if !(tx.fee <= tokens && expr.verify(tokens - tx.fee)) {
|
||||
if !(tx.fee <= lamports && expr.verify(lamports - tx.fee)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -236,12 +236,15 @@ mod tests {
|
|||
let pubkey = keypair.pubkey();
|
||||
let mut tx = BudgetTransaction::new(&keypair, pubkey, 42, zero);
|
||||
let mut system_instruction = BudgetTransaction::system_instruction(&tx, 0).unwrap();
|
||||
if let SystemInstruction::CreateAccount { ref mut tokens, .. } = system_instruction {
|
||||
*tokens = 1_000_000; // <-- attack, part 1!
|
||||
if let SystemInstruction::CreateAccount {
|
||||
ref mut lamports, ..
|
||||
} = system_instruction
|
||||
{
|
||||
*lamports = 1_000_000; // <-- attack, part 1!
|
||||
let mut instruction = BudgetTransaction::instruction(&tx, 1).unwrap();
|
||||
if let BudgetInstruction::InitializeAccount(ref mut expr) = instruction {
|
||||
if let BudgetExpr::Pay(ref mut payment) = expr {
|
||||
payment.tokens = *tokens; // <-- attack, part 2!
|
||||
payment.tokens = *lamports; // <-- attack, part 2!
|
||||
}
|
||||
}
|
||||
tx.instructions[1].userdata = serialize(&instruction).unwrap();
|
||||
|
|
|
@ -48,7 +48,7 @@ fn redeem_vote_credits(keyed_accounts: &mut [KeyedAccount]) -> Result<(), Progra
|
|||
|
||||
// TODO: This assumes the stake is static. If not, it should use the account value
|
||||
// at the time of voting, not at credit redemption.
|
||||
let stake = keyed_accounts[0].account.tokens;
|
||||
let stake = keyed_accounts[0].account.lamports;
|
||||
if stake == 0 {
|
||||
error!("staking account has no stake");
|
||||
Err(ProgramError::InvalidArgument)?;
|
||||
|
@ -57,8 +57,8 @@ fn redeem_vote_credits(keyed_accounts: &mut [KeyedAccount]) -> Result<(), Progra
|
|||
let lamports = calc_vote_reward(vote_state.credits(), stake)?;
|
||||
|
||||
// Transfer rewards from the rewards pool to the staking account.
|
||||
keyed_accounts[1].account.tokens -= lamports;
|
||||
keyed_accounts[0].account.tokens += lamports;
|
||||
keyed_accounts[1].account.lamports -= lamports;
|
||||
keyed_accounts[0].account.lamports += lamports;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -90,9 +90,9 @@ mod tests {
|
|||
use solana_vote_api::vote_instruction::Vote;
|
||||
use solana_vote_api::vote_state;
|
||||
|
||||
fn create_rewards_account(tokens: u64) -> Account {
|
||||
fn create_rewards_account(lamports: u64) -> Account {
|
||||
let space = RewardsState::max_size();
|
||||
Account::new(tokens, space, solana_rewards_api::id())
|
||||
Account::new(lamports, space, solana_rewards_api::id())
|
||||
}
|
||||
|
||||
fn redeem_vote_credits_(
|
||||
|
@ -130,7 +130,7 @@ mod tests {
|
|||
let rewards_id = Keypair::new().pubkey();
|
||||
let mut rewards_account = create_rewards_account(100);
|
||||
|
||||
let tokens_before = vote_account.tokens;
|
||||
let lamports_before = vote_account.lamports;
|
||||
|
||||
redeem_vote_credits_(
|
||||
&rewards_id,
|
||||
|
@ -139,6 +139,6 @@ mod tests {
|
|||
&mut vote_account,
|
||||
)
|
||||
.unwrap();
|
||||
assert!(vote_account.tokens > tokens_before);
|
||||
assert!(vote_account.lamports > lamports_before);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -152,7 +152,7 @@ fn entrypoint(
|
|||
}
|
||||
total_validations += num_validations;
|
||||
if total_validations > 0 {
|
||||
keyed_accounts[0].account.tokens +=
|
||||
keyed_accounts[0].account.lamports +=
|
||||
(TOTAL_VALIDATOR_REWARDS * num_validations) / total_validations;
|
||||
}
|
||||
}
|
||||
|
@ -360,6 +360,6 @@ mod test {
|
|||
let tx = StorageTransaction::new_reward_claim(&keypair, Hash::default(), entry_height);
|
||||
test_transaction(&tx, &mut accounts).unwrap();
|
||||
|
||||
assert!(accounts[0].tokens == TOTAL_VALIDATOR_REWARDS);
|
||||
assert!(accounts[0].lamports == TOTAL_VALIDATOR_REWARDS);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,13 +12,13 @@ const TO_ACCOUNT_INDEX: usize = 1;
|
|||
#[derive(Debug, Clone, PartialEq)]
|
||||
enum SystemError {
|
||||
AccountAlreadyInUse,
|
||||
ResultWithNegativeTokens,
|
||||
ResultWithNegativeLamports,
|
||||
SourceNotSystemAccount,
|
||||
}
|
||||
|
||||
fn create_system_account(
|
||||
keyed_accounts: &mut [KeyedAccount],
|
||||
tokens: u64,
|
||||
lamports: u64,
|
||||
space: u64,
|
||||
program_id: Pubkey,
|
||||
) -> Result<(), SystemError> {
|
||||
|
@ -36,15 +36,15 @@ fn create_system_account(
|
|||
);
|
||||
Err(SystemError::AccountAlreadyInUse)?;
|
||||
}
|
||||
if tokens > keyed_accounts[FROM_ACCOUNT_INDEX].account.tokens {
|
||||
if lamports > keyed_accounts[FROM_ACCOUNT_INDEX].account.lamports {
|
||||
info!(
|
||||
"CreateAccount: insufficient tokens ({}, need {})",
|
||||
keyed_accounts[FROM_ACCOUNT_INDEX].account.tokens, tokens
|
||||
"CreateAccount: insufficient lamports ({}, need {})",
|
||||
keyed_accounts[FROM_ACCOUNT_INDEX].account.lamports, lamports
|
||||
);
|
||||
Err(SystemError::ResultWithNegativeTokens)?;
|
||||
Err(SystemError::ResultWithNegativeLamports)?;
|
||||
}
|
||||
keyed_accounts[FROM_ACCOUNT_INDEX].account.tokens -= tokens;
|
||||
keyed_accounts[TO_ACCOUNT_INDEX].account.tokens += tokens;
|
||||
keyed_accounts[FROM_ACCOUNT_INDEX].account.lamports -= lamports;
|
||||
keyed_accounts[TO_ACCOUNT_INDEX].account.lamports += lamports;
|
||||
keyed_accounts[TO_ACCOUNT_INDEX].account.owner = program_id;
|
||||
keyed_accounts[TO_ACCOUNT_INDEX].account.userdata = vec![0; space as usize];
|
||||
keyed_accounts[TO_ACCOUNT_INDEX].account.executable = false;
|
||||
|
@ -61,16 +61,16 @@ fn assign_account_to_program(
|
|||
keyed_accounts[FROM_ACCOUNT_INDEX].account.owner = program_id;
|
||||
Ok(())
|
||||
}
|
||||
fn move_tokens(keyed_accounts: &mut [KeyedAccount], tokens: u64) -> Result<(), ProgramError> {
|
||||
if tokens > keyed_accounts[FROM_ACCOUNT_INDEX].account.tokens {
|
||||
fn move_lamports(keyed_accounts: &mut [KeyedAccount], lamports: u64) -> Result<(), ProgramError> {
|
||||
if lamports > keyed_accounts[FROM_ACCOUNT_INDEX].account.lamports {
|
||||
info!(
|
||||
"Move: insufficient tokens ({}, need {})",
|
||||
keyed_accounts[FROM_ACCOUNT_INDEX].account.tokens, tokens
|
||||
"Move: insufficient lamports ({}, need {})",
|
||||
keyed_accounts[FROM_ACCOUNT_INDEX].account.lamports, lamports
|
||||
);
|
||||
Err(ProgramError::ResultWithNegativeTokens)?;
|
||||
Err(ProgramError::ResultWithNegativeLamports)?;
|
||||
}
|
||||
keyed_accounts[FROM_ACCOUNT_INDEX].account.tokens -= tokens;
|
||||
keyed_accounts[TO_ACCOUNT_INDEX].account.tokens += tokens;
|
||||
keyed_accounts[FROM_ACCOUNT_INDEX].account.lamports -= lamports;
|
||||
keyed_accounts[TO_ACCOUNT_INDEX].account.lamports += lamports;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -93,24 +93,22 @@ pub fn entrypoint(
|
|||
|
||||
match syscall {
|
||||
SystemInstruction::CreateAccount {
|
||||
tokens,
|
||||
lamports,
|
||||
space,
|
||||
program_id,
|
||||
} => {
|
||||
create_system_account(keyed_accounts, tokens, space, program_id).map_err(
|
||||
|e| match e {
|
||||
SystemError::AccountAlreadyInUse => ProgramError::InvalidArgument,
|
||||
SystemError::ResultWithNegativeTokens => {
|
||||
ProgramError::ResultWithNegativeTokens
|
||||
}
|
||||
SystemError::SourceNotSystemAccount => ProgramError::InvalidArgument,
|
||||
},
|
||||
)
|
||||
}
|
||||
} => create_system_account(keyed_accounts, lamports, space, program_id).map_err(|e| {
|
||||
match e {
|
||||
SystemError::AccountAlreadyInUse => ProgramError::InvalidArgument,
|
||||
SystemError::ResultWithNegativeLamports => {
|
||||
ProgramError::ResultWithNegativeLamports
|
||||
}
|
||||
SystemError::SourceNotSystemAccount => ProgramError::InvalidArgument,
|
||||
}
|
||||
}),
|
||||
SystemInstruction::Assign { program_id } => {
|
||||
assign_account_to_program(keyed_accounts, program_id)
|
||||
}
|
||||
SystemInstruction::Move { tokens } => move_tokens(keyed_accounts, tokens),
|
||||
SystemInstruction::Move { lamports } => move_lamports(keyed_accounts, lamports),
|
||||
}
|
||||
} else {
|
||||
info!("Invalid transaction instruction userdata: {:?}", data);
|
||||
|
@ -138,19 +136,19 @@ mod tests {
|
|||
KeyedAccount::new(&to, false, &mut to_account),
|
||||
];
|
||||
create_system_account(&mut keyed_accounts, 50, 2, new_program_owner).unwrap();
|
||||
let from_tokens = from_account.tokens;
|
||||
let to_tokens = to_account.tokens;
|
||||
let from_lamports = from_account.lamports;
|
||||
let to_lamports = to_account.lamports;
|
||||
let to_owner = to_account.owner;
|
||||
let to_userdata = to_account.userdata.clone();
|
||||
assert_eq!(from_tokens, 50);
|
||||
assert_eq!(to_tokens, 50);
|
||||
assert_eq!(from_lamports, 50);
|
||||
assert_eq!(to_lamports, 50);
|
||||
assert_eq!(to_owner, new_program_owner);
|
||||
assert_eq!(to_userdata, [0, 0]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_create_negative_tokens() {
|
||||
// Attempt to create account with more tokens than remaining in from_account
|
||||
fn test_create_negative_lamports() {
|
||||
// Attempt to create account with more lamports than remaining in from_account
|
||||
let new_program_owner = Pubkey::new(&[9; 32]);
|
||||
let from = Keypair::new().pubkey();
|
||||
let mut from_account = Account::new(100, 0, system_program::id());
|
||||
|
@ -164,9 +162,9 @@ mod tests {
|
|||
KeyedAccount::new(&to, false, &mut to_account),
|
||||
];
|
||||
let result = create_system_account(&mut keyed_accounts, 150, 2, new_program_owner);
|
||||
assert_eq!(result, Err(SystemError::ResultWithNegativeTokens));
|
||||
let from_tokens = from_account.tokens;
|
||||
assert_eq!(from_tokens, 100);
|
||||
assert_eq!(result, Err(SystemError::ResultWithNegativeLamports));
|
||||
let from_lamports = from_account.lamports;
|
||||
assert_eq!(from_lamports, 100);
|
||||
assert_eq!(to_account, unchanged_account);
|
||||
}
|
||||
|
||||
|
@ -188,8 +186,8 @@ mod tests {
|
|||
];
|
||||
let result = create_system_account(&mut keyed_accounts, 50, 2, new_program_owner);
|
||||
assert_eq!(result, Err(SystemError::AccountAlreadyInUse));
|
||||
let from_tokens = from_account.tokens;
|
||||
assert_eq!(from_tokens, 100);
|
||||
let from_lamports = from_account.lamports;
|
||||
assert_eq!(from_lamports, 100);
|
||||
assert_eq!(owned_account, unchanged_account);
|
||||
}
|
||||
|
||||
|
@ -202,7 +200,7 @@ mod tests {
|
|||
|
||||
let populated_key = Keypair::new().pubkey();
|
||||
let mut populated_account = Account {
|
||||
tokens: 0,
|
||||
lamports: 0,
|
||||
userdata: vec![0, 1, 2, 3],
|
||||
owner: Pubkey::default(),
|
||||
executable: false,
|
||||
|
@ -215,7 +213,7 @@ mod tests {
|
|||
];
|
||||
let result = create_system_account(&mut keyed_accounts, 50, 2, new_program_owner);
|
||||
assert_eq!(result, Err(SystemError::AccountAlreadyInUse));
|
||||
assert_eq!(from_account.tokens, 100);
|
||||
assert_eq!(from_account.lamports, 100);
|
||||
assert_eq!(populated_account, unchanged_account);
|
||||
}
|
||||
|
||||
|
@ -255,7 +253,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn test_move_tokens() {
|
||||
fn test_move_lamports() {
|
||||
let from = Keypair::new().pubkey();
|
||||
let mut from_account = Account::new(100, 0, Pubkey::new(&[2; 32])); // account owner should not matter
|
||||
let to = Keypair::new().pubkey();
|
||||
|
@ -264,20 +262,20 @@ mod tests {
|
|||
KeyedAccount::new(&from, true, &mut from_account),
|
||||
KeyedAccount::new(&to, false, &mut to_account),
|
||||
];
|
||||
move_tokens(&mut keyed_accounts, 50).unwrap();
|
||||
let from_tokens = from_account.tokens;
|
||||
let to_tokens = to_account.tokens;
|
||||
assert_eq!(from_tokens, 50);
|
||||
assert_eq!(to_tokens, 51);
|
||||
move_lamports(&mut keyed_accounts, 50).unwrap();
|
||||
let from_lamports = from_account.lamports;
|
||||
let to_lamports = to_account.lamports;
|
||||
assert_eq!(from_lamports, 50);
|
||||
assert_eq!(to_lamports, 51);
|
||||
|
||||
// Attempt to move more tokens than remaining in from_account
|
||||
// Attempt to move more lamports than remaining in from_account
|
||||
keyed_accounts = [
|
||||
KeyedAccount::new(&from, true, &mut from_account),
|
||||
KeyedAccount::new(&to, false, &mut to_account),
|
||||
];
|
||||
let result = move_tokens(&mut keyed_accounts, 100);
|
||||
assert_eq!(result, Err(ProgramError::ResultWithNegativeTokens));
|
||||
assert_eq!(from_account.tokens, 50);
|
||||
assert_eq!(to_account.tokens, 51);
|
||||
let result = move_lamports(&mut keyed_accounts, 100);
|
||||
assert_eq!(result, Err(ProgramError::ResultWithNegativeLamports));
|
||||
assert_eq!(from_account.lamports, 50);
|
||||
assert_eq!(to_account.lamports, 51);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ fn test_system_unsigned_transaction() {
|
|||
let tx = TransactionBuilder::default()
|
||||
.push(BuilderInstruction::new(
|
||||
system_program::id(),
|
||||
&SystemInstruction::Move { tokens: 10 },
|
||||
&SystemInstruction::Move { lamports: 10 },
|
||||
vec![(from_keypair.pubkey(), false), (to_keypair.pubkey(), true)],
|
||||
))
|
||||
.sign(&[&to_keypair], blockhash);
|
||||
|
|
|
@ -396,11 +396,11 @@ impl AccountsDB {
|
|||
let start = self.next_id.fetch_add(1, Ordering::Relaxed);
|
||||
let mut id = self.get_storage_id(start, std::usize::MAX);
|
||||
|
||||
// Even if no tokens, need to preserve the account owner so
|
||||
// Even if no lamports, need to preserve the account owner so
|
||||
// we can update the vote_accounts correctly if this account is purged
|
||||
// when squashing.
|
||||
let acc = &mut account.clone();
|
||||
if account.tokens == 0 {
|
||||
if account.lamports == 0 {
|
||||
acc.userdata.resize(0, 0);
|
||||
}
|
||||
|
||||
|
@ -480,7 +480,7 @@ impl AccountsDB {
|
|||
|
||||
/// Store the account update.
|
||||
fn store_account(&self, fork: Fork, pubkey: &Pubkey, account: &Account) {
|
||||
if account.tokens == 0 && self.is_squashed(fork) {
|
||||
if account.lamports == 0 && self.is_squashed(fork) {
|
||||
// purge if balance is 0 and no checkpoints
|
||||
let account_maps = self.account_index.account_maps.read().unwrap();
|
||||
let map = account_maps.get(&pubkey).unwrap();
|
||||
|
@ -576,14 +576,14 @@ impl AccountsDB {
|
|||
for key in &tx.account_keys {
|
||||
called_accounts.push(self.load(fork, key, true).unwrap_or_default());
|
||||
}
|
||||
if called_accounts.is_empty() || called_accounts[0].tokens == 0 {
|
||||
if called_accounts.is_empty() || called_accounts[0].lamports == 0 {
|
||||
error_counters.account_not_found += 1;
|
||||
Err(BankError::AccountNotFound)
|
||||
} else if called_accounts[0].tokens < tx.fee {
|
||||
} else if called_accounts[0].lamports < tx.fee {
|
||||
error_counters.insufficient_funds += 1;
|
||||
Err(BankError::InsufficientFundsForFee)
|
||||
} else {
|
||||
called_accounts[0].tokens -= tx.fee;
|
||||
called_accounts[0].lamports -= tx.fee;
|
||||
Ok(called_accounts)
|
||||
}
|
||||
}
|
||||
|
@ -735,7 +735,7 @@ impl AccountsDB {
|
|||
self.insert_account_entry(fork, id, offset, &map);
|
||||
} else {
|
||||
let account = self.get_account(id, offset);
|
||||
if account.tokens == 0 {
|
||||
if account.lamports == 0 {
|
||||
if self.remove_account_entries(&[fork], &map) {
|
||||
keys.push(pubkey.clone());
|
||||
}
|
||||
|
@ -803,14 +803,14 @@ impl Accounts {
|
|||
pub fn load_slow(&self, fork: Fork, pubkey: &Pubkey) -> Option<Account> {
|
||||
self.accounts_db
|
||||
.load(fork, pubkey, true)
|
||||
.filter(|acc| acc.tokens != 0)
|
||||
.filter(|acc| acc.lamports != 0)
|
||||
}
|
||||
|
||||
/// Slow because lock is held for 1 operation insted of many
|
||||
pub fn load_slow_no_parent(&self, fork: Fork, pubkey: &Pubkey) -> Option<Account> {
|
||||
self.accounts_db
|
||||
.load(fork, pubkey, false)
|
||||
.filter(|acc| acc.tokens != 0)
|
||||
.filter(|acc| acc.lamports != 0)
|
||||
}
|
||||
|
||||
/// Slow because lock is held for 1 operation insted of many
|
||||
|
@ -943,7 +943,7 @@ impl Accounts {
|
|||
self.accounts_db
|
||||
.get_vote_accounts(fork)
|
||||
.into_iter()
|
||||
.filter(|(_, acc)| acc.tokens != 0)
|
||||
.filter(|(_, acc)| acc.lamports != 0)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1402,11 +1402,11 @@ mod tests {
|
|||
|
||||
// now we have:
|
||||
//
|
||||
// root0 -> key.tokens==1
|
||||
// root0 -> key.lamports==1
|
||||
// / \
|
||||
// / \
|
||||
// key.tokens==0 <- fork1 \
|
||||
// fork2 -> key.tokens==1
|
||||
// key.lamports==0 <- fork1 \
|
||||
// fork2 -> key.lamports==1
|
||||
// (via root0)
|
||||
|
||||
// store value 0 in one child
|
||||
|
@ -1426,11 +1426,11 @@ mod tests {
|
|||
|
||||
// now we should have:
|
||||
//
|
||||
// root0 -> key.tokens==1
|
||||
// root0 -> key.lamports==1
|
||||
// \
|
||||
// \
|
||||
// key.tokens==ANF <- root1 \
|
||||
// fork2 -> key.tokens==1 (from root0)
|
||||
// key.lamports==ANF <- root1 \
|
||||
// fork2 -> key.lamports==1 (from root0)
|
||||
//
|
||||
assert_eq!(db.load(1, &key, true), None); // purged
|
||||
assert_eq!(&db.load(2, &key, true).unwrap(), &account0); // original value
|
||||
|
@ -1447,17 +1447,17 @@ mod tests {
|
|||
let idx = thread_rng().gen_range(0, 99);
|
||||
let account = db.load(0, &pubkeys[idx], true).unwrap();
|
||||
let mut default_account = Account::default();
|
||||
default_account.tokens = (idx + 1) as u64;
|
||||
default_account.lamports = (idx + 1) as u64;
|
||||
assert_eq!(compare_account(&default_account, &account), true);
|
||||
}
|
||||
db.add_fork(1, Some(0));
|
||||
|
||||
// now we have:
|
||||
//
|
||||
// root0 -> key[X].tokens==X
|
||||
// root0 -> key[X].lamports==X
|
||||
// /
|
||||
// /
|
||||
// key[X].tokens==X <- fork1
|
||||
// key[X].lamports==X <- fork1
|
||||
// (via root0)
|
||||
//
|
||||
|
||||
|
@ -1468,7 +1468,7 @@ mod tests {
|
|||
// root0 -> purged ??
|
||||
//
|
||||
//
|
||||
// key[X].tokens==X <- root1
|
||||
// key[X].lamports==X <- root1
|
||||
//
|
||||
|
||||
// check that all the accounts appear in parent after a squash ???
|
||||
|
@ -1477,7 +1477,7 @@ mod tests {
|
|||
let account0 = db.load(0, &pubkeys[idx], true).unwrap();
|
||||
let account1 = db.load(1, &pubkeys[idx], true).unwrap();
|
||||
let mut default_account = Account::default();
|
||||
default_account.tokens = (idx + 1) as u64;
|
||||
default_account.lamports = (idx + 1) as u64;
|
||||
assert_eq!(&default_account, &account0);
|
||||
assert_eq!(&default_account, &account1);
|
||||
}
|
||||
|
@ -1494,7 +1494,7 @@ mod tests {
|
|||
db0.store(0, &key, &account0);
|
||||
|
||||
db0.add_fork(1, Some(0));
|
||||
// 0 tokens in the child
|
||||
// 0 lamports in the child
|
||||
let account1 = Account::new(0, 0, key);
|
||||
db0.store(1, &key, &account1);
|
||||
|
||||
|
@ -1518,7 +1518,7 @@ mod tests {
|
|||
let pubkey = Keypair::new().pubkey();
|
||||
let mut default_account = Account::default();
|
||||
pubkeys.push(pubkey.clone());
|
||||
default_account.tokens = (t + 1) as u64;
|
||||
default_account.lamports = (t + 1) as u64;
|
||||
assert!(accounts.load(0, &pubkey, true).is_none());
|
||||
accounts.store(0, &pubkey, &default_account);
|
||||
}
|
||||
|
@ -1527,7 +1527,7 @@ mod tests {
|
|||
let mut default_account = Account::default();
|
||||
pubkeys.push(pubkey.clone());
|
||||
default_account.owner = solana_vote_api::id();
|
||||
default_account.tokens = (num + t + 1) as u64;
|
||||
default_account.lamports = (num + t + 1) as u64;
|
||||
assert!(accounts.load(0, &pubkey, true).is_none());
|
||||
accounts.store(0, &pubkey, &default_account);
|
||||
}
|
||||
|
@ -1537,13 +1537,13 @@ mod tests {
|
|||
for _ in 1..1000 {
|
||||
let idx = thread_rng().gen_range(0, range);
|
||||
if let Some(mut account) = accounts.load(0, &pubkeys[idx], true) {
|
||||
account.tokens = account.tokens + 1;
|
||||
account.lamports = account.lamports + 1;
|
||||
accounts.store(0, &pubkeys[idx], &account);
|
||||
if account.tokens == 0 {
|
||||
if account.lamports == 0 {
|
||||
assert!(accounts.load(0, &pubkeys[idx], true).is_none());
|
||||
} else {
|
||||
let mut default_account = Account::default();
|
||||
default_account.tokens = account.tokens;
|
||||
default_account.lamports = account.lamports;
|
||||
assert_eq!(compare_account(&default_account, &account), true);
|
||||
}
|
||||
}
|
||||
|
@ -1554,7 +1554,7 @@ mod tests {
|
|||
if account1.userdata != account2.userdata
|
||||
|| account1.owner != account2.owner
|
||||
|| account1.executable != account2.executable
|
||||
|| account1.tokens != account2.tokens
|
||||
|| account1.lamports != account2.lamports
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -1569,7 +1569,7 @@ mod tests {
|
|||
create_account(&accounts, &mut pubkeys, 1, 0);
|
||||
let account = accounts.load(0, &pubkeys[0], true).unwrap();
|
||||
let mut default_account = Account::default();
|
||||
default_account.tokens = 1;
|
||||
default_account.lamports = 1;
|
||||
assert_eq!(compare_account(&default_account, &account), true);
|
||||
}
|
||||
|
||||
|
@ -1583,7 +1583,7 @@ mod tests {
|
|||
let idx = thread_rng().gen_range(0, 99);
|
||||
let account = accounts.load(0, &pubkeys[idx], true).unwrap();
|
||||
let mut default_account = Account::default();
|
||||
default_account.tokens = (idx + 1) as u64;
|
||||
default_account.lamports = (idx + 1) as u64;
|
||||
assert_eq!(compare_account(&default_account, &account), true);
|
||||
}
|
||||
}
|
||||
|
@ -1669,7 +1669,7 @@ mod tests {
|
|||
let mut vote_accounts: Vec<_> = accounts.get_vote_accounts(1).collect();
|
||||
assert_eq!(vote_accounts.len(), 1);
|
||||
|
||||
vote_account.tokens = 0;
|
||||
vote_account.lamports = 0;
|
||||
accounts.store_slow(1, &key, &vote_account);
|
||||
|
||||
vote_accounts = accounts.get_vote_accounts(1).collect();
|
||||
|
@ -1685,7 +1685,7 @@ mod tests {
|
|||
vote_accounts = accounts.get_vote_accounts(1).collect();
|
||||
assert_eq!(vote_accounts.len(), 1);
|
||||
|
||||
vote_account1.tokens = 0;
|
||||
vote_account1.lamports = 0;
|
||||
accounts.store_slow(1, &key1, &vote_account1);
|
||||
accounts.store_slow(0, &key, &vote_account);
|
||||
|
||||
|
@ -1716,11 +1716,11 @@ mod tests {
|
|||
accounts_db.get_vote_accounts(0)
|
||||
);
|
||||
|
||||
info!("storing tokens=0 to fork 1");
|
||||
// should store a tokens=0 account in 1
|
||||
lastaccount.tokens = 0;
|
||||
info!("storing lamports=0 to fork 1");
|
||||
// should store a lamports=0 account in 1
|
||||
lastaccount.lamports = 0;
|
||||
accounts_db.store(1, &lastkey, &lastaccount);
|
||||
// len == 2 because tokens=0 accounts are filtered at the Accounts interface.
|
||||
// len == 2 because lamports=0 accounts are filtered at the Accounts interface.
|
||||
assert_eq!(accounts_db.get_vote_accounts(1).len(), 2);
|
||||
|
||||
accounts_db.squash(1);
|
||||
|
|
|
@ -40,7 +40,7 @@ pub fn serialize_account(dst_slice: &mut [u8], account: &Account, len: usize) {
|
|||
let mut at = 0;
|
||||
|
||||
write_u64(&mut at, dst_slice, len as u64);
|
||||
write_u64(&mut at, dst_slice, account.tokens);
|
||||
write_u64(&mut at, dst_slice, account.lamports);
|
||||
write_bytes(&mut at, dst_slice, &account.userdata);
|
||||
write_bytes(&mut at, dst_slice, account.owner.as_ref());
|
||||
write_bytes(&mut at, dst_slice, &[account.executable as u8]);
|
||||
|
@ -81,7 +81,7 @@ pub fn deserialize_account(
|
|||
let len = size as usize;
|
||||
assert!(current_offset >= at + len);
|
||||
|
||||
let tokens = read_u64(&mut at, &src_slice);
|
||||
let lamports = read_u64(&mut at, &src_slice);
|
||||
|
||||
let userdata_len = len - get_account_size_static();
|
||||
let mut userdata = vec![0; userdata_len];
|
||||
|
@ -96,7 +96,7 @@ pub fn deserialize_account(
|
|||
let executable: bool = exec[0] != 0;
|
||||
|
||||
Ok(Account {
|
||||
tokens,
|
||||
lamports,
|
||||
userdata,
|
||||
owner,
|
||||
executable,
|
||||
|
@ -255,7 +255,7 @@ pub mod tests {
|
|||
let av: AppendVec<Account> = AppendVec::new(path, true, START_SIZE, INC_SIZE);
|
||||
let v1 = vec![1u8; 32];
|
||||
let mut account1 = Account {
|
||||
tokens: 1,
|
||||
lamports: 1,
|
||||
userdata: v1,
|
||||
owner: Pubkey::default(),
|
||||
executable: false,
|
||||
|
@ -266,7 +266,7 @@ pub mod tests {
|
|||
|
||||
let v2 = vec![4u8; 32];
|
||||
let mut account2 = Account {
|
||||
tokens: 1,
|
||||
lamports: 1,
|
||||
userdata: v2,
|
||||
owner: Pubkey::default(),
|
||||
executable: false,
|
||||
|
|
|
@ -240,24 +240,27 @@ impl Bank {
|
|||
assert!(genesis_block.mint_id != Pubkey::default());
|
||||
assert!(genesis_block.bootstrap_leader_id != Pubkey::default());
|
||||
assert!(genesis_block.bootstrap_leader_vote_account_id != Pubkey::default());
|
||||
assert!(genesis_block.tokens >= genesis_block.bootstrap_leader_tokens);
|
||||
assert!(genesis_block.bootstrap_leader_tokens >= 3);
|
||||
assert!(genesis_block.lamports >= genesis_block.bootstrap_leader_lamports);
|
||||
assert!(genesis_block.bootstrap_leader_lamports >= 3);
|
||||
|
||||
// Bootstrap leader collects fees until `new_from_parent` is called.
|
||||
self.collector_id = genesis_block.bootstrap_leader_id;
|
||||
|
||||
let mint_tokens = genesis_block.tokens - genesis_block.bootstrap_leader_tokens;
|
||||
self.deposit(&genesis_block.mint_id, mint_tokens);
|
||||
let mint_lamports = genesis_block.lamports - genesis_block.bootstrap_leader_lamports;
|
||||
self.deposit(&genesis_block.mint_id, mint_lamports);
|
||||
|
||||
let bootstrap_leader_tokens = 2;
|
||||
let bootstrap_leader_lamports = 2;
|
||||
let bootstrap_leader_stake =
|
||||
genesis_block.bootstrap_leader_tokens - bootstrap_leader_tokens;
|
||||
self.deposit(&genesis_block.bootstrap_leader_id, bootstrap_leader_tokens);
|
||||
genesis_block.bootstrap_leader_lamports - bootstrap_leader_lamports;
|
||||
self.deposit(
|
||||
&genesis_block.bootstrap_leader_id,
|
||||
bootstrap_leader_lamports,
|
||||
);
|
||||
|
||||
// Construct a vote account for the bootstrap_leader such that the leader_scheduler
|
||||
// will be forced to select it as the leader for height 0
|
||||
let mut bootstrap_leader_vote_account = Account {
|
||||
tokens: bootstrap_leader_stake,
|
||||
lamports: bootstrap_leader_stake,
|
||||
userdata: vec![0; VoteState::max_size() as usize],
|
||||
owner: solana_vote_api::id(),
|
||||
executable: false,
|
||||
|
@ -645,7 +648,7 @@ impl Bank {
|
|||
}
|
||||
|
||||
/// Create, sign, and process a Transaction from `keypair` to `to` of
|
||||
/// `n` tokens where `blockhash` is the last Entry ID observed by the client.
|
||||
/// `n` lamports where `blockhash` is the last Entry ID observed by the client.
|
||||
pub fn transfer(
|
||||
&self,
|
||||
n: u64,
|
||||
|
@ -659,7 +662,7 @@ impl Bank {
|
|||
}
|
||||
|
||||
pub fn read_balance(account: &Account) -> u64 {
|
||||
account.tokens
|
||||
account.lamports
|
||||
}
|
||||
/// Each program would need to be able to introspect its own state
|
||||
/// this is hard-coded to the Budget language
|
||||
|
@ -680,14 +683,14 @@ impl Bank {
|
|||
parents
|
||||
}
|
||||
|
||||
pub fn withdraw(&self, pubkey: &Pubkey, tokens: u64) -> Result<()> {
|
||||
pub fn withdraw(&self, pubkey: &Pubkey, lamports: u64) -> Result<()> {
|
||||
match self.get_account(pubkey) {
|
||||
Some(mut account) => {
|
||||
if tokens > account.tokens {
|
||||
if lamports > account.lamports {
|
||||
return Err(BankError::InsufficientFundsForFee);
|
||||
}
|
||||
|
||||
account.tokens -= tokens;
|
||||
account.lamports -= lamports;
|
||||
self.accounts()
|
||||
.store_slow(self.accounts_id, pubkey, &account);
|
||||
Ok(())
|
||||
|
@ -696,9 +699,9 @@ impl Bank {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn deposit(&self, pubkey: &Pubkey, tokens: u64) {
|
||||
pub fn deposit(&self, pubkey: &Pubkey, lamports: u64) {
|
||||
let mut account = self.get_account(pubkey).unwrap_or_default();
|
||||
account.tokens += tokens;
|
||||
account.lamports += lamports;
|
||||
self.accounts()
|
||||
.store_slow(self.accounts_id, pubkey, &account);
|
||||
}
|
||||
|
@ -798,7 +801,7 @@ mod tests {
|
|||
use super::*;
|
||||
use bincode::serialize;
|
||||
use hashbrown::HashSet;
|
||||
use solana_sdk::genesis_block::{GenesisBlock, BOOTSTRAP_LEADER_TOKENS};
|
||||
use solana_sdk::genesis_block::{GenesisBlock, BOOTSTRAP_LEADER_LAMPORTS};
|
||||
use solana_sdk::native_program::ProgramError;
|
||||
use solana_sdk::signature::{Keypair, KeypairUtil};
|
||||
use solana_sdk::system_instruction::SystemInstruction;
|
||||
|
@ -815,18 +818,21 @@ mod tests {
|
|||
#[test]
|
||||
fn test_bank_new_with_leader() {
|
||||
let dummy_leader_id = Keypair::new().pubkey();
|
||||
let dummy_leader_tokens = BOOTSTRAP_LEADER_TOKENS;
|
||||
let dummy_leader_lamports = BOOTSTRAP_LEADER_LAMPORTS;
|
||||
let (genesis_block, _) =
|
||||
GenesisBlock::new_with_leader(10_000, dummy_leader_id, dummy_leader_tokens);
|
||||
assert_eq!(genesis_block.bootstrap_leader_tokens, dummy_leader_tokens);
|
||||
GenesisBlock::new_with_leader(10_000, dummy_leader_id, dummy_leader_lamports);
|
||||
assert_eq!(
|
||||
genesis_block.bootstrap_leader_lamports,
|
||||
dummy_leader_lamports
|
||||
);
|
||||
let bank = Bank::new(&genesis_block);
|
||||
assert_eq!(
|
||||
bank.get_balance(&genesis_block.mint_id),
|
||||
10_000 - dummy_leader_tokens
|
||||
10_000 - dummy_leader_lamports
|
||||
);
|
||||
assert_eq!(
|
||||
bank.get_balance(&dummy_leader_id),
|
||||
dummy_leader_tokens - 1 /* 1 token goes to the vote account associated with dummy_leader_tokens */
|
||||
dummy_leader_lamports - 1 /* 1 token goes to the vote account associated with dummy_leader_lamports */
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -878,7 +884,7 @@ mod tests {
|
|||
let key1 = Keypair::new().pubkey();
|
||||
let key2 = Keypair::new().pubkey();
|
||||
let bank = Bank::new(&genesis_block);
|
||||
let spend = SystemInstruction::Move { tokens: 1 };
|
||||
let spend = SystemInstruction::Move { lamports: 1 };
|
||||
let instructions = vec![
|
||||
Instruction {
|
||||
program_ids_index: 0,
|
||||
|
@ -909,7 +915,7 @@ mod tests {
|
|||
bank.get_signature_status(&t1.signatures[0]),
|
||||
Some(Err(BankError::ProgramError(
|
||||
1,
|
||||
ProgramError::ResultWithNegativeTokens
|
||||
ProgramError::ResultWithNegativeLamports
|
||||
)))
|
||||
);
|
||||
}
|
||||
|
@ -957,11 +963,11 @@ mod tests {
|
|||
bank.process_transaction(&tx),
|
||||
Err(BankError::ProgramError(
|
||||
0,
|
||||
ProgramError::ResultWithNegativeTokens
|
||||
ProgramError::ResultWithNegativeLamports
|
||||
))
|
||||
);
|
||||
|
||||
// The tokens didn't move, but the from address paid the transaction fee.
|
||||
// The lamports didn't move, but the from address paid the transaction fee.
|
||||
assert_eq!(bank.get_balance(&dest.pubkey()), 0);
|
||||
|
||||
// This should be the original balance minus the transaction fee.
|
||||
|
@ -993,7 +999,7 @@ mod tests {
|
|||
bank.transfer(10_001, &mint_keypair, pubkey, genesis_block.hash()),
|
||||
Err(BankError::ProgramError(
|
||||
0,
|
||||
ProgramError::ResultWithNegativeTokens
|
||||
ProgramError::ResultWithNegativeLamports
|
||||
))
|
||||
);
|
||||
assert_eq!(bank.transaction_count(), 1);
|
||||
|
@ -1094,7 +1100,7 @@ mod tests {
|
|||
Ok(()),
|
||||
Err(BankError::ProgramError(
|
||||
1,
|
||||
ProgramError::ResultWithNegativeTokens,
|
||||
ProgramError::ResultWithNegativeLamports,
|
||||
)),
|
||||
];
|
||||
|
||||
|
@ -1135,9 +1141,9 @@ mod tests {
|
|||
#[test]
|
||||
fn test_process_genesis() {
|
||||
let dummy_leader_id = Keypair::new().pubkey();
|
||||
let dummy_leader_tokens = 3;
|
||||
let dummy_leader_lamports = 3;
|
||||
let (genesis_block, _) =
|
||||
GenesisBlock::new_with_leader(5, dummy_leader_id, dummy_leader_tokens);
|
||||
GenesisBlock::new_with_leader(5, dummy_leader_id, dummy_leader_lamports);
|
||||
let bank = Bank::new(&genesis_block);
|
||||
assert_eq!(bank.get_balance(&genesis_block.mint_id), 2);
|
||||
assert_eq!(bank.get_balance(&dummy_leader_id), 2);
|
||||
|
@ -1418,8 +1424,8 @@ mod tests {
|
|||
#[test]
|
||||
fn test_bank_epoch_vote_accounts() {
|
||||
let leader_id = Keypair::new().pubkey();
|
||||
let leader_tokens = 3;
|
||||
let (mut genesis_block, _) = GenesisBlock::new_with_leader(5, leader_id, leader_tokens);
|
||||
let leader_lamports = 3;
|
||||
let (mut genesis_block, _) = GenesisBlock::new_with_leader(5, leader_id, leader_lamports);
|
||||
|
||||
// set this up weird, forces:
|
||||
// 1. genesis bank to cover epochs 0, 1, *and* 2
|
||||
|
@ -1485,13 +1491,13 @@ mod tests {
|
|||
let bank = Arc::new(Bank::new(&genesis_block));
|
||||
let key = Keypair::new();
|
||||
|
||||
let move_tokens = SystemInstruction::Move { tokens: 1 };
|
||||
let move_lamports = SystemInstruction::Move { lamports: 1 };
|
||||
|
||||
let mut tx = Transaction::new_unsigned(
|
||||
&mint_keypair.pubkey(),
|
||||
&[key.pubkey()],
|
||||
system_program::id(),
|
||||
&move_tokens,
|
||||
&move_lamports,
|
||||
bank.last_blockhash(),
|
||||
2,
|
||||
);
|
||||
|
|
|
@ -57,7 +57,7 @@ fn process_instruction(
|
|||
fn verify_instruction(
|
||||
program_id: &Pubkey,
|
||||
pre_program_id: &Pubkey,
|
||||
pre_tokens: u64,
|
||||
pre_lamports: u64,
|
||||
pre_userdata: &[u8],
|
||||
account: &Account,
|
||||
) -> Result<(), ProgramError> {
|
||||
|
@ -68,8 +68,8 @@ fn verify_instruction(
|
|||
return Err(ProgramError::ModifiedProgramId);
|
||||
}
|
||||
// For accounts unassigned to the program, the individual balance of each accounts cannot decrease.
|
||||
if *program_id != account.owner && pre_tokens > account.tokens {
|
||||
return Err(ProgramError::ExternalAccountTokenSpend);
|
||||
if *program_id != account.owner && pre_lamports > account.lamports {
|
||||
return Err(ProgramError::ExternalAccountLamportSpend);
|
||||
}
|
||||
// For accounts unassigned to the program, the userdata may not change.
|
||||
if *program_id != account.owner
|
||||
|
@ -95,10 +95,10 @@ fn execute_instruction(
|
|||
let program_id = tx.program_id(instruction_index);
|
||||
// TODO: the runtime should be checking read/write access to memory
|
||||
// we are trusting the hard-coded programs not to clobber or allocate
|
||||
let pre_total: u64 = program_accounts.iter().map(|a| a.tokens).sum();
|
||||
let pre_total: u64 = program_accounts.iter().map(|a| a.lamports).sum();
|
||||
let pre_data: Vec<_> = program_accounts
|
||||
.iter_mut()
|
||||
.map(|a| (a.owner, a.tokens, a.userdata.clone()))
|
||||
.map(|a| (a.owner, a.lamports, a.userdata.clone()))
|
||||
.collect();
|
||||
|
||||
process_instruction(
|
||||
|
@ -110,19 +110,19 @@ fn execute_instruction(
|
|||
)?;
|
||||
|
||||
// Verify the instruction
|
||||
for ((pre_program_id, pre_tokens, pre_userdata), post_account) in
|
||||
for ((pre_program_id, pre_lamports, pre_userdata), post_account) in
|
||||
pre_data.iter().zip(program_accounts.iter())
|
||||
{
|
||||
verify_instruction(
|
||||
&program_id,
|
||||
pre_program_id,
|
||||
*pre_tokens,
|
||||
*pre_lamports,
|
||||
pre_userdata,
|
||||
post_account,
|
||||
)?;
|
||||
}
|
||||
// The total sum of all the tokens in all the accounts cannot change.
|
||||
let post_total: u64 = program_accounts.iter().map(|a| a.tokens).sum();
|
||||
// The total sum of all the lamports in all the accounts cannot change.
|
||||
let post_total: u64 = program_accounts.iter().map(|a| a.lamports).sum();
|
||||
if pre_total != post_total {
|
||||
return Err(ProgramError::UnbalancedInstruction);
|
||||
}
|
||||
|
|
|
@ -5,8 +5,8 @@ use std::{cmp, fmt};
|
|||
#[repr(C)]
|
||||
#[derive(Serialize, Deserialize, Clone, Default, Eq, PartialEq)]
|
||||
pub struct Account {
|
||||
/// tokens in the account
|
||||
pub tokens: u64,
|
||||
/// lamports in the account
|
||||
pub lamports: u64,
|
||||
/// data held in this account
|
||||
pub userdata: Vec<u8>,
|
||||
/// the program that owns this account. If executable, the program that loads this account.
|
||||
|
@ -28,8 +28,8 @@ impl fmt::Debug for Account {
|
|||
};
|
||||
write!(
|
||||
f,
|
||||
"Account {{ tokens: {} userdata.len: {} owner: {} executable: {}{} }}",
|
||||
self.tokens,
|
||||
"Account {{ lamports: {} userdata.len: {} owner: {} executable: {}{} }}",
|
||||
self.lamports,
|
||||
self.userdata.len(),
|
||||
self.owner,
|
||||
self.executable,
|
||||
|
@ -40,9 +40,9 @@ impl fmt::Debug for Account {
|
|||
|
||||
impl Account {
|
||||
// TODO do we want to add executable and leader_owner even though they should always be false/default?
|
||||
pub fn new(tokens: u64, space: usize, owner: Pubkey) -> Account {
|
||||
pub fn new(lamports: u64, space: usize, owner: Pubkey) -> Account {
|
||||
Account {
|
||||
tokens,
|
||||
lamports,
|
||||
userdata: vec![0u8; space],
|
||||
owner,
|
||||
executable: false,
|
||||
|
|
|
@ -8,18 +8,18 @@ use std::fs::File;
|
|||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
|
||||
// The default (and minimal) amount of tokens given to the bootstrap leader:
|
||||
// * 2 tokens for the bootstrap leader ID account to later setup another vote account
|
||||
// * 1 token for the bootstrap leader vote account
|
||||
pub const BOOTSTRAP_LEADER_TOKENS: u64 = 3;
|
||||
// The default (and minimal) amount of lamports given to the bootstrap leader:
|
||||
// * 2 lamports for the bootstrap leader ID account to later setup another vote account
|
||||
// * 1 lamport for the bootstrap leader vote account
|
||||
pub const BOOTSTRAP_LEADER_LAMPORTS: u64 = 3;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct GenesisBlock {
|
||||
pub bootstrap_leader_id: Pubkey,
|
||||
pub bootstrap_leader_tokens: u64,
|
||||
pub bootstrap_leader_lamports: u64,
|
||||
pub bootstrap_leader_vote_account_id: Pubkey,
|
||||
pub mint_id: Pubkey,
|
||||
pub tokens: u64,
|
||||
pub lamports: u64,
|
||||
pub ticks_per_slot: u64,
|
||||
pub slots_per_epoch: u64,
|
||||
pub stakers_slot_offset: u64,
|
||||
|
@ -27,27 +27,27 @@ pub struct GenesisBlock {
|
|||
|
||||
impl GenesisBlock {
|
||||
#[allow(clippy::new_ret_no_self)]
|
||||
pub fn new(tokens: u64) -> (Self, Keypair) {
|
||||
let tokens = tokens
|
||||
.checked_add(BOOTSTRAP_LEADER_TOKENS)
|
||||
.unwrap_or(tokens);
|
||||
Self::new_with_leader(tokens, Keypair::new().pubkey(), BOOTSTRAP_LEADER_TOKENS)
|
||||
pub fn new(lamports: u64) -> (Self, Keypair) {
|
||||
let lamports = lamports
|
||||
.checked_add(BOOTSTRAP_LEADER_LAMPORTS)
|
||||
.unwrap_or(lamports);
|
||||
Self::new_with_leader(lamports, Keypair::new().pubkey(), BOOTSTRAP_LEADER_LAMPORTS)
|
||||
}
|
||||
|
||||
pub fn new_with_leader(
|
||||
tokens: u64,
|
||||
lamports: u64,
|
||||
bootstrap_leader_id: Pubkey,
|
||||
bootstrap_leader_tokens: u64,
|
||||
bootstrap_leader_lamports: u64,
|
||||
) -> (Self, Keypair) {
|
||||
let mint_keypair = Keypair::new();
|
||||
let bootstrap_leader_vote_account_keypair = Keypair::new();
|
||||
(
|
||||
Self {
|
||||
bootstrap_leader_id,
|
||||
bootstrap_leader_tokens,
|
||||
bootstrap_leader_lamports,
|
||||
bootstrap_leader_vote_account_id: bootstrap_leader_vote_account_keypair.pubkey(),
|
||||
mint_id: mint_keypair.pubkey(),
|
||||
tokens,
|
||||
lamports,
|
||||
ticks_per_slot: DEFAULT_TICKS_PER_SLOT,
|
||||
slots_per_epoch: DEFAULT_SLOTS_PER_EPOCH,
|
||||
stakers_slot_offset: DEFAULT_SLOTS_PER_EPOCH,
|
||||
|
@ -81,13 +81,13 @@ mod tests {
|
|||
#[test]
|
||||
fn test_genesis_block_new() {
|
||||
let (genesis_block, mint) = GenesisBlock::new(10_000);
|
||||
assert_eq!(genesis_block.tokens, 10_000 + BOOTSTRAP_LEADER_TOKENS);
|
||||
assert_eq!(genesis_block.lamports, 10_000 + BOOTSTRAP_LEADER_LAMPORTS);
|
||||
assert_eq!(genesis_block.mint_id, mint.pubkey());
|
||||
assert!(genesis_block.bootstrap_leader_id != Pubkey::default());
|
||||
assert!(genesis_block.bootstrap_leader_vote_account_id != Pubkey::default());
|
||||
assert_eq!(
|
||||
genesis_block.bootstrap_leader_tokens,
|
||||
BOOTSTRAP_LEADER_TOKENS
|
||||
genesis_block.bootstrap_leader_lamports,
|
||||
BOOTSTRAP_LEADER_LAMPORTS
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -97,9 +97,9 @@ mod tests {
|
|||
let (genesis_block, mint) =
|
||||
GenesisBlock::new_with_leader(20_000, leader_keypair.pubkey(), 123);
|
||||
|
||||
assert_eq!(genesis_block.tokens, 20_000);
|
||||
assert_eq!(genesis_block.lamports, 20_000);
|
||||
assert_eq!(genesis_block.mint_id, mint.pubkey());
|
||||
assert_eq!(genesis_block.bootstrap_leader_id, leader_keypair.pubkey());
|
||||
assert_eq!(genesis_block.bootstrap_leader_tokens, 123);
|
||||
assert_eq!(genesis_block.bootstrap_leader_lamports, 123);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ pub fn check_id(program_id: &Pubkey) -> bool {
|
|||
/// Create an executable account with the given shared object name.
|
||||
pub fn create_program_account(name: &str) -> Account {
|
||||
Account {
|
||||
tokens: 1,
|
||||
lamports: 1,
|
||||
owner: id(),
|
||||
userdata: name.as_bytes().to_vec(),
|
||||
executable: true,
|
||||
|
|
|
@ -14,16 +14,16 @@ pub enum ProgramError {
|
|||
/// An instruction resulted in an account with a negative balance
|
||||
/// The difference from InsufficientFundsForFee is that the transaction was executed by the
|
||||
/// contract
|
||||
ResultWithNegativeTokens,
|
||||
ResultWithNegativeLamports,
|
||||
|
||||
/// Program's instruction token balance does not equal the balance after the instruction
|
||||
/// Program's instruction lamport balance does not equal the balance after the instruction
|
||||
UnbalancedInstruction,
|
||||
|
||||
/// Program modified an account's program id
|
||||
ModifiedProgramId,
|
||||
|
||||
/// Program spent the tokens of an account that doesn't belong to it
|
||||
ExternalAccountTokenSpend,
|
||||
/// Program spent the lamports of an account that doesn't belong to it
|
||||
ExternalAccountLamportSpend,
|
||||
|
||||
/// Program modified the userdata of an account that doesn't belong to it
|
||||
ExternalAccountUserdataModified,
|
||||
|
|
|
@ -7,35 +7,35 @@ pub enum SystemInstruction {
|
|||
/// Create a new account
|
||||
/// * Transaction::keys[0] - source
|
||||
/// * Transaction::keys[1] - new account key
|
||||
/// * tokens - number of tokens to transfer to the new account
|
||||
/// * lamports - number of lamports to transfer to the new account
|
||||
/// * space - memory to allocate if greater then zero
|
||||
/// * program_id - the program id of the new account
|
||||
CreateAccount {
|
||||
tokens: u64,
|
||||
lamports: u64,
|
||||
space: u64,
|
||||
program_id: Pubkey,
|
||||
},
|
||||
/// Assign account to a program
|
||||
/// * Transaction::keys[0] - account to assign
|
||||
Assign { program_id: Pubkey },
|
||||
/// Move tokens
|
||||
/// Move lamports
|
||||
/// * Transaction::keys[0] - source
|
||||
/// * Transaction::keys[1] - destination
|
||||
Move { tokens: u64 },
|
||||
Move { lamports: u64 },
|
||||
}
|
||||
|
||||
impl SystemInstruction {
|
||||
pub fn new_program_account(
|
||||
from_id: Pubkey,
|
||||
to_id: Pubkey,
|
||||
tokens: u64,
|
||||
lamports: u64,
|
||||
space: u64,
|
||||
program_id: Pubkey,
|
||||
) -> BuilderInstruction {
|
||||
BuilderInstruction::new(
|
||||
system_program::id(),
|
||||
&SystemInstruction::CreateAccount {
|
||||
tokens,
|
||||
lamports,
|
||||
space,
|
||||
program_id,
|
||||
},
|
||||
|
@ -43,10 +43,10 @@ impl SystemInstruction {
|
|||
)
|
||||
}
|
||||
|
||||
pub fn new_move(from_id: Pubkey, to_id: Pubkey, tokens: u64) -> BuilderInstruction {
|
||||
pub fn new_move(from_id: Pubkey, to_id: Pubkey, lamports: u64) -> BuilderInstruction {
|
||||
BuilderInstruction::new(
|
||||
system_program::id(),
|
||||
&SystemInstruction::Move { tokens },
|
||||
&SystemInstruction::Move { lamports },
|
||||
vec![(from_id, true), (to_id, false)],
|
||||
)
|
||||
}
|
||||
|
|
|
@ -15,13 +15,13 @@ impl SystemTransaction {
|
|||
from_keypair: &Keypair,
|
||||
to: Pubkey,
|
||||
recent_blockhash: Hash,
|
||||
tokens: u64,
|
||||
lamports: u64,
|
||||
space: u64,
|
||||
program_id: Pubkey,
|
||||
fee: u64,
|
||||
) -> Transaction {
|
||||
let create = SystemInstruction::CreateAccount {
|
||||
tokens, //TODO, the tokens to allocate might need to be higher then 0 in the future
|
||||
lamports, //TODO, the lamports to allocate might need to be higher then 0 in the future
|
||||
space,
|
||||
program_id,
|
||||
};
|
||||
|
@ -39,7 +39,7 @@ impl SystemTransaction {
|
|||
pub fn new_account(
|
||||
from_keypair: &Keypair,
|
||||
to: Pubkey,
|
||||
tokens: u64,
|
||||
lamports: u64,
|
||||
recent_blockhash: Hash,
|
||||
fee: u64,
|
||||
) -> Transaction {
|
||||
|
@ -48,7 +48,7 @@ impl SystemTransaction {
|
|||
from_keypair,
|
||||
to,
|
||||
recent_blockhash,
|
||||
tokens,
|
||||
lamports,
|
||||
0,
|
||||
program_id,
|
||||
fee,
|
||||
|
@ -75,16 +75,16 @@ impl SystemTransaction {
|
|||
pub fn new_move(
|
||||
from_keypair: &Keypair,
|
||||
to: Pubkey,
|
||||
tokens: u64,
|
||||
lamports: u64,
|
||||
recent_blockhash: Hash,
|
||||
fee: u64,
|
||||
) -> Transaction {
|
||||
let move_tokens = SystemInstruction::Move { tokens };
|
||||
let move_lamports = SystemInstruction::Move { lamports };
|
||||
Transaction::new(
|
||||
from_keypair,
|
||||
&[to],
|
||||
system_program::id(),
|
||||
&move_tokens,
|
||||
&move_lamports,
|
||||
recent_blockhash,
|
||||
fee,
|
||||
)
|
||||
|
@ -100,7 +100,7 @@ impl SystemTransaction {
|
|||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, (_, amount))| {
|
||||
let spend = SystemInstruction::Move { tokens: *amount };
|
||||
let spend = SystemInstruction::Move { lamports: *amount };
|
||||
Instruction::new(0, &spend, vec![0, i as u8 + 1])
|
||||
})
|
||||
.collect();
|
||||
|
|
|
@ -86,7 +86,7 @@ pub struct Transaction {
|
|||
pub account_keys: Vec<Pubkey>,
|
||||
/// The id of a recent ledger entry.
|
||||
pub recent_blockhash: Hash,
|
||||
/// The number of tokens paid for processing and storing of this transaction.
|
||||
/// The number of lamports paid for processing and storing of this transaction.
|
||||
pub fee: u64,
|
||||
/// All the program id keys used to execute this transaction's instructions
|
||||
pub program_ids: Vec<Pubkey>,
|
||||
|
@ -141,7 +141,7 @@ impl Transaction {
|
|||
/// Create a signed transaction
|
||||
/// * `from_keypair` - The key used to sign the transaction. This key is stored as keys[0]
|
||||
/// * `account_keys` - The keys for the transaction. These are the program state
|
||||
/// instances or token recipient keys.
|
||||
/// instances or lamport recipient keys.
|
||||
/// * `recent_blockhash` - The PoH hash.
|
||||
/// * `fee` - The transaction fee.
|
||||
/// * `program_ids` - The keys that identify programs used in the `instruction` vector.
|
||||
|
|
|
@ -50,7 +50,10 @@ fn test_wallet_deploy_program() {
|
|||
.make_rpc_request(1, RpcRequest::GetAccountInfo, Some(params))
|
||||
.unwrap();
|
||||
let account_info_obj = account_info.as_object().unwrap();
|
||||
assert_eq!(account_info_obj.get("tokens").unwrap().as_u64().unwrap(), 1);
|
||||
assert_eq!(
|
||||
account_info_obj.get("lamports").unwrap().as_u64().unwrap(),
|
||||
1
|
||||
);
|
||||
let owner_array = account_info.get("owner").unwrap();
|
||||
assert_eq!(owner_array, &json!(bpf_loader::id()));
|
||||
assert_eq!(
|
||||
|
|
Loading…
Reference in New Issue