mirror of
https://github.com/logos-blockchain/lssa.git
synced 2026-02-18 20:33:13 +00:00
Merge branch 'main' into Pravdyvy/indexer-state-management
This commit is contained in:
commit
992fd26bcd
15
README.md
15
README.md
@ -133,9 +133,8 @@ RUST_LOG=info RISC0_DEV_MODE=1 cargo run $(pwd)/configs/debug all
|
||||
|
||||
|
||||
## Running Manually
|
||||
|
||||
The sequencer and node can be run locally:
|
||||
|
||||
### Normal mode
|
||||
The sequencer and logos blockchain node can be run locally:
|
||||
1. On one terminal go to the `logos-blockchain/logos-blockchain` repo and run a local logos blockchain node:
|
||||
- `git checkout master; git pull`
|
||||
- `cargo clean`
|
||||
@ -145,10 +144,16 @@ The sequencer and node can be run locally:
|
||||
- `./target/debug/logos-blockchain-node --deployment nodes/node/standalone-deployment-config.yaml nodes/node/standalone-node-config.yaml`
|
||||
|
||||
2. On another terminal go to the `logos-blockchain/lssa` repo and run indexer service:
|
||||
- `RUST_LOG=info cargo run --release -p indexer_service indexer/service/configs/indexer_config.json`
|
||||
- `RUST_LOG=info cargo run -p indexer_service indexer/service/configs/indexer_config.json`
|
||||
|
||||
3. On another terminal go to the `logos-blockchain/lssa` repo and run the sequencer:
|
||||
- `RUST_LOG=info RISC0_DEV_MODE=1 cargo run --release -p sequencer_runner sequencer_runner/configs/debug`
|
||||
- `RUST_LOG=info cargo run -p sequencer_runner sequencer_runner/configs/debug`
|
||||
|
||||
### Standalone mode
|
||||
The sequencer can be run in standalone mode with:
|
||||
```bash
|
||||
RUST_LOG=info cargo run --features standalone -p sequencer_runner sequencer_runner/configs/debug
|
||||
```
|
||||
|
||||
## Running with Docker
|
||||
|
||||
|
||||
@ -28,6 +28,9 @@ pub mod indexer_client;
|
||||
#[cfg(feature = "mock")]
|
||||
pub mod mock;
|
||||
|
||||
#[cfg(feature = "mock")]
|
||||
pub use mock::SequencerCoreWithMockClients;
|
||||
|
||||
pub struct SequencerCore<
|
||||
BC: BlockSettlementClientTrait = BlockSettlementClient,
|
||||
IC: IndexerClientTrait = IndexerClient,
|
||||
|
||||
@ -28,3 +28,8 @@ borsh.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
sequencer_core = { workspace = true, features = ["mock"] }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
# Includes types to run the sequencer in standalone mode
|
||||
standalone = ["sequencer_core/mock"]
|
||||
|
||||
@ -49,3 +49,9 @@ pub fn rpc_error_responce_inverter(err: RpcError) -> RpcError {
|
||||
data: content,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "standalone")]
|
||||
use sequencer_core::mock::{MockBlockSettlementClient, MockIndexerClient};
|
||||
|
||||
#[cfg(feature = "standalone")]
|
||||
pub type JsonHandlerWithMockClients = JsonHandler<MockBlockSettlementClient, MockIndexerClient>;
|
||||
|
||||
@ -9,10 +9,19 @@ use common::{
|
||||
use futures::{Future, FutureExt};
|
||||
use log::info;
|
||||
use mempool::MemPoolHandle;
|
||||
#[cfg(not(feature = "standalone"))]
|
||||
use sequencer_core::SequencerCore;
|
||||
#[cfg(feature = "standalone")]
|
||||
use sequencer_core::SequencerCoreWithMockClients as SequencerCore;
|
||||
|
||||
#[cfg(not(feature = "standalone"))]
|
||||
use super::JsonHandler;
|
||||
|
||||
#[cfg(feature = "standalone")]
|
||||
type JsonHandler = super::JsonHandlerWithMockClients;
|
||||
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
use super::JsonHandler;
|
||||
use crate::process::Process;
|
||||
|
||||
pub const SHUTDOWN_TIMEOUT_SECS: u64 = 10;
|
||||
|
||||
@ -291,6 +291,7 @@ impl<BC: BlockSettlementClientTrait, IC: IndexerClientTrait> JsonHandler<BC, IC>
|
||||
);
|
||||
program_ids.insert("token".to_string(), Program::token().id());
|
||||
program_ids.insert("pinata".to_string(), Program::pinata().id());
|
||||
program_ids.insert("amm".to_string(), Program::amm().id());
|
||||
program_ids.insert(
|
||||
"privacy_preserving_circuit".to_string(),
|
||||
nssa::PRIVACY_PRESERVING_CIRCUIT_ID,
|
||||
|
||||
@ -18,3 +18,8 @@ actix.workspace = true
|
||||
actix-web.workspace = true
|
||||
tokio.workspace = true
|
||||
futures.workspace = true
|
||||
|
||||
[features]
|
||||
default = []
|
||||
# Runs the sequencer in standalone mode without depending on Bedrock and Indexer services.
|
||||
standalone = ["sequencer_core/mock", "sequencer_rpc/standalone"]
|
||||
|
||||
@ -5,11 +5,14 @@ use anyhow::{Context as _, Result};
|
||||
use clap::Parser;
|
||||
use common::rpc_primitives::RpcConfig;
|
||||
use futures::{FutureExt as _, never::Never};
|
||||
use log::{error, info, warn};
|
||||
use sequencer_core::{
|
||||
SequencerCore, block_settlement_client::BlockSettlementClientTrait as _,
|
||||
config::SequencerConfig,
|
||||
};
|
||||
#[cfg(not(feature = "standalone"))]
|
||||
use log::warn;
|
||||
use log::{error, info};
|
||||
#[cfg(feature = "standalone")]
|
||||
use sequencer_core::SequencerCoreWithMockClients as SequencerCore;
|
||||
use sequencer_core::config::SequencerConfig;
|
||||
#[cfg(not(feature = "standalone"))]
|
||||
use sequencer_core::{SequencerCore, block_settlement_client::BlockSettlementClientTrait as _};
|
||||
use sequencer_rpc::new_http_server;
|
||||
use tokio::{sync::Mutex, task::JoinHandle};
|
||||
|
||||
@ -156,6 +159,7 @@ async fn main_loop(seq_core: Arc<Mutex<SequencerCore>>, block_timeout: Duration)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "standalone"))]
|
||||
async fn retry_pending_blocks_loop(
|
||||
seq_core: Arc<Mutex<SequencerCore>>,
|
||||
retry_pending_blocks_timeout: Duration,
|
||||
@ -180,8 +184,8 @@ async fn retry_pending_blocks_loop(
|
||||
"Resubmitting pending block with id {}",
|
||||
block.header.block_id
|
||||
);
|
||||
// TODO: We could cache the inscribe tx for each pending block to avoid re-creating it
|
||||
// on every retry.
|
||||
// TODO: We could cache the inscribe tx for each pending block to avoid re-creating
|
||||
// it on every retry.
|
||||
let (tx, _msg_id) = block_settlement_client
|
||||
.create_inscribe_tx(block)
|
||||
.context("Failed to create inscribe tx for pending block")?;
|
||||
@ -199,6 +203,7 @@ async fn retry_pending_blocks_loop(
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "standalone"))]
|
||||
async fn listen_for_bedrock_blocks_loop(seq_core: Arc<Mutex<SequencerCore>>) -> Result<Never> {
|
||||
use indexer_service_rpc::RpcClient as _;
|
||||
|
||||
@ -235,6 +240,19 @@ async fn listen_for_bedrock_blocks_loop(seq_core: Arc<Mutex<SequencerCore>>) ->
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "standalone")]
|
||||
async fn listen_for_bedrock_blocks_loop(_seq_core: Arc<Mutex<SequencerCore>>) -> Result<Never> {
|
||||
std::future::pending::<Result<Never>>().await
|
||||
}
|
||||
|
||||
#[cfg(feature = "standalone")]
|
||||
async fn retry_pending_blocks_loop(
|
||||
_seq_core: Arc<Mutex<SequencerCore>>,
|
||||
_retry_pending_blocks_timeout: Duration,
|
||||
) -> Result<Never> {
|
||||
std::future::pending::<Result<Never>>().await
|
||||
}
|
||||
|
||||
pub async fn main_runner() -> Result<()> {
|
||||
env_logger::init();
|
||||
|
||||
|
||||
@ -359,6 +359,176 @@ pub unsafe extern "C" fn wallet_ffi_transfer_private(
|
||||
}
|
||||
}
|
||||
|
||||
/// Send a shielded token transfer to an owned private account.
|
||||
///
|
||||
/// Transfers tokens from a public account to a private account that is owned
|
||||
/// by this wallet. Unlike `wallet_ffi_transfer_shielded` which sends to a
|
||||
/// foreign account using NPK/VPK keys, this variant takes a destination
|
||||
/// account ID that must belong to this wallet.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `handle`: Valid wallet handle
|
||||
/// - `from`: Source public account ID (must be owned by this wallet)
|
||||
/// - `to`: Destination private account ID (must be owned by this wallet)
|
||||
/// - `amount`: Amount to transfer as little-endian [u8; 16]
|
||||
/// - `out_result`: Output pointer for transfer result
|
||||
///
|
||||
/// # Returns
|
||||
/// - `Success` if the transfer was submitted successfully
|
||||
/// - `InsufficientFunds` if the source account doesn't have enough balance
|
||||
/// - `KeyNotFound` if either account's keys are not in this wallet
|
||||
/// - Error code on other failures
|
||||
///
|
||||
/// # Memory
|
||||
/// The result must be freed with `wallet_ffi_free_transfer_result()`.
|
||||
///
|
||||
/// # Safety
|
||||
/// - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open`
|
||||
/// - `from` must be a valid pointer to a `FfiBytes32` struct
|
||||
/// - `to` must be a valid pointer to a `FfiBytes32` struct
|
||||
/// - `amount` must be a valid pointer to a `[u8; 16]` array
|
||||
/// - `out_result` must be a valid pointer to a `FfiTransferResult` struct
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wallet_ffi_transfer_shielded_owned(
|
||||
handle: *mut WalletHandle,
|
||||
from: *const FfiBytes32,
|
||||
to: *const FfiBytes32,
|
||||
amount: *const [u8; 16],
|
||||
out_result: *mut FfiTransferResult,
|
||||
) -> WalletFfiError {
|
||||
let wrapper = match get_wallet(handle) {
|
||||
Ok(w) => w,
|
||||
Err(e) => return e,
|
||||
};
|
||||
|
||||
if from.is_null() || to.is_null() || amount.is_null() || out_result.is_null() {
|
||||
print_error("Null pointer argument");
|
||||
return WalletFfiError::NullPointer;
|
||||
}
|
||||
|
||||
let wallet = match wrapper.core.lock() {
|
||||
Ok(w) => w,
|
||||
Err(e) => {
|
||||
print_error(format!("Failed to lock wallet: {}", e));
|
||||
return WalletFfiError::InternalError;
|
||||
}
|
||||
};
|
||||
|
||||
let from_id = AccountId::new(unsafe { (*from).data });
|
||||
let to_id = AccountId::new(unsafe { (*to).data });
|
||||
let amount = u128::from_le_bytes(unsafe { *amount });
|
||||
|
||||
let transfer = NativeTokenTransfer(&wallet);
|
||||
|
||||
match block_on(transfer.send_shielded_transfer(from_id, to_id, amount)) {
|
||||
Ok(Ok((response, _shared_key))) => {
|
||||
let tx_hash = CString::new(response.tx_hash)
|
||||
.map(|s| s.into_raw())
|
||||
.unwrap_or(ptr::null_mut());
|
||||
|
||||
unsafe {
|
||||
(*out_result).tx_hash = tx_hash;
|
||||
(*out_result).success = true;
|
||||
}
|
||||
WalletFfiError::Success
|
||||
}
|
||||
Ok(Err(e)) => {
|
||||
print_error(format!("Transfer failed: {:?}", e));
|
||||
unsafe {
|
||||
(*out_result).tx_hash = ptr::null_mut();
|
||||
(*out_result).success = false;
|
||||
}
|
||||
map_execution_error(e)
|
||||
}
|
||||
Err(e) => e,
|
||||
}
|
||||
}
|
||||
|
||||
/// Send a private token transfer to an owned private account.
|
||||
///
|
||||
/// Transfers tokens from a private account to another private account that is
|
||||
/// owned by this wallet. Unlike `wallet_ffi_transfer_private` which sends to a
|
||||
/// foreign account using NPK/VPK keys, this variant takes a destination
|
||||
/// account ID that must belong to this wallet.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `handle`: Valid wallet handle
|
||||
/// - `from`: Source private account ID (must be owned by this wallet)
|
||||
/// - `to`: Destination private account ID (must be owned by this wallet)
|
||||
/// - `amount`: Amount to transfer as little-endian [u8; 16]
|
||||
/// - `out_result`: Output pointer for transfer result
|
||||
///
|
||||
/// # Returns
|
||||
/// - `Success` if the transfer was submitted successfully
|
||||
/// - `InsufficientFunds` if the source account doesn't have enough balance
|
||||
/// - `KeyNotFound` if either account's keys are not in this wallet
|
||||
/// - Error code on other failures
|
||||
///
|
||||
/// # Memory
|
||||
/// The result must be freed with `wallet_ffi_free_transfer_result()`.
|
||||
///
|
||||
/// # Safety
|
||||
/// - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open`
|
||||
/// - `from` must be a valid pointer to a `FfiBytes32` struct
|
||||
/// - `to` must be a valid pointer to a `FfiBytes32` struct
|
||||
/// - `amount` must be a valid pointer to a `[u8; 16]` array
|
||||
/// - `out_result` must be a valid pointer to a `FfiTransferResult` struct
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wallet_ffi_transfer_private_owned(
|
||||
handle: *mut WalletHandle,
|
||||
from: *const FfiBytes32,
|
||||
to: *const FfiBytes32,
|
||||
amount: *const [u8; 16],
|
||||
out_result: *mut FfiTransferResult,
|
||||
) -> WalletFfiError {
|
||||
let wrapper = match get_wallet(handle) {
|
||||
Ok(w) => w,
|
||||
Err(e) => return e,
|
||||
};
|
||||
|
||||
if from.is_null() || to.is_null() || amount.is_null() || out_result.is_null() {
|
||||
print_error("Null pointer argument");
|
||||
return WalletFfiError::NullPointer;
|
||||
}
|
||||
|
||||
let wallet = match wrapper.core.lock() {
|
||||
Ok(w) => w,
|
||||
Err(e) => {
|
||||
print_error(format!("Failed to lock wallet: {}", e));
|
||||
return WalletFfiError::InternalError;
|
||||
}
|
||||
};
|
||||
|
||||
let from_id = AccountId::new(unsafe { (*from).data });
|
||||
let to_id = AccountId::new(unsafe { (*to).data });
|
||||
let amount = u128::from_le_bytes(unsafe { *amount });
|
||||
|
||||
let transfer = NativeTokenTransfer(&wallet);
|
||||
|
||||
match block_on(transfer.send_private_transfer_to_owned_account(from_id, to_id, amount)) {
|
||||
Ok(Ok((response, _shared_keys))) => {
|
||||
let tx_hash = CString::new(response.tx_hash)
|
||||
.map(|s| s.into_raw())
|
||||
.unwrap_or(ptr::null_mut());
|
||||
|
||||
unsafe {
|
||||
(*out_result).tx_hash = tx_hash;
|
||||
(*out_result).success = true;
|
||||
}
|
||||
WalletFfiError::Success
|
||||
}
|
||||
Ok(Err(e)) => {
|
||||
print_error(format!("Transfer failed: {:?}", e));
|
||||
unsafe {
|
||||
(*out_result).tx_hash = ptr::null_mut();
|
||||
(*out_result).success = false;
|
||||
}
|
||||
map_execution_error(e)
|
||||
}
|
||||
Err(e) => e,
|
||||
}
|
||||
}
|
||||
|
||||
/// Register a public account on the network.
|
||||
///
|
||||
/// This initializes a public account on the blockchain. The account must be
|
||||
|
||||
@ -672,6 +672,80 @@ enum WalletFfiError wallet_ffi_transfer_private(struct WalletHandle *handle,
|
||||
const uint8_t (*amount)[16],
|
||||
struct FfiTransferResult *out_result);
|
||||
|
||||
/**
|
||||
* Send a shielded token transfer to an owned private account.
|
||||
*
|
||||
* Transfers tokens from a public account to a private account that is owned
|
||||
* by this wallet. Unlike `wallet_ffi_transfer_shielded` which sends to a
|
||||
* foreign account using NPK/VPK keys, this variant takes a destination
|
||||
* account ID that must belong to this wallet.
|
||||
*
|
||||
* # Parameters
|
||||
* - `handle`: Valid wallet handle
|
||||
* - `from`: Source public account ID (must be owned by this wallet)
|
||||
* - `to`: Destination private account ID (must be owned by this wallet)
|
||||
* - `amount`: Amount to transfer as little-endian [u8; 16]
|
||||
* - `out_result`: Output pointer for transfer result
|
||||
*
|
||||
* # Returns
|
||||
* - `Success` if the transfer was submitted successfully
|
||||
* - `InsufficientFunds` if the source account doesn't have enough balance
|
||||
* - `KeyNotFound` if either account's keys are not in this wallet
|
||||
* - Error code on other failures
|
||||
*
|
||||
* # Memory
|
||||
* The result must be freed with `wallet_ffi_free_transfer_result()`.
|
||||
*
|
||||
* # Safety
|
||||
* - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open`
|
||||
* - `from` must be a valid pointer to a `FfiBytes32` struct
|
||||
* - `to` must be a valid pointer to a `FfiBytes32` struct
|
||||
* - `amount` must be a valid pointer to a `[u8; 16]` array
|
||||
* - `out_result` must be a valid pointer to a `FfiTransferResult` struct
|
||||
*/
|
||||
enum WalletFfiError wallet_ffi_transfer_shielded_owned(struct WalletHandle *handle,
|
||||
const struct FfiBytes32 *from,
|
||||
const struct FfiBytes32 *to,
|
||||
const uint8_t (*amount)[16],
|
||||
struct FfiTransferResult *out_result);
|
||||
|
||||
/**
|
||||
* Send a private token transfer to an owned private account.
|
||||
*
|
||||
* Transfers tokens from a private account to another private account that is
|
||||
* owned by this wallet. Unlike `wallet_ffi_transfer_private` which sends to a
|
||||
* foreign account using NPK/VPK keys, this variant takes a destination
|
||||
* account ID that must belong to this wallet.
|
||||
*
|
||||
* # Parameters
|
||||
* - `handle`: Valid wallet handle
|
||||
* - `from`: Source private account ID (must be owned by this wallet)
|
||||
* - `to`: Destination private account ID (must be owned by this wallet)
|
||||
* - `amount`: Amount to transfer as little-endian [u8; 16]
|
||||
* - `out_result`: Output pointer for transfer result
|
||||
*
|
||||
* # Returns
|
||||
* - `Success` if the transfer was submitted successfully
|
||||
* - `InsufficientFunds` if the source account doesn't have enough balance
|
||||
* - `KeyNotFound` if either account's keys are not in this wallet
|
||||
* - Error code on other failures
|
||||
*
|
||||
* # Memory
|
||||
* The result must be freed with `wallet_ffi_free_transfer_result()`.
|
||||
*
|
||||
* # Safety
|
||||
* - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open`
|
||||
* - `from` must be a valid pointer to a `FfiBytes32` struct
|
||||
* - `to` must be a valid pointer to a `FfiBytes32` struct
|
||||
* - `amount` must be a valid pointer to a `[u8; 16]` array
|
||||
* - `out_result` must be a valid pointer to a `FfiTransferResult` struct
|
||||
*/
|
||||
enum WalletFfiError wallet_ffi_transfer_private_owned(struct WalletHandle *handle,
|
||||
const struct FfiBytes32 *from,
|
||||
const struct FfiBytes32 *to,
|
||||
const uint8_t (*amount)[16],
|
||||
struct FfiTransferResult *out_result);
|
||||
|
||||
/**
|
||||
* Register a public account on the network.
|
||||
*
|
||||
|
||||
@ -139,6 +139,12 @@ pub async fn execute_subcommand(
|
||||
if circuit_id != &nssa::PRIVACY_PRESERVING_CIRCUIT_ID {
|
||||
panic!("Local ID for privacy preserving circuit is different from remote");
|
||||
}
|
||||
let Some(amm_id) = remote_program_ids.get("amm") else {
|
||||
panic!("Missing AMM program ID from remote");
|
||||
};
|
||||
if amm_id != &Program::amm().id() {
|
||||
panic!("Local ID for AMM program is different from remote");
|
||||
}
|
||||
|
||||
println!("✅All looks good!");
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user