Skip to content

Commit 4aad047

Browse files
feat(cli): add surfpool config and integration (#3)
* wip * refactor: Simplify Surfpool configuration and enhance validator argument handling - Removed the SurfpoolConfig struct and related logic, simplifying the ValidatorType enum. - Updated the command processing to accept additional arguments for the validator. - Adjusted the localnet and test functions to handle Surfpool and Solana validators more effectively. - Improved logging management for Surfpool validator. * feat(cli): Enhance argument handling for Surfpool validator - Added support for additional arguments to be passed to the test runner and validator. - Updated command definitions to include `--args` and `--validator-args` options. - Improved handling of validator arguments in the `test` and `localnet` functions. - Ensured proper routing of arguments to Surfpool when no explicit validator arguments are provided. * refactor(cli): Update ValidatorType enum and streamline argument handling * feat(cli): Introduce Surfpool configuration with validator integration * feat(cli): enable tui startup to localnet and fix some typos * feat(cli): add runbooks startup check to wait for the deployment of the program then run the tests against the local environment * chore: remove debug print * refactor(cli): change flags to be compatible with surfpool cli, add the runbooks serialization struct to make a more robust verification when waiting for runbooks * fix(cli): Improve runbook execution handling to consider failures as completed * clean up runbook execution checking logic * augment surfpool config fields * remove `SURFPOOL_RPC_URL` const * `remote_rpc_url` -> `datasource_rpc_url` * use `DEFAULT_RPC_PORT` const * fix surfpool command * add/use workflow to install surfpool * specify surfpool cli version for CI * disable surfpool logs by default; allow configuring in anchor.toml * add timeout_minutes to setup surfpool * clean up action * allow too many arguments for localnet fn * bump surfpool version for CI * start surfpool instead of validator in ci * update run-test.sh * fix setup-surfpool cache * add `.surfpool` folder to gitignore for `anchor init` * fix: apply `--offline` flag by default for surfpool * only print message about surfpool logs if logs created * feat: add block production mode to Surfpool configuration * bump surfpool versions in CI * feat: add block production mode to surfpool config for ido-pool test * feat: add sleep functionality to log tests for improved reliability * fix: update program log messages to use dynamic identifiers for better clarity * fix: skip mut error test until LiteSVM issue is resolved * fix: update surfpool CLI version to 0.11.2 in workflow files * fix: refactor testValidateAssociatedToken calls to use confirmed commitment * fix: add surfpool block production mode configuration for errors test * fix: start surfpool in daemon mode for client/example test * fix: add block production mode configuration for surfpool for misc * lint * fix: add setup step for surfpool in reusable tests workflow * add sleep in run-test.sh to execute runbooks * disable check_surfpool call in run-test.sh --------- Co-authored-by: MicaiahReid <[email protected]>
1 parent 5da4d6a commit 4aad047

File tree

17 files changed

+635
-100
lines changed

17 files changed

+635
-100
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
name: "Setup Surfpool"
2+
description: "Installs and caches the Surfpool CLI"
3+
runs:
4+
using: "composite"
5+
steps:
6+
- uses: actions/cache@v3
7+
name: Cache Surfpool Binary
8+
id: cache-surfpool
9+
with:
10+
path: /usr/local/bin/surfpool
11+
key: surfpool-${{ runner.os }}-v${{ env.SURFPOOL_CLI_VERSION }}
12+
13+
- uses: nick-fields/retry@v2
14+
if: steps.cache-surfpool.outputs.cache-hit != 'true'
15+
with:
16+
retry_wait_seconds: 300
17+
timeout_minutes: 2
18+
max_attempts: 10
19+
retry_on: error
20+
shell: bash
21+
command: |
22+
echo "Installing Surfpool version ${{ env.SURFPOOL_CLI_VERSION }}"
23+
curl -sL https://run.surfpool.run/ | sudo bash
24+

.github/workflows/no-caching-tests.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,4 @@ jobs:
1717
node_version: 20.18.0
1818
cargo_profile: release
1919
anchor_binary_name: anchor-binary-no-caching
20+
surfpool_cli_version: 0.11.2

.github/workflows/reusable-tests.yaml

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,16 @@ on:
1818
anchor_binary_name:
1919
required: true
2020
type: string
21+
surfpool_cli_version:
22+
required: true
23+
type: string
2124
env:
2225
CACHE: ${{ inputs.cache }}
2326
SOLANA_CLI_VERSION: ${{ inputs.solana_cli_version }}
2427
NODE_VERSION: ${{ inputs.node_version }}
2528
CARGO_PROFILE: ${{ inputs.cargo_profile }}
2629
ANCHOR_BINARY_NAME: ${{ inputs.anchor_binary_name }}
30+
SURFPOOL_CLI_VERSION: ${{ inputs.surfpool_cli_version }}
2731
CARGO_CACHE_PATH: |
2832
~/.cargo/bin/
2933
~/.cargo/registry/index/
@@ -111,6 +115,7 @@ jobs:
111115
- uses: ./.github/actions/setup/
112116
- uses: ./.github/actions/setup-solana/
113117
- uses: ./.github/actions/setup-ts/
118+
- uses: ./.github/actions/setup-surfpool/
114119

115120
- uses: actions/cache@v3
116121
if: ${{ env.CACHE != 'false' }}
@@ -236,6 +241,7 @@ jobs:
236241
path: client/example/target
237242
key: cargo-${{ runner.os }}-client/example-${{ env.ANCHOR_VERSION }}-${{ env.SOLANA_CLI_VERSION }}-${{ hashFiles('**/Cargo.lock') }}
238243
- uses: ./.github/actions/setup-solana/
244+
- uses: ./.github/actions/setup-surfpool/
239245
- run: cd client/example && ./run-test.sh
240246
- uses: ./.github/actions/git-diff/
241247

@@ -249,6 +255,7 @@ jobs:
249255
- uses: ./.github/actions/setup/
250256
- uses: ./.github/actions/setup-ts/
251257
- uses: ./.github/actions/setup-solana/
258+
- uses: ./.github/actions/setup-surfpool/
252259

253260
- uses: actions/cache@v3
254261
if: ${{ env.CACHE != 'false' }}
@@ -272,8 +279,8 @@ jobs:
272279
path: tests/bpf-upgradeable-state/target
273280
key: cargo-${{ runner.os }}-tests/bpf-upgradeable-state-${{ env.ANCHOR_VERSION }}-${{ env.SOLANA_CLI_VERSION }}-${{ hashFiles('**/Cargo.lock') }}
274281

275-
- run: solana-test-validator -r --quiet &
276-
name: start validator
282+
- run: surfpool start --ci --offline &
283+
name: start surfpool
277284
- run: cd tests/bpf-upgradeable-state && yarn --frozen-lockfile
278285
- run: cd tests/bpf-upgradeable-state
279286
- run: cd tests/bpf-upgradeable-state && anchor build --skip-lint
@@ -346,6 +353,7 @@ jobs:
346353
- uses: ./.github/actions/setup/
347354
- uses: ./.github/actions/setup-ts/
348355
- uses: ./.github/actions/setup-solana/
356+
- uses: ./.github/actions/setup-surfpool/
349357

350358
- uses: actions/cache@v3
351359
if: ${{ env.CACHE != 'false' }}
@@ -467,6 +475,7 @@ jobs:
467475
- uses: ./.github/actions/setup/
468476
- uses: ./.github/actions/setup-ts/
469477
- uses: ./.github/actions/setup-solana/
478+
- uses: ./.github/actions/setup-surfpool/
470479

471480
- uses: actions/cache@v3
472481
if: ${{ env.CACHE != 'false' }}

.github/workflows/tests.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,4 @@ jobs:
2222
node_version: 20.18.0
2323
cargo_profile: debug
2424
anchor_binary_name: anchor-binary
25+
surfpool_cli_version: 0.11.2

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cli/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ shellexpand = "2.1.0"
3939
solana-cli-config = "2"
4040
solana-faucet = "2"
4141
solana-rpc-client = "2"
42+
solana-rpc-client-api = "2"
4243
solana-sdk = "2"
4344
syn = { version = "1.0.60", features = ["full", "extra-traits"] }
4445
tar = "0.4.35"

cli/src/config.rs

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ use std::str::FromStr;
2525
use std::{fmt, io};
2626
use walkdir::WalkDir;
2727

28+
pub const SURFPOOL_HOST: &str = "127.0.0.1";
29+
2830
pub trait Merge: Sized {
2931
fn merge(&mut self, _other: Self) {}
3032
}
@@ -295,10 +297,19 @@ pub struct Config {
295297
// Separate entry next to test_config because
296298
// "anchor localnet" only has access to the Anchor.toml,
297299
// not the Test.toml files
300+
pub validator: Option<ValidatorType>,
298301
pub test_validator: Option<TestValidator>,
299302
pub test_config: Option<TestConfig>,
303+
pub surfpool_config: Option<SurfpoolConfig>,
300304
}
301305

306+
#[derive(ValueEnum, Parser, Clone, Copy, PartialEq, Eq, Debug)]
307+
pub enum ValidatorType {
308+
/// Use Surfpool validator (default)
309+
Surfpool,
310+
/// Use Solana test validator
311+
Legacy,
312+
}
302313
#[derive(Default, Clone, Debug, Serialize, Deserialize)]
303314
pub struct ToolchainConfig {
304315
pub anchor_version: Option<String>,
@@ -405,6 +416,7 @@ pub enum ProgramArch {
405416
Bpf,
406417
Sbf,
407418
}
419+
408420
impl ProgramArch {
409421
pub fn build_subcommand(&self) -> &str {
410422
match self {
@@ -513,6 +525,7 @@ struct _Config {
513525
workspace: Option<WorkspaceConfig>,
514526
scripts: Option<ScriptsConfig>,
515527
test: Option<_TestValidator>,
528+
surfpool: Option<_SurfpoolConfig>,
516529
}
517530

518531
#[derive(Debug, Serialize, Deserialize)]
@@ -613,6 +626,7 @@ impl fmt::Display for Config {
613626
programs,
614627
workspace: (!self.workspace.members.is_empty() || !self.workspace.exclude.is_empty())
615628
.then(|| self.workspace.clone()),
629+
surfpool: self.surfpool_config.clone().map(Into::into),
616630
};
617631

618632
let cfg = toml::to_string(&cfg).expect("Must be well formed");
@@ -635,10 +649,12 @@ impl FromStr for Config {
635649
wallet: shellexpand::tilde(&cfg.provider.wallet).parse()?,
636650
},
637651
scripts: cfg.scripts.unwrap_or_default(),
652+
validator: None, // Will be set based on CLI flags
638653
test_validator: cfg.test.map(Into::into),
639654
test_config: None,
640655
programs: cfg.programs.map_or(Ok(BTreeMap::new()), deser_programs)?,
641656
workspace: cfg.workspace.unwrap_or_default(),
657+
surfpool_config: cfg.surfpool.map(Into::into),
642658
})
643659
}
644660
}
@@ -723,6 +739,23 @@ pub struct TestValidator {
723739
pub upgradeable: bool,
724740
}
725741

742+
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
743+
pub struct SurfpoolConfig {
744+
pub startup_wait: i32,
745+
pub shutdown_wait: i32,
746+
pub rpc_port: u16,
747+
pub ws_port: Option<u16>,
748+
pub host: String,
749+
pub online: Option<bool>,
750+
pub datasource_rpc_url: Option<String>,
751+
pub airdrop_addresses: Option<Vec<String>>,
752+
pub manifest_file_path: Option<String>,
753+
pub runbooks: Option<Vec<String>>,
754+
pub slot_time: Option<u16>,
755+
pub log_level: Option<String>,
756+
pub block_production_mode: Option<String>,
757+
}
758+
726759
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
727760
pub struct _TestValidator {
728761
#[serde(skip_serializing_if = "Option::is_none")]
@@ -737,6 +770,75 @@ pub struct _TestValidator {
737770
pub upgradeable: Option<bool>,
738771
}
739772

773+
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
774+
pub struct _SurfpoolConfig {
775+
#[serde(skip_serializing_if = "Option::is_none")]
776+
pub startup_wait: Option<i32>,
777+
#[serde(skip_serializing_if = "Option::is_none")]
778+
pub shutdown_wait: Option<i32>,
779+
#[serde(skip_serializing_if = "Option::is_none")]
780+
pub rpc_port: Option<u16>,
781+
#[serde(skip_serializing_if = "Option::is_none")]
782+
pub ws_port: Option<u16>,
783+
#[serde(skip_serializing_if = "Option::is_none")]
784+
pub host: Option<String>,
785+
#[serde(skip_serializing_if = "Option::is_none")]
786+
pub online: Option<bool>,
787+
#[serde(skip_serializing_if = "Option::is_none")]
788+
pub datasource_rpc_url: Option<String>,
789+
#[serde(skip_serializing_if = "Option::is_none")]
790+
pub airdrop_addresses: Option<Vec<String>>,
791+
#[serde(skip_serializing_if = "Option::is_none")]
792+
pub manifest_file_path: Option<String>,
793+
#[serde(skip_serializing_if = "Option::is_none")]
794+
pub runbooks: Option<Vec<String>>,
795+
#[serde(skip_serializing_if = "Option::is_none")]
796+
pub slot_time: Option<u16>,
797+
#[serde(skip_serializing_if = "Option::is_none")]
798+
pub log_level: Option<String>,
799+
#[serde(skip_serializing_if = "Option::is_none")]
800+
pub block_production_mode: Option<String>,
801+
}
802+
803+
impl From<_SurfpoolConfig> for SurfpoolConfig {
804+
fn from(_surfpool_config: _SurfpoolConfig) -> Self {
805+
Self {
806+
startup_wait: _surfpool_config.startup_wait.unwrap_or(STARTUP_WAIT),
807+
shutdown_wait: _surfpool_config.shutdown_wait.unwrap_or(SHUTDOWN_WAIT),
808+
rpc_port: _surfpool_config.rpc_port.unwrap_or(DEFAULT_RPC_PORT),
809+
host: _surfpool_config.host.unwrap_or(SURFPOOL_HOST.to_string()),
810+
ws_port: _surfpool_config.ws_port,
811+
online: _surfpool_config.online,
812+
datasource_rpc_url: _surfpool_config.datasource_rpc_url,
813+
airdrop_addresses: _surfpool_config.airdrop_addresses,
814+
manifest_file_path: _surfpool_config.manifest_file_path,
815+
runbooks: _surfpool_config.runbooks,
816+
slot_time: _surfpool_config.slot_time,
817+
log_level: _surfpool_config.log_level,
818+
block_production_mode: _surfpool_config.block_production_mode,
819+
}
820+
}
821+
}
822+
823+
impl From<SurfpoolConfig> for _SurfpoolConfig {
824+
fn from(surfpool_config: SurfpoolConfig) -> Self {
825+
Self {
826+
startup_wait: Some(surfpool_config.startup_wait),
827+
shutdown_wait: Some(surfpool_config.shutdown_wait),
828+
rpc_port: Some(surfpool_config.rpc_port),
829+
ws_port: surfpool_config.ws_port,
830+
host: Some(surfpool_config.host),
831+
online: surfpool_config.online,
832+
datasource_rpc_url: surfpool_config.datasource_rpc_url,
833+
airdrop_addresses: surfpool_config.airdrop_addresses,
834+
manifest_file_path: surfpool_config.manifest_file_path,
835+
runbooks: surfpool_config.runbooks,
836+
slot_time: surfpool_config.slot_time,
837+
log_level: surfpool_config.log_level,
838+
block_production_mode: surfpool_config.block_production_mode,
839+
}
840+
}
841+
}
740842
pub const STARTUP_WAIT: i32 = 5000;
741843
pub const SHUTDOWN_WAIT: i32 = 2000;
742844

@@ -1354,6 +1456,23 @@ impl AnchorPackage {
13541456
}
13551457
}
13561458

1459+
#[derive(Debug, Serialize, Deserialize)]
1460+
#[serde(rename_all = "camelCase")]
1461+
pub struct SurfnetInfoResponse {
1462+
pub runbook_executions: Vec<RunbookExecution>,
1463+
}
1464+
#[derive(Debug, Serialize, Deserialize)]
1465+
#[serde(rename_all = "camelCase")]
1466+
pub struct RunbookExecution {
1467+
#[serde(rename = "startedAt")]
1468+
pub started_at: u32,
1469+
#[serde(rename = "completedAt")]
1470+
pub completed_at: Option<u32>,
1471+
#[serde(rename = "runbookId")]
1472+
pub runbook_id: String,
1473+
pub errors: Option<Vec<String>>,
1474+
}
1475+
13571476
#[macro_export]
13581477
macro_rules! home_path {
13591478
($my_struct:ident, $path:literal) => {

0 commit comments

Comments
 (0)