يساعدنا فهم هياكل البيانات التي تشكل blockchain على التفكير في طرق إبداعية لتحليل هذه البيانات.
** بقلم: **** NOXX **
** تجميع: فلوش **
يعد التنقل في البيانات الموجودة في السلسلة مهارة أساسية لأي شخص يرغب في فهم مساحة Web3. يساعدنا فهم هياكل البيانات التي تشكل blockchain على التفكير في طرق إبداعية لتحليل هذه البيانات. في الوقت نفسه ، تشكل هذه البيانات على السلسلة جزءًا كبيرًا من البيانات المتاحة. سيتعمق هذا المنشور في بنية البيانات الرئيسية في EVM وإيصال المعاملة وسجل الأحداث المرتبط بها.
** لماذا تسجيل **
قبل أن نبدأ ، دعنا نتحدث بإيجاز عن سبب حاجتنا إلى استخدام سجلات الأحداث كمطور صلابة:
يعد سجل الأحداث خيارًا أرخص لتخزين البيانات لا يحتاج إلى الوصول إليه بموجب العقد ، ويمكنه أيضًا إعادة بناء الحالة المخزنة عن طريق اختبار متغيرات محددة في العقد الذكي ، متغيرات الفهرسة.
تسجيل الأحداث هو وسيلة لتشغيل تطبيق Web3 يستمع إلى سجل أحداث معين.
لا تحتاج عُقد EVM إلى الاحتفاظ بالسجلات إلى الأبد ، ويمكنها توفير مساحة عن طريق حذف السجلات القديمة. لا تتمتع العقود بإمكانية الوصول إلى تخزين السجل ، لذلك لا تحتاج العقد إليها لتنفيذ العقود. من ناحية أخرى ، فإن تخزين العقد مطلوب للتنفيذ وبالتالي لا يمكن حذفه.
** Ethereum Block Merkle Root **
في الجزء 4 ، بحثنا في إطار عمل Ethereum ، وخاصة جزء جذر Merkle الخاص بالحالة. جذر الولاية هو أحد جذور Merkle الثلاثة المضمنة في رأس الكتلة. والاثنان الآخران هما جذر المعاملة وجذر الاستلام.
للإدخال لبناء هذا الإطار ، سنشير إلى الكتلة 15001871 على Ethereum ، والتي تحتوي على 5 معاملات مع الإيصالات المرتبطة بها وسجلات الأحداث المرسلة.
** رأس الكتلة **
سنبدأ بثلاثة أجزاء في رأس الكتلة ، وجذر المعاملة ، وجذر الاستلام ، وتزايد السجلات (يمكن مراجعة مقدمة موجزة لرأس الكتلة في الجزء 4).
مصدر:
في عميل Ethereum ضمن جذر المعاملة وجذر الاستلام ، تحتوي Merkle Patricia Tries على جميع بيانات المعاملات وبيانات الاستلام في الكتلة. ستركز هذه المقالة فقط على جميع المعاملات والإيصالات التي يمكن للعقدة الوصول إليها.
معلومات رأس الكتلة للكتلة 15001871 التي تم العثور عليها من خلال عقدة Ethereum هي كما يلي:
تعد السجلات الموجودة في رأس الكتلة بمثابة بنية بيانات رئيسية ، والتي سيتم ذكرها لاحقًا في هذه المقالة. لنبدأ أولاً بالبيانات الموجودة أسفل جذر المعاملة ، Trie المعاملات.
** تري معاملة شجرة المعاملات **
المعاملات Trie هي مجموعة بيانات تنشئ المعاملات الجذر وتسجيل متجهات طلبات المعاملات. متجهات طلبات المعاملات هي أجزاء من المعلومات المطلوبة لتنفيذ المعاملة. حقول البيانات المضمنة في المعاملة هي كما يلي:
النوع - نوع المعاملة (معاملة LegacyTxType التقليدية ، مقدمة AccessListTxType EIP-2930 ، مقدمة DynamicFeeTxType EIP-1559)
ChainId - معرف سلسلة EIP155 للمعاملة
البيانات - بيانات إدخال المعاملة
قائمة الوصول - قائمة الوصول للمعاملات
الغاز - حد الغاز للصفقة
GasPrice - سعر الغاز للصفقة
GasTipCap - علاوة الحوافز لعمال المناجم الذين تتجاوز وحدة معاملاتهم الغازية الرسوم الأساسية للحزمة أولاً ، يتم تحديد maxPriorityFeePerGas في Geth بواسطة EIP1559
GasFeeCap - الحد الأعلى لرسوم الغاز لكل وحدة معاملة ، maxFeePerGas في Geth (GasFeeCap ≥ base Fee + GasTipCap)
القيمة - كمية Ethereum المتداولة
Nonce - أصل حساب التداول
إلى - عنوان مستلم المعاملة. بالنسبة لمعاملات إنشاء العقد ، لإرجاع قيمة صفرية
RawSignaturues - قيم التوقيع V و R و S لبيانات المعاملة
بعد فهم حقول البيانات أعلاه ، دعنا نلقي نظرة على المعاملة الأولى للكتلة 15001871
من خلال استعلام ethclient الخاص بـ Geth ، يمكنك أن ترى أن كلا من ChainId و AccessList بهما "إهمال" ، مما يعني أنه إذا كان الحقل فارغًا ، فسيتم حذفه في الاستجابة لتقليل أو تقصير حجم البيانات المتسلسلة.
مصدر الكود: *
تمثل هذه المعاملة تحويل رموز USDT إلى عنوان 0xec23e787ea25230f74a3da0f515825c1d820f47a. العنوان هو عنوان عقد ERC20 USDT 0xdac17f958d2ee523a2206206994597c13d831ec7. من خلال INPUT DATA ، يمكننا أن نرى أن توقيع الوظيفة 0xa9059cbb يتوافق مع الوظيفة Transfer (Address، UINT256) ، و 42.251 USDT (دقة 6) إلى 0x2b279b8 (45251000) تم نقله إلى 0xEC23E787EA25230F إلى 0xEC23E787EA25230F.
ربما لاحظت أن بنية بيانات المعاملة هذه لا تخبرنا بأي شيء عن نتيجة المعاملة ، فهل نجحت المعاملة؟ كم تستهلك من الغاز؟ ما هي سجلات الأحداث التي يتم تشغيلها؟ في هذه المرحلة ، سنقوم بإدخال Trie الاستلام.
** الاستلام الثلاثي **
تمامًا كما يسجل إيصال التسوق نتيجة إحدى المعاملات ، فإن العنصر الموجود في Receipt Trie يفعل الشيء نفسه بالنسبة لمعاملة Ethereum ولكنه يسجل أيضًا بعض التفاصيل الإضافية. بالعودة إلى طرح السؤال حول إيصالات المعاملات أعلاه ، سنركز على السجلات التي أدت إلى الأحداث التالية.
استعلم عن البيانات الموجودة في السلسلة 0x311b مرة أخرى واحصل على إيصال المعاملة. في هذا الوقت ، سيتم الحصول على الحقول التالية:
مصدر الكود: *
النوع - نوع المعاملة (LegacyTxType ، AccessListTxType ، DynamicFeeTxType)
PostState (الجذر) - StateRoot ، العقدة الجذرية لشجرة الحالة التي تم إنشاؤها بعد تنفيذ المعاملة ، القيمة المقابلة الموجودة في الشكل هي 0x ، ربما بسبب EIP98
الغاز المستخدم التراكمي - الإجمالي التراكمي للغاز المستهلك من خلال هذه المعاملة وجميع المعاملات السابقة في نفس الكتلة
Bloom (logsBloom) - مرشح Bloom لسجلات الأحداث ، يُستخدم للبحث الفعال عن سجلات أحداث العقد والوصول إليها على blockchain ، مما يسمح للعقد باسترداد ما إذا كان حدث معين قد وقع في كتلة دون تحليل الكتلة بالكامل جميع إيصالات المعاملات في الكتلة
السجلات - مجموعة من كائنات السجل تحتوي على إدخالات السجل الناتجة عن أحداث العقد التي تم إطلاقها أثناء تنفيذ المعاملة
TxHash - تجزئة المعاملة المرتبطة بالإيصال
ContractAddress - إذا كانت المعاملة لإنشاء عقد ، فسيتم نشر العنوان الذي تم نشر العقد فيه. إذا لم تكن المعاملة عبارة عن إنشاء عقد ، ولكن مثل نقل أو تفاعل مع عقد ذكي تم نشره ، فسيكون حقل ContractAddress فارغًا
GasUsed - الغاز الذي تستهلكه هذه المعاملة
BlockNumber - رقم الكتلة الخاص بالكتلة التي حدثت فيها هذه المعاملة
TransactionIndex - فهرس المعاملات داخل الكتلة ، يحدد الفهرس المعاملة التي يتم تنفيذها أولاً. هذه المعاملة في الجزء العلوي من الكتلة ، لذلك فهرس 0
الآن بعد أن عرفنا تكوين إيصال المعاملة ، دعنا نلقي نظرة فاحصة على السجلات Bloom وسجلات مصفوفة السجل في إيصال المعاملة.
** سجلات الأحداث **
من خلال رمز عقد USDT على شبكة Ethereum mainnet ، يمكننا أن نرى أنه تم الإعلان عن حدث التحويل في السطر 86 من العقد ، وأن معلمتَي الإدخال تحتويان على الكلمة الأساسية "مفهرسة".
(مصدر الكود:
عندما يتم "فهرسة" إدخال حدث ، فإنه يتيح لنا العثور بسرعة على السجلات من خلال هذا الإدخال. على سبيل المثال ، عند استخدام الفهرس "من" أعلاه ، من الممكن الحصول على جميع سجلات الأحداث من النوع Transfer مع العنوان "من" 0x5041ed759dd4afc3a72b8192c143f72f4724081a بين الكتلتين X و Y. يمكننا أيضًا ملاحظة أنه عندما يتم استدعاء وظيفة النقل في السطر 138 ، يتم تشغيل سجل الأحداث. تجدر الإشارة إلى أن العقد الحالي يستخدم إصدارًا سابقًا من الصلابة ، لذا فإن الكلمة الأساسية المنبعثة مفقودة.
ارجع إلى البيانات التي تم الحصول عليها على السلسلة:
مصدر الكود: *
دعنا نتعمق قليلاً في العنوان والموضوعات وحقول البيانات.
** مواضيع الموضوع **
الموضوعات هي قيمة مؤشر. من الشكل أعلاه ، يمكننا أن نرى أن هناك 3 معلمات فهرس للموضوعات في بيانات الاستعلام على السلسلة ، بينما يحتوي حدث النقل على معلمتين فهرس فقط (من وإلى). هذا لأن الموضوع الأول هو دائمًا تجزئة توقيع الوظيفة للحدث. توقيع وظيفة الحدث في المثال الحالي هو النقل (العنوان ، العنوان ، uint256). من خلال تجزئتها باستخدام keccak256 ، نحصل على النتيجة ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef.
(أداة عبر الإنترنت:
عندما نقوم بالاستعلام عن الحقل من كما هو مذكور أعلاه ، ولكن في نفس الوقت نريد قصر نوع سجل أحداث الاستعلام على سجلات أحداث نوع التحويل فقط ، نحتاج إلى التصفية حسب نوع الحدث عن طريق فهرسة توقيعات الحدث.
يمكن أن يكون لدينا ما يصل إلى 4 مواضيع ، كل موضوع له حجم 32 بايت (إذا كان نوع معلمة الفهرس أكبر من 32 بايت (أي السلسلة والبايت) ، لا يتم تخزين البيانات الفعلية ، ولكن keccak256 ملخص للبيانات تم تخزينه). يمكننا أن نعلن عن 3 معامِلات فهرس لأن المعلمة الأولى مأخوذة من توقيع الحدث. ولكن هناك حالة لا يكون فيها الموضوع الأول توقيع حدث تجزئة. هذا هو الحال عند الإعلان عن أحداث مجهولة. هذا يفتح إمكانية استخدام 4 معلمات فهرس بدلاً من 3 السابقة ، لكنه يفقد القدرة على فهرسة أسماء الأحداث. ميزة أخرى للأحداث المجهولة هي أنها أقل تكلفة لنشرها لأنها لا تفرض موضوعًا إضافيًا. الموضوعات الأخرى هي قيم الفهارس "من" و "إلى" من حدث النقل.
** بيانات البيانات **
يحتوي قسم البيانات على المعلمات المتبقية (غير المفهرسة) من سجل الأحداث. في المثال أعلاه ، توجد قيمة 0x00000000000000000000000000000000000000000000000000000002b279b8 ، وهي 45251000 في النظام العشري ، وهو المبلغ المذكور أعلاه وهو 45.251 دولارًا. إذا كان هناك المزيد من هذه المعلمات ، فسيتم إلحاقها بعنصر البيانات. سيوضح المثال أدناه حالة أكثر من معلمة غير مفهرسة.
يضيف المثال الحالي حقل "ضريبة" إضافي إلى حدث التحويل. لنفترض أن الضريبة المحددة 20٪ ، ثم قيمة الضريبة يجب أن تكون 45251000 \ * 20٪ = 9050200 ، قيمتها السداسية العشرية هي 0x8a1858 ، نظرًا لأن نوع هذا الرقم هو uint256 ، ونوع البيانات 32 بايت ، فأنت بحاجة إلى تمتلئ القيمة السداسية العشرية بـ 32 بايت ، ونتيجة عنصر البيانات هي 0x00000000000000000000000000000000000000000000000000002b279b80000000000000000000000000000000000000 0000000000000000008a1858.
عنوان
حقل العنوان هو عنوان العقد الذي أرسل الحدث ، ملاحظة مهمة حول هذا الحقل هي أنه سيتم فهرسته على الرغم من عدم تضمينه في قسم الموضوع. والسبب هو أن حدث النقل جزء من معيار ERC20 ، مما يعني أنه عندما يكون من الضروري تصفية سجلات أحداث نقل ERC20 ، سيتم الحصول على أحداث النقل من جميع عقود ERC20. ومن خلال فهرسة عنوان العقد ، يمكن تضييق نطاق البحث إلى عقد / رمز محدد ، مثل USDT في المثال.
** أكواد التشغيل **
أخيرًا هناك رمز التشغيل LOG. وهي تتراوح من LOG0 في حالة عدم وجود موضوعات إلى LOG4 عند وجود 4 موضوعات. LOG3 هو ما نستخدمه في مثالنا. يحتوي على ما يلي:
الإزاحة - إزاحة الذاكرة ، مما يشير إلى موضع البداية لإدخال حقل البيانات
طول - طول البيانات للقراءة من الذاكرة
الموضوع x (0 - 4) - قيمة الموضوع x
(مصدر:
تحدد الإزاحة والطول مكان وجود البيانات في قسم البيانات في الذاكرة.
بعد فهم بنية السجل وكيفية فهرسة الموضوع ، دعنا نفهم كيفية البحث عن عناصر الفهرس.
** بلوم فلاتر بلوم فلاتر **
سر فهرسة العناصر التي يتم البحث عنها بشكل أسرع هو مرشح Bloom.
تحتوي مقالة Llimllib على تعريف وشرح جيد لهيكل البيانات هذا.
"مرشح Bloom هو بنية بيانات يمكن استخدامها لتحديد ما إذا كان العنصر موجودًا في مجموعة أم لا. وله خصائص التشغيل السريع والبصمة الصغيرة للذاكرة. وتكمن تكلفة الإدراج والاستعلام الفعال في أن Bloom Filter عبارة عن بيانات تستند إلى الاحتمالات الهيكل: يمكن أن يخبرنا فقط أن العنصر بالتأكيد ليس في المجموعة أو ربما في المجموعة. هيكل البيانات الأساسي لمرشح Bloom هو متجه بت. "
يوجد أدناه مثال على متجه قليلاً. تمثل الخلايا البيضاء بتات بقيمة 0 ، وتمثل الخلايا الخضراء بتات بقيمة 1.
يتم تعيين هذه البتات على 1 عن طريق أخذ بعض المدخلات والتجزئة ، ويتم استخدام قيمة التجزئة الناتجة كمؤشر بت يجب تحديث البت عليه. متجه البت أعلاه هو نتيجة تطبيق 2 تجزئة مختلفة على قيمة "ethereum" للحصول على دليل 2 بت. يمثل الهاش رقمًا سداسيًا عشريًا ، وللحصول على الفهرس ، يمكنك أخذ الرقم وتحويله إلى قيمة بين 0 و 14. هناك العديد من الطرق للقيام بذلك ، مثل mod 14.
مراجعة
باستخدام مرشح Bloom للمعاملات ، أي متجهًا قليلاً ، يمكن تجزئته في Ethereum لتحديد البتات في متجه البت المراد تحديثها.الإدخال هو حقل العنوان وموضوع سجل الأحداث. دعنا نراجع السجلات الازدهار في إيصال المعاملة ، وهو عامل تصفية بلوم خاص بالمعاملة. يمكن أن تحتوي المعاملة على سجلات متعددة ، والتي تحتوي على عنوان / موضوع جميع السجلات.
إذا نظرت مرة أخرى إلى رأس الكتلة ، فستجد سجلات أخرى Bloom. هذا مرشح بلوم لجميع المعاملات داخل الكتلة. الذي يحتوي على جميع العناوين / الموضوعات في كل سجل لكل معاملة.
يتم التعبير عن فلاتر Bloom هذه بالنظام الست عشري وليس الثنائي. يبلغ طولها 256 بايت وتمثل متجهًا بحجم 2048 بت. إذا أشرنا إلى مثال Llimllib أعلاه ، فإن طول متجه البتة لدينا هو 15 ، ومؤشرات البت 2 و 13 انقلبت على أنها 1. دعونا نرى ما نحصل عليه عندما نحول ذلك إلى سداسي عشري.
على الرغم من أن التمثيل السداسي العشري لا يبدو متجهًا بعض الشيء ، إلا أنه يحدث في logsBloom.
** استعلامات الاستعلام **
تم ذكر محتوى الاستعلام من قبل ، "ابحث عن كافة سجلات الأحداث من نوع التحويل الذي يكون عنوان" من "هو 0x5041ed759dd4afc3a72b8192c143f72f4724081a بين الكتلتين X و Y". يمكننا الحصول على موضوع توقيع الحدث ، والذي يمثل موضوعًا من نوع التحويل ومن قيمة (0x5041 ...) ، وتحديد مؤشرات البت في مرشح Bloom الذي يجب ضبطه على 1.
إذا كنت تستخدم logsBloom في رأس الكتلة ، فيمكنك التحقق لمعرفة ما إذا لم يتم تعيين أي من هذه البتات على 1. إذا لم يكن الأمر كذلك ، فيمكن تحديد عدم وجود سجلات مطابقة للشرط في الكتلة. وإذا تم العثور على هذه البتات مضبوطة ، فإننا نعلم أن سجل المطابقة ربما يكون في الكتلة. لكن لست متأكدًا تمامًا ، لأن سجلات رأس الكتلة تتكون Bloom من عناوين وموضوعات متعددة. قد تحتوي سجلات الأحداث الأخرى على مجموعة بت المطابقة. هذا هو السبب في أن مرشح Bloom هو بنية بيانات احتمالية. كلما زاد حجم متجه البت ، قل احتمال حدوث تضارب في فهرس البت مع السجلات الأخرى. بمجرد أن يكون لديك مرشح Bloom مطابق ، يمكنك استخدام نفس الطريقة للاستعلام عن سجلاتBloom للإيصالات الفردية. عند الحصول على تطابق ، يمكن عرض إدخال السجل الفعلي لاسترداد الكائن.
قم بتنفيذ العمليات المذكورة أعلاه على الكتل من X إلى Y للعثور بسرعة على جميع السجلات التي تفي بالمعايير واستردادها. هذه هي الطريقة التي يعمل بها مرشح Bloom من الناحية المفاهيمية.
الآن دعونا نلقي نظرة على التنفيذ المستخدم في Ethereum.
** تطبيق Geth - Bloom Filters **
الآن بعد أن عرفنا كيف يعمل مرشح Bloom ، دعنا نتعلم كيف يكمل مرشح Bloom عملية الفرز خطوة بخطوة من العنوان / الموضوع إلى السجلات Bloom في كتلة فعلية.
بادئ ذي بدء ، من تعريف الورقة الصفراء Ethereum:
مصدر:
"نحدد وظيفة مرشح Bloom M التي تقلل إدخالات السجل إلى تجزئة 256 بايت واحدة:
في هو مرشح Bloom متخصص يقوم بتعيين ثلاث بتات في عام 2048 نظرًا لتسلسل عشوائي من البايتات. يتم ذلك عن طريق أخذ 11 بت أقل من كل من الأزواج الثلاثة الأولى من البايت في تجزئة Keccak-256 لتسلسل البايت. "
يتم توفير مثال ومرجع لتطبيق Geth client أدناه لتبسيط فهم التعريفات المذكورة أعلاه.
هنا سجل المعاملات الذي نظرنا إليه على Etherscan.
الموضوع الأول هو توقيع الحدث 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef ويحول هذه القيمة إلى فهرس البت الذي يجب تحديثه.
يوجد أدناه وظيفة bloomValues من مصدر كود Geth.
تتلقى هذه الوظيفة موضوع توقيع الحدث ، مثل: 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef وغيرها من البيانات ، وتقوم بإرجاع فهرس البت الذي يحتاج إلى تحديث في مرشح Bloom.
مصدر الكود: *
تستقبل وظيفة bloomValues كموضوع (توقيع الحدث في المثال) و hashbuf (مصفوفة بايت فارغة بطول 6).
راجع مقتطف الورق الأصفر ، "أول ثلاثة أزواج من البايت في تجزئة Keccak-256 من سلسلة من البايتات". هذه الأزواج الثلاثة من البايتات هي 6 بايت ، وهو طول التجزئة.
نموذج البيانات: 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef.
يقوم الأمر sha بين الأسطر 140-144 بتجزئة بيانات الإدخال وتحميل الإخراج إلى التجزئة.
النتيجة السداسية العشرية لإخراج sha باستخدام keccak256 هي (عند استخدام keccak 256 كتوقيع الوظيفة ، يكون الإدخال هو نوع النص ، ولكن هنا نوع سداسي عشري): ada389e1fc24a8587c776340efb91b36e675792ab631816100d55df0b5cf3cbc.
المحتوى الحالي لـ hasbuf [ad، a3، 89، e1، fc، 24] (سداسي عشري). يمثل كل حرف سداسي عشري 4 بتات.
3 احسب v1.
1) حشبوف [1] = 0xa3 = 10100011 للبت باستخدام AND مع 0x7. 0x7 = 00000111.
البايت يتكون من 8 بتات ، إذا كنت تريد الحصول على فهرس بت ، فأنت بحاجة إلى التأكد من أن القيمة التي تم الحصول عليها بين 0 و 7 من صفيف الفهرس الصفري. استخدم أحادي المعامل AND للتجزئة [1] يقتصر على القيم بين 0 و 7. محسوب في المثال ، 10100011 & 00000111 = 00000011 = 3.
تُستخدم قيمة فهرس البتات هذه مع مشغل إزاحة البتات ، أي إزاحة 3 بتات إلى اليسار ، مما ينتج عنه فهرس 8 بتات 00001000 ، لإنشاء بت مقلوب.
v1 هو البايت بالكامل وليس فهرس البت الفعلي ، لأن هذه القيمة ستكون معطلة على مستوى البت في مرشح Bloom لاحقًا. ستضمن العملية OR أن جميع البتات المقابلة في مرشح Bloom قد تم قلبها أيضًا.
لدينا الآن قيم البايت ، لكننا ما زلنا بحاجة إلى فهارس البايت. يبلغ طول مرشح Bloom 256 بايت (2048 بت) ، لذلك نحتاج إلى معرفة البايت الذي سيتم تشغيل OR عليه. تمثل القيمة i1 فهرس البايت هذا.
ضع hashbuf من خلال ترتيب uint16 بايت كبير الحجم ، مما يجعله يحد من أول 2 بايت من صفيف البت ، وهو 0xada3 = 1010110110100011 في المثال.
على مستوى البت وهذه القيمة مع 0x7ff = 0000011111111111. هناك 11 بت حيث تم تعيين 0x7ff على 1. كما هو مذكور في الورقة الصفراء ، "يقوم بذلك عن طريق أخذ 11 بتًا أقل من كل من الأزواج الثلاثة الأولى". سينتج عن ذلك القيمة 0000010110100011 وهي 1010110110100011 & 0000011111111111.
ثم انقل القيمة إلى اليمين بمقدار 3 بتات. يؤدي ذلك إلى تحويل رقم مكون من 11 رقمًا إلى رقم مكون من 8 أرقام. نريد فهرس بايت ، وطول بايت مرشح Bloom هو 256 ، لذلك يجب أن تكون قيمة فهرس البايت في هذا النطاق. ويمكن أن يكون الرقم المكون من 8 بتات أي قيمة بين 0 و 255. في مثالنا ، هذه القيمة هي 0000010110100011 مقلوبة إلى اليمين بمقدار 3 بتات 10110100 = 180.
احسب مؤشر البايت الخاص بنا عن طريق BloomByteLength ، مع العلم أنه 256 ناقص 180 المحسوب ، ناقص 1. اطرح 1 لتحافظ على النتيجة بين 0 و 255. هذا يعطينا فهرس البايت الذي يجب تحديثه ، والذي يتبين في هذه الحالة أنه بايت 75 ، وهي الطريقة التي حسبنا بها i1.
قم بتحديث فهرس البت 3 في البايت 75 لمرشح Bloom (0 هو الفهرس أي البتة الرابعة) ، والذي يمكن القيام به عن طريق إجراء عملية أو عملية على مستوى البت لـ v1 على 75 بايت في مرشح Bloom.
قمنا فقط بتغطية زوج البايت الأول 0xada3 ، والذي تم إجراؤه مرة أخرى لأزواج البايت 2 و 3. سيتم تحديث كل عنوان / موضوع 3 بت في متجه 2048 بت. كما هو مذكور في الورقة الصفراء ، "يعين مرشح Bloom ثلاث بتات في عام 2048 بالنظر إلى تسلسل عشوائي من البايتات".
تقوم حالة زوج البايت 2 بتحديث مؤشر البت 1 بالبايت 195 (يتم التنفيذ وفقًا للإجراءين 3 و 4 ، تظهر النتيجة في الشكل).
تحديث حالة زوج البايت 3 مؤشر بت 4 في البايت 123.
إذا تم قلب البت المراد تحديثه بالفعل بواسطة موضوع آخر ، فسيظل كما هو. سوف يقلب إلى 1 إذا لم يكن كذلك.
من خلال عملية التشغيل المذكورة أعلاه ، يمكن تحديد أن موضوع توقيع الحدث سوف يقلب البتات التالية في مرشح Bloom:
مؤشر البت 3 في البايت 75
مؤشر البت 1 في البايت 195
مؤشر البت 4 في بايت 123
عند النظر إلى logBlooms في إيصال المعاملة ، المحول إلى ثنائي ، يتحقق من تعيين مؤشرات البت هذه.
وفي الوقت نفسه ، بالنسبة لأولئك القراء المهتمين بمعرفة المزيد حول تنفيذ البحث في السجل ومرشح Bloom ، يمكنك الرجوع إلى مقالة BloomBits Trie.
في هذه المرحلة ، انتهت مناقشتنا المتعمقة لسلسلة مقالات EVM ، وسنقدم لك المزيد من المقالات التقنية عالية الجودة في المستقبل.
شاهد النسخة الأصلية
المحتوى هو للمرجعية فقط، وليس دعوة أو عرضًا. لا يتم تقديم أي مشورة استثمارية أو ضريبية أو قانونية. للمزيد من الإفصاحات حول المخاطر، يُرجى الاطلاع على إخلاء المسؤولية.
الغوص في هياكل بيانات EVM وإيصالات المعاملات وسجلات الأحداث
** بقلم: **** NOXX **
** تجميع: فلوش **
يعد التنقل في البيانات الموجودة في السلسلة مهارة أساسية لأي شخص يرغب في فهم مساحة Web3. يساعدنا فهم هياكل البيانات التي تشكل blockchain على التفكير في طرق إبداعية لتحليل هذه البيانات. في الوقت نفسه ، تشكل هذه البيانات على السلسلة جزءًا كبيرًا من البيانات المتاحة. سيتعمق هذا المنشور في بنية البيانات الرئيسية في EVM وإيصال المعاملة وسجل الأحداث المرتبط بها.
** لماذا تسجيل **
قبل أن نبدأ ، دعنا نتحدث بإيجاز عن سبب حاجتنا إلى استخدام سجلات الأحداث كمطور صلابة:
لا تحتاج عُقد EVM إلى الاحتفاظ بالسجلات إلى الأبد ، ويمكنها توفير مساحة عن طريق حذف السجلات القديمة. لا تتمتع العقود بإمكانية الوصول إلى تخزين السجل ، لذلك لا تحتاج العقد إليها لتنفيذ العقود. من ناحية أخرى ، فإن تخزين العقد مطلوب للتنفيذ وبالتالي لا يمكن حذفه.
** Ethereum Block Merkle Root **
في الجزء 4 ، بحثنا في إطار عمل Ethereum ، وخاصة جزء جذر Merkle الخاص بالحالة. جذر الولاية هو أحد جذور Merkle الثلاثة المضمنة في رأس الكتلة. والاثنان الآخران هما جذر المعاملة وجذر الاستلام.
للإدخال لبناء هذا الإطار ، سنشير إلى الكتلة 15001871 على Ethereum ، والتي تحتوي على 5 معاملات مع الإيصالات المرتبطة بها وسجلات الأحداث المرسلة.
** رأس الكتلة **
سنبدأ بثلاثة أجزاء في رأس الكتلة ، وجذر المعاملة ، وجذر الاستلام ، وتزايد السجلات (يمكن مراجعة مقدمة موجزة لرأس الكتلة في الجزء 4).
مصدر:
في عميل Ethereum ضمن جذر المعاملة وجذر الاستلام ، تحتوي Merkle Patricia Tries على جميع بيانات المعاملات وبيانات الاستلام في الكتلة. ستركز هذه المقالة فقط على جميع المعاملات والإيصالات التي يمكن للعقدة الوصول إليها.
معلومات رأس الكتلة للكتلة 15001871 التي تم العثور عليها من خلال عقدة Ethereum هي كما يلي:
تعد السجلات الموجودة في رأس الكتلة بمثابة بنية بيانات رئيسية ، والتي سيتم ذكرها لاحقًا في هذه المقالة. لنبدأ أولاً بالبيانات الموجودة أسفل جذر المعاملة ، Trie المعاملات.
** تري معاملة شجرة المعاملات **
المعاملات Trie هي مجموعة بيانات تنشئ المعاملات الجذر وتسجيل متجهات طلبات المعاملات. متجهات طلبات المعاملات هي أجزاء من المعلومات المطلوبة لتنفيذ المعاملة. حقول البيانات المضمنة في المعاملة هي كما يلي:
بعد فهم حقول البيانات أعلاه ، دعنا نلقي نظرة على المعاملة الأولى للكتلة 15001871
من خلال استعلام ethclient الخاص بـ Geth ، يمكنك أن ترى أن كلا من ChainId و AccessList بهما "إهمال" ، مما يعني أنه إذا كان الحقل فارغًا ، فسيتم حذفه في الاستجابة لتقليل أو تقصير حجم البيانات المتسلسلة.
تمثل هذه المعاملة تحويل رموز USDT إلى عنوان 0xec23e787ea25230f74a3da0f515825c1d820f47a. العنوان هو عنوان عقد ERC20 USDT 0xdac17f958d2ee523a2206206994597c13d831ec7. من خلال INPUT DATA ، يمكننا أن نرى أن توقيع الوظيفة 0xa9059cbb يتوافق مع الوظيفة Transfer (Address، UINT256) ، و 42.251 USDT (دقة 6) إلى 0x2b279b8 (45251000) تم نقله إلى 0xEC23E787EA25230F إلى 0xEC23E787EA25230F.
ربما لاحظت أن بنية بيانات المعاملة هذه لا تخبرنا بأي شيء عن نتيجة المعاملة ، فهل نجحت المعاملة؟ كم تستهلك من الغاز؟ ما هي سجلات الأحداث التي يتم تشغيلها؟ في هذه المرحلة ، سنقوم بإدخال Trie الاستلام.
** الاستلام الثلاثي **
تمامًا كما يسجل إيصال التسوق نتيجة إحدى المعاملات ، فإن العنصر الموجود في Receipt Trie يفعل الشيء نفسه بالنسبة لمعاملة Ethereum ولكنه يسجل أيضًا بعض التفاصيل الإضافية. بالعودة إلى طرح السؤال حول إيصالات المعاملات أعلاه ، سنركز على السجلات التي أدت إلى الأحداث التالية.
استعلم عن البيانات الموجودة في السلسلة 0x311b مرة أخرى واحصل على إيصال المعاملة. في هذا الوقت ، سيتم الحصول على الحقول التالية:
مصدر الكود: *
النوع - نوع المعاملة (LegacyTxType ، AccessListTxType ، DynamicFeeTxType)
PostState (الجذر) - StateRoot ، العقدة الجذرية لشجرة الحالة التي تم إنشاؤها بعد تنفيذ المعاملة ، القيمة المقابلة الموجودة في الشكل هي 0x ، ربما بسبب EIP98
الغاز المستخدم التراكمي - الإجمالي التراكمي للغاز المستهلك من خلال هذه المعاملة وجميع المعاملات السابقة في نفس الكتلة
Bloom (logsBloom) - مرشح Bloom لسجلات الأحداث ، يُستخدم للبحث الفعال عن سجلات أحداث العقد والوصول إليها على blockchain ، مما يسمح للعقد باسترداد ما إذا كان حدث معين قد وقع في كتلة دون تحليل الكتلة بالكامل جميع إيصالات المعاملات في الكتلة
السجلات - مجموعة من كائنات السجل تحتوي على إدخالات السجل الناتجة عن أحداث العقد التي تم إطلاقها أثناء تنفيذ المعاملة
TxHash - تجزئة المعاملة المرتبطة بالإيصال
ContractAddress - إذا كانت المعاملة لإنشاء عقد ، فسيتم نشر العنوان الذي تم نشر العقد فيه. إذا لم تكن المعاملة عبارة عن إنشاء عقد ، ولكن مثل نقل أو تفاعل مع عقد ذكي تم نشره ، فسيكون حقل ContractAddress فارغًا
GasUsed - الغاز الذي تستهلكه هذه المعاملة
BlockNumber - رقم الكتلة الخاص بالكتلة التي حدثت فيها هذه المعاملة
TransactionIndex - فهرس المعاملات داخل الكتلة ، يحدد الفهرس المعاملة التي يتم تنفيذها أولاً. هذه المعاملة في الجزء العلوي من الكتلة ، لذلك فهرس 0
الآن بعد أن عرفنا تكوين إيصال المعاملة ، دعنا نلقي نظرة فاحصة على السجلات Bloom وسجلات مصفوفة السجل في إيصال المعاملة.
** سجلات الأحداث **
من خلال رمز عقد USDT على شبكة Ethereum mainnet ، يمكننا أن نرى أنه تم الإعلان عن حدث التحويل في السطر 86 من العقد ، وأن معلمتَي الإدخال تحتويان على الكلمة الأساسية "مفهرسة".
(مصدر الكود:
عندما يتم "فهرسة" إدخال حدث ، فإنه يتيح لنا العثور بسرعة على السجلات من خلال هذا الإدخال. على سبيل المثال ، عند استخدام الفهرس "من" أعلاه ، من الممكن الحصول على جميع سجلات الأحداث من النوع Transfer مع العنوان "من" 0x5041ed759dd4afc3a72b8192c143f72f4724081a بين الكتلتين X و Y. يمكننا أيضًا ملاحظة أنه عندما يتم استدعاء وظيفة النقل في السطر 138 ، يتم تشغيل سجل الأحداث. تجدر الإشارة إلى أن العقد الحالي يستخدم إصدارًا سابقًا من الصلابة ، لذا فإن الكلمة الأساسية المنبعثة مفقودة.
ارجع إلى البيانات التي تم الحصول عليها على السلسلة:
دعنا نتعمق قليلاً في العنوان والموضوعات وحقول البيانات.
** مواضيع الموضوع **
الموضوعات هي قيمة مؤشر. من الشكل أعلاه ، يمكننا أن نرى أن هناك 3 معلمات فهرس للموضوعات في بيانات الاستعلام على السلسلة ، بينما يحتوي حدث النقل على معلمتين فهرس فقط (من وإلى). هذا لأن الموضوع الأول هو دائمًا تجزئة توقيع الوظيفة للحدث. توقيع وظيفة الحدث في المثال الحالي هو النقل (العنوان ، العنوان ، uint256). من خلال تجزئتها باستخدام keccak256 ، نحصل على النتيجة ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef.
(أداة عبر الإنترنت:
عندما نقوم بالاستعلام عن الحقل من كما هو مذكور أعلاه ، ولكن في نفس الوقت نريد قصر نوع سجل أحداث الاستعلام على سجلات أحداث نوع التحويل فقط ، نحتاج إلى التصفية حسب نوع الحدث عن طريق فهرسة توقيعات الحدث.
يمكن أن يكون لدينا ما يصل إلى 4 مواضيع ، كل موضوع له حجم 32 بايت (إذا كان نوع معلمة الفهرس أكبر من 32 بايت (أي السلسلة والبايت) ، لا يتم تخزين البيانات الفعلية ، ولكن keccak256 ملخص للبيانات تم تخزينه). يمكننا أن نعلن عن 3 معامِلات فهرس لأن المعلمة الأولى مأخوذة من توقيع الحدث. ولكن هناك حالة لا يكون فيها الموضوع الأول توقيع حدث تجزئة. هذا هو الحال عند الإعلان عن أحداث مجهولة. هذا يفتح إمكانية استخدام 4 معلمات فهرس بدلاً من 3 السابقة ، لكنه يفقد القدرة على فهرسة أسماء الأحداث. ميزة أخرى للأحداث المجهولة هي أنها أقل تكلفة لنشرها لأنها لا تفرض موضوعًا إضافيًا. الموضوعات الأخرى هي قيم الفهارس "من" و "إلى" من حدث النقل.
** بيانات البيانات **
يحتوي قسم البيانات على المعلمات المتبقية (غير المفهرسة) من سجل الأحداث. في المثال أعلاه ، توجد قيمة 0x00000000000000000000000000000000000000000000000000000002b279b8 ، وهي 45251000 في النظام العشري ، وهو المبلغ المذكور أعلاه وهو 45.251 دولارًا. إذا كان هناك المزيد من هذه المعلمات ، فسيتم إلحاقها بعنصر البيانات. سيوضح المثال أدناه حالة أكثر من معلمة غير مفهرسة.
يضيف المثال الحالي حقل "ضريبة" إضافي إلى حدث التحويل. لنفترض أن الضريبة المحددة 20٪ ، ثم قيمة الضريبة يجب أن تكون 45251000 \ * 20٪ = 9050200 ، قيمتها السداسية العشرية هي 0x8a1858 ، نظرًا لأن نوع هذا الرقم هو uint256 ، ونوع البيانات 32 بايت ، فأنت بحاجة إلى تمتلئ القيمة السداسية العشرية بـ 32 بايت ، ونتيجة عنصر البيانات هي 0x00000000000000000000000000000000000000000000000000002b279b80000000000000000000000000000000000000 0000000000000000008a1858.
عنوان
حقل العنوان هو عنوان العقد الذي أرسل الحدث ، ملاحظة مهمة حول هذا الحقل هي أنه سيتم فهرسته على الرغم من عدم تضمينه في قسم الموضوع. والسبب هو أن حدث النقل جزء من معيار ERC20 ، مما يعني أنه عندما يكون من الضروري تصفية سجلات أحداث نقل ERC20 ، سيتم الحصول على أحداث النقل من جميع عقود ERC20. ومن خلال فهرسة عنوان العقد ، يمكن تضييق نطاق البحث إلى عقد / رمز محدد ، مثل USDT في المثال.
** أكواد التشغيل **
أخيرًا هناك رمز التشغيل LOG. وهي تتراوح من LOG0 في حالة عدم وجود موضوعات إلى LOG4 عند وجود 4 موضوعات. LOG3 هو ما نستخدمه في مثالنا. يحتوي على ما يلي:
(مصدر:
تحدد الإزاحة والطول مكان وجود البيانات في قسم البيانات في الذاكرة.
بعد فهم بنية السجل وكيفية فهرسة الموضوع ، دعنا نفهم كيفية البحث عن عناصر الفهرس.
** بلوم فلاتر بلوم فلاتر **
سر فهرسة العناصر التي يتم البحث عنها بشكل أسرع هو مرشح Bloom.
تحتوي مقالة Llimllib على تعريف وشرح جيد لهيكل البيانات هذا.
"مرشح Bloom هو بنية بيانات يمكن استخدامها لتحديد ما إذا كان العنصر موجودًا في مجموعة أم لا. وله خصائص التشغيل السريع والبصمة الصغيرة للذاكرة. وتكمن تكلفة الإدراج والاستعلام الفعال في أن Bloom Filter عبارة عن بيانات تستند إلى الاحتمالات الهيكل: يمكن أن يخبرنا فقط أن العنصر بالتأكيد ليس في المجموعة أو ربما في المجموعة. هيكل البيانات الأساسي لمرشح Bloom هو متجه بت. "
يوجد أدناه مثال على متجه قليلاً. تمثل الخلايا البيضاء بتات بقيمة 0 ، وتمثل الخلايا الخضراء بتات بقيمة 1.
يتم تعيين هذه البتات على 1 عن طريق أخذ بعض المدخلات والتجزئة ، ويتم استخدام قيمة التجزئة الناتجة كمؤشر بت يجب تحديث البت عليه. متجه البت أعلاه هو نتيجة تطبيق 2 تجزئة مختلفة على قيمة "ethereum" للحصول على دليل 2 بت. يمثل الهاش رقمًا سداسيًا عشريًا ، وللحصول على الفهرس ، يمكنك أخذ الرقم وتحويله إلى قيمة بين 0 و 14. هناك العديد من الطرق للقيام بذلك ، مثل mod 14.
مراجعة
باستخدام مرشح Bloom للمعاملات ، أي متجهًا قليلاً ، يمكن تجزئته في Ethereum لتحديد البتات في متجه البت المراد تحديثها.الإدخال هو حقل العنوان وموضوع سجل الأحداث. دعنا نراجع السجلات الازدهار في إيصال المعاملة ، وهو عامل تصفية بلوم خاص بالمعاملة. يمكن أن تحتوي المعاملة على سجلات متعددة ، والتي تحتوي على عنوان / موضوع جميع السجلات.
إذا نظرت مرة أخرى إلى رأس الكتلة ، فستجد سجلات أخرى Bloom. هذا مرشح بلوم لجميع المعاملات داخل الكتلة. الذي يحتوي على جميع العناوين / الموضوعات في كل سجل لكل معاملة.
يتم التعبير عن فلاتر Bloom هذه بالنظام الست عشري وليس الثنائي. يبلغ طولها 256 بايت وتمثل متجهًا بحجم 2048 بت. إذا أشرنا إلى مثال Llimllib أعلاه ، فإن طول متجه البتة لدينا هو 15 ، ومؤشرات البت 2 و 13 انقلبت على أنها 1. دعونا نرى ما نحصل عليه عندما نحول ذلك إلى سداسي عشري.
على الرغم من أن التمثيل السداسي العشري لا يبدو متجهًا بعض الشيء ، إلا أنه يحدث في logsBloom.
** استعلامات الاستعلام **
تم ذكر محتوى الاستعلام من قبل ، "ابحث عن كافة سجلات الأحداث من نوع التحويل الذي يكون عنوان" من "هو 0x5041ed759dd4afc3a72b8192c143f72f4724081a بين الكتلتين X و Y". يمكننا الحصول على موضوع توقيع الحدث ، والذي يمثل موضوعًا من نوع التحويل ومن قيمة (0x5041 ...) ، وتحديد مؤشرات البت في مرشح Bloom الذي يجب ضبطه على 1.
إذا كنت تستخدم logsBloom في رأس الكتلة ، فيمكنك التحقق لمعرفة ما إذا لم يتم تعيين أي من هذه البتات على 1. إذا لم يكن الأمر كذلك ، فيمكن تحديد عدم وجود سجلات مطابقة للشرط في الكتلة. وإذا تم العثور على هذه البتات مضبوطة ، فإننا نعلم أن سجل المطابقة ربما يكون في الكتلة. لكن لست متأكدًا تمامًا ، لأن سجلات رأس الكتلة تتكون Bloom من عناوين وموضوعات متعددة. قد تحتوي سجلات الأحداث الأخرى على مجموعة بت المطابقة. هذا هو السبب في أن مرشح Bloom هو بنية بيانات احتمالية. كلما زاد حجم متجه البت ، قل احتمال حدوث تضارب في فهرس البت مع السجلات الأخرى. بمجرد أن يكون لديك مرشح Bloom مطابق ، يمكنك استخدام نفس الطريقة للاستعلام عن سجلاتBloom للإيصالات الفردية. عند الحصول على تطابق ، يمكن عرض إدخال السجل الفعلي لاسترداد الكائن.
قم بتنفيذ العمليات المذكورة أعلاه على الكتل من X إلى Y للعثور بسرعة على جميع السجلات التي تفي بالمعايير واستردادها. هذه هي الطريقة التي يعمل بها مرشح Bloom من الناحية المفاهيمية.
الآن دعونا نلقي نظرة على التنفيذ المستخدم في Ethereum.
** تطبيق Geth - Bloom Filters **
الآن بعد أن عرفنا كيف يعمل مرشح Bloom ، دعنا نتعلم كيف يكمل مرشح Bloom عملية الفرز خطوة بخطوة من العنوان / الموضوع إلى السجلات Bloom في كتلة فعلية.
بادئ ذي بدء ، من تعريف الورقة الصفراء Ethereum:
مصدر:
"نحدد وظيفة مرشح Bloom M التي تقلل إدخالات السجل إلى تجزئة 256 بايت واحدة:
في
هو مرشح Bloom متخصص يقوم بتعيين ثلاث بتات في عام 2048 نظرًا لتسلسل عشوائي من البايتات. يتم ذلك عن طريق أخذ 11 بت أقل من كل من الأزواج الثلاثة الأولى من البايت في تجزئة Keccak-256 لتسلسل البايت. "
يتم توفير مثال ومرجع لتطبيق Geth client أدناه لتبسيط فهم التعريفات المذكورة أعلاه.
هنا سجل المعاملات الذي نظرنا إليه على Etherscan.
الموضوع الأول هو توقيع الحدث 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef ويحول هذه القيمة إلى فهرس البت الذي يجب تحديثه.
يوجد أدناه وظيفة bloomValues من مصدر كود Geth.
تتلقى هذه الوظيفة موضوع توقيع الحدث ، مثل: 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef وغيرها من البيانات ، وتقوم بإرجاع فهرس البت الذي يحتاج إلى تحديث في مرشح Bloom.
راجع مقتطف الورق الأصفر ، "أول ثلاثة أزواج من البايت في تجزئة Keccak-256 من سلسلة من البايتات". هذه الأزواج الثلاثة من البايتات هي 6 بايت ، وهو طول التجزئة.
نموذج البيانات: 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef.
3 احسب v1.
1) حشبوف [1] = 0xa3 = 10100011 للبت باستخدام AND مع 0x7. 0x7 = 00000111.
البايت يتكون من 8 بتات ، إذا كنت تريد الحصول على فهرس بت ، فأنت بحاجة إلى التأكد من أن القيمة التي تم الحصول عليها بين 0 و 7 من صفيف الفهرس الصفري. استخدم أحادي المعامل AND للتجزئة [1] يقتصر على القيم بين 0 و 7. محسوب في المثال ، 10100011 & 00000111 = 00000011 = 3.
تُستخدم قيمة فهرس البتات هذه مع مشغل إزاحة البتات ، أي إزاحة 3 بتات إلى اليسار ، مما ينتج عنه فهرس 8 بتات 00001000 ، لإنشاء بت مقلوب.
v1 هو البايت بالكامل وليس فهرس البت الفعلي ، لأن هذه القيمة ستكون معطلة على مستوى البت في مرشح Bloom لاحقًا. ستضمن العملية OR أن جميع البتات المقابلة في مرشح Bloom قد تم قلبها أيضًا.
ضع hashbuf من خلال ترتيب uint16 بايت كبير الحجم ، مما يجعله يحد من أول 2 بايت من صفيف البت ، وهو 0xada3 = 1010110110100011 في المثال.
على مستوى البت وهذه القيمة مع 0x7ff = 0000011111111111. هناك 11 بت حيث تم تعيين 0x7ff على 1. كما هو مذكور في الورقة الصفراء ، "يقوم بذلك عن طريق أخذ 11 بتًا أقل من كل من الأزواج الثلاثة الأولى". سينتج عن ذلك القيمة 0000010110100011 وهي 1010110110100011 & 0000011111111111.
ثم انقل القيمة إلى اليمين بمقدار 3 بتات. يؤدي ذلك إلى تحويل رقم مكون من 11 رقمًا إلى رقم مكون من 8 أرقام. نريد فهرس بايت ، وطول بايت مرشح Bloom هو 256 ، لذلك يجب أن تكون قيمة فهرس البايت في هذا النطاق. ويمكن أن يكون الرقم المكون من 8 بتات أي قيمة بين 0 و 255. في مثالنا ، هذه القيمة هي 0000010110100011 مقلوبة إلى اليمين بمقدار 3 بتات 10110100 = 180.
احسب مؤشر البايت الخاص بنا عن طريق BloomByteLength ، مع العلم أنه 256 ناقص 180 المحسوب ، ناقص 1. اطرح 1 لتحافظ على النتيجة بين 0 و 255. هذا يعطينا فهرس البايت الذي يجب تحديثه ، والذي يتبين في هذه الحالة أنه بايت 75 ، وهي الطريقة التي حسبنا بها i1.
قمنا فقط بتغطية زوج البايت الأول 0xada3 ، والذي تم إجراؤه مرة أخرى لأزواج البايت 2 و 3. سيتم تحديث كل عنوان / موضوع 3 بت في متجه 2048 بت. كما هو مذكور في الورقة الصفراء ، "يعين مرشح Bloom ثلاث بتات في عام 2048 بالنظر إلى تسلسل عشوائي من البايتات".
تقوم حالة زوج البايت 2 بتحديث مؤشر البت 1 بالبايت 195 (يتم التنفيذ وفقًا للإجراءين 3 و 4 ، تظهر النتيجة في الشكل).
تحديث حالة زوج البايت 3 مؤشر بت 4 في البايت 123.
إذا تم قلب البت المراد تحديثه بالفعل بواسطة موضوع آخر ، فسيظل كما هو. سوف يقلب إلى 1 إذا لم يكن كذلك.
من خلال عملية التشغيل المذكورة أعلاه ، يمكن تحديد أن موضوع توقيع الحدث سوف يقلب البتات التالية في مرشح Bloom:
عند النظر إلى logBlooms في إيصال المعاملة ، المحول إلى ثنائي ، يتحقق من تعيين مؤشرات البت هذه.
وفي الوقت نفسه ، بالنسبة لأولئك القراء المهتمين بمعرفة المزيد حول تنفيذ البحث في السجل ومرشح Bloom ، يمكنك الرجوع إلى مقالة BloomBits Trie.
في هذه المرحلة ، انتهت مناقشتنا المتعمقة لسلسلة مقالات EVM ، وسنقدم لك المزيد من المقالات التقنية عالية الجودة في المستقبل.