Using instances of generic types as return value type in a Hyperledger chain code written in GO - go

In my project, I am using a wrapper structure, that is defined similar to this:
type Wrapper[T any] struct {
Foo int
Data T
}
Additionally, my chain code offers a method with the following signature
func(contract *MyContract) DoSomething() *Wrapper[mypkg.Bar]
where Bar is a simple structure defined - for example - like this:
package mypkg
struct Bar {
Foo string
Bar string
}
Anyhow, if I try to deploy my chaincode, I get the following error:
Error compiling schema for MyContract[DoSomething]. Return schema invalid. Object has no key 'Wrapper[[]<part of module name>'
Strangely, the part with Wrapper[[]<part of module name> is cropped. So only part of the module name is showing, and, as you can see, the bracketing is wrong: The second closing bracket is missing (so that is not a mistake made by me). The name of my module is the link to the GitHub repository.
I have tried to manually replace the generic type T in Wrapper with Bar by creating the structure
type WrapperBar struct {
Foo int
Data Bar
}
If I now adapt the function signature to
func(contract *MyContract) DoSomething() *WrapperBar
it works just fine. Unfortunately, I am using the structure Wrapper several times with different
type instantiations. So although creating all the types manually would be a workaround, it is obviously not a very elegant one.
Is there another workaround so that I can still use my generic Wrapper structure?
I am currently using go in version 1.18 and fabric-contract-api-go in version v1.1.1.

The Go contract-api at this time doesn't support Go Generics, the only workarounds I can suggest are the one that you have tried noted in this question or to write your chaincode without using the contract API, there is an example here https://github.com/hyperledger/fabric-samples/tree/main/chaincode/marbles02/go of an implementation that doesn't use the contract-api.
Your implemention will have to do more work in your chaincode such as providing your own method dispatching, validating and unmarshalling the input data
You could raise an issue at https://github.com/hyperledger/fabric-contract-api-go and ideally also contribute a PR that addresses this issue as I can't say when or if this would ever be supported.

Related

Interface management in Go

I know this has been asked in various forms many times before but I just can't seem to implement what I'm learning in the way that I need. Any help is appreciated.
I have a series of exchanges which all implement roughly the same APIs. For example, each of them have a GetBalance endpoint. However, some have one or two unique things which need to be accessed within the functions. For example, exchange1 needs to use a client when calling it's balance API, while exchange2 requires both the client variable as well as a clientFutures variable. This is an important note for later.
My background is normal OOP. Obviously Go is different in many ways, hence I'm getting tripped up here.
My current implementation and thinking is as follows:
In exchanges module
type Balance struct {
asset string
available float64
unavailable float64
total float64
}
type Api interface {
GetBalances() []Balance
}
In Binance module
type BinanceApi struct {
key string
secret string
client *binance.Client
clientFutures *futures.Client
Api exchanges.Api
}
func (v *BinanceApi) GetBalance() []exchanges.Balance {
// Requires v.client and v.clientFutures
return []exchanges.Balance{}
}
In Kraken module
type KrakenApi struct {
key string
secret string
client *binance.Client
Api exchanges.Api
}
func (v *KrakenApi) GetBalance() []exchanges.Balance {
// Requires v.client
return []exchanges.Balance{}
}
In main.go
var exchange *Api
Now my thought was I should be able to call something like exchange.GetBalance() and it would use the GetBalance function from above. I would also need some kind of casting? I'm quite lost here. The exchange could either be Binance or Kraken--that gets decided at runtime. Some other code basically calls a GetExchange function which returns an instance of the required API object (already casted in either BinanceApi/KrakenApi)
I'm aware inheritance and polymorphism don't work like other languages, hence my utter confusion. I'm struggling to know what needs to go where here. Go seems to require loads of annoying code necessary for what other languages do on the fly 😓
using *exchanges.Api is quite weird. You're wanting something that implements a given interface. What the underlying type is (whether it's a pointer or a value receiver) is not important, so use exchanges.Api instead.
There is another issue, though. In golang, interfaces are implicit (sometimes referred to as duck-type interfaces). Generally speaking, this means that the interface is not declared in the package that implements it, but rather in the package that depends on a given interface. Some say that you should be liberal in terms of what values you return, but restrictive in terms of what arguments you accept. What this boils down to in your case, is that you'd have something like an api package, that looks somewhat like this:
package api
func NewKraken(args ...any) *KrakenExchange {
// ...
}
func NewBinance(args ...any) *BinanceExchange {
}
then in your other packages, you'd have something like this:
package kraken // or maybe this could be an exchange package
type API interface {
GetBalances() []types.Balance
}
func NewClient(api API, otherArgs ...T) *KrakenClient {
}
So when someone looks at the code for this Kraken package, they can instantly tell what dependencies are required, and what types it works with. The added benefit is that, should binance or kraken need additional API calls that aren't shared, you can go in and change the specific dependencies/interfaces, without ending up with one massive, centralised interface that is being used all over the place, but each time you only end up using a subset of the interface.
Yet another benefit of this approach is when writing tests. There are tools like gomock and mockgen, which allow you to quickly generate mocks for unit tests simply by doing this:
package foo
//go:generate go run github.com/golang/mock/mockgen -destination mocks/dep_mock.go -package mocks your/module/path/to/foo Dependency
type Dependency interface {
// methods here
}
Then run go generate and it'll create a mock object in your/module/path/to/foo/mocks that implements the desired interface. In your unit tests, import he mocks package, and you can do things like:
ctrl := gomock.NewController(t)
dep := mocks.NewDependencyMock(ctrl)
defer ctrl.Finish()
dep.EXPECT().GetBalances().Times(1).Return(data)
k := kraken.NewClient(dep)
bal := k.Balances()
require.EqualValues(t, bal, data)
TL;DR
The gist of it is:
Interfaces are interfaces, don't use pointers to interfaces
Declare interfaces in the package that depends on them (ie the user), not the implementation (provider) side.
Only declare methods in an interface if you are genuinely using them in a given package. Using a central, overarching interface makes this harder to do.
Having the dependency interface declared along side the user makes for self-documenting code
Unit testing and mocking/stubbing is a lot easier to do, and to automate this way

