הערכת מדיניות העסקאות

לפני שחותמים על עסקה באמצעות חישוב רב-משתתפים, המערכת בודקת את העסקה בהתאם למדיניות העסקאות במכונה שלכם. במאמר הזה נסביר אילו כללי מדיניות נבדקים, איך כלל מדיניות עובר במחזור החיים שלו, מה אפשר לבדוק באמצעות כלל מדיניות ולמה טרנזקציה נדחית.

איך מתבצעת הערכה של עסקה

מדיניות עסקה היא הצהרה אחת של Cedar מסוג permit או forbid. כשחותם קורא ל-CreateTransaction, המכונה מפענחת את העסקה הלא חתומה ב-Transaction.payload באמצעות המנתח של Transaction.schema, ובודקת כל מדיניות שנאכפת מול העסקה לפני שנעשה שימוש בחלק כלשהו של המפתח. המדיניות נאכפת כשהסטטוס שלה הוא ACTIVE או PENDING_DISABLED. מידע נוסף על מחזור החיים של המדיניות

ההחלטה מבוססת על שלושה כללים:

  1. דחייה כברירת מחדל. טרנזקציה מותרת רק אם לפחות מדיניות אחת של permit תואמת לה. אם אין כללי מדיניות לאכיפה, כל עסקה נדחית.
  2. האיסור מנצח. אם יש התאמה למדיניות forbid כלשהי, הטרנזקציה נדחית, גם אם יש התאמה גם למדיניות permit.
  3. אם המערכת לא מצליחה להעריך מדיניות, היא לא תואמת. לדוגמה, מדיניות שקוראת מאפיין הקשר אופציונלי שלא קיים בטרנזקציה תיכשל בהערכה. המכונה מתעדת את השגיאה, מדלגת על המדיניות הזו ומקבלת החלטה על סמך שאר כללי המדיניות שנאכפים. זה חל גם על כללי מדיניות של forbid, אז צריך לכתוב כללי מדיניות של forbid שלא יכולים להיכשל בגלל מאפיין חסר. לדוגמה, ראו תרחיש 8 ותרחיש 9.

עסקה שמכילה כמה העברות, כמו עסקת Solana עם כמה הוראות העברה, נבדקת פעם אחת לכל העברה. העסקה מותרת רק אם כל העברה מותרת. אם אחת מההעברות נדחית או שלא ניתן לפענח אותה, כל העסקה נדחית.

כל הערכה, אישור או דחייה, יוצרת רשומת הערכה שמוחזרת בעסקה ב-Transaction.policyEvaluationRecord.

ההחלטה קובעת אם המכונה יכולה לחתום על העסקה בלי לחכות לחתימות נוספות:

  • ‫PERMIT: אם בקשת ה-CreateTransaction כבר כוללת מספיק הרשאות חתימה כדי לעמוד בדרישות של מדיניות המפתחות של KeyRing, הטרנזקציה עוברת מיד לסטטוס SIGNING. אחרת, הוא נוצר ב-PENDING_AUTHORIZATION וממתין לחתימות נוספות.
  • ‫DENY: המכונה לא חותמת על העסקה באופן אוטומטי. הטרנזקציה נוצרת ב-PENDING_AUTHORIZATION, והערך של policyEvaluationRecord.decision מוגדר כ-DENY. החותמים יכולים לבדוק את רשומת ההערכה ולדחות את העסקה (RecordSignerDecision עם DENY) או לאשר אותה בכל מקרה (AUTHORIZE). העסקה נחתמת רק אם מספיק חותמים מאשרים אותה כדי לעמוד במדיניות המפתח.

מדיניות העסקאות היא אמצעי הגנה על חתימה אוטומטית, ולא חסימה של החותמים: החותמים יכולים לאשר עסקה שהמדיניות דוחה. הקובץ המקורי של PolicyEvaluationRecord נשאר מצורף לעסקה לצורכי ביקורת.

