How can I add a created at for smart contract? - database

I'm writing a smart contract for patient records. But the data will be in time-series data format. And I guess I should add created_at field for that. But I don't know exactly how to do this.
I'm pretty new at this job. Can you help me?
You can see part of the struct:
struct Patient {
string name;
uint16 age;
//max of uint16 is 4096
//if we use uint8 the max is uint8
string telephone;
string homeAddress;
uint64 birthday; //unix time
string disease; //disease can be enum
Gender gender;
}

You can use the block.timestamp keyword for have current block timestamp as seconds since unix epoch which your transaction is included.
More information about block.timestamp here.
You must to set your createdAt variable into a struct:
struct Patient {
string name;
uint16 age;
//max of uint16 is 4096
//if we use uint8 the max is uint8
string telephone;
string homeAddress;
uint64 birthday; //unix time
string disease; //disease can be enum
Gender gender;
// NOTE: createdAt variable
uint createdAt
}
And then you must use this statement for set this variable:
[your_struct_variable] = block.timestamp;
Example of smart contract code:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Hospital {
enum Gender { MALE, FEMALE }
struct Patient {
string name;
uint16 age;
//max of uint16 is 4096
//if we use uint8 the max is uint8
string telephone;
string homeAddress;
uint64 birthday; //unix time
string disease; //disease can be enum
Gender gender;
uint256 createdAt;
}
mapping(address => Patient) _patients;
function setPatients() public {
Patient memory _patient = Patient({
name: "test",
age: 50,
telephone: "test",
homeAddress: "test",
birthday: 1010101010,
disease: "test",
gender: Gender.MALE,
createdAt: block.timestamp
});
_patients[msg.sender] = _patient;
}
function getPatient() external view returns(Patient memory) {
return _patients[msg.sender];
}
}

Related

Returned error: VM Exception while processing transaction: revert

I'm trying to create the contract using mapping struct and array. My goal is to allow companies to save several data in this system.
I can deploy it on Remix, but I faced the problem Returned error: VM Exception while processing transaction: revert when I wanna interact with the function saveStandard.
However, if I get rid of the array part in the contract, it worked well. Anyone know what happened?
The following is my code(with array)
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
contract Storage{
struct UserInfo {
uint index;
string[] time;
string[] source;
uint[] emission;
}
mapping (string => UserInfo) public users;
function saveStandard(uint input_material, uint weight, string memory input_time, string memory input_source)
public returns (string memory, uint, uint, string memory){
uint id = users[input_source].index + 1;
users[input_source].index = id;
users[input_source].time[id] = input_time;
uint Combustion = weight * input_material / 10;
uint Process = weight * input_material / 10;
users[input_source].emission[id] = Combustion + Process;
return (input_source, Combustion, Process, input_time);
}
function search(string memory input_source) public view returns (uint, string memory) {
uint id = 0;
while (id <= users[input_source].index) {
id += 1;
return (users[input_source].emission[id], users[input_source].time[id]);
}
}
}
And the following is the one without array, this worked well.
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
contract Storage{
struct UserInfo {
string time;
string source;
uint emission;
}
mapping (string => UserInfo) public users;
function saveStandard(uint input_material, uint weight, string memory input_time, string memory input_source)
public returns (string memory, uint, uint, string memory){
users[input_source].time = input_time;
uint Combustion = weight * input_material / 10;
uint Process = weight * input_material / 10;
users[input_source].emission = Combustion + Process;
return (input_source, Combustion, Process, input_time);
}
function search(string memory input_source) public view returns (uint, string memory) {
return (users[input_source].emission, users[input_source].time);
}
}
users[input_source].time[id] = input_time;
users[input_source].emission[id] = Combustion + Process;
It's these lines causing the revert.
You're trying to assign to time[id] array item, but the id index does not exist.
Your use case would fit better to use mappings
struct UserInfo {
uint index;
mapping(uint => string) time;
mapping(uint => string) source;
mapping(uint => uint) emission;
}
Then you can simply assign value by the id key:
users[input_source].time[id] = input_time;
users[input_source].emission[id] = Combustion + Process;

In a typedef struct with a union, do I need to instantiate all variables?

