Projeto de Chaincode Go Andaime

O Blockchain App Builder pega a entrada do seu arquivo de especificação e gera um projeto de chaincode totalmente funcional. O projeto contém classes e funções geradas automaticamente, métodos CRUD, métodos SDK, validação automática de argumentos, marshalling/un-marshalling e recurso de persistência transparente (ORM).

Se o projeto chaincode estiver na linguagem Go, o projeto scaffolded contém três arquivos principais:
  • main.go
  • <chaincodeName>.model.go
  • <chaincodeName>.controller.go
Todas as bibliotecas necessárias são instaladas e empacotadas.

O arquivo <chaincodeName>.model.go no subdiretório model contém várias definições de ativos e o arquivo <chaincodeName>.controller.go no subdiretório controller contém o comportamento do ativo e os métodos CRUD. As várias tags e pacotes de estrutura Go em model.go e controller.go fornecem suporte para recursos como validação automática de argumentos, marshalling/unmarshalling de argumentos, recurso de persistência transparente (ORM) e chamada de consultas avançadas.

O projeto do andaime pode ser encontrado em $GOPATH/src/example.com/<chaincodeName>

Modelo

Propriedade do Tipo de Ativo

Por padrão, cada estrutura terá uma propriedade adicional chamada AssetType. Essa propriedade pode ser útil para extrair somente ativos desse tipo. Qualquer alteração nessa propriedade é ignorada durante a criação e atualização do ativo. Por padrão, o valor da propriedade é <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"'
}

Validadores

Id
id:"true"
Este validador identifica a propriedade que define exclusivamente o ativo subjacente. O ativo é salvo pelo valor nesta chave. Este validador se aplica automaticamente quando um novo projeto Go é andaime.
Na captura de tela abaixo, "SupplierId" é a chave do ativo do fornecedor e tem uma propriedade de tag id:"true" para a propriedade 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 é usado para definir o atributo derivado de outras propriedades. Este decorador tem dois parâmetros obrigatórios:
  • strategy: usa valores de concat ou hash. Requer um parâmetro adicional algorithm se hash for selecionado. O algoritmo padrão é sha256; md5 também é suportado.
  • format: usa um array de strings de especificação e valores a serem usados pela estratégia.
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"'
}
Obrigatória
validate:"mandatory"
Isso marca a propriedade a seguir como obrigatória e não pode ser ignorada ao salvar no razão. Se ignorado, ele lança um erro. No exemplo abaixo, "SupplierId" tem uma 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"'
}
Padrão
default:"<param>"
Isso indica que a propriedade a seguir pode ter um valor padrão. O valor padrão na tag padrão é usado quando a propriedade é ignorada ao salvar no razão. Na propriedade de exemplo abaixo, Active tem um valor padrão de true, fornecido como 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"'
}
Validar tipos
Os tipos de Go Básico são validados para uma propriedade definindo uma tag de validação. Estas são as tags de validação com base nos tipos:
  • string: validate: "string"
  • data: validate: "date"
  • número: validate: "int"
  • booliano: validate: "bool"
