Skip to content
This repository was archived by the owner on Aug 27, 2025. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions evm-ds/src/scillabackend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ impl ScillaBackend {
address, query_name, key, use_default
);
let mut query = ScillaMessage::ProtoScillaQuery::new();
query.set_is_mutable(true);
query.set_name(query_name.into());
if let Some(key) = key {
query.set_indices(vec![bytes::Bytes::from(format!("{:X}", key))]);
Expand Down Expand Up @@ -198,6 +199,7 @@ impl ScillaBackend {
pub(crate) fn encode_storage(&self, key: H256, value: H256) -> (Bytes, Bytes) {
let mut query = ScillaMessage::ProtoScillaQuery::new();
query.set_name("_evm_storage".into());
query.set_is_mutable(true);
query.set_indices(vec![bytes::Bytes::from(format!("{:X}", key))]);
query.set_mapdepth(1);
let mut val = ScillaMessage::ProtoScillaVal::new();
Expand Down
127 changes: 99 additions & 28 deletions src/libPersistence/ContractStorage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -448,37 +448,108 @@ bool ContractStorage::FetchExternalStateValue(
return true;
}

// For _evm_storage, we know the type, so we don't have to query it.
bool fetchType;
if (query.name() == "_evm_storage") {
type = "ByStr32";
fetchType = false;
} else {
fetchType = true;
// External state queries don't have map depth set. Get it from the
// database.
map<string, zbytes> map_depth;
string map_depth_key =
GenerateStorageKey(target, MAP_DEPTH_INDICATOR, {query.name()});
FetchStateDataForKey(map_depth, map_depth_key, true);
if (query.is_mutable()) {
// For _evm_storage, we know the type, so we don't have to query it.
bool fetchType;
if (query.name() == "_evm_storage") {
type = "ByStr32";
fetchType = false;
} else {
fetchType = true;
// External state queries don't have map depth set. Get it from the
// database.
map<string, zbytes> map_depth;
string map_depth_key =
GenerateStorageKey(target, MAP_DEPTH_INDICATOR, {query.name()});
FetchStateDataForKey(map_depth, map_depth_key, true);

int map_depth_val;
try {
map_depth_val = !map_depth.empty()
? std::stoi(DataConversion::CharArrayToString(
map_depth[map_depth_key]))
: -1;
} catch (const std::exception& e) {
LOG_GENERAL(WARNING, "invalid map depth: " << e.what());
return false;
}
query.set_mapdepth(map_depth_val);
fetchType = true;
}

// get value
return FetchStateValue(target, query, dst, d_offset, foundVal, fetchType,
type);
} else { //! query.is_mutable
// Fetch init data
zbytes init_data = GetInitData(target);
if (init_data.empty()) { // This is possible if no contract exists at the
// address, and should not cause an error
foundVal = false;
return true;
}

int map_depth_val;
try {
map_depth_val = !map_depth.empty()
? std::stoi(DataConversion::CharArrayToString(
map_depth[map_depth_key]))
: -1;
} catch (const std::exception& e) {
LOG_GENERAL(WARNING, "invalid map depth: " << e.what());
return false;
// Convert init data to JSON
string init_data_str = DataConversion::CharArrayToString(init_data);
Json::Value init_data_json;
if (!JSONUtils::GetInstance().convertStrtoJson(init_data_str,
init_data_json)) {
return false; // We have a malformed init data
}
query.set_mapdepth(map_depth_val);
fetchType = true;
}

// get value
return FetchStateValue(target, query, dst, d_offset, foundVal, fetchType,
type);
// Entry is the data entry matching the variable name
Json::Value entry;
for (auto it = init_data_json.begin(); it != init_data_json.end(); it++) {
if ((*it)["vname"] == query.name()) {
entry = *it;
}
}
if (!entry) { // This is possible if the parameter name is not
// declared, and should not cause an error
foundVal = false;
return true;
}

// This is the type we return - if this is a map lookup, then we parse the
// type on the OCaml side.
Json::Value res_type = entry["type"];
if (!res_type) {
return false; // We have a malformed init data
}

if (query.ignoreval()) { // Only produce type information
foundVal = true;
type = res_type.asString();
return true;
} else { // See if there is a value to return
ProtoScillaVal value;
Json::Value cur_val = entry["value"]; // Find the value of the parameter
if (!cur_val) {
return false; // We have a malformed init data
}
// If this is a map lookup, traverse the indices
for (const auto& index : query.indices()) {
// See if the key exists in the map
Json::Value next_entry = cur_val["key"];
if (!next_entry) { // This is possible if the key does not exist
// in the map, and should not cause an error
foundVal = false;
return true;
}
cur_val = next_entry["val"]; // Value of the map entry
if (!cur_val) {
return false; // We have a malformed init data
}
}

string cur_val_str = JSONUtils::GetInstance().convertJsontoStr(cur_val);
zbytes cur_val_bval = zbytes(cur_val_str.begin(), cur_val_str.end());
value.set_bval(cur_val_bval.data(), cur_val_bval.size());
foundVal = true;
type = res_type.asString();
return SerializeToArray(value, dst, 0);
}
}
}

void ContractStorage::DeleteByPrefix(const string& prefix) {
Expand Down
7 changes: 4 additions & 3 deletions src/libPersistence/ScillaMessage.proto
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ message ProtoScillaVal
message ProtoScillaQuery
{
string name = 1;
uint32 mapdepth = 2;
repeated bytes indices = 3;
bool ignoreval = 4;
bool is_mutable = 2;
uint32 mapdepth = 3;
repeated bytes indices = 4;
bool ignoreval = 5;
}