LoginSignup
1
2

More than 3 years have passed since last update.

IOSTコントラクト キャッシュ機構を用いたgasの削減

Last updated at Posted at 2020-05-20

目的

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 }
}());
1
2
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2