Progetto codice concatenato go impalcato

Blockchain App Builder prende l'input dal file delle specifiche 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 con codice concatenato utilizza la 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 un package.

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 avanzate.

Il progetto impalcato si trova nella directory $GOPATH/src/example.com/<chaincodeName>.

Modello

Proprietà tipo di asset

Per impostazione predefinita, ogni struttura dispone di una proprietà aggiuntiva denominata AssetType. È possibile utilizzare questa proprietà per recuperare solo gli asset di questo tipo. Eventuali modifiche a questa proprietà vengono ignorate quando gli asset vengono creati o aggiornati. Il valore predefinito 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 in questa chiave. Questo validator viene applicato automaticamente quando un nuovo progetto Go viene impalcato.
Nell'esempio seguente, SupplierId è la chiave per l'asset fornitore e ha 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 decoratore viene utilizzato per definire l'attributo derivato da altre proprietà. Questo decoratore ha due parametri obbligatori:
  • strategy: accetta i valori concat o hash. Se si specifica hash, il parametro aggiuntivo algorithm è obbligatorio. L'algoritmo predefinito è sha256; è supportato anche md5.
  • format: consente di utilizzare un array di stringhe e valori di specifica per la 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"
Questo decoratore contrassegna la proprietà seguente come obbligatoria, in modo che non possa essere saltata durante il salvataggio nel libro contabile. Se saltato, viene restituito un errore. Nell'esempio seguente, la proprietà SupplierId dispone di 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>"
Questo decorator indica che la proprietà seguente ha un valore predefinito. Il valore nel tag predefinito viene utilizzato quando la proprietà viene saltata durante il salvataggio nel libro contabile. Nell'esempio seguente, Active ha il valore predefinito true, specificato 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"'
}
Tipi di convalida
I tipi di accesso di base vengono convalidati per una proprietà mediante la definizione di una tag di convalida. Le tag di convalida riportate di seguito si basano sui tipi di base.
  • stringa: validate: "string"
  • data: validate: "date"
  • numero: validate: "int"
  • booleano: validate: "bool"
Convalidatore minimo
validate:"min=<param>"
È possibile utilizzare il programma di convalida min per impostare il valore minimo per una proprietà di tipo numero o stringa.
Per type int: nell'esempio seguente, la proprietà RawMaterialAvailable ha un valore minimo di 0. Se alla proprietà RawMaterialAvailable viene applicato un valore inferiore a 0, verrà restituito un errore.
Per la stringa di tipo: il validatore minimo controlla la lunghezza della stringa rispetto al valore specificato. Nell'esempio seguente, la proprietà License deve avere una lunghezza minima di dieci caratteri.
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"'
}
Numero massimo di validator
validate:"max=<param>"
È possibile utilizzare il programma di convalida massimo per impostare il valore massimo per una proprietà di tipo numero e stringa.
Per int. tipo: simile al validatore min, se un valore specificato per un campo struttt è maggiore del valore fornito nel validator, viene restituito un errore.
Per la stringa di tipo: simile al validatore min, il validatore max controlla la lunghezza della stringa rispetto al valore specificato. Nell'esempio seguente, la proprietà Domain ha un valore massimo di 50, quindi 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"'
}
Convalida della data
Prima del validatore:
validate:"before=<param>"
Il programma di convalida precedente convalida una proprietà di tipo date con un valore inferiore al parametro specificato.
Nell'esempio seguente, la proprietà ExpiryDate deve essere precedente a "2020-06-26" e, in caso contrario, viene restituito 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 validatore:
validate:"after=<param>"
Il programma di convalida successivo convalida una proprietà di tipo date per avere un valore maggiore del parametro specificato.
Nell'esempio seguente, 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"'
}
Convalida URL
validate:"url"
Il programma di convalida URL convalida una proprietà per le stringhe URL.
Nell'esempio seguente, 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 Regexp
validate:"regexp=<param>"
Il programma di convalida regexp convalida una proprietà con l'espressione regolare specificata.
Nell'esempio riportato di seguito, 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"'
}
Più convalidatori
È possibile applicare più programmi di convalida a una struttura.
Nell'esempio seguente, la proprietà Domain dispone della 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 chiama uno qualsiasi dei seguenti metodi SDK, accedervi utilizzando t.Ctx.Model.

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

