chore: agave 2.x validator in sealevel e2e (#4643)

### Description

Solana Mainnet is hard forking in 1-2 weeks and one of the RPC methods
we were using will be removed.

This PR updates that RPC and runs e2e with an agave `v2.x` network to
ensure compatibility. As in the [svm warp route
guide](https://docs.hyperlane.xyz/docs/guides/deploy-svm-warp-route), we
still use `v1.14.x` to compile programs.

More details:
- `v2.0` migration
[guide](https://github.com/anza-xyz/agave/wiki/Agave-v2.0-Transition-Guide)
- `v2.0` release
[schedule](https://github.com/anza-xyz/agave/wiki/v2.0-Release-Schedule)
- `solana` to `agave` client transition
[guide](https://github.com/anza-xyz/agave/wiki/Agave-Transition)

### Drive-by changes

The solana cli installer logic in e2e is parameterized with `version`
and `url`

### Backward compatibility

Yes - no dependency upgrade was needed to switch to the new rpc method

### Testing

E2E for general network compatiblity. The Jito submission retry logic
(where the new rpc is used) wasn't tested - I'm confident it works but
this is non-critical, as failed submission will eventually end up in the
prep queue again
pull/4655/head
Daniel Savu 1 month ago committed by GitHub
parent ed77033979
commit ad4d61f962
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 15
      rust/main/chains/hyperlane-sealevel/src/mailbox.rs
  2. 16
      rust/main/utils/run-locally/src/main.rs
  3. 25
      rust/main/utils/run-locally/src/solana.rs
  4. 6
      rust/sealevel/client/src/cmd_utils.rs
  5. 3
      rust/sealevel/client/src/main.rs

@ -33,6 +33,7 @@ use solana_client::{
rpc_client::SerializableTransaction, rpc_client::SerializableTransaction,
rpc_config::{RpcAccountInfoConfig, RpcProgramAccountsConfig, RpcSendTransactionConfig}, rpc_config::{RpcAccountInfoConfig, RpcProgramAccountsConfig, RpcSendTransactionConfig},
rpc_filter::{Memcmp, MemcmpEncodedBytes, RpcFilterType}, rpc_filter::{Memcmp, MemcmpEncodedBytes, RpcFilterType},
rpc_response::Response,
}; };
use solana_sdk::{ use solana_sdk::{
account::Account, account::Account,
@ -48,7 +49,7 @@ use solana_sdk::{
transaction::{Transaction, VersionedTransaction}, transaction::{Transaction, VersionedTransaction},
}; };
use solana_transaction_status::{ use solana_transaction_status::{
EncodedConfirmedBlock, EncodedTransaction, EncodedTransactionWithStatusMeta, EncodedConfirmedBlock, EncodedTransaction, EncodedTransactionWithStatusMeta, TransactionStatus,
UiInnerInstructions, UiInstruction, UiMessage, UiParsedInstruction, UiReturnDataEncoding, UiInnerInstructions, UiInstruction, UiMessage, UiParsedInstruction, UiReturnDataEncoding,
UiTransaction, UiTransactionReturnData, UiTransactionStatusMeta, UiTransaction, UiTransactionReturnData, UiTransactionStatusMeta,
}; };
@ -354,15 +355,15 @@ impl SealevelMailbox {
}; };
for status_retry in 0..GET_STATUS_RETRIES { for status_retry in 0..GET_STATUS_RETRIES {
match self let signature_statuses: Response<Vec<Option<TransactionStatus>>> = self
.provider .provider
.rpc() .rpc()
.get_signature_status(&signature) .get_signature_statuses(&[*signature])
.await .await
.map_err(ChainCommunicationError::from_other)? .map_err(ChainCommunicationError::from_other)?;
{ let signature_status = signature_statuses.value.first().cloned().flatten();
Some(Ok(_)) => return Ok(*signature), match signature_status {
Some(Err(e)) => return Err(ChainCommunicationError::from_other(e)), Some(_) => return Ok(*signature),
None => { None => {
if !self if !self
.provider .provider

@ -313,7 +313,11 @@ fn main() -> ExitCode {
// //
let solana_paths = if config.sealevel_enabled { let solana_paths = if config.sealevel_enabled {
let (solana_path, solana_path_tempdir) = install_solana_cli_tools().join(); let (solana_path, solana_path_tempdir) = install_solana_cli_tools(
SOLANA_CONTRACTS_CLI_RELEASE_URL.to_owned(),
SOLANA_CONTRACTS_CLI_VERSION.to_owned(),
)
.join();
state.data.push(Box::new(solana_path_tempdir)); state.data.push(Box::new(solana_path_tempdir));
let solana_program_builder = build_solana_programs(solana_path.clone()); let solana_program_builder = build_solana_programs(solana_path.clone());
Some((solana_program_builder.join(), solana_path)) Some((solana_program_builder.join(), solana_path))
@ -358,8 +362,14 @@ fn main() -> ExitCode {
} }
let solana_ledger_dir = tempdir().unwrap(); let solana_ledger_dir = tempdir().unwrap();
let solana_config_path = if let Some((solana_program_path, solana_path)) = solana_paths.clone() let solana_config_path = if let Some((solana_program_path, _)) = solana_paths.clone() {
{ // use the agave 2.x validator version to ensure mainnet compatibility
let (solana_path, solana_path_tempdir) = install_solana_cli_tools(
SOLANA_NETWORK_CLI_RELEASE_URL.to_owned(),
SOLANA_NETWORK_CLI_VERSION.to_owned(),
)
.join();
state.data.push(Box::new(solana_path_tempdir));
let start_solana_validator = start_solana_test_validator( let start_solana_validator = start_solana_test_validator(
solana_path.clone(), solana_path.clone(),
solana_program_path, solana_program_path,

@ -13,8 +13,14 @@ use crate::program::Program;
use crate::utils::{as_task, concat_path, AgentHandles, ArbitraryData, TaskHandle}; use crate::utils::{as_task, concat_path, AgentHandles, ArbitraryData, TaskHandle};
use crate::SOLANA_AGNET_BIN_PATH; use crate::SOLANA_AGNET_BIN_PATH;
/// The Solana CLI tool version to download and use. /// Solana CLI version for compiling programs
const SOLANA_CLI_VERSION: &str = "1.14.20"; pub const SOLANA_CONTRACTS_CLI_VERSION: &str = "1.14.20";
pub const SOLANA_CONTRACTS_CLI_RELEASE_URL: &str = "github.com/solana-labs/solana";
/// Solana version used by mainnet validators
pub const SOLANA_NETWORK_CLI_VERSION: &str = "2.0.13";
pub const SOLANA_NETWORK_CLI_RELEASE_URL: &str = "github.com/anza-xyz/agave";
const SOLANA_PROGRAM_LIBRARY_ARCHIVE: &str = const SOLANA_PROGRAM_LIBRARY_ARCHIVE: &str =
"https://github.com/hyperlane-xyz/solana-program-library/releases/download/2024-08-23/spl.tar.gz"; "https://github.com/hyperlane-xyz/solana-program-library/releases/download/2024-08-23/spl.tar.gz";
@ -71,10 +77,17 @@ const SOLANA_OVERHEAD_CONFIG_FILE: &str = "../sealevel/environments/local-e2e/ov
// Install the CLI tools and return the path to the bin dir. // Install the CLI tools and return the path to the bin dir.
#[apply(as_task)] #[apply(as_task)]
pub fn install_solana_cli_tools() -> (PathBuf, impl ArbitraryData) { pub fn install_solana_cli_tools(
release_url: String,
release_version: String,
) -> (PathBuf, impl ArbitraryData) {
let solana_download_dir = tempdir().unwrap(); let solana_download_dir = tempdir().unwrap();
let solana_tools_dir = tempdir().unwrap(); let solana_tools_dir = tempdir().unwrap();
log!("Downloading solana cli release v{}", SOLANA_CLI_VERSION); log!(
"Downloading solana cli release v{} from {}",
release_version,
release_url
);
let solana_release_name = { let solana_release_name = {
// best effort to pick one of the supported targets // best effort to pick one of the supported targets
let target = if cfg!(target_os = "linux") { let target = if cfg!(target_os = "linux") {
@ -97,7 +110,9 @@ pub fn install_solana_cli_tools() -> (PathBuf, impl ArbitraryData) {
Program::new("curl") Program::new("curl")
.arg("output", &solana_archive_name) .arg("output", &solana_archive_name)
.flag("location") .flag("location")
.cmd(format!("https://github.com/solana-labs/solana/releases/download/v{SOLANA_CLI_VERSION}/{solana_archive_name}")) .cmd(format!(
"https://{release_url}/releases/download/v{release_version}/{solana_archive_name}"
))
.flag("silent") .flag("silent")
.working_dir(solana_download_dir.as_ref().to_str().unwrap()) .working_dir(solana_download_dir.as_ref().to_str().unwrap())
.run() .run()

@ -4,6 +4,8 @@ use std::{
io::Write, io::Write,
path::{Path, PathBuf}, path::{Path, PathBuf},
process::{Command, Stdio}, process::{Command, Stdio},
thread::sleep,
time::Duration,
}; };
use solana_client::{client_error::ClientError, rpc_client::RpcClient}; use solana_client::{client_error::ClientError, rpc_client::RpcClient};
@ -77,6 +79,10 @@ pub(crate) fn deploy_program(
} }
build_cmd(command.as_slice(), None, None); build_cmd(command.as_slice(), None, None);
// TODO: use commitment level instead of just sleeping here?
println!("Sleeping for 2 seconds to allow program to be deployed");
sleep(Duration::from_secs(2));
} }
pub(crate) fn create_new_directory(parent_dir: &Path, name: &str) -> PathBuf { pub(crate) fn create_new_directory(parent_dir: &Path, name: &str) -> PathBuf {

@ -895,7 +895,7 @@ fn process_mailbox_cmd(ctx: Context, cmd: MailboxCmd) {
}; };
} }
fn process_token_cmd(ctx: Context, cmd: TokenCmd) { fn process_token_cmd(mut ctx: Context, cmd: TokenCmd) {
match cmd.cmd { match cmd.cmd {
TokenSubCmd::Query(query) => { TokenSubCmd::Query(query) => {
let (token_account, token_bump) = let (token_account, token_bump) =
@ -1024,6 +1024,7 @@ fn process_token_cmd(ctx: Context, cmd: TokenCmd) {
} }
TokenSubCmd::TransferRemote(xfer) => { TokenSubCmd::TransferRemote(xfer) => {
is_keypair(&xfer.sender).unwrap(); is_keypair(&xfer.sender).unwrap();
ctx.commitment = CommitmentConfig::finalized();
let sender = read_keypair_file(xfer.sender).unwrap(); let sender = read_keypair_file(xfer.sender).unwrap();
let recipient = if xfer.recipient.starts_with("0x") { let recipient = if xfer.recipient.starts_with("0x") {

Loading…
Cancel
Save