Validador mínimo
validate:"min=<param>"
Usando o validador min, o valor mínimo pode ser definido para uma propriedade do tipo número e string.
Para tipo int: No exemplo, a propriedade RawMaterialAvailable tem um valor mínimo de 0 e, se um valor menor que 0 for aplicado a RawMaterialAvailable, um erro será retornado.
Para string de tipo: Para o validador mínimo de tipo de string, verificará o tamanho da string com o valor fornecido. Portanto, no exemplo abaixo, a propriedade License deve ter no mínimo 10 caracteres.
Exemplo:
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>"
Usando o validador máximo, o valor máximo pode ser definido para uma propriedade do tipo número e string.
Para tipo int: Como o validador min, para tipo int, se um valor fornecido para structfield for maior que o valor fornecido no validador, um erro será retornado.
Para string de tipo: Como o validador mínimo, o validador máximo também verificará o tamanho da string com o valor fornecido. No exemplo, a propriedade Domain tem um valor máximo de 50, portanto, se a propriedade Domain tiver uma string com mais de 50 caracteres, uma mensagem de erro será retornada.
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 data
Antes do validador:
validate:"before=<param>"
O validador anterior valida uma propriedade do tipo date para ter um valor menor que o especificado no parâmetro.
Neste exemplo, a propriedade ExpiryDate deve ser anterior a "2020-06-26" e, caso contrário, retornará um erro.
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"'
}
Após o validador:
validate:"after=<param>"
O validador anterior valida uma propriedade do tipo date para ter um valor maior que o especificado no parâmetro.
Neste exemplo, a propriedade CompletionDate deve ser posterior a "2020-06-26" e, caso contrário, retornará um erro.
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"
O validador de URL validará uma propriedade para strings de URL.
Neste exemplo, a propriedade Domain deve ser um URL válido.
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 Regexp
validate:"regexp=<param>"
O validador Regexp validará a propriedade para a expressão regular de entrada.
Neste exemplo, a propriedade PhoneNumber será validada para um número de celular de acordo com a expressão 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"'
}
Vários validadores
Vários validadores podem ser aplicados a uma propriedade.
Neste exemplo, a propriedade Domain tem validação para uma string, URL e tamanho mínimo e máximo da string.
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

O Recurso de Persistência Transparente ou o ORM simplificado é capturado na classe Model do objeto Contexto (Ctx). Se seu modelo chamar qualquer um dos métodos SDK a seguir, acesse-os usando t.Ctx.Model.

Os métodos SDK que implementam o ORM são os seguintes:
  • Save – isso chama o método Hyperledger Fabric PutState
  • Get – isso chama o método Hyperledger Fabric GetState
  • Update – isso chama o método Hyperledger Fabric PutState
  • Delete – isso chama o método Hyperledger Fabric DeleteState
  • History – isso chama o método Hyperledger Fabric GetHistoryForKey
  • GetByRange – isso chama o método Hyperledger Fabric GetStateByRange
  • GetByRangeWithPagination – isso chama o método Hyperledger Fabric GetStateByRangeWithPagination

Métodos SDK

Os códigos de cadeia Go implementam o recurso de persistência transparente (ORM) com o pacote de modelos.

Observação:

A partir da versão 21.2.3, a maneira de acessar os métodos do ORM foi alterada. Execute o comando ochain --version para determinar a versão do Blockchain App Builder.

Em versões anteriores, os métodos ORM eram expostos como métodos estáticos no pacote de modelos. Os métodos agora são definidos no receptor do modelo, que contém o stub da transação. Para chamar esses métodos, você usa o receptor do modelo mantido pelo contexto da transação no controlador. Você chama esses métodos como t.Ctx.Model.<method_name> em vez de model.<method_name>.

O exemplo a seguir mostra as chamadas do método Save e Get nas versões 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
}

O exemplo a seguir mostra as chamadas do método Save e Get da versão 21.2.3 e posterior:

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
}

Depois de fazer upgrade para a versão 21.2.3, faça essa alteração em todos os projetos de chaincode que você criou com uma versão anterior do Blockchain App Builder. Se você usar o comando sync para sincronizar as alterações entre o arquivo de especificação e o código-fonte, as alterações serão trazidas automaticamente ao controlador para os métodos prontos para uso. Você ainda precisa resolver manualmente quaisquer conflitos.

Os seguintes métodos ORM são expostos por meio do pacote de modelos:

Get
Consulta o razão do ativo armazenado com base no ID fornecido.
func Get(Id string, result ...interface{}) (interface{}, error)
Parâmetros:
  • Id - O ID do ativo que é obrigatório no razão.
  • result (interface{}) - Este é um objeto de ativo vazio de um tipo específico, que é passado por referência. Este objeto conterá o resultado deste método. A ser usado somente se o resultado específico do tipo for obrigatório.
  • asset (interface) - Objeto de ativo vazio, que é informado por referência. Este objeto conterá o resultado deste método. A ser usado somente se o resultado específico do tipo for obrigatório.
