// file: crates/ksp-job-backfill-lib/tests/http_block_material.rs // version: 2 //! Cross-layer canary for the future Worker-owned HTTP block adapter without changing production ownership. fn pool_for_url(url: &str) -> ksp_core_lib::Result { let endpoint_url = match ksp_onchain_transport_lib::HttpEndpointUrl::parse(url) { Ok(endpoint_url) => endpoint_url, Err(error) => return Err(error), }; let role = ksp_onchain_transport_lib::HttpEndpointRoleSettings::new( ksp_onchain_transport_lib::HttpRoleName::new("default"), true, std::vec![ksp_onchain_transport_lib::HttpRequestKind::wildcard()], 10, ksp_onchain_transport_lib::HttpRoleLimits::new( std::option::Option::None, std::option::Option::None, std::option::Option::None, std::option::Option::None, ), ); let endpoint = ksp_onchain_transport_lib::HttpEndpointSettings::new( "http-block-fixture", true, ksp_onchain_transport_lib::HttpProviderName::new("fixture-provider"), ksp_onchain_transport_lib::HttpClusterName::new("devnet"), endpoint_url, std::time::Duration::from_secs(1), std::time::Duration::from_secs(1), std::option::Option::Some(1), std::vec![role], ); return ksp_onchain_transport_lib::HttpTransportPool::new(ksp_onchain_transport_lib::HttpTransportSettings::new( std::vec![endpoint], ksp_onchain_transport_lib::HttpRetrySettings::new(0, std::time::Duration::from_millis(1), std::time::Duration::from_millis(1)), )); } fn serve_once(body: &'static str) -> std::io::Result<(std::string::String, std::thread::JoinHandle>)> { let listener = match std::net::TcpListener::bind("127.0.0.1:0") { Ok(listener) => listener, Err(error) => return Err(error), }; let address = match listener.local_addr() { Ok(address) => address, Err(error) => return Err(error), }; let handle = std::thread::spawn(move || { let (mut stream, _) = match listener.accept() { Ok(accepted) => accepted, Err(error) => return Err(error), }; let mut bytes = std::vec::Vec::new(); let mut buffer = [0_u8; 1024]; loop { let count = match std::io::Read::read(&mut stream, &mut buffer) { Ok(count) => count, Err(error) => return Err(error), }; if count == 0 { break; } bytes.extend_from_slice(&buffer[..count]); if bytes.windows(4).any(|window| return window == b"\r\n\r\n") { break; } } let response = format!("HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nContent-Length: {}\r\nConnection: close\r\n\r\n{}", body.len(), body); if let Err(error) = std::io::Write::write_all(&mut stream, response.as_bytes()) { return Err(error); } return Ok(()); }); return Ok((format!("http://{address}"), handle)); } fn map_meta(field: &ksp_onchain_transport_lib::SolanaWireField) -> ksp_raw_transaction_lib::RawTransactionWireField { return match field { ksp_onchain_transport_lib::SolanaWireField::Omitted => ksp_raw_transaction_lib::RawTransactionWireField::Omitted, ksp_onchain_transport_lib::SolanaWireField::Null => ksp_raw_transaction_lib::RawTransactionWireField::Null, ksp_onchain_transport_lib::SolanaWireField::Value(value) => ksp_raw_transaction_lib::RawTransactionWireField::Value(value.clone()), }; } fn map_version( field: &ksp_onchain_transport_lib::SolanaWireField, ) -> ksp_raw_transaction_lib::RawTransactionWireField { return match field { ksp_onchain_transport_lib::SolanaWireField::Omitted => ksp_raw_transaction_lib::RawTransactionWireField::Omitted, ksp_onchain_transport_lib::SolanaWireField::Null => ksp_raw_transaction_lib::RawTransactionWireField::Null, ksp_onchain_transport_lib::SolanaWireField::Value(ksp_onchain_transport_lib::SolanaTransactionVersion::Legacy) => { ksp_raw_transaction_lib::RawTransactionWireField::Value(ksp_raw_transaction_lib::RawTransactionVersion::Legacy) }, ksp_onchain_transport_lib::SolanaWireField::Value(ksp_onchain_transport_lib::SolanaTransactionVersion::Number(number)) => { ksp_raw_transaction_lib::RawTransactionWireField::Value(ksp_raw_transaction_lib::RawTransactionVersion::Number(*number)) }, }; } #[tokio::test(flavor = "current_thread")] async fn pre_004_http_observed_block_projects_each_base64_transaction_to_common_material_without_new_production_edge() { const BODY: &str = concat!( "{\"jsonrpc\":\"2.0\",\"result\":{\"previousBlockhash\":\"previous\",\"blockhash\":\"block\",\"parentSlot\":430000122,", "\"rewards\":[],\"numRewardPartitions\":0,\"blockTime\":1787072400,\"blockHeight\":410000000,", "\"transactions\":[{\"transaction\":[\"AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAA\",\"base64\"],\"meta\":{\"err\":null,\"fee\":5000},\"version\":\"legacy\"},", "{\"transaction\":[\"AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEA\",", "\"base64\"],\"meta\":{\"err\":null,\"fee\":6000},\"version\":0}]},\"id\":1}", ); let (url, handle) = serve_once(BODY).expect("fixture server must start"); let pool = pool_for_url(url.as_str()).expect("fixture pool must build"); let config = ksp_onchain_transport_lib::SolanaGetBlockConfig::new( std::option::Option::Some(ksp_onchain_transport_lib::SolanaCommitment::Confirmed), std::option::Option::Some(ksp_onchain_transport_lib::SolanaTransactionEncoding::Base64), std::option::Option::Some(ksp_onchain_transport_lib::SolanaTransactionDetails::Full), std::option::Option::Some(0), std::option::Option::Some(false), ); let observed = pool .get_block_observed(&ksp_onchain_transport_lib::HttpRoleName::new("default"), 430_000_123, std::option::Option::Some(&config)) .await .expect("observed block fixture must succeed"); assert_eq!(observed.endpoint_name(), "http-block-fixture"); assert_eq!(observed.provider().as_str(), "fixture-provider"); let block = observed.value().as_ref().expect("fixture block must be present"); let transactions = block.transactions().value().expect("fixture transactions must be present"); assert_eq!(transactions.len(), 2); let network = ksp_store_lib::RawNetworkId::new("devnet").expect("fixture network must be valid"); let expected_signatures = [[0_u8; 64], [1_u8; 64]]; for (index, transaction) in transactions.iter().enumerate() { let (data, meta, version) = match transaction.transaction() { ksp_onchain_transport_lib::SolanaEncodedTransaction::Binary { data, encoding: ksp_onchain_transport_lib::SolanaTransactionBinaryEncoding::Base64, } => (data.as_str(), map_meta(transaction.meta()), map_version(transaction.version())), _ => panic!("fixture must remain full Base64 transaction material"), }; let transaction_index = u32::try_from(index).expect("fixture transaction index must fit u32"); let material = ksp_raw_transaction_lib::RawTransactionMaterial::binary_base64_with_embedded_signature( network.clone(), 430_000_123, block.block_time(), data, meta, version, ksp_raw_transaction_lib::RawTransactionWireField::Value(transaction_index), ) .expect("HTTP block material must map to common RAW material"); let raw = ksp_raw_transaction_lib::canonicalize_raw_transaction(material).expect("mapped HTTP block material must canonicalize"); assert_eq!(raw.reference().signature().as_bytes(), &expected_signatures[index]); assert_eq!(raw.slot(), 430_000_123); assert_eq!(raw.block_time().map(|value| return value.unix_millis()), std::option::Option::Some(1_787_072_400_000)); assert!(raw.payload().bytes().ends_with(format!("\"transactionIndex\":{transaction_index}}}").as_bytes())); } handle.join().expect("fixture server must join").expect("fixture server must complete successfully"); return; }