پرش به مطلب اصلی

قرارداد ماژول امنیتی اوراکل

دامنه این صفحه

این صفحه مرجع قرارداد هوشمند در سطح ذخیره‌سازی و توابع است؛ مخاطب آن حسابرسی، بازبینی مستقل و کار مستقیم با قراردادهای روی زنجیره است. مسیر یکپارچه‌سازی سازمانی از راهنمای یکپارچه‌سازی سازمانی می‌گذرد و مستقل از این مرجع است.

مقدمه

قرارداد ماژول امنیتی اوراکل1 یا OSM تضمین می‌کند که سیستم قیمت‌های تازه‌ منتشرشده از اوراکل را تا نگذشتن مدتی مشخص نپذیرد. مقادیر از قرارداد DSValue یا هر قرارداد دیگری که رابط‌های read و peek را داشته باشد از طریق روش poke خوانده می‌شوند؛ روش‌های read و peek مقدار فعلی تغذیه قیمت را می‌دهند، و برای فراخوانی‌شان، قراردادهای دیگر باید در لیست معتبر قرار گرفته شوند. یک قرارداد ماژول امنیتی اوراکل می‌تواند تنها از یک تغذیه‌گر قیمت بخواند، بنابراین در عمل یک قرارداد ماژول امنیتی اوراکل برای هر نوع وثیقه باید دیپلوی شود.

عملکردهای کلیدی و اصطلاحات ماژول امنیتی اوراکل

چیدمان ذخیره‌سازی

  • stopped : یک پرچم از نوع uint256 که در صورت غیر صفر بودن، به روزرسانی‌های تغذیه قیمت را غیر فعال می‌کند.
  • src : آدرس DSValue که ماژول امنیتی اوراکل از آن خواهد خواند.
  • ONE_HOUR : معادل ۳۶۰۰ ثانیه از نوع داده uint16
  • hop : تاخیر زمانی بین فراخوانی‌های poke از نوع uint16 که به‌صورت پیش‌فرض ONE_HOUR است.
  • zzz: زمان آخرین به‌روزرسانی (گرد شده به نزدیک‌ترین مضرب و کوچکتر از hop)
  • cur : ساختار Feed که مقدار فعلی تغذیه را نگه می‌دارد
  • nxt : ساختار Feed که مقدار بعدی تغذیه را نگه می‌دارد
  • bud : یک نگاشت از آدرس به داده uint256 ؛ خوانش‌های تغذیه را در لیست معتبر قرار می‌دهد

متدهای عمومی

متدهای مدیریتی

این توابع را تنها آدرس‌های مجاز می‌توانند فراخوانی کنند؛ یعنی آدرس‌های usr که wards[usr] == 1 باشد.

  • rely/deny : اضافه یا حذف کاربران مجاز (با انجام تغییرات در نگاشت wards)
  • stop /start : تغییر اینکه آیا تغذیه قیمت می‌تواند به‌روزرسانی شود یا خیر (با تغییر مقدار stopped)
  • change : تغییر داده برای قیمت‌ها (با تنظیم src)
  • step : تغییر فاصله بین به‌روزرسانی‌های قیمت (با تنظیم hop)
  • void : مشابه stop است، اما همچنین cur و nxt را به یک ساختار Feed با مقادیر صفر می‌رساند
  • kiss/diss : اضافه کردن/حذف مصرف‌کنندگان feed مجاز (با تغییرات در نگاشت buds)

متدهای خواندن تغذیه

این متدها را هم تنها آدرس‌هایی می‌توانند فراخوانی کنند که در لیست معتبر جای گرفته‌اند

  • peek : مقدار تغذیه فعلی و یک باینری که نشان دهنده اعتبار است را برمی‌گرداند
  • peep : مقدار تغذیه بعدی را نشان می‌دهد (به عبارت دیگر چیزی که در فراخوانی poke بعدی به مقدار فعلی تبدیل می‌شود) و یک باینری را برمی‌گرداند که نشان می‌دهد معتبر است یا خیر
  • read : مقدار تغذیه فعلی را برمی‌گرداند؛ اگر سازوکار معتبری آن را تنظیم نکرده باشد، متدهای به‌روزرسانی تغذیه را برمی‌گرداند
  • poke : مقدار تغذیه فعلی را به‌روزرسانی می‌کند و مقدار بعدی خوانده می‌شود
  • ساختار Feed: یک ساختار با دو عضو از نوع uint128 شامل val و has که برای ذخیره داده‌ تغذیه استفاده می‌شوند.

سازوکار‌ها و مفاهیم کلیدی

سازوکار مرکزی به‌طور دوره‌ای یک قیمت به تعویق افتاده را برای نوع خاصی از وثیقه به سیستم MCD تأمین می‌کند. برای اینکه این کار به خوبی انجام شود، یک فعال خارجی باید به‌طور منظم متد poke را فراخوانی، قیمت فعلی را به‌روزرسانی کرده و قیمت بعدی را بخواند. این قرارداد زمان آخرین فراخوانی poke را در متغیر zzz ( به نزدیکترین مضرب از hop به پایین گرد شده است) پیگیری می‌کند و اجازه نمی‌دهد تابع poke فراخوانی شود تا وقتی که مقدار block.timestamp حداقل برابر zzz+hop باشد. این مقادیر از قرارداد DSValue (آدرس آن در src ذخیره می‌شود) خوانده می‌شوند. هدف این سازوکار که به‌روزرسانی با تأخیر انجام می‌شود این است که زمان کافی برای شناسایی و واکنش به یک حمله اوراکل (مانند تنظیم قیمت وثیقه به صفر) فراهم شود. واکنش‌ها به این موضوع شامل فراخوانی stop یا void یا فعال‌سازی خاموشی اضطراری است.