מחזור החיים של הפוליסה

אי אפשר לשנות את מדיניות העסקאות. ל-TransactionPolicy אין שיטת עדכון, וה-rule שלו לא ניתן לשינוי. כדי לשנות כלל, משביתים את המדיניות באמצעות DisableTransactionPolicy ויוצרים מדיניות חדשה באמצעות CreateTransactionPolicy.

כדי להפעיל או להשבית מדיניות, צריך לקבל אישורים מקוורום של כותבי מדיניות (משתמשים עם תפקיד POLICY_AUTHOR פעיל ב-User.roleStatuses). כל כותב מדיניות חותם על TransactionPolicySigningPayload שמציין את המדיניות (או את המכונה, במקרה של CreateTransactionPolicy), את הפעולה (ACTIVATE או DISABLE) ואת rule.cedarDocument. הבקשה שכוללת הצעה לשינוי נחשבת לאישור הראשון. מחברי מדיניות אחרים מאשרים באמצעות ApproveTransactionPolicy. מספר האישורים הנדרש הוא בין activationInfo.requiredApprovals ל-deactivationInfo.requiredApprovals. אם המכונה צריכה רק אישור אחד, השינוי נכנס לתוקף באופן מיידי.

בטבלה הבאה מתוארים כל מצבי המדיניות, ומצוין אם המדיניות נאכפת במצב הזה:

מדינה משמעות האם המדיניות נאכפת?
PENDING_ACTIVE המדיניות הוצעה והיא ממתינה לאישורים של כותבי המדיניות. לא
ACTIVE למדיניות יש activationInfo.requiredApprovals אישורים. כן
PENDING_DISABLED מחבר המדיניות ביקש להשבית את המדיניות, והבקשה ממתינה לאישורים. כן, עד שהבקשה תקבל deactivationInfo.requiredApprovals אישורים
DISABLED המדיניות הושבתה או בוטלה לפני שהופעלה. כללי מדיניות מושבתים נשמרים לצורכי ביקורת. לא

המדיניות עוברת בין הסטטוסים האלה בכיוון אחד:

  • ‫PENDING_ACTIVE עד ACTIVE: ההפעלה קיבלה מספיק אישורים.
  • ‫PENDING_ACTIVE עד DISABLED: כותב המדיניות מבטל את המדיניות באמצעות DisableTransactionPolicy לפני שהיא הופכת לפעילה.
  • ‫ACTIVE עד PENDING_DISABLED: כותב המדיניות קורא ל-DisableTransactionPolicy.
  • ‫PENDING_DISABLED עד DISABLED: לבקשת ההשבתה יש מספיק אישורים.

מדיניות יכולה להיכנס לכל מצב המתנה פעם אחת לכל היותר. אי אפשר להפעיל מחדש מדיניות שהושבתה. במקום זאת, צריך ליצור מדיניות חדשה.

בקטע תפקידי משתמשים מוסבר מי יכול להפעיל את השיטות האלה.

גרסת קבוצת המדיניות

קבוצת כללי המדיניות היא קבוצת כללי המדיניות שנאכפים (ACTIVE או PENDING_DISABLED) בנקודת זמן מסוימת. בכל פעם שמסתיימת הפעלה או השבתה, המכונה נותנת למעבר הזה את המספר הבא במונה של המכונה, ומתעדת אותו ב-activationInfo.transitionSequence או ב-deactivationInfo.transitionSequence. המספר הזה הוא גרסת קבוצת המדיניות שנוצרה במעבר.

בטבלה הבאה אפשר לראות איך הגרסה של קבוצת כללי המדיניות משתנה ברצף של אירועים:

אירוע רצף המעבר כללי מדיניות שנאכפים
מדיניות א' מופעלת. תשובה: activationInfo.transitionSequence = 1 A
מדיניות ב' מופעלת. B: activationInfo.transitionSequence = 2 א', ב'
מדיניות ג' מוצעת (PENDING_ACTIVE) ואז מבוטלת. ללא א', ב'
בקשה להשבתת מדיניות א' אושרה. תשובה: deactivationInfo.transitionSequence = 3 B

