Solidity mapping returning null values - mocha.js

So basically, I create a mapping within a smart contract to store hashes of user data. It's mapped from a user id to the hash itself (a bytes32 value). I use a double sha256 hash and store it in the mapping with the aforementioned id. The function for storing it returns the hash by returning the values at the id in the mapping. This hash is correct, meaning at the very least it's initially stored correctly. However, I have another function that gets the hash from the id and it always returns a null value in the javascript tests. I am wondering if it's a problem with the test or with the contract itself.
pragma solidity ^0.4.22;
contract UserStore {
mapping(uint => bytes32) UserHashes; //User id to hash
event HashStored (
uint id,
bytes32 original,
bytes32 hash
);
function HashData(bytes32 data) returns (bytes32){
return sha256(abi.encodePacked(sha256(abi.encodePacked(data))));
}
function StoreHash(uint user_id, bytes32 data) external view returns (bytes32){
UserHashes[user_id] = HashData(data);
HashStored(user_id, data, UserHashes[user_id]);
return UserHashes[user_id];
}
/*
Gets the hash from the blockchain.
*/
function GetHash(uint u_id) view public returns (bytes32){
return UserHashes[u_id];
}
}
Everytime I run this test, GetHash returns a 0 value;
contract("Storage_Test", function(accounts) {
const args = {user_id: 0,
data: "This is some security data",
group_id : 15,
user_ids : [1,2,3,4,5],
num_accounts : 2
}
it("Hash Test: Multiple Storage and retrieving", async function() { return
await UserStore.deployed()
.then(async function(instance) {
var temp = args.data;
var _temp;
for (i = 1; i < args.num_accounts; i++) {
_temp = temp;
temp = await instance.HashData.call(temp);
// console.log("Datahash: " + temp);
result = await instance.StoreHash.call(i, _temp);
// console.log("Result: " + result);
assert.equal(result, temp, "Hash at " + i + " wasn't returned
correctly");
}
temp = args.data;
for (i= 1; i < args.num_accounts; i++) {
temp = await instance.HashData.call(temp);
result = await instance.GetHash.call(i);
assert.equal( result, temp, "Hash at " + i + " wasn't stored
correctly");
}
})
});
});

Change instance.StoreHash.call(...) to instance.StoreHash.sendTransaction(...). call() runs the function locally instead of submitting the transaction. The result is any state change isn’t persisted.

Related

Create Web API in .net Core to process the Large no of records Parallel

I am developing API for to process around 25000 records. For each record I have to call another API which will return additional details for each product .These details needs to be updated in my database
The problem is since , I am processing large no of records & different API is being called inside my API, processing time is very High & data may be processed incorrectly .
[Route("GetSymbolDetailsParallel/{Exchange?}/{MarketGuid?}/{Symbol?}")]
public async Task<IActionResult> GetSymbolDetailsParallel(string Exchange = "", string MarketGuid = "", string Symbol = "")
{
GlobalFunctions objGolobal = new GlobalFunctions();
MongoClient client = new MongoClient(_ConFigSettings.MongoConnectionString);
var db = client.GetDatabase(_ConFigSettings.DatabaseName);
if (!string.IsNullOrEmpty(Symbol) && !string.IsNullOrEmpty(Exchange))
{
SymbolsBE objSymbols = db.GetCollection<SymbolsBE>("Symbols").Find(x => x.Symbol == Symbol + '.' + Exchange).FirstOrDefault();
await objGolobal.getSymbolsDetails(objSymbols, _ConFigSettings);
}
else if (!string.IsNullOrEmpty(MarketGuid))
{
try
{
// Get the List from the MongoDb Database & Pass the list to the function
List<SymbolsBE> lstSymbols = db.GetCollection<SymbolsBE>("Symbols").Find(x => x.MarketGuid == MarketGuid
&& x.isActive == true
&& (x.Fundamental == null || x.Fundamental.Code == "")).ToList();
GetMultipleFundamentalAsync(lstSymbols, _ConFigSettings);
}
catch (Exception ex)
{
}
}
return Ok("Sucess");
}
public async Task GetMultipleFundamentalAsync(List<SymbolsBE> lst, ConfigSettings _ConFigSettings)
{
DateTime StartDate = DateTime.Now;
int cnt = lst.Count;
for (int i = 0; i < cnt; i++)
{
await Task.Factory.StartNew(async () =>
{
await getSymbolsDetails(lst[i], _ConFigSettings);
});
}
}
public async Task getSymbolsDetails(SymbolsBE objSymbol, ConfigSettings _ConFigSettings)
{
// Code Download Details from API using HttpResponseMessage Res = await client.GetAsync(URL)
// This response will be saved in the Database
}

2 items added to DynamoDB when I run putItem

I am working on a bookmark skill for Alexa to teach myself DynamoDB. I've got over various hurdles, and can now write to my table. The issue is that whenever I putItem it adds two items. I'm trying to store the userID (partition key in DynamoDB), the timestamp of the request (as a string, and the sort key in DynamoDB), the title of a book and the page the user is on. This issue has only started since I tried working with a composite key, but I think I will need both these fields to a) get a unique primary key and b) be able to find the last item saved by a user.
Here's my intent code in Lambda:
'addBookmark': function() {
//delegate to Alexa to collect all the required slot values
var filledSlots = delegateSlotCollection.call(this);
//Get slot values as variables
var userID = this.event.session.user.userId;
var pageNumber = this.event.request.intent.slots.pageNumber.value;
var bookTitle = this.event.request.intent.slots.bookTitle.value;
//DynamoDB expects the timestamp as a string, so we convert it
var timeStamp = Date.now().toString();
var params = {
TableName: 'bookmarkV6',
Item: {
'userID' : {S: userID},
'timeStamp': { S: timeStamp },
'bookTitle': { S: bookTitle },
'pageNumber': { N: pageNumber },
}
};
//Call DynamoDB to add the item to the table
ddb.putItem(params, function(err, data) {
if (err) {
console.log("Error", err);
}
else {
console.log("Success", data);
}
});
const speechOutput = "OK, I've made a note that you're on page " + pageNumber + " of " + bookTitle + ".";
this.response.cardRenderer("Bookmark", "Page " + pageNumber + " of " + sentenceCase(bookTitle) +"\n \n" + stringToDate(timeStamp));
this.response.speak(speechOutput);
this.emit(':responseReady');
},
The "duplicate" items have slightly different timestamp values.
I am also having the same issues. It is happening of delegate collections used, but not able to solve. I have delegate slot confirmation for 6 slots and when I give all 6 slots value, finally I end up with 7 records in the table.
In delegateSlotCollection() function, return "COMPLETED" in the else block and in your addbookmark intent , please check like below after your delegateSlotCollection.call method
var filledSlots = delegateSlotCollection.call(this);
if(filledSlots==='COMPLETED'){
place all your save dynamodb logic here.
}

