I have encountered a problem while building my own chaincode.
Hypeledger Fabric version -v 1.0.0
> cannot use new(SampleChaincode) (type *SampleChaincode) as type
> shim.Chaincode in argument to shim.Start:
> *SampleChaincode does not implement shim.Chaincode (wrong type for Init method)
> have Init(shim.ChaincodeStubInterface, string, []string) ([]byte, error)
> want Init(shim.ChaincodeStubInterface) peer.Response
I have try compiling in v0.6 fabric and it succeeded. However when i instantiate the chaincode, i received the same messages, probably because my blockchain is running on v1.0.0
Hence is there a way to fix this??
this is my code
func main() {
lld, _ := shim.LogLevel("DEBUG")
fmt.Println(lld)
logger.SetLevel(lld)
fmt.Println(logger.IsEnabledFor(lld))
err := shim.Start(new(SampleChaincode))
if err != nil {
logger.Error("Could not start SampleChaincode")
} else {
logger.Info("SampleChaincode successfully started")
}
}
In version 1.0.0 the interface of chaincode has been changed to encapsulate the response within:
// A response with a representation similar to an HTTP response that can
// be used within another message.
type Response struct {
// A status code that should follow the HTTP status codes.
Status int32 `protobuf:"varint,1,opt,name=status" json:"status,omitempty"`
// A message associated with the response code.
Message string `protobuf:"bytes,2,opt,name=message" json:"message,omitempty"`
// A payload that can be used to include metadata with this response.
Payload []byte `protobuf:"bytes,3,opt,name=payload,proto3" json:"payload,omitempty"`
}
Hence the signature of the function in interface changed to:
// Chaincode interface must be implemented by all chaincodes. The fabric runs
// the transactions by calling these functions as specified.
type Chaincode interface {
// Init is called during Instantiate transaction after the chaincode container
// has been established for the first time, allowing the chaincode to
// initialize its internal data
Init(stub ChaincodeStubInterface) pb.Response
// Invoke is called to update or query the ledger in a proposal transaction.
// Updated state variables are not committed to the ledger until the
// transaction is committed.
Invoke(stub ChaincodeStubInterface) pb.Response
}
Hence the error message you've got:
cannot use new(SampleChaincode) (type *SampleChaincode) as type
shim.Chaincode in argument to shim.Start:
*SampleChaincode does not implement shim.Chaincode (wrong type for Init method)
have Init(shim.ChaincodeStubInterface, string, []string) ([]byte, error)
want Init(shim.ChaincodeStubInterface) peer.Response
Right, the interfaces are different.
The v1.0 chaincode interface differs than the v0.6 one.
Please take a look at the following example
Thanks for the share, i compared the v0.6 and v1.0.0 hyperledger fabric examples.
v0.6 hyperledger fabric example:
func (t *SampleChaincode) Query(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
if function == "queryPatientInfo" {
return queryPatientInfo(stub, args)
}
return nil, nil
vs
v1.0.0 hyperledger fabric example:
func (t *SampleChaincode) Query(stub shim.ChaincodeStubInterface) pb.Response {
function, args := stub.GetFunctionAndParameters()
if function == "queryPatientInfo" {
return queryPatientInfo(stub, args)
}
return shim.Success(nil)
}
also importing:
pb "github.com/hyperledger/fabric/protos/peer"
i just thought i should share this :)
Related
I want to list all the repositories inside GCP artifact registry in golang.
Current code : (https://pkg.go.dev/cloud.google.com/go/artifactregistry/apiv1beta2)
c, err := artifactregistry.NewClient(ctx, option.WithCredentialsFile("<service account json>"))
if err != nil {
// no error here
}
defer c.Close()
req := &artifactregistrypb.ListRepositoriesRequest{
Parent: "<project-id>",
}
it := c.ListRepositories(ctx, req)
for {
resp, err := it.Next()
if err == nil {
fmt.Println("resp", resp)
} else {
fmt.Println("err ==>", err)
}
}
The error prints: Invalid field value in the request. OR sometimes I get Request contains an invalid argument
What am I doing wrong here ? and What does the "Parent" mean ? (in ListRepositoriesRequest)
On further digging, I found that the value passed in the Parent goes to : "x-goog-request-params", what should be the correct format for this ?
Sometime the libraries/api are well documented, sometime not...
Here the REST API that you can test in the API explorer (right hand side bar). After some tests, the parent must have that format
projects/<PROJECT_ID>/locations/<REGION>
Try with that to solve your issue
Problem: I fail subscribing to my publisher implemented in swift as soon as the publisher has published its first message.
Goal: Publish a data stream over ZeroMQ from my swift app. Then connect and disconnect a few subscribers and get messages through.
Background: I use swift5 and SwiftyZeroMQ5 (I have tested SwiftyZeroMQ too), I deploy on iPhone. I try to subscribe from both swift and python3. It only works if I connect my subscriber prior to publishing the first message. It also works if I first connect my subscriber then start the publisher app, then publishes. Corresponding publish and subscribe code on python3 does not require launching in any specific order and represents the behaviour I want.
Since I get the sub/pub to work if I start i specific order, I know that IP-numbers, ports and topic, formatting etc are correct.
Note that the behaviour is the same when I subscribe from both python3 and swift - it is not compatibility issues between swift and python.
Error messages: No error messages, the poller simply does not trigger if the processes are not started in the described order. The poller do trigger and messages and received if the processes are started in the described order.
What I tried: I've tried different combinations of publishers and subscribers regarding code base and devices.
Swift pub to swift sub on same device [only works in described order]
Swift pub to swift sub on different devices [only works in described order]
Swift pub to python3 sub [only works in described order]
Python3 pub to swift sub [works independent of start order]
Python3 pub to python3 sub [works independent of start order]
My conclusion: There is a problem in the swift publisher socket: it fails to recognise new subscribers after it has published its first message.
Swift code for publisher, initPublisher is called in viewDidLoad(). ZeroMQ library version is 4.2.2:
import SwiftyZeroMQ5
var context: SwiftyZeroMQ.Context = try! SwiftyZeroMQ.Context()
var gpsPublisher: SwiftyZeroMQ.Socket?
let gpsPublishEndPoint = "tcp://*:5560"
// Init the publisher socket
func initPublisher()->Bool{
do{
self.gpsPublisher = try context.socket(.publish)
try self.gpsPublisher?.setSendBufferSize(4096)
try self.gpsPublisher?.setLinger(0) // Dont buffer messages
try self.gpsPublisher?.bind(self.gpsPublishEndPoint)
return true
}
catch{
print("Publish setup failed!")
return false
}
}
// ZMQ publish. Publishes string and serialized json-object
func publish(socket: SwiftyZeroMQ.Socket?, topic: String, json: JSON)->Bool{
// Create string with topic and json representation
let publishStr = getJsonStringAndTopic(topic: topic, json: json)
do{
try socket?.send(string: publishStr)
print("publish: Published: " + publishStr)
return true
}
catch{
print("publish: Error, tried to publish, but failed: " + publishStr)
return false
}
}
//The function is repeatedly called in a thread. Only function call shown here below.
_ = self.publish(socket: self.gpsPublisher, topic: "myTopic", json: json)
The python3 subscriber code,
zmq.zmq_version() -> '4.3.2':
context = zmq.Context()
socket = context.socket(zmq.SUB)
socket.connect("tcp://192.168.1.2:5560")
socket.setsockopt_string(zmq.SUBSCRIBE, 'myTopic')
socket.RCVTIMEO = 1000 # in milliseconds
while socket:
try:
msg = str(socket.recv(), 'utf-8')
(topic, msg) = auxiliaries.zmq.demogrify(msg)
_print((topic, msg))
except zmq.error.Again as error:
_print(str(error))
except KeyboardInterrupt:
auxiliaries.zmq.close_socket_gracefully(socket)
socket = None
Any help, interesting test setups etc is very much appreciated.
I did some more testing and found out a few things and a workaround.
The code works as intended when running on an iPhone simulator (simulator is x86_64 architecture, iPhone8 is armv7)
I don't think it is related, but I did find it interesting. Certain multicast and broadcast protocols require an approval from Apple. You can run without the approval on simulators, but not in devices. Apple networking multicast entitlement. Since it partially works I did rule this out.
The workaround is to bind the socket again prior to each publish. This throws the error "Address already in use", butt seem to not do much harm.
Without unreasonable delays in between publish messages, the pub-sub fails after 500-1000 messages if the publish socket is not binded again when running from the iPhone.
I made a minimal working example app that you can play around with if you want to, or need to dig deeper. It has buttons for "init", "bind", "publish" and "bind and publish". You can send a batch of messages and check timings etc.
I run the app towards a python3 script.
I included SwiftyZeroMQ5 via cocoapods.
Podfile:
platform :ios, '13.0'
target 'ZMQtest' do
use_frameworks!
pod 'SwiftyZeroMQ5'
end
SwiftCode (set up the buttons your self..)
import UIKit
import SwiftyZeroMQ5
class ViewController: UIViewController {
let context = try! SwiftyZeroMQ.Context()
var publisher: SwiftyZeroMQ.Socket?
let publishEndPoint = "tcp://*:5560"
var cnt = 0
let quota = 1200
#IBAction func publishButtonPressed(_ sender: Any) {
while cnt < quota {
publish()
//usleep(10000)
}
cnt = 1
}
#IBAction func bindAndPublishButtonPressed(_ sender: Any) {
while cnt < quota {
bindPublisher()
publish()
}
cnt = 1
}
#IBAction func initPubButtonPressed(_ sender: Any) {
initPublisher()
}
#IBAction func bindPublisherButtonPressed(_ sender: Any) {
bindPublisher()
}
#IBOutlet weak var statusLabel: UILabel!
// **************
// Init publisher
func initPublisher(){
do {
self.publisher = try context.socket(.publish)
print("Publisher socket created")
}
catch {
print("initPublisher error: ", error)
}
}
// **************
// Bind publisher
func bindPublisher(){
do {
try self.publisher?.bind(publishEndPoint)
print("Publisher socket binded to :", publishEndPoint)
}
catch {
print("bindPublisher error: ", error)
}
}
// *****************
// Publish a message
func publish(){
// Publish dummy string
do{
cnt += 1
let str = "topic {\"key\": \"" + String(cnt) + "\"}"
try self.publisher?.send(string: str)
statusLabel.text = str
print("Publish message no: ", String(cnt))
}
catch{
print("publisher error: ", error)
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
And the python3 code:
#!/usr/bin/env python3
'''Minimal running example of a ZMQ SUB socket.'''
import json
import zmq
def demogrify(msg: str):
'''inverse of mogrify()'''
try:
(topic, message) = msg.split(maxsplit=1)
except ValueError:
(topic, message) = (msg, '{}')
return topic, json.loads(message)
def close_socket_gracefully(socket):
'''graceful termination'''
socket.setsockopt(zmq.LINGER, 0) # to avoid hanging infinitely
socket.close()
if __name__ == "__main__":
context = zmq.Context()
socket = context.socket(zmq.SUB) #pylint: disable=no-member
socket.connect("tcp://192.168.1.2:5560")
socket.setsockopt_string(zmq.SUBSCRIBE, '') #pylint: disable=no-member
socket.RCVTIMEO = 1000 # in milliseconds
while socket:
try:
msg = str(socket.recv(), 'utf-8')
(topic, msg) = demogrify(msg)
print((topic, msg))
except zmq.error.Again as error:
print(str(error))
except KeyboardInterrupt:
close_socket_gracefully(socket)
socket = None
Should I mark this issue as solved or not?
I'm trying to compress a JPEG image in go using mozjpeg. Since it doesn't have official go binding, I think I'll just invoke its CLI to do the compression.
I try to model the usage after compress/gzip:
c := jpeg.NewCompresser(destFile)
_, err := io.Copy(c, srcFile)
Now the question is, how do I wrap the CLI inside Compresser so it can support this usage?
I tried something like this:
type Compresser struct {
cmd exec.Command
}
func NewCompressor(w io.Writer) *Compresser {
cmd := exec.Command("jpegtran", "-copy", "none")
cmd.Stdout = w
c := &Compresser{cmd}
return c
}
func (c *Compresser) Write(p []byte) (n int, err error) {
if c.cmd.Process == nil {
err = c.cmd.Start()
if err != nil {
return
}
}
// How do I write p into c.cmd.Stdin?
}
But couldn't finish it.
Also, a second question is, when do I shut down the command? How to shut down the command?
You should take a look at the Cmd.StdinPipe. There is an example in the documentation, which suits your case:
package main
import (
"fmt"
"io"
"log"
"os/exec"
)
func main() {
cmd := exec.Command("cat")
stdin, err := cmd.StdinPipe()
if err != nil {
log.Fatal(err)
}
go func() {
defer stdin.Close()
io.WriteString(stdin, "values written to stdin are passed to cmd's standard input")
}()
out, err := cmd.CombinedOutput()
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s\n", out)
}
In this case, CombinedOutput() executes your command, and the execution is finished, when there are no more bytes to read from out.
As per Kiril's answer, use the cmd.StdInPipe to pass on the data you receive to Write.
However, in terms of closing, I'd be tempted to implement io.Closer. This would make *Compresser automatically implement the io.WriteCloser interface.
I would use Close() as the notification that there is no more data to be sent and that the command should be terminated. Any non-zero exit code returned from the command that indicates failure could be caught and returned as an error.
I would be wary of using CombinedOutput() inside Write() in case you have a slow input stream. The utility could finish processing the input stream and be waiting for more data. This would be incorrectly detected as command completion and would result in an invalid output.
Remember, the Write method can be called an indeterminate number of times during IO operations.
I am new to Hyperledger .I am using docker to run Hyperledger. Pulled hyperledger/fabric-peer:latest from Docker hub and
able to run stub.CreateTable() ,stub.GetRows() , stub.InsertRows() and some other functions in my Chaincode. But when i tried to run
stub.GetHistoryKeys() or stub.GetCompositeKeys() ...etc in my chaincode
It's reporting an error
stub.GetHistoryForKey undefined (type shim.ChaincodeStubInterface has no field
or method GetHistoryForKey)
I found that in my interface.go file there are no such functions . Googled a lot but found nothing .Can anyone tell the correct hyperledger/fabric-peer image to pull so that the above functions can run in Chaincode.
Please download latest version of fabric image, (
hyperledger/fabric-peer x86_64-1.1.0 ). It can be downloaded from script mentioned on hyperledger official website (Install binary)=> (https://hyperledger-fabric.readthedocs.io/en/latest/install.html. Can't paste url due to stackover flow policy issue). Once you have it. Create a go code. Simply add one json record on one key add then try to add some change some field of json and again add to same key. Once you have done that, fire the below code for gethistory:=>
func (s *SmartContract) getAllTransactionForid(APIstub shim.ChaincodeStubInterface, args []string) sc.Response {
fmt.Println("getAllTransactionForNumber called")
id:= args[0]
resultsIterator, err := APIstub.GetHistoryForKey(id)
if err != nil {
return shim.Error(err.Error())
}
defer resultsIterator.Close()
// buffer is a JSON array containing historic values for the number
var buffer bytes.Buffer
buffer.WriteString("[")
bArrayMemberAlreadyWritten := false
for resultsIterator.HasNext() {
response, err := resultsIterator.Next()
if err != nil {
return shim.Error(err.Error())
}
// Add a comma before array members, suppress it for the first array member
if bArrayMemberAlreadyWritten == true {
buffer.WriteString(",")
}
buffer.WriteString("{\"TxId\":")
buffer.WriteString("\"")
buffer.WriteString(response.TxId)
buffer.WriteString("\"")
buffer.WriteString(", \"Value\":")
// if it was a delete operation on given key, then we need to set the
//corresponding value null. Else, we will write the response.Value
//as-is (as the Value itself a JSON marble)
if response.IsDelete {
buffer.WriteString("null")
} else {
buffer.WriteString(string(response.Value))
}
buffer.WriteString(", \"Timestamp\":")
buffer.WriteString("\"")
buffer.WriteString(time.Unix(response.Timestamp.Seconds, int64(response.Timestamp.Nanos)).String())
buffer.WriteString("\"")
buffer.WriteString(", \"IsDelete\":")
buffer.WriteString("\"")
buffer.WriteString(strconv.FormatBool(response.IsDelete))
buffer.WriteString("\"")
buffer.WriteString("}")
bArrayMemberAlreadyWritten = true
}
if !bArrayMemberAlreadyWritten {
buffer.WriteString("No record found")
}
buffer.WriteString("]")
fmt.Printf("- getAllTransactionForNumber returning:\n%s\n", buffer.String())
return shim.Success(buffer.Bytes())
}
If still in doubt, please revert. I will give you my whole source code to make it work. But I hope this will make your problem go away :-)
At last I am able to figure it out to get the hyperledger images to support my chaincode.
I am able to do transactions in Hyperledger (fabric implementation). I want to see all the transactions and its payload details initiated by a user by passing the user's key.
for example:
A transfers 10 units to B
A transfers 5 units to C
D transfers 8 units to A
When I pass A's key then fabric must provide me all the transactions of A.
Is there any way? Or which fabric API function call should I use?
/chain/blocks/{Block} endpoint carries ordered list of transactions in a specified block.
Use /chain endpoint to get the height (number of blocks) of your chain, and then retrieve transactions from each block using /chain/blocks/{Block} REST endpoint.
You can develop the proper indexing and query function in your chaincode.
Meaning for each transaction you store its details in the internal key/value store (stub.PutState) with the user as key and return all the transactions associated to a user in your query (stub.GetState).
The best and simplest way is to use the shim package function
GetHistoryForKey(key string)
As the documentation says:
GetHistoryForKey function can be invoked by a chaincode to return a history of key values across time.
GetHistoryForKey is intended to be used for read-only queries.
IF anyone need Java SDk and go chaincode combination. There you go
answered here similar question
Java code
public List<HistoryDao> getUFOHistory(String key) throws Exception {
String[] args = { key };
Logger.getLogger(QueryChaincode.class.getName()).log(Level.INFO, "UFO communication history - " + args[0]);
Collection<ProposalResponse> responses1Query = ucc.getChannelClient().queryByChainCode("skynetchaincode", "getHistoryForUFO", args);
String stringResponse = null;
ArrayList<HistoryDao> newArrayList = new ArrayList<>();
for (ProposalResponse pres : responses1Query) {
stringResponse = new String(pres.getChaincodeActionResponsePayload());
Logger.getLogger(QueryChaincode.class.getName()).log(Level.INFO, stringResponse);
newArrayList = gson.fromJson(stringResponse, new TypeToken<ArrayList<HistoryDao>>() {
}.getType());
}
if (null == stringResponse)
stringResponse = "Not able to find any ufo communication history";
return newArrayList;
}
and you go chancode implemetation is as follows
Go code
func (t *SmartContract) getHistoryForUFO(APIstub shim.ChaincodeStubInterface, args []string) sc.Response {
if len(args) < 1 {
return shim.Error("Incorrect number of arguments. Expecting 1")
}
ufoId := args[0]
resultsIterator, err := APIstub.GetHistoryForKey(ufoId)
if err != nil {
return shim.Error(err.Error())
}
defer resultsIterator.Close()
var buffer bytes.Buffer
buffer.WriteString("[")
bArrayMemberAlreadyWritten := false
for resultsIterator.HasNext() {
response, err := resultsIterator.Next()
if err != nil {
return shim.Error(err.Error())
}
// Add a comma before array members, suppress it for the first array member
if bArrayMemberAlreadyWritten == true {
buffer.WriteString(",")
}
buffer.WriteString("{\"TxId\":")
buffer.WriteString("\"")
buffer.WriteString(response.TxId)
buffer.WriteString("\"")
buffer.WriteString(", \"Value\":")
// if it was a delete operation on given key, then we need to set the
//corresponding value null. Else, we will write the response.Value
//as-is (as the Value itself a JSON)
if response.IsDelete {
buffer.WriteString("null")
} else {
buffer.WriteString(string(response.Value))
}
buffer.WriteString(", \"Timestamp\":")
buffer.WriteString("\"")
buffer.WriteString(time.Unix(response.Timestamp.Seconds, int64(response.Timestamp.Nanos)).String())
buffer.WriteString("\"")
buffer.WriteString(", \"IsDelete\":")
buffer.WriteString("\"")
buffer.WriteString(strconv.FormatBool(response.IsDelete))
buffer.WriteString("\"")
buffer.WriteString("}")
bArrayMemberAlreadyWritten = true
}
buffer.WriteString("]")
fmt.Printf("- History returning:\n%s\n", buffer.String())
return shim.Success(buffer.Bytes())
}
Let me know if you question.
If you are using composer-client, you can simply use the Historian command.
var historian = await businessNetworkConnection.getHistorian();
historian.getAll().then(historianRecords => console.log(historianRecords));