ביטול של מדיניות PENDING_ACTIVE אף פעם לא משנה את קבוצת כללי המדיניות שנאכפים, ולכן לא מתבצע רצף מעבר וגרסת קבוצת כללי המדיניות לא משתנה. בזמן שההעברה ממתינה לאישורים, הערך של transitionSequence לא מוגדר.

בכל הערכה, המערכת קוראת את כללי המדיניות, את ה-KeyLists ואת המפתחות נכון ל-createTime של העסקה, ומתעדת את רצף המעברים הגבוה ביותר שהושלם באותו זמן ב-policyEvaluationRecord.policySetVersion. אם לשתי הערכות יש את אותה גרסה של קבוצת כללי מדיניות, הן השתמשו באותם כללי מדיניות.

הבקשה של Cedar

בקשה ב-Cedar כוללת את הגורם, הפעולה, המשאב וההקשר. לדוגמה:

permit (
  principal == User::"alice@example.com",
  action == Action::"buy_transaction",
  resource == Resource::"transaction_management"
)
when {
  context.principal_keyring == "institutional-treasury" &&
  context has fiat_amount && context.fiat_amount <= 10000
};

איך משתמש ממופה ל-principal של Cedar

ה-principal הוא יוזם הטרנזקציה: המשתמש שה-principal שלו תואם לזהות המאומתת של מי שקורא ל-CreateTransaction. למשתמש צריך להיות תפקיד פעיל של SIGNER. ב-Cedar, הישות הראשית היא ישות User שהמזהה שלה הוא השדה principal של המשתמש, לדוגמה User::"alice@example.com".

המופע לא מעביר נתוני ישויות ל-Cedar. לישות User אין מאפיינים ואין הורים, לכן:

  • principal == User::"alice@example.com" תואם לעסקאות שאליס יוזמת.
  • התנאי principal in Team::"treasury" אף פעם לא מתקיים. כדי להגביל את המשתמשים שיכולים לחתום באמצעות מפתח, משתמשים במדיניות המפתח של KeyRing. כדי להחיל כלל על קבוצת מפתחות, מסמנים את התיבה context.principal_keyring.
  • כלל שקורא מאפיין של principal, כמו principal.team, נכשל בהערכה.

אי אפשר לשנות את ה-principal של המשתמש, ולכן כלל שכולל שם של חשבון משתמש ממשיך להתייחס לאותה זהות.

פעולה ומשאב

  • ‫action: הערך של Transaction.action בבקשה CreateTransaction, בפורמט של ישות Cedar Action. אפשר לבצע את הפעולות הבאות ב-CreateTransaction:

    פעולה משמש ל:
    Action::"buy_transaction" עסקה שבה רוכשים נכס.
    Action::"sell_transaction" עסקה שבה נפטרים מנכס.
    Action::"internal_transfer_transaction" העברה של נכס, כמו תשלום או העברה בין מפתחות.

    מגיש הבקשה בוחר את הפעולה. החישוב הרב-משתתפים לא מסיק אותה מהמטען הייעודי (payload). כלל יכול להתאים לפעולה אחת (action == Action::"buy_transaction"), לרשימת פעולות (action in [Action::"buy_transaction", Action::"sell_transaction"]), או להשאיר את action ללא הגבלה כדי להתאים לכל פעולה.

  • ‫resource: תמיד Resource::"transaction_management" להערכות של טרנזקציות. כלל יכול לבדוק את resource == Resource::"transaction_management" או להשאיר את resource ללא הגבלה.

מאפייני הקשר

