How retrieve all block transactions in the Hyperledger fabric? - hyperledger-fabric

As you know there is chance to have multiple transaction in one block , depend on the batch size and orderer configuration.
I need to make only one call to return all transaction inside the block not one by one.
I could retrieve one transaction with queryTransaction by using fabric SDK.
like
let response_payload = await channel.queryTransaction(trxnID, peer);
First Approach: implement a chanincode function and pass the block number which comes from eventHub along the method then inside the chaincode retrieve all transaction Ids and then make a query to find all transaction then stitch all together as result.
Second Approach:
retrieve the block inside with fabric sdk then parse all signed proposal in the payload of the block content.
Third Approach:
retrieve the block inside with fabric sdk then retrieve the transaction ids or keys in the payload and then make a couch db query to retrieve all content .
Which approach do you think is more reasonable if not what is your suggestion?

If you have a your client set up correctly, there should be a
LedgerClient which has a function like
QueryBlock(blockNumber uint64, options ...ledger.RequestOption) (*common.Block, error)
Once you have the block, you can pull the data out of it
block, _ := QueryBlock(37)
data := block.GetData().GetData()
data is a [][]byte, and each entry is one transaction.

Related

How can I call one chaincode function inside another chaincode? [nodejs specific]

I'm using NodeJs to write the Hyperledger Fabric chaincode v2.x and using const { Contract } = require('fabric-contract-api')
I have 2 sets of chaincode, one to maintain the user and its wallet amount, and 2nd contract has the information about the asset e.g. quantity, price, name, etc.
I wanted to transfer the asset some quantity from user1 to user2 and wanted to deduct money from user1's account and transfer it to user2's account.
How can I call the function of transfer from the user contract inside the asset contract?
Yes, you can call one chain code function in another chain code .
You can find a few more information in the below link:
https://hyperledger.github.io/fabric-chaincode-node/release-2.2/api/fabric-shim.ChaincodeStub.html#invokeChaincode__anchor
As there is nothing like a piece of code to explain how the SDK works, I would like to offer the following which may help. The exchangeAsset is a method signature on the current contract. It receives as parameters, the AssetId and the buyerId.
async exchangeAsset(ctx, assetId, buyerId) {
Further down in this contract method, there is a need to make a cross contract call to the client contract, which contains information on buyers and sellers. First create an array containing the name of the function to call and the number of parameters required e.g.
let values = new Array("readKeyValue", buyerId);
Then make the call using the following
let buyer = await this.crossChannelRead(
ctx,
"client",
[...values],
"channelname"
);
The "client" string is the name of the other contract to call.
The values array is spread and will read as readKeyValue, buyerId, which means use the readKeyValue function and use buyerId as the parameter.
The "channelname" as shown above will actually be the name of the channel where the contract can be found.

Is there any possibility to search an asset with partial id

In hyperledger-fabric node js sdk.
Is there any possibility to search an asset with partial id?
for example my id is 'abc123'.
I can search with bc12 or abc or 123..and get the matching results.
Using stub.GetStateByRange(startKey, endKey) it is possible to retrieve results on a partial key, if they key has a specific form.
For eg.
the following keys could be used to successfully with a range query in the chaincode to retrieve a list of results, to match key abc123
a
ab
abc
abc1
abc12
abc123
However, a key without the same initial characters will not work. Eg. bc12 or 123.
The below function documentation gives a good idea of how the GetStateByRange function can be used.
// GetStateByRange returns a range iterator over a set of keys in the
// ledger. The iterator can be used to iterate over all keys
// between the startKey (inclusive) and endKey (exclusive).
// However, if the number of keys between startKey and endKey is greater than the
// totalQueryLimit (defined in core.yaml), this iterator cannot be used
// to fetch all keys (results will be capped by the totalQueryLimit).
// The keys are returned by the iterator in lexical order. Note
// that startKey and endKey can be empty string, which implies unbounded range
// query on start or end.
// Call Close() on the returned StateQueryIteratorInterface object when done.
// The query is re-executed during validation phase to ensure result set
// has not changed since transaction endorsement (phantom reads detected).
GetStateByRange(startKey, endKey string) (StateQueryIteratorInterface, error)
The answer by Clyde is the correct one to your question.
But, if you intend to perform complex queries in your code and you are in a position to refactor your data modelling, maybe you can set the information you must filter in some field inside your model (instead of or in addition to the ID itself) and perform rich queries against that field.
To do this, you must enable CouchDB as the state DB in your peers if haven't done it yet. Then you can query the DB and perform rich queries against your model fields.
Of course, this is not the answer to your question, but it may fit better to your use case if you are in a position to perform this kind of changes.

Access CosmosDB from Azure Function (without input binding)

I have 2 collections in CosmosDB, Stocks and StockPrices.
StockPrices collection holds all historical prices, and is constantly updated.
I want to create Azure Function that listens to StockPrices updates (CosmosDBTrigger) and then does the following for each Document passed by the trigger:
Find stock with matching ticker in Stocks collection
Update stock price in Stocks collection
I can't do this with CosmosDB input binding, as CosmosDBTrigger passes a List (binding only works when trigger passes a single item).
The only way I see this working is if I foreach on CosmosDBTrigger List, and access CosmosDB from my function body and perform steps 1 and 2 above.
Question: How do I access CosmosDB from within my function?
One of the CosmosDB binding forms is to get a DocumentClient instance, which provides the full range of operations on the container. This way, you should be able to combine the change feed trigger and the item manipulation into the same function, like:
[FunctionName("ProcessStockChanges")]
public async Task Run(
[CosmosDBTrigger(/* Trigger params */)] IReadOnlyList<Document> changedItems,
[CosmosDB(/* Client params */)] DocumentClient client,
ILogger log)
{
// Read changedItems,
// Create/read/update/delete with client
}
It's also possible with .NET Core to use dependency injection to provide a full-fledged custom service/repository class to your function instance to interface to Cosmos. This is my preferred approach, because I can do validation, control serialization, etc with the latest version of the Cosmos SDK.
You may have done so intentionally, but just mentioning to consider combining your data into a single container partitioned by, for example, a combination of record type (Stock/StockPrice) and identifier. This simplifies things and can be more cost/resource efficient relative to multiple containers.
Ended up going with #Noah Stahl's suggestion. Leaving this here as an alternative.
Couldn't figure out how to do this directly, so came up with a work-around:
Add function with CosmosDBTrigger on StockPrices collection with Queue output binding
foreach over Documents from the trigger, serialize and add to the Queue
Add function with QueueTrigger, CosmosDB input binding for Stocks collection (with PartitionKey and Id set to StockTicker), and CosmosDB output binding for Stocks collection
Update Stock from CosmosDB input binding with values from the QueueTrigger
Assign updated Stock to CosmosDB output binding parameter (updates record in DB)
This said, I'd like to hear about more straightforward ways of doing this, as my approach seems like a hack.

Join a new organization in a channel. Hyperledger Fabric Node-sdk

I am trying to join a new organization in a channel of an existing network.
I understood the flow to join an org to a channel from fabric documentation but they did use docker.
I want to accomplish the same using node-sdk.
To get the latest config block of a channel I am using these methods:
<async> getChannelConfig(target, timeout)
<async> getChannelConfigFromOrderer()
https://fabric-sdk-node.github.io/release-1.4/Channel.html#getChannelConfig__anchor
Both are returning the same result. And its type is common.ConfigEnvelope.
It is not common.Block.
It is returning an object according to documentation and I am saving it as a json file.
When I went through it, It doesn't have the below fields which are required for the purpose.
{"channel_group":{"groups":{"Application":{"groups": {
I am attaching the latest block file which I got.
Please tell where I am making the mistake and if there is any reference for this please mention.
Actually, the latest config blocks are protobuf object.
So, when I am trying to save it as json, it was not properly formatted for json.
To do that, first, it has to convert into buffer and save.
// return latest config block as protobuf object
const latestConfig = await getChannelConfigFromOrderer();
const latestConfigBuffer = latestConfig.toBuffer();
// save it in .pb format
fs.writeFileSync("latest-config.pb", latestConfigBuffer);
Then using configtxlator convert it to json and made changes accordingly.

How to get query result from another channel

I have a trouble when I want to get query result in my fabric. I have 2 channels, channel 1 stored account data, channel 2 stored some content and their cost. I am in channel 1,I want to query a content's cost in channel2,then "buy" it in channel 1. For example,channel1 have an account A and he has $20,channel2 have a movie cost $9, A wants to query the cost of the movie, then "buy" it, so A only have $11 now. But now I don't know how to get the "$9" from channel2. How can I do it?
Fabric uses channels as a form of isolation.
How ever you can invoke another chaincode using 'InvokeChaincode' API.
// InvokeChaincode locally calls the specified chaincode `Invoke` using the
// same transaction context; that is, chaincode calling chaincode doesn't
// create a new transaction message.
// If the called chaincode is on the same channel, it simply adds the called
// chaincode read set and write set to the calling transaction.
// If the called chaincode is on a different channel,
// only the Response is returned to the calling chaincode; any PutState calls
// from the called chaincode will not have any effect on the ledger; that is,
// the called chaincode on a different channel will not have its read set
// and write set applied to the transaction. Only the calling chaincode's
// read set and write set will be applied to the transaction. Effectively
// the called chaincode on a different channel is a `Query`, which does not
// participate in state validation checks in subsequent commit phase.
// If `channel` is empty, the caller's channel is assumed.
InvokeChaincode(chaincodeName string, args [][]byte, channel string) pb.Response
Source

Resources