Projeto Scaffolded Go Chaincode

O Blockchain App Builder pega a entrada do seu arquivo de especificação e gera um projeto de chaincode andaime 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 capacidade de persistência transparente (ORM).

Se o projeto chaincode usa o idioma 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 estruturas 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 scaffolded está localizado no diretório $GOPATH/src/example.com/<chaincodeName>.

Modelo

Propriedade do Tipo de Ativo

Por padrão, cada struct tem uma propriedade adicional chamada AssetType. Você pode usar essa propriedade para extrair somente ativos desse tipo. Todas as alterações nesta propriedade são ignoradas quando os ativos são criados ou atualizados. O valor da propriedade por padrão é <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 é aplicado automaticamente quando um novo projeto Go é scaffolded.
No exemplo 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. Se o parâmetro hash for especificado, o parâmetro adicional algorithm será obrigatório. O algoritmo padrão é sha256; md5 também é suportado.
  • format: Usa um array de strings e valores de especificação para 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"
Este decorador marca a propriedade a seguir como obrigatória, de modo que não possa ser ignorada ao salvar no razão. Se ignorado, um erro é gerado. No exemplo a seguir, a propriedade 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>"
Este decorador indica que a propriedade a seguir tem um valor padrão. O valor na etiqueta padrão é usado quando a propriedade é ignorada ao salvar no razão. No exemplo a seguir, Active tem um valor padrão true, especificado como a 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 Go são validados para uma propriedade definindo uma tag de validação. As seguintes tags de validação são baseadas nos tipos básicos:
  • string: validate: "string"
  • data: validate: "date"
  • número: validate: "int"
  • booliano: validate: "bool"
Validador mínimo
validate:"min=<param>"
Você pode usar o validador min para definir o valor mínimo de uma propriedade do tipo número ou string.
Para o tipo int: No exemplo a seguir, a propriedade RawMaterialAvailable tem um valor mínimo de 0. Se um valor menor que 0 for aplicado à propriedade RawMaterialAvailable, um erro será retornado.
Para a string de tipo: O validador mínimo verifica o tamanho da string em relação ao valor especificado. No exemplo a seguir, a propriedade License deve ter pelo menos dez caracteres.
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>"
Você pode usar o validador máximo para definir o valor máximo para uma propriedade do tipo número e string.
Para o tipo int: Semelhante ao validador min, se um valor especificado para um campo de estrutura for maior que o valor fornecido no validador, um erro será retornado.
Para a string de tipo: Semelhante ao validador mínimo, o validador máximo verifica o tamanho da string em relação ao valor fornecido. No exemplo a seguir, a propriedade Domain tem um valor máximo de 50, portanto, se a propriedade Domain tiver um comprimento de string superior a 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 parâmetro especificado.
No exemplo a seguir, a propriedade ExpiryDate deve ser anterior a "2020-06-26" e, se não for, um erro será retornado.
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 posterior valida uma propriedade do tipo date para ter um valor maior que o parâmetro especificado.
No exemplo a seguir, a propriedade CompletionDate deve ser posterior a "2020-06-26" e, se não for, 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 valida uma propriedade para strings de URL.
No exemplo a seguir, 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 valida uma propriedade com a expressão regular especificada.
No exemplo a seguir, 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.
No exemplo a seguir, a propriedade Domain tem validação para uma string, um URL e o 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 de Contexto (Ctx). Se seu modelo chamar qualquer um dos métodos SDK a seguir, acesse-os usando t.Ctx.Model.

Os seguintes métodos SDK implementam o ORM:
  • O Save chama o método PutState do Hyperledger Fabric.
  • O Get chama o método GetState do Hyperledger Fabric.
  • O Update chama o método PutState do Hyperledger Fabric.
  • O Delete chama o método DeleteState do Hyperledger Fabric.
  • O History chama o método GetHistoryForKey do Hyperledger Fabric.
  • O GetByRange chama o método GetStateByRange do Hyperledger Fabric.
  • O GetByRangeWithPagination chama o método GetStateByRangeWithPagination do Hyperledger Fabric.

Métodos SDK

Go chaincodes implementar Transparent Persistence Capability (ORM) com o pacote de modelos.

Observação:

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

Em releases anteriores, os métodos ORM foram expostos como métodos estáticos no pacote de modelos. Os métodos agora são definidos no receptor de modelo, que contém o canhoto da transação. Para chamar esses métodos, você usa o modelo receptor 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 de 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 de 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 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 deverá resolver manualmente quaisquer conflitos.

Os seguintes métodos ORM são expostos pelo pacote de modelos:

Get
Consulta o razão para o ativo armazenado com base no ID fornecido.
func Get(Id string, result ...interface{}) (interface{}, error)
Parâmetros:
  • Id - O ID do ativo a ser recuperado do razão.
  • result (interface{}) - Um objeto de ativo vazio de um tipo específico, que é passado por referência. Este objeto conterá o resultado deste método. Use esse parâmetro somente se for necessário um resultado específico do tipo.
  • asset (interface) - Um objeto de ativo vazio, que é passado por referência. Este objeto conterá o resultado deste método. Use esse parâmetro somente se for necessário um resultado específico do tipo.
Retorna:
  • interface {} - A interface contém o ativo no formato map[string]interface{}. Antes de operar neste mapa, você deve afirmar a interface retornada 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 do Utilitário).
  • error - Contém um erro se for retornado ou for nulo.
Update
Atualiza o ativo especificado no razão com novos valores.
func Update(args ...interface{}) (interface{}, error)
Parâmetros:
  • obj (interface) - O objeto a ser atualizado no razão é informado por referência nessa API junto com os novos valores. O ativo de entrada é validado e verificado de acordo com as tags de estrutura 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 for retornado ou for 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 a ser armazenado no razão é passado por referência neste método de utilitário.
  • metadata/args[1] (interface{}) - (Opcional) Você pode usar esse parâmetro para armazenar metadados no razão junto com o ativo no runtime.
Retorna:
  • interface {} - O ativo é retornado como uma interface.
  • error - Contém um erro se for retornado ou for nulo.
Delete
Exclui o ativo do razão.
func Delete(Id string) (interface{}, error)
Parâmetros:
  • id (string) - O ID do ativo a ser excluído do razão.
Retorna:
  • interface {} - Contém o ativo que está sendo excluído no formulário map[string]interface{}.
GetByRange
Retorna uma lista de ativos especificados por um 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 a serem recuperados.
  • endkey (string) - ID Final do intervalo de objetos a serem recuperados.
  • asset interface - (Opcional) Um array vazio de ativos, informado por referência. Essa matriz conterá o resultado do método. Use esse parâmetro se for necessário um resultado específico do tipo.
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 um utilitário para converter em um objeto de ativo.
  • error - Contém um erro se for retornado ou for nulo.
GetByRangeWithPagination
O método GetByRangeWithPagination é um método estático da classe OchainModel que é herdado pelas classes Model concretas de {chaincodeName}.model.ts.
Esse método 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 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 a faixa startId e endId, filtrados por tamanho de página e marcadores, use o método do 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, que é incluída no intervalo.
  • endkey : string – Chave final do intervalo, que é excluída do intervalo.
  • pageSize : number – O tamanho da página da consulta.
  • Bookmark : string – O marcador da consulta. Esta saída começa neste marcador.
  • asset interface – (Opcional) Um array vazio de ativos, transmitido 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.
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 esse segmento e afirmando os objetos como map[string]interface{} e usando um utilitário para converter em objeto de ativo.
  • error - Contém o erro se um erro for retornado.
Query
Este método executa uma consulta SQL/Couch DB no razão. Esse método só é suportado para implantações remotas 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) - A string de consulta.
Retorna:
  • []interface{} - A saída da consulta na forma de uma fatia de interfaces. Itere no intervalo e utilize os elementos convertendo-os em seus tipos apropriados.
  • error - Contém o erro se um erro for retornado.
QueryWithPagination
Este método executa uma consulta SQL/Couch DB no razão, filtrada por tamanho de página e marcador. Esse método só é suportado para implantações remotas 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. Esta saída começa neste marcador.
Retorna:
  • []interface{} - A saída da consulta na forma de uma fatia de interfaces. Itere no intervalo e utilize os elementos convertendo-os em seus tipos apropriados.
  • error - Contém o erro se um erro for retornado.
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 cross-chaincode, 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 no 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 no qual a chave composta será formada.
Retorna:
  • string - O resultado da chave composta.
  • error - Contém o erro se um erro for retornado.
GetByCompositeKey
Este método retorna o ativo que corresponde à chave e à coluna especificadas. O parâmetro index indica o índice da chave retornada no array do método stub SplitCompositeKey.
Internamente, esse método chama os métodos 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) - A fatia de atributos na qual o razão será consultado usando a chave composta.
  • index(int) - Índice do atributo.
Retorna:
  • Interface{} - A lista de ativos correspondentes.
  • error - Contém o erro se um erro for retornado.

Método Stub

