Chaincode 事件

增強版的區塊鏈 App 產生器可以產生鏈碼事件以進行權杖作業。

Chaincode 事件是交易執行時所發出的特定通知。事件包含交易資訊,可用來通知外部系統有關區塊鏈分類帳狀態的特定條件或變更。您可以使用鏈碼事件與非區塊鏈上的應用程式進行即時整合和互動,並促進跨區塊鏈環境的事件驅動工作流程和監控。Chaincode 事件有兩個元件,事件名稱和有效負載。

所有區塊鏈 App 產生器規格檔案都支援鏈碼事件。如果您啟用鏈碼事件,除 getter 方法外,鷹架專案中的所有控制器功能都會發出事件。例如,在記號案例中,當記號被提示、傳輸、燒錄或鎖定時,將會發出鏈碼事件。

您可以使用規格檔案中的布林 events 參數來啟用鏈碼事件,如下列範例所示。

assets:
    - name: FiatMoneyTOK # Asset name
      type: token  # Asset type
      events: true  # Generate events for create, update and delete APIs

如果您啟用事件,鷹架式鏈碼專案中的控制器功能將會包含事件建立方法,如下列範例所示。

TypeScript:

@Validator(yup.string(), yup.string(), yup.string())
public async createAccount(org_id: string, user_id: string, token_type: string) {
  await this.Ctx.Auth.checkAuthorization("ACCOUNT.createAccount", "TOKEN", { org_id });
  await this.Ctx.Model.createEvent(EVENT_NAME.CREATE_ACCOUNT, { org_id, user_id, token_type });
  return await this.Ctx.Account.createAccount(org_id, user_id, token_type);
}

移至:

func (t *Controller) CreateAccount(org_id string, user_id string, token_type string, daily_limits ...account.AccountDailyLimits) (interface{}, error) {
    auth, err := t.Ctx.Auth.CheckAuthorization("Account.CreateAccount", "TOKEN", map[string]string{"org_id": org_id})
    if err != nil && !auth {
        return nil, fmt.Errorf("error in authorizing the caller  %s", err.Error())
    }
    err = t.Ctx.Model.CreateEvent(constants.CreateAccountEventName, map[string]interface{}{"org_id": org_id, "user_id": user_id, "token_type": token_type})
    if err != nil {
        return nil, err
    }
    return t.Ctx.Account.CreateAccount(org_id, user_id, token_type, daily_limits...)
}

Chaincode 事件對名稱和有效負載元件使用下列預設值。您可依需要修改預設值。

EventName
控制器功能的名稱。
有效負載
包含控制器函數之所有輸入參數的 JSON 物件。
在擴充的「記號分類標準架構」和 ERC-1155 標準中,也新增了新的 events 參數至記號詳細資訊。如果設定檔案中的 events 參數設為 true,則產生的記號中的 events 參數會設為 true。如果設定檔案中的 events 參數設為 false 或未定義,則產生的記號中的 events 參數會設為 false。下列範例顯示一個記號,其中包含 TypeScript 和 Go 的新 events 參數。
{
    "metadata": {
        "paintingName": "monalisa",
        "description": "monalisa painting",
        "image": "image link",
        "painterName": "Leonardo da Vinci"
    },
    "assetType": "otoken",
    "events": true,
    "quantity": 1,
    "tokenId": "artnft",
    "tokenName": "artcollection",
    "tokenDesc": "artcollection nft",
    "tokenStandard": "erc1155+",
    "tokenType": "nonfungible",
    "tokenUnit": "whole",
    "behaviors": [
        "indivisible",
        "singleton",
        "mintable",
        "transferable",
        "burnable",
        "roles"
    ],
    "roles": {
        "minter_role_name": "minter",
        "burner_role_name": "burner"
    },
    "mintable": {
        "max_mint_quantity": 500
    },
    "owner": "oaccount~42e89f4c72dfde9502814876423c6da630d466e87436dd1aae201d347ad1288d",
    "createdBy": "oaccount~42e89f4c72dfde9502814876423c6da630d466e87436dd1aae201d347ad1288d",
    "creationDate": "2022-12-29T04:08:35.000Z",
    "isBurned": false,
    "tokenUri": "tu",
    "price": 10000,
    "onSaleFlag": false
}
{
    "AssetType": "otoken",
    "Behavior": [
        "indivisible",
        "singleton",
        "mintable",
        "transferable",
        "burnable",
        "roles"
    ],
    "CreatedBy": "oaccount~42e89f4c72dfde9502814876423c6da630d466e87436dd1aae201d347ad1288d",
    "CreationDate": "2022-12-29T09:57:03+05:30",
    "Events": true,
    "IsBurned": false,
    "Mintable": {
        "Max_mint_quantity": 500
    },
    "OnSaleFlag": false,
    "Owner": "oaccount~42e89f4c72dfde9502814876423c6da630d466e87436dd1aae201d347ad1288d",
    "Price": 100,
    "Quantity": 1,
    "Roles": {
        "burner_role_name": "burner",
        "minter_role_name": "minter"
    },
    "TokenDesc": "token description",
    "TokenId": "monalisa",
    "TokenMetadata": {
        "Description": "Mona Lisa Painting",
        "Image": "monalisa.jpeg",
        "PainterName": "Leonardo_da_Vinci",
        "PaintingName": "Mona_Lisa"
    },
    "TokenName": "artcollection",
    "TokenStandard": "erc1155+",
    "TokenType": "nonfungible",
    "TokenUnit": "whole",
    "TokenUri": "https://bafybeid6pmpp62bongoip5iy2skosvyxh3gr7r2e35x3ctvawjco6ddmsq\\\\ .ipfs.infura-ipfs.io/?filename=MonaLisa.jpeg"
}

