Not
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Med enkla användardefinierade funktioner (UDF:er) i azure confidential ledger kan du skapa anpassade JavaScript-funktioner som kan köras innanför transaktionsregistrets förtroendegräns. Den här funktionen är utformad för att vara enkel och enkel att använda, så att du kan utöka funktionerna i transaktionsregistrets API utan att behöva utveckla komplexa program.
Med hjälp av det inbyggda JavaScript-API:et kan du köra anpassad kod för att uppnå olika uppgifter, till exempel anpassade frågor och beräkningar, villkorliga kontroller, uppgifter efter bearbetning med mera. Den här funktionen är lämplig för scenarier där du behöver en direkt integrering med det befintliga transaktionsregister-API:et eller köra enkel anpassad logik i en konfidentiell miljö.
En snabb översikt och demonstration av UDF:er finns i följande video:
Viktigt!
Användardefinierade funktioner är för närvarande i förhandsversion under API-version 2024-12-09-preview.
Du kan begära åtkomst för den här förhandsversionen via det här registreringsformuläret.
Se kompletterande användningsvillkor för Microsoft Azure Previews för juridiska villkor som gäller för Azure-funktioner som är i betaversion, förhandsversion eller på annat sätt ännu inte har släppts i allmän tillgänglighet.
Tips/Råd
Mer avancerade scenarier, till exempel anpassad Role-Based Åtkomstkontroll (RBAC) eller integrering med externa konfidentiella arbetsbelastningar, finns i avancerade användardefinierade funktioner i Azure Confidential Ledger.
Användningsfall
Med azure confidential ledger-UDF:er kan du utöka funktionerna i transaktionsregistret genom att köra anpassad logik. Några vanliga användningsfall för UDF:er är:
Anpassade beräkningar och frågor: kör fristående UDF:er för att läsa eller skriva data i en transaktionsregisterapptabell enligt din affärslogik.
Dataverifierings- och indatakontroller: Använd UDF:er som pre-hooks för att köra förbearbetningsåtgärder innan en transaktionsregisterpost skrivs till transaktionsregistret, till exempel för att sanera indata eller söka efter förhandsvillkor.
Databerikning och smarta kontrakt: Använd UDF:er som post-hooks för att köra åtgärder efter bearbetning när en transaktionsregisterpost har skrivits, till exempel för att lägga till anpassade metadata i transaktionsregistret eller utlösa arbetsflöden efter skrivning.
Skriva UDF:er
En Azure Confidential Ledger UDF är en entitet som lagras i huvudboken med ett unikt ID och innehåller JavaScript-koden som körs när UDF:en anropas. I det här avsnittet beskrivs hur du skriver UDF-kod och använder JavaScript-API:et för att uppnå olika uppgifter.
Funktionsstruktur
Koden för en UDF kräver en exporterad funktion som är startpunkten för skriptet vid tidpunkten för körningen. En grundläggande UDF-kodmall ser ut så här:
export function main() {
// Your JavaScript code here
}
Anmärkning
Namnet på den exporterade entrypointfunktionen som anropas under körningen kan ändras med exportedFunctionName-argumentet när UDF körs. Om det inte anges är mainstandardnamnet .
Anmärkning
Lambda-funktioner stöds, men de kräver att det exporterade funktionsnamnet uttryckligen definieras och matchar namnet på funktionen entrypoint. Till exempel:
export const main = () => {
// Your JavaScript code here
};
Funktionsargument
Du kan ange valfria körningsargument som kan användas av UDF. Argumentets värden kan skickas vid körning av UDF med hjälp av parametern arguments.
Argumenten skickas alltid som en matris med strängar. Det är användarens ansvar att se till att argumenten som anges i UDF-koden matchar argumenten som skickades när UDF kördes. Användaren bör också se till att argumenten parsas korrekt till den förväntade datatypen vid exekvering.
export function main(arg1, arg2) {
// Your JavaScript code here
}
JavaScript-API
JavaScript-koden för en UDF körs i en sandbox-miljö som tillhandahåller en begränsad uppsättning API:er.
Alla globala JavaScript-standardfunktioner, objekt och värden kan användas. Ett globalt objekt med namnet ccf kan användas för att komma åt specifika funktioner och verktyg som tillhandahålls av Confidential Consortium Framework (CCF) ( till exempel kryptografihjälpfunktioner, transaktionsregistertabeller osv.). Det fullständiga API:et för det ccf globala objektet dokumenteras här.
Du kan också komma åt kontextuell information om den aktuella begäran med hjälp av det context globala objektet. Det här objektet ger åtkomst till begärandemetadata som har sitt ursprung i funktionskörningen (context.request) och användar-ID:t för funktionsanroparen (context.userId). För transaktionskrokar läggs samlings-ID:t och transaktionsinnehållet som är kopplat till skrivåtgärden också till i context objektet (context.collectionId respektive context.contents ).
Följande kodfragment visar några grundläggande exempel på användningen av JavaScript-API:et:
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");
}
Tips/Råd
Mer information om hur transaktionsregisterkartor kan användas för att lagra och hämta data finns i CCF-dokumentationen för Key-Value Store-API:et.
Anmärkning
Import av moduler stöds inte i UDF:er. JavaScript-koden måste vara fristående och kan inte förlita sig på externa bibliotek eller moduler. Webb-API:er stöds inte heller för tillfället.
Hantera UDF:er
Azures konfidentiella transaktionsregisterprogram tillhandahåller ett dedikerat CRUD-API för att skapa, läsa, uppdatera och ta bort UDF-entiteter. UDFs lagras säkert i transaktionsregistret och är endast tillgängliga för transaktionsregisterapplikationen.
Anmärkning
Enkla användardefinierade funktioner och avancerade användardefinierade funktioner är ömsesidigt uteslutande funktioner. Du kan inte skapa eller köra enkla UDF:er om avancerade UDF:er har definierats och vice versa. Om du vill växla mellan de två följer du anvisningarna på UDF-översiktssidan.
Skapa eller uppdatera en UDF
PUT /app/userDefinedFunctions/myFunction
{
"code": "export function main() { return "Hello World"; }",
}
Viktigt!
Administratörsroll krävs för att skapa eller uppdatera en UDF.
Hämta en UDF
GET /app/userDefinedFunctions/myFunction
Lista UDF:er
GET /app/userDefinedFunctions
Ta bort en UDF
DELETE /app/userDefinedFunctions/myFunction
Viktigt!
Administratörsrollen krävs för att ta bort en UDF.
Anmärkning
Om du tar bort en UDF tas bara entiteten bort från det aktuella tillståndet för transaktionsregistret. Alla borttagna UDF behålls alltid i den oföränderliga transaktionsregistrets historik (som en allokerad transaktion).
Köra UDF:er
När en Azure Confidential Ledger har skapats kan användarna köra en UDF antingen som en fristående funktion eller som en transaktionsfunktion kopplad till en skrivåtgärd. Varje UDF-körning körs i en separat körningsmiljö och sandbox-miljö, vilket innebär att UDF-körningen är isolerad från andra UDF-filer eller andra transaktionsregisteråtgärder.
UDF-körningen kan styras med valfria egenskaper som kan anges i begärandetexten. De egenskaper som stöds för närvarande är:
arguments: en matris med strängar som representerar argumenten som ska skickas till UDF. Argumenten skickas i samma ordning som de definieras i UDF-koden. Standardvärdet är en tom matris.exportedFunctionName: namnet på den exporterade funktion som ska anropas under körningen. Om det inte anges ärmainstandardvärdet .runtimeOptions: ett objekt som anger alternativ för körning av UDF. Följande alternativ är tillgängliga:max_heap_bytes: den maximala heapstorleken i byte. Standardvärdet är 10 485 760 (10 MB).max_stack_bytes: den maximala stackstorleken i byte. Standardvärdet är 1 048 576 (1 MB).max_execution_time_ms: den maximala exekveringstiden i millisekunder. Standardvärdet är 1 000 (1 sekund).log_exception_details: ett booleskt värde som anger om undantagsinformation ska loggas. Standardvärdet ärtrue.return_exception_details: ett booleskt värde som anger om undantagsinformation ska returneras i svaret. Standardvärdet ärtrue.
Fristående funktioner
En UDF kan köras direkt med hjälp av API:et POST /app/userDefinedFunctions/{functionId}:execute .
POST /app/userDefinedFunctions/myFunction:execute
{}
Begärandetexten kan användas för att ange valfria exekveringsparametrar, till exempel funktionsargument och JavaScript-körtidsegenskaper.
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
}
}
Svaret anger resultatet av UDF-körningen (lyckades eller misslyckades). Om UDF lyckades innehåller svaret det returnerade värdet från funktionen i strängformat (om något).
{
"result":
{
"returnValue": "MyReturnValue"
},
"status": "Succeeded"
}
Om UDF har misslyckats innehåller svaret felmeddelandet med stacktracens detaljer.
{
"error": {
"message": "Error while executing function myFunction: Error: MyCustomError\n at myMainFunction (myFunction)\n"
},
"status": "Failed"
}
Viktigt!
Deltagarrollen krävs för att köra en användardefinierad funktion (UDF).
Transaktionshooks
En UDF kan alternativt köras som en hook före (pre-hook) eller efter (post-hook) en post skrivs till transaktionsregistret som en del av loggskrivnings-API:t (POST /app/transactions). Krokar körs i samma kontext som skrivåtgärden. Det innebär att alla data som skrivs till transaktionsregistret av krokarna automatiskt inkluderas i samma skrivtransaktion.
Begärandetexten i skrivbegäran kan användas för att specificera vilka UDF-ID:n som ska köras som förkrokar respektive efterkrokar.
POST /app/transactions?collectionId=myCollection
{
"contents": "myValue",
"preHooks": [
{
"functionId": "myPreHook"
}
],
"postHooks": [
{
"functionId": "myPostHook"
}
]
}
Viktigt!
Krokar måste uttryckligen definieras i begärandetexten för skrivåtgärden. I allmänhet kan UDF:er inte köras automatiskt för varje skrivåtgärd när de har skapats.
För varje krok är det möjligt att ange valfria egenskaper för exekvering. Till exempel:
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
}
}
}
]
}
Du kan ange upp till 5 pre-hooks och post-hooks i begärandetexten, med valfri kombination. Krokarna körs alltid i den ordning de anges i begärandetexten.
Om en pre-hook eller post-hook misslyckas, avbryts hela transaktionen. I så fall innehåller svaret felmeddelandet med orsaken till felet:
{
"error": {
"code": "InternalError",
"message": "Error while executing function myPreHook: Error: MyCustomError\n at myMainFunction (myPreHook)\n",
}
}
Anmärkning
Även om flera krokar lyckas kan transaktionen fortfarande misslyckas om någon av de definierade pre-hooks eller post-hooks inte körs korrekt till slutförande.
Tips/Råd
En UDF kan återanvändas som både en förhook och en efterhook i samma begäran och anropas flera gånger.
Exempel
I det här avsnittet går vi igenom några praktiska exempel på hur du använder UDF:er i Azure Confidential Ledger. I följande exempelscenarier förutsätter vi att du använder azure confidential ledger för att lagra banktransaktioner för olika bankanvändare.
Kontext
För att lagra en banktransaktion för en användare kan det befintliga transaktionsregisterskrivnings-API:et användas: värdet för transaktionen är innehållet i transaktionsregistrets post och användar-ID:t kan vara samlingen eller nyckeln, där innehållet skrivs under.
POST /app/transactions?collectionId=John
{
"contents": "10"
}
HTTP/1.1 200 OK
Eftersom det inte finns någon validering av indatainnehållet går det att skriva ett icke-numeriskt värde som innehåll. Den här begäran lyckas till exempel även om innehållsvärdet inte är ett tal:
POST /app/transactions?collectionId=Mark
{
"contents": "This is not a number"
}
HTTP/1.1 200 OK
Förkrokar för dataverifiering
För att säkerställa att transaktionsinnehållet alltid är ett tal kan en UDF skapas för att kontrollera indatainnehållet. Följande pre-hook kontrollerar om innehållsvärdet är ett tal och genererar ett fel om inte.
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
Med hjälp av förkroken i skrivbegäran är det möjligt att framtvinga att indata motsvarar det förväntade formatet. Den tidigare begäran misslyckas nu som förväntat:
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"
}
}
Giltiga begäranden som innehåller numeriska värden skulle i stället lyckas som förväntat:
POST /app/transactions?collectionId=Mark
{
"contents": "30",
"preHooks": [
{
"functionId": "validateTransaction"
}
]
}
HTTP/1.1 200 OK
Post-hooks för databerikning
När användarna utför nya banktransaktioner vill vi registrera när en transaktion är högre än ett visst tröskelvärde av granskningsskäl. En post-hook kan användas för att skriva anpassade metadata i en transaktionsregister efter en skrivåtgärd för att ange om transaktionen var högre än ett visst tröskelvärde.
Du kan till exempel skapa en UDF för att kontrollera transaktionsvärdet och skriva ett dummymeddelande ("Avisering" för höga värden, annars "Normal") under användarens inmatning i en anpassad huvudbokstabell (payment_metadata) om värdet är högre än 50.
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
När UDF har skapats kan post-hook användas i nya skrivbegäranden:
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
Fristående UDF:er för anpassade frågor
Om du vill kontrollera de senaste värdena som skrivits till den anpassade tabellen payment_metadata med hjälp av post-hook kan du skapa en UDF för att läsa värdena från tabellen med ett indataanvändar-ID:
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
Genom att köra UDF direkt går det att kontrollera det senaste värdet som registrerats i tabellen med anpassade metadata för en viss användare.
För användare med en nyligen hög transaktion returnerar UDF värdet "Avisering" som förväntat.
POST /app/userDefinedFunctions/checkPaymentMetadataTable:execute
{
"arguments": [
"Mark"
]
}
HTTP/1.1 200 OK
{
"result": {
"returnValue": "Alert"
},
"status": "Succeeded"
}
För användare med en nyligen låg transaktion returnerar UDF värdet "Normal" i stället.
POST /app/userDefinedFunctions/checkPaymentMetadataTable:execute
{
"arguments": [
"John"
]
}
HTTP/1.1 200 OK
{
"result": {
"returnValue": "Normal"
},
"status": "Succeeded"
}
För användare som inte har någon post i den anpassade tabellen genererar UDF ett fel enligt definitionen i UDF-koden.
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"
}
Överväganden
Transaktionskrokar stöds för närvarande endast för API:et
POST /app/transactionsnär du lägger till en ny post i transaktionsregistret.UDF:er och hooks körs alltid på den primära kopian av huvudboken för att säkerställa ordningen av transaktioner och stark konsistens.
UDF-kodkörningen är alltid omsluten i en enda atomisk transaktion. Om JavaScript-logiken i en UDF slutförs utan några undantag, bekräftas alla åtgärder i UDF i transaktionsregistret. Om ett undantag utlöses återställs hela transaktionerna. På samma sätt körs pre-hooks och post-hooks i samma sammanhang som den skrivåtgärd de är registrerade för. Om en pre-hook eller en post-hook misslyckas avbryts hela transaktionen och ingen post läggs till i transaktionsregistret.
UDF:er kan bara komma åt CCF-programtabeller och kan inte komma åt transaktionsregistrets interna tabeller och styrningstabeller eller andra inbyggda tabeller av säkerhetsskäl. De transaktionsregistertabeller där poster skrivs till (
public:confidentialledger.logsför offentliga transaktionsregister ochprivate:confidentialledger.logsför privata transaktionsregister) är skrivskyddade.Det maximala antalet pre-hooks och post-hooks som kan registreras för en enda skrivtransaktion är 5.
UDF- och hook-exekvering är begränsade till 5 sekunder. Om det tar längre tid än 5 sekunder att köra en funktion avbryts åtgärden och ett fel returneras.