Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Mit einfachen benutzerdefinierten Funktionen (UDFs) im Azure Vertraulichen Hauptbuch können Sie maßgeschneiderte JavaScript-Funktionen erstellen, die innerhalb der Vertrauensgrenze des Hauptbuchs ausgeführt werden können. Dieses Feature ist so konzipiert, dass es einfach und einfach zu bedienen ist, sodass Sie die Funktionalität der Ledger-API erweitern können, ohne dass eine komplexe Anwendungsentwicklung erforderlich ist.
Mithilfe der integrierten JavaScript-API können Sie benutzerdefinierten Code ausführen, um verschiedene Aufgaben zu erreichen, z. B. benutzerdefinierte Abfragen und Berechnungen, bedingte Prüfungen, Aufgaben nach der Verarbeitung und vieles mehr. Dieses Feature eignet sich für Szenarien, in denen Sie eine direkte Integration mit der vorhandenen Ledger-API benötigen oder einfache benutzerdefinierte Logik in einer vertraulichen Umgebung ausführen.
Eine kurze Übersicht und Demo zu UDFs sehen Sie im folgenden Video:
Von Bedeutung
Benutzerdefinierte Funktionen befinden sich derzeit in DER VORSCHAU unter API-Version 2024-12-09-preview.
Sie können über dieses Registrierungsformular Zugriff auf diese Vorschau anfordern.
Lesen Sie die ergänzenden Nutzungsbedingungen für Microsoft Azure Previews für rechtliche Bestimmungen, die für Azure-Features gelten, die sich in Der Betaversion, Vorschau oder auf andere Weise noch nicht in der allgemeinen Verfügbarkeit befinden.
Tipp
Erweiterte Szenarien, z. B. benutzerdefinierte rollenbasierte Zugriffssteuerung (RBAC) oder die Integration mit vertraulichen externen Workloads, werden unter Erweiterte benutzerdefinierte Funktionen in Azure Confidential Ledger beschrieben.
Anwendungsfälle
Mit Azure Confidential Ledger-UDFs können Sie die Funktionalität des Ledgers durch Ausführen benutzerdefinierter Logik erweitern. Einige häufige Anwendungsfälle für UDFs sind:
Benutzerdefinierte Berechnungen und Abfragen: Führen Sie eigenständige UDFs aus, um Daten gemäß Ihrer Geschäftslogik in beliebigen Ledger-Anwendungstabellen zu lesen oder zu schreiben.
Datenüberprüfungen und Eingabeüberprüfungen: Verwenden Sie UDFs als Vor-Hooks, um Vorverarbeitungsaktionen auszuführen, bevor ein Ledgereintrag in das Ledger geschrieben wird, z. B. zum Bereinigen von Eingabedaten oder zur Überprüfung auf Vorbedingungen.
Datenanreicherung und intelligente Verträge: Verwenden Sie UDFs als Post-Hooks, um Nachbearbeitungsaktionen auszuführen, nachdem ein Ledgereintrag geschrieben wurde, z. B. um benutzerdefinierte Metadaten in das Hauptbuch hinzuzufügen oder Post-Write-Workflows auszulösen.
Schreiben von UDFs
Ein vertrauliches Azure-Hauptbuch-UDF ist eine Entität, die im Hauptbuch mit einer eindeutigen ID gespeichert ist und den JavaScript-Code enthält, der ausgeführt wird, wenn die UDF aufgerufen wird. In diesem Abschnitt wird beschrieben, wie Sie UDF-Code schreiben und die JavaScript-API zum Erreichen verschiedener Aufgaben verwenden.
Funktionsstruktur
Der Code einer UDF erfordert eine exportierte Funktion, die den Einstiegspunkt des Skripts zum Zeitpunkt der Ausführung darstellt. Eine einfache UDF-Codevorlage sieht wie folgt aus:
export function main() {
// Your JavaScript code here
}
Hinweis
Der Name der exportierten Eintragspunktfunktion, die während der Ausführung aufgerufen wird, kann beim Ausführen der UDF mit dem exportedFunctionName Argument geändert werden. Wenn nicht angegeben, lautet mainder Standardname .
Hinweis
Lambda-Funktionen werden unterstützt, erfordern jedoch, dass der exportierte Funktionsname explizit definiert und dem Eintragspunktfunktionsnamen entspricht. Beispiel:
export const main = () => {
// Your JavaScript code here
};
Funktionsargumente
Sie können alle optionalen Laufzeitargumente angeben, die von der UDF akzeptiert werden. Die Werte der Argumente können zur Laufzeit übergeben werden, wenn die UDF mit dem arguments Parameter ausgeführt wird.
Die Argumente werden immer als Array von Zeichenfolgen übergeben. Es liegt in der Verantwortung des Benutzers, sicherzustellen, dass die im UDF-Code angegebenen Argumente mit den Argumenten übereinstimmen, die beim Ausführen der UDF übergeben werden. Der Benutzer sollte außerdem sicherstellen, dass die Argumente zur Laufzeit ordnungsgemäß auf den erwarteten Datentyp analysiert werden.
export function main(arg1, arg2) {
// Your JavaScript code here
}
JavaScript-API
Der JavaScript-Code einer UDF wird in einer Sandkastenumgebung ausgeführt, die einen begrenzten Satz von APIs bereitstellt.
Alle globalen JavaScript-Standardfunktionen, -Objekte und -Werte können verwendet werden. Ein globales Objekt namens ccf kann verwendet werden, um auf bestimmte Funktionen und Dienstprogramme zuzugreifen, die vom Vertraulichen Konsortium Framework (CCF) bereitgestellt werden (z. B. Kryptografiehilfsfunktionen, Ledger-Tabellen-Zugriffsfunktionen usw.). Die vollständige API des ccf globalen Objekts ist hier dokumentiert.
Sie können auch mithilfe des globalen Objekts auf kontextbezogene Informationen der aktuellen Anforderung context zugreifen. Dieses Objekt bietet Zugriff auf die Anforderungsmetadaten, die die Funktionsausführung initiierten (context.request), und auf die Benutzer-ID des Funktionsaufrufers (context.userId). Bei Transaktions-Hooks werden die Sammlungs-ID und der dem Schreibvorgang zugeordnete Transaktionsinhalt ebenfalls dem context Objekt hinzugefügt (context.collectionId bzw context.contents . ).
Der folgende Codeausschnitt zeigt einige grundlegende Beispiele für die Verwendung der JavaScript-API:
export function main(args) {
// Basic instructions
const a = 1 + 1;
// Basic statements
if (a > 0) {
console.log("a is positive");
} else {
console.log("a is negative or zero");
}
// Parse the string argument as a JSON object
JSON.parse(args);
// Logging utilities
console.log("Hello world");
// Math utilities
Math.random();
// CCF cryptography utilities
ccf.crypto.digest("SHA-256", ccf.strToBuf("Hello world"));
// Write to a custom ledger table
ccf.kv["public:mytable"].set(ccf.strToBuf("myKey"), ccf.strToBuf("myValue"));
// Read from a custom ledger table
ccf.bufToStr(ccf.kv["public:mytable"].get(ccf.strToBuf("myKey")));
// Read from the ledger entry table
ccf.kv["public:confidentialledger.logs"].get(ccf.strToBuf("subledger:0"));
// Get the request metadata that originated the function execution
const requestMetadata = context.request;
// Get the collection ID and transaction content (for transaction hooks only)
const collectionId = context.collectionId;
const contents = context.contents;
// Throw exceptions
throw new Error("MyCustomError");
}
Tipp
Weitere Informationen dazu, wie Ledger-Karten zum Speichern und Abrufen von Daten verwendet werden können, finden Sie in der CCF-Dokumentation zur Key-Value Store-API.
Hinweis
Das Importieren von Modulen wird in UDFs nicht unterstützt. Der JavaScript-Code muss eigenständig sein und kann sich nicht auf externe Bibliotheken oder Module verlassen. Web-APIs werden derzeit nicht unterstützt.
Verwalten von UDFs
Azure Confidential Ledger-Anwendungen bieten eine dedizierte CRUD-API zum Erstellen, Lesen, Aktualisieren und Löschen von UDF-Entitäten. UDFs werden sicher im Hauptbuch gespeichert und sind nur für die Hauptbuchanwendung zugänglich.
Hinweis
Einfache benutzerdefinierte Funktionen und erweiterte benutzerdefinierte Funktionen schließen sich gegenseitig aus. Sie können keine einfachen UDFs erstellen oder ausführen, wenn erweiterte UDFs definiert sind und umgekehrt. Wenn Sie zwischen den beiden Wechseln wechseln möchten, folgen Sie den Anweisungen auf der UDF-Übersichtsseite.
Erstellen oder Aktualisieren einer UDF
PUT /app/userDefinedFunctions/myFunction
{
"code": "export function main() { return "Hello World"; }",
}
Von Bedeutung
Die Administratorrolle ist erforderlich, um eine UDF zu erstellen oder zu aktualisieren.
Abrufen einer UDF
GET /app/userDefinedFunctions/myFunction
Auflisten von UDFs
GET /app/userDefinedFunctions
Löschen einer UDF
DELETE /app/userDefinedFunctions/myFunction
Von Bedeutung
Die Administratorrolle ist erforderlich, um eine UDF zu löschen.
Hinweis
Durch das Löschen einer UDF wird die Entität nur aus dem aktuellen Status des Ledgers entfernt. Alle gelöschten UDFs bleiben immer im unveränderlichen Ledger-Verlauf erhalten (wie alle Transaktionen, für die ein Commit ausgeführt wurde).
Ausführen von UDFs
Nach der Erstellung können Azure-Benutzer vertraulicher Sachkonten eine UDF entweder als eigenständige Funktion oder als Transaktionshaken ausführen, der einem Schreibvorgang zugeordnet ist. Jede UDF-Ausführung wird in einer separaten Laufzeitumgebung und Sandbox ausgeführt, was bedeutet, dass die UDF-Ausführung von anderen UDFs oder anderen Ledger-Vorgängen isoliert ist.
Die UDF-Ausführung kann mithilfe optionaler Eigenschaften gesteuert werden, die im Anforderungstext angegeben werden können. Die derzeit unterstützten Eigenschaften sind:
arguments: ein Array von Zeichenfolgen, die die Argumente darstellen, die an die UDF übergeben werden sollen. Die Argumente werden in der gleichen Reihenfolge übergeben, wie sie im UDF-Code definiert sind. Der Standardwert ist ein leeres Array.exportedFunctionName: der Name der exportierten Funktion, die während der Ausführung aufgerufen werden soll. Wenn Sie hier nichts angeben, lautet der Standardwertmain.runtimeOptions: ein Objekt, das die Laufzeitoptionen für die UDF-Ausführung angibt. Die folgenden Optionen sind verfügbar:max_heap_bytes: die maximale Heapgröße in Bytes. Der Standardwert ist 10.485.760 (10 MB).max_stack_bytes: die maximale Stapelgröße in Byte. Der Standardwert ist 1.048.576 (1 MB).max_execution_time_ms: die maximale Ausführungszeit in Millisekunden. Der Standardwert ist 1000 (1 Sekunde).log_exception_details: ein boolescher Wert, der angibt, ob Ausnahmedetails protokolliert werden sollen. Der Standardwert isttrue.return_exception_details: ein boolescher Wert, der angibt, ob Ausnahmedetails in der Antwort zurückgegeben werden sollen. Der Standardwert isttrue.
Eigenständige Funktionen
Eine UDF kann direkt mithilfe der POST /app/userDefinedFunctions/{functionId}:execute API ausgeführt werden.
POST /app/userDefinedFunctions/myFunction:execute
{}
Der Anforderungstext kann verwendet werden, um optionale Ausführungsparameter anzugeben, z. B. Funktionsargumente und JavaScript-Laufzeiteigenschaften.
POST /app/userDefinedFunctions/myFunction:execute
{
"arguments": ["arg1", "arg2"],
"exportedFunctionName": "myMainFunction",
"runtimeOptions": {
"max_heap_bytes": 5,
"max_stack_bytes": 1024,
"max_execution_time_ms": 5000,
"log_exception_details": true,
"return_exception_details": true
}
}
Die Antwort gibt das Ergebnis der UDF-Ausführung an (erfolgreich oder fehlgeschlagen). Wenn die UDF erfolgreich war, enthält die Antwort den zurückgegebenen Funktionswert im Zeichenfolgenformat (falls vorhanden).
{
"result":
{
"returnValue": "MyReturnValue"
},
"status": "Succeeded"
}
Wenn die UDF fehlgeschlagen ist, enthält die Antwort die Fehlermeldung mit der detaillierten Stapelüberwachung.
{
"error": {
"message": "Error while executing function myFunction: Error: MyCustomError\n at myMainFunction (myFunction)\n"
},
"status": "Failed"
}
Von Bedeutung
Die Teilnehmerrolle ist erforderlich, um eine UDF auszuführen.
Transaktionshooks
Eine UDF kann alternativ als Hook vor (Vor-Hook) oder nach (Nacht-Hook) dem Schreiben eines Eintrags in das Ledger als Teil der Ledger-Schreib-API (POST /app/transactions) ausgeführt werden. Hooks werden im gleichen Kontext wie der Schreibvorgang ausgeführt. Das bedeutet, dass alle Daten, die von den Hooks in den Ledger geschrieben werden, automatisch in dieselbe Schreibtransaktion aufgenommen werden.
Der Anforderungstext der Schreibanforderung kann verwendet werden, um alle UDF-IDs anzugeben, die als Vor- bzw. Nach-Hooks ausgeführt werden sollen.
POST /app/transactions?collectionId=myCollection
{
"contents": "myValue",
"preHooks": [
{
"functionId": "myPreHook"
}
],
"postHooks": [
{
"functionId": "myPostHook"
}
]
}
Von Bedeutung
Hooks müssen explizit im Anforderungstext des Schreibvorgangs definiert werden. Im Allgemeinen können UDFs nach der Erstellung nicht automatisch für jeden Schreibvorgang ausgeführt werden.
Für jeden Hook ist es möglich, optionale Ausführungseigenschaften anzugeben. Beispiel:
POST /app/transactions?collectionId=myCollection
{
"contents": "myValue",
"preHooks": [
{
"functionId": "myPreHook",
"properties": {
"arguments": [
"arg1",
"arg2"
],
"exportedFunctionName": "myMainFunction",
"runtimeOptions": {
"max_heap_bytes": 5,
"max_stack_bytes": 1024,
"max_execution_time_ms": 5000,
"log_exception_details": true,
"return_exception_details": true
}
}
}
],
"postHooks": [
{
"functionId": "myPostHook",
"properties": {
"arguments": [
"arg1"
],
"exportedFunctionName": "myMainFunction",
"runtimeOptions": {
"max_heap_bytes": 5,
"max_stack_bytes": 1024,
"max_execution_time_ms": 5000,
"log_exception_details": true,
"return_exception_details": true
}
}
}
]
}
Sie können bis zu 5 Vor- und Nach-Hooks in beliebiger Kombination im Anforderungstext angeben. Die Hooks werden immer in der Reihenfolge ausgeführt, in der sie im Anforderungstext bereitgestellt werden.
Wenn ein Vor- oder ein Nach-Hook fehlschlägt, wird die gesamte Transaktion abgebrochen. In diesem Fall enthält die Antwort die Fehlermeldung mit dem Grund für den Fehler:
{
"error": {
"code": "InternalError",
"message": "Error while executing function myPreHook: Error: MyCustomError\n at myMainFunction (myPreHook)\n",
}
}
Hinweis
Auch wenn mehrere Hooks erfolgreich sind, kann die Transaktion weiterhin fehlschlagen, wenn eines der definierten Prä-Hooks oder Post-Hooks nicht erfolgreich ausgeführt wird.
Tipp
Eine UDF kann in derselben Anforderung als Vor- und Nach-Hook wiederverwendet und mehrfach aufgerufen werden.
Beispiele
In diesem Abschnitt werden einige praktische Beispiele für die Verwendung von UDFs in einem vertraulichen Azure-Hauptbuch erläutert. In den folgenden Beispielszenarien wird davon ausgegangen, dass Azure Confidential Ledger zum Speichern von Banktransaktionen für verschiedene Bankkunden verwendet wird.
Kontext
Um eine Banktransaktion für einen Benutzer zu speichern, kann die vorhandene Ledger-Schreib-API verwendet werden: Der Wert der Transaktion ist der Inhalt des Ledgereintrags und die Benutzer-ID kann die Sammlung oder der Schlüssel sein, unter dem der Inhalt geschrieben wird.
POST /app/transactions?collectionId=John
{
"contents": "10"
}
HTTP/1.1 200 OK
Da es keine Überprüfung für den Eingabeinhalt gibt, ist es möglich, einen nicht numerischen Wert als Inhalt zu schreiben. Diese Anforderung ist beispielsweise erfolgreich, auch wenn der Inhaltswert keine Zahl ist:
POST /app/transactions?collectionId=Mark
{
"contents": "This is not a number"
}
HTTP/1.1 200 OK
Vor-Hooks für die Datenüberprüfung
Um sicherzustellen, dass der Transaktionsinhalt immer eine Zahl ist, kann eine UDF erstellt werden, um den Eingabeinhalt zu überprüfen. Der folgende Vor-Hook überprüft, ob der Inhalt ein Zahlenwert ist, und gibt andernfalls einen Fehler aus.
PUT /app/userDefinedFunctions/validateTransaction
{
"code": "export function main() { if (isNaN(context.contents)) { throw new Error('Contents is not a number'); } }"
}
HTTP/1.1 201 CREATED
Mithilfe des Pre-Hooks in der Schreibanforderung können Sie erzwingen, dass die Eingabedaten dem erwarteten Format entsprechen. Die vorherige Anforderung schlägt jetzt wie erwartet fehl:
POST /app/transactions?collectionId=Mark
{
"contents": "This is not a number",
"preHooks": [
{
"functionId": "validateTransaction"
}
]
}
HTTP/1.1 500 INTERNAL_SERVER_ERROR
{
"error": {
"code": "InternalError",
"message": "Error while executing function validateTransaction: Error: Contents is not a number\n at main (validateTransaction)\n"
}
}
Gültige Anforderungen, die numerische Werte enthalten, würden stattdessen wie erwartet erfolgreich sein:
POST /app/transactions?collectionId=Mark
{
"contents": "30",
"preHooks": [
{
"functionId": "validateTransaction"
}
]
}
HTTP/1.1 200 OK
Nach-Hooks für die Datenanreicherung
Wenn Benutzer neue Banktransaktionen durchführen, möchten wir aufzeichnen, wenn eine Transaktion aus Prüfungsgründen höher als ein bestimmter Schwellenwert ist. Mit einem Nach-Hook können nach einem Schreibvorgang benutzerdefinierte Metadaten in einen Ledger geschrieben werden, um anzugeben, ob die Transaktion einen bestimmten Schwellenwert überschritten hat.
Beispielsweise kann eine UDF erstellt werden, um den Transaktionswert zu überprüfen und eine Pseudonachricht („Warnung“ für hohe Werte, andernfalls „Normal“) unter der eingegebenen benutzenden Person in eine benutzerdefinierte Ledger-Tabelle (payment_metadata) zu schreiben, wenn der Wert größer als 50 ist.
PUT /app/userDefinedFunctions/detectHighTransaction
{
"code": "export function main() { let value = 'Normal'; if (context.contents > 50) { value = 'Alert' } ccf.kv['public:payment_metadata'].set(ccf.strToBuf(context.collectionId), ccf.strToBuf(value)); }"
}
HTTP/1.1 201 CREATED
Sobald die UDF erfolgreich erstellt wurde, kann der Nach-Hook in neuen Schreibanforderungen verwendet werden:
POST /app/transactions?collectionId=Mark
{
"contents": "100",
"preHooks": [
{
"functionId": "validateTransaction"
}
],
"postHooks": [
{
"functionId": "detectHighTransaction"
}
]
}
HTTP/1.1 200 OK
POST /app/transactions?collectionId=John
{
"contents": "20",
"preHooks": [
{
"functionId": "validateTransaction"
}
],
"postHooks": [
{
"functionId": "detectHighTransaction"
}
]
}
HTTP/1.1 200 OK
Eigenständige UDFs für benutzerdefinierte Abfragen
Um die aktuellen Werte zu überprüfen, die mit dem Nach-Hook in die benutzerdefinierte Tabelle payment_metadata geschrieben wurden, kann eine UDF erstellt werden, die die Werte aus der Tabelle anhand einer eingegebenen Benutzer-ID liest:
PUT /app/userDefinedFunctions/checkPaymentMetadataTable
{
"code": "export function main(user) { const value = ccf.kv['public:payment_metadata'].get(ccf.strToBuf(user)); if (value === undefined) { throw new Error('UnknownUser'); } return ccf.bufToStr(value); }"
}
HTTP/1.1 201 CREATED
Durch direktes Ausführen der UDF ist es möglich, den neuesten Wert zu überprüfen, der in der benutzerdefinierten Metadatentabelle für einen bestimmten Benutzer aufgezeichnet wurde.
Bei Benutzern mit einer letzten hohen Transaktion gibt die UDF den Wert "Alert" wie erwartet zurück.
POST /app/userDefinedFunctions/checkPaymentMetadataTable:execute
{
"arguments": [
"Mark"
]
}
HTTP/1.1 200 OK
{
"result": {
"returnValue": "Alert"
},
"status": "Succeeded"
}
Bei Benutzern mit einer letzten niedrigen Transaktion gibt die UDF stattdessen den Wert "Normal" zurück.
POST /app/userDefinedFunctions/checkPaymentMetadataTable:execute
{
"arguments": [
"John"
]
}
HTTP/1.1 200 OK
{
"result": {
"returnValue": "Normal"
},
"status": "Succeeded"
}
Für Benutzer, die keinen Eintrag in der benutzerdefinierten Tabelle haben, löst die UDF einen Fehler aus, wie im UDF-Code definiert.
POST /app/userDefinedFunctions/checkPaymentMetadataTable:execute
{
"arguments": [
"Jane"
]
}
HTTP/1.1 200 OK
{
"error": {
"message": "Error while executing function checkPaymentMetadataTable: Error: UnknownUser\n at main (checkPaymentMetadataTable)\n"
},
"status": "Failed"
}
Überlegungen
Transaktions-Hooks werden derzeit nur für die
POST /app/transactions-API unterstützt, wenn ein neuer Eintrag im Ledger hinzugefügt wird.UDFs und Hooks werden immer für das primäre Replikat des Ledgers ausgeführt, um die Transaktionsreihenfolge und starke Konsistenz sicherzustellen.
Die Ausführung von UDF-Code wird immer in eine einzelne Atomtransaktion eingeschlossen. Wenn die JavaScript-Logik in einer UDF ohne Ausnahmen abgeschlossen wird, werden alle Vorgänge in der UDF in den Ledger committet. Wenn eine Ausnahme ausgelöst wird, werden die gesamten Transaktionen zurückgesetzt. Ebenso werden Vor- und Nach-Hooks im gleichen Kontext des Schreibvorgangs ausgeführt, für den sie registriert sind. Wenn ein Vor- oder Nach-Hook fehlschlägt, wird die gesamte Transaktion abgebrochen, und dem Ledger wird kein Eintrag hinzugefügt.
UDFs können aus Sicherheitsgründen nur auf CCF-Anwendungstabellen zugreifen und nicht auf die internen Tabellen und Governancetabellen des Ledgers oder andere integrierte Tabellen. Die Ledger-Tabellen, in die Einträge geschrieben werden (
public:confidentialledger.logsfür öffentliche Ledger undprivate:confidentialledger.logsfür private Ledger), sind schreibgeschützt.Die maximale Anzahl von Vor- und Nach-Hooks, die für eine einzelne Schreibtransaktion registriert werden können, ist 5.
Die Ausführung von benutzerdefinierten Funktionen (UDF) und Hooks ist auf 5 Sekunden beschränkt. Wenn die Ausführung einer Funktion länger als 5 Sekunden dauert, wird der Vorgang abgebrochen und ein Fehler zurückgegeben.