How to return Transaction id, time stamp on execution of invoke function in chaincode? - blockchain

I need guidance in returning transaction id, time stamp on the client interface after each invoke function call.
I have found that stub.GetTxID() is used to for getting transaction id, but peer.response only take one argument, so i am not able to return the TxID on the client interface.

You can create a response object to capture relevant information, marshal it into json and return it back, something like this:
type ChaincodeResponse struct {
txID string
time *timestamp.Timestamp
}
and then
// rest of the invoke code skipped, here is
// the relevant part:
resp, err := json.Marshal(ChaincodeResponse{
txID: stub.GetTxID(),
time: stub.GetTxTimestamp(),
})
// return json representation of relevant information
// in response
return shim.Success(resp)

I'm working on something at the moment that requires all of our transactions to be timestamped. I tried some things based on your code above but I think the api has moved on considerably since 2017.
Currently, I'm adding a created: stub.GetTxTimestamp() field to all of the things we're putting on the ledger and then reading them later in any queries. Though I'm wondering if the timestamps are already generated and stored, therefore making this unnecessary - do you know if a timestamp is still automatically stored on each item put on the ledger?

Related

Apollo iOS how to handle partial decoding failure

I'm trying to see if there is a way to do more robust handling of partial decoding failures of Apollo generated Swift classes. Currently, if even one field of one object in an array fails to parse from the network response, the entire collection of objects fails to parse and our iOS client gets no data.
Our graphql is defined something like:
query mobile_getCollections() {
getCollections() {
// ... other fields
items {
activeRange {
expires // Int!
starts // Int!
}
}
}
}
So the Apollo generated Swift code is expecting non-nil Ints when decoding these values. However, due to a backend error (that we would like to make the mobile clients more resilient to), the API will occasionally send us a malformed date String instead of a unix timestamp Int. This causes parsing of the entire mobile_getCollections result to fail, because the Apollo generated query class typing can't be perfectly satisfied.
Ideally, I'd like to just throw out the one item in the collection that failed to be parsed correctly and leave the remaining items intact. Is it possible to do something like that using Apollo?
(Yes, I know the real answer here is to fix the backend, but is there anything I can do in the mean time to more gracefully handle similar partial parsing failure issues?)

How to specify the database in an ArangoDb AQL query?

