I am trying to create a business network which demonstrates nondeterministic behaviour by requesting a random number from a URL (https://random-number-api.mybluemix.net/random).
However, when I invoke the transaction from, the following error appears:
TypeError: request.get is not a function
In the documentation (https://hyperledger.github.io/composer/latest/integrating/call-out), it is mentioned that request is global and can be used directly.
To test the URL,
curl -X GET https://random-number-api.mybluemix.net/random
I am using Composer 0.18.2.
The following is the code. The whole business network definition is found here: https://github.com/caveman7/nondeterministic
async function createStock(request) {
const factory = getFactory();
const namespace = 'org.nondeterministic';
const stock = factory.newResource(namespace, 'Stock', request.stockId);
const priceAsStr = await request.get({uri: 'https://random-number-api.mybluemix.net/random'});
stock.price = parseInt(priceAsStr);
//stock.price = getPrice();
console.log('#debug - Stock Price Generated is: USD' + stock.price);
const ar = await getAssetRegistry(namespace + '.Stock')
await ar.add(stock);
}
const getPrice = () => {
const price = Math.floor((Math.random() * 10000) + 1);
return price;
}
probably because you're providing request as an object to the TP. As shown above or https://github.com/caveman7/nondeterministic/blob/master/lib/script.js#L22
Errors as its 'not' got a method called get?. It should be async function createStock(createStock ) to match the parameter name in the transaction decorator (tracing the github script file from the above link) - and then you should be able to access request.get() as you would expect (since request.get came in in 0.18.1 IIRC).
Related
This is the flow we need on the backend.
First user creates unsigned proposal and the proposal buffer is returned to him.
const proposal = new Endorsement(this.config.chaincodeId, this.channel)
const user = User.createUser(
enrollmentId,
enrollmentId,
this.config.userMspId,
certificate
)
const identityContext = new IdentityContext(user, this.channel.client)
const proposalBuffer = proposal.build(identityContext, {
fcn,
args,
})
const digest = createHash('sha256').update(proposalBuffer).digest('hex')
Then after user signs digest and creates signature our backend sends signed proposal to endorser:
const signedProposal = {
signature: Buffer.from(signature, 'base64'),
proposal_bytes: proposalBuffer,
}
const endorser = this.channel.getEndorsers(this.config.userMspId)[0]
const response = await endorser.sendProposal(
Buffer.from(JSON.stringify( signedProposal ))
)
sendProposal method throws ChaincodeId is nil error.
Anyone knows how we could implement this right?
How do we create the Buffer object for the sendProposal method parameter?
In my case I created the buffer from stringified json object, how SignedProposal is defined in the Hyperledger Fabric documentation.
I see your code is custom code to send a proposal. Why should you do this? Why not do the easy way by using fabric-network lib?
For your question, I found some code in fabric-network:
// This is the object that will centralize this endorsement activities
// with the fabric network
const endorsement = channel.newEndorsement(this.contract.chaincodeId);
const proposalBuildRequest = this.newBuildProposalRequest(args);
logger.debug('%s - build and send the endorsement', method);
// build the outbound request along with getting a new transactionId
// from the identity context
endorsement.build(this.identityContext, proposalBuildRequest);
endorsement.sign(this.identityContext);
...
...
else if (this.endorsingOrgs) {
logger.debug('%s - user has assigned endorsing orgs %s', method, this.endorsingOrgs);
const flatten = (accumulator, value) => {
accumulator.push(...value);
return accumulator;
};
proposalSendRequest.targets = this.endorsingOrgs.map((mspid) => channel.getEndorsers(mspid)).reduce(flatten, []);
}
...
...
// by now we should have targets or a discovery handler to be used
// by the send() of the proposal instance
const proposalResponse = await endorsement.send(proposalSendRequest);
...
In send method:
...
const signedEnvelope = this.getSignedProposal();
...
peer.sendProposal(signedEnvelope, requestTimeout)
...
Look inside getSignedProposal method:
...
const fabproto6 = require('fabric-protos');
...
/*
* return a signed proposal from the signature and the payload as bytes
*
* This method is not intended for use by an application. It will be used
* by the send method of the super class.
* #returns {object} An object with the signature and the payload bytes
*/
getSignedProposal() {
const method = `getSignedProposal[${this.type}:${this.name}]`;
logger.debug('%s - start', method);
this._checkPayloadAndSignature();
const signedProposal = fabproto6.protos.SignedProposal.create({
signature: this._signature,
proposal_bytes: this._payload
});
// const signedProposal = {
// signature: this._signature,
// proposalBytes: this._payload
// };
return signedProposal;
}
So, try to use fabric-protos lib to encode your proposal. Hope this help
Solved this issue by moving to #hyperledger/fabric-gateway library. It works fine and has a well documented API. Offline transactions are better supported too.
The problem I'm trying to solve, is this:
I want to be able to deploy a new API Gateway configuration-file, that is the OpenAPI 2.0 (Swagger) specification, which API Gateway uses to set up the endpoints. I want to do this through code and not the CLI because I require multiple members of a team to be able to deploy new revisions at high speed, and preferably automatically whenever, say, pushing to a main-branch.
I've looked at the following documentation so far:
https://github.com/googleapis/nodejs-api-gateway/tree/main/samples/generated/v1
Mainly, all their examples look more or less the same, i.e. as an example - getting an API Config:
import { ApiGatewayServiceClient } from '#google-cloud/api-gateway';
function main() {
// [START apigateway_v1_generated_ApiGatewayService_GetApiConfig_async]
/**
* TODO(developer): Uncomment these variables before running the sample.
*/
/**
* Required. Resource name of the form:
* `projects/* /locations/global/apis/* /configs/*`
*/
const name = ''projects/<my_project_id>/locations/global/apis/<my_API_name>/configs/<API_config_name>''
/**
* Specifies which fields of the API Config are returned in the response.
* Defaults to `BASIC` view.
*/
const view = {}
// Instantiates a client
const apigatewayClient = new ApiGatewayServiceClient();
async function callGetApiConfig() {
// Construct request
const request = {
name,
};
// Run request
const response = await apigatewayClient.getApiConfig(request);
console.log(response);
}
callGetApiConfig();
// [END apigateway_v1_generated_ApiGatewayService_GetApiConfig_async]
}
The result then looks like this:
Now what I don't understand, is why many of the fields of the response are empty (grcpServices, openapiDocuments, managedServiceConfigs), especially openapiDocuments, because I know for a fact that an OpenAPI YAML spec is present on GCP. For context, I was trying to see what the response would look like in order to find a solution to the main problem.
That leads me to my second question. As I mentioned, I'm trying to deploy/add a new OpenAPI spec (since you have to add a new one if you want to add new stuff) with the same library. The example on how to create an API Config, given from the documentation, is the following:
import { ApiGatewayServiceClient } from '#google-cloud/api-gateway';
function main() {
// [START apigateway_v1_generated_ApiGatewayService_CreateApiConfig_async]
/**
* TODO(developer): Uncomment these variables before running the sample.
*/
/**
* Required. Parent resource of the API Config, of the form:
* `projects/* /locations/global/apis/*`
*/
const parent = 'projects/<project_id>/locations/global/apis/<my_API_name>'
/**
* Required. Identifier to assign to the API Config. Must be unique within scope of
* the parent resource.
*/
const apiConfigId = 'unique-api-config-id-123'
/**
* Required. API resource.
*/
const apiConfig = {} // What to put here???
// Instantiates a client
const apigatewayClient = new ApiGatewayServiceClient();
async function callCreateApiConfig() {
// Construct request
const request = {
parent,
apiConfigId,
apiConfig,
};
// Run request
const [operation] = await apigatewayClient.createApiConfig(request);
const [response] = await operation.promise();
console.log(response);
}
callCreateApiConfig();
// [END apigateway_v1_generated_ApiGatewayService_CreateApiConfig_async]
}
Now if you try to run this code out of the box, you get the following error:
Error: 3 INVALID_ARGUMENT: Please specify one of: (service_rollout.rollout_id, openapi_documents, grpc_services)
I understand that the variable apiConfig shouldn't be empty, but I cannot find any living examples of what this is actually supposed to contain. I've dived into the source code of the library to try to find an answer, but to no prevail. Also where exactly to fulfill the requirements of specify one of service_rollout.rollout_id, openapi_documents, grpc_services is completely beyond me.
Any responses and help here would be greatly appreciated.
EDIT:
I found the answer to the first question. I had to edit the request-parameter, namely by the following:
import { google } from '#google-cloud/api-gateway/build/protos/protos';
const request = {name, google.cloud.apigateway.v1.GetApiConfigRequest.ConfigView.FULL}.
The second question remains open, but perhaps this first solution will guide me to the last.
Lo and behold, the answer to the first question lead me to the answer to the second.
The solution was to simply include the following in the request:
const apiConfigId = 'test-api-gateway-new-config-1';
const openApiDocument: google.cloud.apigateway.v1.ApiConfig.IOpenApiDocument = {
document: {
path: 'name_of_file.yaml',
contents: fs.readFileSync('path/to/file/you/want/to/upload'),
}
}
/**
* Required. API resource.
*/
const apiConfig: google.cloud.apigateway.v1.IApiConfig = {
openapiDocuments: [
openApiDocument,
]
}
After running this code, a new OpenAPI spec will have been uploaded to GCP's API Gateway with the name "test-api-gateway-new-config-1".
I am using Web3.js with Node JS. I need to get the transaction details for a smart contract under BNB. I developed my codes, but no matter what I did, I couldn't get it to work. Can you help me? Where am I doing wrong?
.env
bnbProvider = https://bsc-dataseed1.binance.org:443
web3crypto.js
const Web3 = require('web3')
const thisWeb3 = new Web3(new Web3.providers.HttpProvider(process.env.bnbProvider))
const minimumABI = [ABI OBJECT]
const tb = new thisWeb3.eth.Contract(minimumABI, process.env.contractId)
my function
exports.checkTransaction = async transactionId => {
const transactionData = await thisWeb3.eth.getTransaction(transactionId)
console.log(transactionData)
return transactionData
}
and Error
Error: Returned error: invalid argument 0: hex string has length 40, want 64 for common.Hash
I'm using the node-persist module to persist some data. Have implemented the same using the below documentation
https://www.npmjs.com/package/node-persist/v/1.0.1
Version - "node-persist": "^3.1.0"
Below is my code
const storage = require('node-persist');
class NetworkClass {
public getNetworkIdentity = async (): Promise<any> => {
//My Business logic goes here
// Here I receive the identity with its expiry
await storage.init({ ttl: 3600 });
await storage.setItem('networkIdentity', JSON.stringify({
identity: "XXXXX"
}));
}
public getNetworkIdentity = async () => {
let myIdentity = storage.getItem("networkIdentity")
return myIdentity
}
}
Using this I can see the file getting created inside a node-persist folder in my source structure, it also has value. But while fetching it using storage.getItem()
I'm getting the below exception :
TypeError : storage.getItem() is not a function
Also I'm facing one problem
After the completion of first request, even when storage.setItem() is done successfully, when the seconds request comes I see the persistent file being deleted already. And I don't find the data related to networkIdentity
Updates:
While iterating over multiple requests, I see that the persistent file is still there with the data that is set, but when I try to read it using await storage.getItem() or await storage.data() no data is being fetched and I get the exception again as storage.getItem() is not a function, although the storage file is still present.
I am new to NodeJS, and I am trying to integrate Stripe payments, using Firebase Cloud functions. I Followed these steps:
I got the token from client-side, stored it in Firestore, the token looks like this: pm_1FFhvNDcXKDMgaqV...
I've created a Customer on Stripe
exports.createNewStripeCustomer =
functions.auth.user().onCreate(
async (user) => {
const customer = await stripe.customers.create({email:
user.email}) ;
return admin.firestore()
.collection('customers')
.doc(user.uid)
.set({customer_id: customer.id});
}
);
The above code works.
Now I've tried to add a payment source using the token as specified in tutorials and docs and I keep getting the following error:
Error: You cannot use a payment method as a source for Customers. Instead, use the payment methods API to Attach a Customer to a payment method. See https://stripe.com/docs/api/payment_methods/attach
Here's the code that causes the error:
exports.newPaymentSource = functions.firestore.document('customers/{userId}/tokens/{tokenId}').onWrite(async (change, context) => {
//Get token that strike sdk gave to the client...
const data = change.after.data();
if (data ===null) { return null }
const token = data.tokenId;
const snapshot = await firestore.collection('customers').doc(context.params.userId).get();
const customer = snapshot.data().customer_id;
//calling stripe api...
console.log(customer + ":" + token + ":" + context.params.userId);
const respFromStripe = await stripe.customers.createSource(customer, { source: token });
// console.log(respFromStripe);
return firestore.collection('users').doc(context.params.userId)
.collection('sources').doc(respFromStripe.card.fingerprint).set(respFromStripe, { merge: true });
});
PaymentMethod objects (which represent your user's cards) need to be attached to a Customer with /v1/payment_methods/pm_123/attach endpoint or in Stripe-Node:
pm = await stripe.paymentMethods.attach('pm_678', {customer: 'cus_123'});
https://stripe.com/docs/api/payment_methods/attach?lang=node
The way you're using it (customer.createSource()) works for older Tokens (tok_123) and Source (src_123) objects, not PaymentMethods.