ההקשר מכיל את המאפיינים שכללי המדיניות בודקים. הם מגיעים משני מקומות:

  • מטען הייעודי (payload) של העסקה ומפתח החתימה. המכונה מפענחת את Transaction.payload ומוסיפה את המזהים של מפתח החתימה ושל אוסף המפתחות שלו. המאפיינים האלה הם principal_keyring,‏ principal_key,‏ blockchain,‏ schema,‏ secondary_key,‏ amount_token_scaled,‏ token_symbol,‏ contract_address,‏ chain_id,‏ max_fee_atomic,‏ payload ו-time_stamp. במאמר כתיבת כללים למדיניות של טרנזקציות מופיעה הטבלה המלאה וההתנהגות של כל בלוקצ'יין.
  • השדה metadata של העסקה,שמוגדר על ידי יוזם הפעילות ב-CreateTransaction.

בטבלה הבאה מתוארים מאפייני המטא-נתונים:

השדה Transaction.metadata מאפיין Cedar סוג הארז ערך
fiatAmount context.fiat_amount Long ערך העסקה בדולר ארה"ב (google.type.Money). הערך של currencyCode חייב להיות USD, הערך של units חייב להיות אפס או יותר, והערך של nanos חייב להיות 0.
validity context.validity Long משך הזמן שהעסקה תקפה (google.protobuf.Duration), בשניות שלמות. הערך חייב להיות גדול מ-0 שניות, ללא חלקי שניות.
principalValue1 context.principal_value1 String כל ערך שתגדירו, עד 256 תווים, למשל דסק מסחר או מרכז עלויות.
principalValue2 context.principal_value2 String כל ערך שתגדירו, עד 256 תווים, למשל מזהה פנימי של כרטיס או של צד נגדי.

הכללים הבאים חלים על מטא-נתונים:

  • שדות שלא הוגדרו לא נמצאים בהקשר. אם לעסקה אין fiatAmount, אז context.fiat_amount לא קיים, והמדיניות שקוראת אותו נכשלת בהערכה. קודם בודקים אם המאפיין קיים באמצעות has, כמו ב-context has fiat_amount && context.fiat_amount <= 10000.
  • מטא-נתונים לא תקינים גורמים לבקשה להיכשל. אם שדה מפר את הכללים בטבלה שלמעלה, למשל fiatAmount ב-EUR או עם nanos שאינו אפס, validity של 0 שניות או principalValue1 באורך של יותר מ-256 תווים, הפעולה CreateTransaction נכשלת עם INVALID_ARGUMENT ואף מדיניות לא נבדקת.
  • המופע לא בודק את המטא-נתונים מול העסקה. הערך fiatAmount הוא הערך של העסקה לפי מה שהיוזם אומר. חותמים אחרים רואים את המטא-נתונים ב-Transaction.metadata וב-policyEvaluationRecord.evaluationContext לפני שהם מאשרים אותם. כדי להגביל את הסכומים בשרשרת ללא קשר למטא-נתונים, צריך לבדוק את context.amount_token_scaled ו-context.contract_address.
  • אי אפשר לשנות את המטא-נתונים אחרי שהעסקה נוצרת.

KeyRings

KeyRing מקבץ מפתחות. לכל הקשר של טרנזקציה יש principal_keyring ו-principal_key, כך שכלל יכול לחול על כל מפתח ב-KeyRing, כולל מפתחות שנוצרו מאוחר יותר, ו-KeyRing יכול להיות רשומה ב-KeyList. למידע נוסף ולכלל לדוגמה, ראו KeyRings.

KeyLists

‫KeyList היא רשימה עם שם של כתובות בלוקצ'יין שאפשר להפנות אליהן כללי מדיניות, למשל כרשימת היתרים של יעדים. כל רשומה היא אחת מהאפשרויות הבאות:

  • רשומה ידנית (manualEntry): כתובת שהמכונה לא מנהלת, עם שדות אופציונליים של source ו-reason.
  • מפתח במכונה (key): תואם לכתובות של המפתח.
  • אוסף מפתחות במכונה (keyRing): תואם לכתובות של כל מפתח פעיל באוסף המפתחות, כולל מפתחות שנוצרו אחרי שהרשומה נוספה.

