Skip to content

Commit 4c478d2

Browse files
authored
Merge branch 'master' into dode/compression-3x
2 parents e557e6a + c73b5b0 commit 4c478d2

13 files changed

Lines changed: 167 additions & 97 deletions

File tree

.github/packages/npm-package/mbTestValidator.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,15 @@ function runMbTestValidator(): void {
8787
"--account",
8888
"FRqXJqfCi3o6gF3Yqnkx1gKA3YnbRDJbBs6hKpme3NHJ",
8989
p("FRqXJqfCi3o6gF3Yqnkx1gKA3YnbRDJbBs6hKpme3NHJ.json"),
90+
"--account",
91+
"Sc9MJUngNbQXSXGP3F67KvKwVnhaYn6kcioxXNVowYT",
92+
p("Sc9MJUngNbQXSXGP3F67KvKwVnhaYn6kcioxXNVowYT.json"),
93+
"--account",
94+
"9yvg9551MmE8mhWd88jAPLE3noTXHoopYG1BDhmtkCeR",
95+
p("9yvg9551MmE8mhWd88jAPLE3noTXHoopYG1BDhmtkCeR.json"),
96+
"--account",
97+
"7L9eCRv52UpGVePGj9P1zop8kzmh4SpYzYn6YhoAKHBg",
98+
p("7L9eCRv52UpGVePGj9P1zop8kzmh4SpYzYn6YhoAKHBg.json"),
9099
];
91100