How should I handle very large projections in an event-sourcing context?

I wanted to explore the implications of event-sourcing v.s. active-record.
Suppose I have events with payloads like this:
{
"type": "userCreated",
"id": "4a4cf26c-76ec-4a5a-b839-10cadd206eac",
"name": "Alice",
"passwordHash": "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"
}
... and...
{
"type": "userDeactivated",
"id": "39fd0e9a-1025-42e6-8793-ed5bfa236f40"
}
I can reach the current state of my system with a reducer like this:
const activeUsers = new Map();
for (const event of events) {
// userCreated
if (event.payload.type == 'userCreated') {
const { id, name, passwordHash } = event.payload;
if (!activeUsers.has(id)) {
activeUsers.set(id, { name, passwordHash });
}
}
// userDeactivated
if (event.payload.type == 'userDeactivated') {
const { id } = event.payload;
if (activeUsers.has(id)) {
activeUsers.delete(id);
}
}
}
However, I cannot have my entire user table in a single Map.
So it seems I need a reducer for each user:
const userReducer = id => // filter events by user id...
But this will lead to slow performance because I need to run a reducer over all events for each new user.
I could also shard the users by a function of their id:
const shard = nShards => id => {
let hash = 0, i, chr;
if (this.length === 0) {
return hash;
}
for (i = 0; i < this.length; i++) {
chr = this.charCodeAt(i);
hash = ((hash << 5) - hash) + chr;
hash |= 0; // Convert to 32bit integer
}
return hash % nShards;
};
Then the maps will be less enormous.
How is this problem typically solved in event-sourcing models?
As I understand you think you need to replay all the events using a reducer in order to query all the users, correct?
This is where cqrs comes into play together with read models/denormalizers.
What almost everyone does is they have a read model (which for example is stored in a sql database or something else which is good at querying data). this read model is constantly being updated when new events are created.
When you need to query all users you query this read model and not replay all events.