רשימות KeyLists יכולות להשתנות אחרי שהמדיניות מאושרת. כשמוסיפים או מסירים רשומה באמצעות AddKeyListEntries או RemoveKeyListEntries, כל כללי המדיניות שמתייחסים ל-KeyList משתמשים ברשומות החדשות מההערכה הבאה, בלי אישורים חדשים של כותבי המדיניות. אי אפשר למחוק KeyList באמצעות DeleteKeyList אם כללי המדיניות PENDING_ACTIVE,‏ ACTIVE או PENDING_DISABLED מתייחסים אליו.

‫KeyLists בהקשר של Cedar

בזמן ההערכה, המכונה מרחיבה כל KeyList ל-Set שטוח של כתובות בלוקצ'יין ב-String: הרשומות הידניות, וגם הכתובות שנגזרות מכל רשומה של מפתח ו-KeyRing. כל קבוצה מועברת ל-Cedar בתור context.key_lists["<var>KEY_LIST_ID</var>"], כאשר KEY_LIST_ID הוא המזהה של {keyList} בשם המשאב של KeyList, לדוגמה trusted-destinations עבור projects/my-project/locations/us-central1/instances/my-instance/keyLists/trusted-destinations.

כלל בודק את החברות באמצעות האופרטור contains של Cedar מול כתובת היעד המפוענחת, context.secondary_key. לדוגמה, כדי לאפשר העברות רק לכתובות ב-KeyList של trusted-destinations:

// Assuming you created a KeyList with ID "trusted-destinations":
permit (principal, action, resource)
when { context.key_lists["trusted-destinations"].contains(context.secondary_key) };

כדי לדחות העברות לכל כתובת ב-KeyList של blocked-addresses:

// Assuming you created a KeyList with ID "blocked-addresses":
forbid (principal, action, resource)
when { context.key_lists["blocked-addresses"].contains(context.secondary_key) };

חשוב לזכור:

  • צריך להשתמש בתחביר של סוגריים מרובעים, ולא בתחביר של נקודה, עבור מזהה KeyList. תחביר הנקודה של Cedar‏ (context.key_lists.trusted-destinations) נכשל בניתוח כשהמזהה מכיל מקף, ש-Cedar קורא כחיסור, או כשהוא מתחיל בספרה, כמו UUID שנוצר על ידי שרת. תחביר הסוגריים המרובעים, context.key_lists["<var>KEY_LIST_ID</var>"], פועל עם כל מזהה.
  • ‫key_lists תמיד קיים, וכלל יכול לקרוא KeyList ישירות בתוכו. ‫CreateTransactionPolicy מוודא שכל KeyList שהכלל מתייחס אליו קיים, ו-DeleteKeyList מסרב למחוק KeyList אם מדיניות מתייחסת אליו. השתמשו ב-context.key_lists has "<var>KEY_LIST_ID</var>" רק כשכלל מתייחס ל-KeyList שאולי עדיין לא קיים.
  • הכתובות מושוות כמחרוזות. השדה secondary_key משתמש בפורמט שמתואר בקטע כתיבת כללי מדיניות לעסקאות לכל בלוקצ'יין, למשל פורמט סיכום ביקורת (checksum) של EIP-55 עם אותיות רישיות וקטנות ל-Ethereum. מוסיפים רשומות ידניות באותו פורמט.
  • השדה secondary_key בהעברת טוקן של Solana הוא חשבון הטוקן של היעד, ולא הארנק של הבעלים. כדי לאשר ארנק, צריך להוסיף את חשבון האסימון שלו לכל מטבע שמאשרים.