Metodi SDK

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

Nota

A partire dalla versione 21.2.3, la modalità di accesso ai metodi ORM è cambiata. 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 package del modello. I metodi sono ora definiti sul ricevente modello, che contiene lo stub della transazione. Per chiamare questi metodi, si utilizza il ricevitore modello tenuto dal contesto della transazione nel controller. Questi metodi vengono chiamati 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 l'aggiornamento alla versione 21.2.3, apportare questa modifica in tutti i progetti di 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 apportate al controller per i metodi pronti all'uso. È comunque necessario risolvere manualmente eventuali conflitti.

Il package di modelli espone i seguenti metodi ORM:

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 da recuperare dal libro contabile.
  • result (interface{}): oggetto asset vuoto di un tipo specifico passato per riferimento. Questo oggetto conterrà il risultato di questo metodo. Utilizzare questo parametro solo se è richiesto un risultato specifico del tipo.
  • asset (interface): un oggetto asset vuoto passato per riferimento. Questo oggetto conterrà il risultato di questo metodo. Utilizzare questo parametro solo se è richiesto un risultato specifico del tipo.
Restituisce:
  • interface {} - L'interfaccia contiene l'asset in formato map[string]interface{}. Prima di operare su questa mappa, è necessario affermare l'interfaccia restituita con il tipo map[string]interface{}. Per convertire questa mappa in un oggetto asset, è possibile utilizzare la utility API util.ConvertMaptoStruct (vedere: Utility Package).
  • error: contiene un errore se restituito o è nullo.
Update
Aggiorna il cespite specificato nel libro contabile con nuovi valori.
func Update(args ...interface{}) (interface{}, error)
Parametri:
  • obj (interface) - L'oggetto da aggiornare nel libro contabile viene passato per riferimento a questa API insieme ai nuovi valori. L'asset di input viene convalidato e verificato in base ai tag di struttura 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 l'asset nel libro contabile dopo la convalida su tutti i tag di struttura.
func Save(args ...interface{}) (interface{}, error)
Parametri:
  • obj/args[0] (interface{}) - L'oggetto da memorizzare nel libro contabile viene passato per riferimento in questo metodo di utility.
  • metadata/args[1] (interface{}) - (Facoltativo) È possibile utilizzare questo parametro per memorizzare i metadati nel libro contabile insieme all'asset in fase di runtime.
Restituisce:
  • interface {}: l'asset viene restituito come interfaccia.
  • error: contiene un errore se restituito o è nullo.
Delete
Elimina l'asset dal libro contabile.
func Delete(Id string) (interface{}, error)
Parametri:
  • id (string): l'ID del cespite da eliminare dal libro contabile.
Restituisce:
  • interface {} - Contiene l'asset da eliminare nel modulo map[string]interface{}.
GetByRange
Restituisce un elenco di asset specificato da un intervallo di ID.
func GetByRange(startKey string, endKey string, asset ...interface{})
([]map[string]interface{}, error)
Parametri:
  • startkey (string) - ID iniziale dell'intervallo di oggetti da recuperare.
  • endkey (string) - ID finale per l'intervallo di oggetti da recuperare.
  • asset interface - (Facoltativo) Array vuoto di asset passato per riferimento. Questo array conterrà il risultato del metodo. Utilizzare questo parametro se è richiesto un risultato specifico del tipo.
Restituisce:
  • []map[string]interface{} - Questo array contiene l'elenco degli asset ottenuti dal libro contabile. È possibile accedere agli oggetti iterando su questo array e affermando gli oggetti come map[string]interface{} e utilizzando una utility per la conversione in un oggetto asset.
  • error: contiene un errore se restituito o è nullo.
GetByRangeWithPagination
Il metodo GetByRangeWithPagination è un metodo statico della classe OchainModel ereditato dalle classi Model concrete di {chaincodeName}.model.ts.
Questo metodo restituisce un elenco di asset compresi tra l'intervallo startId e endId, filtrati in base alla dimensione della pagina e al segnalibro. Questo metodo chiama internamente il metodo Hyperledger Fabric GetStateByRangeWithPagination.
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à assetType di sola lettura nella classe Model.
Per restituire tutti gli asset compresi tra l'intervallo startId e endId, filtrati in base alle dimensioni della pagina e ai segnalibri, utilizzare il metodo controller generico 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, inclusa nell'intervallo.
  • endkey : string: chiave finale dell'intervallo, esclusa 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) array di asset vuoto, passato per riferimento. Questo array conterrà il risultato di questo metodo. Utilizzare questo parametro per ottenere risultati specifici del tipo.