I am learning C and apologies if this the question isn't even asked right
But my question is, if I have a typedef struct that contains a union of two other typedef structs, do I need to instantiate all the variables?
For example, if I have the following code:
typedef struct dog {
char *breed;
long weight;
} dog;
typedef struct cat {
bool isBlackCat;
int numberOfLives;
} cat;
typedef struct animal {
int id;
int ownerID;
char *name;
bool isDog;
union {
struct dog aDog;
struct cat aCat;
} animals;
} animal;
If I were to use the above structure in a function like so:
Adoption adoptAnimal(char *nameParam, bool type, int ownerId) {
Adoption pet = (Adoption) malloc(sizeof(struct animal));
pet -> name = (char*) malloc((1 + strlen(nameParam)) * sizeof(char));
strcpy(pet->name, nameParam);
pet -> id = getId(); //function that generates an id
pet -> ownerId = ownerId;
pet -> isDog = type;
// if type = 1, it's a dog
if (type) {
pet -> animals.aDog.breed = some breed;
pet -> animals.aDog.weight = some weight;
} else {
pet -> animals.aCat.lives = 9;
pet -> animals.aCat.isBlackCat = 1;
}
return pet;
}
Is this proper/legal use of a typedef struct that contains a union?
The way the function is set up, the variables from the dog or cat struct will be assigned, but not both, is that allowed? Or do I need to assign all of the variables from both structs
Thank you
This is tricky because of how loosely typed C is. The animals union in the animal struct will be treated as either a dog or a cat, depending on how you are accessing it.
Remember that a union is a single memory location, and it is the size of the largest struct member. This means that calling the struct member animals is misleading, because it is only 1 animal (either a cat or a dog, but never both).
So when you execute pet->animals.aCat.lives = 9, the animals union is treated as a cat struct, and the lives member of that struct is set to 9. However, you could then try and read the animals union as a dog, and C would consider this valid. You would just get data that makes no sense.
I modified your code a little so that it would compile and created a main function to offer some insight about what is going on. The adoptAnimal() function recognizes that the animal being adopted is of type dog, so pet->animals is treated as a dog struct and the members are set accordingly. However, back in the main function, I can go ahead and read the animals union as either a dog or a cat, and C doesn't care.
typedef struct dog {
char *breed;
long weight;
} dog;
typedef struct cat {
bool isBlackCat;
int numberOfLives;
} cat;
typedef struct animal {
int id;
int ownerID;
char *name;
bool isDog;
union {
struct dog aDog;
struct cat aCat;
} animals;
} animal;
animal* adoptAnimal(char *nameParam, bool type, int ownerId) {
animal *pet = (animal*) malloc(sizeof(struct animal));
pet->name = (char*) malloc((1 + strlen(nameParam)) * sizeof(char));
strcpy(pet->name, nameParam);
pet->id = 1234; //function that generates an id
pet->ownerID = ownerId;
pet->isDog = type;
// if type = 1, it's a dog
if (type) {
pet->animals.aDog.breed = malloc(10);
strcpy(pet->animals.aDog.breed, "Pit bull");
pet->animals.aDog.weight = 1000;
} else {
pet->animals.aCat.numberOfLives = 9;
pet->animals.aCat.isBlackCat = 1;
}
return pet;
}
int main() {
animal *pet = adoptAnimal("George", 1, 1234);
printf("Dog: breed=\"%s\", weight=\"%ld\"\n", pet->animals.aDog.breed, pet->animals.aDog.weight);
printf("Cat: lives=\"%d\", isBlack=\"%d\"\n", pet->animals.aCat.numberOfLives, pet->animals.aCat.isBlackCat);
/* Output:
* Dog: breed="Pit bull", weight="1000"
* Cat: lives="32735", isBlack="0"
*/
}
So in conclusion, your use of a union with struct members is valid, and you only need to set the values for a dog struct or a cat struct, but not both. Also make sure you use appropriate naming and associated variables to understand what data your union holds.
I like the explanation that tutorialspoint gives on C unions, you might want to check it out if you haven't already.
Hope this clears things up, let me know if there's something I missed.

How do I initialize a struct containing another struct?