產生事件

stub.setEvent 方法可讓鏈碼在交易執行時建立和發出事件。下列程式碼顯示方法的 TypeScript 版本。
async setEvent(eventName: string, payload: Buffer): Promise<void>

在此範例中,eventName 是要指派給事件的名稱,而 payload 是與事件關聯的資料。有效負載可包含與事件一起傳送的任何資訊,通常會以 JSON 格式序列化。

批次方法的鏈碼事件

增強型 ERC-1155 標準支援批次方法。批次方法會在多個以參數方式傳送的記號上作業。對於批次方法,只會針對規格檔案中 events 參數設為 true 的記號發出鏈碼事件。

針對批次方法中完成的每個交易,會產生對應的鏈碼事件。每個鏈碼事件的有效負載包含交易詳細資訊。例如,如果您使用 BatchTransfer 方法來傳輸五個不同記號的數量,則會發出五個對應的鏈碼事件。每個事件的有效負載包含變數替代字明細與移轉數量,以及適用於所有批次移轉的一般參數。

下列範例顯示使用增強型 ERC-1155 標準的事件代碼。
@Validator(yup.string(), yup.string(), yup.string(), yup.string(), yup.array().of(yup.string()), yup.array().of(yup.number()))
  public async batchTransferFrom(
    fromOrgId: string,
    fromUserId: string,
    toOrgId: string,
    toUserId: string,
    tokenIds: string[],
    quantity: number[]
  ) {
    const fromAccountId = this.Ctx.ERC1155Account.generateAccountId(fromOrgId, fromUserId, ACCOUNT_TYPE.USER_ACCOUNT);
    const toAccountId = this.Ctx.ERC1155Account.generateAccountId(toOrgId, toUserId, ACCOUNT_TYPE.USER_ACCOUNT);
    let tokenAssets = [];
    for (let i = 0; i < tokenIds.length; i++) {
      const tokenAsset = await this.Ctx.ERC1155Token.get(tokenIds[i]);
      tokenAssets.push(tokenAsset);
    }
    await this.Ctx.Model.createEventForBatch(EVENT_NAME.BATCH_TRANSFER_FROM, { fromOrgId, fromUserId, toOrgId, toUserId }, quantity, tokenAssets);
    return await this.Ctx.ERC1155Token.batchTransferFrom(fromAccountId, toAccountId, tokenIds, quantity);
  }

多重資產的鏈碼事件

增強型記號分類架構和 ERC-1155 標準支援在規格檔案中定義多個記號資產。鏈碼事件行為會根據方法為記號特定 (例如建立或更新記號) 或通用 (例如採礦或燒錄) 而有所不同。

對於記號特定方法,只會針對規格檔案中 events 參數設為 true 的記號產生鏈碼事件。

對於一般方法,如果規格檔案中任何記號的 events 參數設為 true,則鏈碼事件會在鷹架專案中產生。實際的鏈碼事件行為是以傳給方法的記號 ID 參數數目為基礎。

  • 如果傳送單一記號 ID 作為參數,則只有在對應記號詳細資訊中的 events 參數設為 true 時,才會產生鏈碼事件。
  • 如果傳送多個記號 ID 作為參數,則只有在任一記號詳細資訊中的 events 參數設為 true 時,才會產生鏈碼事件。
  • 如果未傳送任何權杖 ID 作為參數,則一律會產生鏈碼事件。
下列清單顯示必須傳送兩個記號的通用方法。此清單適用於擴充的「權杖分類標準架構」標準。
  • addConversionRate(from_token_id: string, to_token_id: string, token_conversion_rate: number)
  • updateConversionRate(from_token_id: string, to_token_id: string, token_conversion_rate: number)
  • tokenConversion(from_token_id: string, to_token_id: string, to_org_id: string, to_user_id: string,token_quantity: number)
  • exchangeToken(fromTokenId: string, fromOrgId: string, fromUserId: string, fromTokenQuantity: number, toTokenId: string, toOrgId: string,toUserId: string,toTokenQuantity: number)
