Progetto codice concatenato Go impalcato

Blockchain App Builder prende l'input dal file di specifica e genera un progetto di codice concatenato impalcato completamente funzionale. Il progetto contiene classi e funzioni generate automaticamente, metodi CRUD, metodi SDK, convalida automatica degli argomenti, marshalling/un-marshalling e capacità di persistenza trasparente (ORM).

Se il progetto codice concatenato è nella lingua Go, il progetto impalcato contiene tre file principali:
  • main.go
  • <chaincodeName>.model.go
  • <chaincodeName>.controller.go
Tutte le librerie necessarie vengono installate e inserite in pacchetti.

Il file <chaincodeName>.model.go nella sottodirectory model contiene più definizioni di asset e il file <chaincodeName>.controller.go nella sottodirectory controller contiene il comportamento dell'asset e i metodi CRUD. I vari tag e pacchetti di struttura di Go in model.go e controller.go forniscono supporto per funzioni quali la convalida automatica degli argomenti, il marshalling/unmarshalling degli argomenti, la capacità di persistenza trasparente (ORM) e la chiamata di query rich.

Il progetto impalcato può essere trovato in $GOPATH/src/example.com/<chaincodeName>

Modello

Proprietà tipo di cespite

Per impostazione predefinita, ogni struttura avrà una proprietà aggiuntiva denominata AssetType. Questa proprietà può essere utile per recuperare solo gli asset di questo tipo. Qualsiasi modifica a questa proprietà viene ignorata durante la creazione e l'aggiornamento dell'asset. Per impostazione predefinita, il valore della proprietà è <modelName>.
type Supplier struct {
AssetType string 'json:"AssetType" default:"TestGoProject.Supplier"'

SupplierId            string      'json:"SupplierId" validate:"string,mandatory" id:"true'
RawMaterialAvailable  int         'json:"RawMaterialAvailable" validate:"int,min=0"'
License               string      'json:"License" validate:"string,min=10"'
ExpiryDate            date.Date   'json:"ExpiryDate" validate:"date,before=2020-06-26"'
Active                bool	  'json:"Active" validate:"bool" default:"true"'
Metadata              interface{} 'json:"Metadata,omitempty"'
}

Validator

ID
id:"true"
Questo programma di convalida identifica la proprietà che definisce in modo univoco l'asset sottostante. Il cespite viene salvato dal valore di questa chiave. Questo programma di convalida si applica automaticamente quando un nuovo progetto Go è impalcato.
Nello screenshot riportato di seguito, "SupplierId" è la chiave per l'asset fornitore e contiene una proprietà tag id:"true" per la proprietà SupplierId.
type Supplier struct {
    Supplierld              string        'json:"Supplierld" validate:"string,mandatory" id:"true"' 
    RawMaterialAvailable    int           'json:"RawMaterialAvailable" validate:"int,min=0"'
    License                 string        'json:"License" validate:"string,min=10"'
    ExpiryDate              date.Date     'json:"ExpiryDate" validate:"date,before=2020-06-26"'
    Active                  bool          'json:"Active" validate:"bool" default :"true"'
    Metadata                interface{}   'json:"Metadata,omitempty"'   
}
Derivato
derived:"strategy,algorithm,format"
Questo decorator viene utilizzato per definire l'attributo derivato da altre proprietà. Questo decoratore ha due parametri obbligatori:
  • strategy: accetta i valori concat o hash. Richiede un parametro aggiuntivo algorithm se si seleziona hash. L'algoritmo predefinito è sha256; è supportato anche md5.
  • format: accetta un array di stringhe e valori di specifica che devono essere utilizzati dalla strategia.
