目的
storageAPIはgasの消費量が多いため(300gas),同じkey, field の値を何度も参照したり変更する場合は,putやgetの回数を極力減らしたい.
着想
最も削減できる手段はコントラクトの最適化を行う事だが,ある程度の規模を超えてくるとコーディングが大変になる.そこで,storage API のラッパーを実装してgasの削減を目指した.
概要
storage情報にアクセスしたらその情報をキャッシュに保存.以降のアクセスはstorageではなくキャッシュに行う.
変更が行われると,そのkeyとfieldを記録する.
トランザクション処理の最後に,変更があったキャッシュの内容のみをstorageに反映する.
実装
const state = (function () {
const _cache = {};
const _modified = {};
function get(key, field) {
if (typeof _cache[key] === "undefined")
_cache[key] = {};
if (typeof _cache[key][field] === "undefined")
_cache[key][field] = storage.mapGet(key, field);
return JSON.parse(_cache[key][field]);
}
function exists(key, field) {
if (typeof _cache[key] === "undefined")
_cache[key] = { [field]: storage.mapGet(key, field) };
else if (typeof _cache[key][field] === "undefined")
_cache[key][field] = storage.mapGet(key, field);
return typeof _cache[key][field] === "string";
}
function require_exists(expect, key, field) {
if (expect !== exists(key, field))
throw `property_exists_expect_${expect}: ${key}, ${field}`;
}
function init(key, field, value) {
require_exists(false, key, field);
_cache[key][field] = JSON.stringify(value);
if (typeof _modified[key] === "undefined")
_modified[key] = [field];
else if (_modified[key].indexOf(field) === -1)
_modified[key].push(field);
}
function update(key, field, value) {
require_exists(true, key, field);
_cache[key][field] = JSON.stringify(value);
if (typeof _modified[key] === "undefined")
_modified[key] = [field];
else if (_modified[key].indexOf(field) === -1)
_modified[key].push(field);
}
function remove(key, field) {
require_exists(true, key, field);
_cache[key][field] = null;
if (typeof _modified[key] === "undefined")
_modified[key] = [field];
else if (_modified[key].indexOf(field) === -1)
_modified[key].push(field);
}
function merge() {
for (const key in _modified)
for (const field of _modified[key])
if (_cache[key][field] === null)
storage.mapDel(key, field);
else
storage.mapPut(key, field, _cache[key][field]);
}
return { get, exists, require_exists, init, update, remove, merge }
}());