NetSuite / Suitescript - Why does this Validate Field script enter an infinite loop?

My script is entering into an infinite loop and I have no idea why. I am running this on validate field and I am preventing a change to the field if another vendor bill exists with the same reference number, forcing the user to change the "Reference Number" to be unique. Here is my code:
function validateField(type, name) {
if (uniqueReferenceNum(type, name) === false) {
return false;
}
return true;
}
function uniqueReferenceNum(type, name) {
if (name !== 'tranid') {
return true;
}
var tranID = nlapiGetFieldValue('tranid');
var vendor = nlapiGetFieldValue('entity');
var vendorName = nlapiGetFieldText('entity');
var filters = new Array();
var columns = new Array();
filters[0] = new nlobjSearchFilter('entity', null, 'is', vendor);
filters[1] = new nlobjSearchFilter('tranid', null, 'is', tranID);
filters[2] = new nlobjSearchFilter('mainline', null, 'is', 'T');
columns[0] = new nlobjSearchColumn('internalid');
results = nlapiSearchRecord('vendorbill', null, filters, columns);
if (!results) {
return true;
}
alert("There is already a vendor bill with reference # " + tranID + " for " + vendorName + ". Please verify and change the reference number before continuing.");
return false;
}
For those still facing this issue, you can set the field in question - in this case, Reference Number - to a 'falsy' value such as an empty string. Only return false after checking that the field contains a 'truthy' value. Then display the alert or dialog to the user. This should break the validation loop.

Parse Cloud Code - How to query the User Class