下列清單顯示未將記號當作引數的一般方法。下列清單適用於擴充的「記號分類架構」標準。
  • addTokenAdmin(org_id: string, user_id: string)
  • removeTokenAdmin(org_id: string, user_id: string)
  • addOrgAdmin(org_id: string, user_id: string)
  • removeOrgAdmin(org_id: string, user_id: string)
  • createAccount(org_id: string, user_id: string, token_type: string)
  • deleteHistoricalTransactions(time_to_expiration: Date)
  • initializeExchangePoolUser(org_id: string, user_id: string)
此清單顯示未將記號當作延伸 ERC-1155 標準引數的一般方法。
  • addTokenAdmin(orgId: string, userId: string)
  • removeTokenAdmin(orgId: string, userId: string)
  • createAccount(orgId: string, userId: string, ftAccount: boolean, nftAccount: boolean)
  • createUserAccount(orgId: string, userId: string)
  • createTokenAccount(orgId: string, userId: string, tokenType: TokenType)
  • addTokenSysRole(orgId: string, userId: string, role: string)
  • removeTokenSysRole(orgId: string, userId: string, role: string)
  • transferTokenSysRole(fromOrgId: string, fromUserId: string, toOrgId: string, toUserId: string, role: string)
  • deleteHistoricalTransactions(time_to_expiration: Date)

TypeScript Chaincode 事件的 SDK 方法

createEvent
此方法會根據指定的事件名稱和有效負載產生事件。
public async createEvent(eventName: any, eventPayload: any, assets?: any)
參數:
  • eventName: string – 產生事件時要使用的事件名稱。
  • eventPayload: map[string]interface{} – 產生事件時要使用的事件有效負載。
  • assets – 或者,記號資產可以當作參數傳送至方法。
createEventForBatch
此方法會產生批次作業的事件,例如 mintBatchburnBatch 方法。
public async createEventForBatch(eventName: any, eventPayload: any, quantities: number[], assets: any)
參數:
  • eventName: string – 產生事件時要使用的事件名稱。
  • eventPayload: map[string]interface{} – 產生事件時要使用的事件有效負載。
  • quantities: number[] – 相對應於每個記號 ID 的金額清單,代表批次方法交易中使用的記號數目。
  • assets – 或者,記號資產可以當作參數傳送至方法。

前往 Chaincode 事件的 SDK 方法

CreateEvent
此方法會根據指定的事件名稱和有效負載產生事件。
func (m *Model) CreateEvent(eventName string, eventPayload map[string]interface{}, assets ...interface{})
參數:
  • eventName: string – 產生事件時要使用的事件名稱。
  • eventPayload: map[string]interface{} – 產生事件時要使用的事件有效負載。
  • assets – 或者,記號資產可以當作參數傳送至方法。
CreateEventForBatch
此方法會產生批次作業的事件,例如 mintBatchburnBatch 方法。
func (m *Model) CreateEventForBatch(eventName string, eventPayload map[string]interface{}, quantities []float64, assets []interface{})
參數:
  • eventName: string – 產生事件時要使用的事件名稱。
  • eventPayload: map[string]interface{} – 產生事件時要使用的事件有效負載。
  • quantities: []float64 – 相對應於每個記號 ID 的金額清單,代表批次方法交易中使用的記號數目。
  • assets – 或者,記號資產可以當作參數傳送至方法。

區塊鏈 App 產生器鏈碼中的事件產生

如果規格檔案中的 events 參數設為 true,則會為所有控制器 API 產生鏈碼事件代碼,但指定為 getter API 的控制器 API 除外。下列範例顯示啟用 TypeScript 和 Go 鏈碼事件的控制器 API。
@Validator(yup.string(), yup.string(), yup.string())
public async createAccount(org_id: string, user_id: string, token_type: string) {
  await this.Ctx.Auth.checkAuthorization("ACCOUNT.createAccount", "TOKEN", { org_id });
  await this.Ctx.Model.createEvent(EVENT_NAME.CREATE_ACCOUNT, { org_id, user_id, token_type });
  return await this.Ctx.Account.createAccount(org_id, user_id, token_type);
}
func (t *Controller) CreateAccount(org_id string, user_id string, token_type string, daily_limits ...account.AccountDailyLimits) (interface{}, error) {
    auth, err := t.Ctx.Auth.CheckAuthorization("Account.CreateAccount", "TOKEN", map[string]string{"org_id": org_id})
    if err != nil && !auth {
        return nil, fmt.Errorf("error in authorizing the caller  %s", err.Error())
    }
    err = t.Ctx.Model.CreateEvent(constants.CreateAccountEventName, map[string]interface{}{"org_id": org_id, "user_id": user_id, "token_type": token_type})
    if err != nil {
        return nil, err
    }
    return t.Ctx.Account.CreateAccount(org_id, user_id, token_type, daily_limits...)
}
使用下列預設值產生 Chaincode 事件。您可以視需要修改這些值。
  • EventName:控制器功能的名稱。
  • Payload:包含控制器函數之所有輸入參數的 JSON 物件。