Solidity mapping not returns an array in a struct - struct

The Solidity's mapping not returns an array inside a struct (when call mapping_data(), the data variable is undefined).
Just be able to read it from read() function.
Does anyone know a reason?
struct structPackage
{
uint256 ui;
string[2] data;
}
// the mapping_data(address) is not includes data variable, undefined.
mapping(address => structPackage) public mapping_data;
constructor()
{
structPackage storage data_package = mapping_data[msg.sender];
data_package.data[0] = "test1";
data_package.data[1] = "test2";
}
// This function shows data as expected, [ 'test1', 'test2' ].
function read() external view
returns (structPackage memory)
{
structPackage storage data_package = mapping_data[msg.sender];
return data_package;
}
Tested on Remix, mapping_data doesn't return the array inside struct

When a struct is used as value inside a mapping, the getter function of the mapping will ignore the mappings or arrays used inside the struct, because there is no easy way to provide keys or indexes to get the specific element from array or mapping. This mechanism exists to avoid high gas costs when returning an entire array or entire mapping.
Hence, if you want to access a complete array or mapping inside a struct (which is used as a value in a mapping which is public) make separate specific getters as required(Similar to as you wrote your read method).
Read Getter Functions docs
Read a similar GitHub issue

Related

The performance issue of validating entity using value object

