При сотрудничестве с Civil одним из самых больших запросов от редакций новостей, публикующих в экосистеме, была устойчивость к цензуре, способ хранения всех документов внутри самого блокчейна.

Несколько требований:

  1. Любой должен иметь возможность получить указатель всех перечисленных статей.
  2. Статьи должны быть доступны для поиска во внешнем интерфейсе
  3. Затраты не могут быть непомерно высокими, менее 1 доллара за статью.

Мы приступили к исследованию проблемы и в итоге пришли к следующей технической схеме. Каждая служба новостей будет отдельным смарт-контрактом в блокчейне, а каждая статья будет создавать событие. Таким образом, любой может просмотреть все события и перестроить индекс на стороне клиента.

Мы повторяли процесс хранения статей, пока не нашли решение, которое стоит всего 0,04 доллара США за 100 предложений.

Сначала мы выбрали самый простой способ — хранить статью прямо в массиве Storage смарт-контракта.

contract Example {
  event ArticleStored(uint id);
  string[] public articleArray;
  function storeArticle(string calldata content) external {
    emit ArticleAddedInArray(articleArray.length);
    articleArray.push(content);
  }
}

Что в итоге стоило около $1,42 за статью, что слишком дорого.

Согласно Желтой бумаге Эфириума за байт статьи нужно платить трижды.

  1. Стоимость данных о транзакциях
  2. Стоимость загрузки данных транзакции в память
  3. Стоимость хранения данных из памяти в хранилище

Это решение самое дорогое, но единственное, если вы хотите, чтобы другие контракты сами читали статьи.

После этого мы сохранили статью в самом событии. Хранение данных в событиях значительно дешевле, чем хранение чего-либо в постоянном хранилище.
Недостатком здесь является то, что теперь статью можно извлечь только из-за пределов блокчейна, со стороны клиента.

contract Example {
  event ArticleStored(string content);
  function storeArticle(string calldata content) external {
    emit ArticleStored(content);
  }
}

Нам по-прежнему приходится платить трижды за статью, разница здесь в том, что хранилище Event стоит всего 32 газа за слово по сравнению с 20000 газа для хранилища. Это уже огромная экономия средств.

Мы хотим заплатить за статью только один раз и поместить ее только в сам вызов функции.

contract Example {
  event ArticleStored();
  
  function storeArticle() external {
    emit ArticleStored();
  }
}

Для этого нам нужно понять структуру вызовов, которую мы используем.

Во-первых, это закодированные инструкции смарт-контракта, это то, что смарт-контракт читает, чтобы понять, какую функцию вызывать. Затем идет сама статья в формате gzip и, наконец, длина статьи в формате gzip, отформатированная до 8 байт.

Вот как отправить транзакцию с помощью Truffle.

// Node has a built-in deflate function
const deflatedArticle = (await deflate(ARTICLE)).toString("hex");
// Data to call the function of the contract
const encodedABI = instance.contract.methods.inTransaction().encodeABI();
// Length of the article padded to 8 bytes so it's constant in length
const hexLength = deflatedArticle.length.toString(16).padStart(16, "0");
const txData = encodedABI + deflatedArticle + hexLength;
const web3 = Example.web3;
await web3.eth.sendTransaction({
  from: (await web3.eth.getAccounts())[0],
  to: instance.address,
  data: txData,
  gas: 4000000 // A random big number
}));

И в итоге мы получаем статью, которая навсегда хранится в блокчейне, доступна для поиска и стоит всего 0,04 доллара США!

Проверьте сам репозиторий, чтобы увидеть полный пример