92101
const expectedFiles = [
@@ -108,6 +117,9 @@ function runMbTestValidator(): void {
108117
"CXMc1eCiEp9YXjanBNB6HUvbWCmxeVmhcR3bPXw8exJA.json",
109118
"GKE6d7iv8kCBrsxr78W3xVdjGLLLJnxsGiuzrsZCGEvb.json",
110119
"FRqXJqfCi3o6gF3Yqnkx1gKA3YnbRDJbBs6hKpme3NHJ.json",
120+
"Sc9MJUngNbQXSXGP3F67KvKwVnhaYn6kcioxXNVowYT.json",
121+
"9yvg9551MmE8mhWd88jAPLE3noTXHoopYG1BDhmtkCeR.json",
122+
"7L9eCRv52UpGVePGj9P1zop8kzmh4SpYzYn6YhoAKHBg.json",
111123
];
112124
const missingFiles = expectedFiles
113125
.map((f) => p(f))

.github/packages/npm-package/scripts/fetch-local-dumps.sh

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,16 @@ accounts=(
1717
mAGicPQYBMvcYveUZA5F5UNNwyHvfYh5xkLS2Fr1mev
1818
EpJnX7ueXk7fKojBymqmVuCuwyhDQsYcLVL1XMsBbvDX
1919
7JrkjmZPprHwtuvtuGTXp9hwfGYFAQLnLeFM52kqAgXg
20-
Cuj97ggrhhidhbu39TijNVqE74xvKJ69gDervRUXAxGh
21-
5hBR571xnXppuCPveTrctfTU7tJLSN94nq7kv7FRK5Tc
20+
Cuj97ggrhhidhbu39TijNVqE74xvKJ69gDervRUXAxGh # vrf oracle queue
21+
5hBR571xnXppuCPveTrctfTU7tJLSN94nq7kv7FRK5Tc # vrf oracle ephemeral queue
2222
F72HqCR8nwYsVyeVd38pgKkjXmXFzVAM8rjZZsXWbdE
2323
paywJiVATrVDLYLmowJqzG6MsaCt77L8WyTnBb2754t # vrf oracle identity
2424
CXMc1eCiEp9YXjanBNB6HUvbWCmxeVmhcR3bPXw8exJA # vrf oracle data
2525
GKE6d7iv8kCBrsxr78W3xVdjGLLLJnxsGiuzrsZCGEvb # queue for paywJiVATrVDLYLmowJqzG6MsaCt77L8WyTnBb2754t
2626
FRqXJqfCi3o6gF3Yqnkx1gKA3YnbRDJbBs6hKpme3NHJ # deleted queue for paywJiVATrVDLYLmowJqzG6MsaCt77L8WyTnBb2754t
27+
Sc9MJUngNbQXSXGP3F67KvKwVnhaYn6kcioxXNVowYT # ephemeral (delegated) test queue, index 1 for paywJ
28+
9yvg9551MmE8mhWd88jAPLE3noTXHoopYG1BDhmtkCeR # delegation record for Sc9MJ ephemeral test queue
29+
7L9eCRv52UpGVePGj9P1zop8kzmh4SpYzYn6YhoAKHBg # delegation metadata for Sc9MJ ephemeral test queue
2730
)
2831

2932
for acc in "${accounts[@]}"; do

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ solana-program-error = { version = "3.0" }
199199
solana-program-option = { version = "3.0" }
200200
solana-program-pack = { version = "3.0" }
201201
solana-program-runtime = { git = "https://github.com/magicblock-labs/magicblock-svm.git", rev = "b91ab7dad6642c63b9ea177fb318840b4c64c6cb" }
202+
solana-packet = { version = "3.0" }
202203
solana-pubkey = { version = "3.0" }
203204
solana-pubsub-client = { version = "3.1" }
204205
solana-rent = { version = "3.0" }

magicblock-committor-service/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ doctest = false
1212

1313
[dependencies]
1414
async-trait = { workspace = true }
15-
base64 = { workspace = true }
1615
bincode = { workspace = true }
1716
borsh = { workspace = true }
1817
compressed-delegation-api = { workspace = true }
@@ -41,6 +40,7 @@ solana-hash = { workspace = true }
4140
solana-instruction = { workspace = true }
4241
solana-keypair = { workspace = true }
4342
solana-message = { workspace = true }
43+
solana-packet = { workspace = true }
4444
solana-program = { workspace = true }
4545
solana-pubkey = { workspace = true }
4646
solana-rpc-client = { workspace = true }

magicblock-committor-service/src/tasks/mod.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -767,7 +767,7 @@ fn test_close_buffer_limit() {
767767
use crate::{
768768
test_utils,
769769
transactions::{
770-
serialize_and_encode_base64, MAX_ENCODED_TRANSACTION_SIZE,
770+
serialized_transaction_size, MAX_TRANSACTION_WIRE_SIZE,
771771
},
772772
};
773773

@@ -797,9 +797,9 @@ fn test_close_buffer_limit() {
797797
.collect();
798798

799799
let tx = Transaction::new_with_payer(&ixs, Some(&authority.pubkey()));
800-
let tx_size = serialize_and_encode_base64(&tx).len();
800+
let tx_size = serialized_transaction_size(&tx);
801801
info!(transaction_size = tx_size, "Cleanup task transaction size");
802-
assert!(tx_size <= MAX_ENCODED_TRANSACTION_SIZE);
802+
assert!(tx_size <= MAX_TRANSACTION_WIRE_SIZE);
803803

804804
// One more unique task should overflow
805805
let overflow_task = CleanupTask {
@@ -810,7 +810,5 @@ fn test_close_buffer_limit() {
810810
ixs.push(overflow_task.instruction(&authority.pubkey()));
811811

812812
let tx = Transaction::new_with_payer(&ixs, Some(&authority.pubkey()));
813-
assert!(
814-
serialize_and_encode_base64(&tx).len() > MAX_ENCODED_TRANSACTION_SIZE
815-
);
813+
assert!(serialized_transaction_size(&tx) > MAX_TRANSACTION_WIRE_SIZE);
816814
}

magicblock-committor-service/src/tasks/task_strategist.rs

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use crate::{
1212
commit_task::CommitDelivery, utils::TransactionUtils, BaseActionTask,
1313
BaseTask, BaseTaskImpl,
1414
},
15-
transactions::{serialize_and_encode_base64, MAX_ENCODED_TRANSACTION_SIZE},
15+
transactions::{serialized_transaction_size, MAX_TRANSACTION_WIRE_SIZE},
1616
};
1717

1818
#[derive(Default)]
@@ -222,7 +222,7 @@ impl TaskStrategist {
222222
) -> TaskStrategistResult<TransactionStrategy> {
223223
// Attempt optimizing tasks themselves(using buffers)
224224
if Self::try_optimize_tx_size_if_needed(&mut tasks)?
225-
<= MAX_ENCODED_TRANSACTION_SIZE
225+
<= MAX_TRANSACTION_WIRE_SIZE
226226
{
227227
// Persist tasks strategy
228228
if let Some(persistor) = persistor {
@@ -292,8 +292,7 @@ impl TaskStrategist {
292292
return false;
293293
};
294294

295-
let encoded_alt_tx = serialize_and_encode_base64(&alt_tx);
296-
encoded_alt_tx.len() <= MAX_ENCODED_TRANSACTION_SIZE
295+
serialized_transaction_size(&alt_tx) <= MAX_TRANSACTION_WIRE_SIZE
297296
}
298297

299298
pub fn collect_lookup_table_keys(
@@ -393,10 +392,10 @@ impl TaskStrategist {
393392
}
394393
}
395394

396-
/// Optimizes tasks so as to bring the transaction size within the limit [`MAX_ENCODED_TRANSACTION_SIZE`]
395+
/// Optimizes tasks so as to bring the transaction size within the limit [`MAX_TRANSACTION_WIRE_SIZE`]
397396
/// Returns Ok(size of tx after optimizations) else Err(SignerError).
398397
/// Note that the returned size, though possibly optimized one, may still not be under
399-
/// the limit MAX_ENCODED_TRANSACTION_SIZE. The caller needs to check and make decision accordingly.
398+
/// the limit MAX_TRANSACTION_WIRE_SIZE. The caller needs to check and make decision accordingly.
400399
fn try_optimize_tx_size_if_needed(
401400
tasks: &mut [BaseTaskImpl],
402401
) -> Result<usize, SignerError> {
@@ -408,7 +407,7 @@ impl TaskStrategist {
408407
u64::default(), // placeholder
409408
&[],
410409
) {
411-
Ok(tx) => Ok(serialize_and_encode_base64(&tx).len()),
410+
Ok(tx) => Ok(serialized_transaction_size(&tx)),
412411
Err(TaskStrategistError::FailedToFitError) => Ok(usize::MAX),
413412
Err(TaskStrategistError::SignerError(err)) => Err(err),
414413
}
@@ -417,7 +416,7 @@ impl TaskStrategist {
417416
// Get initial transaction size
418417
let mut current_tx_length = calculate_tx_length(tasks)?;
419418

420-
if current_tx_length <= MAX_ENCODED_TRANSACTION_SIZE {
419+
if current_tx_length <= MAX_TRANSACTION_WIRE_SIZE {
421420
return Ok(current_tx_length);
422421
}
423422

@@ -439,7 +438,7 @@ impl TaskStrategist {
439438

440439
// We keep popping heaviest el-ts & try to optimize while heap is non-empty
441440
while let Some((_, index)) = map.pop() {
442-
if current_tx_length <= MAX_ENCODED_TRANSACTION_SIZE {
441+
if current_tx_length <= MAX_TRANSACTION_WIRE_SIZE {
443442
break;
444443
}
445444

magicblock-committor-service/src/transactions.rs

Lines changed: 20 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
use base64::{prelude::BASE64_STANDARD, Engine};
1+
use solana_packet::PACKET_DATA_SIZE;
22
use solana_rpc_client::rpc_client::SerializableTransaction;
33
use static_assertions::const_assert;
44

5-
/// From agave rpc/src/rpc.rs [MAX_BASE64_SIZE]
6-
pub(crate) const MAX_ENCODED_TRANSACTION_SIZE: usize = 1644;
5+
/// Maximum serialized transaction size that can be sent over the wire.
6+
pub(crate) const MAX_TRANSACTION_WIRE_SIZE: usize = PACKET_DATA_SIZE;
77

88
/// How many process and commit buffer instructions fit into a single transaction
99
#[allow(unused)] // serves as documentation as well
@@ -34,7 +34,7 @@ pub const MAX_PROCESS_AND_CLOSE_PER_TX: u8 = 2;
3434
/// close buffer instructions fit into a single transaction when
3535
/// using lookup tables but not including the buffer account
3636
#[allow(unused)] // serves as documentation as well
37-
pub const MAX_PROCESS_AND_CLOSE_PER_TX_USING_LOOKUP: u8 = 5;
37+
pub const MAX_PROCESS_AND_CLOSE_PER_TX_USING_LOOKUP: u8 = 4;
3838

3939
/// How many finalize instructions fit into a single transaction
4040
#[allow(unused)] // serves as documentation as well
@@ -54,7 +54,7 @@ pub const MAX_UNDELEGATE_PER_TX: u8 = 3;
5454
/// when using address lookup tables
5555
/// NOTE: that we assume the rent reimbursement account to be the delegated account
5656
#[allow(unused)] // serves as documentation as well
57-
pub const MAX_UNDELEGATE_PER_TX_USING_LOOKUP: u8 = 16;
57+
pub const MAX_UNDELEGATE_PER_TX_USING_LOOKUP: u8 = 15;
5858

5959
// Allows us to run undelegate instructions without rechunking them since we know
6060
// that we didn't process more than we also can undelegate
@@ -66,12 +66,11 @@ const_assert!(
6666
MAX_PROCESS_PER_TX_USING_LOOKUP <= MAX_UNDELEGATE_PER_TX_USING_LOOKUP
6767
);
6868

69-
pub fn serialize_and_encode_base64(
69+
pub fn serialized_transaction_size(
7070
transaction: &impl SerializableTransaction,
71-
) -> String {
72-
// SAFETY: runs statically
73-
let serialized = bincode::serialize(transaction).unwrap();
74-
BASE64_STANDARD.encode(serialized)
71+
) -> usize {
72+
// SAFETY: runs on transactions we already serialize before sending.
73+
usize::try_from(bincode::serialized_size(transaction).unwrap()).unwrap()
7574
}
7675

7776
#[cfg(test)]
@@ -131,7 +130,7 @@ mod test {
131130
NoLookupTable,
132131
UseLookupTable,
133132
}
134-
fn encoded_tx_size(
133+
fn transaction_wire_size(
135134
auth: &Keypair,
136135
ixs: &[Instruction],
137136
opts: &TransactionOpts,
@@ -165,8 +164,7 @@ mod test {
165164
)
166165
})?;
167166

168-
let encoded = serialize_and_encode_base64(&versioned_tx);
169-
Ok(encoded.len())
167+
Ok(serialized_transaction_size(&versioned_tx))
170168
}
171169

172170
// -----------------
@@ -309,7 +307,7 @@ mod test {
309307
.collect::<Vec<_>>();
310308

311309
let tx_size =
312-
encoded_tx_size(auth, &ixs, &tx_opts).unwrap();
310+
transaction_wire_size(auth, &ixs, &tx_opts).unwrap();
313311
tx_sizes.push((size, tx_size));
314312
}
315313
tx_lines.push(tx_sizes);
@@ -349,51 +347,8 @@ mod test {
349347
run(auth, 10);
350348
run(auth, 15);
351349
run(auth, 20);
352-
/*
353-
0 ixs:
354-
0: 184| 10: 184| 20: 184| 50: 184| 100: 184| 200: 184| 500: 184|1024: 184
355-
0: 184| 10: 184| 20: 184| 50: 184| 100: 184| 200: 184| 500: 184|1024: 184
356-
1 ixs:
357-
0: 620| 10: 636| 20: 648| 50: 688| 100: 756| 200: 888| 500: 1288|1024: 1988
358-
0: 336| 10: 348| 20: 364| 50: 404| 100: 472| 200: 604| 500: 1004|1024: 1704
359-
2 ixs:
360-
0: 932| 10: 960| 20: 984| 50: 1064| 100: 1200| 200: 1468| 500: 2268|1024: 3664
361-
0: 400| 10: 424| 20: 452| 50: 532| 100: 668| 200: 936| 500: 1736|1024: 3132
362-
5 ixs:
363-
0: 1864| 10: 1932| 20: 1996| 50: 2196| 100: 2536| 200: 3204| 500: 5204|1024: 8696
364-
0: 588| 10: 652| 20: 720| 50: 920| 100: 1260| 200: 1928| 500: 3928|1024: 7420
365-
8 ixs:
366-
0: 2796| 10: 2904| 20: 3008| 50: 3328| 100: 3872| 200: 4940| 500: 8140|1024:13728
367-
0: 776| 10: 880| 20: 988| 50: 1308| 100: 1852| 200: 2920| 500: 6120|1024:11708
368-
10 ixs:
369-
0: 3416| 10: 3552| 20: 3684| 50: 4084| 100: 4764| 200: 6096| 500:10096|1024:17084
370-
0: 900| 10: 1032| 20: 1168| 50: 1568| 100: 2248| 200: 3580| 500: 7580|1024:14568
371-
15 ixs:
372-
0: 4972| 10: 5172| 20: 5372| 50: 5972| 100: 6992| 200: 8992| 500:14992|1024:25472
373-
0: 1212| 10: 1412| 20: 1612| 50: 2212| 100: 3232| 200: 5232| 500:11232|1024:21712
374-
20 ixs:
375-
0: 6524| 10: 6792| 20: 7056| 50: 7856| 100: 9216| 200:11884| 500:19884|1024:33856
376-
0: 1528| 10: 1792| 20: 2060| 50: 2860| 100: 4220| 200: 6888| 500:14888|1024:28860
377-
378-
Legend:
379-
380-
x ixs:
381-
data size/ix: encoded size | ...
382-
data size/ix: encoded size | ... (using lookup tables)
383-
384-
Given that max transaction size is 1644 bytes, we can see that the max data size is:
385-
386-
- 1 ixs: slightly larger than 500 bytes
387-
- 2 ixs: slightly larger than 200 bytes
388-
- 5 ixs: slightly larger than 100 bytes
389-
- 8 ixs: slightly larger than 50 bytes
390-
- 10 ixs: slightly larger than 20 bytes
391-
- 15 ixs: slightly larger than 10 bytes
392-
- 20 ixs: no data supported (only lamport changes)
393-
394-
Also it is clear that using a lookup table makes a huge difference especially if we commit
395-
lots of different accounts.
396-
*/
350+
// This logs raw wire sizes. The sendability limit is
351+
// MAX_TRANSACTION_WIRE_SIZE.
397352
}
398353

399354
// -----------------
@@ -573,13 +528,13 @@ mod test {
573528
&[&auth],
574529
)
575530
.unwrap();
576-
let encoded = serialize_and_encode_base64(&versioned_tx);
531+
let tx_size = serialized_transaction_size(&versioned_tx);
577532
info!(
578533
chunks = chunks,
579-
size_bytes = encoded.len(),
534+
size_bytes = tx_size,
580535
"Transaction size measured"
581536
);
582-
if encoded.len() > MAX_ENCODED_TRANSACTION_SIZE {
537+
if tx_size > MAX_TRANSACTION_WIRE_SIZE {
583538
return chunks - 1;
584539
}
585540
}
@@ -662,13 +617,13 @@ mod test {
662617
&[&auth],
663618
)
664619
.unwrap();
665-
let encoded = serialize_and_encode_base64(&versioned_tx);
620+
let tx_size = serialized_transaction_size(&versioned_tx);
666621
info!(
667622
chunks = chunks,
668-
size_bytes = encoded.len(),
623+
size_bytes = tx_size,
669624
"Transaction size measured with lookup table"
670625
);
671-
if encoded.len() > MAX_ENCODED_TRANSACTION_SIZE {
626+
if tx_size > MAX_TRANSACTION_WIRE_SIZE {
672627
return chunks - 1;
673628
}
674629
}

magicblock-processor/src/scheduler/mod.rs

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,8 @@ impl TransactionScheduler {
270270
biased;
271271
Ok(latest) = block_produced.recv() => {
272272
if !self.coordinator.is_primary() && latest.slot >= self.slot {
273-
self.transition_to_new_slot(Some(latest)).await;
273+
let slot = self.transition_to_new_slot(Some(latest)).await;
274+
self.handle_superblock(slot).await;
274275
}
275276
}
276277
_ = self.slot_ticker.tick() => {
@@ -342,8 +343,10 @@ impl TransactionScheduler {
342343
error!("failed to create accountsdb snapshot");
343344
return;
344345
};
345-
let msg = Message::SuperBlock(SuperBlock { slot, checksum });
346-
self.send_replication(msg).await;
346+
if self.coordinator.is_primary() {
347+
let msg = Message::SuperBlock(SuperBlock { slot, checksum });
348+
self.send_replication(msg).await;
349+
}
347350
}
348351

349352
async fn pause_executors_for_snapshot(&mut self) -> OwnedSemaphorePermit {
@@ -380,7 +383,7 @@ impl TransactionScheduler {
380383
);
381384
}
382385

383-
let _permit = self
386+
let permit = self
384387
.pause_permit
385388
.clone()
386389
.acquire_owned()
@@ -395,7 +398,17 @@ impl TransactionScheduler {
395398
.map_err(|error| error.to_string())?;
396399
self.accountsdb.set_slot(block.slot);
397400
self.update_sysvars(&block);
398-
self.notify_executors_of_block(block).await
401+
let slot = block.slot;
402+
let result = self.notify_executors_of_block(block).await;
403+
drop(permit);
404+
// apply_replayed_block advances self.slot before the queued
405+
// latest_block notification can be received. The block_produced path
406+
// then skips transition_to_new_slot for this already-applied slot, so
407+
// handle_superblock must run here for replayed superblock snapshots.
408+
if result.is_ok() {
409+
self.handle_superblock(slot).await;
410+
}
411+
result
399412
}
400413

401414
async fn notify_executors_of_block(

0 commit comments

Comments
 (0)