I am working on a Solidity smart contract and I want to store an array of structs inside another struct. Here are my structs:
struct Product {
string productId;
string cabineNumber;
string productName;
string country;
string factoryNumber;
string productWeight;
string productAmount;
}
struct Form {
uint256 Id;
string purchId;
string customerName;
string customerPhone;
string contractNumber;
Product[] products;
uint256 created;
uint256 updated;
}
As you can see, the Form struct contains an array of Product structs called products.
I have a function to initialize a Product struct:
function initProduct(string[] memory product) public returns (Product memory) {
Product memory myproduct;
myproduct.productId = product[0];
myproduct.cabineNumber = product[1];
myproduct.productName = product[2];
myproduct.country = product[3];
myproduct.factoryNumber = product[4];
myproduct.productWeight = product[5];
myproduct.productAmount = product[6];
return myproduct;
}
I also have a function to create a Form struct:
function createForm(Form memory form, string[] memory product) public returns (bool) {
Product memory productEvi;
productEvi = initProduct(product);
Product[] memory products = new Product[](1);
products[0] = productEvi;
forms.push(Form(
form.Id,
form.purchId,
form.customerName,
form.customerPhone,
form.contractNumber,
products, // Error: copying of type struct Product[] memory to storage not yet supported
form.created,
form.updated
));
uint256 index = findFormIndex(form.Id);
forms[index].updated = block.timestamp;
forms[index].created = block.timestamp;
return true;
}
However, I am getting the error "Copying of type struct Product[] memory to storage not yet supported" when trying to store the products array in the Form struct. How can I fix this error and store an array of Product structs inside a Form struct?
I tried to store multiple instances of a struct Product inside another struct Form and push the Form object to an array. I expected the code to compile without any errors and to be able to store and retrieve multiple Product objects within a Form.
I have this code:
function somePureFunction() public pure returns(uint256){
uint8 temp = 255;
return 2 + temp;
}
This code gives:
call to SimpleStorage.somePureFunction errored: VM error: revert.
revert
The transaction has been reverted to the initial state.
Note: The called function should be payable if you send value and the value you send should be less than your current balance.
But this works:
function somePureFunction() public pure returns(uint256){
return 2 + 255;
}
In particular your problem refers to value about temp that you give to this variable.
When you declare a variable with datatype uint8 you must to put inside it a value from 0 - 255 (255 excluded). For calculate the range of a specific uint, you can use this statement:
MaximumRange = 2*[numberOfBit]-1
Example:
Issue: I want know what is the range about uint32.
Expression = 2*32-1
Result = 0 - 4294967295
In your specific case, if you change this line:
uint8 temp = 255;
with this:
uint16 temp = 255;
it'll work successfully.
NOTE: You can change current datatype temp variable with other uint datatype like: uint16, uint32, uint64 and others. You must to keep in your mind the range of a single datatype and the value that you want to store inside the variable.
Ok. So I know this should be easy to do, I simply want to set a default value in the following:
uint8 public gasPriceLimit; //Gas Price Limit
//Constructor
constructor(string _name, string _symbol, uint8 _decimals) public {
name = _name;
symbol = _symbol;
decimals = _decimals;
uint8 gasPriceLimit = 999;
}
However, doing this I get the following error when compiling:
Type int_const 999 is not implicitly convertible to expected type uint8.
I also tried setting in the declaration itself without luck.
Cheers
Ok. A mystery to me, but if I change to use uint instead of uint8 then the following works fine:
uint public gasPriceLimit = 999;
I am trying to create a contract from a contract factory using the following function:
function createContract(string _var1, string _var2,
uint32 _var3, string _var4, string _var5,
string _var6, uint32 _var7, uint32 _var8, uint32 _var9,
uint32 _var10, uint32 _var11)
public returns (address contractAddress) {
return new Contract(_var1, random1, random2, _var2,
_var3, _var4, _var5, _var6, _var7, _var8,
_var9, _var10, _var11);
}
N.B. random1 and random2 are fields in the contract factory.
This function throws Stack too deep, try using less variables. I have read that I should split up the function etc. to get around this, but obviously, that is not an option here. Is there a way to get this working?
So, initially I tried grouping the variables by type into this:
function createContract(string[] _var1, uint32[] _var2)
public returns (address contractAddress) {
return new Contract(_var1, random1, random2, _var2);
}
However, nested dynamic arrays are not supported at this time. As string is represented as byte[] in EVM, a string[] is in fact passed as a byte[][].
I ended up grouping the uint32 and leaving the strings:
function createContract(string _var1, string _var2, uint32[] _var3,
string _var4, string _var5, string _var6)
public returns (address contractAddress) {
return new Contract(_var1, random1, random2, _var2,
_var3, _var4, _var5, _var6);
}
EDIT: Even though this method works, it is badly designed. See my other answer for a better workaround for this.
I went one step further with this as having an array of unit32 is ambiguous and confusing in terms of the position of a specific argument.
My final attempt utilized the struct type to provide a less ambiguous implementation. This struct is in a library in a separate file Library.sol:
struct ContractArgs {
uint32 var1;
string var2;
uint32 var3;
....
}
The factory method looks like this:
function createContract(Library.ContractArgs _contractArgs)
public returns (address contractAddress) {
return new Contract(_contractArgs, random1, random2);
}
And my constructor looks like this:
function Contract(Library.ContructorArgs _contractorArgs,
uint32 _supplierId, string _supplierName) {
contractArgs = _contractArgs;
random1 = _random1;
random2 = _random2;
}
bellow code is the marshling of a native win32 code.
but i get an error message
type load exception, can not load from assembly because it contains an object field at offset 0 that is incorrectly aligned or overlapped by a non-object field
there is a structure S1 with both value-type member and reference-type.. this structure is a member of union which has to have fieldOffset, but all S1 members can not start from fieldOffset 0 they are a mixture of reference and value type...how can I handle that??
[StructLayout(LayoutKind.Sequential)]
public struct S1
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = Const.FieldSizeMsgid + 1)]//Reference Type
public String MsgId;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = Const.FieldSizeTime + 1)]//Reference Type
public String SendTime;
public UInt32 SubsSeq;//Value Type
public UInt32 ServTime;//Value Type
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = Const.FieldSizeFillerA1 + 1)]//Reference Type
public String Filler;
}
[StructLayout(LayoutKind.Explicit)]
public struct AdminData
{
[FieldOffset(0)] public S1 S11;// get an error because the S1 has both reference type member and value type member
[FieldOffset(0)] public S2 S22;
[FieldOffset(0)] public S3 S33;
}
I know I have to break the S1 into 2 structures, one with value-type members and the other for reference-type members..but I do not know how to do it and how to reference them in AdminData which is a union.
EDIT:
here is the c++ code
typedef struct S1
{
char MsgId [Const.FieldSizeMsgid + 1];//Reference Type
char SendTime[Const.FieldSizeTime + 1];//Reference Type
int SubsSeq;//Value Type
int ServTime;//Value Type
char Filler[Const.FieldSizeFillerA1 + 1];//Reference Type
}
union AdminData
{
S1 S11;//has both value type member and reference type member
S2 S22;//has both value type member and reference type member
S3 S33;//has both value type member and reference type member
}
typedef struct MMTPMsg
{
int Length;
short Type;
AdminData Data; //the union
long long TimeStamp;
}
As you have discovered you cannot overlay reference types on top of value types. So to implement your union, you need to use either one or the other. Your structures must contain value types and so we conclude that you must use value types exclusively.
So, how do you implement your character arrays as value types? By using a fixed size buffer.
unsafe public struct S1
{
fixed byte MsgId[Const.FieldSizeTime + 1];
....
}