כל הערכה פותרת את החברות ב-KeyList נכון ל-createTime של העסקה, באותו זמן כמו המדיניות, ומתעדת את התוצאה ב-policyEvaluationRecord.keyListMemberships: ה-KeyList, הכתובת שנבדקה, אם היא הייתה חברה, והרשומה שהתאימה.

מכיוון ש-KeyList משנה את מה שהמדיניות מתירה, צריך להגביל את מי שיכול לשנות אותה. השיטות של KeyList צריכות את roles/mpc.admin. מידע נוסף זמין במאמר הרשאות IAM.

הסיבות לדחייה

כשהערך של policyEvaluationRecord.decision הוא DENY, הסיבה מופיעה בשדה policyEvaluationRecord.denyReason. בטבלה הבאה מפורטות הסיבות לדחייה:

הסיבה לדחייה מתי קביעת כללי מדיניות
FORBID_RULE_MATCHED לפחות מדיניות forbid אחת שנאכפה תאמה. forbid כללי המדיניות שתואמים.
NO_PERMIT_RULE_MATCHED המטען הייעודי (payload) פוענח, לא נמצאה התאמה למדיניות forbid, לא נכשלה הערכה של מדיניות ולא נמצאה התאמה למדיניות permit. ללא
EVALUATION_ERROR אין התאמה למדיניות permit או forbid, ולפחות מדיניות אחת נכשלה בהערכה, למשל כי היא קוראת מאפיין אופציונלי שלא נמצא בהקשר. אין. ‫evaluationErrors מפרט את השגיאות.
UNRECOGNIZED_PAYLOAD המכונה לא הצליחה לפענח את Transaction.payload או להקרין אותו להקשר, למשל בגלל בייטים פגומים, הוראה או פעולת חוזה לא נתמכות, או עסקה בביטקוין עם כמה נמענים. לא מתבצעת הערכה של המדיניות. אין. השגיאה בניתוח מופיעה ב-evaluationErrors.

הסיבות נקבעות לפי הסדר הבא:

  1. אם אי אפשר לפענח את המטען הייעודי (payload) או להקרין אותו להקשר, ההחלטה היא DENY עם UNRECOGNIZED_PAYLOAD.
  2. אחרת, כל מדיניות שנאכפת נבדקת. אם יש התאמה למדיניות forbid כלשהי, ההחלטה היא DENY עם FORBID_RULE_MATCHED, גם אם יש התאמה גם לכללי מדיניות permit או אם כללי מדיניות אחרים לא נבדקו.
  3. אחרת, אם יש התאמה לפחות למדיניות אחת של permit, ההחלטה היא PERMIT. שגיאות ממדיניות אחרת עדיין מתועדות ב-evaluationErrors.
  4. אחרת, ההחלטה היא DENY עם EVALUATION_ERROR אם הערכת מדיניות כלשהי נכשלה, או NO_PERMIT_RULE_MATCHED אם כל כללי המדיניות הוערכו ללא התאמה.

השגיאות מתועדות גם כשההחלטה היא PERMIT, לכן כדאי לבדוק את רשומת ההערכה כדי לראות אם יש כללי מדיניות שאף פעם לא תואמים כי הם תמיד נכשלים.

תרחישים

בתרחישים 1 עד 9, אליס (User::"alice@example.com") יוצרת העברת Ethereum תקינה, שבה action מוגדר ל-Action::"internal_transfer_transaction", עם המטא-נתונים הבאים, אלא אם צוין אחרת בתרחיש:

"metadata": {
  "fiatAmount": {"currencyCode": "USD", "units": "5000"},
  "principalValue1": "treasury-desk"
}

בעסקה אין validity ואין principalValue2.

בטבלה הבאה מפורטים התרחישים השונים:

