Blockchain هي تقنية مبتكرة تعد بتحسين العديد من مجالات الحياة البشرية. إنه ينقل العمليات والمنتجات الحقيقية إلى الفضاء الرقمي ، ويضمن سرعة وموثوقية المعاملات المالية ، ويقلل من تكلفتها ، ويسمح لك أيضًا بإنشاء تطبيقات DAPP حديثة باستخدام العقود الذكية في الشبكات اللامركزية.
نظرًا للعديد من المزايا والاستخدامات المتنوعة لـ blockchain ، فقد يبدو غريباً أن هذه التكنولوجيا الواعدة لم تخترق بعد جميع القطاعات. المشكلة تكمن في أن السلاسل اللامركزية الحديثة تفتقر إلى قابلية التوسع. يعالج Ethereum حوالي 20 معاملة في الثانية ، وهو ما لا يكفي لتلبية احتياجات الأعمال الحيوية اليوم. في الوقت نفسه ، لا تجرؤ الشركات التي تستخدم تقنية blockchain على التخلي عن Ethereum بسبب درجة الحماية العالية ضد القرصنة وإخفاقات الشبكة.
من أجل ضمان اللامركزية والأمن وقابلية التوسع على blockchain ، وبالتالي حل Tralemal Trilemma ، قام
فريق تطوير الفرصة بتطوير Plasma Cash - سلسلة فرعية تتكون من عقد ذكي وشبكة خاصة تعتمد على Node.js ، وتنقل حالتها بشكل دوري إلى سلسلة الجذر ( Ethereum).

العمليات الرئيسية في Plasma Cash
1. يقوم المستخدم باستدعاء وظيفة العقد الذكي "إيداع" ، ونقل المبلغ الموجود في ETH إلى ذلك ، والذي يريد وضعه في الرمز المميز للبلازما. تقوم وظيفة العقد الذكية بإنشاء رمز مميز وتولد حدثًا حول هذا الموضوع.
2. العقد البلازما النقدية المشتركة في أحداث العقد الذكي تلقي حدث حول إنشاء إيداع وإضافة معاملة حول إنشاء رمز مميز إلى المجمع.
3. بشكل دوري ، تأخذ نقاط Plasma Cash الخاصة جميع المعاملات من المجمع (حتى 1 مليون) وتشكل كتلة منها ، وحساب شجرة Merkle ، وبالتالي التجزئة. يتم إرسال هذه الكتلة إلى العقد الأخرى للتحقق منها. تتحقق العقد من صحة تجزئة Merkle ، وما إذا كانت المعاملات صالحة (على سبيل المثال ، إذا كان مرسل الرمز مميز هو مالكها). بعد التحقق من الكتلة ، تستدعي العقدة الدالة `submitBlock` للعقد الذكي ، والتي تخزن الرقم وتجزئة Merkle للكتلة في سلسلة التتبع. يُنشئ العقد الذكي حدثًا حول الإضافة الناجحة للكتلة. يتم حذف المعاملات من التجمع.
4. تبدأ العقد التي تلقت الحدث حول تقديم الكتلة في تطبيق المعاملات التي تمت إضافتها إلى الكتلة.
5. في مرحلة ما ، يريد مالك (أو غير مالك) الرمز المميز سحبه من Plasma Cash. للقيام بذلك ، يقوم باستدعاء الدالة `startExit` ، ويمرر معلومات حول آخر معاملتين على الرمز المميز فيه ، مما يؤكد أنه مالك الرمز المميز. يتحقق العقد الذكي ، باستخدام تجزئة Merkle ، من المعاملات في الكتل ويرسل رمزًا مميزًا للإخراج ، والذي سيحدث خلال أسبوعين.
6. في حالة حدوث عملية سحب الرمز المميز مع حدوث انتهاكات (تم إنزال الرمز المميز بعد بدء إجراء السحب أو كان الرمز مميزًا بالفعل غريبًا على الانسحاب) ، يمكن لمالك الرمز المميز دحض الانسحاب خلال أسبوعين.