I'm new and i try to create a struct of stuct on C code. I don't understand how i can inizialize a struct of struct. Someneone help me?
I have:
#define SIZEHOSP 200
#define DIM 200
#define SIZESICK 2000
typedef struct SICKREGION {
char firstName[20];
char lastName[20];
char fiscalCode[16];
enum stateSick;
diagnosisDate data;
healingDate dataH;
};
typedef struct HOSPITAL {
char nameHospital[30];
int codeHospital;
char addressHospital[40];
char departmentManager[30];
int beds;
int bedsIntensiveCare;
};
HOSPITAL hospital[SIZEHOSP];
typedef struct REGION {
char nameRegion[20];
int codeRegion;
char MainTownRegion[15];
char namePresidentRegion[20];
int numberHospital;
int numberSickRegion;
HOSPITAL hospital[SIZEHOSP];
SICKREGION sickregion[SIZESICK];
};
REGION region[DIM] = {
{"Sicilia", 0004, "Palermo", "Musumeci", 40, 150},
{"sardegna", 4444, "cagliari", "pippo", 200, 50},
{"calabria", 0000, "reggio", "Josh", 12, 18}
};
for example i inizialized 3 type of REGION. but they are incomplete because i don't know how insert the value of structure HOSPITAL and SICKREGION inside the region[DIM]. What is the syntax? I hope he explained the problem well.
How do I initialize a struct containing another struct?
There are several ways to initialize a struct. To simplify, the following example uses smaller structs than those you provided...
The following will illustrate initialization with initialization with values ( = {,,,{,,}}; ), then with zeros = {0} :
typedef struct {
int count;
float cash;
char item[50];
}Purchase;
typedef struct {
int accnt;
char acct_name[50];
Purchase purch;
} Acct;
Acct acct = {100123, "Robert Baily", {15, 12.50, "Tires"}};
//Or, using member names to self document the initialization statement as suggested in comments:
Acct acct1 = Acct acct = {.accnt=100123, .acct_name="Robert Baily", {.count=15, .cash=12.50, .item="Tires"}};
Acct acct2 = {0};
int main(void)
{
printf("acct = %d\nAcct_name = %s\nitem = %s\ncount = %d\ncash = %3.2f\n", acct.accnt, acct.acct_name, acct.purch.item, acct.purch.count, acct.purch.cash);
printf("acct2 = %d\nAcct_name = %s\nitem = %s\ncount = %d\ncash = %3.2f\n", acct2.accnt, acct2.acct_name, acct2.purch.item, acct2.purch.count, acct2.purch.cash);
return 0;
}
Although these are small, they illustrate what you are doing with your larger, more complicated structs. I suggest that for your structs it will be extremely tedious, and probably not necessary to use the first method. struct declaration in an actual program is often initialized by zeroing. i.e. {0}

Malloc and realloc for union of structs linked to array of structs

