Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add deactivation cooldown before address lookup tables can be closed #22011

Merged
merged 1 commit into from
Dec 20, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 38 additions & 6 deletions programs/address-lookup-table-tests/tests/close_lookup_table_ix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,13 @@ async fn test_close_lookup_table() {
let mut context = setup_test_context().await;
overwrite_slot_hashes_with_slots(&mut context, &[]);

let authority_keypair = Keypair::new();
let initialized_table = new_address_lookup_table(Some(authority_keypair.pubkey()), 0);
let lookup_table_address = Pubkey::new_unique();
let authority_keypair = Keypair::new();
let initialized_table = {
let mut table = new_address_lookup_table(Some(authority_keypair.pubkey()), 0);
table.meta.deactivation_slot = 0;
table
};
add_lookup_table_account(&mut context, lookup_table_address, initialized_table).await;

let client = &mut context.banks_client;
Expand All @@ -49,7 +53,7 @@ async fn test_close_lookup_table() {
}

#[tokio::test]
async fn test_close_lookup_table_too_recent() {
async fn test_close_lookup_table_not_deactivated() {
let mut context = setup_test_context().await;

let authority_keypair = Keypair::new();
Expand All @@ -63,10 +67,38 @@ async fn test_close_lookup_table_too_recent() {
context.payer.pubkey(),
);

// The ix should fail because the table hasn't been deactivated yet
assert_ix_error(
&mut context,
ix,
Some(&authority_keypair),
InstructionError::InvalidArgument,
)
.await;
}

#[tokio::test]
async fn test_close_lookup_table_recently_deactivated() {
let mut context = setup_test_context().await;

let authority_keypair = Keypair::new();
let initialized_table = {
let mut table = new_address_lookup_table(Some(authority_keypair.pubkey()), 0);
table.meta.deactivation_slot = 0;
table
};
let lookup_table_address = Pubkey::new_unique();
add_lookup_table_account(&mut context, lookup_table_address, initialized_table).await;

let ix = close_lookup_table(
lookup_table_address,
authority_keypair.pubkey(),
context.payer.pubkey(),
);

// Context sets up the slot hashes sysvar to have an entry
// for slot 0 which is what the default initialized table
// has as its derivation slot. Because that slot is present,
// the ix should fail.
// for slot 0 which is when the table was deactivated.
// Because that slot is present, the ix should fail.
assert_ix_error(
&mut context,
ix,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ async fn test_create_lookup_table() {
Rent::default().minimum_balance(LOOKUP_TABLE_META_SIZE)
);
let lookup_table = AddressLookupTable::deserialize(&lookup_table_account.data).unwrap();
assert_eq!(lookup_table.meta.derivation_slot, test_recent_slot);
assert_eq!(lookup_table.meta.deactivation_slot, Slot::MAX);
assert_eq!(lookup_table.meta.authority, Some(authority_address));
assert_eq!(lookup_table.meta.last_extended_slot, 0);
assert_eq!(lookup_table.meta.last_extended_slot_start_index, 0);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
use {
assert_matches::assert_matches,
common::{
add_lookup_table_account, assert_ix_error, new_address_lookup_table, setup_test_context,
},
solana_address_lookup_table_program::{
instruction::deactivate_lookup_table, state::AddressLookupTable,
},
solana_program_test::*,
solana_sdk::{
instruction::InstructionError,
pubkey::Pubkey,
signature::{Keypair, Signer},
transaction::Transaction,
},
};

mod common;

#[tokio::test]
async fn test_deactivate_lookup_table() {
let mut context = setup_test_context().await;

let authority = Keypair::new();
let mut initialized_table = new_address_lookup_table(Some(authority.pubkey()), 10);
let lookup_table_address = Pubkey::new_unique();
add_lookup_table_account(
&mut context,
lookup_table_address,
initialized_table.clone(),
)
.await;

let client = &mut context.banks_client;
let payer = &context.payer;
let recent_blockhash = context.last_blockhash;
let transaction = Transaction::new_signed_with_payer(
&[deactivate_lookup_table(
lookup_table_address,
authority.pubkey(),
)],
Some(&payer.pubkey()),
&[payer, &authority],
recent_blockhash,
);

assert_matches!(client.process_transaction(transaction).await, Ok(()));
let table_account = client
.get_account(lookup_table_address)
.await
.unwrap()
.unwrap();
let lookup_table = AddressLookupTable::deserialize(&table_account.data).unwrap();
assert_eq!(lookup_table.meta.deactivation_slot, 1);

// Check that only the deactivation slot changed
initialized_table.meta.deactivation_slot = 1;
assert_eq!(initialized_table, lookup_table);
}

#[tokio::test]
async fn test_deactivate_immutable_lookup_table() {
let mut context = setup_test_context().await;

let initialized_table = new_address_lookup_table(None, 10);
let lookup_table_address = Pubkey::new_unique();
add_lookup_table_account(&mut context, lookup_table_address, initialized_table).await;

let authority = Keypair::new();
let ix = deactivate_lookup_table(lookup_table_address, authority.pubkey());

assert_ix_error(
&mut context,
ix,
Some(&authority),
InstructionError::Immutable,
)
.await;
}

#[tokio::test]
async fn test_deactivate_already_deactivated() {
let mut context = setup_test_context().await;

let authority = Keypair::new();
let initialized_table = {
let mut table = new_address_lookup_table(Some(authority.pubkey()), 0);
table.meta.deactivation_slot = 0;
table
};
let lookup_table_address = Pubkey::new_unique();
add_lookup_table_account(&mut context, lookup_table_address, initialized_table).await;

let ix = deactivate_lookup_table(lookup_table_address, authority.pubkey());

assert_ix_error(
&mut context,
ix,
Some(&authority),
InstructionError::InvalidArgument,
)
.await;
}

#[tokio::test]
async fn test_deactivate_lookup_table_with_wrong_authority() {
let mut context = setup_test_context().await;

let authority = Keypair::new();
let wrong_authority = Keypair::new();
let initialized_table = new_address_lookup_table(Some(authority.pubkey()), 10);
let lookup_table_address = Pubkey::new_unique();
add_lookup_table_account(&mut context, lookup_table_address, initialized_table).await;

let ix = deactivate_lookup_table(lookup_table_address, wrong_authority.pubkey());

assert_ix_error(
&mut context,
ix,
Some(&wrong_authority),
InstructionError::IncorrectAuthority,
)
.await;
}

#[tokio::test]
async fn test_deactivate_lookup_table_without_signing() {
let mut context = setup_test_context().await;

let authority = Keypair::new();
let initialized_table = new_address_lookup_table(Some(authority.pubkey()), 10);
let lookup_table_address = Pubkey::new_unique();
add_lookup_table_account(&mut context, lookup_table_address, initialized_table).await;

let mut ix = deactivate_lookup_table(lookup_table_address, authority.pubkey());
ix.accounts[1].is_signer = false;

assert_ix_error(
&mut context,
ix,
None,
InstructionError::MissingRequiredSignature,
)
.await;
}
Loading