I'm trying to query the Parse User Class but I'm not getting any results. The User class has a column labeled "phone", and I'm passing an array of dictionaries where each dictionary has a key "phone_numbers" that corresponds to an array of phone numbers. I'm trying to determine if a User in my table has one of those phone numbers. I'm not getting any errors running the code, but there does exist a user in my table with a matching phone number. What am I doing wrong?
Parse.Cloud.define("hasApp", function(request, response) {
var dict = request.params.contacts;
var num = 0;
var found = 0;
var error = 0;
var phoneNumbers = "";
for (var i = 0; i < dict.length; i++){
var result = dict[i].phone_numbers;
num += result.length;
for (var j = 0; j < result.length; j++){
phoneNumbers += result[j] + ", ";
var query = new Parse.Query(Parse.User);
query.equalTo("phone", result[j]);
query.find({
success: function(results) {
found = 1;
},
error: function() {
error = 1;
}
});
}
}
response.success("hasApp " + dict.length + " numbers " + num + " found " + found + " error " + error + " phoneNumbers " + phoneNumbers);
});
My response from calling this is
hasApp 337 numbers 352 found 0 error 0 phoneNumbers "list of phone numbers"
where some of those phone numbers appear in my User class. As far as I can tell I'm not getting any errors but I'm also not successfully querying the User table
UPDATE
After moving
response.success("hasApp " + dict.length + " numbers " + num + " found " + found + " error " + error + " phoneNumbers " + phoneNumbers);
to the body of the success block, I get the following error because I'm only allowed to call response.success once per cloud function.
Error Domain=Parse Code=141 "The operation couldn’t be completed. (Parse error 141.)"
UserInfo=0x14d035e0 {code=141, error=Error: Can't call success/error multiple times
at Object.success (<anonymous>:99:13)
at query.find.success (main.js:44:12)
at Parse.js:2:5786
at r (Parse.js:2:4981)
at Parse.js:2:4531
at Array.forEach (native)
at Object.w.each.w.forEach [as _arrayEach] (Parse.js:1:666)
at n.extend.resolve (Parse.js:2:4482)
at r (Parse.js:2:5117)
at Parse.js:2:4531}
Does this mean that I'm only able to verify one phone number at a time? So I can't pass an array of phone numbers and get the PFUser objects corresponding to those phone numbers (if they exist)?
I understand that my internal query to Parse.User is happening synchronously with my "hasApp" call, so is there a way to query Parse.User asynchronously? That way I can respond back to the client after checking all the phone numbers?
You can use Parse.Promise to solve logic where you need to iterate through O(n) number of database queries in one asynchronous Cloud Code definition:
var _ = require("underscore"),
isEmpty = function (o) { // standard function to check for empty objects
if (o == null) return true;
if (o.length > 0) return false;
if (o.length === 0) return true;
for (var p in o) {
if (hasOwnProperty.call(o, p)) return false;
}
return true;
};
Parse.Cloud.define("hasApp", function (request, response) {
var dict = request.params.contacts,
users = [];
var promise = Parse.Promise.as();
_.each(dict, function (obj) {
_.each(obj.phone_numbers, function (num) {
promise = promise.then(function () {
var promiseQuery = new Parse.Query(Parse.User);
promiseQuery.equalTo("phone", parseInt(num));
return promiseQuery.find({
success: function (result) {
if (isEmpty(result)) // don't save empty results e.g., "[]"
return;
users.push(result); // save results to a model to prevent losing it in scope
}
});
});
});
});
return promise.then(function () {
response.success("Found user(s): " + JSON.stringify(users));
});
});
Note a few things about this block:
You can append functionality iteratively to a Parse.Promise.
You can loose scope of database results in your iteration. Use a local array model to save your query results to. Although, I presume there is a better way to achieve the same functionality without the use of a user model, someone else can quote me on that.
Pay close attention to the way Parse handles data. For example, if you are storing your phone numbers as numbers, you have to make sure you use parseInt() when querying for it.
Be aware that you must attach your response.success() function to your promise to assure it is resolved after your iterations have run. From this block, your response from Parse will look similar to an array of User objects. You can decide on the many different ways you can save the data model depending on what you need it for.
As a final note, this block doesn't account for any validation or error handling that should be accounted for otherwise.
The problem seems to be that your response.success call is happening before the query can even happen. While you have response.success calls in your query success block, they are never called because you return success before the query is executed.
Try commenting out the line:
response.success("hasApp " + dict.length + " numbers " + num + " found " + found + " error " + error + " phoneNumbers " + phoneNumbers);
This should let the code go to your query, and maybe move it into the success block of your query.
Let me know if this works.
You're now calling response.success in a loop now. You should only call response.success/response.error once per cloud function.
It would help if you can show the original code with no commented out lines (to show your original intention) and the new code with no commented out lines as two separate code samples.
Querying a Parse.User is fairly easy and well explained in the documentation, here is an example taken from it
var query = new Parse.Query(Parse.User);
query.equalTo("gender", "female"); // find all the women
query.find({
success: function(women) {
// Do stuff
}
});
For your case it will be something like this:
Parse.Cloud.define("getAllFemales", function(request, response) {
var query = new Parse.Query(Parse.User);
query.equalTo("gender", "female"); // find all the women
query.find({
success: function(women) {
// Do stuff
}
});
});
Hope it helps, as always more info on the Documentation

Resources