📥 استقبال المعاملات المفكوكة
يُدفع Decoded Shred Stream عبر UDP إلى عنوان IP والمنفذ اللذين تحددهما في صفحة تفاصيل البث — لا اتصال، لا مصافحة، لا إعادة إرسال. كل datagram لا يتجاوز 1,408 بايت ويحمل معاملة واحدة كاملة: ترويسة ثنائية من 16 بايت، ثم الـ slot، ثم المعاملة بتنسيق wire القياسي في Solana.
📦 ترويسة المغلّف (16 بايت)
يبدأ كل datagram بالترويسة الثابتة نفسها. جميع الأعداد الصحيحة little-endian.
| الإزاحة | الحجم | الحقل | القيمة / الدلالة |
|---|---|---|---|
| 0 | 2 | magic | 0x5AE7 (u16 LE) — أي قيمة أخرى ⇒ ارفض الـ datagram |
| 2 | 1 | version | 2 — ارفض أي إصدار غير معروف |
| 3 | 1 | msg_type | 2 = DecodedTx (1 = محجوز) |
| 4 | 1 | flags | محجوز، 0 |
| 5 | 1 | frag_index | فهرس الجزء، يبدأ من 0 — دائماً 0 للمعاملات المفكوكة |
| 6 | 1 | frag_count | عدد الأجزاء — دائماً 1 للمعاملات المفكوكة (لا تُجزّأ أبداً) |
| 7 | 1 | _pad | 0 |
| 8 | 8 | seq | u64 LE، متزايد رتيباً لكل بث منتج |
🧾 الحمولة (msg_type = 2)
مباشرةً بعد الترويسة:
| الحقل | الحجم | الدلالة |
|---|---|---|
slot | 8 | u64 LE — الـ slot الذي تنتمي إليه المعاملة |
transaction | بقية الـ datagram | تنسيق wire القياسي في Solana (VersionedTransaction مُسلسلة بـ bincode) |
بايتات المعاملة هي بالضبط ما يتوقعه أي SDK Solana — مرّرها إلى محلّلك الحالي دون تعديل. المعاملات المفكوكة لا تُجزّأ أبداً: كل datagram هو دائماً معاملة كاملة واحدة. معاملات التصويت مستبعدة افتراضياً.
📉 اكتشاف الفقد عبر seq
لا يعيد UDP الإرسال. كل datagram يحمل seq يزيد بمقدار 1 بالضبط ضمن بثك. أي فجوة في seq تعني فقدان هذا العدد من الـ datagrams:
seq المستلَم = 1042، السابق = 1039 ← فقدان 2 datagram
تتبّع آخر seq رأيته ونبّه عند الفجوات — الفقد المستمر يعني عادةً أن مخزن الاستقبال لديك صغير جداً (أدناه) أو وجود اختناق على المسار.
🔧 تحجيم المخزن المؤقت
يأتي البث على شكل اندفاعات (bursts) — قد يسلّم slot مزدحم معاملات كثيرة متتالية. امنح المقبس مخزن استقبال سخياً (SO_RCVBUF، عدة ميغابايتات) لتُمتصّ الاندفاعات القصيرة بدلاً من أن تُسقطها النواة، وأفرغ المقبس من حلقة مخصصة وسريعة.
💻 مفكك ترميز بسيط (Python)
import socket, structsock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)sock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 8 * 1024 * 1024)sock.bind(("0.0.0.0", 5000)) # المنفذ الذي حددته في لوحة التحكمexpected = Nonewhile True:dgram = sock.recv(2048)if len(dgram) < 24:continuemagic, version, msg_type = struct.unpack_from("<HBB", dgram, 0)if magic != 0x5AE7 or version != 2:continue # ارفض magic/version غير المعروفينif msg_type != 2:continue # ليس datagram من نوع DecodedTx(seq,) = struct.unpack_from("<Q", dgram, 8)if expected is not None and seq != expected:print(f"gap: {seq - expected} datagram(s) lost")expected = seq + 1(slot,) = struct.unpack_from("<Q", dgram, 16)tx_bytes = dgram[24:] # تنسيق wire القياسي — مرّره إلى أي محلّل معاملات Solana
🦀 العملاء الرسميون ووحدة codec
لست مضطراً إلى كتابة مفكك الترميز أعلاه: عملاء decoded-shredstream الرسميون (Rust وGo وJavaScript/TypeScript وPython) يربطون المنفذ، ويحلّلون المغلّف، ويكتشفون فجوات seq، ويسلّمونك كل معاملة مع الـ slot والتوقيعات الخاصة بها — عبر UDP وgRPC على حدٍّ سواء، بالـ API نفسها.
// cargo add decoded-shredstream tokio --features tokio/macros,tokio/rt-multi-threaduse decoded_shredstream::{UdpClient, UdpConfig};#[tokio::main]async fn main() -> std::io::Result<()> {let mut client = UdpClient::bind(UdpConfig { port: 8002, ..Default::default() })?;while let Some(update) = client.next_update().await {println!("slot={} sig={} {}B", update.slot(), update.signature(), update.bytes().len());}Ok(())}
تعرض حزمة Rust أيضاً التأطير (framing) على شكل وحدة codec (الثوابت FRAME_MAGIC = 0x5AE7 وFRAME_VERSION = 2 وFRAME_HEADER_LEN = 16 وMAX_DATAGRAM = 1408، وparse_header، وStreamDecoder) كي تتمكن من فك ترميز datagrams مقروءة من مقبس تديره بنفسك — ويعرض عميل Go الشيء نفسه عبر ParseHeader / StreamDecoder:
use std::net::UdpSocket;use decoded_shredstream::codec::{Push, StreamDecoder, MAX_DATAGRAM};fn decode_loop(socket: &UdpSocket) -> std::io::Result<()> {let mut decoder = StreamDecoder::new();let mut buf = [0u8; MAX_DATAGRAM + 64];loop {let n = socket.recv(&mut buf)?;if let Push::Update(update) = decoder.push(&buf[..n]) {println!("slot={} sig={}", update.slot(), update.signature());}}}
التثبيت: npm install decoded-shredstream · pip install decoded-shredstream · cargo add decoded-shredstream · go get github.com/shredstream/decoded-shredstream-go.
➡️ الخطوات التالية
- Decoded Shred Stream — الموقع، وزمن الاستجابة، وأوضاع التوصيل.
- التسليم عبر gRPC — المعاملات نفسها عبر بث مرتّب قائم على الاتصال، مع تصفية الحسابات على جانب الخادم.