Retorna:
  • interface {} - A interface contém o ativo na forma de map[string]interface{}. Antes de operar neste mapa, é necessário afirmar a interface obtida com o tipo map[string]interface{}. Para converter esse mapa em um objeto de ativo, você pode usar a API do utilitário util.ConvertMaptoStruct (consulte: Pacote de Utilitários).
  • error - Contém um erro se retornado ou é nulo.
Update
Atualiza o ativo fornecido no razão com os novos valores.
func Update(args ...interface{}) (interface{}, error)
Parâmetros:
  • obj (interface) - O objeto que deve ser atualizado no razão é passado por referência para essa API com os novos valores. O ativo de entrada é validado e verificado de acordo com as tags structure mencionadas na especificação do modelo e, em seguida, armazenado no razão.
Retorna:
  • interface{} - O ativo salvo é retornado como uma interface.
  • error - Contém um erro se retornado ou é nulo.
Save
Salva o ativo no razão após a validação em todas as tags de estrutura.
func Save(args ...interface{}) (interface{}, error)
Parâmetros:
  • obj/args[0] (interface{}) - O objeto que precisa ser armazenado no razão é passado por referência neste método de utilitário.
  • metadata/args[1] (interface{}) - Este parâmetro é opcional. Ele foi fornecido para facilitar se você precisar armazenar quaisquer metadados no razão junto com o ativo no tempo de execução. Esse parâmetro poderá ser ignorado se esse requisito não existir.
Retorna:
  • interface {} - O ativo é retornado como uma interface.
  • error - Contém um erro se retornado ou é nulo.
Delete
Exclui o ativo do razão.
func Delete(Id string) (interface{}, error)
Parâmetros:
  • id (string) - O ID do ativo que deve ser excluído do razão.
Retorna:
  • interface {} - Contém o ativo que está sendo excluído no formato map[string]interface{}.
GetByRange
Retorna a lista de ativos por faixa de IDs.
func GetByRange(startKey string, endKey string, asset ...interface{})
([]map[string]interface{}, error)
Parâmetros:
  • startkey (string) - ID Inicial do intervalo de objetos que são obrigatórios.
  • endkey (string) - Fim da faixa de objetos que são obrigatórios.
  • asset interface - (opcional) Array vazio de ativos, que é informado por referência. Essa matriz conterá o resultado desse método. A ser usado se o resultado específico do tipo for obrigatório.
Retorna:
  • []map[string]interface{} - Este array contém a lista de ativos obtidos do razão. Você pode acessar os objetos iterando nesse array e afirmando os objetos como map[string]interface{} e usando o utilitário para converter em objeto de ativo.
  • error - Contém um erro se retornado ou é nulo.
GetByRangeWithPagination
O método GetByRangeWithPagination é um método estático da classe OchainModel que é herdado pelas classes Model concretas de {chaincodeName}.model.ts.
Isso retorna uma lista de ativos entre o intervalo startId e endId, filtrados por tamanho de página e marcador. Esse método chama internamente o método Hyperledger Fabric GetStateByRangeWithPagination.
Se o parâmetro modelName não for fornecido, o método retornará Promise<Object [ ] >. Se o parâmetro modelName for fornecido, o método tratará a conversão no tipo Model do chamador. No exemplo a seguir, o array de resultados é do tipo Supplier. Se o ativo retornado do razão não for do tipo Model, ele não será incluído na lista. Essa verificação é feita pela propriedade assetType somente para leitura na classe Model.
Para retornar todos os ativos entre o intervalo startId e endId, filtrados por tamanho de página e marcadores, use o 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 – Chave inicial do intervalo. Incluído no intervalo.
  • endkey : string – Chave final do intervalo. Excluído do intervalo.
  • pageSize : number – O tamanho da página da consulta.
  • Bookmark : string – O marcador da consulta. A saída começa com este marcador.
  • asset interface – (Opcional) Um array vazio de ativos, passado por referência. Essa matriz conterá o resultado desse método. Use esse parâmetro para obter resultados específicos do tipo.