type Supplier struct{
   AssetType string 'json:"AssetType" final:"chaincode1.Supplier"'
   SupplierId   string  'json:"SupplierId" validate:"string" id:"true" mandatory:"true" derived:"strategy=hash,algorith=sha256,format=IND%1%2,License,Name"'
   Name         string  'json:"Name" validate:"string,min=2,max=4"'
   License      string  'json:"License" validate:"string,min=2,max=4"'
}
Obbligatorio
validate:"mandatory"
Questa proprietà viene contrassegnata come obbligatoria e non può essere ignorata durante il salvataggio nel libro contabile. Se saltato, genera un errore. Nell'esempio seguente, "SupplierId" è associato a un tag validate:"mandatory".
Type Supplier struct {
    Supplierld              string      'json:"Supplierld" validate:"string,mandatory" id:"true"'
    RawMaterialAvailable    int         'json:"RawMaterialAvailable" validate:"int,min=0"'
    License                 string      'json:"License" validate:"string,min=10"'
    ExpiryDate              date.Date   'json:"ExpiryDate" validate:"date,before=2020-06-26"'
    Active                  bool        'json:"Active" validate:"bool" default :"true"'
    Metadata                interface{} 'json:"Metadata,omitempty"'
}
Predefinito
default:"<param>"
In questo modo, la proprietà seguente può avere un valore predefinito. Il valore predefinito nel tag predefinito viene utilizzato quando la proprietà viene saltata durante il salvataggio nel libro contabile. Nella proprietà di esempio riportata di seguito, Active ha il valore predefinito true, fornito come tag default:"true"
Type Supplier struct {
    Supplierld            string       'json:"Supplierld" validate:"string,mandatory" id:"true"'
    RawMaterialAvailable  int          'json:"RawMaterialAvailable" validate:"int,min=0"'
    License               string       'json:"License" validate:"string,min=10"'
    ExpiryDate            date.Date    'json:"ExpiryDate" validate:"date,before=2020-06-26"'
    Active                bool         'json:"Active" validate:"bool" default :"true"'
    Metadata              interface{}  'json:"Metadata,omitempty"'
}
I tipi di convalida
I tipi di accesso di base vengono convalidati per una proprietà mediante la definizione di un tag di convalida. Di seguito sono riportati i tag di convalida basati sui tipi.
  • stringa: validate: "string"
  • data: validate: "date"
  • numero: validate: "int"
  • booleano: validate: "bool"
