ブロックチェーン・アプリケーション・ビルダーは、仕様ファイルから入力を受け取り、完全に機能するスキャフォールド済チェーンコード・プロジェクトを生成します。
チェーンコード・プロジェクトでTypeScript言語を使用する場合、スキャフォールド済プロジェクトには次の3つのメイン・ファイルが含まれます:
main.ts
<chaincodeName>.model.ts
<chaincodeName>.controller.ts
必要なライブラリがすべてインストールされ、パッケージ化されます。
tsconfig.jsonファイルには、TypeScriptプロジェクトのコンパイルおよびビルドに必要な構成が含まれています。
<chaincodeName>.model.tsには複数のアセット定義が含まれ、<chaincodeName>.controller.tsにはアセットの動作とCRUDメソッドが含まれます。
model.tsおよびcontroller.tsの各種デコレータは、引数の自動検証、引数の整列化/非整列化、透過的永続性機能(ORM)およびリッチ問合せのコールなどの機能をサポートしています。
アセット
デフォルトでは、
OchainModelを拡張するすべてのクラスには、
assetTypeという追加の読取り専用プロパティがあります。このプロパティは、このタイプのアセットのフェッチにのみ使用できます。このプロパティへの変更は、アセットの作成および更新時に無視されます。デフォルトのプロパティ値は
<chaincodeName>.<assetName>です。
@Id('supplierId')
export class Supplier extends OchainModel<Supplier> {
public readonly assetType = 'tsdeml36.supplier';
@Mandatory()
@Validate(yup.string())
public supplierId: string;
デコレータ
-
クラス・デコレータ
@Id(identifier)
- このデコレータは、基礎となるアセットを一意に定義するプロパティを識別します。このプロパティは、チェーンコードの状態でこのアセットを表すレコードのキーとして使用されます。このデコレータは、新しいTypeScriptプロジェクトがスキャフォールドされると自動的に適用されます。デコレータの'identifier'引数は、仕様ファイルから値を取得します。
@Id('supplierId')
export class Supplier extends OchainModel{
...
}
-
プロパティ・デコレータ
- 複数のプロパティ・デコレータを使用できます。デコレータは上から下の順に解決されます。
@Mandatory()
- これにより、次のプロパティが必須としてマークされるため、台帳への保存中にスキップできません。スキップすると、エラーがスローされます。
@Mandatory()
public supplierID: string;
@Default(param)
- このプロパティにはデフォルト値を指定できます。台帳への保存中にプロパティがスキップされると、引数(
param)のデフォルト値が使用されます。@Default('open for business')
@Validate(yup.string())
public remarks: string;
@Validate(param)
- 次のプロパティは、パラメータに指定されたスキーマに対して検証されます。引数
paramはyupスキーマを使用し、多数のスキーマ・メソッドを連鎖させることができます。多数の複雑な検証を追加できます。詳細は、https://www.npmjs.com/package/yupを参照してください。@Validate(yup.number().min(3))
public productsShipped: number;
@Embedded(PropertyClass)
- このプロパティ・デコレータは、基礎となるプロパティを埋込み可能アセットとしてマークします。埋込み可能クラスをパラメータとして使用します。このクラスは、
EmbeddedModelクラスを拡張する必要があります。これはデコレータによって検証されます。
- この例では、
Employeeには、Employeeアセットに埋め込まれるAddressタイプのaddressというプロパティがあります。これは、@Embedded()デコレータによって示されます。
export class Employee extends OchainModel<Employee> {
public readonly assetType = 'TsSample.employee';
@Mandatory()
@Validate(yup.string())
public emplyeeID: string;
@Mandatory()
@Validate(yup.string().max(30))
public firstName: string;
@Mandatory()
@Validate(yup.string().max(30))
public lastName: string;
@Validate(yup.number().positive().min(18))
public age: number;
@Embedded(Address)
public address: Address;
}
export class Address extends EmbeddedModel<Address> {
@Validate(yup.string())
public street: string;
@Validate(yup.string())
public city: string;
@Validate(yup.string())
public state: string;
@Validate(yup.string())
public country: string;
}
Addressクラスの新しいインスタンスが作成されると、Addressクラスのすべてのプロパティが@Validate()デコレータによって自動的に検証されます。Addressクラスには、assetTypeプロパティまたは@Id()クラス・デコレータがありません。このアセットとそのプロパティは、台帳に個別に保存されませんが、Employeeアセットとともに保存されます。埋込みアセットは、値タイプとして機能するユーザー定義クラスです。このクラスのインスタンスは、含まれているオブジェクト(OchainModelアセット)の一部としてのみ台帳に格納できます。前述のデコレータはすべて、プロジェクトのスキャフォールド時に入力ファイルに基づいて自動的に適用されます。
@Derived(STRATEGY, ALGORITHM, FORMAT)
- このデコレータは、他のプロパティから導出された属性を定義するために使用します。このデコレータには、次の2つの必須パラメータがあります:
STRATEGY: CONCATまたはHASHの値を使用します。HASHが選択されている場合は、追加のパラメータALGORITHMが必要です。デフォルトのアルゴリズムはsha256で、md5もサポートされています。
FORMAT: 戦略で使用される仕様文字列と値の配列を使用します。
@Id('supplierID')
export class Supplier extends OchainModel<Supplier> {
public readonly assetType = 'chaincodeTS.supplier';
@Mandatory()
@Derived(STRATEGY.HASH.'sha256',['IND%1IND%2','license','name'])
@Validate(yup.string())
public supplierID: string;
@Validate(yup.string().min(2).max(4))
public license: string;
@Validate(yup.string().min(2).max(4))
public name: string;
-
メソッド・デコレータ
@Validator(…params)
- このデコレータは、メイン・コントローラ・クラスのメソッドに適用されます。このデコレータは、引数を解析し、すべてのプロパティ・デコレータに対して検証し、モデル/タイプ・オブジェクトを返す際に重要です。複数のユーザーで作成されたモデルまたはyupスキーマをパラメータとして使用します。
- パラメータの順序は、メソッド内の引数の順序とまったく同じである必要があります。
- この例では、メソッド引数の
assetタイプに対応するパラメータでSupplierモデル参照が渡されます。ランタイムのデコレータは、メソッド引数を解析してJSONオブジェクトに変換し、Supplierバリデータに対して検証し、検証が成功したら、JSONオブジェクトをSupplierオブジェクトに変換してasset変数に割り当てます。完了すると、基礎となるメソッドが最後にコールされます。@Validator(Supplier)
public async createSupplier(asset: Supplier) {
return await asset.save();
}
- この例では、複数のアセット参照が渡されます。これらはメソッド引数のオブジェクト型に対応しています。パラメータの順序に注意してください。
@Validator(Supplier, Manufacturer)
public async createProducts(supplier: Supplier, manufacturer: Manufacturer) {
}
- 引数が基本的な型の場合は、アセット参照とは別に、yupスキーマ・オブジェクトも渡すことができます。この例では、
supplierIdおよびrawMaterialSupplyはそれぞれstringおよびnumber型であるため、同様の型および正しい順序のyupスキーマがデコレータに渡されます。yupスキーマ・メソッドの連鎖に注意してください。@Validator(yup.string(), yup.number().positive())
public async fetchRawMaterial(supplierID:string, rawMaterialSupply: number) {
const supplier = await Supplier.get(supplierID);
supplier.rawMaterialAvailable = supplier.rawMaterialAvailable + rawMaterialSupply;
return await supplier.update();
}
モデル
すべてのモデル・クラスはOchainModelを拡張します。透過的永続性機能または簡略化されたORMは、OchainModelクラスで取得されます。モデルで次のORMメソッドのいずれかをコールする必要がある場合は、OchainModelクラスを拡張する必要があります。
OchainModelを介して公開されるORMメソッド:
save - これはHyperledger FabricのputStateメソッドをコールします
get – これはHyperledger FabricのgetState メソッドをコールします
update - これはHyperledger FabricのputStateメソッドをコールします
delete – これはHyperledger FabricのdeleteState メソッドをコールします
history – これはHyperledger FabricのgetHistoryForKeyメソッドをコールします
getByRange – これはHyperledger FabricのgetStateByRange メソッドをコールします
関連項目:
モデル・メソッド
コントローラ
メイン・コントローラ・クラスは、OchainControllerを拡張します。メインコントローラは1つのみです。
export class TSProjectController extends OchainController{
任意の数のクラス、関数またはファイルを作成できますが、メイン・コントローラ・クラス内で定義されているメソッドのみが外部から呼出し可能で、残りのメソッドは非表示になります。
CRUDメソッド
「入力仕様ファイル」で説明されているように、生成するCRUDメソッドを仕様ファイルで指定できます。たとえば、すべてのメソッドの生成を選択した場合、結果は次のようになります:
@Validator(Supplier)
public asynch createSupplier(asset: Supplier){
return await asset.save();
}
public asynch getSupplierById(id: string){
const asset = await Supplier.get(id);
return asset;
}
@Validator(Supplier)
public asynch updateSupplier(asset: Supplier){
return await asset.update();
}
public asynch deleteSupplier(id: string){
const result = await Supplier.delete(id);
return result;
}
public asynch getSupplierHistoryById(id: string){
const result = await Supplier.history(id);
return result;
}
@Validator(yup.string(), yup.string())
public asynch getSupplierByRange(startId: string, endId: string){
const result = await Supplier.getByRange(startId, endId);
return result;
}
モデル・メソッド
-
save
saveメソッドは、コール元のasset詳細を台帳に追加します。
- このメソッドは、Hyperledger Fabricの
putStateを内部的にコールします。整列化/非整列化はすべて内部的に処理されます。
<Asset>.save(extraMetadata?: any): Promise<any>
- パラメータ:
extraMetadata : any (オプション) – アセットとは別にメタデータを台帳に保存します。
- 戻り値:
Promise<any> - 完了時にpromiseを返します
- 例:
@Validator(Supplier)
public async createSupplier(asset: Supplier) {
return await asset.save();
}
-
get
getメソッドは、{chaincodeName}.model.tsの具象モデル・クラスによって継承されるOchainModelクラスの静的メソッドです。
- これは、
idが台帳で見つかり、<Asset>と同じタイプである場合に、<Asset>のアセットを返します。このメソッドは、Hyperledger FabricのgetStateメソッドを内部的にコールします。指定されたidを持つアセットが台帳から返されても、このメソッドはコール元のModelタイプにキャストします。
- 指定された
idによってアセットを返す場合は、汎用コントローラ・メソッドgetAssetByIdを使用します。
<Asset>.get(id: string): Promise<asset>
- パラメータ:
id : string - 台帳にデータを保存するために使用されるキー。
- 戻り値:
Promise: <Asset> - <Asset>タイプのオブジェクトを返します。指定されたidを持つアセットが台帳から返されても、このメソッドはコール元のAssetタイプにキャストします。台帳から返されたアセットがAssetタイプでない場合は、エラーがスローされます。このチェックは、Modelクラスの読取り専用のassetTypeプロパティによって行われます。
- 例:
public async getSupplierById: string) {
const asset = await Supplier.get(id);
return asset;
}
この例では、assetはSupplierタイプです。
-
update
updateメソッドは、台帳のコール元assetの詳細を更新します。このメソッドは、promiseを返します。
- このメソッドは、Hyperledger Fabricの
putStateを内部的にコールします。整列化/非整列化はすべて内部的に処理されます。
<Asset>.update(extraMetadata?: any): Promise<any>
- パラメータ:
extraMetadata : any (オプション) – アセットとは別にメタデータを台帳に保存します。
- 戻り値:
Promise<any> - 完了時にpromiseを返します
- 例:
@Validator(Supplier)
public async updateSupplier(asset: Supplier) {
return await asset.update();
}
-
delete
- これにより、
idで指定された台帳からアセットが削除されます(存在する場合)。このメソッドは、Hyperledger FabricのdeleteStateメソッドを内部的にコールします。
deleteメソッドは、{chaincodeName}.model.tsの具象Modelクラスによって継承されるOchainModelクラスの静的メソッドです。
<Asset>. delete(id: string): Promise<any>
- パラメータ:
id : string - 台帳にデータを保存するために使用されるキー。
- 戻り値:
Promise <any> - 完了時にpromiseを返します。
- 例:
public async deleteSupplier(id: string) {
const result = await Supplier.delete(id);
return result;
}
-
history
- 履歴メソッドは、
{chaincodeName}.model.tsの具象Modelクラスによって継承されるOchainModelクラスの静的メソッドです。これは、台帳からidによって指定されたアセット履歴を返します(存在する場合)。
- このメソッドは、Hyperledger Fabricの
getHistoryForKeyメソッドを内部的にコールします。
<Asset>.history(id: string): Promise<any[]>
- パラメータ:
id : string - 台帳にデータを保存するために使用されるキー。
- 戻り値:
Promise <any[]> - 完了時に任意の[]を返します。
- 例
public async getSupplierHistoryById(id: string) {
const result = await Supplier.history(id);
return result;
}
getSupplierHistoryByIdに対して返されるアセット履歴の例:[
{
"trxId": "8ef4eae6389e9d592a475c47d7d9fe6253618ca3ae0bcf77b5de57be6d6c3829",
"timeStamp": 1602568005,
"isDelete": false,
"value": {
"assetType": "supp.supplier",
"supplierId": "s01",
"rawMaterialAvailable": 10,
"license": "abcdabcdabcd",
"expiryDate": "2020-05-28T18:30:00.000Z",
"active": true
}
},
{
"trxId": "92c772ce41ab75aec2c05d17d7ca9238ce85c33795308296eabfd41ad34e1499",
"timeStamp": 1602568147,
"isDelete": false,
"value": {
"assetType": "supp.supplier",
"supplierId": "s01",
"rawMaterialAvailable": 15,
"license": "valid license",
"expiryDate": "2020-05-28T18:30:00.000Z",
"active": true
}
}
]
-
getByRange
getByRangeメソッドは、{chaincodeName}.model.tsの具象Modelクラスによって継承されるOchainModelクラスの静的メソッドです。
- これは、
startIdからendIdの範囲のアセットのリストを返します。このメソッドは、Hyperledger FabricのgetStateByRangeメソッドを内部的にコールします。
- 指定された
idを持つアセットが台帳から返されても、このメソッドはコール元のModelタイプにキャストします。前述の例では、result配列はSupplier型です。台帳から返されたアセットがModelタイプでない場合、リストには含まれません。このチェックは、Modelクラスの読取り専用のassetTypeプロパティによって行われます。
startIdからendIdの範囲のすべてのアセットを返す場合は、汎用コントローラ・メソッドgetAssetsByRangeを使用します。
<Asset>.getByRange(startId: string, endId: string): Promise<Asset[]>
- パラメータ:
startId : string – 範囲の開始キー。範囲に含まれます。
endId : string – 範囲の終了キー。範囲から除外されます。
- 戻り値:
Promise< Asset[ ] > - 完了時に<Asset>の配列を返します。
- 例:
@Validator(yup.string(), yup.string())
public async getSupplierByRange(startId: string, endId: string){
const result = await Supplier.getByRange(startId, endId);
return result;
}
-
getId
- アセットに
Idとして導出キーがある場合、このメソッドを使用して導出IDを取得できます。導出キーに%t (タイムスタンプ)が含まれている場合、このメソッドはエラーを返します。
- パラメータ:
object – オブジェクトには、導出キーが依存するすべてのプロパティが含まれている必要があります。
- 戻り値:
- 例:
@Validator(yup.string(), yup.string())
public async customGetterForSupplier(license: string, name: string){
let object = {
license : license,
name: name
}
const id = await Supplier.getID(object);
return Supplier.get(id);
}
コントローラ・メソッドの詳細
前述のモデルのCRUDメソッドおよびCRUD以外のメソッドとは別に、ブロックチェーン・アプリケーション・ビルダーでは、コントローラの他のHyperledger Fabricメソッドに即時対応可能なサポートを提供しています。これらのメソッドを次に示します:
getAssetById
getAssetsByRange
getAssetHistoryById
query
generateCompositeKey
getByCompositeKey
getTransactionId
getTransactionTimestamp
getTransactionInvoker
getChannelID
getCreator
getSignedProposal
getArgs
getStringArgs
getMspID
getNetworkStub
これらのメソッドは、
Controllerクラスの
thisコンテキスト自体で使用できます。例:
public async getModelById(id: string) {
const asset = await this.getAssetById(id);
return asset;
}
@Validator(yup.string(), yup.string())
public async getModelsByRange(startId: string, endId: string) {
const asset = await this.getAssetsByRange(startId, endId);
return asset;
}
public async getModelHistoryById(id: string) {
const result = await this.getAssetHistoryById(id);
return result;
}
-
getAssetById
getAssetByIdメソッドは、指定されたidに基づいてアセットを返します。これは汎用メソッドで、任意のタイプのアセットを取得するために使用されます。
this< OchainController>.getAssetById(id: string): Promise<byte[]>
- パラメータ:
id : string - 台帳にデータを保存するために使用されるキー。
- 戻り値:
Promise <byte [ ]> - 完了時にpromiseを返します。byte[]をオブジェクトに変換する必要があります。
-
getAssetsByRange
getAssetsByRangeメソッドは、アセット・タイプに関係なく、startId (これを含む)からendId (これを含まない)までのすべてのアセットを返します。これは汎用メソッドであり、任意のタイプのアセットを取得するために使用できます。
this<OchainController>.getAssetsByRange(startId: string, endId: string):
Promise<shim.Iterators.StateQueryIterator>
- パラメータ:
startId : string – 範囲の開始キー。範囲に含まれます。
endId : string – 範囲の終了キー。範囲から除外されます。
- 戻り値:
Promise< shim.Iterators.StateQueryIterator> - 完了時にイテレータを返します。これに対して反復する必要があります。
-
getAssetHistoryById
getAssetHistoryByIdメソッドは、指定されたidのアセットの履歴イテレータを返します。
this<OchainController>.getAssetHistoryById(id: string):
Promise<shim.Iterators.HistoryQueryIterator>
- パラメータ:
id : string - 台帳にデータを保存するために使用されるキー。
- 戻り値:
Promise<shim.Iterators.HistoryQueryIterator> - 履歴問合せイテレータを返します。これに対して反復する必要があります。
-
query
queryメソッドは、台帳に対してリッチSQL/Couch DB問合せを実行します。このメソッドは、Oracle Blockchain Platformでのリモート・デプロイメントでのみサポートされます。これは、台帳でSQL問合せを実行するための一般的な方法です。
this<OchainController>.query(queryStr: string):
Promise<shim.Iterators.StateQueryIterator>
- パラメータ:
queryStr : string - リッチSQL/Couch DB問合せ。
- 戻り値:
Promise<shim.Iterators.StateQueryIterator> - 状態問合せイテレータを返します。これに対して反復する必要があります。
-
generateCompositeKey
- このメソッドは、
indexNameおよび引数で指定された属性に基づいてコンポジット・キーを生成し、返します。
this<OchainController>.generateCompositeKey(indexName: string, attributes:
string[]): string
- パラメータ:
indexName : string - 台帳へのデータの保存に使用されるキーのオブジェクト・タイプ。
attributes: string[ ] - 作成されるコンポジット・キーに基づく属性。
- 戻り値:
-
getByCompositeKey
- このメソッドは、コンポジット・キーの作成中に属性パラメータに指定されたキーおよび列に一致するアセットを返します。
indexOfIdパラメータは、スタブ・メソッドSplitCompositeKeyの配列で返されるキーの索引を指定します。内部的には、このメソッドはHyperledger FabricのgetStateByPartialCompositeKey、splitCompositeKeyおよびgetStateをコールします。
this<OchainController>.getByCompositeKey(key: string, columns: string[],
indexOfId: number): Promise<any []>
- パラメータ:
key: string – データを台帳に保存するために使用されるキー。
columns: string[ ] - キーに基づく属性が生成されます。
indexOfId: number - キーから取得される属性の索引。
- 戻り値:
Promise< any [ ] - 完了時に任意の[]を返します。
-
getTransactionId
- 現在のチェーンコード呼出しリクエストのトランザクションIDを返します。トランザクションIDは、チャネルのスコープ内でトランザクションを一意に識別します。
this<OchainController>.getTransactionId(): string
- パラメータ:
- 戻り値:
string - 現在のチェーンコード呼出しリクエストのトランザクションIDを返します。
-
getTransactionTimestamp
- トランザクションが作成されたときのタイムスタンプを返します。これはトランザクション
ChannelHeaderから取得されるため、クライアントのタイムスタンプを示し、すべてのエンドーサで同じ値になります。
this<OchainController>.getTransactionTimestamp(): Timestamp
- パラメータ:
id : string - 台帳にデータを保存するために使用されるキー。
- 戻り値:
Timestamp - トランザクションが作成されたときのタイムスタンプを返します。
-
getTransactionInvoker
- 一時マップ・プロパティ
bcsRestClientIdからトランザクションのコール元を返します。
this<OchainController>.getTransactionInvoker(): string
- パラメータ:
- 戻り値:
string - トランザクションのコール元を返します。
-
getChannelID
- チェーンコードが処理する提案のチャネルIDを返します。
this<OchainController>.getChannelID(): string
- パラメータ:
- 戻り値:
-
getCreator
- チェーンコード呼出しの発行者のアイデンティティ・オブジェクトを返します。
this<OchainController>.getCreator(): shim.SerializedIdentity
- パラメータ:
- 戻り値:
shim.SerializedIdentity - アイデンティティ・オブジェクトを返します。
-
getSignedProposal
- 署名済トランザクション提案の完全にデコードされたオブジェクトを返します。
this<OchainController>.getSignedProposal():
shim.ChaincodeProposal.SignedProposal
- パラメータ:
- 戻り値:
shim.ChaincodeProposal.SignedProposal - 署名済トランザクション提案のデコードされたオブジェクトを返します。
-
getArgs
- チェーンコード呼出しリクエストから引数を文字列の配列として返します。
this<OchainController>.getArgs(): string[]
- パラメータ:
- 戻り値:
string [ ] - チェーンコード呼出しから文字列の配列として引数を返します。
-
getStringArgs
- チェーンコード呼出しリクエストから引数を文字列の配列として返します。
this<OchainController>.getStringArgs(): string[]
- パラメータ:
- 戻り値:
string [ ] - チェーンコード呼出しから文字列の配列として引数を返します。
-
getMspID
- 呼出し側アイデンティティのMSP IDを返します。
this<OchainController>.getMspID(): string
- パラメータ:
- 戻り値:
string - 呼出し側アイデンティティのMSP IDを返します。
-
getNetworkStub
- ユーザーは、
getNetworkStubメソッドをコールすることでshimスタブにアクセスできます。これは、ユーザーがアセットを直接操作する独自の実装を記述するのに役立ちます。
this<OchainController>.getNetworkStub(): shim.ChaincodeStub
- パラメータ:
- 戻り値:
shim.ChaincodeStub - チェーンコード・ネットワーク・スタブを返します。
カスタム・メソッド
このサンプル仕様ファイルから、次のカスタム・メソッドが生成されました。
executeQueryは、SQLリッチ問合せのコール方法を示しています。引数に対するバリデータは、仕様ファイルで指定された引数のタイプに基づいてブロックチェーン・アプリケーション・ビルダーによって自動的に追加されます。
/**
*
* BDB sql rich queries can be executed in OBP CS/EE.
* This method can be invoked only when connected to remote OBP CS/EE network.
*
*/
@Validator(yup.string()}
public async executeQuery(query: string) {
const result = await OchainController.query(query);
return result;
}
@Validator(yup.string(), yup.number()}
public async fetchRawMaterial(supplierId: string, rawMaterialSupply: number) {
}
@Validator(yup.string(), yup.string(), yup.number())
public async getRawMaterialFromSupplier(manufacturerId: string, supplierId: string, rawMaterialSupply: number) {
}
@Validator(yup.string(), yup.number(), yup.number())
public async createProducts(manufacturerId: string, rawMaterialConsumed: number, productsCreated: number) {
}
public async sendProductsToDistribution() {
}
初期化メソッド
コントローラには、空の定義を持つinitメソッドが用意されています。このメソッドは、チェーンコードを初めてインスタンス化またはアップグレードするときにHyperledger FabricのInitメソッドによってコールされます。
export class TestTsProjectController extends OchainController {
public async init(params: any) {
return;
}
この時点でアプリケーションの状態を初期化する場合は、このメソッドを使用して初期化できます。