Retorna:
  • []map[string]interface{} – Um array que contém a lista de ativos recuperados do razão. Você pode acessar os objetos iterando sobre esse array e afirmando os objetos como map[string]interface{} e usando um utilitário para conversão em um objeto de ativo.
  • error – Contém um erro se um erro for retornado; caso contrário, nulo.
GetHistoryById
Retorna o histórico do ativo com o ID fornecido.
func GetHistoryByID(Id string) ([]interface{}, error)
Parâmetros:
  • Id (string) - ID do ativo para o qual o histórico é necessário.
Retorna:
  • []interface{} - Esta fatia contém o histórico do ativo obtido do razão na forma de fatia de map[string]interface{}. Você pode acessar cada elemento do histórico iterando sobre essa fatia e afirmando os objetos como map[string]interface{} e usando o utilitário para converter em objeto de ativo.
  • error - Contém o erro, se observado.
Query
O método de consulta executará uma consulta SQL/Couch DB no razão. Esse método só é suportado para implantação remota no Oracle Blockchain Platform. Este é um método genérico para executar consultas SQL no razão.
func Query(queryString string) ([]interface{}, error)
Parâmetros:
  • queryString (string) - Informe a string de consulta.
Retorna:
  • []interface{} - Contém a saída da consulta. O resultado está na forma de fatia de interfaces. É necessário iterar no intervalo e utilizar os elementos convertendo-os nos tipos adequados.
  • error - Contém o erro, se observado.
QueryWithPagination
O método de consulta executará uma consulta SQL/Couch DB no razão, filtrada por tamanho de página e marcador. Esse método só é suportado para implantação remota no Oracle Blockchain Platform. Este é um método genérico para executar consultas SQL no razão.
func (m *Model) QueryWithPagination(queryString string, pageSize int32, bookmark string) ([]interface{}, error)
Parâmetros:
  • queryString (string) - Consulta Rich SQL/Couch DB.
  • pageSize : number - O tamanho da página da consulta.
  • bookmark : string - O marcador da consulta. A saída começa com este marcador.
Retorna:
  • []interface{} - Contém a saída da consulta. O resultado está na forma de fatia de interfaces. É necessário iterar no intervalo e utilizar os elementos convertendo-os nos tipos adequados.
  • error - Contém o erro, se observado.
InvokeCrossChaincode
Você pode usar esse método em um chaincode para chamar uma função em outro chaincode. Ambos os chaincodes devem ser instalados no mesmo par.
func InvokeCrossChaincode(chaincodeName string, method string, args []string, channelName string) (interface{}, error)
Parâmetros:
  • chaincodeName – O nome do chaincode a ser chamado.
  • methodName - O nome do método a ser chamado no chaincode.
  • arg - O argumento do método de chamada.
  • channelName - O canal onde o chaincode a ser chamado está localizado.
Retorna:
  • interface{} - Retorna um objeto map[string]interface{} que contém três chaves:
    • isValid - true se a chamada for válida.
    • payload - A saída retornada pela chamada de código de cadeia cruzada, como um objeto JSON.
    • message - A mensagem retornada pela chamada de código de cadeia cruzada, no formato UTF-8.
Exemplo 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
Você pode usar esse método em um chaincode para chamar uma função em outro chaincode. Ambos os chaincodes devem ser instalados no mesmo par.
func InvokeChaincode(chaincodeName string, method string, args []string, channelName string) (interface{}, error)
Parâmetros:
  • chaincodeName – O nome do chaincode a ser chamado.
  • methodName - O nome do método a ser chamado no chaincode.
  • arg - O argumento do método de chamada.
  • channelName - O canal onde o chaincode a ser chamado está localizado.
Retorna:
  • interface{} - Retorna um objeto map[string]interface{} que contém três chaves:
    • isValid - true se a chamada for válida.
    • payload - A saída retornada pela chamada de código de cadeia cruzada, no formato UTF-8.
    • message - A mensagem retornada pela chamada de código de cadeia cruzada, no formato UTF-8.
Exemplo 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 Chave Composta