Restituisce:
  • []map[string]interface{}: array che contiene l'elenco di asset recuperati dal libro contabile. È possibile accedere agli oggetti iterando su questo array e affermando 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) - ID dell'asset.
Restituisce:
  • []interface{} - Questa sezione contiene la cronologia dell'asset ottenuto dal libro contabile sotto forma di sezione di map[string]interface{}. È possibile accedere a ogni elemento della cronologia iterando su questa sezione e affermando gli oggetti come map[string]interface{} e utilizzando una utility per la conversione in oggetto asset.
  • error - Contiene l'errore se viene restituito un errore.
Query
Questo metodo esegue una query DB SQL/Couch sul libro contabile. Questo metodo è supportato solo per le distribuzioni remote su Oracle Blockchain Platform. Metodo generico per l'esecuzione di query SQL nel libro contabile.
func Query(queryString string) ([]interface{}, error)
Parametri:
  • queryString (string): la stringa di query.
Restituisce:
  • []interface{}: l'output della query sotto forma di una slice di interfacce. Iterare sulla slice e utilizzare gli elementi convertendoli nei tipi appropriati.
  • error - Contiene l'errore se viene restituito un errore.
QueryWithPagination
Questo metodo esegue una query SQL/Couch DB sul libro contabile, filtrata in base alla dimensione della pagina e al segnalibro. Questo metodo è supportato solo per le distribuzioni remote su Oracle Blockchain Platform. Metodo generico per l'esecuzione di query SQL nel 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{}: l'output della query sotto forma di una slice di interfacce. Iterare sulla slice e utilizzare gli elementi convertendoli nei tipi appropriati.
  • error - Contiene l'errore se viene restituito un errore.
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{} che contiene tre chiavi:
    • isValid - true se la chiamata è valida.
    • payload: l'output restituito dalla chiamata cross-chaincode come 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{} che contiene 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 composita

GenerateCompositeKey
Questo metodo genera e restituisce la chiave composta in base al valore 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 verrà formata la chiave composta.
Restituisce:
  • string: il risultato della chiave composta.
  • error - Contiene l'errore se viene restituito un errore.
GetByCompositeKey
Questo metodo restituisce l'asset che corrisponde alla chiave e alla colonna specificate. Il parametro index indica l'indice della chiave restituita nell'array del metodo stub SplitCompositeKey.
Internamente questo metodo chiama i metodi 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 porzione di attributi su cui verrà eseguita una query sul libro contabile utilizzando la chiave composta.
  • index(int) - Indice dell'attributo.
Restituisce:
  • Interface{}: la lista degli asset corrispondenti.
  • error - Contiene l'errore se viene restituito un errore.

Metodo stub

GetNetworkStub
Questo metodo restituisce il valore chaincodeStub di Hyperledger Fabric.
È possibile accedere allo stub shim chiamando il metodo GetNetworkStub. Ciò può aiutarti a scrivere la tua implementazione che funziona direttamente con gli asset.
func GetNetworkStub() shim.ChaincodeStubInterface
Parametri:
  • nessuno
Restituisce:
  • shim.ChaincodeStubInterface - Lo stub del codice concatenato Hyperledger Fabric.

Altri metodi

  • GetTransactionId()
  • GetTransactionTimestamp()
  • GetChannelID()
  • GetCreator()
  • GetSignedProposal()
  • GetArgs()
  • GetStringArgs()
  • GetCreatorMspId()
  • GetId
GetTransactionId
Questo metodo 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 - ID transazione.
GetTransactionTimestamp
Restituisce l'indicatore orario durante la creazione della transazione. Poiché il valore deriva dalla transazione ChannelHeader, indica l'indicatore orario del cliente e ha lo stesso valore in tutti gli approvatori.
func GetTransactionTimestamp() (*timestamp.Timestamp, error)
Parametri:
  • nessuno
