Merge 51e4141a93a41f5b9672596e68ee98685deb0887 into fe4c7a96da393808946d0ffdb9ef44a5da9d8ef0

This commit is contained in:
Ricardo Guilherme Schmidt 2026-07-02 20:30:10 +00:00 committed by GitHub
commit a808b649ff
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 1398 additions and 12 deletions

View File

@ -125,6 +125,38 @@ jobs:
env: env:
RISC0_DEV_MODE: 1 RISC0_DEV_MODE: 1
local-sequencer-integration-tests:
name: Local Sequencer Integration Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: ./.github/actions/install-risc0
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@master
with:
toolchain: "1.94.0"
- name: Cache cargo registry
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
~/.cache/logos-scaffold
target
key: ${{ runner.os }}-cargo-scaffold-test-node-${{ hashFiles('**/Cargo.lock', 'scaffold.toml') }}
restore-keys: |
${{ runner.os }}-cargo-scaffold-test-node-
${{ runner.os }}-cargo-
- name: Local sequencer integration tests
run: cargo test -p integration_tests --features local-sequencer-tests -- --nocapture
env:
RISC0_BUILD_DEBUG: 0
RISC0_DEV_MODE: 1
RUST_TEST_THREADS: 1
build-programs: build-programs:
name: Build Guest Programs name: Build Guest Programs
runs-on: ubuntu-latest runs-on: ubuntu-latest

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
target/ target/
.scaffold/
*.bin *.bin
**/*/result **/*/result

679
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -67,10 +67,17 @@ RISC0_DEV_MODE=1 cargo test -p token_program -p amm_program -p ata_program -p st
# Run integration tests (dev mode skips ZK proof generation) # Run integration tests (dev mode skips ZK proof generation)
RISC0_DEV_MODE=1 cargo test -p integration_tests RISC0_DEV_MODE=1 cargo test -p integration_tests
# Run integration tests through scaffold-managed local sequencer test nodes.
# RISC0_BUILD_DEBUG=0 keeps embedded guest ELFs on the release profile while
# RISC0_DEV_MODE=1 skips proof generation.
RISC0_BUILD_DEBUG=0 RISC0_DEV_MODE=1 RUST_TEST_THREADS=1 cargo test -p integration_tests --features local-sequencer-tests -- --nocapture
# Run all tests # Run all tests
make test make test
``` ```
The `local-sequencer-tests` feature mirrors the suite through scaffold-managed test nodes configured by `scaffold.toml`.
Integration tests live in `programs/integration_tests/tests/` and cover `token`, `amm`, and `ata` programs end-to-end through the zkVM using `RISC0_DEV_MODE=1` to skip proof generation. Each test file corresponds to a program: Integration tests live in `programs/integration_tests/tests/` and cover `token`, `amm`, and `ata` programs end-to-end through the zkVM using `RISC0_DEV_MODE=1` to skip proof generation. Each test file corresponds to a program:
- `programs/integration_tests/tests/token.rs` - `programs/integration_tests/tests/token.rs`

View File

@ -6,10 +6,22 @@ edition = "2021"
[lints] [lints]
workspace = true workspace = true
[features]
local-sequencer-tests = [
"dep:base64",
"dep:borsh",
"dep:logos-scaffold",
"dep:rocksdb",
]
[dependencies] [dependencies]
nssa = { workspace = true } nssa = { workspace = true }
nssa_core = { workspace = true, features = ["host", "test_utils"] } nssa_core = { workspace = true, features = ["host", "test_utils"] }
clock_core = { git = "https://github.com/logos-blockchain/logos-execution-zone.git", tag = "v0.2.0-rc6" } clock_core = { git = "https://github.com/logos-blockchain/logos-execution-zone.git", tag = "v0.2.0-rc6" }
base64 = { version = "0.22", optional = true }
borsh = { workspace = true, optional = true }
logos-scaffold = { git = "https://github.com/logos-co/scaffold.git", rev = "9e4d148d08fd86213d3becc17d6863895048e9cb", package = "logos-scaffold", optional = true }
rocksdb = { version = "0.24.0", default-features = false, features = ["snappy", "bindgen-runtime"], optional = true }
amm_core = { workspace = true } amm_core = { workspace = true }
token_core = { workspace = true } token_core = { workspace = true }
ata_core = { workspace = true } ata_core = { workspace = true }