תרחיש כללי מדיניות שנאכפים או מטען ייעודי (payload) החלטה הסיבה לדחייה
1 ללא DENY NO_PERMIT_RULE_MATCHED
2 ‫permit אחד שתואם PERMIT
3 ‫permit אחד שלא תואם DENY NO_PERMIT_RULE_MATCHED
4 שני permit, אחד תואם PERMIT
5 ‫permit ו-forbid ששניהם תואמים DENY FORBID_RULE_MATCHED
6 ‫permit שקורא מאפיין חסר DENY EVALUATION_ERROR
7 אותו permit, עם has DENY NO_PERMIT_RULE_MATCHED
8 forbid שקורא מאפיין חסר, וpermit תואם PERMIT
9 forbid שנדרש לו מאפיין DENY FORBID_RULE_MATCHED
10 מטען ייעודי (payload) שלא ניתן לפענח DENY UNRECOGNIZED_PAYLOAD

תרחיש 1: אין כללי מדיניות שנאכפים

במכונה אין כללי מדיניות של ACTIVE או PENDING_DISABLED.

החלטה: DENY, NO_PERMIT_RULE_MATCHED. בלי מדיניות permit תואמת, כל טרנזקציה נדחית. במכונה חדשה, אף טרנזקציה לא נחתמת באופן אוטומטי עד שכותבי המדיניות מפעילים מדיניות permit. החותמים חייבים לאשר כל טרנזקציה.

תרחיש 2: היתר אחד שתואם

permit (principal, action, resource)
when { context has fiat_amount && context.fiat_amount <= 10000 };

ההחלטה: PERMIT. הסכום, 5,000, הוא לכל היותר 10,000. המדיניות הזו מופיעה ב-determiningPolicyIds.

תרחיש 3: היתר אחד שלא תואם

permit (principal, action, resource)
when { context has fiat_amount && context.fiat_amount <= 1000 };

החלטה: DENY, NO_PERMIT_RULE_MATCHED. הסכום, 5,000, גבוה מ-1,000, ואין מדיניות אחרת שמאפשרת את העסקה.

תרחיש 4: שני היתרים, אחד תואם

מדיניות א':

permit (principal, action, resource)
when { context has fiat_amount && context.fiat_amount <= 1000 };

מדיניות ב':

permit (
  principal == User::"alice@example.com",
  action == Action::"internal_transfer_transaction",
  resource == Resource::"transaction_management"
)
when {
  context has fiat_amount && context.fiat_amount <= 25000 &&
  context has principal_value1 && context.principal_value1 == "treasury-desk"
};

ההחלטה: PERMIT. מדיניות א' לא תואמת, אבל מדיניות ב' כן. מספיקה מדיניות permit תואמת אחת. determiningPolicyIds מציג רק את מדיניות ב'.

תרחיש 5: איסור מבטל היתר

מדיניות א':

permit (principal, action, resource)
when { context has fiat_amount && context.fiat_amount <= 10000 };

מדיניות ב':

forbid (principal, action, resource)
when { context has principal_value1 && context.principal_value1 == "treasury-desk" };

החלטה: DENY, FORBID_RULE_MATCHED. שתי כללי המדיניות תואמים, והמדיניות forbid מנצחת. determiningPolicyIds מציג רק את מדיניות ב'.

תרחיש 6: היתר קורא מאפיין חסר

permit (principal, action, resource)
when { context.validity <= 3600 };

החלטה: DENY, EVALUATION_ERROR. בעסקה אין validity, ולכן context.validity לא קיים והמדיניות לא נבדקת. אין מדיניות אחרת שמאפשרת את העסקה. השגיאה מופיעה בעמודה evaluationErrors.

תרחיש 7: אותו היתר, עם

permit (principal, action, resource)
when { context has validity && context.validity <= 3600 };

החלטה: DENY, NO_PERMIT_RULE_MATCHED. context has validity הוא false, ולכן המדיניות מקבלת את הערך false במקום להיכשל. העסקה עדיין נדחית, אבל הסיבה מראה שהמדיניות נבדקה ולא נמצאה התאמה.

תרחיש 8: כלל איסור קורא מאפיין חסר