Convalidatore minimo
validate:"min=<param>"
Utilizzando il programma di convalida minimo, è possibile impostare un valore minimo per una proprietà di tipo numero e stringa.
Per type int: nell'esempio, la proprietà RawMaterialAvailable ha un valore minimo di 0 e se un valore minore di 0 viene applicato a RawMaterialAvailable verrà restituito un errore.
Per tipo stringa: per il tipo di stringa il validator minimo controllerà la lunghezza della stringa con il valore fornito. Pertanto, nell'esempio riportato di seguito la proprietà License deve avere una lunghezza minima di 10 caratteri.
Esempio:
Type Supplier struct {
    Supplierld             string       'json:"Supplierld" validate:"string,mandatory" id:"true"'
    RawMaterialAvailable   int          'json:"RawMaterialAvailable" validate:"int,min=0"'
    License                string       'json:"License" validate:"string,min=10"'
    ExpiryDate             date.Date    'json:"ExpiryDate" validate:"date,before=2020-06-26"'
    Active                 bool         'json:"Active" validate:"bool" default :"true"'
    Metadata               interface{}  'json:"Metadata,omitempty"'
}
Convalidatore massimo
validate:"max=<param>"
Utilizzando il validator max, è possibile impostare il valore massimo per una proprietà di tipo numero e stringa.
Per type int: analogamente al validator minimo, per type int, se un valore fornito per structfield è maggiore del valore fornito nel validator, verrà restituito un errore.
Per tipo stringa: come il validatore minimo, il validatore massimo controllerà anche la lunghezza della stringa con il valore specificato. Nell'esempio la proprietà Domain ha un valore massimo di 50 caratteri, pertanto se la proprietà Domain ha una lunghezza di stringa superiore a 50 caratteri, verrà restituito un messaggio di errore.
type Retailer struct {
    Retailerld         string        'json:"Retailerld" validate:"string,mandatory" id:"true"'   
    ProductsOrdered    int           'json:"ProductsOrdered" validate:"int,mandatory"'
    ProductsAvailable  int           'json:"ProductsAvailable" validate:"int" default:"1"' 
    ProductsSold       int           'json:"ProductsSold" validate:"int"'
    Remarks            string        'json:"Remarks" validate:"string" default :"open for business"'
    Items              []int         'json:"Items" validate:"array=int,range=l-5"'
    Domain             string        'json:"Domain" validate:"url,min=30,max=50"'
    Metadata           interface{}   'json:"Metadata,omitempty"'
}
Convalidatori di data
Prima del programma di convalida:
validate:"before=<param>"
Il programma di convalida precedente convalida una proprietà di tipo date in modo che abbia un valore minore di quello specificato nel parametro.
In questo esempio, la proprietà ExpiryDate deve essere precedente a "2020-06-26" e in caso contrario restituirà un errore.
Type Supplier struct {
    Supplierld            string       'json:"Supplierld" validate:"string,mandatory" id:"true"'
    RawMaterialAvailable  int          'json:"RawMaterialAvailable" validate:"int,min=0"'
    License               string       'json:"License" validate:"string,min=10"'
    ExpiryDate            date.Date    'json:"ExpiryDate" validate:"date,before=2020-06-26"'
    Active                bool         'json:"Active" validate:"bool" default :"true"'
    Metadata              interface{}  'json:"Metadata,omitempty"'
}
Dopo il validator:
validate:"after=<param>"
Il programma di convalida precedente convalida una proprietà di tipo date in modo che abbia un valore maggiore di quello specificato nel parametro.
In questo esempio, la proprietà CompletionDate deve essere successiva a "2020-06-26" e in caso contrario restituirà un errore.
Type Supplier struct {
    Manufacturerld        string       'json:"Manufacturerld" validate:"string,mandatory" id:"true"'
    RawMaterialAvailable  int          'json:"RawMaterialAvailable" validate:"int,max=8"'
    ProductsAvailable     int          'json:"ProductsAvailable" validate:"int"'
    CompletionDate        date.Date    'json:"CompletionDate" validate:"date,after=2020-06-26"'
    Metadata              interface{}  'json:"Metadata,omitempty"'
}
Convalidatore URL
validate:"url"
Il programma di convalida URL convaliderà una proprietà per le stringhe URL.
In questo esempio, la proprietà Domain deve essere un URL valido.
type Retailer struct {
    Retailerld         string        'json:"Retailerld" validate:"string,mandatory" id:"true"'   
    ProductsOrdered    int           'json:"ProductsOrdered" validate:"int,mandatory"'
    ProductsAvailable  int           'json:"ProductsAvailable" validate:"int" default:"1"' 
    ProductsSold       int           'json:"ProductsSold" validate:"int"'
    Remarks            string        'json:"Remarks" validate:"string" default :"open for business"'
    Items              []int         'json:"Items" validate:"array=int,range=l-5"'
    Domain             string        'json:"Domain" validate:"string,url,min=30,max=50"'
    Metadata           interface{}   'json:"Metadata,omitempty"'
}
Convalidatore espressioni regolari
validate:"regexp=<param>"
Il programma di convalida Regexp convaliderà la proprietà per l'espressione regolare di input.
In questo esempio, la proprietà PhoneNumber verrà convalidata per un numero di cellulare in base all'espressione regolare.
type Customer struct {
Customerld      string       'json:"Customerld" validate:"string,mandatory" id:"true"'
Name            string       'json:"Name" validate:"string,mandatory"'
ProductsBought  int          'json:"ProductsBought" validate:"int"'
OfferApplied    int          'json:"OfferApplied" validate :"int,nax=0"'
PhoneNumber     string       'json:"PhoneNumber" validate:"string,regexp=A\(?([0-9]{3})\)?[-. ]?([0-9]{3})[-. ]?([0-9]{4})$"'
Received        bool         'json:"Received" validate:"bool"'
Metadata        interface{}  'json:"Metadata,omitempty"'
}
Convalide multiple
È possibile applicare più validator a una proprietà.
In questo esempio la proprietà Domain dispone di una convalida per una stringa, un URL e una lunghezza di stringa minima e massima.
type Retailer struct {
    Retailerld         string        'json:"Retailerld" validate:"string,mandatory" id:"true"'   
    ProductsOrdered    int           'json:"ProductsOrdered" validate:"int,mandatory"'
    ProductsAvailable  int           'json:"ProductsAvailable" validate:"int" default:"1"' 
    ProductsSold       int           'json:"ProductsSold" validate:"int"'
    Remarks            string        'json:"Remarks" validate:"string" default :"open for business"'
    Items              []int         'json:"Items" validate:"array=int,range=l-5"'
    Domain             string        'json:"Domain" validate:"string,url,min=30,max=50"'
    Metadata           interface{}   'json:"Metadata,omitempty"'
}

ORM

La funzionalità di persistenza trasparente o ORM semplificato viene acquisita nella classe Model dell'oggetto Contesto (Ctx). Se il modello richiama uno dei seguenti metodi SDK, accedervi utilizzando t.Ctx.Model.

I metodi SDK che implementano ORM sono i seguenti:
  • Save: chiama il metodo PutState di Hyperledger Fabric
  • Get: chiama il metodo GetState di Hyperledger Fabric
  • Update: chiama il metodo PutState di Hyperledger Fabric
  • Delete: chiama il metodo DeleteState di Hyperledger Fabric
  • History: chiama il metodo GetHistoryForKey di Hyperledger Fabric
  • GetByRange: chiama il metodo GetStateByRange di Hyperledger Fabric
  • GetByRangeWithPagination: chiama il metodo GetStateByRangeWithPagination di Hyperledger Fabric

Metodi SDK

Go chaincodes implementa Transparent Persistence Capability (ORM) con il pacchetto modello.

Nota

A partire dalla versione 21.2.3, il modo di accedere ai metodi ORM è cambiato. Eseguire il comando ochain --version per determinare la versione di Blockchain App Builder.

