瀏覽代碼

🪓 Remove SVM conformance tests 🪓 (#7322)

* Remove conformance tests

* Remove transaction builder
Lucas Ste 3 月之前
父節點
當前提交
7b98233b26

+ 0 - 13
Cargo.lock

@@ -10857,12 +10857,10 @@ dependencies = [
  "assert_matches",
  "bincode",
  "ed25519-dalek",
- "itertools 0.12.1",
  "libsecp256k1",
  "log",
  "openssl",
  "percentage",
- "prost",
  "qualifier_attr",
  "rand 0.7.3",
  "serde",
@@ -10907,10 +10905,8 @@ dependencies = [
  "solana-secp256r1-program",
  "solana-signature",
  "solana-signer",
- "solana-slot-hashes",
  "solana-svm",
  "solana-svm-callback",
- "solana-svm-conformance",
  "solana-svm-feature-set",
  "solana-svm-transaction",
  "solana-system-interface",
@@ -10938,15 +10934,6 @@ dependencies = [
  "solana-pubkey",
 ]
 
-[[package]]
-name = "solana-svm-conformance"
-version = "3.0.0"
-dependencies = [
- "prost",
- "prost-build",
- "prost-types",
-]
-
 [[package]]
 name = "solana-svm-feature-set"
 version = "3.0.0"

+ 0 - 2
Cargo.toml

@@ -104,7 +104,6 @@ members = [
     "streamer",
     "svm",
     "svm-callback",
-    "svm-conformance",
     "svm-feature-set",
     "svm-transaction",
     "syscalls",
@@ -523,7 +522,6 @@ solana-storage-proto = { path = "storage-proto", version = "=3.0.0" }
 solana-streamer = { path = "streamer", version = "=3.0.0" }
 solana-svm = { path = "svm", version = "=3.0.0" }
 solana-svm-callback = { path = "svm-callback", version = "=3.0.0" }
-solana-svm-conformance = { path = "svm-conformance", version = "=3.0.0" }
 solana-svm-feature-set = { path = "svm-feature-set", version = "=3.0.0" }
 solana-svm-transaction = { path = "svm-transaction", version = "=3.0.0" }
 solana-system-interface = "1.0"

+ 0 - 2
programs/sbf/Cargo.lock

@@ -9132,7 +9132,6 @@ name = "solana-svm"
 version = "3.0.0"
 dependencies = [
  "ahash 0.8.11",
- "itertools 0.12.1",
  "log",
  "percentage",
  "qualifier_attr",
@@ -9159,7 +9158,6 @@ dependencies = [
  "solana-rent",
  "solana-rent-collector",
  "solana-sdk-ids",
- "solana-slot-hashes",
  "solana-svm-callback",
  "solana-svm-feature-set",
  "solana-svm-transaction",

+ 0 - 20
svm-conformance/Cargo.toml

@@ -1,20 +0,0 @@
-[package]
-name = "solana-svm-conformance"
-description = "Solana SVM conformance"
-documentation = "https://docs.rs/solana-svm-conformance"
-version = { workspace = true }
-authors = { workspace = true }
-repository = { workspace = true }
-homepage = { workspace = true }
-license = { workspace = true }
-edition = { workspace = true }
-
-[package.metadata.docs.rs]
-targets = ["x86_64-unknown-linux-gnu"]
-
-[dependencies]
-prost = { workspace = true }
-prost-types = { workspace = true }
-
-[build-dependencies]
-prost-build = { workspace = true }

+ 0 - 20
svm-conformance/build.rs

@@ -1,20 +0,0 @@
-fn main() {
-    let proto_base_path = std::path::PathBuf::from("proto");
-    let protos = [
-        "context.proto",
-        "invoke.proto",
-        "metadata.proto",
-        "txn.proto",
-    ];
-    let protos_path: Vec<_> = protos
-        .iter()
-        .map(|name| proto_base_path.join(name))
-        .collect();
-
-    protos_path
-        .iter()
-        .for_each(|proto| println!("cargo:rerun-if-changed={}", proto.display()));
-
-    prost_build::compile_protos(protos_path.as_ref(), &[proto_base_path])
-        .expect("Failed to compile protobuf files");
-}

+ 0 - 61
svm-conformance/proto/context.proto

@@ -1,61 +0,0 @@
-syntax = "proto3";
-package org.solana.sealevel.v1;
-
-// A set of feature flags.
-message FeatureSet {
-  // Every item in this list marks an enabled feature.  The value of
-  // each item is the first 8 bytes of the feature ID as a little-
-  // endian integer.
-  repeated fixed64 features = 1;
-}
-
-// A seed address.  This is not a PDA.
-message SeedAddress {
-  // The seed address base.  (32 bytes)
-  bytes base = 1;
-
-  // The seed path  (<= 32 bytes)
-  bytes seed = 2;
-
-  // The seed address owner.  (32 bytes)
-  bytes owner = 3;
-}
-
-// The complete state of an account excluding its public key.
-message AcctState {
-  // The account address.  (32 bytes)
-  bytes address = 1;
-
-  uint64 lamports = 2;
-
-  // Account data is limited to 10 MiB on Solana mainnet as of 2024-Feb.
-  bytes data = 3;
-
-  bool executable = 4;
-
-  // The rent epoch is deprecated on Solana mainnet as of 2024-Feb.
-  // If ommitted, implies a value of UINT64_MAX.
-  uint64 rent_epoch = 5;
-
-  // Address of the program that owns this account.  (32 bytes)
-  bytes owner = 6;
-
-  // The account address, but derived as a seed address.  Overrides
-  // `address` if present.
-  // TODO: This is a solfuzz specific extension and is not compliant
-  // with the org.solana.sealevel.v1 API.
-  SeedAddress seed_addr = 7;
-}
-
-// EpochContext includes context scoped to an epoch.
-// On "real" ledgers, it is created during the epoch boundary.
-message EpochContext {
-  FeatureSet features = 1;
-}
-
-// SlotContext includes context scoped to a block.
-// On "real" ledgers, it is created during the slot boundary.
-message SlotContext {
-  // Slot number
-  fixed64 slot = 1;
-}

+ 0 - 65
svm-conformance/proto/invoke.proto

@@ -1,65 +0,0 @@
-syntax = "proto3";
-package org.solana.sealevel.v1;
-
-import "context.proto";
-import "metadata.proto";
-
-message InstrAcct {
-  // Selects an account in an external list
-  uint32 index = 1;
-  bool is_writable = 2;
-  bool is_signer = 3;
-}
-
-// The execution context of a program invocation (aka instruction).
-// Contains all required information to independently replay an instruction.
-// Also includes partial transaction context.
-message InstrContext {
-  // The address of the program invoked.  (32 bytes)
-  bytes program_id = 1;
-
-  // Account state accessed by the instruction.  This may include
-  // indirect accesses like sysvars.
-  repeated AcctState accounts = 3;
-
-  // Account access list for this instruction (refers to above accounts list)
-  repeated InstrAcct instr_accounts = 4;
-
-  // The input data passed to program execution.
-  bytes data = 5;
-
-  uint64 cu_avail = 6;
-
-  SlotContext slot_context = 8;
-  EpochContext epoch_context = 9;
-}
-
-// The results of executing an InstrContext.
-message InstrEffects {
-  // result is zero if the instruction executed succesfully.
-  // Otherwise, a non-zero error code.  Error codes are not relevant to
-  // consensus.
-  int32 result = 1;
-
-  // Some error cases additionally have a custom error code.  Unlike
-  // the expected_result, this is stable across clients.
-  uint32 custom_err = 2;
-
-  // Copies of accounts that were changed.  May be in an arbitrary
-  // order.  The pubkey of each account is unique in this list.  Each
-  // account address modified here must also be in the
-  // InstrContext.
-  repeated AcctState modified_accounts = 3;
-
-  uint64 cu_avail = 4;
-
-  // Instruction return data.
-  bytes return_data = 5;
-}
-
-// An instruction processing test fixture.
-message InstrFixture {
-  FixtureMetadata metadata = 1;
-  InstrContext input = 2;
-  InstrEffects output = 3;
-}

+ 0 - 7
svm-conformance/proto/metadata.proto

@@ -1,7 +0,0 @@
-syntax = "proto3";
-package org.solana.sealevel.v1;
-
-// FixtureMetadata includes the metadata for the fixture
-message FixtureMetadata {
-  string fn_entrypoint = 1;
-}

+ 0 - 134
svm-conformance/proto/txn.proto

@@ -1,134 +0,0 @@
-syntax = "proto3";
-package org.solana.sealevel.v1;
-
-import "context.proto";
-import "metadata.proto";
-
-// Message header contains the counts of required readonly and signatures
-message MessageHeader {
-  uint32 num_required_signatures = 1;
-  uint32 num_readonly_signed_accounts = 2;
-  uint32 num_readonly_unsigned_accounts = 3;
-}
-
-// The instruction a transaction executes
-message CompiledInstruction {
-  // Index into the message pubkey array
-  uint32 program_id_index = 1;
-  // Indexes into the message pubkey array
-  repeated uint32 accounts = 2;
-  bytes data = 3;
-}
-
-// List of address table lookups used to load additional accounts for a transaction
-message MessageAddressTableLookup {
-  bytes account_key = 1;
-  repeated uint32 writable_indexes = 2;
-  repeated uint32 readonly_indexes = 3;
-}
-
-// Message contains the transaction data
-message TransactionMessage {
-  // Whether this is a legacy message or not
-  bool is_legacy = 1;
-
-  MessageHeader header = 2;
-
-  // Vector of pubkeys
-  repeated bytes account_keys = 3;
-
-  // Data associated with the accounts referred above. Not all accounts need to be here.
-  repeated AcctState account_shared_data = 4;
-
-  // Recent blockhash provided in message
-  bytes recent_blockhash = 5;
-
-  // The instructions this transaction executes
-  repeated CompiledInstruction instructions = 6;
-
-  // Not available in legacy message
-  repeated MessageAddressTableLookup address_table_lookups = 7;
-}
-
-// A valid verified transaction
-message SanitizedTransaction {
-  // The transaction information
-  TransactionMessage message = 1;
-  // The message hash
-  bytes message_hash = 2;
-  // Is this a voting transaction?
-  bool is_simple_vote_tx = 3;
-  // The signatures needed in the transaction
-  repeated bytes signatures = 4;
-}
-
-// This Transaction context be used to fuzz either `load_execute_and_commit_transactions`,
-// `load_and_execute_transactions` in `bank.rs` or `load_and_execute_sanitized_transactions`
-// in `svm/transaction_processor.rs`
-message TxnContext {
-  // The transaction data
-  SanitizedTransaction tx = 1;
-
-  // Up to 300 (actually 301) most recent blockhashes (ordered from oldest to newest)
-  repeated bytes blockhash_queue = 3;
-
-  EpochContext epoch_ctx = 4;
-  SlotContext slot_ctx = 5;
-}
-
-// The resulting state of an account after a transaction
-message ResultingState {
-    repeated AcctState acct_states = 1;
-    repeated RentDebits rent_debits = 2;
-    uint64 transaction_rent = 3;
-}
-
-// The rent state for an account after a transaction
-message RentDebits {
-  bytes pubkey = 1;
-  int64 rent_collected = 2;
-}
-
-message FeeDetails {
-  uint64 transaction_fee = 1;
-  uint64 prioritization_fee = 2;
-}
-
-// The execution results for a transaction
-message TxnResult {
-  // Whether this transaction was executed
-  bool executed = 1;
-  // Whether there was a sanitization error
-  bool sanitization_error = 2;
-  // The state of each account after the transaction
-  ResultingState resulting_state = 3;
-  uint64 rent = 4;
-
-  // If an executed transaction has no error
-  bool is_ok = 5;
-  // The transaction status (error code)
-  uint32 status = 6;
-  // The instruction error, if any
-  uint32 instruction_error = 7;
-  // The instruction error index, if any
-  uint32 instruction_error_index = 8;
-  // Custom error, if any
-  uint32 custom_error = 9;
-
-
-  // The return data from this transaction, if any
-  bytes return_data = 10;
-  // Number of executed compute units
-  uint64 executed_units = 11;
-  // The collected fees in this transaction
-  FeeDetails fee_details = 12;
-}
-
-// Txn fixtures
-message TxnFixture {
-  FixtureMetadata metadata = 1;
-  // Context
-  TxnContext input = 2;
-  // Effects
-  TxnResult output = 3;
-}

+ 0 - 3
svm-conformance/src/lib.rs

@@ -1,3 +0,0 @@
-pub mod proto {
-    include!(concat!(env!("OUT_DIR"), "/org.solana.sealevel.v1.rs"));
-}

+ 0 - 4
svm/Cargo.toml

@@ -36,7 +36,6 @@ svm-internal = []
 
 [dependencies]
 ahash = { workspace = true }
-itertools = { workspace = true }
 log = { workspace = true }
 percentage = { workspace = true }
 qualifier_attr = { workspace = true, optional = true }
@@ -69,7 +68,6 @@ solana-pubkey = { workspace = true }
 solana-rent = { workspace = true }
 solana-rent-collector = { workspace = true }
 solana-sdk-ids = { workspace = true }
-solana-slot-hashes = { workspace = true }
 solana-svm-callback = { workspace = true }
 solana-svm-feature-set = { workspace = true }
 solana-svm-transaction = { workspace = true }
@@ -91,7 +89,6 @@ bincode = { workspace = true }
 ed25519-dalek = { workspace = true }
 libsecp256k1 = { workspace = true }
 openssl = { workspace = true }
-prost = { workspace = true }
 rand0-7 = { workspace = true }
 shuttle = { workspace = true }
 solana-bpf-loader-program = { workspace = true }
@@ -116,7 +113,6 @@ solana-signature = { workspace = true, features = ["rand"] }
 solana-signer = { workspace = true }
 # See order-crates-for-publishing.py for using this unusual `path = "."`
 solana-svm = { path = ".", features = ["dev-context-only-utils", "svm-internal"] }
-solana-svm-conformance = { workspace = true }
 solana-system-program = { workspace = true }
 solana-system-transaction = { workspace = true }
 solana-sysvar = { workspace = true }

+ 0 - 2
svm/examples/Cargo.lock

@@ -8184,7 +8184,6 @@ name = "solana-svm"
 version = "3.0.0"
 dependencies = [
  "ahash 0.8.11",
- "itertools 0.12.1",
  "log",
  "percentage",
  "serde",
@@ -8210,7 +8209,6 @@ dependencies = [
  "solana-rent",
  "solana-rent-collector",
  "solana-sdk-ids",
- "solana-slot-hashes",
  "solana-svm-callback",
  "solana-svm-feature-set",
  "solana-svm-transaction",

+ 31 - 44
svm/tests/concurrent_tests.rs

@@ -1,10 +1,7 @@
 #![cfg(feature = "shuttle-test")]
 
 use {
-    crate::{
-        mock_bank::{create_custom_loader, deploy_program, register_builtins, MockForkGraph},
-        transaction_builder::SanitizedTransactionBuilder,
-    },
+    crate::mock_bank::{create_custom_loader, deploy_program, register_builtins, MockForkGraph},
     assert_matches::assert_matches,
     mock_bank::MockBankCallback,
     shuttle::{
@@ -12,15 +9,13 @@ use {
         thread, Runner,
     },
     solana_account::{AccountSharedData, ReadableAccount, WritableAccount},
-    solana_hash::Hash,
-    solana_instruction::AccountMeta,
+    solana_instruction::{AccountMeta, Instruction},
     solana_program_runtime::{
         execution_budget::SVMTransactionExecutionAndFeeBudgetLimits,
         loaded_programs::ProgramCacheEntryType,
     },
     solana_pubkey::Pubkey,
     solana_sdk_ids::bpf_loader_upgradeable,
-    solana_signature::Signature,
     solana_svm::{
         account_loader::{CheckedTransactionDetails, TransactionCheckResult},
         transaction_processing_result::{
@@ -32,13 +27,12 @@ use {
         },
     },
     solana_timings::ExecuteTimings,
-    std::collections::HashMap,
+    solana_transaction::{sanitized::SanitizedTransaction, Transaction},
+    std::collections::{HashMap, HashSet},
 };
 
 mod mock_bank;
 
-mod transaction_builder;
-
 fn program_cache_execution(threads: usize) {
     let mut mock_bank = MockBankCallback::default();
     let fork_graph = Arc::new(RwLock::new(MockForkGraph {}));
@@ -147,7 +141,6 @@ fn svm_concurrent() {
     batch_processor.fill_missing_sysvar_cache_entries(&*mock_bank);
     register_builtins(&mock_bank, &batch_processor, false);
 
-    let mut transaction_builder = SanitizedTransactionBuilder::default();
     let program_id = deploy_program("transfer-from-account".to_string(), 0, &mock_bank);
 
     const THREADS: usize = 4;
@@ -192,40 +185,34 @@ fn svm_concurrent() {
             shared_data.insert(fee_payer, account_data);
         }
 
-        transaction_builder.create_instruction(
-            program_id,
-            vec![
-                AccountMeta {
-                    pubkey: sender,
-                    is_signer: true,
-                    is_writable: true,
-                },
-                AccountMeta {
-                    pubkey: recipient,
-                    is_signer: false,
-                    is_writable: true,
-                },
-                AccountMeta {
-                    pubkey: read_account,
-                    is_signer: false,
-                    is_writable: false,
-                },
-                AccountMeta {
-                    pubkey: system_account,
-                    is_signer: false,
-                    is_writable: false,
-                },
-            ],
-            HashMap::from([(sender, Signature::new_unique())]),
-            vec![0],
-        );
+        let accounts = vec![
+            AccountMeta {
+                pubkey: sender,
+                is_signer: true,
+                is_writable: true,
+            },
+            AccountMeta {
+                pubkey: recipient,
+                is_signer: false,
+                is_writable: true,
+            },
+            AccountMeta {
+                pubkey: read_account,
+                is_signer: false,
+                is_writable: false,
+            },
+            AccountMeta {
+                pubkey: system_account,
+                is_signer: false,
+                is_writable: false,
+            },
+        ];
+
+        let instruction = Instruction::new_with_bytes(program_id, &[0], accounts);
+        let legacy_transaction = Transaction::new_with_payer(&[instruction], Some(&fee_payer));
 
-        let sanitized_transaction = transaction_builder.build(
-            Hash::default(),
-            (fee_payer, Signature::new_unique()),
-            true,
-            false,
-        );
+        let sanitized_transaction =
+            SanitizedTransaction::try_from_legacy_transaction(legacy_transaction, &HashSet::new());
         transactions[idx % THREADS].push(sanitized_transaction.unwrap());
         check_data[idx % THREADS].push(CheckTxData {
             fee_payer,

+ 0 - 545
svm/tests/conformance.rs

@@ -1,545 +0,0 @@
-use {
-    crate::{
-        mock_bank::{MockBankCallback, MockForkGraph},
-        transaction_builder::SanitizedTransactionBuilder,
-    },
-    agave_feature_set::{FeatureSet, FEATURE_NAMES},
-    agave_syscalls::create_program_runtime_environment_v1,
-    prost::Message,
-    solana_account::{AccountSharedData, ReadableAccount, WritableAccount},
-    solana_clock::Clock,
-    solana_epoch_schedule::EpochSchedule,
-    solana_hash::Hash,
-    solana_instruction::AccountMeta,
-    solana_log_collector::LogCollector,
-    solana_message::SanitizedMessage,
-    solana_program_runtime::{
-        execution_budget::{SVMTransactionExecutionBudget, SVMTransactionExecutionCost},
-        invoke_context::{EnvironmentConfig, InvokeContext},
-        loaded_programs::{ProgramCacheEntry, ProgramCacheForTxBatch},
-    },
-    solana_pubkey::Pubkey,
-    solana_rent::Rent,
-    solana_signature::Signature,
-    solana_svm::{program_loader, transaction_processor::TransactionBatchProcessor},
-    solana_svm_callback::TransactionProcessingCallback,
-    solana_svm_conformance::proto::{AcctState, InstrEffects, InstrFixture},
-    solana_svm_transaction::instruction::SVMInstruction,
-    solana_sysvar::last_restart_slot,
-    solana_sysvar_id::SysvarId,
-    solana_timings::ExecuteTimings,
-    solana_transaction_context::{
-        ExecutionRecord, IndexOfAccount, TransactionAccount, TransactionContext,
-    },
-    std::{
-        collections::{hash_map::Entry, HashMap},
-        env,
-        ffi::OsString,
-        fs::{self, File},
-        io::Read,
-        path::PathBuf,
-        process::Command,
-        sync::{Arc, RwLock},
-    },
-};
-
-mod mock_bank;
-mod transaction_builder;
-
-const fn feature_u64(feature: &Pubkey) -> u64 {
-    let feature_id = feature.to_bytes();
-    feature_id[0] as u64
-        | ((feature_id[1] as u64) << 8)
-        | ((feature_id[2] as u64) << 16)
-        | ((feature_id[3] as u64) << 24)
-        | ((feature_id[4] as u64) << 32)
-        | ((feature_id[5] as u64) << 40)
-        | ((feature_id[6] as u64) << 48)
-        | ((feature_id[7] as u64) << 56)
-}
-
-static INDEXED_FEATURES: std::sync::LazyLock<HashMap<u64, Pubkey>> =
-    std::sync::LazyLock::new(|| {
-        FEATURE_NAMES
-            .keys()
-            .map(|pubkey| (feature_u64(pubkey), *pubkey))
-            .collect()
-    });
-
-fn setup() -> PathBuf {
-    let mut dir = env::current_dir().unwrap();
-    dir.push("test-vectors");
-    if !dir.exists() {
-        std::println!("Cloning test-vectors ...");
-        Command::new("git")
-            .args([
-                "clone",
-                "https://github.com/firedancer-io/test-vectors",
-                dir.as_os_str().to_str().unwrap(),
-            ])
-            .status()
-            .expect("Failed to download test-vectors");
-
-        std::println!("Checking out commit 4abb2046cf51efe809498f4fd717023684050d2f");
-        Command::new("git")
-            .current_dir(&dir)
-            .args(["checkout", "4abb2046cf51efe809498f4fd717023684050d2f"])
-            .status()
-            .expect("Failed to checkout to proper test-vector commit");
-
-        std::println!("Setup done!");
-    }
-
-    dir
-}
-
-fn cleanup() {
-    let mut dir = env::current_dir().unwrap();
-    dir.push("test-vectors");
-
-    if dir.exists() {
-        fs::remove_dir_all(dir).expect("Failed to delete test-vectors repository");
-    }
-}
-
-#[test]
-fn execute_fixtures() {
-    let mut base_dir = setup();
-    base_dir.push("instr");
-    base_dir.push("fixtures");
-
-    // bpf-loader tests
-    base_dir.push("bpf-loader");
-    run_from_folder(&base_dir);
-    base_dir.pop();
-
-    // bpf-loader-v2 tests
-    base_dir.push("bpf-loader-v2");
-    run_from_folder(&base_dir);
-    base_dir.pop();
-
-    // bpf-loader-v3 tests
-    base_dir.push("bpf-loader-v3");
-    run_from_folder(&base_dir);
-    base_dir.pop();
-
-    // bpf-loader-v3 tests
-    base_dir.push("bpf-loader-v3-programs");
-    run_from_folder(&base_dir);
-    base_dir.pop();
-
-    // System program tests
-    base_dir.push("system");
-    run_from_folder(&base_dir);
-    base_dir.pop();
-
-    // non-builtin-programs tests
-    base_dir.push("unknown");
-    run_from_folder(&base_dir);
-    base_dir.pop();
-
-    cleanup();
-}
-
-fn run_from_folder(base_dir: &PathBuf) {
-    for path in std::fs::read_dir(base_dir).unwrap() {
-        let filename = path.as_ref().unwrap().file_name();
-        let mut file = File::open(path.as_ref().unwrap().path()).expect("file not found");
-        let mut buffer = Vec::new();
-        file.read_to_end(&mut buffer).expect("Failed to read file");
-        let fixture = InstrFixture::decode(buffer.as_slice()).unwrap();
-        run_fixture(fixture, filename);
-    }
-}
-
-fn run_fixture(fixture: InstrFixture, filename: OsString) {
-    let input = fixture.input.unwrap();
-    let output = fixture.output.as_ref().unwrap();
-
-    let mut transaction_builder = SanitizedTransactionBuilder::default();
-    let program_id = Pubkey::new_from_array(input.program_id.try_into().unwrap());
-    let mut accounts: Vec<AccountMeta> = Vec::with_capacity(input.instr_accounts.len());
-    let mut signatures: HashMap<Pubkey, Signature> =
-        HashMap::with_capacity(input.instr_accounts.len());
-
-    for item in input.instr_accounts {
-        let pubkey = Pubkey::new_from_array(
-            input.accounts[item.index as usize]
-                .address
-                .clone()
-                .try_into()
-                .unwrap(),
-        );
-        accounts.push(AccountMeta {
-            pubkey,
-            is_signer: item.is_signer,
-            is_writable: item.is_writable,
-        });
-        if item.is_signer {
-            signatures.insert(pubkey, Signature::new_unique());
-        }
-    }
-
-    transaction_builder.create_instruction(program_id, accounts, signatures, input.data);
-
-    let mut feature_set = FeatureSet::default();
-    if let Some(features) = &input.epoch_context.as_ref().unwrap().features {
-        for id in &features.features {
-            if let Some(pubkey) = INDEXED_FEATURES.get(id) {
-                feature_set.activate(pubkey, 0);
-            }
-        }
-    }
-
-    let mut fee_payer = Pubkey::new_unique();
-    let mut mock_bank = MockBankCallback::default();
-    {
-        let mut account_data_map = mock_bank.account_shared_data.write().unwrap();
-        for item in input.accounts {
-            let pubkey = Pubkey::new_from_array(item.address.try_into().unwrap());
-            let mut account_data = AccountSharedData::default();
-            account_data.set_lamports(item.lamports);
-            account_data.set_data(item.data);
-            account_data.set_owner(Pubkey::new_from_array(
-                item.owner.clone().try_into().unwrap(),
-            ));
-            account_data.set_executable(item.executable);
-            account_data.set_rent_epoch(item.rent_epoch);
-
-            account_data_map.insert(pubkey, account_data);
-        }
-        let mut account_data = AccountSharedData::default();
-        account_data.set_lamports(800000);
-
-        while account_data_map.contains_key(&fee_payer) {
-            // The fee payer must not coincide with any of the previous accounts
-            fee_payer = Pubkey::new_unique();
-        }
-        account_data_map.insert(fee_payer, account_data);
-    }
-
-    let Ok(transaction) = transaction_builder.build(
-        Hash::default(),
-        (fee_payer, Signature::new_unique()),
-        false,
-        true,
-    ) else {
-        // If we can't build a sanitized transaction,
-        // the output must be a failed instruction as well
-        assert_ne!(output.result, 0);
-        return;
-    };
-
-    let transactions = vec![transaction];
-
-    let compute_budget = SVMTransactionExecutionBudget {
-        compute_unit_limit: input.cu_avail,
-        ..SVMTransactionExecutionBudget::default()
-    };
-
-    let v1_environment = create_program_runtime_environment_v1(
-        &feature_set.runtime_features(),
-        &compute_budget,
-        false,
-        false,
-    )
-    .unwrap();
-
-    mock_bank.override_feature_set(feature_set.runtime_features());
-
-    let fork_graph = Arc::new(RwLock::new(MockForkGraph {}));
-    let batch_processor = TransactionBatchProcessor::new(
-        42,
-        2,
-        Arc::downgrade(&fork_graph),
-        Some(Arc::new(v1_environment)),
-        None,
-    );
-
-    batch_processor
-        .writable_sysvar_cache()
-        .write()
-        .unwrap()
-        .fill_missing_entries(|pubkey, callbackback| {
-            if let Some(account) = mock_bank.get_account_shared_data(pubkey) {
-                if account.lamports() > 0 {
-                    callbackback(account.data());
-                    return;
-                }
-            }
-
-            if *pubkey == Clock::id() {
-                let default_clock = Clock {
-                    slot: 10,
-                    ..Default::default()
-                };
-                let clock_data = bincode::serialize(&default_clock).unwrap();
-                callbackback(&clock_data);
-            } else if *pubkey == EpochSchedule::id() {
-                callbackback(&bincode::serialize(&EpochSchedule::default()).unwrap());
-            } else if *pubkey == Rent::id() {
-                callbackback(&bincode::serialize(&Rent::default()).unwrap());
-            } else if *pubkey == last_restart_slot::id() {
-                let slot_val = 5000_u64;
-                callbackback(&bincode::serialize(&slot_val).unwrap());
-            }
-        });
-
-    execute_fixture_as_instr(
-        &mock_bank,
-        &batch_processor,
-        transactions[0].message(),
-        compute_budget,
-        output,
-        filename,
-        input.cu_avail,
-    );
-}
-
-fn execute_fixture_as_instr(
-    mock_bank: &MockBankCallback,
-    batch_processor: &TransactionBatchProcessor<MockForkGraph>,
-    sanitized_message: &SanitizedMessage,
-    compute_budget: SVMTransactionExecutionBudget,
-    output: &InstrEffects,
-    filename: OsString,
-    cu_avail: u64,
-) {
-    let rent = if let Ok(rent) = batch_processor.sysvar_cache().get_rent() {
-        (*rent).clone()
-    } else {
-        Rent::default()
-    };
-
-    let transaction_accounts: Vec<TransactionAccount> = sanitized_message
-        .account_keys()
-        .iter()
-        .map(|key| (*key, mock_bank.get_account_shared_data(key).unwrap()))
-        .collect();
-
-    let mut transaction_context = TransactionContext::new(
-        transaction_accounts,
-        rent,
-        compute_budget.max_instruction_stack_depth,
-        compute_budget.max_instruction_trace_length,
-    );
-    transaction_context.set_remove_accounts_executable_flag_checks(false);
-
-    let mut loaded_programs = ProgramCacheForTxBatch::new(
-        42,
-        batch_processor
-            .program_cache
-            .read()
-            .unwrap()
-            .environments
-            .clone(),
-        None,
-        2,
-    );
-
-    let program_idx = sanitized_message.instructions()[0].program_id_index as usize;
-    let program_id = *sanitized_message.account_keys().get(program_idx).unwrap();
-
-    let loaded_program = program_loader::load_program_with_pubkey(
-        mock_bank,
-        &batch_processor.get_environments_for_epoch(2).unwrap(),
-        &program_id,
-        42,
-        &mut ExecuteTimings::default(),
-        false,
-    )
-    .unwrap();
-
-    loaded_programs.replenish(program_id, loaded_program);
-    loaded_programs.replenish(
-        solana_system_program::id(),
-        Arc::new(ProgramCacheEntry::new_builtin(
-            0u64,
-            0usize,
-            solana_system_program::system_processor::Entrypoint::vm,
-        )),
-    );
-
-    let log_collector = LogCollector::new_ref();
-
-    let sysvar_cache = &batch_processor.sysvar_cache();
-    #[allow(deprecated)]
-    let (blockhash, lamports_per_signature) = batch_processor
-        .sysvar_cache()
-        .get_recent_blockhashes()
-        .ok()
-        .and_then(|x| (*x).last().cloned())
-        .map(|x| (x.blockhash, x.fee_calculator.lamports_per_signature))
-        .unwrap_or_default();
-
-    let env_config = EnvironmentConfig::new(
-        blockhash,
-        lamports_per_signature,
-        mock_bank,
-        &mock_bank.feature_set,
-        sysvar_cache,
-    );
-
-    let mut invoke_context = InvokeContext::new(
-        &mut transaction_context,
-        &mut loaded_programs,
-        env_config,
-        Some(log_collector.clone()),
-        compute_budget,
-        SVMTransactionExecutionCost::default(),
-    );
-
-    invoke_context
-        .prepare_next_top_level_instruction(
-            sanitized_message,
-            &SVMInstruction::from(&sanitized_message.instructions()[0]),
-            vec![program_idx as IndexOfAccount],
-        )
-        .expect("Failed to configure instruction");
-    let mut compute_units_consumed = 0u64;
-    let mut timings = ExecuteTimings::default();
-    let result = invoke_context.process_instruction(&mut compute_units_consumed, &mut timings);
-
-    if output.result == 0 {
-        assert!(
-            result.is_ok(),
-            "Instruction execution was NOT successful, but should have been: {filename:?}"
-        );
-    } else {
-        assert!(
-            result.is_err(),
-            "Instruction execution was successful, but should NOT have been: {filename:?}"
-        );
-        return;
-    }
-
-    let ExecutionRecord {
-        accounts,
-        return_data,
-        ..
-    } = transaction_context.into();
-
-    verify_accounts_and_data(
-        &accounts,
-        output,
-        compute_units_consumed,
-        cu_avail,
-        &return_data.data,
-        filename,
-    );
-}
-
-fn verify_accounts_and_data(
-    accounts: &[TransactionAccount],
-    output: &InstrEffects,
-    consumed_units: u64,
-    cu_avail: u64,
-    return_data: &Vec<u8>,
-    filename: OsString,
-) {
-    // The input created by firedancer is malformed in that there may be repeated accounts in the
-    // instruction execution output. This happens because the set system program as the program ID,
-    // as pass it as an account to be modified in the instruction.
-    let mut idx_map: HashMap<Pubkey, Vec<usize>> = HashMap::new();
-    for (idx, item) in accounts.iter().enumerate() {
-        match idx_map.entry(item.0) {
-            Entry::Occupied(mut this) => {
-                this.get_mut().push(idx);
-            }
-            Entry::Vacant(this) => {
-                this.insert(vec![idx]);
-            }
-        }
-    }
-
-    for item in &output.modified_accounts {
-        let pubkey = Pubkey::new_from_array(item.address.clone().try_into().unwrap());
-        let indexes = *idx_map
-            .get(&pubkey)
-            .as_ref()
-            .expect("Account not in expected results");
-
-        let mut error: Option<String> = Some("err".to_string());
-        for idx in indexes {
-            let received_data = &accounts[*idx].1;
-            let check_result = check_account(received_data, item, &filename);
-
-            if error.is_some() && check_result.is_none() {
-                // If at least one of the accounts pass the check, we have no error.
-                error = None;
-            } else if error.is_some() && check_result.is_some() {
-                error = check_result;
-            }
-        }
-
-        if let Some(error) = error {
-            panic!("{}", error);
-        }
-    }
-
-    assert_eq!(
-        consumed_units,
-        cu_avail.saturating_sub(output.cu_avail),
-        "Execution units differs in case: {filename:?}"
-    );
-
-    if return_data.is_empty() {
-        assert!(output.return_data.is_empty());
-    } else {
-        assert_eq!(&output.return_data, return_data);
-    }
-}
-
-fn check_account(
-    received: &AccountSharedData,
-    expected: &AcctState,
-    filename: &OsString,
-) -> Option<String> {
-    macro_rules! format_args {
-        ($received:expr, $expected:expr) => {
-            format!("received: {:?}\nexpected: {:?}", $received, $expected).as_str()
-        };
-    }
-
-    if received.lamports() != expected.lamports {
-        return Some(
-            format!("Lamports differ in case: {filename:?}\n")
-                + format_args!(received.lamports(), expected.lamports),
-        );
-    }
-
-    if received.data() != expected.data.as_slice() {
-        return Some(
-            format!("Account data differs in case: {filename:?}\n")
-                + format_args!(received.data(), expected.data.as_slice()),
-        );
-    }
-
-    let expected_owner = Pubkey::new_from_array(expected.owner.clone().try_into().unwrap());
-    if received.owner() != &expected_owner {
-        return Some(
-            format!("Account owner differs in case: {filename:?}\n")
-                + format_args!(received.owner(), expected_owner),
-        );
-    }
-
-    if received.executable() != expected.executable {
-        return Some(
-            format!("Executable boolean differs in case: {filename:?}\n")
-                + format_args!(received.executable(), expected.executable),
-        );
-    }
-
-    // u64::MAX means we are not considering the epoch
-    if received.rent_epoch() != u64::MAX
-        && expected.rent_epoch != u64::MAX
-        && received.rent_epoch() != expected.rent_epoch
-    {
-        return Some(
-            format!("Rent epoch differs in case: {filename:?}\n")
-                + format_args!(received.rent_epoch(), expected.rent_epoch),
-        );
-    }
-
-    None
-}

+ 0 - 250
svm/tests/transaction_builder.rs

@@ -1,250 +0,0 @@
-use {
-    agave_reserved_account_keys::ReservedAccountKeys,
-    solana_hash::Hash,
-    solana_instruction::AccountMeta,
-    solana_message::{
-        compiled_instruction::CompiledInstruction,
-        v0::{self, LoadedAddresses, MessageAddressTableLookup},
-        AddressLoader, AddressLoaderError, Message, MessageHeader, VersionedMessage,
-    },
-    solana_pubkey::Pubkey,
-    solana_signature::Signature,
-    solana_transaction::{
-        sanitized::SanitizedTransaction,
-        versioned::{sanitized::SanitizedVersionedTransaction, VersionedTransaction},
-    },
-    solana_transaction_error::TransactionError,
-    std::collections::{HashMap, HashSet},
-};
-
-#[derive(Default)]
-pub struct SanitizedTransactionBuilder {
-    instructions: Vec<InnerInstruction>,
-    num_required_signatures: u8,
-    num_readonly_signed_accounts: u8,
-    num_readonly_unsigned_accounts: u8,
-    signed_readonly_accounts: Vec<(Pubkey, Signature)>,
-    signed_mutable_accounts: Vec<(Pubkey, Signature)>,
-    unsigned_readonly_accounts: Vec<Pubkey>,
-    unsigned_mutable_accounts: Vec<Pubkey>,
-}
-
-#[derive(PartialEq, Eq, Hash, Clone)]
-enum AccountType {
-    Readonly,
-    Writable,
-    SignerReadonly,
-    SignerWritable,
-}
-
-struct InnerInstruction {
-    program_id: Pubkey,
-    accounts: Vec<(Pubkey, AccountType)>,
-    data: Vec<u8>,
-}
-
-#[derive(Clone)]
-struct MockLoader {}
-
-// This implementation is only necessary if one is using account table lookups.
-impl AddressLoader for MockLoader {
-    fn load_addresses(
-        self,
-        _lookups: &[MessageAddressTableLookup],
-    ) -> Result<LoadedAddresses, AddressLoaderError> {
-        Ok(LoadedAddresses {
-            writable: vec![],
-            readonly: vec![],
-        })
-    }
-}
-
-impl SanitizedTransactionBuilder {
-    pub fn create_instruction(
-        &mut self,
-        program_id: Pubkey,
-        // The fee payer and the program id shall not appear in the accounts vector
-        accounts: Vec<AccountMeta>,
-        signatures: HashMap<Pubkey, Signature>,
-        data: Vec<u8>,
-    ) {
-        let mut instruction = InnerInstruction {
-            program_id,
-            accounts: Vec::new(),
-            data,
-        };
-
-        for item in &accounts {
-            let acc_type = match (item.is_signer, item.is_writable) {
-                (true, true) => {
-                    self.num_required_signatures = self.num_required_signatures.saturating_add(1);
-                    self.signed_mutable_accounts
-                        .push((item.pubkey, signatures[&item.pubkey]));
-                    AccountType::SignerWritable
-                }
-                (true, false) => {
-                    self.num_required_signatures = self.num_required_signatures.saturating_add(1);
-                    self.num_readonly_signed_accounts =
-                        self.num_readonly_signed_accounts.saturating_add(1);
-                    self.signed_readonly_accounts
-                        .push((item.pubkey, signatures[&item.pubkey]));
-                    AccountType::SignerReadonly
-                }
-                (false, true) => {
-                    self.unsigned_mutable_accounts.push(item.pubkey);
-                    AccountType::Writable
-                }
-                (false, false) => {
-                    self.num_readonly_unsigned_accounts =
-                        self.num_readonly_unsigned_accounts.saturating_add(1);
-                    self.unsigned_readonly_accounts.push(item.pubkey);
-                    AccountType::Readonly
-                }
-            };
-            instruction.accounts.push((item.pubkey, acc_type));
-        }
-
-        self.instructions.push(instruction);
-    }
-
-    pub fn build(
-        &mut self,
-        block_hash: Hash,
-        fee_payer: (Pubkey, Signature),
-        v0_message: bool,
-        ignore_reserved_accounts: bool,
-    ) -> Result<SanitizedTransaction, TransactionError> {
-        let mut account_keys = Vec::with_capacity(
-            self.signed_mutable_accounts
-                .len()
-                .saturating_add(self.signed_readonly_accounts.len())
-                .saturating_add(self.unsigned_mutable_accounts.len())
-                .saturating_add(self.unsigned_readonly_accounts.len())
-                .saturating_add(1),
-        );
-        let header = MessageHeader {
-            // The fee payer always requires a signature so +1
-            num_required_signatures: self.num_required_signatures.saturating_add(1),
-            num_readonly_signed_accounts: self.num_readonly_signed_accounts,
-            // The program id is always a readonly unsigned account
-            num_readonly_unsigned_accounts: self.num_readonly_unsigned_accounts.saturating_add(1),
-        };
-
-        let mut compiled_instructions = Vec::new();
-
-        let mut signatures = Vec::with_capacity(
-            self.signed_mutable_accounts
-                .len()
-                .saturating_add(self.signed_readonly_accounts.len())
-                .saturating_add(1),
-        );
-        let mut positions: HashMap<(Pubkey, AccountType), usize> = HashMap::new();
-
-        account_keys.push(fee_payer.0);
-        signatures.push(fee_payer.1);
-
-        let mut positions_lambda = |key: &Pubkey, ty: AccountType| {
-            positions.insert((*key, ty), account_keys.len());
-            account_keys.push(*key);
-        };
-
-        self.signed_mutable_accounts
-            .iter()
-            .for_each(|(key, signature)| {
-                positions_lambda(key, AccountType::SignerWritable);
-                signatures.push(*signature);
-            });
-        self.signed_readonly_accounts
-            .iter()
-            .for_each(|(key, signature)| {
-                positions_lambda(key, AccountType::SignerReadonly);
-                signatures.push(*signature);
-            });
-        self.unsigned_mutable_accounts
-            .iter()
-            .for_each(|key| positions_lambda(key, AccountType::Writable));
-        self.unsigned_readonly_accounts
-            .iter()
-            .for_each(|key| positions_lambda(key, AccountType::Readonly));
-
-        let instructions = self.clean_up();
-
-        for item in instructions {
-            let accounts = item
-                .accounts
-                .iter()
-                .map(|key| positions[key] as u8)
-                .collect::<Vec<u8>>();
-            let instruction = CompiledInstruction {
-                program_id_index: push_and_return_index(item.program_id, &mut account_keys),
-                accounts,
-                data: item.data,
-            };
-
-            compiled_instructions.push(instruction);
-        }
-
-        let message = if v0_message {
-            let message = v0::Message {
-                header,
-                account_keys,
-                recent_blockhash: block_hash,
-                instructions: compiled_instructions,
-                address_table_lookups: vec![],
-            };
-
-            VersionedMessage::V0(message)
-        } else {
-            let message = Message {
-                header,
-                account_keys,
-                recent_blockhash: block_hash,
-                instructions: compiled_instructions,
-            };
-
-            VersionedMessage::Legacy(message)
-        };
-
-        let transaction = VersionedTransaction {
-            signatures,
-            message,
-        };
-
-        let sanitized_versioned_transaction =
-            SanitizedVersionedTransaction::try_new(transaction).unwrap();
-
-        let loader = MockLoader {};
-
-        let reserved_active = &ReservedAccountKeys::new_all_activated().active;
-        let all_inactive = HashSet::new();
-        SanitizedTransaction::try_new(
-            sanitized_versioned_transaction,
-            Hash::new_unique(),
-            false,
-            loader,
-            if ignore_reserved_accounts {
-                &all_inactive
-            } else {
-                reserved_active
-            },
-        )
-    }
-
-    fn clean_up(&mut self) -> Vec<InnerInstruction> {
-        let instructions = std::mem::take(&mut self.instructions);
-        self.num_required_signatures = 0;
-        self.num_readonly_signed_accounts = 0;
-        self.num_readonly_unsigned_accounts = 0;
-        self.signed_mutable_accounts.clear();
-        self.signed_readonly_accounts.clear();
-        self.unsigned_mutable_accounts.clear();
-        self.unsigned_readonly_accounts.clear();
-
-        instructions
-    }
-}
-
-fn push_and_return_index(value: Pubkey, vector: &mut Vec<Pubkey>) -> u8 {
-    vector.push(value);
-    vector.len().saturating_sub(1) as u8
-}