If have multiple databases defined on a particular ArangoDB server, how do I specify the database I'd like an AQL query to run against?
Running the query through the REST endpoint that includes the db name (substituted into [DBNAME] below) ie:
/_db/[DBNAME]/_api/cursor
doesn't seem to work. The error message says 'unknown path /_db/[DBNAME]/_api/cursor'
Is this something I have to specify in the query itself?
Also: The query I'm trying to run is:
FOR col in COLLECTIONS() RETURN col.name
Fwiw, I haven't found a way to set the "current" database through the REST API. Also, I'm accessing the REST API from C++ using fuerte.
Tom Regner deserves primary credit here for prompting the enquiry that produced this answer. I am posting my findings here as an answer to help others who might run into this.
I don't know if this is a fuerte bug, shortcoming or just an api caveat that wasn't clear to me... BUT...
In order for the '/_db/[DBNAME/' prefix in an endpoint (eg full endpoint '/_db/[DBNAME/_api/cursor') to be registered and used in the header of a ::arangodb::fuerte::Request, it is NOT sufficient (as of arangodb 3.5.3 and the fuerte version available at the time of this answer) to simply call:
std::unique_ptr<fuerte::Request> request;
const char *endpoint = "/_db/[DBNAME/_api/cursor";
request = fuerte::createRequest(fuerte::RestVerb::Post,endpoint);
// and adding any arguments to the request using a VPackBuilder...
// in this case the query (omitted)
To have the database name included as part of such a request, you must additionally call the following:
request->header.parseArangoPath(endpoint);
Failure to do so seems to result in an error about an 'unknown path'.
Note 1: Simply setting the database member variable, ie
request->header.database = "[DBNAME]";
does not work.
Note 2: that operations without the leading '/_db/[DBNAME]/' prefix, seem to work fine using the 'current' database. (which at least for me, seems to be stuck at '_system' since as far as I can tell, there doesn't seem to be an endpoint to change this via the HTTP REST Api.)
The docs aren't very helpful right now, so just incase someone is looking for a more complete example, then please consider the following code.
EventLoopService eventLoopService;
// adjust the connection for your environment!
std::shared_ptr<Connection> conn = ConnectionBuilder().endpoint("http://localhost:8529")
.authenticationType(AuthenticationType::Basic)
.user(?) // enter a user with access
.password(?) // enter the password
.connect(eventLoopService);
// create the request
std::unique_ptr<Request> request = createRequest(RestVerb::Post, ContentType::VPack);
// enter the database name (ensure the user has access)
request->header.database = ?;
// API endpoint to submit AQL queries
request->header.path = "/_api/cursor";
// Create a payload to be submitted to the API endpoint
VPackBuilder builder;
builder.openObject();
// here is your query
builder.add("query", VPackValue("for col in collections() return col.name"));
builder.close();
// add the payload to the request
request->addVPack(builder.slice());
// send the request (blocking)
std::unique_ptr<Response> response = conn->sendRequest(std::move(request));
// check the response code - it should be 201
unsigned int statusCode = response->statusCode();
// slice has the response data
VPackSlice slice = response->slices().front();
std::cout << slice.get("result").toJson() << std::endl;

Pagination in Dynamo DB Results with Completable Future

I am querying Dynamo DB for a given primary key. Primary Key consists of two UUID fields (fieldUUID1, fieldUUID2).
I have a lot of queries to be executed for the above primary key combination with list of values. For which i am using Asynchronous CompleteableFuture with ExecutorService with a thread pool of size 4.
After all the queries return results, which is CompletableFuture<Object>, i join them using allOf method of completable future which ensures that all the query execution is complete, and it gives me CompletableFuture<void>, on which using stream i receive CompletableFuture<List<Object>>
If some of the queries result in pagination of result, i.e. returns lastEvaluatedKey, there is no way for me to know which Query Request returned this.
if i do a .get() call while i received `CompletableFuture, this will be a blocking operation, which defeats the purpose of using asynchronous. Is there a way i can handle this scenario?
example:
I can try thenCompose method, but how do i know at what point i need to stop when lastEvaluatedKey is absent.
for (final QueryRequest queryRequest : queryRequests) {
final CompletableFuture<QueryResult> futureResult =
CompletableFuture.supplyAsync(() ->
dynamoDBClient.query(queryRequest), executorService));
if (futureResult == null) {
continue;
}
futures.add(futureResult);
}
// Wait for completion of all of the Futures provided
final CompletableFuture<Void> allfuture = CompletableFuture
.allOf(futures.toArray(new CompletableFuture[futures.size()]));
// The return type of the CompletableFuture.allOf() is a
// CompletableFuture<Void>. The limitation of this method is that it does not
// return the combined results of all Futures. Instead we have to manually get
// results from Futures. CompletableFuture.join() method and Java 8 Streams API
// makes it simple:
final CompletableFuture<List<QueryResult>> allFutureList = allfuture.thenApply(val -> {
return futures.stream().map(f -> f.join()).collect(Collectors.toList());
});
final List<QueryOutcome> completableResults = new ArrayList<>();
try {
try {
// at this point all the Futures should be done, because we already executed
// CompletableFuture.allOf method.
final List<QueryResult> returnedResult = allFutureList.get();
for (final QueryResult queryResult : returnedResult) {
if (MapUtils.isNotEmpty(queryResult.getLastEvaluatedKey()) {
// how to get hold of original request and include last evaluated key ?
}
}
} finally {
}
} finally {
}
I can rely on .get() method, but it will be a blocking call.
the quick solution to your need is to change your futures list. Instead of having it store CompletableFuture<QueryResult> you can change to store CompletableFuture<RequestAndResult> where RequestAndResult is a simple data class holding a QueryRequest and a QueryResult. To do that you need to change your first loop.
Then, once the allfuture completes you can iterate over futures and get access to both the requests and the results.
However, there is a deeper issue here. What are you planning to do once you have access to the origianl QueryRequest? my guess is that you want to issue a followup request with exclusiveStartKey set to whatever the response's lastEvaluatedKey holds. This means that you will wait for all original queries to complete and only then you'll issue the next bunch. This is inefficient: if a query returned with a lastEvaluatedKey you want to issue its followup query ASAP.
To achieve this my advise to you is to introduce a new method which takes a single QueryRequest object and returns a CompletableFuture<QueryResult>. Its implementation will be roughly as follows:
issue a query with the given request
once the result arrives check it. if its lastEvaluatedKey is empty return it as the result of the method
otherwise, update request.exclusiveStartKey and go back to the first step.
Yes, its a bit harder to do that with CompletableFutures (compared to blocking code) but is totally doable.
Once you have that method your code needs to call this method once for each of the requests in queryRequests, put the returned CompletableFutures in a list, and do a CompletableFuture.allOf() on that list. Once the allOf future completes you can just use the results - no need to do issue followup queries.

Is there a way to programmatically invoke a WebJob function from another function within the WebJob and still have the output binding work?

Here's the code:
[return: Table("AnalysisDataTable", Connection = "TableStorageConnection")]
public static async Task<OrchestrationManagerAnalysisData> InputQueueTriggerHandler(
[QueueTrigger("DtOrchestrnRequestQueueName",
Connection = "StorageQueueConnection")] string queueMsg,
[OrchestrationClient] DurableOrchestrationClient client, ILogger logger)
{
logger.LogInformation($"***DtOrchestrationRequestQueueTriggerHandler(): queueMsg = {queueMsg}");
await ProcessInputMessage(queueMsg, client, logger);
// Below is where the code goes to format the TableStorage Entity called analysisData.
// This return causes the above output binding to be executed, saving analysis data to
// Table Storage.
return analysisData;
}
The above code works fine and saves analysisData to TableStorage.
However when I put the output binding attribute on ProcessInputMessage() which is programatically invoked
rather that invoked as a result of a trigger everything works OK except there is no data output
to Table Storage.
[return: Table("AnalysisDataTable", Connection = "TableStorageConnectionName")]
public static async Task<OrchestrationManagerAnalysisData>
ProcessInputMessage(string queueMsg, DurableOrchestrationClient client, ILogger logger)
{
// Do the processing of the input message.
// Below is where the code goes to format the TableStorage Entity called analysisData.
// This return causes the above output binding to be executed, saving analysis data to
// Table Storage.
return analysisData;
}
QUESTION is there a way to cause an output binding to "trigger" when invoked programatically from another function within the WebJob?
I like the labor saving characteristics of output bindings and want to leverage them as much as possible, while also having well factored code, i.e. tight cohesion in each method.
Thanks,
George
is there a way to cause an output binding to "trigger" when invoked programatically from another function within the WebJob?
In short, No.
You send data by using the return value of the function which apply the output binding attribute in function. So, if you want to invoke another function and write data into Table Storage.
If you want to achieve the idea you want, you need to overwrite the return method. However, it is a package integration method, so I suggest that you could use the TableOperation object that inserts the customer entity to the Table Storage.
TableOperation insertOperation = TableOperation.Insert(customer1);
// Execute the insert operation.
table.Execute(insertOperation);
For more details, you could refer to this article.

How does one identify the type (whatToShow) of HistoricalData received from iBrokers API

The IB API reqHistoricalData() method offers a whatToShow argument which can take values to denote you seek data on TRADES, MIDPOINT, BID, ASK etc...
However, the API's historicalData callback, provided to asynchronously receive the requested historical data, doesn't return the relevant whatToShow making it impossible to ascertain what one is looking at. Is it the line for the TRADES, the BIDS or the ASKS I requested???
I get around this the obvious way, namely by requesting TRADES first, waiting for the entirety of the messages to come back and then requesting BIDS then wait again and request ASKS.
Does anyone have a better solution?
Please use the tickerId field properly which is the first parameter in reqHistoricalData() method. When you get the historical data with callbacks, you will be receiving this id back as the first parameter with historicalData().
You just need to keep track which tickerId is associated with which kind of data (bid, ask or trade) to identify that on the callback.
Example:
While requesting:
reqHistoricalData(1, ..whatToShow = Bid,...);
reqHistoricalData(2, ..whatToShow = Ask,...);
Callback handling:
historicalData(int reqId,....)
if(reqId == 1)
//This is the data built of bids as per request1
else if(reqId == 2)
//This is the data built of asks as per request2