Nelle release precedenti, i metodi ORM erano esposti come metodi statici nel pacchetto del modello. I metodi sono ora definiti nel ricevente modello, che contiene lo stub della transazione. Per chiamare questi metodi, si utilizza il ricevitore modello detenuto dal contesto della transazione nel controller. Questi metodi vengono chiamati come t.Ctx.Model.<method_name> anziché model.<method_name>.

L'esempio seguente mostra le chiamate ai metodi Save e Get nelle release precedenti:

func (t *Controller) CreateSupplier(asset Supplier) (interface{}, error) {
  return model.Save(&asset)
}

func (t *Controller) GetSupplierById(id string) (Supplier, error) {
  var asset Supplier
  _, err := model.Get(id, &asset)
  return asset, err
}

L'esempio seguente mostra le chiamate ai metodi Save e Get dalla versione 21.2.3 e successive:

func (t *Controller) CreateSupplier(asset Supplier) (interface{}, error) {
  return t.Ctx.Model.Save(&asset)
}

func (t *Controller) GetSupplierById(id string) (Supplier, error) {
  var asset Supplier
  _, err := t.Ctx.Model.Get(id, &asset)
  return asset, err
}

Dopo aver eseguito l'aggiornamento alla versione 21.2.3, apportare questa modifica in tutti i progetti con codice concatenato creati con una versione precedente di Blockchain App Builder. Se si utilizza il comando sync per sincronizzare le modifiche tra il file di specifica e il codice sorgente, le modifiche vengono automaticamente trasferite al controller per i metodi pronti all'uso. È comunque necessario risolvere manualmente eventuali conflitti.

I seguenti metodi ORM sono esposti tramite il pacchetto modello:

Get
Esegue una query sul libro contabile per il cespite memorizzato in base all'ID specificato.
func Get(Id string, result ...interface{}) (interface{}, error)
Parametri:
  • Id: l'ID del cespite richiesto dal libro contabile.
  • result (interface{}): oggetto asset vuoto di un tipo particolare passato per riferimento. Questo oggetto conterrà il risultato di questo metodo. Da utilizzare solo se è richiesto un risultato specifico per tipo.
  • asset (interface): oggetto asset vuoto passato per riferimento. Questo oggetto conterrà il risultato di questo metodo. Da utilizzare solo se è richiesto un risultato specifico per tipo.
Restituisce:
  • interface {}: l'interfaccia contiene l'asset sotto forma di map[string]interface{}. Prima di operare su questa mappa, è necessario affermare l'interfaccia ottenuta con il tipo map[string]interface{}. Per convertire questa mappa in un oggetto asset, è possibile utilizzare l'API della utility util.ConvertMaptoStruct (vedere: Pacchetto utility).
  • error: contiene un errore se restituito o è nullo.
Update
Aggiorna il cespite fornito nel libro contabile con i nuovi valori.
func Update(args ...interface{}) (interface{}, error)
Parametri:
  • obj (interface): l'oggetto da aggiornare nel libro contabile viene passato per riferimento in questa API con i nuovi valori. L'asset di input viene convalidato e verificato in base ai tag di struttura menzionati nella specifica del modello e quindi memorizzato nel libro contabile.
Restituisce:
  • interface{}: l'asset salvato viene restituito come interfaccia.
  • error: contiene un errore se restituito o è nullo.
Save
Salva il cespite nel libro contabile dopo la convalida in tutti i tag di struttura.
func Save(args ...interface{}) (interface{}, error)
Parametri:
  • obj/args[0] (interface{}): l'oggetto che deve essere memorizzato nel libro contabile viene passato per riferimento in questo metodo di utility.
  • metadata/args[1] (interface{}): questo parametro è facoltativo. È stato fornito per facilitare l'utente se è necessario memorizzare i metadati nel libro contabile insieme all'asset in fase di esecuzione. Questo parametro può essere ignorato se non esiste alcun requisito di questo tipo.
Restituisce:
  • interface {}: l'asset viene restituito come interfaccia.
  • error: contiene un errore se restituito o è nullo.
Delete
Elimina il cespite dal libro contabile.
func Delete(Id string) (interface{}, error)
Parametri:
  • id (string): l'ID del cespite che deve essere eliminato dal libro contabile.
Restituisce:
  • interface {}: contiene l'asset da eliminare sotto forma di map[string]interface{}.
GetByRange
Restituisce l'elenco dei cespiti per intervallo di ID.
func GetByRange(startKey string, endKey string, asset ...interface{})
([]map[string]interface{}, error)
Parametri:
  • startkey (string): ID iniziale per l'intervallo di oggetti richiesto.
  • endkey (string): la fine dell'intervallo di oggetti richiesto.
  • asset interface: (facoltativo) array vuoto di asset, passato per riferimento. Questo array conterrà il risultato di questo metodo. Da utilizzare se è richiesto un risultato specifico per tipo.