מדיניות א':

permit (principal, action, resource)
when { context has fiat_amount && context.fiat_amount <= 10000 };

מדיניות ב':

forbid (principal, action, resource)
when { context.principal_value2 == "sanctioned-counterparty" };

ההחלטה: PERMIT. בעסקה אין principalValue2, ולכן מדיניות ב' לא נבדקת והמערכת מדלגת עליה. מדיניות א' תואמת. determiningPolicyIds מציג את מדיניות א', ו-evaluationErrors מציג את השגיאה ממדיניות ב'.

תרחיש 9: איסור שדורש מאפיין

מדיניות א' היא המדיניות permit מתרחיש 8. מדיניות ב':

forbid (principal, action, resource)
unless { context has fiat_amount };

החלטה: PERMIT על העסקה בתרחישים האלה, שבהם יש fiatAmount. אם אליס לא כוללת את fiatAmount, ההחלטה היא DENY, FORBID_RULE_MATCHED: context has fiat_amount הוא false, ולכן המדיניות forbid תואמת. המדיניות הזו לא יכולה להיכשל בהערכה, כי היא משתמשת רק ב-has.

כדי לשלב מאפיין חובה עם בדיקה של הערך שלו במדיניות forbid אחת, קודם בודקים את המאפיין:

forbid (principal, action, resource)
unless { context has fiat_amount && context.fiat_amount <= 10000 };

תרחיש 10: מטען ייעודי (payload) שלא ניתן לפענח

אליס יוצרת עסקה שהמנתח של Transaction.schema לא יכול לפענח את ה-payload שלה, למשל בייטים של RLP קטועים, PSBT של ביטקוין עם כמה נמענים או עסקת סולאנה עם הוראה שלא נתמכת.

החלטה: DENY, UNRECOGNIZED_PAYLOAD. לא מתבצעת הערכה של המדיניות. השדה evaluationErrors מפרט את שגיאת הניתוח, והשדה determiningPolicyIds ריק.

רשומת הערכה

כל הערכה מפיקה PolicyEvaluationRecord שאי אפשר לשנות. הוא מוחזר ב-Transaction.policyEvaluationRecord וכולל את השדות הבאים:

שדה ערך
decision ‫PERMIT או DENY.
denyReason אחת מהסיבות לדחייה. לא מוגדר כשההחלטה היא PERMIT.
determiningPolicyIds ב-PERMIT, המזהים של כללי המדיניות של permit שתאמו. ב-FORBID_RULE_MATCHED, המזהים של כללי המדיניות של forbid שתאמו. אחרת, השדה ריק.
evaluationErrors השגיאות ממדיניות שההערכה שלה נכשלה, או שגיאת המנתח כש-denyReason הוא UNRECOGNIZED_PAYLOAD.
evaluationContext ההקשר של Cedar שכללי המדיניות הוערכו לפיו, בתור google.protobuf.Struct. מספרים שלמים של 64 ביט מאוחסנים כמחרוזות עשרוניות כדי לשמור על הדיוק שלהם.
policySetVersion גרסת קבוצת כללי המדיניות ששימשה להערכה.
keyListMemberships החברויות ב-KeyList שזוהו במהלך ההערכה.
intentDigest תקציר מקודד הקסדצימלי באותיות קטנות של המטען הייעודי (payload) של העסקה שנבדקה. הגיבוב תלוי בסכימה של המטען הייעודי (payload): ‏Keccak-256 של העסקה עבור ETHEREUM_TX_V2, ה-sighash של הקלט הראשון עבור BITCOIN_TX_V2, ‏SHA-256 של ההודעה הלא חתומה עבור SOLANA_TX_V1, ותקציר החתימה של EIP-712, ‏keccak256(0x1901 ++ domainSeparator ++ hashStruct(message)), עבור EIP712_TYPED_DATA_V1.
evaluationTime מתי הבדיקה בוצעה.