View File

@ -1 +1,8 @@
#[cfg(feature = "local-sequencer-tests")]
mod local_sequencer;
#[cfg(feature = "local-sequencer-tests")]
pub use local_sequencer::TestState;
#[cfg(not(feature = "local-sequencer-tests"))]
pub type TestState = nssa::V03State;

View File

@ -0,0 +1,635 @@
use std::{
env,
error::Error,
fmt::Write as _,
fs, io,
path::{Path, PathBuf},
sync::OnceLock,
time::{Duration, SystemTime, UNIX_EPOCH},
};
use base64::{engine::general_purpose::STANDARD as BASE64_STANDARD, Engine as _};
use borsh::BorshSerialize;
use logos_scaffold::api::{
testnode::{
AccountValue, PinOverrides, ProofValue, ReadAt, RejectionPhase, TestNode, TestNodeClient,
TestNodeConfig, TransactionBytes, TransactionOutcome, WaitOptions,
},
Project,
};
use nssa::{
error::LeeError, privacy_preserving_transaction::PrivacyPreservingTransaction,
program_deployment_transaction::ProgramDeploymentTransaction,
public_transaction::PublicTransaction,
};
use nssa_core::{
account::{Account, AccountId},
Commitment, MembershipProof, Nullifier, Timestamp,
};
use rocksdb::{ColumnFamilyDescriptor, DBWithThreadMode, MultiThreaded, Options};
type DynError = Box<dyn Error + Send + Sync>;
type DynResult<T> = Result<T, DynError>;
const TEST_NODE_CIRCUITS_VERSION_ENV: &str = "LOGOS_SCAFFOLD_TEST_NODE_CIRCUITS_VERSION";
const RISC0_BUILD_DEBUG_ENV: &str = "RISC0_BUILD_DEBUG";
const DEFAULT_CIRCUITS_VERSION: &str = "0.4.2";
const CF_BLOCK_NAME: &str = "cf_block";
const CF_META_NAME: &str = "cf_meta";
const CF_NSSA_STATE_NAME: &str = "cf_nssa_state";
const DB_NSSA_STATE_KEY: &str = "nssa_state";
const POLL_INTERVAL: Duration = Duration::from_millis(100);
const COMMIT_TIMEOUT: Duration = Duration::from_secs(20);
const HEALTH_TIMEOUT: Duration = Duration::from_secs(60);
pub struct TestState {
inner: nssa::V03State,
sequencer: Option<LocalSequencer>,
dirty: bool,
}
impl TestState {
#[must_use]
pub fn new() -> Self {
Self {
inner: nssa::V03State::new(),
sequencer: None,
dirty: true,
}
}
#[must_use]
pub fn new_with_genesis_accounts(
public_accounts: &[(AccountId, u128)],
private_accounts: Vec<(Commitment, Nullifier)>,
_genesis_timestamp: Timestamp,
) -> Self {
Self {
inner: nssa::V03State::new()
.with_public_account_balances(public_accounts.iter().copied())
.with_private_accounts(private_accounts),
sequencer: None,
dirty: true,
}
}
pub fn transition_from_public_transaction(
&mut self,
tx: &PublicTransaction,
block_id: u64,
timestamp: Timestamp,
) -> Result<(), LeeError> {
let rpc_tx = RpcTransaction::Public(Box::new(tx.clone()));
match self.mirror_transaction(&rpc_tx) {
MirrorOutcome::Committed(context) => {
let mut next = self.inner.clone();
next.transition_from_public_transaction(tx, context.block_id, context.timestamp)
.unwrap_or_else(|err| {
panic!(
"local replay rejected public transaction committed by sequencer at \
block {}: {err}",
context.block_id
)
});
self.inner = next;
self.assert_affected_accounts_match(&rpc_tx);
Ok(())
}
MirrorOutcome::NotCommitted(rejection) => {
let mut expected = self.inner.clone();
let result = if let Some(context) = rejection.validation_context {
expected.transition_from_public_transaction(
tx,
context.block_id,
context.timestamp,
)
} else {
expected.transition_from_public_transaction(tx, block_id, timestamp)
};
if result.is_ok() {
panic!("local replay accepted public transaction dropped by sequencer");
}
result
}
}
}
pub fn transition_from_privacy_preserving_transaction(
&mut self,
tx: &PrivacyPreservingTransaction,
block_id: u64,
timestamp: Timestamp,
) -> Result<(), LeeError> {
let rpc_tx = RpcTransaction::PrivacyPreserving(Box::new(tx.clone()));
match self.mirror_transaction(&rpc_tx) {
MirrorOutcome::Committed(context) => {
let mut next = self.inner.clone();
next.transition_from_privacy_preserving_transaction(
tx,
context.block_id,
context.timestamp,
)
.unwrap_or_else(|err| {
panic!(
"local replay rejected privacy-preserving transaction committed by \
sequencer at block {}: {err}",
context.block_id
)
});
self.inner = next;
self.assert_affected_accounts_match(&rpc_tx);
Ok(())
}
MirrorOutcome::NotCommitted(rejection) => {
let mut expected = self.inner.clone();
let result = if let Some(context) = rejection.validation_context {
expected.transition_from_privacy_preserving_transaction(
tx,
context.block_id,
context.timestamp,
)
} else {
expected.transition_from_privacy_preserving_transaction(tx, block_id, timestamp)
};
if result.is_ok() {
panic!(
"local replay accepted privacy-preserving transaction dropped by sequencer"
);
}
result
}
}
}
pub fn transition_from_program_deployment_transaction(
&mut self,
tx: &ProgramDeploymentTransaction,
) -> Result<(), LeeError> {
let rpc_tx = RpcTransaction::ProgramDeployment(Box::new(tx.clone()));
match self.mirror_transaction(&rpc_tx) {
MirrorOutcome::Committed(context) => {
let mut next = self.inner.clone();
next.transition_from_program_deployment_transaction(tx)
.unwrap_or_else(|err| {
panic!(
"local replay rejected program deployment committed by sequencer at \
block {}: {err}",
context.block_id
)
});
self.inner = next;
self.assert_affected_accounts_match(&rpc_tx);
Ok(())
}
MirrorOutcome::NotCommitted(_) => {
let mut expected = self.inner.clone();
let result = expected.transition_from_program_deployment_transaction(tx);
if result.is_ok() {
panic!("local replay accepted program deployment dropped by sequencer");
}
result
}
}
}
pub fn force_insert_account(&mut self, account_id: AccountId, account: Account) {
self.inner.force_insert_account(account_id, account);
self.dirty = true;
}
#[must_use]
pub fn get_account_by_id(&self, account_id: AccountId) -> Account {
let account = self.inner.get_account_by_id(account_id);
if !self.dirty {
if let Some(sequencer) = &self.sequencer {
let sequencer_account = sequencer
.get_account_by_id(account_id)
.unwrap_or_else(|err| panic!("local sequencer getAccount failed: {err}"));
assert_eq!(
sequencer_account, account,
"local sequencer account state diverged for {account_id}"
);
}
}
account
}
#[must_use]
pub fn get_proof_for_commitment(&self, commitment: &Commitment) -> Option<MembershipProof> {
let proof = self.inner.get_proof_for_commitment(commitment);
if !self.dirty {
if let Some(sequencer) = &self.sequencer {
let sequencer_proof = sequencer
.get_proof_for_commitment(commitment)
.unwrap_or_else(|err| {
panic!("local sequencer getProofForCommitment failed: {err}")
});
assert_eq!(
sequencer_proof, proof,
"local sequencer commitment proof diverged"
);
}
}
proof
}
fn mirror_transaction(&mut self, tx: &RpcTransaction) -> MirrorOutcome {
let tx_hash = hex_encode(&tx.hash());
let outcome = self
.ensure_sequencer()
.submit_and_wait(tx, COMMIT_TIMEOUT)
.unwrap_or_else(|err| panic!("local sequencer failed to submit {tx_hash}: {err}"));
match outcome {
TransactionOutcome::Committed { block, .. } => {
MirrorOutcome::Committed(ObservedBlock {
block_id: block.block_id,
timestamp: block.timestamp,
})
}
TransactionOutcome::Rejected {
phase: RejectionPhase::Stateless,
..
} => MirrorOutcome::NotCommitted(RejectionContext::precheck()),
TransactionOutcome::Rejected {
phase: RejectionPhase::Stateful,
observed_after_block_id,
..
} => {
let validation_context = observed_after_block_id
.and_then(|block_id| self.sequencer.as_ref()?.block_context(block_id).ok());
MirrorOutcome::NotCommitted(RejectionContext { validation_context })
}
TransactionOutcome::Timeout {
last_observed_block_id,
..
} => {
panic!(
"local sequencer timed out waiting for {tx_hash}; last observed block \
{last_observed_block_id}"
)
}
TransactionOutcome::TransportError { operation, message } => {
panic!(
"local sequencer transport error during {operation} for {tx_hash}: {message}"
)
}
TransactionOutcome::WireMismatch { .. } => {
panic!("local sequencer echoed different transaction bytes for {tx_hash}")
}
}
}
fn ensure_sequencer(&mut self) -> &mut LocalSequencer {
if self.sequencer.is_none() || self.dirty {
self.sequencer = Some(
LocalSequencer::spawn(&self.inner)
.unwrap_or_else(|err| panic!("failed to start local sequencer: {err}")),
);
self.dirty = false;
}
match &mut self.sequencer {
Some(sequencer) => sequencer,
None => unreachable!("local sequencer should be initialized"),
}
}
fn assert_affected_accounts_match(&self, tx: &RpcTransaction) {
let Some(sequencer) = &self.sequencer else {
return;
};
let account_ids = tx.affected_public_account_ids();
let sequencer_accounts = sequencer
.get_accounts_by_id(&account_ids)
.unwrap_or_else(|err| panic!("local sequencer batch getAccount failed: {err}"));
for (account_id, sequencer_account) in account_ids.into_iter().zip(sequencer_accounts) {
let account = self.inner.get_account_by_id(account_id);
assert_eq!(
sequencer_account, account,
"local sequencer account state diverged for {account_id}"
);
}
}
}
enum MirrorOutcome {
Committed(ObservedBlock),
NotCommitted(RejectionContext),
}
struct RejectionContext {
validation_context: Option<ObservedBlock>,
}
impl RejectionContext {
const fn precheck() -> Self {
Self {
validation_context: None,
}
}
}
#[derive(Clone, Copy)]
struct ObservedBlock {
block_id: u64,
timestamp: Timestamp,
}
fn ensure_risc0_dev_mode() -> DynResult<()> {
if let Some(value) = env::var_os("RISC0_DEV_MODE") {
let value = value.to_string_lossy();
if matches!(value.trim(), "0" | "false") {
return Err(io::Error::other(format!(
"RISC0_DEV_MODE={value} disables dev mode, but the local sequencer harness requires it; unset RISC0_DEV_MODE or set it to 1"
))
.into());
}
}
Ok(())
}
fn ensure_release_guest_builds() -> DynResult<()> {
if let Some(value) = env::var_os(RISC0_BUILD_DEBUG_ENV) {
let value = value.to_string_lossy();
if value.trim() == "1" {
return Err(io::Error::other(format!(
"{RISC0_BUILD_DEBUG_ENV}=1 enables debug-profile guest ELFs, but local sequencer tests require release-profile guest ELFs; unset {RISC0_BUILD_DEBUG_ENV} or set it to 0"
))
.into());
}
}
Ok(())
}
struct LocalSequencer {
// Fields drop in declaration order; shut the node down before seed cleanup.
_node: TestNode,
client: TestNodeClient,
_seed_dir: SeedDirGuard,
}
impl LocalSequencer {
fn spawn(state: &nssa::V03State) -> DynResult<Self> {
ensure_risc0_dev_mode()?;
ensure_release_guest_builds()?;
let seed_dir = SeedDirGuard::from_state(state)?;
let config = TestNodeConfig {
state: Some(seed_dir.path().to_path_buf()),
timeout_sec: HEALTH_TIMEOUT.as_secs(),
..Default::default()
};
let node = TestNode::start(scaffold_project(), &config)
.map_err(|err| io::Error::other(format!("scaffold test-node start failed: {err}")))?;
Ok(Self {
client: node.client(),
_node: node,
_seed_dir: seed_dir,
})
}
fn submit_and_wait(
&self,
tx: &RpcTransaction,
timeout: Duration,
) -> DynResult<TransactionOutcome> {
let bytes = TransactionBytes::borsh(borsh::to_vec(tx)?);
Ok(self.client.submit_and_wait(
&bytes,
&WaitOptions {
timeout,
rejection_blocks: 1,
poll_interval: POLL_INTERVAL,
..Default::default()
},
))
}
fn block_context(&self, block_id: u64) -> DynResult<ObservedBlock> {
let block = self.client.block_info(block_id)?.ok_or_else(|| {
io::Error::new(
io::ErrorKind::NotFound,
format!("sequencer block {block_id} was not found"),
)
})?;
Ok(ObservedBlock {
block_id: block.block_id,
timestamp: block.timestamp,
})
}
fn get_account_by_id(&self, account_id: AccountId) -> DynResult<Account> {
let read = self
.client
.account(&account_id.to_string(), ReadAt::Latest)?;
account_from_value(account_id, read.value)
}
fn get_accounts_by_id(&self, account_ids: &[AccountId]) -> DynResult<Vec<Account>> {
let ids = account_ids
.iter()
.map(ToString::to_string)
.collect::<Vec<_>>();
let read = self.client.accounts(&ids, ReadAt::Latest)?;
read.accounts
.into_iter()
.zip(account_ids)
.map(|(entry, account_id)| account_from_value(*account_id, entry.value))
.collect()
}
fn get_proof_for_commitment(
&self,
commitment: &Commitment,
) -> DynResult<Option<MembershipProof>> {
let commitment_hex = hex_encode(&commitment.to_byte_array());
let read = self.client.proof(&commitment_hex, ReadAt::Latest)?;
read.proof.map(proof_from_value).transpose()
}
}
struct SeedDirGuard {
path: PathBuf,
}
impl SeedDirGuard {
fn from_state(state: &nssa::V03State) -> DynResult<Self> {
let path = local_sequencer_seed_dir()?;
if path.exists() {
fs::remove_dir_all(&path)?;
}
fs::create_dir_all(&path)?;
seed_sequencer_state(&path, state)?;
Ok(Self { path })
}
fn path(&self) -> &Path {
&self.path
}
}
impl Drop for SeedDirGuard {
fn drop(&mut self) {
let _ = fs::remove_dir_all(&self.path);
}
}
#[derive(BorshSerialize)]
struct NssaStateCellRef<'state>(&'state nssa::V03State);
fn seed_sequencer_state(seed_dir: &Path, state: &nssa::V03State) -> DynResult<()> {
// Scaffold snapshot seeding cannot represent full public account data at
// this LEZ pin, while these fixtures use force-inserted public accounts.
let mut cf_opts = Options::default();
cf_opts.set_max_write_buffer_number(16);
let cfb = ColumnFamilyDescriptor::new(CF_BLOCK_NAME, cf_opts.clone());
let cfmeta = ColumnFamilyDescriptor::new(CF_META_NAME, cf_opts.clone());
let cfstate = ColumnFamilyDescriptor::new(CF_NSSA_STATE_NAME, cf_opts);
let mut db_opts = Options::default();
db_opts.create_missing_column_families(true);
db_opts.create_if_missing(true);
let db = DBWithThreadMode::<MultiThreaded>::open_cf_descriptors(
&db_opts,
seed_dir.join("rocksdb"),
vec![cfb, cfmeta, cfstate],
)?;
let state_column = db
.cf_handle(CF_NSSA_STATE_NAME)
.ok_or_else(|| io::Error::other("state column family not created"))?;
db.put_cf(
&state_column,
borsh::to_vec(&DB_NSSA_STATE_KEY)?,
borsh::to_vec(&NssaStateCellRef(state))?,
)?;
Ok(())
}
fn scaffold_project() -> &'static Project {
static PROJECT: OnceLock<Project> = OnceLock::new();
PROJECT.get_or_init(|| {
let root = repo_root();
let project = Project::open(&root).unwrap_or_else(|err| {
panic!(
"failed to open scaffold project at {}: {err}",
root.display()
)
});
let circuits_version = env::var(TEST_NODE_CIRCUITS_VERSION_ENV)
.unwrap_or_else(|_| DEFAULT_CIRCUITS_VERSION.to_owned());
logos_scaffold::api::testnode::prepare_test_node(
&project,
&PinOverrides {
circuits_version: Some(circuits_version),
..Default::default()
},
None,
)
.unwrap_or_else(|err| panic!("failed to prepare scaffold test node: {err}"));
project
})
}
fn repo_root() -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR"))
.parent()
.and_then(Path::parent)
.expect("integration_tests crate lives under programs/integration_tests")
.to_path_buf()
}
fn local_sequencer_seed_dir() -> DynResult<PathBuf> {
let timestamp = SystemTime::now().duration_since(UNIX_EPOCH)?.as_nanos();
Ok(repo_root().join(format!(
"target/local-sequencer/seeds/{}-{timestamp}",
std::process::id()
)))
}
fn account_from_value(account_id: AccountId, value: AccountValue) -> DynResult<Account> {
match value {
AccountValue::Missing => Ok(Account::default()),
AccountValue::Present { encoded, .. } => {
let bytes = BASE64_STANDARD.decode(encoded)?;
Ok(borsh::from_slice(&bytes)?)
}
AccountValue::DecodeError { message, .. } => Err(io::Error::new(
io::ErrorKind::InvalidData,
format!("sequencer account {account_id} could not be decoded: {message}"),
)
.into()),
}
}
fn proof_from_value(proof: ProofValue) -> DynResult<MembershipProof> {
let leaf_index = usize::try_from(proof.leaf_index).map_err(|_| {
io::Error::new(
io::ErrorKind::InvalidData,
format!("proof leaf index {} does not fit usize", proof.leaf_index),
)
})?;
let path = proof
.path
.iter()
.map(|node| parse_hex_32(node))
.collect::<DynResult<Vec<_>>>()?;
Ok((leaf_index, path))
}
fn parse_hex_32(value: &str) -> DynResult<[u8; 32]> {
let bytes = value.as_bytes();
if bytes.len() != 64 {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!("expected 64 hex chars, got {}", bytes.len()),
)
.into());
}
let mut out = [0_u8; 32];
for (index, chunk) in bytes.chunks_exact(2).enumerate() {
let slot = out
.get_mut(index)
.ok_or_else(|| io::Error::other("hex output index out of bounds"))?;
let pair = std::str::from_utf8(chunk)?;
*slot = u8::from_str_radix(pair, 16)?;
}
Ok(out)
}
#[derive(BorshSerialize)]
enum RpcTransaction {
Public(Box<PublicTransaction>),
PrivacyPreserving(Box<PrivacyPreservingTransaction>),
ProgramDeployment(Box<ProgramDeploymentTransaction>),
}
impl RpcTransaction {
fn hash(&self) -> [u8; 32] {
match self {
Self::Public(tx) => tx.hash(),
Self::PrivacyPreserving(tx) => tx.hash(),
Self::ProgramDeployment(tx) => tx.hash(),
}
}
fn affected_public_account_ids(&self) -> Vec<AccountId> {
match self {
Self::Public(tx) => tx.affected_public_account_ids(),
Self::PrivacyPreserving(tx) => tx.affected_public_account_ids(),
Self::ProgramDeployment(tx) => tx.affected_public_account_ids(),
}
}
}
fn hex_encode(bytes: &[u8]) -> String {
let mut output = String::with_capacity(bytes.len().saturating_mul(2));
for byte in bytes {
write!(&mut output, "{byte:02x}").expect("writing to String cannot fail");
}
output
}

