fabric2.3链码学习小记

最近实验室的项目要部署到fabric2.0以上版本,之前写的都是1.4的链码,现在看2.0版本的链码还是有些不一样的,主要是链码api改了:

下面实例这个链码:

package chaincode

import (
    "encoding/json"
    "fmt"

    "github.com/hyperledger/fabric-contract-api-go/contractapi"
)

// SmartContract provides functions for managing an Asset
type SmartContract struct {
    contractapi.Contract
}

// Asset describes basic details of what makes up a simple asset
type Asset struct {
    ID             string `json:"ID"`
    Color          string `json:"color"`
    Size           int    `json:"size"`
    Owner          string `json:"owner"`
    AppraisedValue int    `json:"appraisedValue"`
}

// InitLedger adds a base set of assets to the ledger
func (s *SmartContract) InitLedger(ctx contractapi.TransactionContextInterface) error {
    assets := []Asset{
        {ID: "asset1", Color: "blue", Size: 5, Owner: "Tomoko", AppraisedValue: 300},
        {ID: "asset2", Color: "red", Size: 5, Owner: "Brad", AppraisedValue: 400},
        {ID: "asset3", Color: "green", Size: 10, Owner: "Jin Soo", AppraisedValue: 500},
        {ID: "asset4", Color: "yellow", Size: 10, Owner: "Max", AppraisedValue: 600},
        {ID: "asset5", Color: "black", Size: 15, Owner: "Adriana", AppraisedValue: 700},
        {ID: "asset6", Color: "white", Size: 15, Owner: "Michel", AppraisedValue: 800},
    }

    for _, asset := range assets {
        assetJSON, err := json.Marshal(asset)
        if err != nil {
            return err
        }

        err = ctx.GetStub().PutState(asset.ID, assetJSON)
        if err != nil {
            return fmt.Errorf("failed to put to world state. %v", err)
        }
    }

    return nil
}

// CreateAsset issues a new asset to the world state with given details.
func (s *SmartContract) CreateAsset(ctx contractapi.TransactionContextInterface, id string, color string, size int, owner string, appraisedValue int) error {
    exists, err := s.AssetExists(ctx, id)
    if err != nil {
        return err
    }
    if exists {
        return fmt.Errorf("the asset %s already exists", id)
    }

    asset := Asset{
        ID:             id,
        Color:          color,
        Size:           size,
        Owner:          owner,
        AppraisedValue: appraisedValue,
    }
    assetJSON, err := json.Marshal(asset)
    if err != nil {
        return err
    }

    return ctx.GetStub().PutState(id, assetJSON)
}

// ReadAsset returns the asset stored in the world state with given id.
func (s *SmartContract) ReadAsset(ctx contractapi.TransactionContextInterface, id string) (*Asset, error) {
    assetJSON, err := ctx.GetStub().GetState(id)
    if err != nil {
        return nil, fmt.Errorf("failed to read from world state: %v", err)
    }
    if assetJSON == nil {
        return nil, fmt.Errorf("the asset %s does not exist", id)
    }

    var asset Asset
    err = json.Unmarshal(assetJSON, &asset)
    if err != nil {
        return nil, err
    }

    return &asset, nil
}

// UpdateAsset updates an existing asset in the world state with provided parameters.
func (s *SmartContract) UpdateAsset(ctx contractapi.TransactionContextInterface, id string, color string, size int, owner string, appraisedValue int) error {
    exists, err := s.AssetExists(ctx, id)
    if err != nil {
        return err
    }
    if !exists {
        return fmt.Errorf("the asset %s does not exist", id)
    }

    // overwriting original asset with new asset
    asset := Asset{
        ID:             id,
        Color:          color,
        Size:           size,
        Owner:          owner,
        AppraisedValue: appraisedValue,
    }
    assetJSON, err := json.Marshal(asset)
    if err != nil {
        return err
    }

    return ctx.GetStub().PutState(id, assetJSON)
}

// DeleteAsset deletes an given asset from the world state.
func (s *SmartContract) DeleteAsset(ctx contractapi.TransactionContextInterface, id string) error {
    exists, err := s.AssetExists(ctx, id)
    if err != nil {
        return err
    }
    if !exists {
        return fmt.Errorf("the asset %s does not exist", id)
    }

    return ctx.GetStub().DelState(id)
}

// AssetExists returns true when asset with given ID exists in world state
func (s *SmartContract) AssetExists(ctx contractapi.TransactionContextInterface, id string) (bool, error) {
    assetJSON, err := ctx.GetStub().GetState(id)
    if err != nil {
        return false, fmt.Errorf("failed to read from world state: %v", err)
    }

    return assetJSON != nil, nil
}