Restituisce:
  • []map[string]interface{}: questo array contiene l'elenco dei cespiti ottenuti dal libro contabile. È possibile accedere agli oggetti che eseguono l'iterazione su questo array e asseriscono gli oggetti come map[string]interface{} e utilizzando la utility per eseguire la conversione in oggetto asset.
  • error: contiene un errore se restituito o è nullo.
GetByRangeWithPagination
Il metodo GetByRangeWithPagination è un metodo statico di classe OchainModel ereditato dalle classi Model concrete di {chaincodeName}.model.ts.
Restituisce un elenco di asset compreso tra l'intervallo startId e endId, filtrato in base alla dimensione della pagina e al segnalibro. Questo metodo chiama internamente il metodo GetStateByRangeWithPagination di Hyperledger Fabric.
Se il parametro modelName non viene fornito, il metodo restituisce Promise<Object [ ] >. Se viene fornito il parametro modelName, il metodo gestisce il casting nel tipo Model del chiamante. Nell'esempio seguente, l'array dei risultati è di tipo Supplier. Se il cespite restituito dal libro contabile non è di tipo Model, non verrà incluso nell'elenco. Questo controllo viene eseguito dalla proprietà di sola lettura assetType nella classe Model.
Per restituire tutti gli asset compresi tra l'intervallo startId e endId, filtrati in base alla dimensione della pagina e ai segnalibri, utilizzare il metodo generico del controller getAssetsByRange.
func (m *Model) GetByRangeWithPagination(startKey string, endKey string, pageSize int32, bookmark string, asset ...interface{}) ([]map[string]interface{}, error) 
Parametri:
  • startkey : string: chiave iniziale dell'intervallo. Incluso nell'intervallo.
  • endkey : string: chiave finale dell'intervallo. Escluso dall'intervallo.
  • pageSize : number: la dimensione della pagina della query.
  • Bookmark : string: il segnalibro della query. L'output inizia da questo segnalibro.
  • asset interface: (facoltativo) un array vuoto di asset passato per riferimento. Questo array conterrà il risultato di questo metodo. Utilizzare questo parametro per ottenere risultati specifici del tipo.
Restituisce:
  • []map[string]interface{}: un array che contiene l'elenco dei cespiti recuperati dal libro contabile. È possibile accedere agli oggetti iterando questo array e asserendo gli oggetti come map[string]interface{} e utilizzando una utility per la conversione in un oggetto asset.
  • error: contiene un errore se viene restituito un errore, altrimenti è nullo.
GetHistoryById
Restituisce la cronologia del cespite con l'ID specificato.
func GetHistoryByID(Id string) ([]interface{}, error)
Parametri:
  • Id (string): l'ID dell'asset per il quale è necessaria la cronologia.
Restituisce:
  • []interface{}: questa sezione contiene la cronologia del cespite ottenuto dal libro contabile sotto forma di sezione di map[string]interface{}. È possibile accedere a ciascun elemento della cronologia iterando questa sezione e asserendo gli oggetti come map[string]interface{} e utilizzando la utility per eseguire la conversione in oggetto asset.
  • error - Contiene l'errore se osservato.
Query
Il metodo di query eseguirà una query SQL/Couch DB sul libro contabile. Questo metodo è supportato solo per la distribuzione remota su Oracle Blockchain Platform. Si tratta di un metodo generico per l'esecuzione di query SQL sul libro contabile.
func Query(queryString string) ([]interface{}, error)
Parametri:
  • queryString (string): immettere la stringa di query.
Restituisce:
  • []interface{}: conterrà l'output della query. Il risultato è sotto forma di slice di interfacce. È necessario iterare la slice e utilizzare gli elementi convertendoli in tipi appropriati.
  • error - Contiene l'errore se osservato.
QueryWithPagination
Il metodo di query eseguirà una query SQL/Couch DB sul libro contabile, filtrata in base alla dimensione della pagina e al segnalibro. Questo metodo è supportato solo per la distribuzione remota su Oracle Blockchain Platform. Si tratta di un metodo generico per l'esecuzione di query SQL sul libro contabile.
func (m *Model) QueryWithPagination(queryString string, pageSize int32, bookmark string) ([]interface{}, error)
Parametri:
  • queryString (string): query Rich SQL/Couch DB.
  • pageSize : number: la dimensione della pagina della query.
  • bookmark : string: il segnalibro della query. L'output inizia da questo segnalibro.
Restituisce:
  • []interface{}: conterrà l'output della query. Il risultato è sotto forma di slice di interfacce. È necessario iterare la slice e utilizzare gli elementi convertendoli in tipi appropriati.
  • error - Contiene l'errore se osservato.
