Hyperledger fabric smart contract writing (1)

1. Differences in fabric chain code versions

Fabric chaincode is divided into two major versions, version 1.x and version 2.x. The main differences between the two are:
####1. Differences in imported packages
The packages imported by 1.x are:

"[github.com/hyperledger/fabric/core/chaincode/shim](http://github.com/hyperledger/fabric/core/chaincode/shim)"

  pb "[github.com/hyperledger/fabric/protos/peer](http://github.com/hyperledger/fabric/protos/peer)"

The packages imported by 2.0 are:

"[github.com/hyperledger/fabric-contract-api-go/contractapi](http://github.com/hyperledger/fabric-contract-api-go/contractapi)"

####2. Different method structures
There is no need for invoke and init methods in Fabric2.0 chaincode
####3. The formal parameter types and return values called in methods are different.
1.x method is:

createCar1(stub shim.ChaincodeStubInterface, args []string) pb.Response { }

The 2.x method is:

Create(ctx contractapi.TransactionContextInterface,key string,value string)error { }

###2. Simple analysis of contractapi package
image.png

As can be seen from the various simple Go chain codes provided by the official fabric-samples, generally our chain code method is to customize a SmartContract struct, which contains the Contract struct in the contractapi package. Contract struct implements the ContractInterface interface. The custom structure can quickly help my custom structure implement the ContractInterface interface by combining Contract horizontally.

type SimpleChaincode struct {
contractapi.Contract
}
type Contract struct {
Name string
Info metadata.InfoMetadata
UnknownTransaction interface{}
BeforeTransaction interface{}
AfterTransaction interface{}
TransactionContextHandler SettableTransactionContextInterface
}

ContractInterface defines the functionality a valid contract should have. Contracts used in chaincode must implement this interface. Therefore, applying chain code will directly nest contractapi.Contract in the chain code structure to implement the ContractInterface interface.

type ContractInterface interface {
//Get the metadata that currently describes the smart contract
GetInfo() metadata.InfoMetadata

//When the contract is converted to chain code, obtain the unknown transaction set in the contract
GetUnknownTransaction() interface{}

//Get the before transaction collection
GetBeforeTransaction() interface{}

//Get the after transaction collection
GetAfterTransaction() interface{}

//GetName returns the name of the contract. This function will be called when a contract is used to create a new chaincode, and the returned name will be used to identify the contract within the chaincode upon initialization/calling.
GetName() string

//GetTransactionContextHandler returns the SettableTransactionContextInterface used by the agreed function.
       //When the contract is converted to chaincode, this function will be called and the returned transaction context will be stored.
       //When the chaincode is called via init/Invoke, if the function requires a context in its parameter list, a transaction context of the storage type is created and sent as a parameter to the named contract's function (after, before and unknown functions) .
       //If a function that takes a transaction context uses an interface as the context, the transaction context returned by this function must satisfy the interface
GetTransactionContextHandler() SettableTransactionContextInterface
}

In addition to the normal chain code, the contractapi package also provides many extended functions of the normal chain code:

  • IgnoreContractInterface extends ContractInterface and provides additional functionality that can be used to mark which functions should not be accessed by calling/querying the chain code;

  • EvaluationContractInterface extends ContractInterface, indicating that these functions should be query (query) rather than invoke (call)

As can be seen from the above figure, the application structure we defined can be converted into a ContractChaincode structure by entering the NewChaincode(contracts…ContractInterface)(*ContractChainCode,error) function. The basic logic of NewChaincode is that this function parses each passed function. And store the composition details to be used by the chain code. The public functions of the contract are stored in the chain code and can be called. At the same time, the system contract is added to the chain code, which provides the function of obtaining chain code metadata. The generated metadata is a JSON-formatted MetadataContractChaincode containing the name of each contract and details of the public functions and types they accept/return. It also outlines the contract and chaincode version details.

At the same time, ContractChaincode implements the Chaincode interface, which is an interface that every chain code in fabric must implement. It provides Invoke and Init methods. This is the interactive interface of fabric1.x chain code. Fabric2.x chain code implementation is based on fabric1. x is encapsulated to facilitate developers to write chain codes.