I have the following value object code which validates CustCode by some expensive database operations.
public class CustCode : ValueObject<CustCode>
{
private CustCode(string code) { Value = code; }
public static Result<CustCode> Create(string code)
{
if (string.IsNullOrWhiteSpace(code))
return Result.Failure<CustCode>("Code should not be empty");
// validate if the value is still valid against the database. Expensive and slow
if (!ValidateDB(code)) // Or web api calls
return Result.Failure<CustCode>("Database validation failed.");
return Result.Success<CustCode>(new CustCode(code));
}
public string Value { get; }
// other methods omitted ...
}
public class MyEntity
{
CustCode CustCode { get; }
....
It works fine when there is only one or a few entity instances with the type. However, it becomes very slow for method like GetAll() which returns a lot of entities with the type.
public async IAsyncEnumerable<MyEntity> GetAll()
{
string line;
using var sr = File.OpenText(_config.FileName);
while ((line = await sr.ReadLineAsync()) != null)
{
yield return new MyEntity(CustCode.Create(line).Value); // CustCode.Create called many times
}
}
Since data in the file was already validated before saving so it's actually not necessary to be validated again. Should another Create function which doesn't validate the value to be created? What's the DDD idiomatically way to do this?
I generally attempt not to have the domain call out to retrieve any additional data. Everything the domain needs to do its job should be passed in.
Since value objects represent immutable state it stands to reason that once it has managed to be created the values are fine. To this end perhaps the initial database validation can be performed in the integration/application "layer" and then the CustCode is created using only the value(s) provided.
Just wanted to add an additional point to #Eben Roux answer:
In many cases the validation result from a database query is dependent on when you run the query.
For example when you want to check if a phone number exists or if some product is in stock. The answers to those querys can change any second, and though are not suited to allow or prevent the creation of a value object.
You may create a "valid" object, that is (unknowingly) becoming invalid in the very next second (or the other way around). So why bother running an expensive validation, if the validation result is not reliable.

ConcurrentModificationException with WeakHashMap

I have the code below but I'm getting ConcurrentModificationException, how should I avoid this issue? (I have to use WeakHashMap for some reason)
WeakHashMap<String, Object> data = new WeakHashMap<String, Object>();
// some initialization code for data
for (String key : data.keySet()) {
if (data.get(key) != null && data.get(key).equals(value)) {
//do something to modify the key
}
}
The Javadoc for WeakHashMap class explains why this would happen:
Map invariants do not hold for this class. Because the garbage
collector may discard keys at any time, a WeakHashMap may behave as
though an unknown thread is silently removing entries
Furthermore, the iterator generated under the hood by the enhanced for-loop you're using is of fail-fast type as per quoted explanation in that javadoc.
The iterators returned by the iterator method of the collections
returned by all of this class's "collection view methods" are
fail-fast: if the map is structurally modified at any time after the
iterator is created, in any way except through the iterator's own
remove method, the iterator will throw a
ConcurrentModificationException. Thus, in the face of concurrent
modification, the iterator fails quickly and cleanly, rather than
risking arbitrary, non-deterministic behavior at an undetermined time
in the future.
Therefore your loop can throw this exception for these reasons:
Garbage collector has removed an object in the keyset.
Something outside the code added an object to that map.
A modification occurred inside the loop.
As your intent appears to be processing the objects that are not GC'd yet, I would suggest using an iterator as follows:
Iterator<String> it = data.keySet().iterator();
int count = 0;
int maxTries = 3;
while(true) {
try {
while (it.hasNext()) {
String str = it.next();
// do something
}
break;
} catch (ConcurrentModificationException e) {
it = data.keySet().iterator(); // get a new iterator
if (++count == maxTries) throw e;
}
}
You can clone the key set first, but note that you hold the strong reference after that:
Set<KeyType> keys;
while(true) {
try {
keys = new HashSet<>(weakHashMap.keySet());
break;
} catch (ConcurrentModificationException ignore) {
}
}
for (KeyType key : keys) {
// ...
}
WeakHashMap's entries are automatically removed when no ordinary use of the key is realized anymore, this may happens in a different thread. While cloning the keySet() into a different Set a concurrent Thread may remove entries meanwhile, in this case a ConcurrentModificationException will 100% be thrown! You must synchronize the cloning.
Example:
Collections.synchronizedMap(data);
Please understand that
Collections.synchronizedSet(data.keySet());
Can not be used because data.keySet() rely on data's instance who is not synchronized here! More detail: synchronize(keySet) prevents the execution of methods on the keySet but keySet's remove-method is never called but WeakHashMap's remove-method is called so you have to synchronize over WeakHashMap!
Probably because your // do something in the iteration is actually modifying the underlying collection.
From ConcurrentModificationException:
For example, if a thread modifies a collection directly while it is iterating over the collection with a fail-fast iterator, the iterator will throw this exception.
And from (Weak)HashMap's keySet():
Returns a Set view of the keys contained in this map. The set is backed by the map, so changes to the map are reflected in the set, and vice-versa. If the map is modified while an iteration over the set is in progress (except through the iterator's own remove operation), the results of the iteration are undefined.

Calling Properties from Struct in c#

i have a structure defined, which contains a public field and a public property named _one and One respectively, now i instantiate the struct in the main function (not creating new object), and called the Property from the struct, i am getting the compile time error saying use of unassigned local variable One, however when i called the field _one, it works pretty expected here what i am doing:
public struct myStruct
{
public int _one;
public int One
{
get { return _one; }
set { _one = value; }
}
public void Display()
{
Console.WriteLine(One);
}
}
static void Main(string[] args)
{
myStruct _struct;
_struct.One = 2; // Does not works
_struct._one = 2; // Works fine
}
can anyone explain whats the reason behind this, could not understand the concept.
You need to initialize the struct in order for the property to be accessible - _struct has a default value otherwise:
myStruct _struct = new myStruct();
By the way - mutable value types are evil.
This is unintuitive behavior, but it is permitted by the rules of Definite assignment checking. Described in excruciating detail in section 5.3 of the C# Language Specification. The key phrase, early in the chapter is:
In additional to the rules above, the following rules apply to struct-type variables and their instance variables:
- An instance variable is considered definitely assigned if its containing struct-type variable is considered definitely assigned.
- A struct-type variable is considered definitely assigned if each of its instance variables is considered definitely assigned.
It is the latter rule that permits this. In other words, you can also initialize a struct by assigning all of its variables. You can see this by trying these snippets:
myStruct _struct = new myStruct();
_struct.Display(); // fine by the 1st bullet
myStruct _struct;
_struct.Display(); // bad
myStruct _struct;
_struct._one = 2;
_struct.Display(); // fine by the 2nd bullet
So you don't get CS0165 by assigning the field because that would disallow initializing the structure by assigning its variables.
The reasons which would favor using read-write properties instead of exposed fields in class definitions do not apply to structures, since they can support neither inheritance nor update notifications, and the mutability of a struct's field depends upon the mutability of the struct instance, regardless of whether the field is exposed or not. If a struct is supposed to represent a group of related but freely-independently-modifiable variables, it should simply expose those variables as fields. If a property with a backing field is supposed to be read-only, the constructor should set the backing field directly, rather than via property setter.

Handle NULL BLOB-s in MFC

I have an old MFC project that I need to expand. For database operations I use a class derived from CRecordSet, and bind Oracle BLOB to CByteArray. When I retrieve a row with null blob, I get an array with size of 1 byte, and value 0xFF. Is there a way to check if a field is actually NULL in database? Or is this 0xFF array actually a value denoting a null BLOB?
OK, I found it. The function is CRecordset::IsFieldNull, the parameter is the address of bound CByteArray object, and the function can be only used between Open() and Close(). Something like this:
void CMySet::DoFieldExchange(CFieldExchange* pFX)
{
...
RFX_Binary(pFX, _T("[THE_BLOB]"), m_TheBlob, MAX_BLOB_SIZE);
}
void CMySet::ReadBlob(CByteArray& theBlob, BOOL& isNull)
{
m_strFilter = ...;
Open();
isNull = IsFieldNull(&m_TheBlob);
if (!isNull)
theBlob.Copy(m_TheBlob);
Close();
}

DynamicMethod code unverifiable in .Net 4.0 (found ref 'this' pointer... expected ref '<>f__AnonymousType1`)

Was using this solution to convert anonymous types to dictionaries using reflection.emit. Was working fine until I changed to .Net 4.0 from 3.5.
Now, I'm getting the "System.Security.VerificationException: Operation could destabilize the runtime." error.
Converted the anonymously loaded dynamic method to one hosted in a dynamic assembly, saved it, then ran peverify.exe on it to find out what was wrong.
Got: [IL]: Error: [DynamicAssemblyExample.dll : MyDynamicType::MyMethod][offs
et 0x0000000D][found ref ('this' ptr) 'MyDynamicType'][expected ref '<>f__AnonymousType1`3[System.String,System.Int32,System.Byte]'] Unexpected type on the stac
k.
[IL]: Error: [DynamicAssemblyExample.dll : MyDynamicType::MyMethod][offs
et 0x0000000D] Method is not visible.
2 Error(s) Verifying DynamicAssemblyExample.dll
The code:
foreach (PropertyInfo property in itemType.GetProperties(attributes).Where(info => info.CanRead))
{
// load Dictionary (prepare for call later)
methIL.Emit(OpCodes.Ldloc_0);
// load key, i.e. name of the property
methIL.Emit(OpCodes.Ldstr, property.Name);
// load value of property to stack
methIL.Emit(OpCodes.Ldarg_0);
methIL.EmitCall(OpCodes.Callvirt, property.GetGetMethod(), null);
// perform boxing if necessary
if (property.PropertyType.IsValueType)
{
methIL.Emit(OpCodes.Box, property.PropertyType);
}
// stack at this point
// 1. string or null (value)
// 2. string (key)
// 3. dictionary
// ready to call dict.Add(key, value)
methIL.EmitCall(OpCodes.Callvirt, addMethod, null);
}
Is there a way to derefence the pointer to the actual property? Or do I have to cast it somehow? Any pointers?
Regards!
Sorry guys, made a mistake, since the actual dynamic method creates a delegate type that acts on the instance of the anonymous (or non-anonymous) type, the Ldarg_0 code is looking for a something that is not there in this debug implementation.
So I, changed it to OpCodes.Ldnull.
var attributes = BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy;
foreach (PropertyInfo property in itemType.GetProperties(attributes).Where(info => info.CanRead))
{
// load Dictionary (prepare for call later)
methIL.Emit(OpCodes.Ldloc_0);
// load key, i.e. name of the property
methIL.Emit(OpCodes.Ldstr, property.Name);
// load value of property to stack
methIL.Emit(OpCodes.Ldnull);
//methIL.Emit(OpCodes.Castclass, itemType);
methIL.EmitCall(OpCodes.Callvirt, property.GetGetMethod(), null);
// perform boxing if necessary
if (property.PropertyType.IsValueType)
{
methIL.Emit(OpCodes.Box, property.PropertyType);
}
// stack at this point
// 1. string or null (value)
// 2. string (key)
// 3. dictionary
// ready to call dict.Add(key, value)
methIL.EmitCall(OpCodes.Callvirt, addMethod, null);
}
But I still get a method not visible error after peverifying it. Is it that get methods for properties of anonymous types are not visible via reflection?
Just a suggestion, have you tried to rewrite the code that emits IL to actually write to the dictionary - i.e. no Reflection.Emit ? My bet is that the generated IL is not proper in some way, not the code that accesses the anonymous type.

Resources