Projeto Scaffolded Go Chaincode

O Blockchain App Builder pega a entrada do seu arquivo de especificação e gera um projeto de chaincode com andaimes 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 estã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 de andaimes pode ser encontrado em $GOPATH/src/example.com/<chaincodeName>

Modelo

Propriedade do Tipo de Ativo

Por padrão, cada struct terá uma propriedade adicional chamada AssetType. Essa propriedade pode ser útil na extração apenas de ativos desse tipo. Todas as alterações nesta propriedade são ignoradas 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 desta chave. Este validador se aplica automaticamente quando um novo projeto Go é montado.
Na captura de tela a seguir, "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: obtém valores de concat ou hash. Requer um parâmetro adicional algorithm se hash estiver 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 seguinte propriedade como obrigatória e não pode ser ignorada ao salvar no razão. Se ignorado, ele gera 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 Básicos de Ir 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"
  • booleano: validate: "bool"
Validador mínimo
validate:"min=<param>"
Usando o validador mínimo, o valor mínimo pode ser definido para uma propriedade do tipo número e string.
Para o 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, verifique 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 o tipo int: Como o validador min, para o 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 da 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"'
}
Depois do 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 validará 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
É possível aplicar uma propriedade a vários validadores.
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 ORM simplificado é capturado na classe Model do objeto Context (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 - chama o método PutState do Hyperledger Fabric
  • Get - chama o método GetState do Hyperledger Fabric
  • Update - chama o método PutState do Hyperledger Fabric
  • Delete - chama o método DeleteState do Hyperledger Fabric
  • History - chama o método GetHistoryForKey do Hyperledger Fabric
  • GetByRange - chama o método GetStateByRange do Hyperledger Fabric
  • GetByRangeWithPagination - chama o método GetStateByRangeWithPagination do Hyperledger Fabric

Métodos SDK

Os chaincodes 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 forma de acessar os métodos 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 de modelo mantido pelo contexto de 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 seu 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 é necessário do 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 é 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.
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 precisa ser atualizado no razão é passado por referência a essa API com os novos valores. O ativo de entrada é validado e verificado de acordo com as tags de estrutura 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 do utilitário.
  • metadata/args[1] (interface{}) - Esse parâmetro é opcional. Ele foi fornecido para facilitar se você precisar armazenar quaisquer metadados no razão juntamente com o ativo no runtime. Este parâmetro poderá ser ignorado se não existir tal requisito.
Retorna:
  • interface {} - O ativo é retornado como uma interface.
  • error - Contém um erro, se retornado, ou nulo.
Delete
Deleta 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 na forma de map[string]interface{}.
GetByRange
Retorna a lista de ativos por intervalo 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 é passado 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{} - Esse array contém a lista de ativos obtidos do razão. Você pode acessar os objetos iterando sobre esse 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 o método GetStateByRangeWithPagination do Hyperledger Fabric internamente.
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 para o 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 este 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 de 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 sobre o 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{} - conterá a saída da consulta. O resultado é na forma de segmento de interfaces. É necessário iterar sobre o intervalo e utilizar os elementos convertendo-os em tipos apropriados.
  • error - Contém o erro, se observado.
QueryWithPagination
O método de consulta executará uma consulta SQL/Couch DB sobre o 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 avançada de 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{} - conterá a saída da consulta. O resultado é na forma de segmento de interfaces. É necessário iterar sobre o intervalo e utilizar os elementos convertendo-os em tipos apropriados.
  • 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 para chamar no chaincode.
  • arg - O argumento do método de chamada.
  • channelName - O canal no qual 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 cross-chaincode, como um objeto JSON.
    • message - A mensagem retornada pela chamada de cross-chaincode, 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 para chamar no chaincode.
  • arg - O argumento do método de chamada.
  • channelName - O canal no qual 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 cross-chaincode, 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
Este 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 na qual o razão deve ser consultado usando a chave composta.
  • index(int) - Índice do atributo.
Retorna:
  • Interface{} - Contém a lista de ativos que são resultado desse método.
  • error - Contém erros, se houver.

Método Stub

GetNetworkStub
Este método retornará o Hyperledger Fabric chaincodeStub.
Você pode obter acesso ao stub de shim chamando o método GetNetworkStub. Isso ajudará você a escrever 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 de transação necessário.
GetTransactionTimestamp
Retorna o timestamp quando a transação foi criada. Isso é retirado 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 da proposta para o chaincode processar.
func GetChannelID() string
Parâmetros:
  • nenhuma
Retorna:
  • string - Contém o ID de 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 necessá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 um array 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 do 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 do utilitário 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 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 os erros encontrados durante a criação ou validação do 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 do ativo.
  • resultStruct (interface{}) - A referência do objeto de ativo necessário que precisa ser gerado a partir do mapa. Contém o objeto do ativo de resultado necessário.
Retorna:
  • error - Contém os erros encontrados durante a criação ou validação do ativo.

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

Controladora

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

Você pode criar qualquer número de classes, funções ou arquivos, mas apenas os métodos definidos na estrutura do chaincode podem ser invocados de fora, o restante deles está oculto.

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 de nosso 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 upgrade 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 chaincodes 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 Inicial

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 do 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 do 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 você quiser inicializar qualquer estado do aplicativo neste momento, poderá usar esse método para fazer isso.