lssa/integration_tests/tests/block_size_limit.rs
Sergio Chouhy 4bcffafe27 refactor!: rename nssa crate to lee
BREAKING CHANGE:
- Crate `nssa` renamed to `lee`; update `Cargo.toml` dependencies from `nssa = { workspace = true }` to `lee = { workspace = true }`.
- Crate `nssa_core` renamed to `lee_core`; update similarly.
- Crate `key_protocol` moved under `lee`; update `Cargo.toml` dependencies from `key_protocol = { workspace = true }` to `lee_key_protocol = { workspace = true }`.
- Type `NSSATransaction` (in `common`) renamed to `LeeTransaction`.
- Error type `nssa::error::NssaError` renamed to `lee::error::LeeError`.
- Error type `nssa_core::error::NssaCoreError` renamed to `lee_core::error::LeeCoreError`.
- All `use nssa::` and `use nssa_core::` import paths must be updated to `use lee::` and `use lee_core::` respectively.
- Guest programs must replace `write_nssa_outputs` with `write_lee_outputs`.
- The sequencer RocksDB column family for the chain state was renamed. Existing databases are incompatible and must be wiped before running the new version.
- Domain separators updated: `"NSSA_seed"` → `"LEE_seed"` (key derivation), `"NSSA/v0.2/KDF-SHA256/"` → `"LEE/v0.2/KDF-SHA256/"` (encryption KDF), `"/NSSA/v0.2/AccountId/PDA/"` →
  `"/LEE/v0.2/AccountId/PDA/"` (public PDA address derivation). All previously derived keys, encrypted outputs, and public PDA addresses are invalidated.
2026-06-01 17:11:42 -03:00

203 lines
6.4 KiB
Rust

#![expect(
clippy::as_conversions,
clippy::tests_outside_test_module,
reason = "We don't care about these in tests"
)]
use std::time::Duration;
use anyhow::Result;
use bytesize::ByteSize;
use common::transaction::LeeTransaction;
use integration_tests::{
TIME_TO_WAIT_FOR_BLOCK_SECONDS, TestContext, config::SequencerPartialConfig,
};
use lee::program::Program;
use sequencer_service_rpc::RpcClient as _;
use tokio::test;
#[test]
async fn reject_oversized_transaction() -> Result<()> {
let ctx = TestContext::builder()
.with_sequencer_partial_config(SequencerPartialConfig {
max_num_tx_in_block: 100,
max_block_size: ByteSize::mib(1),
mempool_max_size: 1000,
block_create_timeout: Duration::from_secs(10),
})
.build()
.await?;
// Create a transaction that's definitely too large
// Block size is 1 MiB (1,048,576 bytes), minus ~200 bytes for header = ~1,048,376 bytes max tx
// Create a 1.1 MiB binary to ensure it exceeds the limit
let oversized_binary = vec![0_u8; 1100 * 1024]; // 1.1 MiB binary
let message = lee::program_deployment_transaction::Message::new(oversized_binary);
let tx = lee::ProgramDeploymentTransaction::new(message);
// Try to submit the transaction and expect an error
let result = ctx
.sequencer_client()
.send_transaction(LeeTransaction::ProgramDeployment(tx))
.await;
assert!(
result.is_err(),
"Expected error when submitting oversized transaction"
);
let err = result.unwrap_err();
let err_str = format!("{err:?}");
// Check if the error contains information about transaction being too large
assert!(
err_str.contains("TransactionTooLarge") || err_str.contains("too large"),
"Expected TransactionTooLarge error, got: {err_str}"
);
Ok(())
}
#[test]
async fn accept_transaction_within_limit() -> Result<()> {
let ctx = TestContext::builder()
.with_sequencer_partial_config(SequencerPartialConfig {
max_num_tx_in_block: 100,
max_block_size: ByteSize::mib(1),
mempool_max_size: 1000,
block_create_timeout: Duration::from_secs(10),
})
.build()
.await?;
// Create a small program deployment that should fit
let small_binary = vec![0_u8; 1024]; // 1 KiB binary
let message = lee::program_deployment_transaction::Message::new(small_binary);
let tx = lee::ProgramDeploymentTransaction::new(message);
// This should succeed
let result = ctx
.sequencer_client()
.send_transaction(LeeTransaction::ProgramDeployment(tx))
.await;
assert!(
result.is_ok(),
"Expected successful submission of small transaction, got error: {:?}",
result.as_ref().unwrap_err()
);
Ok(())
}
#[test]
async fn transaction_deferred_to_next_block_when_current_full() -> Result<()> {
let manifest_dir = env!("CARGO_MANIFEST_DIR");
let artifacts_dir =
std::path::PathBuf::from(manifest_dir).join("../artifacts/test_program_methods");
let burner_bytecode = std::fs::read(artifacts_dir.join("burner.bin"))?;
let chain_caller_bytecode = std::fs::read(artifacts_dir.join("chain_caller.bin"))?;
// Calculate block size to fit only one of the two transactions, leaving some room for headers
// (e.g., 10 KiB)
let max_program_size = burner_bytecode.len().max(chain_caller_bytecode.len());
let block_size = ByteSize::b((max_program_size + 10 * 1024) as u64);
let ctx = TestContext::builder()
.with_sequencer_partial_config(SequencerPartialConfig {
max_num_tx_in_block: 100,
max_block_size: block_size,
mempool_max_size: 1000,
block_create_timeout: Duration::from_secs(10),
})
.build()
.await?;
let burner_id = Program::new(burner_bytecode.clone())?.id();
let chain_caller_id = Program::new(chain_caller_bytecode.clone())?.id();
let initial_block_height = ctx.sequencer_client().get_last_block_id().await?;
// Submit both program deployments
ctx.sequencer_client()
.send_transaction(LeeTransaction::ProgramDeployment(
lee::ProgramDeploymentTransaction::new(
lee::program_deployment_transaction::Message::new(burner_bytecode),
),
))
.await?;
ctx.sequencer_client()
.send_transaction(LeeTransaction::ProgramDeployment(
lee::ProgramDeploymentTransaction::new(
lee::program_deployment_transaction::Message::new(chain_caller_bytecode),
),
))
.await?;
// Wait for first block
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
let block1 = ctx
.sequencer_client()
.get_block(initial_block_height + 1)
.await?
.unwrap();
// Check which program is in block 1
let get_program_ids = |block: &common::block::Block| -> Vec<lee::ProgramId> {
block
.body
.transactions
.iter()
.filter_map(|tx| {
if let LeeTransaction::ProgramDeployment(deployment) = tx {
let bytecode = deployment.message.clone().into_bytecode();
Program::new(bytecode).ok().map(|p| p.id())
} else {
None
}
})
.collect()
};
let block1_program_ids = get_program_ids(&block1);
// First program should be in block 1, but not both due to block size limit
assert_eq!(
block1_program_ids.len(),
1,
"Expected exactly one program deployment in block 1"
);
assert_eq!(
block1_program_ids[0], burner_id,
"Expected burner program to be deployed in block 1"
);
// Wait for second block
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
let block2 = ctx
.sequencer_client()
.get_block(initial_block_height + 2)
.await?
.unwrap();
let block2_program_ids = get_program_ids(&block2);
// The other program should be in block 2
assert_eq!(
block2_program_ids.len(),
1,
"Expected exactly one program deployment in block 2"
);
assert_eq!(
block2_program_ids[0], chain_caller_id,
"Expected chain_caller program to be deployed in block 2"
);
Ok(())
}