📥 استقبال المعاملات المفكوكة

يُدفع Decoded Shred Stream عبر UDP إلى عنوان IP والمنفذ اللذين تحددهما في صفحة تفاصيل البث — لا اتصال، لا مصافحة، لا إعادة إرسال. كل datagram لا يتجاوز 1,408 بايت ويحمل معاملة واحدة كاملة: ترويسة ثنائية من 16 بايت، ثم الـ slot، ثم المعاملة بتنسيق wire القياسي في Solana.


📦 ترويسة المغلّف (16 بايت)

يبدأ كل datagram بالترويسة الثابتة نفسها. جميع الأعداد الصحيحة little-endian.

الإزاحةالحجمالحقلالقيمة / الدلالة
02magic0x5AE7 ‏(u16 LE) — أي قيمة أخرى ⇒ ارفض الـ datagram
21version2 — ارفض أي إصدار غير معروف
31msg_type2 = DecodedTx ‏(1 = محجوز)
41flagsمحجوز، 0
51frag_indexفهرس الجزء، يبدأ من 0 — دائماً 0 للمعاملات المفكوكة
61frag_countعدد الأجزاء — دائماً 1 للمعاملات المفكوكة (لا تُجزّأ أبداً)
71_pad0
88seq‏u64 LE، متزايد رتيباً لكل بث منتج

🧾 الحمولة (msg_type = 2)

مباشرةً بعد الترويسة:

الحقلالحجمالدلالة
slot8‏u64 LE — الـ slot الذي تنتمي إليه المعاملة
transactionبقية الـ datagramتنسيق wire القياسي في Solana ‏(VersionedTransaction مُسلسلة بـ bincode)

بايتات المعاملة هي بالضبط ما يتوقعه أي SDK ‏Solana — مرّرها إلى محلّلك الحالي دون تعديل. المعاملات المفكوكة لا تُجزّأ أبداً: كل datagram هو دائماً معاملة كاملة واحدة. معاملات التصويت مستبعدة افتراضياً.


📉 اكتشاف الفقد عبر seq

لا يعيد UDP الإرسال. كل datagram يحمل seq يزيد بمقدار 1 بالضبط ضمن بثك. أي فجوة في seq تعني فقدان هذا العدد من الـ datagrams:

text
seq المستلَم = 1042، السابق = 1039 ← فقدان 2 datagram

تتبّع آخر seq رأيته ونبّه عند الفجوات — الفقد المستمر يعني عادةً أن مخزن الاستقبال لديك صغير جداً (أدناه) أو وجود اختناق على المسار.


🔧 تحجيم المخزن المؤقت

يأتي البث على شكل اندفاعات (bursts) — قد يسلّم slot مزدحم معاملات كثيرة متتالية. امنح المقبس مخزن استقبال سخياً ‏(SO_RCVBUF، عدة ميغابايتات) لتُمتصّ الاندفاعات القصيرة بدلاً من أن تُسقطها النواة، وأفرغ المقبس من حلقة مخصصة وسريعة.


💻 مفكك ترميز بسيط (Python)

python
import socket, struct
sock = 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 = None
while True:
dgram = sock.recv(2048)
if len(dgram) < 24:
continue
magic, 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 نفسها.

rust
// cargo add decoded-shredstream tokio --features tokio/macros,tokio/rt-multi-thread
use 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:

rust
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 — المعاملات نفسها عبر بث مرتّب قائم على الاتصال، مع تصفية الحسابات على جانب الخادم.
استقبال المعاملات المفكوكة — Docs | ShredStream.com