// TransferAsset updates the owner field of asset with given id in world state.
func (s *SmartContract) TransferAsset(ctx contractapi.TransactionContextInterface, id string, newOwner string) error {
    asset, err := s.ReadAsset(ctx, id)
    if err != nil {
        return err
    }

    asset.Owner = newOwner
    assetJSON, err := json.Marshal(asset)
    if err != nil {
        return err
    }

    return ctx.GetStub().PutState(id, assetJSON)
}

// GetAllAssets returns all assets found in world state
func (s *SmartContract) GetAllAssets(ctx contractapi.TransactionContextInterface) ([]*Asset, error) {
    // range query with empty string for startKey and endKey does an
    // open-ended query of all assets in the chaincode namespace.
    resultsIterator, err := ctx.GetStub().GetStateByRange("", "")
    if err != nil {
        return nil, err
    }
    defer resultsIterator.Close()

    var assets []*Asset
    for resultsIterator.HasNext() {
        queryResponse, err := resultsIterator.Next()
        if err != nil {
            return nil, err
        }

        var asset Asset
        err = json.Unmarshal(queryResponse.Value, &asset)
        if err != nil {
            return nil, err
        }
        assets = append(assets, &asset)
    }

    return assets, nil
}

首先这里执行完初始化链码之后:

peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" -C mychannel -n basic --peerAddresses localhost:7051 --tlsRootCertFiles "${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt" --peerAddresses localhost:9051 --tlsRootCertFiles "${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt" -c '{"function":"InitLedger","Args":[]}'

这里记住一个模板:

就是peer chiancode invoke ....... -c '{"function":"函数名","Args":[参数]}'

function就是我们链码里的函数名!

2.0的链码是不需要初始化链码的,1.4版本的是需要的,这里2.0的就按照上面的模板就行,注意,参数这里不管链码里传入上面参数,这里都是用字符串格式,比如,int的4也要写成"4"。

注意,如果你想继续用的1.4的链码也可以,将1.4链码原来的包改成这样就可以在2.0环境中继续使用了!

fabric2.3链码学习小记_第1张图片

如果你想使用2.0以上版本的链码,需要用的是这个api:

fabric2.3链码学习小记_第2张图片

这里注意,2.0的链码,传参数的时候是不能使用args []string的,如果是1.4的链码是可以的。

这里注意,如果想在2.0链码环境中使用如1.4的传入多个参数 args []string的话,可以用这个api:

function, args := ctx.GetStub().GetFunctionAndParameters()

这里注意,这里的function就是Testargs,后面args直接传入4个args参数即可!

根据返回的args,就是之前在1.4环境中的args!

贴上自己写的链码方法demo:

//-c '{"function":"Testargs","Args":["01","fanwen","dayang","man"]}'
//这里注意args后面传入的参数就是args,function是不需要传入的,不然就会报错"err! number is not 4!",这里是和1.4不一样的地方
func (t *mycc) Testargs(ctx contractapi.TransactionContextInterface) string{
	function, args := ctx.GetStub().GetFunctionAndParameters()//这里的function就是获取了上面的函数名就是Testargs
	if len(args) != 4 {
		return "err! number is not 4!"
	}
	stu := Student{
		StuId:   args[0],
		Name:    args[1],
		Address: args[2],
		Sex:     args[3],
	}
	assetJSON, err := json.Marshal(stu)
	if err != nil {
		return err.Error()
	}
	//根据StuId存入账本
	err = ctx.GetStub().PutState(stu.StuId, assetJSON)
	if err != nil{
		return err.Error()
	}
	return "you use the function:" + function + " put in state ok!"

}

执行效果:

fabric2.3链码学习小记_第3张图片

如果在args输入了超过4个参数:

 fabric2.3链码学习小记_第4张图片

就会报错,就是我们在链码里自己写的逻辑判断的错误! 

这里注意,fabric在2.0版本以上的链码中,可以返回任何数据!比如string,int,float64,或者是自定义的结构体或者结构体指针都可以!

注意:传参数的时候,不管传什么参数,在cli端,都是传入的"内容",也就是字符串形式传入的!

如果是查询操作的话,不需要连接orderer结点,也不需要背书策略,直接用以下模板就行:

peer chaincode query -C mychannel -n fan12 -c '{"function":"GetAll","Args":["args"]}'

fabric2.3链码学习小记_第5张图片

当然,如果用invoke也可以!看个人习惯。

 

 

你可能感兴趣的:(区块链,docker,学习)