View File

@ -8,10 +8,11 @@ use amm_core::{
MINIMUM_LIQUIDITY, MINIMUM_LIQUIDITY,
}; };
use clock_core::{ClockAccountData, CLOCK_01_PROGRAM_ACCOUNT_ID}; use clock_core::{ClockAccountData, CLOCK_01_PROGRAM_ACCOUNT_ID};
use integration_tests::TestState as V03State;
use nssa::{ use nssa::{
error::LeeError, error::LeeError,
program_deployment_transaction::{self, ProgramDeploymentTransaction}, program_deployment_transaction::{self, ProgramDeploymentTransaction},
public_transaction, PrivateKey, PublicKey, PublicTransaction, V03State, public_transaction, PrivateKey, PublicKey, PublicTransaction,
}; };
use nssa_core::account::{Account, AccountId, Data, Nonce}; use nssa_core::account::{Account, AccountId, Data, Nonce};
use token_core::{TokenDefinition, TokenHolding}; use token_core::{TokenDefinition, TokenHolding};

View File

@ -1,6 +1,7 @@
use std::collections::HashMap; use std::collections::HashMap;
use ata_core::{compute_ata_seed, get_associated_token_account_id}; use ata_core::{compute_ata_seed, get_associated_token_account_id};
use integration_tests::TestState as V03State;
use nssa::{ use nssa::{
execute_and_prove, execute_and_prove,
privacy_preserving_transaction::{ privacy_preserving_transaction::{
@ -8,7 +9,7 @@ use nssa::{
}, },
program::Program, program::Program,
program_deployment_transaction::{self, ProgramDeploymentTransaction}, program_deployment_transaction::{self, ProgramDeploymentTransaction},
public_transaction, PrivateKey, PublicKey, PublicTransaction, SharedSecretKey, V03State, public_transaction, PrivateKey, PublicKey, PublicTransaction, SharedSecretKey,
}; };
use nssa_core::{ use nssa_core::{
account::{Account, AccountId, AccountWithMetadata, Data, Nonce}, account::{Account, AccountId, AccountWithMetadata, Data, Nonce},

View File

@ -1,6 +1,7 @@
use integration_tests::TestState as V03State;
use nssa::{ use nssa::{
program_deployment_transaction::{self, ProgramDeploymentTransaction}, program_deployment_transaction::{self, ProgramDeploymentTransaction},
public_transaction, PrivateKey, PublicKey, PublicTransaction, V03State, public_transaction, PrivateKey, PublicKey, PublicTransaction,
}; };
use nssa_core::account::{Account, AccountId, Data, Nonce}; use nssa_core::account::{Account, AccountId, Data, Nonce};
use stablecoin_core::{compute_position_pda, compute_position_vault_pda, Position}; use stablecoin_core::{compute_position_pda, compute_position_vault_pda, Position};

View File

@ -1,9 +1,10 @@
use integration_tests::TestState as V03State;
use nssa::{ use nssa::{
execute_and_prove, execute_and_prove,
privacy_preserving_transaction::{Message, PrivacyPreservingTransaction, WitnessSet}, privacy_preserving_transaction::{Message, PrivacyPreservingTransaction, WitnessSet},
program::Program, program::Program,
program_deployment_transaction::{self, ProgramDeploymentTransaction}, program_deployment_transaction::{self, ProgramDeploymentTransaction},
public_transaction, PrivateKey, PublicKey, PublicTransaction, SharedSecretKey, V03State, public_transaction, PrivateKey, PublicKey, PublicTransaction, SharedSecretKey,
}; };
use nssa_core::{ use nssa_core::{
account::{Account, AccountId, AccountWithMetadata, Data, Nonce}, account::{Account, AccountId, AccountWithMetadata, Data, Nonce},

25
scaffold.toml Normal file
View File

@ -0,0 +1,25 @@
[scaffold]
version = "0.2.0"
[repos.lez]
source = "https://github.com/logos-blockchain/logos-execution-zone.git"
pin = "cf3639d8252040d13b3d4e933feb19b42c76e14a"
[repos.spel]
source = "https://github.com/logos-co/spel.git"
pin = "84f50d4aa473a70b72a16a7fb468c5618277cdd7"
[wallet]
home_dir = ".scaffold/wallet"
[framework]
kind = "default"
version = "0.1.0"
[framework.idl]
spec = "lssa-idl/0.1.0"
path = "artifacts"
[localnet]
port = 3040
risc0_dev_mode = true