Restituisce:
  • timestamp.Timestamp: l'indicatore orario.
  • error - Contiene l'errore se viene restituito un errore.
GetChannelID
Restituisce l'ID canale per la proposta per il codice concatenato da elaborare.
func GetChannelID() string
Parametri:
  • nessuno
Restituisce:
  • string: l'ID canale richiesto in formato stringa.
GetCreator
Restituisce l'oggetto di identità dell'autore sottomissione del richiamo del codice concatenato.
func GetCreator() ([]byte, error)
Parametri:
  • nessuno
Restituisce:
  • []byte: l'oggetto identità richiesto in formato serializzato.
  • error - Contiene l'errore se viene restituito un errore.
GetSignedProposal
Restituisce un oggetto completamente decodificato della proposta di transazione firmata.
func GetSignedProposal() (*peer.SignedProposal, error)
Parametri:
  • nessuno
Restituisce:
  • *peer.SignedProposal - L'oggetto della proposta firmato.
  • error - Contiene l'errore se viene restituito un errore.
GetArgs
Restituisce gli argomenti come array di stringhe della richiesta di richiamo del codice concatenato.
func GetArgs() [][]byte
Parametri:
  • nessuno
Restituisce:
  • [][]byte: gli argomenti passati.
GetStringArgs
Restituisce gli argomenti destinati ai metodi Init e Invoke del codice concatenato come array di stringhe.
func GetStringArgs() []string
Parametri:
  • nessuno
Restituisce:
  • []string: gli argomenti come array di stringhe.
GetCreatorMspId
Restituisce l'ID MSP dell'identità di richiamo.
func GetCreatorMspId() string
Parametri:
  • nessuno
Restituisce:
  • string: l'ID MSP dell'identità di richiamo.
GetId
Quando il cespite ha una chiave derivata come Id, è possibile utilizzare questo metodo per ottenere un ID derivato. Questo metodo restituisce 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)
}

Pacchetto utility

Nel pacchetto di utility sono disponibili i metodi riportati di seguito.

Util.CreateModel
Analizza la stringa JSON specificata e crea un oggetto asset del tipo specificato.
func CreateModel(obj interface{}, inputString string) error
Parametri:
  • inputString (string): la stringa JSON di input da utilizzare per creare 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 ai tag validator.
Restituisce:
  • error: contiene l'errore se viene restituito un errore durante la creazione o la convalida dell'asset.
util.ConvertMapToStruct
Converte la mappa specificata in un oggetto del tipo specificato.
func ConvertMapToStruct(inputMap map[string](interface{}), resultStruct
interface{}) error
Parametri:
  • inputMap (map[string](interface{})): la mappa da convertire in un oggetto asset.
  • resultStruct (interface{}): il riferimento dell'oggetto asset da creare dalla mappa.
Restituisce:
  • error: contiene l'errore se viene restituito un errore durante la creazione o la convalida dell'asset.

Per i metodi SDK del token, vedere gli argomenti in Supporto della tokenizzazione mediante Blockchain App Builder.

Controller

Il file Controller.go implementa il CRUD e i metodi 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 sono nascosti.

Metodi generati automaticamente

Come descritto in File di specifica di input, è possibile specificare i metodi CRUD da generare nel file di specifica. Ad esempio, se si sceglie di generare tutti i metodi, il risultato sarà simile al codice 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 di specifica di esempio.

La funzione executeQuery mostra come è possibile chiamare le query RTF SQL. I validator rispetto agli argomenti vengono aggiunti automaticamente da Blockchain App Builder in base al tipo di argomento specificato nel file di specifica.

È possibile implementare le funzionalità in base alla logica aziendale necessaria. 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: empty interface e error, come mostrato nell'esempio riportato di seguito.
func (t *Controller) FetchRawMaterial(supplierId string, rawMaterialSupply int) (interface{}, error) { 
    return nil, nil
}

Metodo inizializzazione

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 richiamato automaticamente. Se si esegue la distribuzione o l'upgrade dalla console di Oracle Blockchain Platform, è necessario chiamare il metodo Init manualmente. È possibile utilizzare uno strumento di terze parti come Postman per chiamare manualmente il metodo Init.

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

È quindi possibile utilizzare questo metodo per inizializzare qualsiasi stato dell'applicazione.