Blockchain App Builder toma la entrada de su archivo de especificación y genera un proyecto de código de cadenas de andamios totalmente funcional. El proyecto contiene clases y funciones generadas automáticamente, métodos CRUD, métodos SDK, validación automática de argumentos, canalización/anulación de canalización y capacidad de persistencia transparente (ORM).
Si el proyecto de código de cadenas está en el idioma Go, el proyecto de andamio contiene tres archivos principales:
main.go
<chaincodeName>.model.go
<chaincodeName>.controller.go
Todas las bibliotecas necesarias están instaladas y empaquetadas.
El archivo <chaincodeName>.model.go
del subdirectorio model
contiene varias definiciones de activos y el archivo <chaincodeName>.controller.go
del subdirectorio controller
contiene el comportamiento del activo y los métodos CRUD. Las distintas etiquetas y paquetes de estructura Go de model.go
y controller.go
proporcionan soporte para funciones como la validación automática de argumentos, la canalización/anulación de canalización de argumentos, la capacidad de persistencia transparente (ORM) y la llamada a consultas enriquecidas.
El proyecto de andamios se puede encontrar en $GOPATH/src/example.com/<chaincodeName>
Modelo
Propiedad de tipo de activo
Por defecto, cada estructura tendrá una propiedad adicional denominada
AssetType
. Esta propiedad puede ser útil para recuperar solo activos de este tipo. Los cambios realizados en esta propiedad se ignoran durante la creación y actualización del activo. El valor de la propiedad por defecto es
<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"'
}
Validación
-
ID
id:"true"
- Este validador identifica la propiedad que define de forma única el activo subyacente. El valor de esta clave guarda el activo. Este validador se aplica automáticamente cuando un nuevo proyecto Go está en andamio.
- En la siguiente captura de pantalla,
"SupplierId"
es la clave del activo de proveedor y tiene una propiedad de etiqueta id:"true"
para la propiedad 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"'
}
-
Derivado
derived:"strategy,algorithm,format"
- Este decorador se utiliza para definir el atributo derivado de otras propiedades. Este decorador tiene dos parámetros obligatorios:
strategy
: toma valores de concat
o hash
. Necesita un parámetro adicional algorithm
si se selecciona hash
. El algoritmo por defecto es sha256
; también se admite md5
.
format
: toma una matriz de cadenas y valores de especificación que utilizará la estrategia.
-
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"'
}
-
Obligatorio
validate:"mandatory"
- Esto marca la siguiente propiedad como obligatoria y no se puede omitir al guardar en el libro mayor. Si se omite, devuelve un error. En el siguiente ejemplo,
"SupplierId"
tiene una etiqueta 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"'
}
-
Valor por Defecto
default:"<param>"
- Esto indica que la siguiente propiedad puede tener un valor predeterminado. El valor por defecto de la etiqueta por defecto se utiliza cuando se omite la propiedad al guardar en el libro mayor. En la propiedad de ejemplo siguiente,
Active
tiene un valor por defecto true
, proporcionado como etiqueta 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"'
}
-
Validación de Tipos
- Los tipos de Go básicos se validan para una propiedad mediante la definición de una etiqueta de validación. Estas son las etiquetas de validación basadas en tipos:
- cadena:
validate: "string"
- fecha:
validate: "date"
- número:
validate: "int"
- booleano:
validate: "bool"
-
Validador mínimo
validate:"min=<param>"
- Mediante el validador mínimo, se puede definir un valor mínimo para una propiedad de tipo número y cadena.
- Para el tipo int: en el ejemplo, la propiedad
RawMaterialAvailable
tiene un valor mínimo de 0 y si se aplica un valor inferior a 0 a RawMaterialAvailable
, se devolverá un error.
- Para el tipo cadena: para el tipo cadena, el validador mínimo comprobará la longitud de la cadena con el valor proporcionado. Por lo tanto, en el siguiente ejemplo, la propiedad
License
debe tener un mínimo de 10 caracteres.
- Por ejemplo:
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"'
}
-
Validador máximo
validate:"max=<param>"
- Con el validador máximo, se puede definir el valor máximo para una propiedad de tipo número y cadena.
- Para el tipo int: como el validador mínimo, para el tipo int, si un valor proporcionado para
structfield
es mayor que el valor proporcionado en el validador, se devolverá un error.
- Para la cadena de tipo: al igual que el validador mínimo, el validador máximo también comprobará la longitud de la cadena con el valor especificado. En el ejemplo, la propiedad
Domain
tiene un valor máximo de 50, por lo que si la propiedad Domain
tiene una longitud de cadena superior a 50 caracteres, se devolverá un mensaje de error.
-
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"'
}
-
Validadores de fecha
- Antes del validador:
validate:"before=<param>"
- El validador anterior valida una propiedad de tipo
date
para que tenga un valor menor que el especificado en el parámetro.
- En este ejemplo, la propiedad
ExpiryDate
debe ser anterior a "2020-06-26"
y, si no es así, devolverá un error.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"'
}
- Después del validador:
validate:"after=<param>"
- El validador anterior valida una propiedad de tipo
date
para que tenga un valor mayor que el especificado en el parámetro.
- En este ejemplo, la propiedad
CompletionDate
debe ser posterior a "2020-06-26"
y, si no es así, devolverá un error.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"'
}
-
Validador de URL
validate:"url"
- El validador de URL validará una propiedad para cadenas de URL.
- En este ejemplo, la propiedad
Domain
debe ser una URL válida.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"'
}
-
Validador de expresión regular
validate:"regexp=<param>"
- El validador de expresión regular validará la propiedad para la expresión regular de entrada.
- En este ejemplo, la propiedad
PhoneNumber
se validará para un número de móvil según la expresión regular.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"'
}
-
Varios validadores
- Se pueden aplicar varios validadores a una propiedad.
- En este ejemplo, la propiedad
Domain
tiene validación para una cadena, una URL y una longitud de cadena mínima y máxima.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 capacidad de persistencia transparente u ORM simplificado se captura en la clase Model
del objeto de contexto (Ctx
). Si el modelo llama a cualquiera de los siguientes métodos de SDK, acceda a ellos mediante t.Ctx.Model
.
Los métodos de SDK que implantan ORM son los siguientes:
Save
: llama al método PutState
de Hyperledger Fabric
Get
: llama al método GetState
de Hyperledger Fabric
Update
: llama al método PutState
de Hyperledger Fabric
Delete
: llama al método DeleteState
de Hyperledger Fabric
History
: llama al método GetHistoryForKey
de Hyperledger Fabric
GetByRange
: llama al método GetStateByRange
de Hyperledger Fabric
GetByRangeWithPagination
: llama al método GetStateByRangeWithPagination
de Hyperledger Fabric
Métodos de SDK
Los códigos de cadena de Go implantan la capacidad de persistencia transparente (ORM) con el paquete de modelos.
Note:
A partir de la versión 21.2.3, la forma de acceder a los métodos ORM ha cambiado. Ejecute el comando
ochain --version
para determinar la versión de Blockchain App Builder.
En versiones anteriores, los métodos ORM se exponían como métodos estáticos en el paquete de modelos. Los métodos ahora se definen en el receptor modelo, que contiene el stub de transacción. Para llamar a estos métodos, utilice el receptor de modelo que tiene el contexto de transacción en el controlador. Estos métodos se llaman t.Ctx.Model.<method_name>
en lugar de model.<method_name>
.
En el siguiente ejemplo se muestran las llamadas al método Save
y Get
en versiones anteriores:
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
}
En el siguiente ejemplo se muestran las llamadas al método Save
y Get
de la versión 21.2.3 y posteriores:
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
}
Después de actualizar a la versión 21.2.3, realice este cambio en todos los proyectos de código de cadenas que haya creado con una versión anterior de Blockchain App Builder. Si utiliza el comando sync
para sincronizar los cambios entre el archivo de especificación y el código fuente, los cambios se llevan automáticamente al controlador para los métodos listos para usar. Aún debe resolver manualmente cualquier conflicto.
Los siguientes métodos ORM se exponen mediante el paquete de modelos:
-
Get
- Consulta la contabilidad del activo almacenado en función del ID especificado.
-
func Get(Id string, result ...interface{}) (interface{}, error)
- Parámetros:
Id
: ID del activo que se necesita del libro mayor.
result (interface{})
: objeto de activo vacío de un tipo concreto, que se transfiere como referencia. Este objeto contendrá el resultado de este método. Solo se utilizará si se requiere un resultado específico del tipo.
asset (interface)
: objeto de activo vacío, que se transfiere como referencia. Este objeto contendrá el resultado de este método. Solo se utilizará si se requiere un resultado específico del tipo.
- Devuelve:
interface {}
: la interfaz contiene el activo con el formato map[string]interface{}
. Antes de operar en este mapa, es necesario hacer valer la interfaz obtenida con el tipo map[string]interface{}
. Para convertir esta asignación en un objeto de activo, puede utilizar la API de la utilidad util.ConvertMaptoStruct
(consulte: Paquete de utilidad).
error
: contiene un error si se devuelve o es nulo.
-
Update
- Actualiza el activo proporcionado en el libro mayor con los nuevos valores.
-
func Update(args ...interface{}) (interface{}, error)
- Parámetros:
obj (interface)
: el objeto que se debe actualizar en el libro mayor se transfiere como referencia a esta API con los nuevos valores. El activo de entrada se valida y verifica de acuerdo con las etiquetas de estructura mencionadas en la especificación del modelo y, a continuación, se almacena en el libro mayor.
- Devuelve:
interface{}
: el activo guardado se devuelve como interfaz.
error
: contiene un error si se devuelve o es nulo.
-
Save
- Guarda el activo en el libro mayor después de validarlo en todas las etiquetas de estructura.
-
func Save(args ...interface{}) (interface{}, error)
- Parámetros:
obj/args[0] (interface{})
: el objeto que se debe almacenar en el libro mayor se transfiere por referencia en este método de utilidad.
metadata/args[1] (interface{})
: este parámetro es opcional. Se ha proporcionado para facilitarle si necesita almacenar metadatos en el libro mayor junto con el activo en tiempo de ejecución. Este parámetro se puede omitir si no existe tal requisito.
- Devuelve:
interface {}
: el activo se devuelve como interfaz.
error
: contiene un error si se devuelve o es nulo.
-
Delete
- Elimina el activo de la contabilidad.
-
func Delete(Id string) (interface{}, error)
- Parámetros:
id (string)
: ID del activo que se debe suprimir del libro mayor.
- Devuelve:
interface {}
: contiene el activo que se está suprimiendo con el formato map[string]interface{}
.
-
GetByRange
- Devuelve la lista de activos por rango de ID.
-
func GetByRange(startKey string, endKey string, asset ...interface{})
([]map[string]interface{}, error)
- Parámetros:
startkey (string)
: ID inicial para el rango de objetos que son necesarios.
endkey (string)
: fin del rango de objetos necesarios.
asset interface
: (opcional) matriz vacía de activos, que se transfiere por referencia. Esta matriz contendrá el resultado de este método. Se utilizará si se requiere un resultado específico del tipo.
- Devuelve:
[]map[string]interface{}
: esta matriz contiene la lista de activos obtenidos del libro mayor. Puede acceder a los objetos que iteran en esta matriz y afirmar los objetos como map[string]interface{}
y utilizar la utilidad para convertirlos en objeto de activo.
error
: contiene un error si se devuelve o es nulo.
-
GetByRangeWithPagination
- El método
GetByRangeWithPagination
es un método estático de la clase OchainModel
que heredan las clases Model
concretas de {chaincodeName}.model.ts
.
- Devuelve una lista de activos entre el rango
startId
y endId
, filtrados por tamaño de página y marcador. Este método llama al método GetStateByRangeWithPagination
de Hyperledger Fabric internamente.
- Si no se proporciona el parámetro
modelName
, el método devuelve Promise<Object [ ] >
. Si se proporciona el parámetro modelName
, el método maneja la conversión en el tipo Model
del emisor de llamada. En el siguiente ejemplo, la matriz de resultados es del tipo Supplier
. Si el activo devuelto del libro mayor no es del tipo Model
, no se incluirá en la lista. Esta comprobación se realiza mediante la propiedad assetType
de solo lectura en la clase Model
.
- Para devolver todos los activos entre el rango
startId
y endId
, filtrados por tamaño de página y marcadores, utilice el método de controlador genérico getAssetsByRange
.
-
func (m *Model) GetByRangeWithPagination(startKey string, endKey string, pageSize int32, bookmark string, asset ...interface{}) ([]map[string]interface{}, error)
- Parámetros:
startkey : string
: clave de inicio del rango. Incluido en el rango.
endkey : string
: clave de finalización del rango. Excluido del rango.
pageSize : number
: tamaño de página de la consulta.
Bookmark : string
: marcador de la consulta. La salida comienza con este marcador.
asset interface
: (opcional) matriz vacía de activos, transferida como referencia. Esta matriz contendrá el resultado de este método. Utilice este parámetro para obtener resultados específicos del tipo.
- Devuelve:
[]map[string]interface{}
: matriz que contiene la lista de activos recuperados del libro mayor. Puede acceder a los objetos iterando en esta matriz y afirmando los objetos como map[string]interface{}
y utilizando una utilidad para la conversión en un objeto de activo.
error
: contiene un error si se devuelve un error; de lo contrario, es nulo.
-
GetHistoryById
- Devuelve el historial del activo con el ID proporcionado.
-
func GetHistoryByID(Id string) ([]interface{}, error)
- Parámetros:
Id (string)
: ID del activo para el que se necesita el historial.
- Devuelve:
[]interface{}
: esta división contiene el historial del activo obtenido del libro mayor en forma de división map[string]interface{}
. Puede acceder a cada elemento del historial iterando en este segmento y afirmando los objetos como map[string]interface{}
y utilizando la utilidad para convertirlos en objeto de activo.
error
: contiene el error si se observa.
-
Query
- El método de consulta ejecutará una consulta SQL/Couch DB en el libro mayor. Este método solo está soportado para el despliegue remoto en Oracle Blockchain Platform. Se trata de un método genérico para ejecutar consultas SQL en el libro mayor.
-
func Query(queryString string) ([]interface{}, error)
- Parámetros:
queryString (string)
: introduzca la cadena de consulta.
- Devuelve:
[]interface{}
: contendrá la salida de la consulta. El resultado es en forma de segmento de interfaces. Debe iterar sobre la división y utilizar los elementos convirtiéndolos en tipos adecuados.
error
: contiene el error si se observa.
-
QueryWithPagination
- El método de consulta ejecutará una consulta SQL/Couch DB en el libro mayor, filtrada por tamaño de página y marcador. Este método solo está soportado para el despliegue remoto en Oracle Blockchain Platform. Se trata de un método genérico para ejecutar consultas SQL en el libro mayor.
-
func (m *Model) QueryWithPagination(queryString string, pageSize int32, bookmark string) ([]interface{}, error)
- Parámetros:
queryString (string)
: consulta SQL/Couch DB enriquecida.
pageSize : number
: tamaño de página de la consulta.
bookmark : string
: marcador de la consulta. La salida comienza con este marcador.
- Devuelve:
[]interface{}
: contendrá la salida de la consulta. El resultado es en forma de segmento de interfaces. Debe iterar sobre la división y utilizar los elementos convirtiéndolos en tipos adecuados.
error
: contiene el error si se observa.
-
InvokeCrossChaincode
- Puede utilizar este método en un código de cadenas para llamar a una función en otro código de cadenas. Ambos códigos de cadenas deben estar instalados en el mismo par.
-
func InvokeCrossChaincode(chaincodeName string, method string, args []string, channelName string) (interface{}, error)
- Parámetros:
chaincodeName
: nombre del código de cadenas al que llamar.
methodName
: nombre del método al que se llama en el código de cadena.
arg
: argumento del método de llamada.
channelName
: canal donde se encuentra el código de cadena a llamar.
- Devuelve:
interface{}
: devuelve un objeto map[string]interface{}
que contiene tres claves:
isValid
: true
si la llamada es válida.
payload
: salida devuelta por la llamada entre cadenas, como un objeto JSON.
message
: mensaje devuelto por la llamada entre cadenas, en formato UTF-8.
- Ejemplo de valor de retorno:
{
"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
- Puede utilizar este método en un código de cadenas para llamar a una función en otro código de cadenas. Ambos códigos de cadenas deben estar instalados en el mismo par.
-
func InvokeChaincode(chaincodeName string, method string, args []string, channelName string) (interface{}, error)
- Parámetros:
chaincodeName
: nombre del código de cadenas al que llamar.
methodName
: nombre del método al que se llama en el código de cadena.
arg
: argumento del método de llamada.
channelName
: canal donde se encuentra el código de cadena a llamar.
- Devuelve:
interface{}
: devuelve un objeto map[string]interface{}
que contiene tres claves:
isValid
: true
si la llamada es válida.
payload
: salida devuelta por la llamada entre cadenas, en formato UTF-8.
message
: mensaje devuelto por la llamada entre cadenas, en formato UTF-8.
- Ejemplo de valor de retorno:
{
"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}"
}
Métodos de clave compuesta
-
GenerateCompositeKey
- Este método genera y devuelve la clave compuesta basada en
indexName
y los atributos proporcionados en los argumentos.
func GenerateCompositeKey(indexName string, attributes []string)
(string, error)
- Parámetros:
indexName (string)
: tipo de objeto de la clave compuesta.
attrbutes ([]string)
: atributos del activo en función del cual se debe formar la clave compuesta.
- Devuelve:
string
: contiene el resultado de la clave compuesta.
error
: contiene el error si se observa.
-
GetByCompositeKey
- Este método devuelve el activo que coincide con la clave y la columna proporcionada en los parámetros. El parámetro
index
indica el índice de la clave devuelta en la matriz del método de stub SplitCompositeKey
.
- Internamente, este método llama a
getStateByPartialCompositeKey
, splitCompositeKey
y getState
de Hyperledger Fabric.
func GetByCompositeKey(key string, columns []string, index int)
(interface{}, error)
- Parámetros:
key (string)
: tipo de objeto proporcionado al crear la clave compuesta.
column ([]string)
: segmento de atributos en el que se debe consultar el libro mayor mediante la clave compuesta.
index(int)
: índice del atributo.
- Devuelve:
Interface{}
: contiene la lista de activos que son el resultado de este método.
error
: contiene cualquier error si está presente.
Método de resguardo
-
GetNetworkStub
- Este método devolverá Hyperledger Fabric
chaincodeStub
.
- Puede obtener acceso al stub shim llamando al método
GetNetworkStub
. Esto le ayudará a escribir su propia implantación trabajando directamente con los activos.
func GetNetworkStub() shim.ChaincodeStubInterface
- Parámetros:
- Devuelve:
shim.ChaincodeStubInterface
: es el stub de código de cadena de Hyperledger Fabric.
Otros Métodos
GetTransactionId()
GetTransactionTimestamp()
GetChannelID()
GetCreator()
GetSignedProposal()
GetArgs()
GetStringArgs()
GetCreatorMspId()
GetId
-
GetTransactionId
- Devuelve el ID de transacción para la solicitud de llamada de código de cadenas actual. El ID de transacción identifica de manera única la transacción dentro del ámbito del canal.
func GetTransactionId() string
- Parámetros:
- Devuelve:
string
: contiene el ID de transacción necesario.
-
GetTransactionTimestamp
- Devuelve el registro de hora en que se creó la transacción. Esto se toma de la transacción
ChannelHeader
, por lo que indicará el registro de hora del cliente y tendrá el mismo valor en todos los avales.
func GetTransactionTimestamp() (*timestamp.Timestamp, error)
- Parámetros:
- Devuelve:
timestamp.Timestamp
: contiene el registro de hora necesario.
error
: contiene cualquier error si está presente.
-
GetChannelID
- Devuelve el ID de canal de la propuesta para que se procese el código de cadenas.
func GetChannelID() string
- Parámetros:
- Devuelve:
string
: contiene el ID de canal necesario como cadena.
-
GetCreator
- Devuelve el objeto de identidad del remitente de la llamada de código de cadenas
func GetCreator() ([]byte, error)
- Parámetros:
- Devuelve:
[]byte
: contiene el objeto de identidad necesario serializado.
error
: contiene cualquier error si está presente.
-
GetSignedProposal
- Devuelve un objeto totalmente descodificado de la propuesta de transacción firmada.
func GetSignedProposal() (*peer.SignedProposal, error)
- Parámetros:
- Devuelve:
*peer.SignedProposal
: contiene el objeto de propuesta firmado necesario.
error
: contiene cualquier error si está presente.
-
GetArgs
- Devuelve los argumentos como matriz de cadenas de la solicitud de invocación de código de cadena.
func GetArgs() [][]byte
- Parámetros:
- Devuelve:
[][]byte
: contiene los argumentos transferidos.
-
GetStringArgs
- Devuelve los argumentos destinados al código de cadenas Init y Invoke como una matriz de cadenas.
func GetStringArgs() []string
- Parámetros:
- Devuelve:
[]string
: contiene los argumentos necesarios como una matriz de cadenas.
-
GetCreatorMspId
- Devuelve el ID de MSP de la identidad que llama.
-
func GetCreatorMspId() string
- Parámetros:
- Devuelve:
string
: devuelve el ID de MSP de la identidad que llama.
-
GetId
- Cuando el activo tiene una clave derivada como
Id
, puede utilizar este método para obtener un ID derivado. Este método devolverá un error si la clave derivada contiene %t
(registro de hora).
- Parámetros:
object
: el objeto debe contener todas las propiedades de las que depende la clave derivada.
- Devuelve:
- Devuelve la clave derivada como una cadena.
- Por ejemplo:
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)
}
Paquete de utilidades
Los siguientes métodos del paquete de utilidades pueden ser útiles:
-
Util.CreateModel
- Analiza la cadena JSON proporcionada y crea un objeto de activo del tipo proporcionado.
func CreateModel(obj interface{}, inputString string) error
- Parámetros:
inputString (string)
: cadena de JSON de entrada a partir de la cual se va a crear el objeto.
obj (interface{})
: referencia del objeto que se va a crear a partir de la cadena JSON. Este objeto almacenará el modelo creado, que también se valida según las etiquetas de validador.
- Devuelve:
error
: contiene los errores encontrados al crear o validar el activo.
-
util.ConvertMapToStruct
- Convierta el mapa proporcionado en un objeto del tipo proporcionado.
func ConvertMapToStruct(inputMap map[string](interface{}), resultStruct
interface{}) error
- Parámetros:
inputMap (map[string](interface{}))
: asignación que se debe convertir en el objeto de activo.
resultStruct (interface{})
: referencia del objeto de activo necesario que se debe generar a partir de la asignación. Contiene el objeto de activo de resultado necesario.
- Devuelve:
error
: contiene los errores encontrados al crear o validar el activo.
Para conocer los métodos de SDK de token, consulte los temas de Soporte de tokenización mediante el creador de aplicaciones de blockchain.
Controlador
El archivo Controller.go
implanta los métodos CRUD y personalizados para los activos.
Puede crear cualquier número de clases, funciones o archivos, pero solo los métodos que se definen en la estructura de código de cadenas son invocables desde el exterior, el resto de ellos están ocultos.
Métodos generados automáticamente
Como se describe en Archivo de Especificación de Entrada, puede especificar los métodos CRUD que desea generar en el archivo de especificación. Por ejemplo, si ha seleccionado generar todos los métodos, el resultado sería similar a:
//
//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
}
Métodos personalizados
Los siguientes métodos personalizados se han generado a partir de nuestro archivo de especificación de ejemplo.
executeQuery
muestra cómo se puede llamar a consultas enriquecidas con SQL. Los validadores de los argumentos los agrega automáticamente Blockchain App Builder en función del tipo de argumento especificado en el archivo de especificación.
Puede implantar la funcionalidad según la lógica de negocio. Si agrega métodos personalizados, agréguelos al archivo de controlador. Si agrega métodos personalizados a la biblioteca en lugar del archivo de controlador, los cambios se perderán cuando el contenido de la carpeta de la biblioteca se actualice durante los procesos de sincronización o actualización del código de cadenas.
//
//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
}
Para los códigos de cadenas Go, cada método personalizado debe devolver dos valores:
interfaz vacía,
error. Por ejemplo:
func (t *Controller) FetchRawMaterial(supplierId string, rawMaterialSupply int) (interface{}, error) {
return nil, nil
}
Método de inicialización
Se proporciona un método Init
personalizado en el controlador con una definición vacía. Si utiliza Blockchain App Builder para desplegar o actualizar, el método Init
se llama automáticamente. Si despliega o actualiza desde la consola de Oracle Blockchain Platform en la plataforma Hyperledger Fabric v1.4.7, el método Init
también se llama automáticamente. Si despliega o actualiza desde la consola de Oracle Blockchain Platform en la plataforma Hyperledger Fabric v2.x, debe llamar al método Init
manualmente. Puede utilizar una herramienta de terceros como Postman para llamar al método Init
manualmente.
type Controller struct {
}
func (t *Controller) Init(args string) (interface{}, error)
{ return nil, nil
}
Si desea inicializar cualquier estado de aplicación en este punto, puede utilizar este método para hacerlo.