I currently have my chaincode in a single file and it's getting bigger as I am adding more functions, so it's really frustrating to maintain it.
I thought it's good idea to take advantage of module system in Go, But I can't figure out the way.
What I have:
my_chaincode
├── go.mod
├── go.sum
└── chaincode.go (whole chaincode)
AND
my_chaincode
├── go.mod
├── go.sum
├── modules
│ └── smartcontract.go (All other functions)
└── chaincode.go (Only main function)
What I want:
my_chaincode
├── go.mod
├── go.sum
├── modules
│ ├── admin.go (Some functions)
│ ├── system.go (Some functions)
│ └── user.go (Some functions)
└── chaincode.go (Only main function)
(*Note: I have a basic knowledge of creating and using Go modules.)
I tried dividing the chaincode (like What I want) and deployed the chaincode, but when I try to execute a transaction the chaincode container crashes with error -
status:500 message:"error in simulation: failed to execute transaction
This doesn't happen with my previous two attempts. I am sure that I am lacking some knowledge regarding Go modules.
What am I missing? Some reference like a GitHub repository with structure like what I want will be great?
Yes, it is possible using Go modules.
Let me explain using a example, consider file structure like below
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)
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
- (optional, if you know what it does)