GenerateCompositeKey
Esse método gera e retorna a chave composta com base em indexName e nos atributos fornecidos nos argumentos.
func GenerateCompositeKey(indexName string, attributes []string)
(string, error)
Parâmetros:
  • indexName (string) - Tipo de objeto da chave composta.
  • attrbutes ([]string) - Atributos do ativo com base nos quais a chave composta deve ser formada.
Retorna:
  • string - Contém o resultado da chave composta.
  • error - Contém o erro, se observado.
GetByCompositeKey
Esse método retorna o ativo que corresponde à chave e à coluna fornecidas nos parâmetros. O parâmetro index indica o índice da chave retornada no array do método stub SplitCompositeKey.
Internamente, esse método chama getStateByPartialCompositeKey, splitCompositeKey e getState do Hyperledger Fabric.
func GetByCompositeKey(key string, columns []string, index int)
(interface{}, error)
Parâmetros:
  • key (string) - Tipo de objeto fornecido ao criar a chave composta.
  • column ([]string) - Esta é a fatia de atributos em que o razão deve ser consultado usando a chave composta.
  • index(int) - Índice do atributo.
Retorna:
  • Interface{} - Contém a lista de ativos resultantes desse método.
  • error - Contém erros, se houver.

Método Canhoto

GetNetworkStub
Esse método retornará o Hyperledger Fabric chaincodeStub.
Você pode obter acesso ao shim stub chamando o método GetNetworkStub. Isso ajudará você a criar sua própria implementação trabalhando diretamente com os ativos.
func GetNetworkStub() shim.ChaincodeStubInterface
Parâmetros:
  • nenhuma
Retorna:
  • shim.ChaincodeStubInterface - Este é o stub de chaincode do Hyperledger Fabric.

Outros Métodos

  • GetTransactionId()
  • GetTransactionTimestamp()
  • GetChannelID()
  • GetCreator()
  • GetSignedProposal()
  • GetArgs()
  • GetStringArgs()
  • GetCreatorMspId()
  • GetId
GetTransactionId
Retorna o ID da transação para a solicitação de chamada de chaincode atual. O ID da transação identifica exclusivamente a transação dentro do escopo do canal.
func GetTransactionId() string
Parâmetros:
  • nenhuma
Retorna:
  • string - Contém o ID da transação necessário.
GetTransactionTimestamp
Retorna o timestamp quando a transação foi criada. Isso é obtido da transação ChannelHeader, portanto, indicará o timestamp do cliente e terá o mesmo valor em todos os endossadores.
func GetTransactionTimestamp() (*timestamp.Timestamp, error)
Parâmetros:
  • nenhuma
Retorna:
  • timestamp.Timestamp - Contém o timestamp necessário.
  • error - Contém erros, se houver.
GetChannelID
Retorna o ID do canal para a proposta do chaincode a ser processado.
func GetChannelID() string
Parâmetros:
  • nenhuma
Retorna:
  • string - Contém o ID do canal necessário como uma string.
GetCreator
Retorna o objeto de identidade do remetente da chamada de chaincode
func GetCreator() ([]byte, error)
Parâmetros:
  • nenhuma
Retorna:
  • []byte - Contém o objeto de identidade necessário serializado.
  • error - Contém erros, se houver.
GetSignedProposal
Retorna um objeto totalmente decodificado da proposta de transação assinada.
func GetSignedProposal() (*peer.SignedProposal, error)
Parâmetros:
  • nenhuma
Retorna:
  • *peer.SignedProposal - Contém o objeto de proposta assinado obrigatório.
  • error - Contém erros, se houver.
GetArgs
Retorna os argumentos como array de strings da solicitação de chamada de chaincode.
func GetArgs() [][]byte
Parâmetros:
  • nenhuma
Retorna:
  • [][]byte - Contém os argumentos informados.
GetStringArgs
Retorna os argumentos destinados ao chaincode Init e Invoke como uma matriz de string.
func GetStringArgs() []string
Parâmetros:
  • nenhuma
Retorna:
  • []string - Contém os argumentos necessários como um array de string.
GetCreatorMspId
Retorna o ID MSP da identidade de chamada.
func GetCreatorMspId() string
Parâmetros:
  • nenhuma