InvokeCrossChaincode
È possibile utilizzare questo metodo in un codice concatenato per chiamare una funzione in un altro codice concatenato. Entrambi i codici concatenati devono essere installati sullo stesso peer.
func InvokeCrossChaincode(chaincodeName string, method string, args []string, channelName string) (interface{}, error)
Parametri:
  • chaincodeName: il nome del codice concatenato da chiamare.
  • methodName: il nome del metodo da chiamare nel codice concatenato.
  • arg: l'argomento del metodo chiamante.
  • channelName: il canale in cui si trova il codice concatenato da chiamare.
Restituisce:
  • interface{}: restituisce un oggetto map[string]interface{} contenente tre chiavi:
    • isValid: true se la chiamata è valida.
    • payload: l'output restituito dalla chiamata cross-chaincode sotto forma di oggetto JSON.
    • message: il messaggio restituito dalla chiamata cross-chaincode in formato UTF-8.
Esempio di valore restituito:
{
      "isValid": true,
      "message": "Successfully invoked method [CreateAccount] on sub-chaincode [erc721_go_453]",
      "payload": {
                  "AccountId": "oaccount~6b83b8ab931f99442897dd04cd7a2a55f808686f49052a40334afe3753fda4c4",
                  "AssetType": "oaccount",
                  "BapAccountVersion": 0,
                  "NoOfNfts": 0,
                  "OrgId": "appdev",
                  "TokenType": "nonfungible",
                  "UserId": "user2"
      }
}
InvokeChaincode
È possibile utilizzare questo metodo in un codice concatenato per chiamare una funzione in un altro codice concatenato. Entrambi i codici concatenati devono essere installati sullo stesso peer.
func InvokeChaincode(chaincodeName string, method string, args []string, channelName string) (interface{}, error)
Parametri:
  • chaincodeName: il nome del codice concatenato da chiamare.
  • methodName: il nome del metodo da chiamare nel codice concatenato.
  • arg: l'argomento del metodo chiamante.
  • channelName: il canale in cui si trova il codice concatenato da chiamare.
Restituisce:
  • interface{}: restituisce un oggetto map[string]interface{} contenente tre chiavi:
    • isValid: true se la chiamata è valida.
    • payload: l'output restituito dalla chiamata cross-chaincode in formato UTF-8.
    • message: il messaggio restituito dalla chiamata cross-chaincode in formato UTF-8.
Esempio di valore restituito:
{
    "isValid": true,
    "message": "Successfully invoked method [CreateAccount] on sub-chaincode [erc721_go_453]",
    "payload": "{\"AssetType\":\"oaccount\",\"AccountId\":\"oaccount~c6bd7f8dcc339bf7144ea2e1cf953f8c1df2f28482b87ad7895ac29e7613a58f\",\"UserId\":\"user1\",\"OrgId\":\"appdev\",\"TokenType\":\"nonfungible\",\"NoOfNfts\":0,\"BapAccountVersion\":0}"
} 

Metodi chiave composta

GenerateCompositeKey
Questo metodo genera e restituisce la chiave composta in base al indexName e agli attributi specificati negli argomenti.
func GenerateCompositeKey(indexName string, attributes []string)
(string, error)
Parametri:
  • indexName (string): tipo di oggetto della chiave composta.
  • attrbutes ([]string): attributi dell'asset in base ai quali deve essere formata la chiave composta.
Restituisce:
  • string: contiene il risultato della chiave composta.
  • error - Contiene l'errore se osservato.
GetByCompositeKey
Questo metodo restituisce il cespite che corrisponde alla chiave e alla colonna specificate nei parametri. Il parametro index indica l'indice della chiave restituita nell'array del metodo stub SplitCompositeKey.
Internamente questo metodo chiama getStateByPartialCompositeKey, splitCompositeKey e getState di Hyperledger Fabric.
func GetByCompositeKey(key string, columns []string, index int)
(interface{}, error)
Parametri:
  • key (string): tipo di oggetto fornito durante la creazione della chiave composta.
  • column ([]string): la sezione di attributi in cui è necessario eseguire la query sul libro contabile utilizzando la chiave composta.
  • index(int): indice dell'attributo.
Restituisce:
  • Interface{}: contiene l'elenco degli asset risultanti da questo metodo.
  • error: contiene eventuali errori, se presenti.

Metodo matrice

GetNetworkStub
Questo metodo restituirà Hyperledger Fabric chaincodeStub.
È possibile accedere allo stub shim chiamando il metodo GetNetworkStub. Questo ti aiuterà a scrivere la tua implementazione lavorando direttamente con gli asset.
func GetNetworkStub() shim.ChaincodeStubInterface
Parametri:
  • nessuno
