Skip to content

Commit a6a0503

Browse files
taco-pacothlorenzDodecahedr0xBretasArthur1GabrielePicco
authored
Base layer actions (#485)
Everything starts when a scheduled Intent arrives... # Architecture ## Schedulers We can't directly spawn bunch of **IntentExecutor**s. The reason is that one message can block execution of another message. To handle this the messages have to go through Scheduling. Details: Once message make it to `CommittorProcessor::schedule_base_intents` it outsources intent to tokio task `IntentExecutionEngine` which figures out a scheduling. ## IntentExecutionEngine Accepts new messages, schedules them, and spawns up to 50 parallel **IntentExecutor**s for each Intent. Once a particular **IntentExecutor** finishes execution we broadcast result to subscribers, like: `RemoteScheduledCommitsProcessor` or `ExternalAccountsManager` details: For scheduling logic see **IntentScheduler**. Number of parallel **IntentExecutor** is controller by Semaphore. ## IntentExecutor IntentExecutor - responsible for execution of Intent. Calls **TransactionPreparator** and then executes a transaction returning as result necessary signatures ## TransactionPreparator TransactionPreparator - is an entity that handles all of the above "Transaction preparation" calling **TaskBuilderV1**, **TaskStrategist**, **DeliveryPreparator** and then assempling it all and passing to **MessageExecutor** ## DeliveryPreparator After our **L1Task**s are ready we need to prepare eveything for their successful execution. **DeliveryPreparator** - handles ALTs and commit buffers ## TaskBuilder First, lets build atomic tasks from scheduled message/intent. High level: TaskBuilder responsible for creating L1Tasks(to be renamed...) from ScheduledL1Message(to be renamed...). Details: To do that is requires additional information from DelegationMetadata, it is provided **CommitIdFetcher** ### L1Task High level: L1Task - is an atomic operation that is to be performed on the Base layer, like: Commit, Undelegate, Finalize, Action. Details: There's to implementation of L1Tasks: ArgsTask, BufferTask. ArgsTask - gives instruction using args. BufferTask - gives instruction using buffer. BufferTask at the moment supports only commits ### CommitIdFetcher High level: for account to be accepted by dlp it needs to have incremental commit ids. CommitIdFetcher provides a user with the correct ids/nonces for set of committees Details: CommitIdTracker - implementation of CommitIdFetcher, that caches and locally increments commit ids using LruCache ## TaskStrategist After our tasks were built with **TaskBuilder**, they need to be optimized to fit into transaction. That what TaskStrategist does. Details: Initially **TaskBuilder** builds ArgsTasks, **TaskStrategist** if needed optimzes them to BufferTask. ### Changes - Persister changed from reqid & bundle_id format to message_id. Meaning row created per message. A particular Row tracking lifespan of Intent - Persister will be passed along into Executors & Scheduler for them to update Intent statuses during execution - No notion of bundles anymore, we represent things by Intent id - AccountsManager doesn't use custom `AccountCommitter` for periodic commits of accounts but instead uses CommittorService - RemoteScheduledCommitsProcessor extracted from AccountsManager since has nothing to do with it # Benchmarks Using the same config as in this [PR](#366) Here's best result on master I got on my machine: ``` +-------------------------------+--------------+--------+------+-------+------+-----------+--------+ | Metric | Observations | Median | Min | Max | Avg | 95th Perc | Stddev | +-------------------------------+--------------+--------+------+-------+------+-----------+--------+ | sendTransaction Response (μs) | 2000 | 3401 | 1499 | 23918 | 3543 | 5079 | 1244 | +-------------------------------+--------------+--------+------+-------+------+-----------+--------+ | Account Update (μs) | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------+--------------+--------+------+-------+------+-----------+--------+ | Signature Confirmation (μs) | 2000 | 3460 | 1520 | 13509 | 3609 | 5430 | 1123 | +-------------------------------+--------------+--------+------+-------+------+-----------+--------+ | Transactions Per Second (TPS) | 51 | 40 | 40 | 40 | 40 | 40 | 0 | +-------------------------------+--------------+--------+------+-------+------+-----------+--------+ | Requests Per Second (TPS) | --- | --- | --- | --- | --- | --- | --- | +-------------------------------+--------------+--------+------+-------+------+-----------+--------+ | getX Request Response (TPS) | --- | --- | --- | --- | --- | --- | --- | +-------------------------------+--------------+--------+------+-------+------+-----------+--------+ ``` Here's the best result on feat/base-layer-ix/main which is current PR on review ``` +-------------------------------+--------------+--------+------+-------+------+-----------+--------+ | Metric | Observations | Median | Min | Max | Avg | 95th Perc | Stddev | +-------------------------------+--------------+--------+------+-------+------+-----------+--------+ | sendTransaction Response (μs) | 2000 | 3241 | 1450 | 17898 | 3397 | 4907 | 954 | +-------------------------------+--------------+--------+------+-------+------+-----------+--------+ | Account Update (μs) | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------+--------------+--------+------+-------+------+-----------+--------+ | Signature Confirmation (μs) | 2000 | 3332 | 1504 | 17947 | 3517 | 5187 | 988 | +-------------------------------+--------------+--------+------+-------+------+-----------+--------+ | Transactions Per Second (TPS) | 51 | 40 | 40 | 40 | 40 | 40 | 0 | +-------------------------------+--------------+--------+------+-------+------+-----------+--------+ | Requests Per Second (TPS) | --- | --- | --- | --- | --- | --- | --- | +-------------------------------+--------------+--------+------+-------+------+-----------+--------+ | getX Request Response (TPS) | --- | --- | --- | --- | --- | --- | --- | +-------------------------------+--------------+--------+------+-------+------+-----------+--------+ ``` So results are almost the same, but current `feat/base-layer-ix/main` sends 2 txs for commit & finalize, while master sends 1. Here's results on optimized branch feat/base-layer-ix/single-tx-intent which sends just 1 tx as well. We get ~13% increase in performance on our trait fuel ``` +-------------------------------+--------------+--------+------+-------+------+-----------+--------+ | Metric | Observations | Median | Min | Max | Avg | 95th Perc | Stddev | +-------------------------------+--------------+--------+------+-------+------+-----------+--------+ | sendTransaction Response (μs) | 2000 | 2896 | 1360 | 14462 | 3050 | 4619 | 1060 | +-------------------------------+--------------+--------+------+-------+------+-----------+--------+ | Account Update (μs) | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +-------------------------------+--------------+--------+------+-------+------+-----------+--------+ | Signature Confirmation (μs) | 2000 | 2977 | 1376 | 15452 | 3149 | 4916 | 1149 | +-------------------------------+--------------+--------+------+-------+------+-----------+--------+ | Transactions Per Second (TPS) | 51 | 40 | 40 | 40 | 40 | 40 | 0 | +-------------------------------+--------------+--------+------+-------+------+-----------+--------+ | Requests Per Second (TPS) | --- | --- | --- | --- | --- | --- | --- | +-------------------------------+--------------+--------+------+-------+------+-----------+--------+ | getX Request Response (TPS) | --- | --- | --- | --- | --- | --- | --- | +-------------------------------+--------------+--------+------+-------+------+-----------+--------+ ``` --------- Co-authored-by: Thorsten Lorenz <thlorenz@gmx.de> Co-authored-by: Dodecahedr0x <90185028+Dodecahedr0x@users.noreply.github.com> Co-authored-by: Arthur Bretas <158767751+BretasArthur1@users.noreply.github.com> Co-authored-by: Dodecahedr0x <hexadecifish@gmail.com> Co-authored-by: Gabriele Picco <piccogabriele@gmail.com>
1 parent 5eafcf7 commit a6a0503

File tree

166 files changed

+12450
-9016
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

166 files changed

+12450
-9016
lines changed

Cargo.lock

Lines changed: 49 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -66,14 +66,15 @@ borsh = { version = "1.5.1", features = ["derive", "unstable__schema"] }
6666
borsh-derive = "1.5.1"
6767
bs58 = "0.4.0"
6868
byteorder = "1.5.0"
69-
cargo-lock = "10.0.0"
7069
cargo-expand = "1"
70+
cargo-lock = "10.0.0"
7171
clap = "4.5.40"
72-
convert_case = "0.8.0"
7372
conjunto-transwise = { git = "https://github.com/magicblock-labs/conjunto.git", rev = "bf82b45" }
7473
console-subscriber = "0.2.0"
75-
crossbeam-channel = "0.5.11"
7674
const_format = "0.2.34"
75+
convert_case = "0.8.0"
76+
crossbeam-channel = "0.5.11"
77+
dyn-clone = "1.0.20"
7778
ed25519-dalek = "1.0.1"
7879
enum-iterator = "1.5.0"
7980
env_logger = "0.11.2"
@@ -100,7 +101,9 @@ lazy_static = "1.4.0"
100101
libc = "0.2.153"
101102
libloading = "0.7.4"
102103
log = "0.4.20"
104+
lru = "0.16.0"
103105
macrotest = "1"
106+
magic-domain-program = { git = "https://github.com/magicblock-labs/magic-domain-program.git", rev = "ea04d46", default-features = false }
104107
magicblock-account-cloner = { path = "./magicblock-account-cloner" }
105108
magicblock-account-dumper = { path = "./magicblock-account-dumper" }
106109
magicblock-account-fetcher = { path = "./magicblock-account-fetcher" }
@@ -118,8 +121,7 @@ magicblock-config = { path = "./magicblock-config" }
118121
magicblock-config-helpers = { path = "./magicblock-config-helpers" }
119122
magicblock-config-macro = { path = "./magicblock-config-macro" }
120123
magicblock-core = { path = "./magicblock-core" }
121-
magicblock-delegation-program = { git = "https://github.com/magicblock-labs/delegation-program.git", rev = "4af7f1c" }
122-
magic-domain-program = { git = "https://github.com/magicblock-labs/magic-domain-program.git", rev = "ea04d46", default-features = false }
124+
magicblock-delegation-program = { git = "https://github.com/magicblock-labs/delegation-program.git", rev = "5fb8d20", features = ["no-entrypoint"] }
123125
magicblock-geyser-plugin = { path = "./magicblock-geyser-plugin" }
124126
magicblock-ledger = { path = "./magicblock-ledger" }
125127
magicblock-metrics = { path = "./magicblock-metrics" }
@@ -148,20 +150,20 @@ protobuf-src = "1.1"
148150
quote = "1.0"
149151
rand = "0.8.5"
150152
rayon = "1.10.0"
151-
rustc_version = "0.4"
152153
rusqlite = { version = "0.34.0", features = ["bundled"] } # bundled sqlite 3.44
154+
rustc_version = "0.4"
153155
semver = "1.0.22"
154156
serde = "1.0.217"
155157
serde_derive = "1.0"
156158
serde_json = "1.0"
157159
sha3 = "0.10.8"
158160
solana-account = { git = "https://github.com/magicblock-labs/solana-account.git", rev = "176540a" }
159-
solana-accounts-db = { version = "2.2" }
160161
solana-account-decoder = { version = "2.2" }
162+
solana-accounts-db = { version = "2.2" }
161163
solana-address-lookup-table-program = { version = "2.2" }
162164
solana-bpf-loader-program = { version = "2.2" }
163-
solana-compute-budget-program = { version = "2.2" }
164165
solana-compute-budget-instruction = { version = "2.2" }
166+
solana-compute-budget-program = { version = "2.2" }
165167
solana-cost-model = { version = "2.2" }
166168
solana-frozen-abi-macro = { version = "2.2" }
167169
solana-geyser-plugin-interface = { version = "2.2", package = "agave-geyser-plugin-interface" }
@@ -175,17 +177,17 @@ solana-program = "2.2"
175177
solana-program-runtime = { version = "2.2" }
176178
solana-program-test = "2.2"
177179
solana-pubkey = { version = "2.2" }
178-
solana-rayon-threadlimit = { version = "2.2" }
179180
solana-pubsub-client = { version = "2.2" }
181+
solana-rayon-threadlimit = { version = "2.2" }
180182
solana-rpc = "2.2"
181183
solana-rpc-client = { version = "2.2" }
182184
solana-rpc-client-api = { version = "2.2" }
183185
solana-sdk = { version = "2.2" }
186+
solana-storage-proto = { path = "storage-proto" }
184187
solana-svm = { git = "https://github.com/magicblock-labs/magicblock-svm.git", rev = "e93eb57", features = [
185188
"dev-context-only-utils",
186189
] }
187190
solana-svm-transaction = { version = "2.2" }
188-
solana-storage-proto = { path = "storage-proto" }
189191
solana-system-program = { version = "2.2" }
190192
solana-timings = "2.2"
191193
solana-transaction-status = { version = "2.2" }

magicblock-account-cloner/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ magicblock-account-fetcher = { workspace = true }
1616
magicblock-account-updates = { workspace = true }
1717
magicblock-account-dumper = { workspace = true }
1818
magicblock-accounts-api = { workspace = true }
19+
magicblock-rpc-client = { workspace = true }
1920
magicblock-config = { workspace = true }
2021
magicblock-core = { workspace = true }
2122
magicblock-committor-service = { workspace = true }

magicblock-account-cloner/src/account_cloner.rs

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@ use magicblock_account_fetcher::AccountFetcherError;
1010
use magicblock_account_updates::AccountUpdatesError;
1111
use magicblock_committor_service::{
1212
error::{CommittorServiceError, CommittorServiceResult},
13-
ChangesetCommittor,
13+
BaseIntentCommittor,
1414
};
1515
use magicblock_core::magic_program;
16+
use magicblock_rpc_client::MagicblockRpcClient;
1617
use solana_sdk::{clock::Slot, pubkey::Pubkey, signature::Signature};
1718
use thiserror::Error;
1819
use tokio::sync::oneshot::{self, Sender};
@@ -76,9 +77,9 @@ pub enum AccountClonerUnclonableReason {
7677
DelegatedAccountsNotClonedWhileHydrating,
7778
}
7879

79-
pub async fn map_committor_request_result<T, CC: ChangesetCommittor>(
80+
pub async fn map_committor_request_result<T, CC: BaseIntentCommittor>(
8081
res: oneshot::Receiver<CommittorServiceResult<T>>,
81-
changeset_committor: Arc<CC>,
82+
intent_committor: Arc<CC>,
8283
) -> AccountClonerResult<T> {
8384
match res.await.map_err(|err| {
8485
// Send request error
@@ -96,10 +97,21 @@ pub async fn map_committor_request_result<T, CC: ChangesetCommittor>(
9697
format!("{:?}", table_mania_err),
9798
));
9899
};
99-
let cus =
100-
changeset_committor.get_transaction_cus(&sig).await;
101-
let logs =
102-
changeset_committor.get_transaction_logs(&sig).await;
100+
let (logs, cus) = if let Ok(Ok(transaction)) =
101+
intent_committor.get_transaction(&sig).await
102+
{
103+
let cus = MagicblockRpcClient::get_cus_from_transaction(
104+
&transaction,
105+
);
106+
let logs =
107+
MagicblockRpcClient::get_logs_from_transaction(
108+
&transaction,
109+
);
110+
(logs, cus)
111+
} else {
112+
(None, None)
113+
};
114+
103115
let cus_str = cus
104116
.map(|cus| format!("{:?}", cus))
105117
.unwrap_or("N/A".to_string());

magicblock-account-cloner/src/remote_account_cloner_client.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use magicblock_account_dumper::AccountDumper;
1111
use magicblock_account_fetcher::AccountFetcher;
1212
use magicblock_account_updates::AccountUpdates;
1313
use magicblock_accounts_api::InternalAccountProvider;
14-
use magicblock_committor_service::ChangesetCommittor;
14+
use magicblock_committor_service::BaseIntentCommittor;
1515
use solana_sdk::pubkey::Pubkey;
1616
use tokio::sync::oneshot::channel;
1717

@@ -34,7 +34,7 @@ impl RemoteAccountClonerClient {
3434
AFE: AccountFetcher,
3535
AUP: AccountUpdates,
3636
ADU: AccountDumper,
37-
CC: ChangesetCommittor,
37+
CC: BaseIntentCommittor,
3838
{
3939
Self {
4040
clone_request_sender: worker.get_clone_request_sender(),

magicblock-account-cloner/src/remote_account_cloner_worker.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use magicblock_account_dumper::AccountDumper;
1717
use magicblock_account_fetcher::AccountFetcher;
1818
use magicblock_account_updates::{AccountUpdates, AccountUpdatesResult};
1919
use magicblock_accounts_api::InternalAccountProvider;
20-
use magicblock_committor_service::ChangesetCommittor;
20+
use magicblock_committor_service::BaseIntentCommittor;
2121
use magicblock_config::{
2222
AccountsCloneConfig, LedgerResumeStrategyConfig, PrepareLookupTables,
2323
};
@@ -137,7 +137,7 @@ where
137137
AFE: AccountFetcher,
138138
AUP: AccountUpdates,
139139
ADU: AccountDumper,
140-
CC: ChangesetCommittor,
140+
CC: BaseIntentCommittor,
141141
{
142142
#[allow(clippy::too_many_arguments)]
143143
pub fn new(
@@ -737,11 +737,10 @@ where
737737

738738
// Allow the committer service to reserve pubkeys in lookup tables
739739
// that could be needed when we commit this account
740-
if let Some(committor) = self.changeset_committor.as_ref() {
740+
if let Some(committor) = self.changeset_committor.clone() {
741741
if self.clone_config.prepare_lookup_tables
742742
== PrepareLookupTables::Always
743743
{
744-
let committor = Arc::clone(committor);
745744
let pubkey = *pubkey;
746745
let owner = delegation_record.owner;
747746
tokio::spawn(async move {

magicblock-account-dumper/src/account_dumper_bank.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,6 @@ impl AccountDumper for AccountDumperBank {
181181

182182
let mut program_id_modification =
183183
AccountModification::from((program_pubkey, program_account));
184-
185184
// point program account to the derived program data account address
186185
let program_id_state =
187186
bincode::serialize(&UpgradeableLoaderState::Program {

magicblock-accounts-api/src/bank_account_provider.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
use std::sync::Arc;
22

33
use magicblock_bank::bank::Bank;
4-
use solana_sdk::{account::AccountSharedData, clock::Slot, pubkey::Pubkey};
4+
use solana_sdk::{
5+
account::AccountSharedData, clock::Slot, hash::Hash, pubkey::Pubkey,
6+
};
57

68
use crate::InternalAccountProvider;
79

@@ -33,4 +35,7 @@ impl InternalAccountProvider for BankAccountProvider {
3335
fn get_slot(&self) -> Slot {
3436
self.bank.slot()
3537
}
38+
fn get_blockhash(&self) -> Hash {
39+
self.bank.last_blockhash()
40+
}
3641
}
Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1-
use solana_sdk::{account::AccountSharedData, clock::Slot, pubkey::Pubkey};
1+
use solana_sdk::{
2+
account::AccountSharedData, clock::Slot, hash::Hash, pubkey::Pubkey,
3+
};
24

35
pub trait InternalAccountProvider: Send + Sync {
46
fn has_account(&self, pubkey: &Pubkey) -> bool;
57
fn remove_account(&self, _pubkey: &Pubkey) {}
68
fn get_account(&self, pubkey: &Pubkey) -> Option<AccountSharedData>;
79
fn get_all_accounts(&self) -> Vec<(Pubkey, AccountSharedData)>;
810
fn get_slot(&self) -> Slot;
11+
fn get_blockhash(&self) -> Hash;
912
}

0 commit comments

Comments
 (0)