Retorna:
  • string - Retorna o ID do MSP da identidade de chamada.
GetId
Quando o ativo tiver uma chave derivada como Id, você poderá usar esse método para obter um ID derivado. Este método retornará um erro se a chave derivada contiver %t (timestamp).
Parâmetros:
  • object - O objeto deve conter todas as propriedades das quais a chave derivada é dependente.
Retorna:
  • Retorna a chave derivada como uma string.
Exemplo:
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)
}

Pacote de Utilitários

Os seguintes métodos no pacote de utilitários podem ser úteis:

Util.CreateModel
Analisa a string JSON fornecida e cria um objeto de ativo do tipo fornecido.
func CreateModel(obj interface{}, inputString string) error
Parâmetros:
  • inputString (string) - A string JSON de entrada da qual o objeto deve ser criado.
  • obj (interface{}) - A referência do objeto que deve ser criado com base na string JSON. Este objeto armazenará o modelo criado, que também é validado de acordo com as tags do validador.
Retorna:
  • error - Contém quaisquer erros encontrados ao criar ou validar o ativo.
util.ConvertMapToStruct
Converta o mapa fornecido em objeto do tipo fornecido.
func ConvertMapToStruct(inputMap map[string](interface{}), resultStruct
interface{}) error
Parâmetros:
  • inputMap (map[string](interface{})) - Mapa que precisa ser convertido no objeto de ativo.
  • resultStruct (interface{}) - A referência do objeto de ativo necessário que precisa ser gerado no mapa. Contém o objeto de ativo de resultado necessário.
Retorna:
  • error - Contém quaisquer erros encontrados ao criar ou validar o ativo.

Para métodos SDK de token, consulte os tópicos em Suporte à Tokenização Usando o Blockchain App Builder.

Controlador

O arquivo Controller.go implementa o CRUD e métodos personalizados para os ativos.

Você pode criar qualquer número de classes, funções ou arquivos, mas apenas os métodos que são definidos na estrutura de chaincode são invocáveis de fora, o resto deles estão ocultos.

Métodos Gerados Automaticamente

Conforme descrito em Arquivo de Especificação de Entrada, você pode especificar quais métodos CRUD deseja gerar no arquivo de especificação. Por exemplo, se você selecionou gerar todos os métodos, o resultado seria semelhante 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

Os métodos personalizados a seguir foram gerados a partir do arquivo de especificação de exemplo.

O executeQuery mostra como as consultas ricas em SQL podem ser chamadas. Os validadores contra os argumentos são adicionados automaticamente pelo Blockchain App Builder com base no tipo de argumento especificado no arquivo de especificação.

É possível implementar a funcionalidade de acordo com a lógica de negócios. Se você adicionar métodos personalizados, adicione-os ao arquivo do controlador. Se você adicionar métodos personalizados à biblioteca em vez do arquivo do controlador, suas alterações serão perdidas quando o conteúdo da pasta da biblioteca for atualizado durante os processos de sincronização ou atualização de chaincode.

//	
//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 códigos de cadeia Go, cada método personalizado deve retornar dois valores: interface vazia, erro. Por exemplo:
func (t *Controller) FetchRawMaterial(supplierId string, rawMaterialSupply int) (interface{}, error) { 
    return nil, nil
}

Método de inicialização

Um método Init personalizado é fornecido no controlador com uma definição vazia. Se você usar o Blockchain App Builder para implantar ou fazer upgrade, o método Init será chamado automaticamente. Se você implantar ou fazer upgrade da console do Oracle Blockchain Platform na plataforma Hyperledger Fabric v1.4.7, o método Init também será chamado automaticamente. Se você implantar ou fazer upgrade da console do Oracle Blockchain Platform na plataforma Hyperledger Fabric v2.x, deverá chamar o método Init manualmente. Você pode usar uma ferramenta de terceiros, como Postman, para chamar o método Init manualmente.

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

Se quiser inicializar qualquer estado de aplicativo nesse ponto, você poderá usar esse método para fazer isso.