Restituisce:
  • shim.ChaincodeStubInterface: questo è lo stub del codice concatenato Hyperledger Fabric.

Altri metodi

  • GetTransactionId()
  • GetTransactionTimestamp()
  • GetChannelID()
  • GetCreator()
  • GetSignedProposal()
  • GetArgs()
  • GetStringArgs()
  • GetCreatorMspId()
  • GetId
GetTransactionId
Restituisce l'ID transazione per la richiesta di richiamo del codice concatenato corrente. L'ID transazione identifica in modo univoco la transazione nell'ambito del canale.
func GetTransactionId() string
Parametri:
  • nessuno
Restituisce:
  • string: contiene l'ID transazione richiesto.
GetTransactionTimestamp
Restituisce l'indicatore orario di creazione della transazione. Questo è tratto dalla transazione ChannelHeader, quindi indicherà l'indicatore orario del cliente e avrà lo stesso valore tra tutti gli approvatori.
func GetTransactionTimestamp() (*timestamp.Timestamp, error)
Parametri:
  • nessuno
Restituisce:
  • timestamp.Timestamp: contiene l'indicatore orario richiesto.
  • error: contiene eventuali errori, se presenti.
GetChannelID
Restituisce l'ID canale per la proposta per il codice concatenato da elaborare.
func GetChannelID() string
Parametri:
  • nessuno
Restituisce:
  • string: contiene l'ID canale richiesto come stringa.
GetCreator
Restituisce l'oggetto identità dell'autore sottomissione del richiamo del codice concatenato
func GetCreator() ([]byte, error)
Parametri:
  • nessuno
Restituisce:
  • []byte: contiene l'oggetto identità richiesto serializzato.
  • error: contiene eventuali errori, se presenti.
GetSignedProposal
Restituisce un oggetto completamente decodificato della proposta di transazione firmata.
func GetSignedProposal() (*peer.SignedProposal, error)
Parametri:
  • nessuno
Restituisce:
  • *peer.SignedProposal: contiene l'oggetto proposta firmato richiesto.
  • error: contiene eventuali errori, se presenti.
GetArgs
Restituisce gli argomenti come array di stringhe dalla richiesta di richiamo del codice concatenato.
func GetArgs() [][]byte
Parametri:
  • nessuno
Restituisce:
  • [][]byte: contiene gli argomenti passati.
GetStringArgs
Restituisce gli argomenti previsti per il codice concatenato Inizializza e Richiama come array di stringhe.
func GetStringArgs() []string
Parametri:
  • nessuno
Restituisce:
  • []string: contiene gli argomenti richiesti come array di stringhe.
GetCreatorMspId
Restituisce l'ID MSP dell'identità chiamante.
func GetCreatorMspId() string
Parametri:
  • nessuno
Restituisce:
  • string: restituisce l'ID MSP dell'identità chiamante.
GetId
Quando la chiave derivata del cespite è Id, è possibile utilizzare questo metodo per ottenere un ID derivato. Questo metodo restituirà un errore se la chiave derivata contiene %t (indicatore orario).
Parametri:
  • object: l'oggetto deve contenere tutte le proprietà da cui dipende la chiave derivata.
Restituisce:
  • Restituisce la chiave derivata come stringa.
Esempio:
func (t *Controller) CustomGetterForSupplier(License string, Name string)(interface{}, error){
   var asset Supplier
   asset.License = License
   asset.Name = Name
   id,err := t.Ctx.Model.GetId(&asset)

   if err !=nil {
      return nil, fmt.Errorf("error in getting ID %v", err.Error())
   }
   return t.GetSupplierById(id)
}

Package utility

I seguenti metodi nel pacchetto utility possono essere utili:

Util.CreateModel
Analizza la stringa JSON fornita e crea un oggetto asset del tipo specificato.
func CreateModel(obj interface{}, inputString string) error
Parametri:
  • inputString (string): la stringa JSON di input da cui deve essere creato l'oggetto.
  • obj (interface{}): il riferimento dell'oggetto da creare dalla stringa JSON. Questo oggetto memorizzerà il modello creato che viene convalidato anche in base alle tag del validator.
Restituisce:
  • error: contiene eventuali errori trovati durante la creazione o la convalida dell'asset.
util.ConvertMapToStruct
Convertire la mappa fornita in oggetto del tipo specificato.
func ConvertMapToStruct(inputMap map[string](interface{}), resultStruct
interface{}) error
Parametri:
  • inputMap (map[string](interface{})): mappa da convertire nell'oggetto asset.
  • resultStruct (interface{}): il riferimento dell'oggetto asset richiesto che deve essere generato dalla mappa. Contiene l'oggetto asset risultato richiesto.