يتم تحقيق الخصوصية بطريقتين.
1. سلسلة الجذر لا تعرف أي شيء عن المعاملات التي يتم تشكيلها وإعادة توجيهها داخل السلسلة الفرعية. تبقى المعلومات حول من بدأ وسحب ETH من / إلى Plasma Cash.
2. تتيح لك السلسلة الفرعية تنظيم معاملات مجهولة باستخدام zk-SNARKs.
كومة التكنولوجية
تجريب
عند تطوير Plasma Cash ، اختبرنا سرعة النظام وحصلنا على النتائج التالية:
- تتم إضافة ما يصل إلى 35000 معاملة في الثانية إلى المجموعة ؛
- يمكن تخزين ما يصل إلى 1،000،000 معاملة في الكتلة.
تم إجراء الاختبارات على الخوادم الثلاثة التالية:
1. إنتل كور i7-6700 رباعي النواة Skylake مدفوع. NVMe SSD - 512 جيجابايت ، 64 جيجابايت ذاكرة DDR4رفعت 3 نقاط التحقق من صحة البلازما.
2. AMD Ryzen 7 1700X ثماني النواة "Summit Ridge" (Zen) ، SATA SSD - 500 جيجابايت ، 64 جيجابايت ذاكرة DDR4تم رفع عقدة RSTST testnet ETH.
رفعت 3 نقاط التحقق من صحة البلازما.
3. Intel Core i9-9900K Octa-Core incl. NVMe SSD - 1 تيرابايت ، ذاكرة وصول عشوائي DDR4 بسعة 64 جيجابايت1 تم إرسال عقدة Plasma Cash.
رفعت 3 نقاط التحقق من صحة البلازما.
تم إطلاق اختبار لإضافة المعاملات إلى شبكة Plasma Cash.
المجموع: 10 نقاط البلازما النقدية في شبكة خاصة.
اختبار 1
هناك حد مليون المعاملات لكل كتلة. لذلك ، هناك مليون معاملة تنقسم إلى كتلتين (نظرًا لأن النظام يدير المشاركة في المعاملات ويرسلها أثناء إرسالها).
الحالة الأولية: آخر كتلة # 7 ؛ يتم تخزين 1 مليون معاملة ورموز في قاعدة البيانات.
00:00 - بدء البرنامج النصي لإنشاء المعاملة
01:37 - تم إنشاء مليون معاملة وبدأ إرسالها إلى العقدة
01:46 - أخذت عقدة التقديم 240k معاملة من المجموعة ونماذج المجموعة رقم 8. نرى أيضًا أنه تتم إضافة معاملات 320 ألف إلى المجموعة خلال 10 ثوانٍ
01:58 - يتم توقيع الكتلة رقم 8 وإرسالها للتحقق من الصحة
02:03 - يتم التحقق من صحة المربع رقم 8 ويتم استدعاء وظيفة `submitBlock` للعقد الذكي مع تجزئة Merkle ورقم الكتلة
02:10 - انتهى البرنامج النصي التجريبي من العمل ، والذي أرسل مليون معاملة في 32 ثانية
02:33 - بدأت العقد في تلقي المعلومات التي تمت إضافتها للكتلة رقم 8 إلى سلسلة الجذر ، وبدأت في تنفيذ 240 ألف معاملة
تم حذف 02:40 - 240 ألف معاملة من التجمع ، والتي هي بالفعل في كتلة رقم 8
02:56 - إرسال عقدة أخذت المعاملات المتبقية 760k من المجمع وبدأت في حساب تجزئة Merkle وتوقيع كتلة # 9
03:20 - جميع العقد تحتوي على المعاملات و الرموز بحجم 1 مليون
03:35 - كتلة # 9 موقعة وإرسالها للتحقق من الصحة إلى العقد الأخرى
03:41 - حدث خطأ في الشبكة
04:40 - بحلول المهلة ، توقف انتظار التحقق من صحة الكتلة رقم 9
04:54 - أخذت العقدة تقديم المعاملات المتبقية 760k من التجمع وبدأت في حساب تجزئة Merkle وتوقيع كتلة # 9
05:32 - كتلة # 9 موقعة وإرسالها للتحقق من الصحة إلى العقد الأخرى
05:53 - يتم التحقق من صحة الكتلة رقم 9 وإرسالها إلى سلسلة الجذر
06:17 - بدأت العقد في تلقي المعلومات التي تمت إضافتها للكتلة رقم 9 إلى سلسلة الجذر وبدأت في تنفيذ 760 ألف معاملة
06:47 - تم مسح المجموعة من المعاملات الموجودة في المربع رقم 9
09:06 - جميع العقد تحتوي على 2 مليون معاملة ورموز
اختبار 2
هناك حد 350k لكل كتلة. نتيجة لذلك ، لدينا 3 كتل.
الحالة الأولية: آخر كتلة # 9 ؛ 2 مليون معاملة ورموز مخزنة في قاعدة البيانات
00:00 - البرنامج النصي لإنشاء المعاملات قيد التشغيل بالفعل
00:44 - تم إنشاء مليون معاملة وبدأ إرسالها إلى العقدة
00:56 - أخذت العقدة تقديم معاملات 320k من التجمع ونماذج كتلة رقم 10. نرى أيضًا أنه تتم إضافة معاملات 320 ألف إلى المجموعة خلال 10 ثوانٍ
01:12 - يتم توقيع الكتلة رقم 10 وإرسالها إلى العقد الأخرى للتحقق من صحتها
18: 1 - انتهى البرنامج النصي التجريبي من العمل ، والذي أرسل مليون معاملة في 34 ثانية
01:20 - يتم التحقق من صحة المربع رقم 10 وإرساله إلى سلسلة الجذر
01:51 - تمت إضافة جميع العقد التي تم تلقيها من سلسلة الجذر التي تم حظرها رقم 10 ، وبدأت في تطبيق معاملات 320 كيلو
02:01 - تم مسح البركة للمعاملات 320k التي تمت إضافتها لحجب رقم 10
02:15 - إرسال عقدة استغرق 350k المعاملات من التجمع ونماذج كتلة # 11
02:34 - كتلة # 11 يتم توقيع وإرسالها إلى العقد الأخرى للتحقق من الصحة
02:51 - يتم التحقق من صحة الكتلة رقم 11 وإرسالها إلى سلسلة الجذر
02:55 - آخر العقدة المنفذة المعاملات من كتلة رقم 10
10:59 - لفترة طويلة جدًا ، تم تنفيذ معاملة في سلسلة الجذر مع تقديم الكتلة رقم 9 ، لكنها اكتملت وتلقى جميع العقد معلومات حول هذا وبدأ تنفيذ المعاملات 350k
05: 11 - تم مسح تجمع للمعاملات 320k التي تمت إضافتها إلى كتلة رقم 11
12:10 - تحتوي جميع العقد على 1 مليون معاملة 670k ورموز
12:17 - إرسال عقدة استغرق 330k المعاملات من التجمع ونماذج كتلة # 12
12:32 - يتم توقيع الكتلة رقم 12 وإرسالها إلى العقد الأخرى للتحقق من صحتها
12:39 - يتم التحقق من صحة المربع رقم 12 وإرساله إلى سلسلة الجذر
13:44 - تمت إضافة جميع العقد التي تم تلقيها من سلسلة الجذر والتي تم حظرها # 12 وبدأت في تطبيق 330 ألف معاملة
50:14 - جميع العقد تحتوي على 2 مليون معاملة ورموز
اختبار 3
في الخوادم الأولى والثانية ، تم استبدال عقدة التحقق من الصحة بعقدة إرسال.
الحالة الأولية: المربع الأخير # 84؛ يتم تخزين المعاملات 0 و الرموز في قاعدة البيانات
00:00 - يتم إطلاق 3 برامج نصية تولد وترسل مليون معاملة
01:38 - تم إنشاء مليون معاملة وبدأ إرسال إرسال العقدة رقم 3
01:50 - إرسال عقدة # 3 استغرق 330k المعاملات من التجمع ونماذج كتلة 85 (f21). نرى أيضًا أنه تتم إضافة 350 ألف معاملة إلى المجموعة خلال 10 ثوانٍ
01:53 - تم إنشاء مليون معاملة وبدأ إرسالها لإرسال العقدة رقم 1
01:50 - إرسال عقدة # 3 استغرق 330k المعاملات من التجمع ونماذج كتلة 85 (f21). نرى أيضًا أنه تتم إضافة 350 ألف معاملة إلى المجموعة خلال 10 ثوانٍ
02:01 - إرسال عقدة # 1 استغرق 250K المعاملات من التجمع ونماذج كتلة 85 (65e)
02:06 - يتم توقيع الكتلة رقم 85 (f21) وإرسالها إلى العقد الأخرى للتحقق من صحتها
02:08 - انتهى البرنامج النصي للعرض التوضيحي الخاص بالخادم رقم 3 من العمل ، والذي أرسل معاملات بقيمة 1 مليون في 30 ثانية
02:14 - يتم التحقق من صحة الكتلة رقم 85 (f21) وإرسالها إلى سلسلة الجذر
02:19 - كتلة # 85 (65e) يتم التوقيع وإرسالها إلى العقد الأخرى للتحقق من الصحة
02:22 - تم إنشاء مليون معاملة وبدأ إرسال إرسال العقدة رقم 2
02:27 - يتم التحقق من صحة العنصر رقم 85 (65e) وإرساله إلى سلسلة الجذر
02:29 - إرسال عقدة # 2 أخذت من تجمع 111855 المعاملات ونماذج كتلة رقم 85 (256).
02:36 - كتلة # 85 (256) يتم التوقيع وإرسالها إلى العقد الأخرى للتحقق من الصحة
02:36 - انتهى البرنامج النصي الخاص بالخادم رقم 1 من العمل ، والذي أرسل معاملات بقيمة 1 مليون في 42.5 ثانية
02:38 - يتم التحقق من صحة الكتلة رقم 85 (256) وإرسالها إلى سلسلة الجذر
03:08 - سيناريو الخادم رقم 2 ، الذي أرسل مليون معاملة في 47 ثانية ، انتهى من العمل
03:38 - تلقت جميع العقد معلومات من سلسلة الجذر التي تمت إضافة الكتل رقم 85 (f21) و # 86 (65e) و # 87 (256) وبدأت في تطبيق 330k و 250k و 111855
03:49 - تمت إزالة البركة من 330 ألفًا و 250 ألفًا و 111855 صفقة تمت إضافتها إلى الكتل رقم 85 (f21) و # 86 (65e) و # 87 (256)
03:59 - إرسال عقدة # 1 مأخوذة من مجموعة 888145 المعاملات ونماذج كتلة رقم 88 (214) ، تقديم عقدة # 2 أخذت من المعاملات تجمع 750K ونماذج كتلة # 88 (50A) ، تقديم عقدة # 3 مأخوذة من المعاملات 670k تجمع نماذج النماذج رقم 88 (d3b)
04:44 - يتم توقيع الكتلة رقم 88 (d3b) وإرسالها إلى العقد الأخرى للتحقق من صحتها
04:58 - يتم توقيع الكتلة رقم 88 (214) وإرسالها إلى العقد الأخرى للتحقق من صحتها
05:11 - كتلة # 88 (50a) يتم التوقيع وإرسالها إلى العقد الأخرى للتحقق من الصحة
05:11 - يتم التحقق من صحة الكتلة رقم 85 (d3b) وإرسالها إلى سلسلة الجذر
05:36 - يتم التحقق من صحة الكتلة رقم 85 (214) وإرسالها إلى سلسلة الجذر
05:43 - جميع العقد التي تلقت معلومات من سلسلة الجذر التي تم حظرها رقم 88 (d3b) ، تمت إضافة رقم 89 (214) وبدأت في تطبيق 670k ، 750k معاملة
06:50 - بسبب انقطاع الاتصال ، لم يتم التحقق من صحة الكتلة رقم 85 (50a)
06:55 - إرسال عقدة # 2 استغرق 888145 المعاملات من التجمع ونماذج كتلة رقم 90 (50A)
08:14 - كتلة # 90 (50a) يتم التوقيع وإرسالها إلى العقد الأخرى للتحقق من الصحة
09:04 - يتم التحقق من صحة الكتلة رقم 90 (50a) وإرسالها إلى سلسلة الجذر
11:23 - تمت إضافة جميع العقد التي تم تلقيها من سلسلة الجذر التي تم حظرها رقم 90 (50a) ، وبدأ تطبيق 888145 معاملة. في الوقت نفسه ، يطبق الخادم رقم 3 معاملات مطولة من الكتل رقم 88 (d3b) و # 89 (214)
11: 11 - جميع حمامات فارغة
41: 13 - تحتوي جميع العقد الخادم # 3 على 3 ملايين معاملة ورموز
35: 14 - تحتوي جميع العقد الخادم رقم 1 على 3 ملايين معاملة ورموز
24: 19 - جميع العقد الخادم # 2 تحتوي على 3 ملايين معاملة ورموز
العقبات
أثناء تطوير Plasma Cash ، واجهنا المشكلات التالية ، والتي قمنا بحلها تدريجياً وحلها:
1. تعارض التفاعل بين وظائف النظام المختلفة. على سبيل المثال ، منعت وظيفة إضافة المعاملات إلى التجمع من تقديم والتحقق من صحة الكتل ، والعكس بالعكس ، مما أدى إلى انخفاض السرعة.
2. لم يكن من الواضح على الفور كيفية إرسال عدد كبير من المعاملات وفي الوقت نفسه تقليل تكلفة نقل البيانات.
3. لم يكن من الواضح كيف وأين يتم تخزين البيانات من أجل تحقيق نتائج عالية.
4. لم يكن من الواضح كيفية تنظيم شبكة بين العقد ، حيث أن حجم الكتلة مع 1 مليون معاملة يستغرق حوالي 100 ميغابايت.
5. العمل في وضع المفرد مترابطة يقطع الاتصال بين العقد عند حدوث عمليات حسابية طويلة (على سبيل المثال ، بناء شجرة Merkle وحساب التجزئة الخاصة به).
كيف تعاملنا مع كل هذا؟
كان الإصدار الأول من عقدة Plasma Cash عبارة عن نوع من أنواع الدمج يمكن أن يفعل كل شيء في نفس الوقت: قبول المعاملات ، وإرسال والتحقق من الكتل ، وتوفير واجهة برمجة تطبيقات للوصول إلى البيانات. نظرًا لأن NodeJS كان مترابطًا في البداية ، فإن وظيفة حساب شجرة ميركل الثقيلة منعت وظيفة الإضافة للمعاملات. لقد رأينا خيارين لحل هذه المشكلة:
1. قم بتشغيل عدة عمليات NodeJS ، كل منها يؤدي وظائف معينة.
2. استخدام worker_threads ووضع تنفيذ التعليمات البرمجية في المواضيع.
نتيجة لذلك ، استخدمنا كلا الخيارين في نفس الوقت: قسمنا عقدة منطقية إلى 3 أجزاء ، والتي يمكن أن تعمل بشكل منفصل ، ولكن في نفس الوقت بشكل متزامن
1. تقديم عقدة تقبل المعاملات إلى التجمع ويخلق كتل.
2. التحقق من صحة العقدة التي تتحقق من صحة العقد.
3. Node API - يوفر API للوصول إلى البيانات.
في الوقت نفسه ، يمكنك الاتصال بكل عقدة من خلال مأخذ يونيكس باستخدام CLI.
العمليات الثقيلة ، مثل حساب شجرة Merkle ، قمنا بها في دفق منفصل.
وبالتالي ، حققنا التشغيل الطبيعي لجميع وظائف Plasma Cash في وقت واحد ودون إخفاقات.
بمجرد أن يعمل النظام وظيفيًا ، بدأنا في اختبار السرعة ، وللأسف ، حصلنا على نتائج غير مرضية: 5000 معاملة في الثانية وحتى 50،000 معاملة في كتلة واحدة. اضطررت لمعرفة ما تم تنفيذه بشكل غير صحيح.
بادئ ذي بدء ، بدأنا في اختبار آلية التواصل مع Plasma Cash لمعرفة القدرة القصوى للنظام. في وقت سابق كتبنا أن العقدة النقدية البلازما توفر واجهة مقبس يونيكس. كان في الأصل نصية. تم إرسال كائنات json باستخدام `JSON.parse ()` و `JSON.stringify ()`.
```json { "action": "sendTransaction", "payload":{ "prevHash": "0x8a88cc4217745fd0b4eb161f6923235da10593be66b841d47da86b9cd95d93e0", "prevBlock": 41, "tokenId": "57570139642005649136210751546585740989890521125187435281313126554130572876445", "newOwner": "0x200eabe5b26e547446ae5821622892291632d4f4", "type": "pay", "data": "", "signature": "0xd1107d0c6df15e01e168e631a386363c72206cb75b233f8f3cf883134854967e1cd9b3306cc5c0ce58f0a7397ae9b2487501b56695fe3a3c90ec0f61c7ea4a721c" } } ```
قمنا بقياس سرعة نقل هذه الأشياء وتلقينا ~ 130k في الثانية. حاولوا استبدال الوظائف القياسية بـ json ، لكن الأداء لم يتحسن. يجب أن يكون هناك محرك V8 الأمثل لهذه العمليات.
العمل مع المعاملات ، الرموز ، تم تنفيذ الكتل من خلال الطبقات. عند إنشاء مثل هذه الفئات ، تباطأ الأداء مرتين ، مما يشير إلى: OOP غير مناسب لنا. اضطررت إلى إعادة كتابة كل شيء على نهج وظيفي بحت.
الكتابة إلى قاعدة البيانات
في البداية ، تم اختيار Redis لتخزين البيانات كأحد الحلول الأكثر إنتاجية التي تلبي متطلباتنا: التخزين ذي القيمة الأساسية ، العمل مع جداول التجزئة ، والكثير. أطلقنا redis-benchmark وحصلنا على حوالي 80 ألف عملية في الثانية في وضع خط أنابيب واحد.
من أجل الأداء العالي ، قمنا بضبط Redis بشكل أكثر دقة:
- تأسيس اتصال مأخذ يونيكس.
- تعطيل حفظ الحالة على القرص (من أجل الموثوقية ، يمكنك تكوين النسخة المتماثلة والحفظ بالفعل على القرص في Redis منفصل).
في Redis ، يمثل التجمع جدولًا للتجزئة ، حيث نحتاج إلى القدرة على تلقي جميع المعاملات في طلب واحد وحذف المعاملات واحدًا تلو الآخر. لقد حاولنا استخدام قائمة عادية ، ولكنها تعمل ببطء أكبر عند تفريغ القائمة بأكملها.
باستخدام مكتبة NodeJS القياسية ، حققت مكتبات Redis 18 ألف معاملة في الأداء في الثانية. انخفضت السرعة 9 مرات.
نظرًا لأن المعيار أظهر لنا الاحتمالات بوضوح 5 مرات أكثر ، فقد بدأوا في التحسين. لقد غيرنا المكتبة إلى ioredis وحصلنا على أداء قدره 25k في الثانية. أضفنا المعاملات واحدة تلو الأخرى باستخدام الأمر "hset". وبالتالي ، أنشأنا العديد من الطلبات في Redis. كانت هناك فكرة لدمج المعاملات في حزم وإرسالها بأمر hmset واحد. والنتيجة هي 32 كيلو في الثانية.
لعدة أسباب ، سيتم وصفها أدناه ، نعمل مع البيانات باستخدام "Buffer" ، وكما اتضح فيما بعد ، إذا قمت بترجمته إلى نص (`buffer.toString ('hex')`) قبل الكتابة ، يمكنك الحصول على أداء إضافي. وبالتالي ، تم زيادة السرعة إلى 35 كيلو في الثانية. في الوقت الحالي ، قررنا تعليق التحسين الإضافي.
كان علينا التبديل إلى البروتوكول الثنائي للأسباب التالية:
1. غالبًا ما يقوم النظام بحساب التجزئة والتواقيع وما إلى ذلك ، ولهذا يحتاج إلى بيانات في "المخزن المؤقت".
2. عند النقل بين الخدمات ، تزن البيانات الثنائية أقل من النص. على سبيل المثال ، عند إرسال كتلة بها مليون معاملة ، يمكن أن تشغل البيانات الموجودة في النص أكثر من 300 ميغابايت.
3. تحويل البيانات المستمر يؤثر على الأداء.
لذلك ، اتخذنا كبروتوكولنا الثنائي الخاص بنا لتخزين ونقل البيانات ، والذي تم تطويره على أساس مكتبة البيانات الثنائية الرائعة.
نتيجة لذلك ، لدينا هياكل البيانات التالية:
- المعاملات
```json { prevHash: BD.types.buffer(20), prevBlock: BD.types.uint24le, tokenId: BD.types.string(null), type: BD.types.uint8, newOwner: BD.types.buffer(20), dataLength: BD.types.uint24le, data: BD.types.buffer(({current}) => current.dataLength), signature: BD.types.buffer(65), hash: BD.types.buffer(32), blockNumber: BD.types.uint24le, timestamp: BD.types.uint48le, } ```
- الرمز
```json { id: BD.types.string(null), owner: BD.types.buffer(20), block: BD.types.uint24le, amount: BD.types.string(null), } ```
- بلوك
```json { number: BD.types.uint24le, merkleRootHash: BD.types.buffer(32), signature: BD.types.buffer(65), countTx: BD.types.uint24le, transactions: BD.types.array(Transaction.Protocol, ({current}) => current.countTx), timestamp: BD.types.uint48le, } ```
من خلال الأوامر المعتادة `BD.encode (block، Protocol) .slice ()؛` و `BD.decode (buffer، Protocol)` ، نقوم بتحويل البيانات إلى "Buffer" لحفظها في Redis أو إرسال عقدة أخرى واسترداد البيانات مرة أخرى.
لدينا أيضًا بروتوكولان ثنائيان لنقل البيانات بين الخدمات:
- بروتوكول للتفاعل مع البلازما عقدة عبر مأخذ يونيكس ```json { type: BD.types.uint8, messageId: BD.types.uint24le, error: BD.types.uint8, length: BD.types.uint24le, payload: BD.types.buffer(({node}) => node.length) } ```
حيث:
- `type` - الإجراء المطلوب تنفيذه ، على سبيل المثال ، 1 - sendTransaction ، 2 - getTransaction ؛
- "الحمولة النافعة" - البيانات المراد نقلها إلى الوظيفة المقابلة ؛
- `messageId` - معرف الرسالة بحيث يمكن تحديد الاستجابة.
- بروتوكول التفاعل بين العقد ```json { code: BD.types.uint8, versionProtocol: BD.types.uint24le, seq: BD.types.uint8, countChunk: BD.types.uint24le, chunkNumber: BD.types.uint24le, length: BD.types.uint24le, payload: BD.types.buffer(({node}) => node.length) } ```
حيث:
- `code` - رمز الرسالة ، على سبيل المثال 6 - PREPARE_NEW_BLOCK ، 7 - BLOCK_VALID ، 8 - BLOCK_COMMIT ؛
- `versionProtocol` - إصدار البروتوكول ، حيث يمكن رفع العقد ذات الإصدارات المختلفة على الشبكة ويمكنها العمل بطرق مختلفة ؛
- `seq - معرف الرسالة ؛
- هناك حاجة إلى "countChunk" و "chunkNumber" لتقسيم الرسائل الكبيرة ؛
- " الطول" و " الحمولة" الطول والبيانات نفسها.
منذ أن قمنا بكتابة البيانات مسبقًا ، أصبح النظام النهائي أسرع بكثير من مكتبة rlp من Ethereum. لسوء الحظ ، لم نتمكن بعد من رفضه ، لأنه من الضروري الانتهاء من العقد الذكي ، الذي نعتزم القيام به في المستقبل.
إذا تمكنا من تحقيق سرعة تصل إلى
35000 معاملة في الثانية ، فنحن نحتاج أيضًا إلى معالجتها في الوقت الأمثل. نظرًا لأن وقت التكوين التقريبي للكتلة يستغرق 30 ثانية ، نحتاج إلى تضمين
1،000،000 معاملة في الكتلة ، مما يعني إرسال أكثر من
100 ميغابايت من البيانات.
في البداية ، استخدمنا مكتبة `ethereumjs-devp2p` للتواصل مع العقد ، لكنها لم تستطع التعامل مع الكثير من البيانات. نتيجة لذلك ، استخدمنا مكتبة `ws` وقمنا بإعداد نقل البيانات الثنائية على websocket. بالطبع ، واجهنا أيضًا مشكلات عند إرسال حزم بيانات كبيرة ، لكننا قسمناها إلى مجموعات ، والآن لا توجد مثل هذه المشكلات.
أيضًا ، يتطلب تكوين شجرة Merkle وحساب التجزئة
لـ 1،000،000 معاملة حوالي
10 ثوانٍ من الحساب المستمر. خلال هذا الوقت ، يمكن الاتصال مع جميع العقد لكسر. تقرر نقل هذا الحساب إلى سلسلة رسائل منفصلة.
الاستنتاجات:
في الواقع ، إن النتائج التي توصلنا إليها ليست جديدة ، ولكن لسبب ما ، ينسى الكثير من الخبراء هذه النتائج أثناء التطوير.
- استخدام البرمجة الوظيفية بدلاً من البرمجة الموجهة للكائن يزيد من الأداء.
- تعد الوحدة المتجانسة أسوأ من بنية الخدمة لنظام الإنتاج على NodeJS.
- يؤدي استخدام "worker_threads" للحوسبة الثقيلة إلى تحسين استجابة النظام ، خاصة عند العمل مع عمليات الإدخال / الإخراج.
- مأخذ يونكس هو أكثر استقرارا وأسرع من طلبات المتشعب.
- إذا كنت بحاجة إلى نقل البيانات الكبيرة بسرعة عبر الشبكة ، فمن الأفضل استخدام مجموعات الويب وإرسال البيانات الثنائية ، المقطوعة إلى مجموعات ، والتي يمكن إعادة توجيهها إذا لم تصل ، ثم يتم دمجها في رسالة واحدة.
نحن ندعوك لزيارة مشروع
جيثب :
https://github.com/opporty-com/Plasma-Cash/tree/new-versionشارك في كتابة
المقال ألكساندر ناشيفان ، المطور الرئيسي لشركة
Clever Solution.