Golang gRPC database serialization key format defined on struct

I want to use the go structs that are generated by the gRPC compiler directly for database transactions but the problem is that only the json serialization field is set by gRPC.
Is there a way to either set additional serialization keys (like shown below) or is there another golang specific way to tell the database driver (sqlx on top of database/sql) that the json key format should be used?
Some example - The gRPC compiler creates the following struct:
type HelloWorld struct {
TraceId string `protobuf:"bytes,1,opt,name=trace_id,json=traceId,proto3" json:"trace_id,omitempty"`
...
What I would like to have:
type HelloWorld struct {
TraceId string `db:"trace_id" protobuf:"bytes,1,opt,name=trace_id,json=traceId,proto3" json:"trace_id,omitempty"`
...
A temporary workaround would be to write sql queries that use aliases (traceid instead of trace_id in this example) but it doesn't feel consistent and adds a lot of complexity.
I think that currently there is no built-in way of doing this. However, you might be interested in following this thread: https://github.com/golang/protobuf/issues/52
Other than that I think you can just create yet another struct for database access and make the mapping explicit which might be more readable.

Inheritance in golang

I'm trying to create a template method that should be executed a certain other method is called.
For example:
func main(){
onInit()
}
func onInit(){
var Instance entity.EntityInstance
Instance.Init()
//do something
}
Another source file, instance.go
type EntityInstance struct{
name string
version string
}
func (instance *EntityInstance) Init(){
// do some initialization
}
The main method is in different code base/app and uses the Instance app to invoke certain initializations.
Currently the user writing this above main method needs to explicitly call the Instance.init()
The objective is for the developers (in this case one who implements the main method) only concern themselves with any of their custom initializations and not worry about calling "Instance.Init()". The OnInit() invoke should take care of "Instance.Init()" implicitly.
Any help to get me started in the right direction ?
EDIT: I do understand that the exact OOP concepts cannot be translated here in Golang but all I'm looking for is the appropriate approach. Clearly, I need to change the way I think of design in here but just don't know how.
Your question is a little unclear, I suspect because you are trying to directly translate ideas and idioms from another language, you should resist doing that. However, if you want an implicit init for a package in Go, you can use the magic function name
func init(){}
https://golang.org/doc/effective_go.html#init
Finally, each source file can define its own niladic init function to
set up whatever state is required. (Actually each file can have
multiple init functions.) And finally means finally: init is called
after all the variable declarations in the package have evaluated
their initializers, and those are evaluated only after all the
imported packages have been initialized.
Be careful with this though, it is implicit behaviour and could cause mysterious bugs if your callers don't know it is happening when they import your package.

How to define a struct globally and reuse it packages

Im very new to Go and have this "design" problem.
I have a main program passing jobs through channels. Each job will end up in a function defined in separate "worker" packages. Jobs are structs.
Now i want each function called, to return result as a common struct through a "result" channel. But the package doesnt know about the struct definition i have in main and so i cannot define it.
package main
type resultEvent struct {
name string
desc string
}
Then in a worker package:
package worker
func Test() {
result := &resultEvent{name: "test"}
}
Of course the idea is to eventually send this result down a channel, but even this simple example wont work, because worker doesnt know about resultEvent.
What would be the correct way of doing this?
Update:
It should be noted that there will be many worker packages, doing different things. Sorta like "plugins" (only not pluggable at all).
I dont want to define a redundant struct in each go-file and then have to maintain that over maybe 50 very different worker-packages.
Im looking for what would be the correct way to structure this, so i can reuse one struct for all worker-packages.
Basically, anything that lives in package main will only ever be able to be referenced from that pacakge. If you want it to be shared between multiple packages, put it in the worker package and export it (Upper case the first letter), then import worker from main.
No matter what, you will have to import the package which contains the type you'd like to use. However, the reason this isn't working for you is because your type is not exported. You need to uppercase the types name like;
type ResultEvent struct {
name string
desc string
}
Worth checking out what exported vs unexported means but basically upper case means exported which is similar to the public specifier in other systems languages. Lower case means unexported which is more like internal or private.
As pointed out in the comment and other answer you can't import main so I believe you'll have to move your types definition as well.
One possible way would be something like:
package workerlib
type ResultEvent struct {
Name string // Export the struct fields, unless you have a
Description string // real good reason not to.
}
Then stick the rest of the worker utility functions in that package. Unless you provide suitable methods to read the name and description from an event, simply export the fields. If you have an absolute need to make them changeable only from within the package they're defined in, you could keep them unexported, then provide a function to create a ResultEvent as well as methods to read the name and description.

Get names of structs that implement an interface or inherit a struct

Is it possible to get a slice of strings that represent the names of all types that implement an interface or inherit from a specific struct in a specific package using reflection?
After some research on the reflect package's doc, I don't think it's possible. That's not the way reflection work in go: the interfaces mechanism not beeing declarative (but duck-typed instead), there is no such list of types.
That said, you may have more luck using the ast package to parse your project, get the list of types, and check wheter or not they implement an interface, then write some code to give you the said slice. That would add a step to compilation, but could work like a charm.
AFAIK, you can't do this with reflect, since packages are kinda out of reflect's scope.
You can do this the same way godoc's static analysis works. That is, using code.google.com/p/go.tools/go/types to parse the package's source code and get the type info.
The go oracle can do this. https://godoc.org/code.google.com/p/go.tools/oracle
Here is the relevant section of the user manual.

Resources