What's the best way to dinamically allocate memory to an array of structs with union included? I should malloc and then realloc to record_user or to data_user? Below I explain more of it, this is the sample code:
core.h
#define MAX_USER sizeof(record_user) / sizeof(record_user[0])
#define MAX_ARTIST sizeof(record_artist) / sizeof(record_artist[0])
/* all my other defines here */
typedef enum {
admin = 1,
basic = 0
} type;
typedef struct {
int hour;
int minute;
int second;
} tm;
typedef struct {
int day;
int month;
int year;
} date;
typedef struct {
short id;
char name[MAX_USER_NAME];
char surname[MAX_USER_SURNAME];
char email[MAX_USER_EMAIL];
char password[MAX_PASSWORD_LENGTH];
date birthday;
date subscription_date;
tm subscription_time;
type role;
} user;
typedef struct {
short id;
char name[MAX_ARTIST_NAME];
char genre[MAX_GENRE][MAX_GENRE_NAME];
char producer[MAX_PRODUCER_NAME];
char nationality[MAX_NATIONALITY_NAME];
int starting_year;
} artist;
/* and other structs */
typedef struct {
enum { USER, ARTIST } type;
union {
user *u_user;
artist *u_artist;
};
int size;
} data;
data.h
#ifndef DATA_H
#define DATA_H
#include "core.h"
extern user record_user[];
extern artist record_artist[];
extern data data_user;
extern data data_artist;
/* etc */
#endif
data.c
#include "data.h"
// SOME PRESET DATA
user record_user[] = {
{ 1, "Name 1", "Surname 1", "name1.surname1#email.com", ",+o[oS", { 29, 9, 1996 }, { 7, 3, 2011 }, { 18, 25, 58 }, 0 },
/** The list goes on **/
}
artist record_artist[] = {
{ 1, "Coldplay", { "Pop", "Britpop", "Alternative Rock" }, "Parlophone", "United Kingdom", 1997 },
/** The list goes on **/
}
data data_user = { .type = USER,.u_user = record_user,.size = MAX_USER };
data data_artist = { .type = ARTIST,.u_artist = record_artist,.size = MAX_ARTIST };
As you can see, there is a union struct for artist and user. I decided to create a union struct in order to pass multiple array of structs to a generic function. In the full code, I have more unions, but that's not the point to list them all. I just really need to understand what's I'm going to further explain below.
record_user like record_artist has some preset data that I link to data_user and data_artist respectively in data.c. Now this data needs to be increased during the runtime. I mean if record_user has 100 preset data rows (same thing for record_artist) in it, I'd like to add more rows or even remove them. For that I know there's malloc and realloc. I tried to play with it, making some tests and I don't know what's the best way of doing that.
I tried to declare in my main.c file the following:
int main() {
data_user.u_user = (user *)malloc(size * sizeof(user));
/***/
}
but I also tried with this
int main() {
record_user = (user *)malloc(size * sizeof(user));
/***/
}
but as I already imagined I lose all the preset data delcared in data.c file.
MY GOAL
What I'd like to achieve is to malloc a temp size for my data (for starting 100) and then to link the array of structs (or the union struct), with the starting temp size, to my preset data in order for using them. Naturally, during runtime, I will add more rows, and for that I'll use realloc (or even remove them).
This is the sample code of my add function:
data *add_data(data *record_data) {
date record_date;
tm record_time;
switch (record_data->type) {
case USER:
{
/* SOMEWHERE HERE I should use realloc to my record_data */
int ID = record_data->size;
record_data->u_user[ID].id = ID;
printf("\n\n\tNEW USER");
printf("\n\tEnter name: ");
strcpy(record_data->u_user[ID].name, inputString(MIN_USER_NAME, MAX_USER_NAME));
printf("\tEnter surname: ");
strcpy(record_data->u_user[ID].surname, inputString(MIN_USER_SURNAME, MAX_USER_SURNAME));
printf("\tEnter email: ");
strcpy(record_data->u_user[ID].email, inputString(MIN_USER_EMAIL, MAX_USER_EMAIL));
printf("\tEnter password: ");
strcpy(record_data->u_user[ID].password, inputString(MIN_PASSWORD_LENGTH, MAX_PASSWORD_LENGTH));
/* etc for birthday, subscription date */
record_data->size += 1;
printf("\n\tUser added!");
return record_data;
}
case ARTIST:
/* asking for input data */
return record_data;
}
}
this is how I call the function instead in the main.c file
int main() {
/***/
data_user = *add_data(&data_user);
/***/
}
I don't know how to move here, if I should work with the struct record_user or the union struct data_user. If it's the same or not... if I work with the original struct (allocating memory), is the union capable of reading the new memory size or not? Or is it best to work with the union struct leaving the original struct untouched?
I hope someone clear my mind!

How to use a Union to store 2 different structs in 1 C array

I would like to create one array to store 2 types of C structs - Employee, and its 'child', Manager. I created a union Person to hold either of them and then tried creating an array with it, but it doesn't work. How can I get such an array to work? The relevant code is below.
typedef struct {
char name[20];
double salary;
} Employee;
//Manager struct inheriting from employee struct
typedef struct {
Employee employee;
int bonus;
} Manager;
typedef union{
Employee e;
Manager m;
} Person;
Manager boss;
Employee harry ;
Employee tommy;
Person staff[];
int main(void)
{
...
boss = newManager(...);
harry = newEmployee(...);
tommy = newEmployee(...);
I couldn't get the next line to work, I tried many things.
staff[3] = {boss, harry, tommy};
Try:
staff[0].manager = boss;
staff[1].employee = harry;
/* ... */
Or maybe:
Person staff [] = {
{.manager = boss},
{.employee = harry},
/* ... */
};
But ask yourself: how will you know later if staff[x] is a manager or a mere employee ?

Resources