Skip to content

Commit

Permalink
Refactor and document
Browse files Browse the repository at this point in the history
  • Loading branch information
eledra89 committed Apr 11, 2021
1 parent 7fb4d6f commit debc111
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 116 deletions.
23 changes: 22 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,29 @@

[![Go Report Card](https://goreportcard.com/badge/github.com/Akachain/akc-go-sdk-v2)](https://goreportcard.com/report/github.com/Akachain/akc-go-sdk-v2)

golang SDK that supports writing chaincodes on Hyperledger Fabric version 2+
golang SDK that supports writing chaincodes on Hyperledger Fabric version 2+ with minimum setup.

We have written a few dozen of complex chaincodes for production environment of enterprise use cases since 2018.
We found that it would give junior developers tremendous help if they are provided with several utilities to
quickly interact with the state database as well as mockup tool to quickly test their chaincode without requiring a real Hyperledger Fabric Peer.

### Getting started
Obtaining the Akachain go SDK package

``
go get https://github.com/Akachain/akc-go-sdk-v2
``

We recommend to use the SDK with ``gomod``

### Documentation

Our document is available at [pkg.go.dev](https://pkg.go.dev/github.com/Akachain/akc-go-sdk-v2)

### Examples
Sample Test Code is available at

[sample_test](test/contract/sample_test.go): Basic example that uses SDK to query and execute transaction with a CouchDB state database

### License
This source code are made available under the MIT license, located in the [LICENSE](LICENSE) file. You can do whatever you want with them, we do not bother. But if you have some nice idea that wants to share back with us, please do.
Expand Down
10 changes: 6 additions & 4 deletions doc.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
// Package akc_go_sdk_v2 provide core functions for developers to build a robust chaincode
// with minimum setup. We have written a few dozen of complex chaincode for production environment
// with minimum setup. There are 2 main sub packages to use
//
// Packages for end developer usages
//
// Packages for end developer usage
// akc-go-sdk-v2/util provides CRUD utilities to work with CouchDB State Database
// Reference: https://pkg.go.dev/github.com/Akachain/akc-go-sdk-v2/util
//
// smartcontract: Provides methods for initializing the platform and interact with the token
// management engine
// akc-go-sdk-v2/mock provides testing suit to connect to a CouchDB instance and run the chaincode code against it.
// Reference: https://pkg.go.dev/github.com/Akachain/akc-go-sdk-v2/mock
//
package akc_go_sdk_v2
15 changes: 15 additions & 0 deletions mock/mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,21 @@
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

// Package mock provides mock methods to simulate how a peer node interact with CouchDB
// and simulate a transaction proposal. This does not requires a working Fabric Peer like
// FabricSDK but require connection to a remote CouchDB instance.
//
// The workflow is as follow
//
// 1) Create a core.yaml follow similar template in test/contract/core.yaml, remember to change the configuration of the couchDB as you need
//
// 2) Create a NewMockStubExtend object that point to the core.yaml and the smart contract object
//
// 3) Process Indexes (if need)
//
// 4) Perform MockInvokeTransaction
//
// For more details, please find test example in the README file
package mock

import (
Expand Down
6 changes: 5 additions & 1 deletion test/contract/sample.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

// Package contract provides a sample smart contract.
// it uses util package to interact with the state database
// it also uses mock package to quickly test the solution
// by connecting to a remote couchDB instance.
package contract

import (
Expand All @@ -39,5 +43,5 @@ type SampleData struct {

// Create something
func (s *SampleContract) CreateSampleObject(ctx contractapi.TransactionContextInterface, key string, val string) error {
return util.Createdata(ctx.GetStub(), DocPrefix, []string{key}, &SampleData{Key1: key, Attribute1: val})
return util.CreateData(ctx.GetStub(), DocPrefix, []string{key}, &SampleData{Key1: key, Attribute1: val})
}
164 changes: 54 additions & 110 deletions util/daoHandle.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,83 +28,65 @@ import (
"github.com/Akachain/akc-go-sdk-v2/common"

"github.com/hyperledger/fabric-chaincode-go/shim"
pb "github.com/hyperledger/fabric-protos-go/peer"
"github.com/hyperledger/fabric-protos-go/peer"
"github.com/mitchellh/mapstructure"
)

// Update Infomation
func Changeinfo(stub shim.ChaincodeStubInterface, TableModel string, row_key []string, data interface{}) error {
_, err := InsertTableRow(stub, TableModel, row_key, data, FAIL_UNLESS_OVERWRITE, nil)
// ChangeInfo overwrites a value in the state database by performing an insert with
// overwrite indicator
func ChangeInfo(stub shim.ChaincodeStubInterface, DocPrefix string, rowKey []string, data interface{}) error {
_, err := InsertTableRow(stub, DocPrefix, rowKey, data, FAIL_UNLESS_OVERWRITE, nil)
return err
}

// UpdateExistingData works similar to Changeinfo.
// UpdateExistingData works similar to ChangeInfo function.
// However, it does not check if the document is already existed
// This is useful if we already query out the row before and do not want to query again.
func UpdateExistingData(stub shim.ChaincodeStubInterface, TableModel string, row_key []string, data interface{}) error {
err := UpdateTableRow(stub, TableModel, row_key, data)
func UpdateExistingData(stub shim.ChaincodeStubInterface, DocPrefix string, rowKey []string, data interface{}) error {
err := UpdateTableRow(stub, DocPrefix, rowKey, data)
return err
}

//create data
func Createdata(stub shim.ChaincodeStubInterface, TableModel string, row_key []string, data interface{}) error {
var old_data interface{}
row_was_found, err := InsertTableRow(stub, TableModel, row_key, data, FAIL_BEFORE_OVERWRITE, &old_data)
// CreateData simply inserts a new key-value pair into the state database. It will fail if the key already
// exists. The pair is formatted as follows.
//
// Key: DocPrefix_rowKey[0]_rowKey[1]_..._rowKey[n]_randomId
// Value: JSON document parsed from the data object.
func CreateData(stub shim.ChaincodeStubInterface, DocPrefix string, rowKey []string, data interface{}) error {
var oldData interface{}
rowWasFound, err := InsertTableRow(stub, DocPrefix, rowKey, data, FAIL_BEFORE_OVERWRITE, &oldData)
if err != nil {
return err
}
if row_was_found {
if rowWasFound {
return fmt.Errorf("Could not create data %v because an data already exists", data)
}
return nil //success
}

//get information of data by ID
func Getdatabyid(stub shim.ChaincodeStubInterface, ID string, MODELTABLE string) (interface{}, error) {
var datastruct interface{}
// GetDataById get the state value of a key from the state database
// It returns a generic object.
func GetDataById(stub shim.ChaincodeStubInterface, ID string, DocPrefix string) (interface{}, error) {
var dataStruct interface{}

row_was_found, err := GetTableRow(stub, MODELTABLE, []string{ID}, &datastruct, FAIL_IF_MISSING)
rowWasFound, err := GetTableRow(stub, DocPrefix, []string{ID}, &dataStruct, FAIL_IF_MISSING)

if err != nil {
return nil, err
}
if !row_was_found {
if !rowWasFound {
return nil, fmt.Errorf("Data with ID %s does not exist", ID)
}
return datastruct, nil
}

//get information of data by row keys
func Getdatabyrowkeys(stub shim.ChaincodeStubInterface, rowKeys []string, MODELTABLE string) (interface{}, error) {
var datastruct interface{}

row_was_found, err := GetTableRow(stub, MODELTABLE, rowKeys, &datastruct, FAIL_IF_MISSING)

if err != nil {
return nil, err
}
if !row_was_found {
return nil, fmt.Errorf("Data with rowKeys %s does not exist", rowKeys)
}
return datastruct, nil
return dataStruct, nil
}

//get all data
func Getalldata(stub shim.ChaincodeStubInterface, MODELTABLE string) (chan []byte, error) {
row_json_bytes, err := GetTableRows(stub, MODELTABLE, []string{})
if err != nil {
return nil, fmt.Errorf("Could not get %v", err.Error())
}
return row_json_bytes, nil
}

// GetDataByID
func GetDataByID(stub shim.ChaincodeStubInterface, DataID string, data interface{}, ModelTable string) pb.Response {

rs, err := Getdatabyid(stub, DataID, ModelTable)
// GetDataByIdWithResponse returns the peer.Response object directly to the caller so that
// the caller does not have to format it into Fabric response.
func GetDataByIdWithResponse(stub shim.ChaincodeStubInterface, DataID string, data interface{}, ModelTable string) peer.Response {
rs, err := GetDataById(stub, DataID, ModelTable)
if err != nil {
//Get Data Fail
resErr := common.ResponseError{common.ERR4, fmt.Sprintf("%s %s %s", common.ResCodeDict[common.ERR4], err.Error(), common.GetLine())}
resErr := common.ResponseError{ResCode: common.ERR4, Msg: fmt.Sprintf("%s %s %s", common.ResCodeDict[common.ERR4], err.Error(), common.GetLine())}
return common.RespondError(resErr)
}
if rs != nil {
Expand All @@ -115,21 +97,38 @@ func GetDataByID(stub shim.ChaincodeStubInterface, DataID string, data interface
bytes, err := json.Marshal(data)
if err != nil {
//Convert Json Fail
resErr := common.ResponseError{common.ERR3, fmt.Sprintf("%s %s %s", common.ResCodeDict[common.ERR3], err.Error(), common.GetLine())}
resErr := common.ResponseError{ResCode: common.ERR3, Msg: fmt.Sprintf("%s %s %s", common.ResCodeDict[common.ERR3], err.Error(), common.GetLine())}
return common.RespondError(resErr)
}
fmt.Printf("Response: %s\n", string(bytes))
resSuc := common.ResponseSuccess{common.SUCCESS, common.ResCodeDict[common.SUCCESS], string(bytes)}
resSuc := common.ResponseSuccess{ResCode: common.SUCCESS, Msg: common.ResCodeDict[common.SUCCESS], Payload: string(bytes)}
return common.RespondSuccess(resSuc)
}

// GetDataByKey
func GetDataByRowKeys(stub shim.ChaincodeStubInterface, rowKeys []string, data interface{}, ModelTable string) pb.Response {
// GetDataByRowKeys returns the state value of a key that is constructed with only document prefix
// and rowKeys. This is used for documents that we don't need random generated value in the key.
func GetDataByRowKeys(stub shim.ChaincodeStubInterface, rowKeys []string, DocPrefix string) (interface{}, error) {
var dataStruct interface{}

rowWasFound, err := GetTableRow(stub, DocPrefix, rowKeys, &dataStruct, FAIL_IF_MISSING)

if err != nil {
return nil, err
}
if !rowWasFound {
return nil, fmt.Errorf("Data with rowKeys %s does not exist", rowKeys)
}
return dataStruct, nil
}

// GetDataByRowKeysWithResponse returns the peer.Response directly to the caller so that
// the caller does not have to format it into Fabric response
func GetDataByRowKeysWithResponse(stub shim.ChaincodeStubInterface, rowKeys []string, data interface{}, ModelTable string) peer.Response {

rs, err := Getdatabyrowkeys(stub, rowKeys, ModelTable)
rs, err := GetDataByRowKeys(stub, rowKeys, ModelTable)
if err != nil {
//Get Data Fail
resErr := common.ResponseError{common.ERR4, fmt.Sprintf("%s %s %s", common.ResCodeDict[common.ERR4], err.Error(), common.GetLine())}
resErr := common.ResponseError{ResCode: common.ERR4, Msg: fmt.Sprintf("%s %s %s", common.ResCodeDict[common.ERR4], err.Error(), common.GetLine())}
return common.RespondError(resErr)
}
if rs != nil {
Expand All @@ -141,65 +140,10 @@ func GetDataByRowKeys(stub shim.ChaincodeStubInterface, rowKeys []string, data i
bytes, err := json.Marshal(data)
if err != nil {
//Convert Json Fail
resErr := common.ResponseError{common.ERR3, fmt.Sprintf("%s %s %s", common.ResCodeDict[common.ERR3], err.Error(), common.GetLine())}
resErr := common.ResponseError{ResCode: common.ERR3, Msg: fmt.Sprintf("%s %s %s", common.ResCodeDict[common.ERR3], err.Error(), common.GetLine())}
return common.RespondError(resErr)
}
fmt.Printf("Response: %s\n", string(bytes))
resSuc := common.ResponseSuccess{common.SUCCESS, common.ResCodeDict[common.SUCCESS], string(bytes)}
return common.RespondSuccess(resSuc)
}

// GetAllData
func GetAllData(stub shim.ChaincodeStubInterface, data interface{}, ModelTable string) pb.Response {

// var Datalist []interface{}
var Datalist = make([]map[string]interface{}, 0)

datalbytes, err := Getalldata(stub, ModelTable)
if err != nil {
//Get Data Fail
resErr := common.ResponseError{common.ERR4, fmt.Sprintf("%s %s %s", common.ResCodeDict[common.ERR4], err.Error(), common.GetLine())}
return common.RespondError(resErr)
}

for row_json_bytes := range datalbytes {

err := json.Unmarshal(row_json_bytes, data)
if err != nil {
resErr := common.ResponseError{common.ERR3, common.ResCodeDict[common.ERR6]}
return common.RespondError(resErr)
}

bytes, err := json.Marshal(data)
if err != nil {
//convert JSON eror
resErr := common.ResponseError{common.ERR3, common.ResCodeDict[common.ERR6]}
return common.RespondError(resErr)
}

var temp map[string]interface{}
err = json.Unmarshal(bytes, &temp)
if err != nil {
resErr := common.ResponseError{common.ERR3, common.ResCodeDict[common.ERR6]}
return common.RespondError(resErr)
}
Datalist = append(Datalist, temp)
}

//if err != nil {
// //Get data eror
// resErr := common.ResponseError{common.ERR3, common.ResCodeDict[common.ERR3]}
// return common.RespondError(resErr)
//}

fmt.Printf("Datalist: %v\n", Datalist)
dataJson, err2 := json.Marshal(Datalist)
if err2 != nil {
//convert JSON eror
resErr := common.ResponseError{common.ERR6, common.ResCodeDict[common.ERR6]}
return common.RespondError(resErr)
}
fmt.Printf("Response: %s\n", string(dataJson))
resSuc := common.ResponseSuccess{common.SUCCESS, common.ResCodeDict[common.SUCCESS], string(dataJson)}
resSuc := common.ResponseSuccess{ResCode: common.SUCCESS, Msg: common.ResCodeDict[common.SUCCESS], Payload: string(bytes)}
return common.RespondSuccess(resSuc)
}

0 comments on commit debc111

Please sign in to comment.