قرارداد‌های دیگر، اگر در لیست معتبر قرار داده شوند، می‌توانند مقدار cur را از طریق متد‌های peek و read بررسی کنند. تابع peek یک مقدار باینری برمی‌گرداند که نشان می‌دهد که آیا مقدار برای آن تنظیم شده است یا خیر. اگر مقدار تنظیم نشده باشد، read وظیفه ‍revert را دارد. مقدار nxt می‌تواند از طریق peep بررسی شود. این قرارداد از یک ساختار مجوزدهی دوسطحی استفاده می‌کند. به این صورت که آدرس‌هایی که به ۱ در wards نگاشت می‌شوند، می‌توانند شروع و متوقف شوند، src را تنظیم کنند، مقدار void را فراخوانی کنند، و خوانش‌های جدید را اضافه کنند؛ آدرس‌هایی که در ‍buds به ۱ نگاشت می‌شوند می‌توانند peek، peep و read را فراخوانی کنند.

خطاهای احتمالی کاربر

اشتباه در فراخوانی peek به‌عنوان peep (یا برعکس) می‌تواند موجب اشتباهاتی شود. نام این متدها تنها یک حرف اختلاف دارد و در استفاده فعلی، هر دو "peek" و "peep" مفهوم مشابهی را دارند. این امر ممکن است باعث شود یک توسعه‌دهنده این دو را با هم اشتباه بگیرد و متد اشتباه را فراخوانی کند. اثرات چنین اشتباهاتی به‌طور طبیعی به متن وابسته هستند، اما ممکن است برای مثال هدف اصلی ماژول امنیتی اوراکل نادیده گرفته شود. یک روش یادآوری برای کمک به تمایز دادن آن‌ها این است که چون 'k' در زبان انگلیسی قبل از 'p' می‌آید، مقداری که peek برمی‌گرداند، پیش از مقداری است که peep برمی‌گرداند.

حالت‌های احتمالی شکست

هنگامی که poke به موقع فراخوانی نمی‌شود، قیمت‌های مخرب به سرعت وارد الگوریتم می‌شوند. به دلایل مختلفی، poke همواره و تا زمانی که block.timestamp/hop در حال افزایش است، قابل فراخوانی است بدون توجه به اینکه اخرین بار چه وقتی poke فراخوانی می‌شود. (زیرا zzz به نزدیک‌ترین مضرب از hop به پایین گرد می‌شود). این به این معناست که در واقع قرارداد تضمینی ندارد که یک بازه زمانی حداقلی hop ثانیه از زمان آخرین فراخوانی گذشته است. در واقع فقط این ضمانت را دارد که آخرین فراخوانی poke بلافاصله پس از افزایش قبلی block.timestamp/hop رخ داده باشد. بنابراین، ممکن است سیستم قیمت مخرب را در فاصله‌ای کمتر از hop تأیید کند.

مورد بعدی در واقع تصمیمی عمدی در طراحی است. دلیلی که در حمایت از آن آورده می‌شود این است که امکان اجرای کامل ماژول امنیتی اوراکل را به‌طور قابل اعتمادی در همان زمان و در یک تراکنش تضمین می‌کند. عمومی بودن poke و اینکه هر کسی می‌تواند فراخوانی‌اش کند، از این نگرانی‌ها می‌کاهد، هرچند آن‌ها را از میان نمی‌برد. به‌عنوان مثال، شلوغی شبکه می‌تواند جلوی هر کسی را از فراخوانی موفق poke بگیرد. اگر مشاهده شود که poke به‌موقع فراخوانی نشده است، اقداماتی که می‌شود انجام داد از این قرارند:

  • فراخوانی poke به‌ صورت شخصی و تصمیم‌گیری در مورد اینکه آیا مقدار بعدی مخرب است یا نه.
  • فراخوانی stop یا void (اولی اگر تنها nxt مخرب باشد؛ دومی اگر مقدار مخرب از قبل در cur باشد).
  • فعال‌سازی خاموشی اضطراری (اگر سلامتی سیستم به‌طور کلی آسیب دیده باشد یا اگر باور بر این باشد که اوراکل‌های شرور در زمان معقولی قابل اصلاح نیستند). در آینده، منطق قرارداد ممکن است برای کاهش این چالش (به‌طور مثال با تنظیم فقط اجازه فراخوانی poke در یک بازه زمانی کوتاه در هر دوره hop ) تنظیم شود.

حملات اجازه‌دهنده و اشتباهات تنظیمات

افراد یا قراردادهای مجاز می‌توانند اقدام‌های مخرب گوناگونی انجام دهند؛ چه تصادفی و چه از سر بی‌احتیاطی:

  • لغو دسترسی قراردادهای اصلی به متدهایی که مقادیر را می‌خوانند، باعث عدم موفقیت در به‌روزرسانی قیمت می‌شود
  • لغو کامل دسترسی به قرارداد
  • تغییر src به یک قرارداد مخرب یا به چیزی که دارای رابط peek نباشد، باعث می‌شود تراکنش‌هایی که OSM آسیب‌دیده را به poke بازگرداند.
  • فراخوانی توابع مختلفی مانند stop و void به‌صورت نامناسب تنها راه حل برای این مسائل، مراقبت و دقت در مورد wards از ماژول امنیتی اوراکل است.

Footnotes

  1. Oracle Security Module