###3. Simple analysis of shim package

3.1 shim package structure content

It is found in the contractapi package that the contractapi package encapsulates the shim just to facilitate interaction. The calling interface still needs to obtain the ChaincodeStub in the shim package.

func (t *SimpleChaincode) InitLedger(ctx contractapi.TransactionContextInterface) error {
key := "assetGlobal"
exist, err := ctx.GetStub().GetState(key)

type TransactionContextInterface interface {
// GetStub should provide a way to access the stub set by Init/Invoke
GetStub() shim.ChaincodeStubInterface
// GetClientIdentity should provide a way to access the client identity set by Init/Invoke
GetClientIdentity() cid.ClientIdentity
}

// ChaincodeStub is an object passed to chaincode for shim side handling of
//APIs.
type ChaincodeStub struct {
TxID string
ChannelID string
chaincodeEvent *pb.ChaincodeEvent
args[][]byte
handler *Handler
signedProposal *pb.SignedProposal
proposal *pb.Proposal
validationParameterMetakey string

// Additional fields extracted from the signedProposal
creator[]byte
transient map[string][]byte
binding[]byte

decorations map[string][]byte
}
`

The handler.go in the shim is the functional code for communication between the chain code service and the peer service. Currently, the main focus is on the API interfaces provided to interact with the ledger to facilitate learning and writing chain code. From interface.go, we can see that the chaincode’s interaction API with the ledger is mainly provided by ChaincodeStubInterface, and the remaining three Iterators are all iterator interfaces for ledger rich queries.

ChaincodeStubInterface is implemented by ChaincodeStub. By understanding the method of ChaincodeStub structure, we basically master the method of writing fabric chain code. You can also learn it from the official API document and the chain code example in fabric-sample.

2. API function classification

The most important (emphasis added three times) main function of the chain code is to operate the ledger, plus some additional functions such as msp identity authentication, with the purpose of operating the ledger more securely.

Auxiliary functions: such as parameter acquisition, transaction acquisition, network information acquisition, etc.

  • Parameter acquisition: This type of method is no longer needed in chain code 2.x. The NewChaincode method in the contractapi package has helped us fill in the parameters, allowing us to write chain code methods just like writing regular methods.
    – Functions to obtain information types: GetTxID(), GetChannel(), GetCreator(), GetSignedProposal(), GetTxTimestamp()
  • Status operation: operate on the K-V of the ledger
    1. Read and write: PutState, DelState, GetStateByRange, GetStateByRangeWithPagination, GetHistoryForKey
    2. Composite keys: SplitCompositeKey, CreateCompositeKey, GetStateByPartialCompositeKey, GetStateByPartialCompositeKeyWithPagination
    3. Endorsement policy settings for this Key: SetStateValidationParameter, GetStateValidationParameter
  • Private database operations:
    1. Read and write: GetPrivateData, GetPrivateDataHash (convenient for non-private members to verify transactions, only the Hash of data can be read), PutPrivateData, DelPrivateData, PurgePrivateData, GetPrivateDataByRange
    2. Key-level endorsement policy settings: SetPrivateDataValidationParameter, GetPrivateDataValidationParameter
    3. Composite key: GetPrivateDataByPartialCompositeKey
  • Rich query: GetQueryResult, GetPrivateDataQueryResult
  • Transient data: GetTransient (Transient data is mainly to protect data. Literally, the data passed in through transient data will not be stored permanently. There will be special data to temporarily store it. Currently it can only be used to transfer structures. data)
  • Event setting: SetEvent (mainly bound to the event set after the execution of a special function. Only one Event can be set in a method. If two Events are set, the first Event will be overwritten by the second Event)
  • GetBinding: Returns the transaction binding that is used to enforce the link between the application data (such as the data stored in the transient fields above) and the proposal itself. Helps avoid possible replay attacks.
  • GetDecorations: Returns additional data about proposals originating from the peer (if applicable). These data are set by decorators on the peer that append or mutate the chaincode inputs passed to the chaincode.

Original link:
https://blog.csdn.net/weixin_43274469/article/details/129643800