是否可以利用 Go 中的模块系统将链代码划分为多个文件?

Is it possible to divide chaincode in multiple files by taking advantage of module system in Go?

我目前将我的链代码放在一个文件中,并且随着我添加更多函数它变得越来越大,所以维护它真的很令人沮丧。

我认为在 Go 中利用模块系统是个好主意,但我想不出办法。

我有:

my_chaincode
├── go.mod
├── go.sum
└── chaincode.go (whole chaincode)

my_chaincode
├── go.mod
├── go.sum
├── modules
│   └── smartcontract.go  (All other functions)
└── chaincode.go          (Only main function)

我想要的:

my_chaincode
├── go.mod
├── go.sum
├── modules
│   ├── admin.go   (Some functions)
│   ├── system.go  (Some functions)
│   └── user.go    (Some functions)
└── chaincode.go   (Only main function)

(*注意:我有创建和使用 Go 模块的基本知识。)

我尝试划分链代码(就像我想要的那样)并部署链代码,但是当我尝试执行事务时,链代码容器崩溃并出现错误 -

status:500 message:"error in simulation: failed to execute transaction

我前两次尝试都没有发生这种情况。 我确定我缺乏一些关于 Go 模块的知识。

我错过了什么? 一些像 GitHub 结构像我想要的存储库这样的参考会很棒吗?

是的,可以使用 Go 模块。

让我用一个例子来解释,考虑如下文件结构

my_chaincode        (not necessary to use modules as folder name)
├── go.mod          (created after executing `go mod init`)
├── go.sum          (created after executing `go mod tidy`)
├── modules         (not necessary to use modules as folder name)
│   ├── module1.go  (Some functions)
│   ├── module2.go  (Some functions)
│   └── module3.go  (Some functions)
└── main.go         (not necessary to use "main" as file name)
  • 创建文件夹“my_chaincode”
  • cd my_chaincode
  • go mod init my_chaincode
// main.go

package main
import (
    "fmt"
    "github.com/hyperledger/fabric-contract-api-go/contractapi"

    "my_chaincode/modules"  // importing all files from modules folder
)

func main() {
    chaincode, err := contractapi.NewChaincode(new(modules.SmartContract))

    if err != nil {
        fmt.Printf("Error create chaincode: %s", err.Error())
        return
    }
    if err := chaincode.Start(); err != nil {
        fmt.Printf("Error starting chaincode: %s", err.Error())
    }
}
// modules/module1.go

package modules

type SmartContract struct {
    contractapi.Contract
}

type User struct {
    // anything
}

func (s *SmartContract) InitLedger(ctx contractapi.TransactionContextInterface) error {
    // your logic
}
// modules/module2.go

package modules

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

// private function (because name starts with a small letter)
func validateUid (uid string) (bool, error) {
    // your logic
}

// public function (because name starts with a capital letter)
func (s *SmartContract) Create_User (ctx contractapi.TransactionContextInterface, uid string, name string, age int) error {
    // your logic
    // you can use "validateUid(uid)" function here
}
// modules/module3.go

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

func (s *SmartContract) Create_Record (ctx contractapi.TransactionContextInterface, rid int, uid int) error {
    // your logic

    // you can use "validateUid(uid)" function here
    // you can use "User" struct here
    // you can use "ctx.Create_User(uid, 'user1', '20')" function here

    // all above uses may seem irrelevant, but my intention is to show
    // that you can directly use them without again defining in this file, 
    // which is the main goal. So, the whole chaincode can be divided 
    // into small modules.
}
  • go mod tidy
  • GO111MODULE=on go mod vendor -(可选,如果你知道它的作用)