Restituisce:
  • error: contiene eventuali errori trovati durante la creazione o la convalida dell'asset.

Per i metodi SDK di token, vedere gli argomenti nella sezione Supporto alla generazione di token mediante Blockchain App Builder.

Controllore

Il file Controller.go implementa i metodi CRUD e personalizzati per gli asset.

È possibile creare un numero qualsiasi di classi, funzioni o file, ma solo i metodi definiti nella struttura del codice concatenato possono essere richiamati dall'esterno, il resto è nascosto.

Metodi generati automaticamente

Come descritto in File di specifica input, è possibile specificare i metodi CRUD che si desidera generare nel file di specifica. Ad esempio, se si è scelto di generare tutti i metodi, il risultato sarà simile al seguente:

//	
//Supplier
//	
func (t *ChainCode) CreateSupplier(inputString string) (interface{}, error) {
    var obj Supplier
    err := util.CreateModel(&obj, inputString)
    if err != nil {
        return nil, err   
    }
    return model.Save(&obj)
}

func (t *ChainCode) GetSupplierById(id string) (interface{}, error) {
    asset, err := model.Get(id) 
    return asset, err
}

func (t *ChainCode) UpdateSupplier(inputString string) (interface{}, error) {
    var obj Supplier
    err := util.CreateModel(&obj, inputstring)
    if err != nil {   
        return nil, err
    }
return model.Update(&obj)
}

func (t *ChainCode) DeleteSupplier(id string) (interface{}, error) { 
    return model.Delete(id)
}

func (t *ChainCode) GetSupplierHistoryById(id string) (interface{}, error) { 
    historyArray, err := model.GetHistoryByld(id) 
    return historyArray, err
}

func (t *ChainCode) GetSupplierByRange(startkey string, endKey string) (interface{}, error) { 
    assetArray, err := model.GetByRange(startkey, endKey) 
    return assetArray, err
}

Metodi personalizzati

I seguenti metodi personalizzati sono stati generati dal file delle specifiche di esempio.

executeQuery mostra in che modo è possibile chiamare le query rich SQL. I programmi di convalida rispetto agli argomenti vengono aggiunti automaticamente da Blockchain App Builder in base al tipo di argomento specificato nel file di specifica.

È possibile implementare la funzionalità in base alla business logic. Se si aggiungono metodi personalizzati, aggiungerli al file del controller. Se si aggiungono metodi personalizzati alla libreria anziché al file del controller, le modifiche andranno perse quando il contenuto della cartella della libreria viene aggiornato durante i processi di sincronizzazione o aggiornamento del codice concatenato.

//	
//Custom Methods
//			
/*
*	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.
*/
func (t *ChainCode) ExecuteQuery(inputQuery string) (interface{}, error) { 
    resultArray, err := model.Query(inputQuery) 
    return resultArray, err
}

func (t *ChainCode) FetchRawMaterial(supplierId string, rawMaterialSupply int) (interface{}, error) {
    return nil, nil
}

func (t *ChainCode) GetRawMaterialFromSupplier(manufacturerId string, supplierId string, rawMaterialSupply int) (interface{} error) { 
    return nil, nil
}

Func (t *ChainCode) CreateProducts(manufacturerId string, rawMaterialConsumed int, productsCreated int) (interface{}, error) { 
    return nil, nil
}

func (t *ChainCode) SendProductsToDistribution() (interface{}, error) { 
    return nil, nil
}
Per i codici concatenati Go, ogni metodo personalizzato deve restituire due valori: interfaccia vuota, errore. Ad esempio:
func (t *Controller) FetchRawMaterial(supplierId string, rawMaterialSupply int) (interface{}, error) { 
    return nil, nil
}

Metodo Init

Nel controller viene fornito un metodo Init personalizzato con una definizione vuota. Se si utilizza Blockchain App Builder per la distribuzione o l'aggiornamento, il metodo Init viene chiamato automaticamente. Se si esegue la distribuzione o l'aggiornamento dalla console di Oracle Blockchain Platform sulla piattaforma Hyperledger Fabric v1.4.7, viene chiamato automaticamente anche il metodo Init. Se si esegue la distribuzione o l'aggiornamento dalla console di Oracle Blockchain Platform sulla piattaforma Hyperledger Fabric v2.x, è necessario chiamare manualmente il metodo Init. È possibile utilizzare uno strumento di terze parti, ad esempio Postman, per chiamare manualmente il metodo Init.

type Controller struct {
}
func (t *Controller) Init(args string) (interface{}, error) 
    { return nil, nil
}

Se si desidera inizializzare uno stato dell'applicazione in questo momento, è possibile utilizzare questo metodo per eseguire questa operazione.