GetNetworkStub
Este método retorna o valor chaincodeStub do Hyperledger Fabric.
Você pode acessar o stub do shim chamando o método GetNetworkStub. Isso pode ajudá-lo a escrever sua própria implementação que funciona diretamente com ativos.
func GetNetworkStub() shim.ChaincodeStubInterface
Parâmetros:
  • nenhuma
Retorna:
  • shim.ChaincodeStubInterface - Stub de chaincode do Hyperledger Fabric.

Outros métodos

  • GetTransactionId()
  • GetTransactionTimestamp()
  • GetChannelID()
  • GetCreator()
  • GetSignedProposal()
  • GetArgs()
  • GetStringArgs()
  • GetCreatorMspId()
  • GetId
GetTransactionId
Este método 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 no escopo do canal.
func GetTransactionId() string
Parâmetros:
  • nenhuma
Retorna:
  • string - O ID da transação.
GetTransactionTimestamp
Retorna o timestamp quando a transação foi criada. Como o valor é obtido da transação ChannelHeader, ele indica o timestamp do cliente e tem o mesmo valor em todos os endossadores.
func GetTransactionTimestamp() (*timestamp.Timestamp, error)
Parâmetros:
  • nenhuma
Retorna:
  • timestamp.Timestamp - O timestamp.
  • error - Contém o erro se um erro for retornado.
GetChannelID
Retorna o ID do canal da proposta para o chaincode a ser processado.
func GetChannelID() string
Parâmetros:
  • nenhuma
Retorna:
  • string - O ID do canal solicitado no formato de string.
GetCreator
Retorna o objeto de identidade do remetente da chamada de chaincode.
func GetCreator() ([]byte, error)
Parâmetros:
  • nenhuma
Retorna:
  • []byte - O objeto de identidade necessário em formato serializado.
  • error - Contém o erro se um erro for retornado.
GetSignedProposal
Retorna um objeto totalmente decodificado da proposta de transação assinada.
func GetSignedProposal() (*peer.SignedProposal, error)
Parâmetros:
  • nenhuma
Retorna:
  • *peer.SignedProposal - O objeto de proposta assinado.
  • error - Contém o erro se um erro for retornado.
GetArgs
Retorna os argumentos como um array de strings da solicitação de chamada de chaincode.
func GetArgs() [][]byte
Parâmetros:
  • nenhuma
Retorna:
  • [][]byte - Os argumentos informados.
GetStringArgs
Retorna os argumentos destinados aos métodos chaincode Init e Invoke como um array de string.
func GetStringArgs() []string
Parâmetros:
  • nenhuma
Retorna:
  • []string - Os argumentos como um array de string.
GetCreatorMspId
Retorna o ID do MSP da identidade de chamada.
func GetCreatorMspId() string
Parâmetros:
  • nenhuma
Retorna:
  • string - 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 (carimbo de data/hora).
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 métodos a seguir são fornecidos no pacote de utilitários.

Util.CreateModel
Faz parse da string JSON especificada e cria um objeto de ativo do tipo especificado.
func CreateModel(obj interface{}, inputString string) error
Parâmetros:
  • inputString (string) - A string JSON de entrada a ser usada para criar o objeto.
  • obj (interface{}) - A referência do objeto a 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 o erro se um erro for retornado ao criar ou validar o ativo.
util.ConvertMapToStruct
Converta o mapa especificado em um objeto do tipo especificado.
func ConvertMapToStruct(inputMap map[string](interface{}), resultStruct
interface{}) error
Parâmetros:
  • inputMap (map[string](interface{})) - O mapa a ser convertido em um objeto de ativo.
  • resultStruct (interface{}) - A referência do objeto do ativo a ser criado no mapa.
Retorna:
  • error - Contém o erro se um erro for retornado ao criar ou validar o ativo.

Para métodos de token SDK, consulte os tópicos em Suporte à 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 que são definidos na estrutura 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ê optar por gerar todos os métodos, o resultado será semelhante ao seguinte código:

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

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

É possível implementar a funcionalidade de acordo com a lógica de negócio necessária. Se você adicionar métodos personalizados, adicione-os ao arquivo do controlador. Se você adicionar métodos personalizados à biblioteca em vez do arquivo 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 chaincodes Go, cada método personalizado deve retornar dois valores: empty interface e error, conforme mostrado no seguinte exemplo:
func (t *Controller) FetchRawMaterial(supplierId string, rawMaterialSupply int) (interface{}, error) { 
    return nil, nil
}

Método Init

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, 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
}

Em seguida, você pode usar esse método para inicializar qualquer estado do aplicativo.