<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[mecablog]]></title><description><![CDATA[Thoughts, stories and ideas.]]></description><link>https://blog.misosi.ru/</link><image><url>https://blog.misosi.ru/favicon.png</url><title>mecablog</title><link>https://blog.misosi.ru/</link></image><generator>Ghost 3.22</generator><lastBuildDate>Thu, 04 Dec 2025 01:14:31 GMT</lastBuildDate><atom:link href="https://blog.misosi.ru/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Hardhat による Ethereum スマートコントラクト開発メモ 小ネタ編]]></title><description><![CDATA[本記事では、Hardhat を使って Ethererum スマートコントラクトを開発・テストするときの小ネタを紹介する。]]></description><link>https://blog.misosi.ru/2022/06/02/hardhat-ethereum-smart-contract-development-tips/</link><guid isPermaLink="false">62950d901d2a1e1b4199c8b8</guid><category><![CDATA[tech]]></category><category><![CDATA[development]]></category><category><![CDATA[ethereum]]></category><category><![CDATA[hardhat]]></category><category><![CDATA[smart contract]]></category><dc:creator><![CDATA[mecab]]></dc:creator><pubDate>Thu, 02 Jun 2022 17:21:12 GMT</pubDate><media:content url="https://blog.misosi.ru/content/images/2022/06/hardhat_log-1.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://blog.misosi.ru/content/images/2022/06/hardhat_log-1.png" alt="Hardhat による Ethereum スマートコントラクト開発メモ 小ネタ編"><p>前回の記事で Hardhat を使って Ethereum スマートコントラクトを開発・テスト・デプロイする方法を紹介した。</p>
<figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://blog.misosi.ru/2022/06/02/smart-contract-development-and-testing-with-hardhat/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Hardhat を使った Ethereum スマートコントラクト開発メモ</div><div class="kg-bookmark-description">本記事では、Hardhat を使った Ethereum スマートコントラクト開発について紹介する。Hardhat はスマートコントラクト開発に必要なものが揃った開発環境であり、プロジェクトテンプレートの生成、コントラクトのコンパイルやシミュレーター上でのテスト、デプロイのいずれをも `hardhat` コマンドを通して行うことができる。さらに、TypeScript をサポートしており、TypeScript 版のテンプレートを生成できる上に、typechain を使って、コントラクトに対応する型定義ファイルを出力して開発に利用できる。</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://blog.misosi.ru/favicon.ico" alt="Hardhat による Ethereum スマートコントラクト開発メモ 小ネタ編"><span class="kg-bookmark-author">mecab</span><span class="kg-bookmark-publisher">mecablog</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://blog.misosi.ru/content/images/2022/06/hardhat_log.png" alt="Hardhat による Ethereum スマートコントラクト開発メモ 小ネタ編"></div></a></figure>
<p>前回は全体の流れを紹介したが、本記事ではより踏み込んだシナリオでのテスト方法を紹介する。</p>
<h1 id>複数のアドレスを使う</h1>
<p>コントラクトをデプロイしたアドレスとそれ以外とか、トークンの送り手側と受け手側など、複数のアドレスを使ったテストが必要な状況がある。この場合、以下のようにして別のアドレスを使ってコントラクトを操作できる。</p>
<pre><code class="language-ts">const [signer1, signer2, signer3] = await ethers.getSigners();
const Greeter = await ethers.getContractFactory(&quot;Greeter&quot;);

// signer1 としてデプロイ
const greeter = await Greeter.connect(signer1).deploy(&quot;Hello, world!&quot;);
await greeter.deployed();

// signer2 としてコントラクト呼び出し
await greeter.connect(signer2).greet();
// signer3 としてコントラクト呼び出し
await greeter.connect(signer3).greet();
</code></pre>
<p><code>connect()</code> を省略した場合、暗黙的に最初の signer (<code>signer1</code>) を利用して操作が行われると考えると分かりやすい。</p>
<p>シミュレーション時は 20 個のテスト用アドレスが元から用意されている。実際にネットワークと通信する場合は、<code>hardhat.config.ts</code> 内の <code>accounts</code> に含めた秘密鍵に対応した signer になると思うが確認はしていない。</p>
<h1 id>コントラクトのログを取得する</h1>
<p>コントラクトのログを取得するためには、<code>await tx.wait()</code> の返り値（<code>ContractReceipt</code>）の <code>events</code> 配列を取得する。 この配列の各要素内の <code>args</code> フィールド（<code>events[].args</code>）には、発生した順にログが格納されている。Solidity で定義したイベントの型は、TypeChain により生成される型定義ファイルの中に <code>${イベント名}Event</code> という名前で定義されており、ログの発生順が分かっていれば <code>events</code> の各要素を対応するイベント型にキャストできる。</p>
<p>例として、<code>Greeter.sol</code> を変更して、<code>setGreeting()</code> が呼ばれた時にログを出力する以下のようなコントラクトの場合</p>
<pre><code class="language-sol">pragma solidity ^0.8.0;

contract Greeter {
    event SetGreetingEvent(string oldGreeting, string newGreeting);
    string private greeting;

    constructor(string memory _greeting) {
        console.log(&quot;Deploying a Greeter with greeting:&quot;, _greeting);
        greeting = _greeting;
    }

    function greet() public view returns (string memory) {
        return greeting;
    }

    function setGreeting(string memory _greeting) public {
        emit SetGreetingEvent(greeting, _greeting);
        greeting = _greeting;
    }
}
</code></pre>
<p>以下のようなコードでログを取得できる。</p>
<pre><code class="language-ts">import { SetGreetingEventEvent as SetGreetingEvent } from '../typechain/Greeter';

//...

const Greeter = await ethers.getContractFactory(&quot;Greeter&quot;);
const greeter = await Greeter.deploy(&quot;Hello, world!&quot;);
await greeter.deployed();

expect(await greeter.greet()).to.equal(&quot;Hello, world!&quot;);

const setGreetingTx = await greeter.setGreeting(&quot;Hola, mundo!&quot;);

// wait until the transaction is mined
const receipt = await setGreetingTx.wait();
const { args } = receipt.events?.[0] as SetGreetingEvent;

expect([args[0], args[1]]).to.eql([&quot;Hello, world!&quot;, &quot;Hola, mundo!&quot;]); // 配列インデックスでのアクセス
expect([args.oldGreeting, args.newGreeting]).to.eql([&quot;Hello, world!&quot;, &quot;Hola, mundo!&quot;]); //プロパティ名でのアクセス
</code></pre>
<p>型定義はイベント型の名前にサフィックスとして <code>Event</code> とつけるので、元々の（コントラクト内での）イベント名を <code>xxxEvent</code> としていた場合、型名が <code>xxxEventEvent</code> となってしまうので注意したい。インポート時に名前を修正するのが良いと思う。イベント内の値には、配列インデックスとプロパティ名での両方でアクセスできる。</p>
<h1 id>シミュレーション時のネットワークへの介入</h1>
<p>テスト時に、ブロックのタイムスタンプを調整したいという状況がある。例えばタイムスタンプが重要なコントラクトをテストする場合だ。また、同じブロック内でコントラクトが実行された場合のテストをするために、マイニングのタイミングを調整したいこともある。このような場合、以下のように <code>network.provider.send()</code> でシミュレーターにコマンドを発行し、ネットワークに介入することができる。</p>
<pre><code class="language-ts">await ethers.provider.send('hardhat_reset', []); // ネットワークをリセットする
await ethers.provider.send('evm_setAutomine', [false]) // ブロックが自動でマイニングされないようにする
await ethers.provider.send(&quot;evm_setNextBlockTimestamp&quot;, [0]); // 次にマイニングされるブロックの timestamp を 0 にする
await ethers.provider.send(&quot;evm_mine&quot;, []);  // マイニングをする。
</code></pre>
<p>以上の例では、自動でマイニングされないようにした上で、timestamp が 0 のブロックをマイニングしている。最新のブロックよりも古い timestamp は設定できないので、事前にチェーンをリセットしている。自動マイニングを切った場合、<code>evm_mine</code> を発行するたびにブロックがマイニングされる。</p>
<p>他に利用できるコマンドは <a href="https://hardhat.org/hardhat-network/reference">Hardhat Network Reference</a> で調べることができる。</p>
<p>以上、テストでの小ネタを紹介した。特に最後のネットワークに介入する機能は便利で、様々なシナリオのテストに役立つと思う。</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Hardhat を使った Ethereum スマートコントラクト開発メモ]]></title><description><![CDATA[本記事では、Hardhat を使った Ethereum スマートコントラクト開発について紹介する。Hardhat はスマートコントラクト開発に必要なものが揃った開発環境であり、プロジェクトテンプレートの生成、コントラクトのコンパイルやシミュレーター上でのテスト、デプロイのいずれをも `hardhat` コマンドを通して行うことができる。さらに、TypeScript をサポートしており、TypeScript 版のテンプレートを生成できる上に、typechain を使って、コントラクトに対応する型定義ファイルを出力して開発に利用できる。]]></description><link>https://blog.misosi.ru/2022/06/02/smart-contract-development-and-testing-with-hardhat/</link><guid isPermaLink="false">6225b4bd1d2a1e1b4199c052</guid><category><![CDATA[tech]]></category><category><![CDATA[development]]></category><category><![CDATA[ethereum]]></category><category><![CDATA[smart contract]]></category><category><![CDATA[hardhat]]></category><category><![CDATA[typescript]]></category><dc:creator><![CDATA[mecab]]></dc:creator><pubDate>Thu, 02 Jun 2022 17:15:37 GMT</pubDate><media:content url="https://blog.misosi.ru/content/images/2022/06/hardhat_log.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://blog.misosi.ru/content/images/2022/06/hardhat_log.png" alt="Hardhat を使った Ethereum スマートコントラクト開発メモ"><p>Ethereum のスマートコントラクト開発について調べてみたところ、Hardhat を使って開発するのが楽そうだったのでメモしておく。</p>
<p>Hardhat はスマートコントラクト開発に必要なものが揃った開発環境であり、プロジェクトテンプレートの生成、コントラクトのコンパイルやシミュレーター上でのテスト、デプロイのいずれをも <code>hardhat</code> コマンドを通して行うことができる。さらに、TypeScript をサポートしており、TypeScript 版のテンプレートを生成できる上に、TypeChain を使って、コントラクトに対応する型定義ファイルを出力して開発に利用できる。</p>
<h1 id>プロジェクトの作成</h1>
<p><code>npm init</code> した新しいディレクトリで、<code>npm install --save-dev hardhat</code> として hardhat をインストールする。その後、<code>npx hardhat</code> とすると、初期設定のためにいくつか項目を質問される。</p>
<pre><code>👷 Welcome to Hardhat v2.9.1 👷‍

? What do you want to do? …
  Create a basic sample project
  Create an advanced sample project
❯ Create an advanced sample project that uses TypeScript
  Create an empty hardhat.config.js
  Quit
</code></pre>
<p>TypeScript を使いたいので、<code>Create an advanced sample project that uses TypeScript</code> を選ぶ。advanced といっても、そこまで複雑なテンプレートが生成されるわけではないので、TypeScript を使いたくない場合でも、<code>Create an advanced sample project</code> を選んでしまって問題ないと思う。</p>
<p>続けて</p>
<pre><code>? Hardhat project root: › /path/to/hardhat_example
? Do you want to add a .gitignore? (Y/n) › y
</code></pre>
<p>との質問によしなに答える。普通はデフォルトのまま Enter 連打で構わないだろう。最後に</p>
<pre><code>? Do you want to install this sample project's dependencies with npm (hardhat @nomiclabs/hardhat-waffle ethereum-waffle chai @nomiclabs/hardhat-ethers ethers @nomiclabs/hardhat-etherscan dotenv eslint eslint-config-prettier eslint-config-standard eslint-plugin-import eslint-plugin-node eslint-plugin-prettier eslint-plugin-promise hardhat-gas-reporter prettier prettier-plugin-solidity solhint solidity-coverage @typechain/ethers-v5 @typechain/hardhat @typescript-eslint/eslint-plugin @typescript-eslint/parser @types/chai @types/node @types/mocha ts-node typechain typescript)? (Y/n) · y
</code></pre>
<p>と、必要なライブラリのインストールを求められるので y と答えインストールすると、環境構築は終了だ。</p>
<h1 id>コントラクトの開発とテスト</h1>
<p>作成したコントラクトを <code>contracts/</code>　以下に配置する。サンプルとして <code>Greeter.sol</code> が最初から置いてあるのでこれを流用する。</p>
<pre><code>$ npx hardhat compile
</code></pre>
<p>とするとSolidity のコンパイラがダウンロード（初回のみ）され、コンパイルされる。コンパイルに成功すると、バイトコードやABIが含まれた <code>artifacts/Greeter.sol/Greeter.json</code> が生成される。</p>
<p>テストを行うには</p>
<pre><code>$ npx hardhat test
</code></pre>
<p>とする。このコマンドは <code>test</code> ディレクトリ以下の全てのファイルを Mocha のテストとして実行する。Hardhat と一緒に Mocha がインストールされているため、改めてインストールする必要はないので嬉しい。こちらにもサンプルとして <code>Greeter.sol</code> をテストするための <code>index.ts</code> が配置されている。</p>
<pre><code>$ npx hardhat test
No need to generate any newer typings.


  Greeter
Deploying a Greeter with greeting: Hello, world!
Changing greeting from 'Hello, world!' to 'Hola, mundo!'
    ✔ Should return the new greeting once it's changed (710ms)


  1 passing (712ms)
</code></pre>
<p>と、サンプルのテストが実行される。</p>
<p>簡単にテストコードを見てみよう。</p>
<pre><code class="language-ts">const Greeter = await ethers.getContractFactory(&quot;Greeter&quot;);
const greeter = await Greeter.deploy(&quot;Hello, world!&quot;);
await greeter.deployed();
</code></pre>
<p>ブロックチェーンとのインタラクションは <a href="https://www.npmjs.com/package/ethers">ethers</a> ライブラリで行う。<code>getContractFactory()</code> にコントラクト名を渡すと <code>CotractFactory</code> を得ることができ、これの <code>deploy()</code> メソッドを呼ぶことでコントラクトをデプロイすることができる。<code>ContractFactory</code> はデプロイ前のコントラクトコードそのものを表しており、<code>deploy()</code> で得られたオブジェクト <code>greeter</code> がネットワークにデプロイされたコントラクトに対応している。</p>
<p>コントラクトは、マイナーによってブロックに取り込まれることでそのデプロイが完了し、ブロックチェーン上で認識される。デプロイの完了を確かなものにするためには、<code>greeter.deployed()</code> を待つ。</p>
<p>あとは、<code>greeter</code> オブジェクトを使ってコントラクトを操作してテストを行う。Greeter コントラクトは、<code>greet()</code> を呼ぶと、デプロイ時に設定されたか、またはその後 <code>setGreeting()</code> で設定された挨拶文を返すという単純なものだ。以下でその通りの挙動をするか確認している。</p>
<pre><code class="language-ts">expect(await greeter.greet()).to.equal(&quot;Hello, world!&quot;);

const setGreetingTx = await greeter.setGreeting('Hola, mundo!');

// wait until the transaction is mined
await setGreetingTx.wait();

expect(await greeter.greet()).to.equal(&quot;Hola, mundo!&quot;);
</code></pre>
<p>データの取得のみで、チェーンの状態を変えない（<code>view</code> または <code>pure</code> な）関数を呼ぶためには、単純に対応したメソッドを呼ぶ。</p>
<pre><code class="language-ts">const greet: string = await greeter.greet();
</code></pre>
<p>上の例では、<code>greet</code> にはコントラクトが返す文字列が直接代入される。</p>
<p>一方、チェーンの状態を変える（＝ネットワークに対してトランザクションを発行する）関数を呼ぶ場合、トランザクションを表すオブジェクトが返される。このオブジェクトの <code>wait()</code> を待つことで、トランザクションの完了を待機できる。</p>
<pre><code class="language-ts">const setGreetingTx: ContractTransaction = await greeter.setGreeting('Hello');
await setGreetingTx.wait()
</code></pre>
<p><sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup></p>
<p>テストは EVM のシミュレーター上で実行される。その上、実行時の自分自身のアドレスもテストの実行時に hardhat が準備してくれるため、何も自分で準備することなく気軽にテストを実行できる <sup class="footnote-ref"><a href="#fn2" id="fnref2">[2]</a></sup>。</p>
<h2 id="typescript">コントラクトに対する TypeScript サポート</h2>
<p>ところで、Greeter コントラクトは、デプロイ時に <code>string</code> の引数を取っていた。</p>
<pre><code class="language-sol">constructor(string memory _greeting) {
    console.log(&quot;Deploying a Greeter with greeting:&quot;, _greeting);
    greeting = _greeting;
}
</code></pre>
<p>驚くべきことに、<code>Greeter.deploy()</code> の型は <code>Greeter__factory.deploy(_greeting: string, overrides?: (略): Promise&lt;Greeter&gt;</code> と、<code>_greeting: string</code> を取るようになっており、コントラクトに対応している。また、<code>greeter</code> オブジェクトにもコントラクトの各関数に対応するメソッドが生えている。これは、コントラクトのコンパイル時に <a href="https://github.com/dethcrypto/TypeChain">TypeChain</a> によって対応する型定義が生成されるためだ。このため、エディタによる補完もなされ、快適にコントラクトとのインタラクションを書くことができる。</p>
<p><img src="https://blog.misosi.ru/content/images/2022/03/223e1003a2c2782820d1c9d06da5868f.gif" alt="Hardhat を使った Ethereum スマートコントラクト開発メモ"></p>
<h2 id>コントラクトのデプロイ</h2>
<p>テストが完了したところで、コントラクトを実際にブロックチェーンネットワークにデプロイする。これは実際にネットワークと通信する必要があるため、ネットワークの情報や、自分自身のアドレスについて事前に設定する必要がある。（デプロイしようとするネットワーク上で、自分のアドレスが十分なガス代を持っている必要がある。これについては本項では説明しない。）</p>
<p><code>hardhat.config.ts</code> に設定を記述する。サンプルとして ropsten テストネットの設定が最初から記述されているので、自分が使いたいチェーンの情報を追加する。例えば Polygon Mumbai テストネット<sup class="footnote-ref"><a href="#fn3" id="fnref3">[3]</a></sup>を利用したいなら</p>
<pre><code class="language-ts">const config: HardhatUserConfig = {
  //...
  networks: {
    ropsten: {
      url: process.env.ROPSTEN_URL || &quot;&quot;,
      accounts:
        process.env.PRIVATE_KEY !== undefined ? [process.env.PRIVATE_KEY] : [],
    },
    mumbai: {
      url: process.env.MUMBAI_URL || &quot;https://rpc-mumbai.maticvigil.com&quot;,
      accounts:
        process.env.PRIVATE_KEY !== undefined ? [process.env.PRIVATE_KEY] : [],
    },
  },
  //...
}
</code></pre>
<p>といった形になる。ここでキー（<code>mumbai</code>）は何でも良いが、ここで書いたキーを後でネットワークの指定に使う。具体的なパラメータは <code>.env</code> ファイルで設定する <sup class="footnote-ref"><a href="#fn4" id="fnref4">[4]</a></sup>。<code>.env.sample</code> を <code>.env</code> にリネームし、各項目を設定する。</p>
<pre><code>MUMBAI_URL=https://rpc-mumbai.maticvigil.com
PRIVATE_KEY=&lt;自分の秘密鍵&gt;
</code></pre>
<p>設定後、</p>
<pre><code class="language-bash">$ npx hardhat run scripts/deploy.ts --network mumbai # hardhat.config.ts で設定したネットワーク名を指定する
</code></pre>
<p>とすると、<code>scripts/deploy.ts</code> を、mumbai ネットワークに対して実行する。このスクリプトを見ると、</p>
<pre><code class="language-ts">async function main() {
  const Greeter = await ethers.getContractFactory(&quot;Greeter&quot;);
  const greeter = await Greeter.deploy(&quot;Hello, Hardhat!&quot;);

  await greeter.deployed();

  console.log(&quot;Greeter deployed to:&quot;, greeter.address);
}
</code></pre>
<p>となっており、テストの時と同様に、<code>ethers.getContractFactory()</code> でコントラクトを読み込み、<code>contractFactory.deploy()</code> でデプロイしている。もちろん、必要であれば以下のようなコードを追加して、コントラクトの機能を呼び出し簡単なテストを行うこともできる。</p>
<pre><code class="language-ts">const contract = await greeter.deployed();
assert(contract.greet(), &quot;Hello, Hardhat!&quot;);
</code></pre>
<p>テストの時同様、秘密鍵やネットワークの設定は Hardhat によって自動で行われているため、このスクリプト内ではデプロイに集中することができる。また、network に渡す値を変えることで、複数のネットワークにデプロイすることも簡単だ。</p>
<h1 id>まとめ</h1>
<p>本記事では、Ethererum スマートコントラクトの開発環境を Hardhat を使って構築する方法と、この環境下でコントラクトのテストとデプロイを行う方法を紹介した。Hardhat はコントラクト開発時に必要なことの多くをカバーしてくれており、面倒な準備無しにコントラクトの開発を始めることができてとても生産性が高いと感じる。さらに TypeChain を使ってコントラクトに対応する型情報を生成してくれるため、TypeScript との親和性が高い点も良い。本記事が、今からスマートコントラクトを開発してみようと考えている人の助けになれば嬉しい。</p>
<p>実際にコントラクトを開発する中で気づいた点を続く記事にまとめたので、気になる方はそちらも参考にしてほしい。</p>
<figure class="kg-card kg-bookmark-card also-new-tag">
                    <a href="https://blog.misosi.ru/2022/06/02/hardhat-ethereum-smart-contract-development-tips/" class="kg-bookmark-container">
                        <div class="kg-bookmark-content">
                            <div class="kg-bookmark-title">Hardhat による Ethereum スマートコントラクト開発 小ネタ編</div>
                            <div class="kg-bookmark-description">本記事では、Hardhat を使って Ethererum スマートコントラクトを開発・テストするときの小ネタを紹介する。</div>
                            <div class="kg-bookmark-metadata">
                                    <img src="https://blog.misosi.ru/favicon.ico" class="kg-bookmark-icon" alt="Hardhat を使った Ethereum スマートコントラクト開発メモ">
                                    <span class="kg-bookmark-author">mecab</span>
                                    <span class="kg-bookmark-publisher">mecablog</span>
                            </div>
                        </div>
                            <div class="kg-bookmark-thumbnail">
                                <img src="https://blog.misosi.ru/content/images/2022/06/hardhat_log-1.png" alt="Hardhat を使った Ethereum スマートコントラクト開発メモ">
                            </div>
                    </a>
                </figure>
<hr class="footnotes-sep">
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p>分かりやすさのために変数の型を明示したが、推論されるため書く必要はない。 <a href="#fnref1" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn2" class="footnote-item"><p>テストコードにおいて、ethers モジュールを、そのもの直接ではなく <code>import { ethers } from &quot;hardhat&quot;</code> として Hardhat からインポートしていることに注意してほしい。ここで export されている ethers は、Hardhat によって様々なお膳立てがされている。 <a href="#fnref2" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn3" class="footnote-item"><p>Ethererum じゃなくて Polygon じゃん！という突っ込みは無しで...。 <a href="#fnref3" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn4" class="footnote-item"><p>見て分かるとおり、環境変数から値が取得されるので、実行時に環境変数として渡しても良い。今回の場合、インポートされる dotenv モジュールのおかげで、<code>.env</code> ファイルに設定した値も <code>process.env</code> から取得できるようになっている。 <a href="#fnref4" class="footnote-backref">↩︎</a></p>
</li>
</ol>
</section>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[不動産サイトで坪単価計算を簡単に計算するブラウザ拡張を作った]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>ここ2年間ほど無限に不動産サイトを見ていて、最初は価格しか見ていなかったわけだけど、最終的には毎回坪単価を計算するタイプの人間になってしまった。</p>
<p>毎回電卓を叩くのはめんどくさいので、ブラウザ拡張を作った。名前はそのまま「坪単価計算」という。下記からダウンロードできる。</p>
<p>👉 <strong><a href="https://misosi.ru/tsubotanka">https://misosi.ru/tsubotanka</a></strong></p>
<p>面積と価格を選択すると、右クリックメニューから坪単価を計算できるようになる。（現代人向けに平米単価も出る。）実際に動く動画は以下。</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/R5vwAeK-rPk?loop=1&mute=1&autoplay=1" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" style="margin-bottom: 2em !important;" allowfullscreen></iframe>
<p>元々は Suumo とか Homes のような特定のサイト向けに坪単価を自動で表示するような拡張にしようかと思ったが、ページがリニューアルされたり HTML の構造が変わったりすると使えなくなるし、その変更に追従するのもめんどくさいので、様々なサイトで汎用的に使えるものにしようと思った結果、このような拡張となった。価格と面積さえ選択できれば計算できるので、マイナーなページとか、社内向けに閉じたページであっても使えて便利だと思う。</p>
<p>現在は Chrome のみだが、そのうち Firefox や Edge 向けにもリリースする予定だ。</p>
<p>拡張機能周りは以前少し触ったことがあったが、パッケージしてリリースするのは初めてだった。複数のブラウザに対応する拡張機能を作るにあたって、<a href="https://github.com/webextension-toolbox/webextension-toolbox">webextension-toolbox</a> を使ったが、これは便利だった。他にもいくつか得られた知見があったので開発についても後日別記事で何か書きたいなと思っている。</p>
<p>ぜひ使ってみてください。</p>
<!--kg-card-end: markdown-->]]></description><link>https://blog.misosi.ru/2022/05/25/release-tsubotanka-browser-extension/</link><guid isPermaLink="false">628dfce41d2a1e1b4199c6b2</guid><category><![CDATA[development]]></category><category><![CDATA[tech]]></category><category><![CDATA[browser extension]]></category><category><![CDATA[real estate]]></category><dc:creator><![CDATA[mecab]]></dc:creator><pubDate>Wed, 25 May 2022 16:34:25 GMT</pubDate><media:content url="https://blog.misosi.ru/content/images/2022/05/ogp_1200x630.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://blog.misosi.ru/content/images/2022/05/ogp_1200x630.png" alt="不動産サイトで坪単価計算を簡単に計算するブラウザ拡張を作った"><p>ここ2年間ほど無限に不動産サイトを見ていて、最初は価格しか見ていなかったわけだけど、最終的には毎回坪単価を計算するタイプの人間になってしまった。</p>
<p>毎回電卓を叩くのはめんどくさいので、ブラウザ拡張を作った。名前はそのまま「坪単価計算」という。下記からダウンロードできる。</p>
<p>👉 <strong><a href="https://misosi.ru/tsubotanka">https://misosi.ru/tsubotanka</a></strong></p>
<p>面積と価格を選択すると、右クリックメニューから坪単価を計算できるようになる。（現代人向けに平米単価も出る。）実際に動く動画は以下。</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/R5vwAeK-rPk?loop=1&mute=1&autoplay=1" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" style="margin-bottom: 2em !important;" allowfullscreen></iframe>
<p>元々は Suumo とか Homes のような特定のサイト向けに坪単価を自動で表示するような拡張にしようかと思ったが、ページがリニューアルされたり HTML の構造が変わったりすると使えなくなるし、その変更に追従するのもめんどくさいので、様々なサイトで汎用的に使えるものにしようと思った結果、このような拡張となった。価格と面積さえ選択できれば計算できるので、マイナーなページとか、社内向けに閉じたページであっても使えて便利だと思う。</p>
<p>現在は Chrome のみだが、そのうち Firefox や Edge 向けにもリリースする予定だ。</p>
<p>拡張機能周りは以前少し触ったことがあったが、パッケージしてリリースするのは初めてだった。複数のブラウザに対応する拡張機能を作るにあたって、<a href="https://github.com/webextension-toolbox/webextension-toolbox">webextension-toolbox</a> を使ったが、これは便利だった。他にもいくつか得られた知見があったので開発についても後日別記事で何か書きたいなと思っている。</p>
<p>ぜひ使ってみてください。</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Nature Remo をかっこよく電源プラグに取りつけるウルトラマル秘テク]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p class="highlight">本記事では Nature Remo の初期モデルについて書く。製品写真を見る限り、Nature Remo mini（初期モデル）や、現行の Nature Remo 3 や他のモデルにでも適用できると思うが保証しない。（試してみた方はぜひ <a href="https://twitter.com/mecab">@mecab</a> まで教えていただけると嬉しい。）</p>
<p><a href="https://nature.global/nature-remo/">Nature Remo</a> という製品があって、これはいわゆるスマートリモコンで、赤外線リモコンに対応した各種家電（主にエアコンやテレビ）をスマートフォンから操作できるようにするものだ。</p>
<p>製品自体は結構便利で、見た目もシュッとしていて良いのだが、USB 給電で動くためにコンセントからの配線がダサくなってしまう。コンセントに USB 電源アダプタを差し、そこから USB ケーブルを伸ばさなければいけない。Nature Remo には下の写真に示す USB ケーブルとアダプタが付属していたが、結構目立ってしまう。</p>
<p><a href="https://www.flickr.com/photos/mecab/52093052207/in/album-72157649296605064/"><img src="https://live.staticflickr.com/65535/52093052207_0e3e44ce26_b.jpg" alt="Nature Remo 付属の USB ケーブルとアダプタ"></a></p>
<p>どうにか良い方法がないかと探していたが、エレコムが出しているキューブ型の USB 電源アダプタと、SwitchBot ハブミニ用の USB アダプタを組み合わせ、アダプタの先端を少し削ることで、</p>]]></description><link>https://blog.misosi.ru/2022/05/23/nature-remo-cool-deployment/</link><guid isPermaLink="false">628bac271d2a1e1b4199c579</guid><category><![CDATA[nature remo]]></category><category><![CDATA[smart home]]></category><category><![CDATA[home]]></category><dc:creator><![CDATA[mecab]]></dc:creator><pubDate>Mon, 23 May 2022 17:41:41 GMT</pubDate><media:content url="https://blog.misosi.ru/content/images/2022/05/52092847282_d3b6534521_b.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://blog.misosi.ru/content/images/2022/05/52092847282_d3b6534521_b.jpg" alt="Nature Remo をかっこよく電源プラグに取りつけるウルトラマル秘テク"><p class="highlight">本記事では Nature Remo の初期モデルについて書く。製品写真を見る限り、Nature Remo mini（初期モデル）や、現行の Nature Remo 3 や他のモデルにでも適用できると思うが保証しない。（試してみた方はぜひ <a href="https://twitter.com/mecab">@mecab</a> まで教えていただけると嬉しい。）</p>
<p><a href="https://nature.global/nature-remo/">Nature Remo</a> という製品があって、これはいわゆるスマートリモコンで、赤外線リモコンに対応した各種家電（主にエアコンやテレビ）をスマートフォンから操作できるようにするものだ。</p>
<p>製品自体は結構便利で、見た目もシュッとしていて良いのだが、USB 給電で動くためにコンセントからの配線がダサくなってしまう。コンセントに USB 電源アダプタを差し、そこから USB ケーブルを伸ばさなければいけない。Nature Remo には下の写真に示す USB ケーブルとアダプタが付属していたが、結構目立ってしまう。</p>
<p><a href="https://www.flickr.com/photos/mecab/52093052207/in/album-72157649296605064/"><img src="https://live.staticflickr.com/65535/52093052207_0e3e44ce26_b.jpg" alt="Nature Remo をかっこよく電源プラグに取りつけるウルトラマル秘テク"></a></p>
<p>どうにか良い方法がないかと探していたが、エレコムが出しているキューブ型の USB 電源アダプタと、SwitchBot ハブミニ用の USB アダプタを組み合わせ、アダプタの先端を少し削ることで、Nature Remo を良い感じにコンセントに直付けできることに気づいた。削るのは、アダプタが少し太く、そのままでは Nature Remo に差し込めないからだ。</p>
<p>商品はこちら:</p>
<ul>
<li><a href="https://amzn.to/3lxN1pt">エレコム AC充電器 Walkman/CUBE/1A/USB1ポート/ホワイト</a></li>
<li><a href="https://amzn.to/3wDKP6a">SwitchBot ハブミニ専用コネクタ</a></li>
</ul>
<p>実際にやってみたので写真を載せる。</p>
<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<p><ins class="adsbygoogle" style="display:block; text-align:center;" data-ad-layout="in-article" data-ad-format="fluid" data-ad-client="ca-pub-5314531653763426" data-ad-slot="9673121688"></ins></p>
<script>
     (adsbygoogle = window.adsbygoogle || []).push({});
</script>
<p>まず、SwitchBot ハブミニ用の USB アダプタを削る。最初はヤスリでやっていたが、粗目のものが手持ちになく全然削れなかった。痺れを切らして適当にカッターナイフで切ってみたところ案外簡単に切れた。雑すぎて切り口が汚く、さらに削りすぎている部分もあるが、最終的には見えないので気にしない...。</p>
<p><a href="https://www.flickr.com/photos/mecab/52094110484/in/album-72157649296605064/"><img src="https://live.staticflickr.com/65535/52094110484_3df70956a4_b.jpg" alt="Nature Remo をかっこよく電源プラグに取りつけるウルトラマル秘テク"></a></p>
<p>削るとなんとか Nature Remo 本体に差すことができる。</p>
<p><a href="https://www.flickr.com/photos/mecab/52094110544/in/album-72157649296605064/"><img src="https://live.staticflickr.com/65535/52094110544_e681c2cc89_b.jpg" alt="Nature Remo をかっこよく電源プラグに取りつけるウルトラマル秘テク"></a></p>
<p>これを、エレコムの USB 電源アダプタに差す。この電源アダプタは L 字になっているので、コンセント直付けでに壁に沿って良い感じに設置できる。</p>
<p><a href="https://www.flickr.com/photos/mecab/52092847282/in/album-72157649296605064/"><img src="https://live.staticflickr.com/65535/52092847282_d3b6534521_b.jpg" alt="Nature Remo をかっこよく電源プラグに取りつけるウルトラマル秘テク"></a></p>
<p>無事に設置できた。Nature Remo と壁の間の空間がもう少し小さくなればより嬉しいが十分だろう。なお、L字に取りつけられる USB 電源アダプタは色々ありそうな気もするが、意外なことにエレコムの製品しか見つからない。</p>
<hr>
<p>この方法を思いつくにあたって、以下 2 つのサイトを参考にした。</p>
<ul>
<li>
<p><a href="https://totonoe.blog/switchbot-hubmini/">家電操作をスマート化。QOLが爆上がりする『SwitchBotハブミニ』 | トトノエ</a></p>
<ul>
<li>エレコムの USB 電源アダプタとハブミニ用 USB アダプタで SwitchBot をコンセント直付けできるという記事。ちなみに SwitchBot も家に設定しており、ハブミニは同じ方法で取りつけている。</li>
</ul>
</li>
<li>
<p><a href="https://www.buzzyvox.com/2020128846.html">スマートリモコン『Nature Remo mini』を導入してみた – buzzyvox</a></p>
<ul>
<li>別の USB A → USB Micro-B 変換アダプタを削って Nature Remo mini に差した記事。この記事を見てアダプタを削ることに思い至った。この変換アダプタを使っても良いのだが、見た目を白色で統一したかったので、ハブミニ用のアダプタを買って削ることにした。</li>
</ul>
</li>
</ul>
<hr>
<p>最後に今回買った 2 つの製品を並べてみた写真を貼る。ハブミニ用アダプタを削る前に写真を撮ればよかった...。</p>
<p><a href="https://www.flickr.com/photos/mecab/52093888813/in/album-72157649296605064/"><img src="https://live.staticflickr.com/65535/52093888813_6c2ac04f76_b.jpg" alt="Nature Remo をかっこよく電源プラグに取りつけるウルトラマル秘テク"></a></p>
<p><a href="https://amzn.to/3PGpPmH" target="_blank">エレコム AC充電器 Walkman/CUBE/1A/USB1ポート/ホワイト</a><br><br>
<a href="https://amzn.to/3PGpPmH" target="_blank"><img src="https://m.media-amazon.com/images/I/318JTRfT0RL._SL200_.jpg" alt="Nature Remo をかっこよく電源プラグに取りつけるウルトラマル秘テク" border="0"></a></p>
<p><a href="hhttps://amzn.to/3PF486q" target="_blank">SwitchBot ハブミニ専用コネクタ Amazon Echo Flexに適用 - アダプター USB Type-A to Micro USB A 変換コネクタ ケーブル不要</a><br><br>
<a href="https://amzn.to/3PF486q" target="_blank"><img src="https://m.media-amazon.com/images/I/21DI0FC1UWL._SL200_.jpg" alt="Nature Remo をかっこよく電源プラグに取りつけるウルトラマル秘テク" border="0"></a></p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[WireGuard で VPN サーバーを作り、OpenWRT から接続して拠点間 VPN を構成する]]></title><description><![CDATA[<!--kg-card-begin: markdown--><h1 id>背景</h1>
<p>先日引っ越しをした。引っ越し先のインターネット環境は一言で言えば残念で、好きな ISP と契約することができず、マンションが包括して契約している ISP 経由でしかインターネットに接続できない。悲しいことにこの ISP は各個にグローバル IP を割り当てないので、外に向けたサーバーの公開が制限されている <sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup>。</p>
<p>この問題を回避するため、外部の VPS を VPN サーバーとし、ルータとの間にVPN を張ることでサーバーを公開できるようにした。外部のユーザーは、VPS に割り当てられたグローバル IP を通して、筆者の自宅内のサーバーに接続することができる。</p>
<h1 id>構成</h1>
<p>表題の通り、VPN には WireGuard を使う。高速に動作し、設定もシンプルらしい。</p>
<figure>
<div class="mxgraph" style="max-width:100%;border:1px solid transparent;" data-mxgraph="{&quot;nav&quot;:true,&quot;resize&quot;:true,&quot;toolbar&quot;:&quot;zoom lightbox&quot;,&quot;edit&quot;:&quot;_blank&quot;,&quot;xml&quot;:&quot;&lt;mxfile host=\&quot;app.diagrams.net\&quot; modified=\&quot;2022-05-09T16:50:54.984Z\&quot; agent=\&quot;5.0 (Windows)\&quot; etag=\&quot;zIsZoImL4WpQcOyyHK7p\&quot; version=\&quot;17.4.6\&quot; type=\&quot;onedrive\&quot;&gt;&lt;diagram name=\&quot;Page-1\&quot; id=\&quot;822b0af5-4adb-64df-f703-e8dfc1f81529\&quot;&gt;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&lt;/diagram&gt;&lt;/mxfile&gt;&quot;}"></div>
<script type="text/javascript" src="https://viewer.diagrams.net/js/viewer-static.min.js"></script>
<figcaption>図1. ネットワーク構成図</figcaption>
</figure>
<p>図 1 のように、ルーターには ISP からプライベート IP アドレス、10.167.</p>]]></description><link>https://blog.misosi.ru/2022/05/09/wireguard-openwrt/</link><guid isPermaLink="false">626acaaf1d2a1e1b4199c244</guid><category><![CDATA[tech]]></category><category><![CDATA[networking]]></category><category><![CDATA[openwrt]]></category><category><![CDATA[wireguard]]></category><category><![CDATA[vpn]]></category><dc:creator><![CDATA[mecab]]></dc:creator><pubDate>Mon, 09 May 2022 16:43:42 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h1 id>背景</h1>
<p>先日引っ越しをした。引っ越し先のインターネット環境は一言で言えば残念で、好きな ISP と契約することができず、マンションが包括して契約している ISP 経由でしかインターネットに接続できない。悲しいことにこの ISP は各個にグローバル IP を割り当てないので、外に向けたサーバーの公開が制限されている <sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup>。</p>
<p>この問題を回避するため、外部の VPS を VPN サーバーとし、ルータとの間にVPN を張ることでサーバーを公開できるようにした。外部のユーザーは、VPS に割り当てられたグローバル IP を通して、筆者の自宅内のサーバーに接続することができる。</p>
<h1 id>構成</h1>
<p>表題の通り、VPN には WireGuard を使う。高速に動作し、設定もシンプルらしい。</p>
<figure>
<div class="mxgraph" style="max-width:100%;border:1px solid transparent;" data-mxgraph="{&quot;nav&quot;:true,&quot;resize&quot;:true,&quot;toolbar&quot;:&quot;zoom lightbox&quot;,&quot;edit&quot;:&quot;_blank&quot;,&quot;xml&quot;:&quot;&lt;mxfile host=\&quot;app.diagrams.net\&quot; modified=\&quot;2022-05-09T16:50:54.984Z\&quot; agent=\&quot;5.0 (Windows)\&quot; etag=\&quot;zIsZoImL4WpQcOyyHK7p\&quot; version=\&quot;17.4.6\&quot; type=\&quot;onedrive\&quot;&gt;&lt;diagram name=\&quot;Page-1\&quot; id=\&quot;822b0af5-4adb-64df-f703-e8dfc1f81529\&quot;&gt;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&lt;/diagram&gt;&lt;/mxfile&gt;&quot;}"></div>
<script type="text/javascript" src="https://viewer.diagrams.net/js/viewer-static.min.js"></script>
<figcaption>図1. ネットワーク構成図</figcaption>
</figure>
<p>図 1 のように、ルーターには ISP からプライベート IP アドレス、10.167.X.Y/24 が割り当てられている。グローバル IP 203.0.113.1 が割り当てられた VPS とルーター間で 10.10.0.0/24 のサブネットで VPN を構築し、VPS に 10.10.0.1 、ルーターに 10.10.0.2 を割り当てる。VPS と ルーターのそれぞれで NAT を行い、LAN内のサーバーから公開するポートに外部から接続できるようにする。LAN 内では、ルーターに 192.168.1.1、公開するサーバーには 192.168.1.2 が割り当てられているものとする。</p>
<p>VPS の OS には Debian (bullseye) を使う。ルーターには OpenWRT (18.06.4) を使う。</p>
<p>なお、WireGuard はピアツーピア型の VPN であるため、本来どちらがサーバーであるという概念は存在しないが、便宜上 VPS 側をサーバー側と呼ぶことにする。</p>
<h1 id="vpnvps">VPN サーバー (VPS) 側の設定</h1>
<h2 id="wireguard">WireGuardのインストール</h2>
<p>WireGuard をインストールする。</p>
<pre><code class="language-bash">$ sudo apt install wireguard
</code></pre>
<h2 id>鍵生成</h2>
<p>サーバーの秘密鍵を生成する。</p>
<pre><code class="language-bash">$ sudo wg genkey &gt; server.key
</code></pre>
<p>秘密鍵から公開鍵を生成する。</p>
<pre><code class="language-bash">$ cat server.key | sudo wg pubkey &gt; server.pub
</code></pre>
<p>便宜上秘密鍵を <code>server.key(.pub)</code> として書き出したが、値をファイルから読むことはないので、値を控えしだいファイルを消してしまっても構わない。</p>
<p>同様にして、ルーター側の鍵ペアも生成する。</p>
<pre><code class="language-bash">$ sudo wg genkey &gt; client.key
$ cat client.key | sudo wg pubkey &gt; client.pub
</code></pre>
<h2 id="ip">IP転送の許可</h2>
<p>サーバー内でのIP転送を許可する。<code>/etc/sysctl.conf</code> を編集し、</p>
<pre><code>net.ipv4.ip_forward=1
</code></pre>
<p>をアンコメントする。</p>
<pre><code>$ sudo sysctl -p
</code></pre>
<p>として設定を反映させる。</p>
<h2 id>設定</h2>
<p><code>/etc/wireguard/[インターフェース名].conf</code> として設定ファイルを作成する。今回は <code>wg0</code> とする。内容は以下の通り。</p>
<pre><code>[Interface]
ListenPort = 51820
Address = 10.10.0.1/32
PrivateKey = [生成したサーバー側の秘密鍵]
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o [WAN向きのインターフェース名] -j MASQUERADE;
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o [WAN向きのインターフェース名] -j MASQUERADE;
SaveConfig = true

[Peer]
PublicKey = [生成したルーター側の公開鍵]
AllowedIPs = 10.10.0.0/24
PersistentKeepalive = 25
</code></pre>
<p>各項目の意味は以下の通り。<br>
<strong>[Interface]</strong><br>
サーバー側の設定。<br>
<strong>ListenPort</strong>: WireGuard が待ち受けるポート<br>
<strong>Address</strong>: 作成するインターフェース (wg0) に割り当てるアドレス。<code>/32</code> 以外にすると通信できないので注意。<br>
<strong>PrivateKey</strong>: サーバーが利用する秘密鍵<br>
<strong>PostUp/PostDown</strong>: インターフェースの作成後/破棄後に実行させるコマンド。IPマスカレードを行い、VPN 内から外向きの通信を WAN 側インターフェースを経由して行えるようにしている。<br>
<strong>SaveConfig</strong>: インターフェースを破棄した際に現在の WireGuard の設定をこのファイルに書き出す。<code>true</code> にしていると、インターフェースを作成してから設定を変更しても、インターフェースを落とした際に設定が上書きされるので注意したい。<sup class="footnote-ref"><a href="#fn2" id="fnref2">[2]</a></sup></p>
<p><strong>[Peer]</strong><br>
各クライアントに対する設定。複数のクライアントを設定するには、Peer セクションを複数書けば良い。<br>
<strong>PublicKey</strong>: 接続を許可するクライアントの公開鍵<br>
<strong>AllowedIPs</strong>: クライアントに許可する IP レンジ。<strong>0.0.0.0/0 には設定しないことを強く勧める。デフォルトゲートウェイが変更され、（SSH等でも）サーバーに接続できなくなる可能性がある。 → <a href="https://takuya-1st.hatenablog.jp/entry/2021/12/21/013007">参照</a></strong><br>
<strong>PersistentKeepalive</strong>: 無通信でも Keep-Alive パケットを送る間隔（秒）。NAT 越えの場合、無通信で切断されないように 25 に設定することが推奨されているようだ <sup class="footnote-ref"><a href="#fn3" id="fnref3">[3]</a></sup>。今回は NAT 越えではないが、念のために入れておいた。</p>
<h1 id>ルーター側の設定</h1>
<p>Web インターフェースにログインし、以下を行う。</p>
<h2 id>必要なプラグインのインストール</h2>
<p>上部メニューの System -&gt; Software でソフトウェア管理ページを開き、Available Packages の中から <code>luci-app-wireguard</code> を探しインストールする。同様に <code>luci-proto-wireguard</code> もインストールする。</p>
<h2 id>インターフェースの追加</h2>
<p>Network -&gt; Interfaces から、Add new interface... ボタンをクリックしてインターフェースを追加する。以下の通り設定する。</p>
<ul>
<li><strong>Name of the new interface</strong>: 追加するインターフェース名（<code>wg0</code>とする）を入力する。</li>
<li><strong>Protocol of the new interface</strong>: WireGuard VPN</li>
</ul>
<p>インターフェースの設定画面が開く。以下の通り設定する。</p>
<ul>
<li><strong>Private Key</strong>: 前のステップで生成したクライアント秘密鍵</li>
<li><strong>Listen Port</strong>: 51820</li>
<li><strong>IP Address</strong>: このルーターに割り当てる VPN 内の IP、10.10.0.2 を入力する。</li>
</ul>
<p>Peers セクションの Add ボタンをクリックして、ピアを追加する。これはクライアントから見たピアなので、つまりサーバーのこと。</p>
<ul>
<li><strong>Public Key</strong>: 前のステップで生成したサーバー公開鍵</li>
<li><strong>Allowed IPs</strong>: サーバー側に許可される IP レンジを入力する。すなわち 10.10.0.1/24</li>
<li><strong>Route Allowed IPs</strong>: 有効にする</li>
<li><strong>Endpoint Host / Port</strong>: サーバーの WAN 側 IP とポート番号を入力する。203.0.113.1 および 51820 とする。</li>
<li><strong>Persistent Keep Alive</strong>: 有効にする。</li>
</ul>
<p>こちらから接続に行くのに、接続に行った先が許可される IP レンジを指定するというのも妙な話だが、上でも書いたようにピアツーピア型の VPN であるためだ。</p>
<p>上のタブから Firewall Settings を開く。</p>
<ul>
<li><strong>Create / Assign firewall-zone</strong>: wan にする。<sup class="footnote-ref"><a href="#fn4" id="fnref4">[4]</a></sup></li>
</ul>
<p>Save &amp; Apply ボタンを押して反映する。</p>
<h1 id>接続の確認</h1>
<p>ここまでで VPS とルータ間で接続が確立できているはずだ。Network -&gt; Interface で、追加した wg0 がアクティブになったことや（図2）、Status -&gt; Wireguard Status で Peer が表示され、Latest Handshake が直近の日次になっていることを確認する（図3）。また、VPS と ルーター、互いに VPN 内 IP で ping が通ることを確認する。</p>
<figure>
<p><img src="https://blog.misosi.ru/content/images/2022/05/interface_wg0.png" alt="interface_wg0"></p>
<figcaption>図2. インターフェース w0 が設定された画面例</figcaption>
</figure>
<figure>
<p><img src="https://blog.misosi.ru/content/images/2022/05/wireguard_status.png" alt="Wireguard Status の画面例"></p>
<figcaption>図3. Wireguard Status の画面例</figcaption>
</figure>
<p>インターフェース一覧で wg0 にエラーが表示されている場合、Restart ボタンでインターフェースを再起動したり、ルーター本体を再起動すると直るかもしれない。</p>
<p>VPS 側でも</p>
<pre><code>sudo wg
</code></pre>
<p>とすることで状態を確認できる。</p>
<h1 id>ポートフォワードの設定</h1>
<p>本記事の目的は、外部のユーザーが LAN 内のサーバーに接続できるようにすることである。つまり、ポートフォワードを設定しなければならない。今回の構成では、ルーター側で行う通常のポートフォワードに加え、最初に接続を受ける VPS 側でもポートフォワードを設定する必要がある。</p>
<h2 id="vps">VPS 側でのポートフォワードの設定</h2>
<p>iptables で淡々とルールを追加する。例えば、TCP 80 に来た通信を LAN　内のサーバーで受け取れるようにするには、</p>
<pre><code class="language-bash">$ sudo iptables -t nat -A PREROUTING -i [WAN向きのインターフェース名] -p tcp -m tcp --dport 80 -j DNAT --to-destination 10.10.0.2;
$ sudo iptables -t nat -A POSTROUTING -m tcp -p tcp --dst 10.10.0.2 --dport 80 -j SNAT --to-source 10.10.0.1;
</code></pre>
<p>とする。上記のルールが VPN 生成/破棄時に自動で設定/削除されるように、<code>wg0.conf</code> の<code>PostUp</code> / <code>PostDown</code> に追加しておくと良い。直接書くと見づらいので、以下のような内容で <code>/etc/wireguard/wg0-up.sh</code> と <code>/etc/wireguard/wg0-down.sh</code> というファイルを作り、</p>
<p><code>wg0-up.sh</code></p>
<pre><code class="language-bash">#!/bin/bash

iptables -t nat -A PREROUTING -i [WAN向きのインターフェース名] -p tcp -m tcp --dport 80 -j DNAT --to-destination 10.10.0.2;
iptables -t nat -A POSTROUTING -m tcp -p tcp --dst 10.10.0.2 --dport 80 -j SNAT --to-source 10.10.0.1;
</code></pre>
<p><code>wg0-up.sh</code></p>
<pre><code class="language-bash">#!/bin/bash

iptables -t nat -D PREROUTING -i [WAN向きのインターフェース名] -p tcp -m tcp --dport 80 -j DNAT --to-destination 10.10.0.2;
iptables -t nat -D POSTROUTING -m tcp -p tcp --dst 10.10.0.2 --dport 80 -j SNAT --to-source 10.10.0.1;
</code></pre>
<p><code>PostUp</code> / <code>PostDown</code> で実行されるようにした。</p>
<p><code>wg0.conf</code></p>
<pre><code>[Interface]
...
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o [WAN向きのインターフェース名] -j MASQUERADE; /etc/wireguard/wg0-up.sh
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o [WAN向きのインターフェース名] -j MASQUERADE; /etc/wireguard/wg0-down.sh
...
</code></pre>
<h2 id>ルーター側でのポートフォワードの設定</h2>
<p>Network -&gt; Firewall 内の Port Forwards タブから設定できる。上記の HTTP を転送する例であれば、</p>
<ul>
<li><strong>Protocol</strong>: TCP</li>
<li><strong>External Zone</strong>: wan</li>
<li><strong>External Port</strong>: 80</li>
<li><strong>Internal Zone</strong>: lan</li>
<li><strong>Internal IP Address</strong>: 192.168.1.2</li>
<li><strong>Internal Port</strong>: 80</li>
</ul>
<p>上記のようなフォワードルールを作成する。図4. に作成した後の画面を示す。</p>
<figure>
<p><img src="https://blog.misosi.ru/content/images/2022/05/----------2022-05-10-002837.png" alt="ルータ側でのポートフォワードを設定した画面"></p>
<figcaption>図4. ルータ側でのポートフォワードを設定した画面</figcaption>
</figure>
<h1 id>まとめ</h1>
<p>本記事では、Wireguard を使って VPS と OpenWRT 間で拠点間 VPN を構築し、グローバル IP が与えられない環境下で外部向けにサーバーを公開する方法を説明した。Wireguard は初めて使ったが、設定ファイルがとても簡素で分かりやすく、またハマりそうな要素も少なく、必要最低限の VPN を構築するには便利だと感じた。</p>
<hr class="footnotes-sep">
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p>月 500 円ほどで固定 IP をもらえるオプションがあるので申し込み中。固定されてなくても良いのでとりあえずグローバル IP が欲しい。 <a href="#fnref1" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn2" class="footnote-item"><p>正直 false でもいい気がするが、どの解説サイトでも true になっているので一応 true にしておいた。 <a href="#fnref2" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn3" class="footnote-item"><p><a href="https://www.wireguard.com/quickstart/">https://www.wireguard.com/quickstart/</a> <a href="#fnref3" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn4" class="footnote-item"><p>好みで新しいゾーンを作るのも良い。 <a href="#fnref4" class="footnote-backref">↩︎</a></p>
</li>
</ol>
</section>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[非中央集権型 DNS Handshake でトップレベルドメインを取得した。]]></title><description><![CDATA[非中央集権型の DNS を構築を目指すプロジェクト、 Handshake でドメインを取得した。本記事では、Handshake の紹介し、ドメイン名取得の方法を解説する。]]></description><link>https://blog.misosi.ru/2021/06/03/how-to-acquire-handshake-tld/</link><guid isPermaLink="false">60ae81456722fa7cae9c98c9</guid><category><![CDATA[handshake]]></category><category><![CDATA[dns]]></category><category><![CDATA[blockchain]]></category><category><![CDATA[tech]]></category><dc:creator><![CDATA[mecab]]></dc:creator><pubDate>Thu, 03 Jun 2021 09:40:02 GMT</pubDate><media:content url="https://blog.misosi.ru/content/images/2021/06/handshake-1.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://blog.misosi.ru/content/images/2021/06/handshake-1.png" alt="非中央集権型 DNS Handshake でトップレベルドメインを取得した。"><p>ブロックチェーンを利用して非中央集権 (decentralized) 型の DNS を構築を目指すプロジェクト、 <a href="https://handshake.org/">Handshake</a> を知った。このプロジェクトは、DNS が本質的に <a href="https://ja.wikipedia.org/wiki/ICANN">ICANN</a> が管理するルートサーバーによって集中管理されていることを問題として <sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup> 定義し、それを解決するためにドメイン名の情報をブロックチェーンに書き込むことで、P2P で 非中央集権型 の DNS を実現しようというものだ。</p>
<figure>
<p><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1179px" viewbox="-0.5 -0.5 1179 492" content="&lt;mxfile host=&quot;app.diagrams.net&quot; modified=&quot;2021-05-31T17:13:04.632Z&quot; agent=&quot;5.0 (Windows)&quot; etag=&quot;HqqMkE0KNBVJ5-82Tqne&quot; version=&quot;14.7.3&quot; type=&quot;onedrive&quot;&gt;&lt;diagram name=&quot;Page-1&quot; id=&quot;822b0af5-4adb-64df-f703-e8dfc1f81529&quot;&gt;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&lt;/diagram&gt;&lt;/mxfile&gt;" onclick="(function(svg){var src=window.event.target||window.event.srcElement;while (src!=null&amp;&amp;src.nodeName.toLowerCase()!='a'){src=src.parentNode;}if(src==null){if(svg.wnd!=null&amp;&amp;!svg.wnd.closed){svg.wnd.focus();}else{var r=function(evt){if(evt.data=='ready'&amp;&amp;evt.source==svg.wnd){svg.wnd.postMessage(decodeURIComponent(svg.getAttribute('content')),'*');window.removeEventListener('message',r);}};window.addEventListener('message',r);svg.wnd=window.open('https://viewer.diagrams.net/?client=1&amp;page=0&amp;edit=_blank');}}})(this);" style="cursor:pointer;max-width:100%;max-height:492px;"><defs/><g><rect x="660" y="291" width="480" height="100" rx="15" ry="15" fill="#d5e8d4" stroke="none" pointer-events="all"/><rect x="12.4" y="121" width="480" height="100" rx="15" ry="15" fill="#dae8fc" stroke="none" pointer-events="all"/><image x="226.9" y="40.5" width="42.6" height="54" xlink:href="https://app.diagrams.net/img/lib/allied_telesis/computer_and_terminals/Server_Desktop.svg"/><g transform="translate(-0.5 -0.5)"><switch><foreignobject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredfeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 102px; margin-left: 249px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; background-color: white; white-space: nowrap; "><div>DNS root server</div></div></div></div></foreignobject><text x="249" y="114" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">DNS roo...</text></switch></g><image x="106.9" y="140.5" width="42.6" height="54" xlink:href="https://app.diagrams.net/img/lib/allied_telesis/computer_and_terminals/Server_Desktop.svg"/><g transform="translate(-0.5 -0.5)"><switch><foreignobject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredfeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 202px; margin-left: 129px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: nowrap; "><span>.com</span></div></div></div></foreignobject><text x="129" y="214" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">.com</text></switch></g><image x="336.9" y="140.5" width="42.6" height="54" xlink:href="https://app.diagrams.net/img/lib/allied_telesis/computer_and_terminals/Server_Desktop.svg"/><g transform="translate(-0.5 -0.5)"><switch><foreignobject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredfeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 202px; margin-left: 359px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: nowrap; "><span>.jp</span></div></div></div></foreignobject><text x="359" y="214" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">.jp</text></switch></g><image x="46.9" y="250.5" width="42.6" height="54" xlink:href="https://app.diagrams.net/img/lib/allied_telesis/computer_and_terminals/Server_Desktop.svg"/><g transform="translate(-0.5 -0.5)"><switch><foreignobject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredfeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 312px; margin-left: 69px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; background-color: white; white-space: nowrap; ">example1.com</div></div></div></foreignobject><text x="69" y="324" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">example...</text></switch></g><image x="156.9" y="250.5" width="42.6" height="54" xlink:href="https://app.diagrams.net/img/lib/allied_telesis/computer_and_terminals/Server_Desktop.svg"/><g transform="translate(-0.5 -0.5)"><switch><foreignobject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredfeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 312px; margin-left: 179px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; background-color: white; white-space: nowrap; ">example2.com</div></div></div></foreignobject><text x="179" y="324" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">example...</text></switch></g><image x="256.9" y="250.5" width="42.6" height="54" xlink:href="https://app.diagrams.net/img/lib/allied_telesis/computer_and_terminals/Server_Desktop.svg"/><g transform="translate(-0.5 -0.5)"><switch><foreignobject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredfeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 312px; margin-left: 279px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; background-color: white; white-space: nowrap; ">.co.jp</div></div></div></foreignobject><text x="279" y="324" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">.co.jp</text></switch></g><image x="406.9" y="250.5" width="42.6" height="54" xlink:href="https://app.diagrams.net/img/lib/allied_telesis/computer_and_terminals/Server_Desktop.svg"/><g transform="translate(-0.5 -0.5)"><switch><foreignobject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredfeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 312px; margin-left: 429px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; background-color: white; white-space: nowrap; "><div>.ne.jp</div><div><br/></div></div></div></div></foreignobject><text x="429" y="324" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">.ne.jp
</text></switch></g><image x="199.5" y="330.5" width="42.6" height="54" xlink:href="https://app.diagrams.net/img/lib/allied_telesis/computer_and_terminals/Server_Desktop.svg"/><g transform="translate(-0.5 -0.5)"><switch><foreignobject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredfeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 392px; margin-left: 221px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; background-color: white; white-space: nowrap; ">a.co.jp</div></div></div></foreignobject><text x="221" y="404" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">a.co.jp</text></switch></g><image x="296.9" y="330.5" width="42.6" height="54" xlink:href="https://app.diagrams.net/img/lib/allied_telesis/computer_and_terminals/Server_Desktop.svg"/><g transform="translate(-0.5 -0.5)"><switch><foreignobject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredfeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 392px; margin-left: 319px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; background-color: white; white-space: nowrap; ">b.co.jp</div></div></div></foreignobject><text x="319" y="404" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">b.co.jp</text></switch></g><image x="356.9" y="330.5" width="42.6" height="54" xlink:href="https://app.diagrams.net/img/lib/allied_telesis/computer_and_terminals/Server_Desktop.svg"/><g transform="translate(-0.5 -0.5)"><switch><foreignobject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredfeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 392px; margin-left: 379px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; background-color: white; white-space: nowrap; ">a.ne.jp</div></div></div></foreignobject><text x="379" y="404" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">a.ne.jp</text></switch></g><image x="453.9" y="330.5" width="42.6" height="54" xlink:href="https://app.diagrams.net/img/lib/allied_telesis/computer_and_terminals/Server_Desktop.svg"/><g transform="translate(-0.5 -0.5)"><switch><foreignobject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredfeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 392px; margin-left: 476px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; background-color: white; white-space: nowrap; ">b.ne.jp</div></div></div></foreignobject><text x="476" y="404" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">b.ne.jp</text></switch></g><path d="M 155.43 144.44 L 227.4 81.01" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="2 6" pointer-events="stroke"/><path d="M 151.68 147.75 L 154.33 143.19 L 156.53 145.69 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/><path d="M 354.32 136.05 L 270 81.72" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="2 6" pointer-events="stroke"/><path d="M 358.52 138.76 L 353.42 137.46 L 355.22 134.65 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/><path d="M 75.72 243.54 L 106.42 183.98" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="2 6" pointer-events="stroke"/><path d="M 73.43 247.99 L 74.24 242.78 L 77.2 244.31 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/><path d="M 182.08 243.54 L 150.38 181.99" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="2 6" pointer-events="stroke"/><path d="M 184.36 247.99 L 180.59 244.3 L 183.56 242.78 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/><path d="M 288.06 245.15 L 335.4 179.99" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="2 6" pointer-events="stroke"/><path d="M 285.13 249.19 L 286.72 244.17 L 289.41 246.13 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/><path d="M 427.07 244.16 L 379.4 179.99" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="2 6" pointer-events="stroke"/><path d="M 430.05 248.18 L 425.73 245.16 L 428.41 243.17 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/><path d="M 234.94 323.9 L 258.81 287.02" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="2 6" pointer-events="stroke"/><path d="M 232.23 328.1 L 233.54 322.99 L 236.34 324.8 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/><path d="M 323.85 325.72 L 303.79 289.99" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="2 6" pointer-events="stroke"/><path d="M 326.3 330.08 L 322.39 326.53 L 325.3 324.9 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/><path d="M 389.43 325.27 L 407.4 301.98" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="2 6" pointer-events="stroke"/><path d="M 386.37 329.23 L 388.11 324.25 L 390.74 326.29 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/><path d="M 477.18 324.4 L 450.38 291.99" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="2 6" pointer-events="stroke"/><path d="M 480.37 328.25 L 475.9 325.46 L 478.47 323.34 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/><rect x="182.2" y="1" width="150" height="20" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignobject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredfeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 11px; margin-left: 257px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: nowrap; "><font style="font-size: 18px"><b>Traditional DNS</b></font></div></div></div></foreignobject><text x="257" y="15" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">Traditional DNS</text></switch></g><rect x="0" y="95" width="150" height="20" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignobject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredfeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 105px; margin-left: 75px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: nowrap; "><b>Top Level Domain (TLD)</b></div></div></div></foreignobject><text x="75" y="109" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">Top Level Domain (TLD)</text></switch></g><image x="677.1" y="110.5" width="29.51" height="40" xlink:href="https://app.diagrams.net/img/lib/allied_telesis/computer_and_terminals/Personal_Computer.svg" pointer-events="none"/><image x="757.1" y="70.5" width="29.51" height="40" xlink:href="https://app.diagrams.net/img/lib/allied_telesis/computer_and_terminals/Personal_Computer.svg" pointer-events="none"/><image x="747.1" y="170.5" width="29.51" height="40" xlink:href="https://app.diagrams.net/img/lib/allied_telesis/computer_and_terminals/Personal_Computer.svg" pointer-events="none"/><image x="687.1" y="210.5" width="29.51" height="40" xlink:href="https://app.diagrams.net/img/lib/allied_telesis/computer_and_terminals/Personal_Computer.svg" pointer-events="none"/><image x="877.1" y="110.5" width="29.51" height="40" xlink:href="https://app.diagrams.net/img/lib/allied_telesis/computer_and_terminals/Personal_Computer.svg" pointer-events="none"/><image x="837.1" y="210.5" width="29.51" height="40" xlink:href="https://app.diagrams.net/img/lib/allied_telesis/computer_and_terminals/Personal_Computer.svg" pointer-events="none"/><image x="797.1" y="130.5" width="29.51" height="40" xlink:href="https://app.diagrams.net/img/lib/allied_telesis/computer_and_terminals/Personal_Computer.svg" pointer-events="none"/><path d="M 707.11 124.11 L 756.6 101" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="2 6" pointer-events="none"/><path d="M 717.11 221.16 L 747.6 200.84" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="2 6" pointer-events="none"/><path d="M 842.36 211 L 822.36 171" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="2 6" pointer-events="none"/><path d="M 777.11 179.2 L 797.6 162.8" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="2 6" pointer-events="none"/><path d="M 877.6 126.08 L 787.11 95.92" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="2 6" pointer-events="none"/><path d="M 747.6 178.35 L 707.11 143.65" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="2 6" pointer-events="none"/><path d="M 884.36 151 L 860.36 211" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="2 6" pointer-events="none"/><path d="M 700.36 211 L 694.36 151" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="2 6" pointer-events="none"/><path d="M 717.11 231 L 837.6 231" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="2 6" pointer-events="none"/><path d="M 799.02 131 L 785.69 111" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="2 6" pointer-events="none"/><path d="M 827.11 147.31 L 877.6 134.69" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="2 6" pointer-events="none"/><path d="M 943.25 107.69 C 933.31 110.7 922.14 108.01 915.8 101.07 C 909.45 94.13 909.45 84.6 915.8 77.66 C 922.14 70.72 933.31 68.03 943.25 71.04 C 943.17 58.82 952.36 47.84 966.32 43.49 C 980.28 39.14 996.08 42.33 1005.96 51.5 C 1012.31 38.51 1027.68 29.99 1044.78 29.99 C 1061.88 29.99 1077.26 38.51 1083.61 51.5 C 1093.76 44.01 1108.22 41.9 1120.91 46.05 C 1133.6 50.21 1142.29 59.9 1143.33 71.04 C 1153.26 68.03 1164.44 70.72 1170.78 77.66 C 1177.12 84.6 1177.12 94.13 1170.78 101.07 C 1164.44 108.01 1153.26 110.7 1143.33 107.69 C 1142.25 119.47 1132.63 129.57 1118.93 133.3 C 1105.23 137.04 1090.13 133.68 1080.62 124.79 C 1073.06 135.08 1059.46 141.37 1044.78 141.37 C 1030.11 141.37 1016.51 135.08 1008.95 124.79 C 1001.73 136.66 981.17 142.46 963.03 137.74 C 944.89 133.01 936.03 119.56 943.25 107.69 Z" fill="#ffffff" stroke="#000000" stroke-linejoin="round" stroke-miterlimit="10" pointer-events="none"/><rect x="907.11" y="30" width="0" height="0" fill="none" stroke="#000000" pointer-events="none"/><ellipse cx="952.2" cy="149.22" rx="17.918371861519745" ry="6.596091205211727" fill="#ffffff" stroke="#000000" pointer-events="none"/><ellipse cx="931.3" cy="165.1" rx="11.348302178962504" ry="4.397394136807818" fill="#ffffff" stroke="#000000" pointer-events="none"/><ellipse cx="914.28" cy="176.82" rx="7.167348744607897" ry="3.1758957654723132" fill="#ffffff" stroke="#000000" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignobject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredfeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe flex-start; width: 148px; height: 1px; padding-top: 62px; margin-left: 966px;"><div style="box-sizing: border-box; font-size: 0; text-align: left; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; "><div><b>.mecab:</b> 192.0.2.1<br/></div><div><b>.example:</b> 198.51.100.1<br/></div><div><b>.foobar:</b> 203.0.113.0<br/></div></div></div></div></foreignobject><text x="966" y="74" fill="#000000" font-family="Helvetica" font-size="12px">.mecab: 192.0.2.1...</text></switch></g><image x="764.5" y="310.5" width="42.6" height="54" xlink:href="https://app.diagrams.net/img/lib/allied_telesis/computer_and_terminals/Server_Desktop.svg" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignobject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredfeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 372px; margin-left: 786px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: nowrap; ">.mecab</div></div></div></foreignobject><text x="786" y="384" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">.mecab</text></switch></g><image x="707.1" y="400.5" width="42.6" height="54" xlink:href="https://app.diagrams.net/img/lib/allied_telesis/computer_and_terminals/Server_Desktop.svg" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignobject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredfeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 462px; margin-left: 729px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; background-color: white; white-space: nowrap; ">a.mecab</div></div></div></foreignobject><text x="729" y="474" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">a.mecab</text></switch></g><image x="807.1" y="400.5" width="42.6" height="54" xlink:href="https://app.diagrams.net/img/lib/allied_telesis/computer_and_terminals/Server_Desktop.svg" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignobject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredfeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 462px; margin-left: 829px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; background-color: white; white-space: nowrap; ">b.mecab</div></div></div></foreignobject><text x="829" y="474" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">b.mecab</text></switch></g><path d="M 741.98 393.57 L 766.41 347.02" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="2 6" pointer-events="none"/><path d="M 739.65 397.99 L 740.5 392.79 L 743.45 394.34 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 834.34 395.56 L 811.39 349.99" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="2 6" pointer-events="none"/><path d="M 836.58 400.03 L 832.85 396.31 L 835.83 394.81 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignobject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredfeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 331px; margin-left: 843px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: nowrap; ">192.0.2.1</div></div></div></foreignobject><text x="843" y="335" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">192.0.2.1</text></switch></g><image x="974.5" y="310.5" width="42.6" height="54" xlink:href="https://app.diagrams.net/img/lib/allied_telesis/computer_and_terminals/Server_Desktop.svg" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignobject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredfeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 372px; margin-left: 996px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: nowrap; ">.example</div></div></div></foreignobject><text x="996" y="384" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">.example</text></switch></g><image x="917.1" y="400.5" width="42.6" height="54" xlink:href="https://app.diagrams.net/img/lib/allied_telesis/computer_and_terminals/Server_Desktop.svg" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignobject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredfeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 462px; margin-left: 939px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; background-color: white; white-space: nowrap; ">a.example</div></div></div></foreignobject><text x="939" y="474" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">a.examp...</text></switch></g><image x="1017.1" y="400.5" width="42.6" height="54" xlink:href="https://app.diagrams.net/img/lib/allied_telesis/computer_and_terminals/Server_Desktop.svg" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignobject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredfeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 462px; margin-left: 1039px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; background-color: white; white-space: nowrap; ">b.example</div></div></div></foreignobject><text x="1039" y="474" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">b.examp...</text></switch></g><path d="M 951.98 393.57 L 976.41 347.02" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="2 6" pointer-events="none"/><path d="M 949.65 397.99 L 950.5 392.79 L 953.45 394.34 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 1044.34 395.56 L 1021.39 349.99" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="2 6" pointer-events="none"/><path d="M 1046.58 400.03 L 1042.85 396.31 L 1045.83 394.81 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignobject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredfeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 331px; margin-left: 1063px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: nowrap; ">198.51.100.1</div></div></div></foreignobject><text x="1063" y="335" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">198.51.100.1</text></switch></g><g transform="translate(-0.5 -0.5)"><switch><foreignobject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredfeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 11px; margin-left: 900px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: nowrap; "><font style="font-size: 18px"><b>Handshake DNS</b></font></div></div></div></foreignobject><text x="900" y="15" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">Handshake DNS</text></switch></g><g transform="translate(-0.5 -0.5)"><switch><foreignobject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredfeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 271px; margin-left: 1065px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: nowrap; "><b>Top Level Domain (TLD)</b></div></div></div></foreignobject><text x="1065" y="275" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">Top Level Domain (TLD)</text></switch></g><path d="M 802.59 305.76 L 856.6 249" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="2 6" pointer-events="none"/><path d="M 799.14 309.38 L 801.38 304.61 L 803.8 306.91 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 988.91 304.28 L 857.6 251" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="2 6" pointer-events="none"/><path d="M 993.55 306.16 L 988.29 305.83 L 989.54 302.74 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/></g><switch><g requiredfeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/><a transform="translate(0,-5)" xlink:href="https://www.diagrams.net/doc/faq/svg-export-text-problems" target="_blank"><text text-anchor="middle" font-size="10px" x="50%" y="100%">Viewer does not support full SVG 1.1</text></a></switch></svg></p>
<figcaption>通常のの DNS と、Handshake による DNS の比較。前者では Top Level Domain (TLD) がルートサーバーによって管理されるのに対し、後者ではルートサーバーは存在せず、ブロックチェーンによる合意によって TLD を管理するネームサーバーが記録される。TLD 以下は通常の仕組みと同じだ。</figcaption>
</figure>
<p>公式ページでも &quot;experimental&quot; と書かれているようにまだまだ発展途上のプロジェクトではあるが、公開されているフルノードは Handshake 内のドメイン名を解決するリゾルバとして動くようになっており、本質的な機能は既に実装されている。</p>
<p>当然ながら、Handshake 上のドメイン名は通常の DNS サーバーからは解決されないため、例えばこのドメイン名を使って Web サイトを閲覧したい場合、ネットワークの設定を変更し、対応した DNS サーバーを利用するように設定する必要がある。一般のユーザーが Handshake DNS を透過的に利用する日はとても遠いだろうし、そもそもそのような日が来るかは分からないが、それでも期待できる、ワクワクするプロジェクトだと感じた。</p>
<p>そこで、実際に Handshake ドメイン名 <code>mecab</code> を取得して、またそのドメインのゾーン情報を管理する権威サーバーを構築してみた。Handshake DNS を解決できる環境であれば、 <a href="http://mecab/">http://mecab/</a> でホームページ <a href="http://misosi.ru/">http://misosi.ru/</a> と同じコンテンツを閲覧できる。環境が無ければ、ゲートウェイ <a href="https://blog.misosi.ru/2021/06/03/how-to-acquire-handshake-tld/hns.to">hns.to</a> を使い、<a href="http://mecab.hns.to/">http://mecab.hns.to/</a> で閲覧できる。</p>
<p>本記事では、Handshake ドメインを取得するまでの一連の流れを紹介する。</p>
<h1 id="handshake">Handshake ドメイン名の取得</h1>
<p>まずは、ドメイン名を取得する方法について説明する。通常のドメイン名は先着順で取得されるが、Handshake ドメイン名はオークション形式で取得される。つまり、あるドメイン名を欲しいと思った人は一定期間のオークションを開始し、期間内に最高入札額を提示した人がドメインを取得する。このオークションはだれでも入札できるため、最初にそのドメイン名を欲しいと思った人が落札できない場合もある。</p>
<p>また、Handshake 上で取得できるドメインは全て TLD になる。取得した TLD 配下のドメインについては、通常の DNS のように自分でネームサーバーを設定することになる。</p>
<h2 id="1hns">1. HNS の入手</h2>
<p>入札には、Handshake のネイティブトークンである HNS を使う。まずは HNS を入手しなければならない。基本的には仮想通貨取引所で購入することになるだろう。ここでは HNS の取引について詳しくは述べないが、<a href="https://bittrex.com/">Bittrex</a> や <a href="https://www.mxcio.co/auth/signup?inviteCode=1CUBG">MXC.COM</a> などで取り扱われている。</p>
<p><strong>なお、2019 年 2月 時点で 15 人以上のフォロワーがいた GitHub ユーザーには 4246 HNS の無料配布が行われている（！）</strong> <a href="https://handshake.org/claim/">Claim HNS</a> に書かれている手順で受け取ることができる。後でやり方についての記事を書くかもしれない。</p>
<h2 id="2hsd">2. HSD のインストール</h2>
<p>Handshake のフルノードである <a href="https://github.com/handshake-org/hsd">hsd</a> をインストールする。ソースコードをクローンして、<code>npm install --production</code> すればよい。</p>
<pre><code>$ git clone https://github.com/handshake-org/hsd.git
$ cd hsd
$ git checkout v2.4.0 # そのときの最新のバージョンにする
$ npm install --production
</code></pre>
<p>インストール後、<code>hsd</code> ディレクトリで</p>
<pre><code>$ ./bin/hsd --log-level info
</code></pre>
<p>とすると hsd が起動する。hsd はフルノードなので、全てのブロックをダウンロードしてネットワークと同期する。同期が終わるまでしばらく（数時間）待つ。</p>
<p>以下のコマンドはローカルで起動中のフルノードに対して指示を出すコマンドになる。このため、hsd をバックグラウンドで動かしたまま実行する必要である。</p>
<pre><code>$ ./bin/hsw-cli account get default | grep receiveAddress
</code></pre>
<p>とすると自分のアドレスが表示される。取引所で入手した HNS はこのアドレスに送るとドメイン名取得のために使えるようになる。</p>
<h2 id="3">3. オークション</h2>
<p>この節では、ドメイン名オークションの開催から入札、入札した場合のドメイン情報登録の方法や、落札できなかった場合の入札金額の回収を、順を追って説明する。ネットワークを操作するためのコマンドは <code>hsd-cli</code> と <code>hsw-cli</code> の両方があって紛らわしいが間違えないように注意したい。</p>
<h3 id="31">3.1 ドメイン名の現在の状態を確認する</h3>
<p>まず自分が欲しいドメイン名が取得可能かを調べる。</p>
<pre><code>$ ./bin/hsd-cli rpc getnameinfo zettaini-hosikunai-domein
</code></pre>
<p>で、ドメイン名 <code>zettaini-hosikunai-domein</code> の状態が表示される。</p>
<pre><code>{
  &quot;start&quot;: {
    &quot;reserved&quot;: false,
    &quot;week&quot;: 27,
    &quot;start&quot;: 29232
  },
  &quot;info&quot;: null
}
</code></pre>
<p>上記のように、<code>start</code> オブジェクトが存在し、かつ <code>start.reserved</code> が <code>false</code> の場合は、ドメイン名が現在空いていることを意味するので、オークションを主催して入札することができる。<code>start.reserved</code> が <code>true</code> の場合、そのドメインは既存の有名なサイト <sup class="footnote-ref"><a href="#fn2" id="fnref2">[2]</a></sup> のために予約されているため入札することはできない。（例: google)</p>
<pre><code>$ ./bin/hsd-cli rpc getnameinfo google
{
  &quot;start&quot;: {
    &quot;reserved&quot;: true,
    &quot;week&quot;: 33,
    &quot;start&quot;: 35280
  },
  &quot;info&quot;: null
}
</code></pre>
<p><code>start</code> が存在しない場合、そのドメインは既に取得されているか、またはちょうどオークションが開催されている。<code>state</code> フィールドが <code>OPENING</code> または <code>BID</code> の場合は、ちょうど現在オークションが開催されているところなので、直接入札できる。それ以外の場合、そのドメインは他の人に取得されているため諦めるしかない。</p>
<p>ドメインの状態を確認するために、Handshake のブロックチェーンエクスプローラーを使うのも良いだろう。例えば、<a href="https://e.hnsfans.com/">https://e.hnsfans.com/</a> や、 <a href="https://hnscan.com/">https://hnscan.com/</a> がある。（<a href="https://e.hnsfans.com/name/mecab">e.hnsfans.com で mecab TLD の取得状況を見る例</a>）</p>
<h3 id="32">3.2 オークションを開催する。</h3>
<p><code>sendopen</code> を発行することでオークションを開催する。</p>
<pre><code>$ ./bin/hsw-cli rpc sendopen zettaini-hosikunai-domein
{
  &quot;hash&quot;: &quot;aa5f93ef1...&quot;,
  &quot;witnessHash&quot;: &quot;dbd7943fc...&quot;,
  &quot;mtime&quot;: 1622228535,
  &quot;version&quot;: 0,
  ...
}
</code></pre>
<p>成功すると、送信したトランザクションの詳細が表示される。Handshake ブロックチェーンでは、およそ 10 分ごとにブロックが生成されるため、最長で約 10 分ほど待つと、このトランザクションがネットワークで認識される。</p>
<p>ネットワークで認識されていれば、<code>getnameinfo</code> で確認すると、<code>state</code> が <code>OPENING</code> になっているはずだ。</p>
<p><code>OPENING</code> になった後、実際に入札が可能な <code>BIDDING</code> フェーズになるまでさらに 37 ブロック、約 6 時間 かかる。ただ待つだけだ。</p>
<h3 id="33">3.3 オークションに入札する</h3>
<p>ドメインの入札ステータスが <code>BIDDING</code> になったらいよいよ入札を行う。落札者による確実な支払いを保証するため、入札時点で入札金額を一時的にロックアップし、落札できなかった人はオークション終了後にロックアップ額を回収する形を取っている。</p>
<pre><code>$ ./bin/hsw-cli rpc sendopen zettaini-hosikunai-domein 10 100
</code></pre>
<p>上の例は、ドメイン名 <code>zettaini-hishikunai-domein</code> に対して、10 HNS で入札し、100 HNS のブラインドを追加する。この操作により、計 110 HNS が一時的にロックアップされる。ブラインドは、実際の入札額を隠すために追加でロックアップする額だ。</p>
<p>Handshake のオークションは、2 位価格封印入札（ヴィックリーオークション）という形式で行われる。入札額を伏せて入札した上で、最も高額の入札をした人が落札できる。しかしブロックチェーン上で全てのトランザクションが公開されるため、後に入札する人は先に入札した人の入札額を知ることができる。この問題に対処するため、任意のブラインドを追加して資金をロックアップすることができるようになっている。上記の例では、他の人からは 110 HNS をロックアップした入札者がいることが分かるが、実際の入札額は 110 HNS 以下であること以外は不明になる。</p>
<figure>
<p><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="634px" viewbox="-0.5 -0.5 634 381" content="&lt;mxfile host=&quot;app.diagrams.net&quot; modified=&quot;2021-06-01T05:35:09.618Z&quot; agent=&quot;5.0 (Windows)&quot; etag=&quot;opRxP7M4oFAgw17UyTTy&quot; version=&quot;14.7.3&quot; type=&quot;onedrive&quot;&gt;&lt;diagram id=&quot;fbcsYVYQLWZRbV0vv2dI&quot; name=&quot;Page-1&quot;&gt;7Vxte6K8Ev41/bheQALKRxSq7GOwVlwr3xAooigexQr8+jPhxTewa7dr9+x57F5byCSZCXcmmYHcuw+otYjaa3M1JYHt+A8cY0cPSH7gOBGL8JsK4kxQbwiZwF17diZiD4KBlzi5kMmlW892NicNwyDwQ291KrSC5dKxwhOZuV4Hu9Nmr4F/anVluk5JMLBMvywdeXY4zaWYYQ4VHcdzp7npBp9XLMyicS7YTE072B2JkPKAWusgCLO7RdRyfIpdgUvW7/FC7X5ga2cZXtNB+GcjLZcqtpSVHkj/vEqKon/j+EzNm+lv8yfORxvGBQTuOtiuytbyAbw569CJqubCnBQaDo8LbuIECydcx9Au78WhHKHcRTicl3dHgItMrVHPxNMjuLl63tbM59ndqz9AATc5Gh9AhhV/jgxM6YreeovUi5rpVdqsMkdkQGIWhVcvcsBck8LlgXt1zYnjPwUbL/SCJdRPgjAMFkcNJN9zaUUYrArNULLN0HxAUlbkHjdv7gPXjBbwNK2njsYZcZMzXr4n5kjcPg3UqDtTPLUzDSdtPnkafA/szvOu5zXebGSj7tJKugsxNuJGTGRp10W0v+o6bXYzWRLBaUeryWIjqospY3ckoRuL0Mva2gnZTtD3ZTdR+J4+f8vbgZ1mbLxovrU0/P6LtjNGGjNcPDLmqCGqy6lmjp4NfeTP1TbrGy99aG+sjBe7NUGuqM4kl7QkOg6XzPq77mzME72/02Yqq3pNBH0ZU2Y8MpN2UA6Mkb80O33opzKkhbmerjBEHsfaQAU8ntrPvrEk9K7TnNpt1zWgr66DbmWX2SiuuS39/P4x8NS2PwfMpr1HTdCVKB78IF43wQ2rDc/UatI6TZsNt9qs7xJd3fZ0W9bk+VZLxm5vgGMSS4kWY16VFZgHi1FlAld335bMyJYkcyj3QcfYJYmyhToYxxzq+64mQzmVg07dkDVdgnYE5O5Wk6E+Gaf1mq6A3IUy6BlILIkxR4YkIQMcge0dXHe9loS6syGMQaF4Mb3BvswRDyfQvijzMHaWDCSm18K8RucExqPNLBgnYC+rMdRzGkMiahcwh/GqPOCGaF/QxWieFIFfwJgV6DOPu7M+d2QH6lQYP/TTCfSD+ZUVRMcMY4+IPARMAANdYaEfYDdMQHfUT5QI2vCEPp8H2EJbwGDbk+G5ZQtwGEIf2taKAWfQO+SgDwd94DkkisWOjgtwhj7UNsWOztuQjoE+N4xzjqAPxS+GPhHFKbMjwbwQF/DgaBls5fOWz6OucLDO6DPCmFOcaBl0qtSfsCrPQQ5PJauA8TzuJy6tj7P6PrSzoKwmWX+K1Riu4/2YRp7qmiPw9QWJhp1n4fnF1nVFTX2xy+09vW2d/+78SIxBE0/a/tZMVoG1+LGAPWE21qe6M4+INfd1WEtv4M8z8+WZp/sFlBfmKNrQdsYi+1PIuiNxNx5pK7szp+s1t3+FveSxb3dWjzarEVj17gQ1p2POZxwd1vNAdY2Fv5nA+lS58c7Qf3hGK5e12LOxNX6PrVO9dD9J7M73N5MbiqpHEkOGtdMew/6kMdZCXBsD9rD/wP5ooed4woX+KR7KMR4tcfk0270Zx5LEXtA72MvLofT90HweYMuBNA+cH4mb6FZxs1ERNgUfzDZt7w1u3TCFIBNNCkHT95Z2IQW7k/OWIKvon4qOIrLwny1Np5qvwTL8tkmTSQkaoFV0qLs4BriaCxpsl5PN6rjBumIwHxlgJmIZmjMyHW1QZfkTls6SEnAWKp+GkBUgmaVJSJ5KWOBwzroix1h4tk27N9cOgJbnbTR9WQXeMkw9hG8+8DLVtQ2DDNhU9SZcB3OnFfgB6JWXwdK5iYPntQJTw5x4+OFP8kax7P5Fdnjs+vytPL9I9H8hl/4YPh/OsPFpgs3yFRsFw9UaAnP4YcvIibdCTigBxx7WyhmCoA7e/aib7aZe6AxWpkVrdvD2eer116LMXEC5jGYJri+EqH5xWz3sod6FHfSv3SCun5q8Fgk1jMpOXPh92e1RxQbB3WyD4H4pNnYDaw696L7xmwLS3xIx2XvE/GTE5IXKiPmnQiSq+tx0XwEXVwD/710Alz4vXnZ1xNeEI1dvnOz9VZu/8JWuj++b/4dcn7u7/gdcX6yJ9SPfP3H9tFb8w95/xTlD8TX91XciiR7dADjO0s5vZcs3NxvPOp2sV8/3CzwfOMROTNbhPoy0Y58cAr2b+fPvwLZ2fDP03k6PjqqwzC08UYc5Ogih77fodO4wruEzRZtgu7acvO/xgc+ZOiRepS40164TltQB7GZ81Cx37ouDR/g9awffyfQePGmP8iecq/z+WKx+urNds+Wx4lV73sVXrL0sM/j/vNnA+1UN49OJrgiuVevkZm9WuOqr4xn4paO4FEFnrbw5GZApaMUhLYXYNjdT2jItHE2af3Z2V5q8Dx7ulZyg2AkXkUsP1Wtmsl07te0mrby05VHPO5K/pj839ANWZH7qBLji0/PtXi4ubwP3DKsCicY9w7ra2esCVysy+NzfEWrUyq/TX5pVcb/AUfgMAeF9asO/g6MQ9XRrq83UiMjzREuGLpkR3J25u5485ElinfIV9DnqzsYx0aWi7pi7kPRaGBPZZXs6QVdwFwrbp/eZ/SjjMBzdHzgMC2f2vWvNHw3S3lVwGMi2J2fn2WT2Q6b8AiIr9LybJZ6UaB6O0rP5Ad5RTgNp4V1a9nCsDUlMKB+AnpfHGV+gN8CJFqfXlAOR8glAD31WaE95BbjXkhgtxgjqkdZK+QYsoXwDKINepGXn/Hw/odwCwqU8hlaql56xU04F1YuOyhwdRz8ZbrX0bH5Occi4AfqcchSgPGdVmcop50CNU37DkESUs5FyDvZtFB5sIXrW39PdbS+dcwn0Uj7DGPzVkEHnDuxG6Tjo+GMpgvptL+U8SEyX8jZ0hfIRQN8w7s58yhOAq4KgHGXcBoUBzAA3wMLDLMWQcipgXl2SgF35h5zZS7kjYI/QsXHaAPpQXkKGK/QBPziaP6JT/ZTLMd8CPhHVRfkKORclTrkWrf38RSn/RFZSHgo8bz5+QtvylH8AeuA5hjjjL6hRP3FpPc7qrUSVLSj3aZnJnncM7V0+4y+o7IG/oCbOy3PbTnzGVJRf5i8YyyAeoO/Nkd7cfAl/YabxtmKg3stz0B+8w19IDE9bqNzY+wR/4Rpb7/MXdnSfhL+34i98PpYKZ8eRqCJxZPl6DTOI5XD+RQOVwyrboN81eKHOiHVU5zl0q7zy1891fxtHUqjjmliv8w0EyDQY8fT9C4lijRPYOsaiIGDMiUIJ0AbgCSA1OJbBgiAUJwnHeNaFGuTwjFBnWcyIqFDy+/FkK/DMUslVZfLse0vnWzHS9G2dZln8uxn0VWqYajVHb/k/yYDR42kGDZWr8w4lwWmjM0e6+nj7Ys5c9sL3vfpD597nbvTnvIjD99z3nvvec9977nvPfe+579+S+/Js/fyUhKtg40E+B8GzRNs4yX5Zmv1iDkMshsSwzt8sXbvi2/o90N4D7T3Q3gPtPdDeA+3/SKBlmD1Bu/hK0qj4zoS4Go95hBAW6wInVLDeWZ4GWqYOYRYJGLPv0Do+FWf5quPLL/7MxCN2zw8p/lFRRXoiNGp8xcmucKtzLv4y+/3+xejLvhjtHfRDX4yorwjvp7K385srUtfbL6l6jT3N+BFTXlI8tMJlaG52dMxXHR3fl9RXL6nGBTd7n4JIParMdP6k30Dx8J9RZNS8w//ogZT/Ag==&lt;/diagram&gt;&lt;/mxfile&gt;" onclick="(function(svg){var src=window.event.target||window.event.srcElement;while (src!=null&amp;&amp;src.nodeName.toLowerCase()!='a'){src=src.parentNode;}if(src==null){if(svg.wnd!=null&amp;&amp;!svg.wnd.closed){svg.wnd.focus();}else{var r=function(evt){if(evt.data=='ready'&amp;&amp;evt.source==svg.wnd){svg.wnd.postMessage(decodeURIComponent(svg.getAttribute('content')),'*');window.removeEventListener('message',r);}};window.addEventListener('message',r);svg.wnd=window.open('https://viewer.diagrams.net/?client=1&amp;page=0&amp;edit=_blank');}}})(this);" style="cursor:pointer;max-width:100%;max-height:381px;"><defs/><g><image x="39.5" y="69.5" width="190.87" height="230" xlink:href="data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHByZXNlcnZlQXNwZWN0UmF0aW89InhNaWRZTWlkIG1lZXQiIHZpZXdCb3g9IjAgMCAyMDAgMjQwLjY5MTQwNjI1IiB3aWR0aD0iMjAwIiBoZWlnaHQ9IjI0MC42OTE0MDYyNSI+PGRlZnM+PHBhdGggZD0iTTAgMEwyMDAgMEwyMDAgMjQwLjY5TDAgMjQwLjY5TDAgMFoiIGlkPSJhOFN6TExySVMiLz48cGF0aCBkPSJNNjUuNjQgMTIuOTdDNDkuNzYgOS4yMyAzNy45IDExLjc0IDMxLjggMTIuOTdDMjMuMzkgMTQuNjYgMzEuMTIgMjkuOTQgNDEuMjYgMzkuNTZDNTAuNjMgNDguNDQgNzYuMjYgNTEuNjggNzQuNSA1My42MUMzMS4xIDEwMS4wOCA3LjU0IDE0MC40OSA3LjU0IDE2Mi4zMUM3LjU0IDE5OS41MSA0OC45NCAyMjkuNjcgMTAwIDIyOS42N0MxNTEuMDYgMjI5LjY3IDE5Mi40NiAxOTkuNTEgMTkyLjQ2IDE2Mi4zMUMxOTIuNDYgMTM5LjI1IDE3My42NSAxMDUuMzIgMTE1LjQ5IDUzLjYxQzExMy45MSA1Mi4yMSAxNDQuODggNDcuMjUgMTUzLjcyIDM5LjU2QzE2My40OCAzMS4wNiAxNjYuODYgMTYuMjQgMTU5LjI0IDEyLjk3QzE1My4yOCAxMC40MSAxNDAuMTMgOC42MSAxMjUuMzkgMTIuOTdDMTE2LjE2IDE1LjcgMTA2LjE0IDIwLjY4IDk1LjMzIDI3LjkyQzg2LjEyIDIwLjQ0IDc2LjIzIDE1LjQ2IDY1LjY0IDEyLjk3WiIgaWQ9ImMxUHR6RXdTTEIiLz48L2RlZnM+PGc+PGc+PGc+PHVzZSB4bGluazpocmVmPSIjYThTekxMcklTIiBvcGFjaXR5PSIxIiBmaWxsPSIjZmZmZmZmIiBmaWxsLW9wYWNpdHk9IjAiLz48L2c+PGc+PHVzZSB4bGluazpocmVmPSIjYzFQdHpFd1NMQiIgb3BhY2l0eT0iMSIgZmlsbD0iI2YwZTViZCIgZmlsbC1vcGFjaXR5PSIxIi8+PGc+PHVzZSB4bGluazpocmVmPSIjYzFQdHpFd1NMQiIgb3BhY2l0eT0iMSIgZmlsbC1vcGFjaXR5PSIwIiBzdHJva2U9IiMzZDMzMGYiIHN0cm9rZS13aWR0aD0iMyIgc3Ryb2tlLW9wYWNpdHk9IjEiLz48L2c+PC9nPjwvZz48L2c+PC9zdmc+" preserveaspectratio="none" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignobject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredfeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 145px; margin-left: 135px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: nowrap; "><div><b>Blind</b></div><div style="font-size: 3px"><b> <br/></b></div><div>100 HNS<b><br/></b></div></div></div></div></foreignobject><text x="135" y="149" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">Blind...</text></switch></g><ellipse cx="131.43" cy="225" rx="51.43" ry="45" fill="#ffffff" stroke="#000000" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignobject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredfeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 101px; height: 1px; padding-top: 225px; margin-left: 81px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; ">10 HNS</div></div></div></foreignobject><text x="131" y="229" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">10 HNS</text></switch></g><g transform="translate(-0.5 -0.5)"><switch><foreignobject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredfeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 200px; margin-left: 131px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: nowrap; "><b>Bid</b></div></div></div></foreignobject><text x="131" y="204" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">Bid</text></switch></g><g transform="translate(-0.5 -0.5)"><switch><foreignobject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredfeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 55px; margin-left: 131px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: nowrap; "><div><b>Lock up<br/></b></div><div style="font-size: 3px"><b> <br/></b></div><div>110 HNS<b><br/></b></div></div></div></div></foreignobject><text x="131" y="59" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">Lock up...</text></switch></g><g transform="translate(-0.5 -0.5)"><switch><foreignobject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredfeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 25px; margin-left: 376px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: nowrap; "><div><b>Lock up<br/></b></div><div style="font-size: 3px"><b> <br/></b></div><div>50 HNS<b><br/></b></div></div></div></div></foreignobject><text x="376" y="29" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">Lock up...</text></switch></g><g transform="translate(-0.5 -0.5)"><switch><foreignobject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredfeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 355px; margin-left: 380px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: nowrap; "><div><b>Lock up<br/></b></div><div style="font-size: 3px"><b> <br/></b></div><div>20 HNS<b><br/></b></div></div></div></div></foreignobject><text x="380" y="359" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">Lock up...</text></switch></g><path d="M 70.93 339.41 L 70.93 329.41 L 150.43 329.41 L 180.93 329.41 L 180.93 318.91 L 199.93 334.41 L 180.93 349.91 L 180.93 339.41 L 150.43 339.41 Q 150.43 339.41 150.43 339.41 Z" fill="#1ba1e2" stroke="none" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignobject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredfeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 310px; margin-left: 135px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: nowrap; "><font style="font-size: 19px"><b>Bid</b></font></div></div></div></foreignobject><text x="135" y="314" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">Bid</text></switch></g><path d="M 13.44 314.39 C 13.36 310.61 14.62 306.96 16.93 304.25 C 19.23 301.55 22.39 300.01 25.69 300 C 33.05 300.08 39.05 306.48 39.32 314.54 C 39.6 318.24 38.49 321.91 36.24 324.69 C 34 327.46 30.83 329.1 27.46 329.23 C 20.01 329.39 13.79 322.81 13.44 314.39 Z M 0 350 C 0.3 342.97 2.88 336.42 7.14 331.94 C 10.51 328.56 15.21 328.36 18.75 331.44 C 20.77 332.95 22.99 334.17 25.35 335.06 C 27.76 336.12 30.41 335.94 32.73 334.56 C 34 333.94 35.12 333.04 36.03 331.94 C 36.92 330.86 38.47 330.64 39.62 331.44 C 41.64 332.81 43.46 335.24 44.88 338.48 C 46.26 342.16 46.98 346.05 47 349.99 Z" fill="#1ba1e2" stroke="none" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignobject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredfeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 154px; margin-left: 602px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: nowrap; "><div><b>Lock up<br/></b></div><div style="font-size: 3px"><b> <br/></b></div><div>80 HNS<b><br/></b></div></div></div></div></foreignobject><text x="602" y="157" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">Lock up...</text></switch></g><image x="449.5" y="99.5" width="157.4" height="190" xlink:href="data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHByZXNlcnZlQXNwZWN0UmF0aW89InhNaWRZTWlkIG1lZXQiIHZpZXdCb3g9IjAgMCAxOTcuNjIxMDkzNzUgMjM4LjgwODU5Mzc1IiB3aWR0aD0iMTk3LjYyMTA5Mzc1IiBoZWlnaHQ9IjIzOC44MDg1OTM3NSI+PGRlZnM+PHBhdGggZD0iTTAgMEwxOTcuNjIgMEwxOTcuNjIgMjM4LjgxTDAgMjM4LjgxTDAgMFoiIGlkPSJmejJLckFZMGwiLz48cGF0aCBkPSJNNjMuODkgMTIuMjVDNDguMDEgOC41MiAzNi4xNSAxMS4wMyAzMC4wNSAxMi4yNUMyMS42NCAxMy45NCAyOS4zNyAyOS4yMyAzOS41MiAzOC44NUM0OC44OCA0Ny43MyA3NC41MSA1MC45NyA3Mi43NSA1Mi45QzI5LjM2IDEwMC4zNyA1Ljc5IDEzOS43NyA1Ljc5IDE2MS42QzUuNzkgMTk4LjggNDcuMTkgMjI4Ljk1IDk4LjI1IDIyOC45NUMxNDkuMzIgMjI4Ljk1IDE5MC43MSAxOTguOCAxOTAuNzEgMTYxLjZDMTkwLjcxIDEzOC41MyAxNzEuOTEgMTA0LjYgMTEzLjc1IDUyLjlDMTEyLjE3IDUxLjQ5IDE0My4xMyA0Ni41NCAxNTEuOTcgMzguODVDMTYxLjc0IDMwLjM1IDE2NS4xMSAxNS41MiAxNTcuNDkgMTIuMjVDMTUxLjU0IDkuNyAxMzguMzkgNy45IDEyMy42NCAxMi4yNUMxMTQuNDEgMTQuOTggMTA0LjM5IDE5Ljk3IDkzLjU4IDI3LjIxQzg0LjM4IDE5LjczIDc0LjQ4IDE0Ljc1IDYzLjg5IDEyLjI1WiIgaWQ9ImIzeXRGdzl0aEEiLz48L2RlZnM+PGc+PGc+PGc+PHVzZSB4bGluazpocmVmPSIjZnoyS3JBWTBsIiBvcGFjaXR5PSIxIiBmaWxsPSIjZmZmZmZmIiBmaWxsLW9wYWNpdHk9IjAiLz48L2c+PGc+PHVzZSB4bGluazpocmVmPSIjYjN5dEZ3OXRoQSIgb3BhY2l0eT0iMSIgZmlsbD0iIzZiNmI2YiIgZmlsbC1vcGFjaXR5PSIxIi8+PGc+PHVzZSB4bGluazpocmVmPSIjYjN5dEZ3OXRoQSIgb3BhY2l0eT0iMSIgZmlsbC1vcGFjaXR5PSIwIiBzdHJva2U9IiMwMDAwMDAiIHN0cm9rZS13aWR0aD0iMyIgc3Ryb2tlLW9wYWNpdHk9IjEiLz48L2c+PC9nPjwvZz48L2c+PC9zdmc+" preserveaspectratio="none" pointer-events="none"/><ellipse cx="528.7" cy="227.52" rx="43.7187910523331" ry="38.25503355704698" fill="#ffffff" stroke="#000000" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignobject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredfeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 85px; height: 1px; padding-top: 228px; margin-left: 486px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; "><p style="line-height: 160%"><b style="line-height: 100%">Bid<br/></b>? HNS</p><p/></div></div></div></foreignobject><text x="529" y="231" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">Bid...</text></switch></g><image x="326.93" y="39.5" width="99.41" height="119.99" xlink:href="data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHByZXNlcnZlQXNwZWN0UmF0aW89InhNaWRZTWlkIG1lZXQiIHZpZXdCb3g9IjAgMCAxOTcuNjIxMDkzNzUgMjM4LjgwODU5Mzc1IiB3aWR0aD0iMTk3LjYyMTA5Mzc1IiBoZWlnaHQ9IjIzOC44MDg1OTM3NSI+PGRlZnM+PHBhdGggZD0iTTAgMEwxOTcuNjIgMEwxOTcuNjIgMjM4LjgxTDAgMjM4LjgxTDAgMFoiIGlkPSJmejJLckFZMGwiLz48cGF0aCBkPSJNNjMuODkgMTIuMjVDNDguMDEgOC41MiAzNi4xNSAxMS4wMyAzMC4wNSAxMi4yNUMyMS42NCAxMy45NCAyOS4zNyAyOS4yMyAzOS41MiAzOC44NUM0OC44OCA0Ny43MyA3NC41MSA1MC45NyA3Mi43NSA1Mi45QzI5LjM2IDEwMC4zNyA1Ljc5IDEzOS43NyA1Ljc5IDE2MS42QzUuNzkgMTk4LjggNDcuMTkgMjI4Ljk1IDk4LjI1IDIyOC45NUMxNDkuMzIgMjI4Ljk1IDE5MC43MSAxOTguOCAxOTAuNzEgMTYxLjZDMTkwLjcxIDEzOC41MyAxNzEuOTEgMTA0LjYgMTEzLjc1IDUyLjlDMTEyLjE3IDUxLjQ5IDE0My4xMyA0Ni41NCAxNTEuOTcgMzguODVDMTYxLjc0IDMwLjM1IDE2NS4xMSAxNS41MiAxNTcuNDkgMTIuMjVDMTUxLjU0IDkuNyAxMzguMzkgNy45IDEyMy42NCAxMi4yNUMxMTQuNDEgMTQuOTggMTA0LjM5IDE5Ljk3IDkzLjU4IDI3LjIxQzg0LjM4IDE5LjczIDc0LjQ4IDE0Ljc1IDYzLjg5IDEyLjI1WiIgaWQ9ImIzeXRGdzl0aEEiLz48L2RlZnM+PGc+PGc+PGc+PHVzZSB4bGluazpocmVmPSIjZnoyS3JBWTBsIiBvcGFjaXR5PSIxIiBmaWxsPSIjZmZmZmZmIiBmaWxsLW9wYWNpdHk9IjAiLz48L2c+PGc+PHVzZSB4bGluazpocmVmPSIjYjN5dEZ3OXRoQSIgb3BhY2l0eT0iMSIgZmlsbD0iIzZiNmI2YiIgZmlsbC1vcGFjaXR5PSIxIi8+PGc+PHVzZSB4bGluazpocmVmPSIjYjN5dEZ3OXRoQSIgb3BhY2l0eT0iMSIgZmlsbC1vcGFjaXR5PSIwIiBzdHJva2U9IiMwMDAwMDAiIHN0cm9rZS13aWR0aD0iMyIgc3Ryb2tlLW9wYWNpdHk9IjEiLz48L2c+PC9nPjwvZz48L2c+PC9zdmc+" preserveaspectratio="none" pointer-events="none"/><image x="310.36" y="169.5" width="132.55" height="159.99" xlink:href="data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHByZXNlcnZlQXNwZWN0UmF0aW89InhNaWRZTWlkIG1lZXQiIHZpZXdCb3g9IjAgMCAxOTcuNjIxMDkzNzUgMjM4LjgwODU5Mzc1IiB3aWR0aD0iMTk3LjYyMTA5Mzc1IiBoZWlnaHQ9IjIzOC44MDg1OTM3NSI+PGRlZnM+PHBhdGggZD0iTTAgMEwxOTcuNjIgMEwxOTcuNjIgMjM4LjgxTDAgMjM4LjgxTDAgMFoiIGlkPSJmejJLckFZMGwiLz48cGF0aCBkPSJNNjMuODkgMTIuMjVDNDguMDEgOC41MiAzNi4xNSAxMS4wMyAzMC4wNSAxMi4yNUMyMS42NCAxMy45NCAyOS4zNyAyOS4yMyAzOS41MiAzOC44NUM0OC44OCA0Ny43MyA3NC41MSA1MC45NyA3Mi43NSA1Mi45QzI5LjM2IDEwMC4zNyA1Ljc5IDEzOS43NyA1Ljc5IDE2MS42QzUuNzkgMTk4LjggNDcuMTkgMjI4Ljk1IDk4LjI1IDIyOC45NUMxNDkuMzIgMjI4Ljk1IDE5MC43MSAxOTguOCAxOTAuNzEgMTYxLjZDMTkwLjcxIDEzOC41MyAxNzEuOTEgMTA0LjYgMTEzLjc1IDUyLjlDMTEyLjE3IDUxLjQ5IDE0My4xMyA0Ni41NCAxNTEuOTcgMzguODVDMTYxLjc0IDMwLjM1IDE2NS4xMSAxNS41MiAxNTcuNDkgMTIuMjVDMTUxLjU0IDkuNyAxMzguMzkgNy45IDEyMy42NCAxMi4yNUMxMTQuNDEgMTQuOTggMTA0LjM5IDE5Ljk3IDkzLjU4IDI3LjIxQzg0LjM4IDE5LjczIDc0LjQ4IDE0Ljc1IDYzLjg5IDEyLjI1WiIgaWQ9ImIzeXRGdzl0aEEiLz48L2RlZnM+PGc+PGc+PGc+PHVzZSB4bGluazpocmVmPSIjZnoyS3JBWTBsIiBvcGFjaXR5PSIxIiBmaWxsPSIjZmZmZmZmIiBmaWxsLW9wYWNpdHk9IjAiLz48L2c+PGc+PHVzZSB4bGluazpocmVmPSIjYjN5dEZ3OXRoQSIgb3BhY2l0eT0iMSIgZmlsbD0iIzZiNmI2YiIgZmlsbC1vcGFjaXR5PSIxIi8+PGc+PHVzZSB4bGluazpocmVmPSIjYjN5dEZ3OXRoQSIgb3BhY2l0eT0iMSIgZmlsbC1vcGFjaXR5PSIwIiBzdHJva2U9IiMwMDAwMDAiIHN0cm9rZS13aWR0aD0iMyIgc3Ryb2tlLW9wYWNpdHk9IjEiLz48L2c+PC9nPjwvZz48L2c+PC9zdmc+" preserveaspectratio="none" pointer-events="none"/><ellipse cx="375.69" cy="270" rx="34.284999999999975" ry="30" fill="#ffffff" stroke="#000000" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignobject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredfeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 67px; height: 1px; padding-top: 270px; margin-left: 342px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; "><p style="line-height: 160%"><b style="line-height: 100%">Bid<br/></b>? HNS</p><p/></div></div></div></foreignobject><text x="376" y="274" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">Bid...</text></switch></g><ellipse cx="375.7" cy="115" rx="28.56999999999999" ry="25" fill="#ffffff" stroke="#000000" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignobject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredfeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 55px; height: 1px; padding-top: 115px; margin-left: 348px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; "><p style="line-height: 160%"><b style="line-height: 100%">Bid<br/></b>? HNS</p><p/></div></div></div></foreignobject><text x="376" y="119" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">Bid...</text></switch></g></g><switch><g requiredfeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/><a transform="translate(0,-5)" xlink:href="https://www.diagrams.net/doc/faq/svg-export-text-problems" target="_blank"><text text-anchor="middle" font-size="10px" x="50%" y="100%">Viewer does not support full SVG 1.1</text></a></switch></svg></p>
<figcaption>入札の概念図。ブラインドを追加して資金をロックアップすることで、実際の入札額を不明瞭にできる。左の入札したユーザーは、他の入札に関して合計のロックアップ額を知ることしかできない。</figcaption>
</figure>
<p>2 位価格封印入札では、<strong>最高入札額を提示した入札者が、次点の入札額を支払って落札する</strong>。例えば、オークションの参加者が 1000 HNS を入札した A と 10 HNS を入札した B の 2 人のみだった場合、A が 10 HNS で落札する。また、自分以外に入札者がいなかった場合、無料で落札できる。このオークション形式では、自分がそのドメイン名に感じる価値の範囲内においては、入札額を高く設定することで損はしないはずなので、入札額を変に渋って他の人に落札されてしまわないようにしたい。</p>
<p>なお、<strong>最高額入札者が複数存在した場合、最高額入札者の中でランダムに落札者が決定する</strong>。これを防ぐため、0.1 HNS のような端数を追加すると、万が一このようなケースが起こったときに救われるかもしれない。</p>
<p>最後に、落札者の決定するプロセスにおいて、ブラインドは完全に無視されることに注意したい。例えば上記のような複数の最高入札額が現れたケースでも、<strong>ブラインドが多かったからといって有利になることはない</strong>。</p>
<p>入札期間は 720 ブロック（約 5 日）だ。この間に入札する必要がある。入札額を追加したい場合、<code>sendbid</code> を重ねて実行することで、再入札できる。ただし、前の入札は取り消されず、別々の入札者として扱われる。（例えば、入札者が実際は自分だけだったとしても、 2 回入札した場合は、無料で落札できない）</p>
<h3 id="34">3.4. 入札額を開示する</h3>
<p>入札期間が終わり、ステータスが <code>REVEAL</code> になると、<code>sendreveal</code> コマンドで実際の入札額を開示できる。</p>
<pre><code>$ ./bin/hsw-cli rpc sendreveal zettaini-hosikunai-domein
</code></pre>
<p>この操作により、ブラインド分のロックアップが解除され、手元に戻ってくる。各入札者が reveal を行い次第、ブロックチェーンエクスプローラーを見ると実際の入札額が分かるようになる。</p>
<p><strong><code>REVEAL</code> 期間は 1440 ブロック（約 10 日）あるこの期間に reveal 操作を行わないと、ブラインドを含む全てのロックアップ額が没収（ネットワーク上で焼却）されてしまう</strong>ので確実に reveal するようにしたい。</p>
<p><code>REVEAL</code> 期間が終わると、ステータスは <code>CLOSED</code> となる。</p>
<h3 id="35a">3.5. (A) ドメインのレコードを登録する。</h3>
<p>ステータスが <code>CLOSED</code> に変わった後、オークションに競り勝ち、無事そのドメインを取得することができていたら、<code>sendupdate</code> コマンドで DNS リソースレコードを登録できる。これにより、登録したドメイン名を解決する権威 DNS サーバーを指定できる。</p>
<p>詳細は省略するが、単純な例では以下のようになる。</p>
<pre><code>$ ./bin/hsw-cli rpc sendupdate zettaini-hosikunai-domein $(cat &lt;&lt;&lt;EOF
{
  &quot;records&quot;: [{
    &quot;type&quot;: &quot;NS&quot;,
    &quot;ns&quot;: &quot;ns1.example.com.&quot;,
  }]
}
EOF
)
</code></pre>
<p>権威 DNS サーバーが、通常の DNS サーバーで解決できるホスト名 <code>ns1.example.com</code> を持っている場合は上記のように指定できる。</p>
<p>そうでない場合、</p>
<pre><code>$ ./bin/hsw-cli rpc sendupdate zettaini-hosikunai-domein $(cat &lt;&lt;&lt;EOF
{
  &quot;records&quot;: [{
    &quot;type&quot;: &quot;GLUE4&quot;,
    &quot;ns&quot;: &quot;ns1.zettaini-hosikunai-domein.&quot;,
    &quot;address&quot;: &quot;203.0.113.1&quot;
  }]
}
EOF
)
</code></pre>
<p>として <code>203.0.113.1</code> の IP アドレスを持ち、<code>ns1.zettaini-hosikunai-domein.</code> の内部名で解決される権威ネームサーバーを指定できる。</p>
<p>初めて <code>sendupdate</code> を実行した際、実際に入札した価格と、落札額（＝次点入札者の入札額）の差額が自動的に回収される。</p>
<p>取得したドメイン名は 2 年で有効期限が切れる。切れてしまう前に <code>sendrenewal</code> を発行することで更新ができる。</p>
<h3 id="35b">3.5. (B) 競り負けた際に入札額を回収する</h3>
<p>運悪くドメイン名を落札できなかった場合、<code>sendredeem</code> コマンドにより入札額を回収できる。</p>
<pre><code>$ ./bin/hsw-cli rpc sendredeem zettaini-hosikunai-domein
</code></pre>
<p>残念でした。</p>
<h2 id="4">4. 確認</h2>
<p><code>getnameresource</code> コマンドで、ブロックチェーン上で実際にリソースレコードが登録されたことを確認できる。</p>
<pre><code>$ ./bin/hsd-cli rpc getnameresource zettaini-hosikunai-domein
{
  &quot;records&quot;: [{
    &quot;type&quot;: &quot;GLUE4&quot;,
    &quot;ns&quot;: &quot;ns1.zettaini-hosikunai-domein.&quot;,
    &quot;address&quot;: &quot;203.0.113.1&quot;
  }]
}
</code></pre>
<p>登録した情報で実際に DNS を引けるようになるには、 36ブロック（約 6 時間）ごとに発生する urkle-tree の更新タイミングを待たなければならない。これが更新されると、以下のように DNS の解決を試すことができる。</p>
<p><code>hsd</code> フルノードは、それ自体が Handshake DNS ドメイン名を解決するネームサーバーとしての機能を持っている。デフォルトでは、ポート 5349 で権威サーバー、5350 でフルサービスリゾルバが動いている。よって、</p>
<pre><code>$ dig +noall +authority +additional @localhost -p 5349 zettaini-hosikunai-domein.
zettaini-hosikunai-domein.                  21600   IN      NS      ns1.zettaini-hosikunai-domein.
ns1.zettaini-hosikunai-domein.              21600   IN      A       203.0.113.1
...
</code></pre>
<p>のようにドメイン名が解決できることを確認できる。また、権威ネームサーバー <code>ns1.zettaini-hosikunai-domein.</code> を正しく設定していれば、フルサービスリゾルバを使って</p>
<pre><code>$ dig +short @localhost -p 5350 www.zettaini-hosikunai-domein.
203.0.113.2
</code></pre>
<p>のように、権威ネームサーバーが解決する結果を得ることができるはずだ。また、<a href="https://www.hdns.io">hdns.io</a> が公開しているオープンリゾルバ <code>103.196.38.38</code> や <code>103.196.38.39</code> でも同じ結果が返ってくることを確認できるはずだ。</p>
<h1 id>おわりに</h1>
<p>この記事では、Handshake の概要と、Handshake でドメイン名を取得する方法について取得した。僕は実際に <code>mecab</code> というトップレベルドメインを取得して、<a href="http://mecab/">http://mecab/</a> でホームページ <a href="http://misosi.ru/">http://misosi.ru/</a> と同じコンテンツを表示するようにしてみた。当然、この URL は通常の DNS で解決することはできない。しかし、Handshake ドメインを解決してページを表示してくれるゲートウェイ <a href="https://hns.to/">hns.to</a> を通せば、<a href="http://mecab.hns.to/">http://mecab.hns.to/</a> として見ることができる。もちろん、ネットワーク の設定を変更し、ネームサーバーとして上記の <code>103.196.38.38</code> や <code>103.196.38.39</code> を指定しても見ることができる。</p>
<p>はじめに書いたように、Handshake はまだ実験的なプロジェクトで、稼働はするが実用的に使える状態ではない。そもそも Handshake DNS を解決できるネームサーバーを設定しているユーザーがいないということは脇に置いても、CDN がない（少なくとも、Cloudflare は ICANN が管理しているドメインしか origin に指定できない）とか、対応した認証局 (CA) がないため SSL で暗号化できないという問題がある。</p>
<p>しかし、鶏か卵かという問題はあれど、Handshake が普及するにつれて既存のサービスも徐々に対応が進むかもしれないので、これからに期待したい。CA に関しては、そもそも Handshake のプロジェクトのスコープとして、分散型の CA を立ち上げることも含まれるため、プロジェクトの今後に期待したい。</p>
<p>最後に、本文に含めた物も含め、Handshake に関連したいくつかのサービスを挙げて終わりにしようと思う。</p>
<ul>
<li><strong>Namebase</strong> (<a href="https://www.namebase.io/">https://www.namebase.io/</a>): ドメイン名売買サービス。自分が持つドメインの管理も行える。実は手元に <code>hsd</code> をインストールしなくても、このサイトに HNS を送金してそこからドメイン取得を行えるらしい。reveal や 更新の処理も自動でやってくれるようだ。その他 Handshake に関する文書も多くあり、情報源としても役に立つ。</li>
<li><strong>hns.to</strong> (<a href="https://hns.to/">https://hns.to/</a>): Handshake ゲートウェイ。Handshake ドメイン名の後に <code>.hns.to</code> を付けると、それが HTTP サーバーだった場合、提供されているコンテンツを表示してくれる。</li>
<li><strong>hdns.io</strong> (<a href="https://www.hdns.io">https://www.hdns.io</a>): Handshake ドメイン名を解決するオープンリゾルバ。<code>103.196.38.38</code> と <code>103.196.38.39</code>。</li>
<li><strong>domains.tasuki</strong> (<a href="http://domains.tasuki">http://domains.tasuki</a>) と <strong>sniper.tasuki</strong> (<a href="http://sniper.tasuki">http://sniper.tasuki</a>): Namebase で売られているドメインを価格帯ごとにリストするサイトと、オークションの締め切りが近いドメインをリストするサイト。これらは Handshake ドメイン名で公開されているので、閲覧するには環境を整える必要がある。（おそらく JavaScript の都合で、hns.to を通しても見ることができない。）</li>
</ul>
<hr class="footnotes-sep">
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p>例えば、政府がドメイン名を差し押さえることがある。（参考: <a href="https://webtan.impress.co.jp/e/2010/11/30/9282">アメリカ政府がWebサイトのDNSを差し押さえ、数十サイトがアクセス不可に | 初代編集長ブログ―安田英久 | Web担当者Forum</a>） <a href="#fnref1" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn2" class="footnote-item"><p>Alexa ランキング上位 10 万位までに入ったドメイン名が予約されている。これらのドメインの所有者は、TXT レコードを設定するか、または DNSSEC を設定したネームサーバーであれば、その秘密鍵を使って署名した情報を送信することで Handshake 上でも同じドメインを取得することができる。詳細は <a href="https://hsd-dev.org/guides/claims.html">How to Claim a Name</a> 参照。 <a href="#fnref2" class="footnote-backref">↩︎</a></p>
</li>
</ol>
</section>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Chia を 換金できる取引所のメモ]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>1月前から Chia ブロックチェーンのファーミングを行っているが、先日ようやくファーミングに成功した。Chia 自体についての詳細は前記事を参照されたい。</p>
<p>報酬として獲得できるネイティブトークン XCH のうち一部を売却して USDT に換金した。複数の取引所を試したのでそれぞれの比較をメモしておく。</p>
<p>以下は 2021 年 5 月 14 日の情報に基づく。それぞれの取引所で、1) XCH の入金、2) XCH 売り USDT 買いの取引、3) USDT の Binance への送付を試した。以下の全ての取引所で、TRX20 ネットワークでの USDT 送金がサポートされていた。出金手数料は TRX20 を利用した場合の手数料だ。</p>
<p><strong><a href="https://www.okex.com/join/8279255">OKEX</a></strong></p>
<ul>
<li>最低出金額: 2USDT (Feeを除外して)</li>
<li>出金手数料: 1USDT</li>
<li>100USD相当入金+100USD相当の取引をすると80USDT分の取引手数料（出金手数料に使えるかは不明）</li></ul>]]></description><link>https://blog.misosi.ru/2021/05/17/chia-exchange/</link><guid isPermaLink="false">60a2b85c6722fa7cae9c988c</guid><dc:creator><![CDATA[mecab]]></dc:creator><pubDate>Mon, 17 May 2021 18:51:41 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>1月前から Chia ブロックチェーンのファーミングを行っているが、先日ようやくファーミングに成功した。Chia 自体についての詳細は前記事を参照されたい。</p>
<p>報酬として獲得できるネイティブトークン XCH のうち一部を売却して USDT に換金した。複数の取引所を試したのでそれぞれの比較をメモしておく。</p>
<p>以下は 2021 年 5 月 14 日の情報に基づく。それぞれの取引所で、1) XCH の入金、2) XCH 売り USDT 買いの取引、3) USDT の Binance への送付を試した。以下の全ての取引所で、TRX20 ネットワークでの USDT 送金がサポートされていた。出金手数料は TRX20 を利用した場合の手数料だ。</p>
<p><strong><a href="https://www.okex.com/join/8279255">OKEX</a></strong></p>
<ul>
<li>最低出金額: 2USDT (Feeを除外して)</li>
<li>出金手数料: 1USDT</li>
<li>100USD相当入金+100USD相当の取引をすると80USDT分の取引手数料（出金手数料に使えるかは不明）に充当できるクーポンがもらえる。<br>
流動性がある。価格が安い。Googleアカウントで登録できて楽。出金パスワードを設定しないといけないのがちょっとめんどくさい（セキュリティ的には良いけど）。全体的にUXは良い気がする。とりあえず100USDはKYC無しで出金できた。上限不明</li>
</ul>
<p><strong><a href="https://www.mxcio.co/auth/signup?inviteCode=1CUBG">MXC.com</a></strong></p>
<ul>
<li>最低出金額:  30USDT</li>
<li>出金手数料: 1USDT<br>
流動性は低めだけどちょこちょこ売る分には大丈夫では。メール認証が時々到着遅いときがある（1分ほど待てばちゃんと来るけど）。0.7BTC/日まではKYC無しで出金できる。</li>
</ul>
<p><strong><a href="https://www.gate.io/signup/5328237">Gate.io</a></strong></p>
<ul>
<li>最低出金額: 300USDT (!!)</li>
<li>出金手数料: 0USDT<br>
流動性はMXCと同じぐらい。10USDT ほど換金したものの、最低出金額が 300 USDT だったので怖いので出金は試さずそのまま放置している。他の通貨建てでも最低出金額が10000円相当だったりでクソ。パスポートと自撮り送ってのKYCを済ませないと出金できないような雰囲気があるけど不明...。</li>
</ul>
<p><strong><a href="https://www.xt.com/r/5RY4KKGQFH">XT.com</a></strong><br>
XCHの入金ができなかった。</p>
<p>5 月 14 日時点では取引所間の価格が大きく、OKEX が　MXC や Gate.io に比べて安かったのだが、現在はほとんど変わらなくなっている（むしろ執筆時点では OKEX がやや高い）。現在は Huobi での取り扱いもされているので、Huobi も良いかもしれない（名前は時々聞くので）。</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[MergerFS を使った Chia の plot 管理]]></title><description><![CDATA[Chia ブロックチェーンのファーミングを行うに当たって、plot の管理を MergerFS を使って行うと便利だったので紹介する。]]></description><link>https://blog.misosi.ru/2021/05/16/organize-chia-plots-with-mergerfs/</link><guid isPermaLink="false">609f896f6722fa7cae9c95e4</guid><category><![CDATA[chia]]></category><category><![CDATA[mergerfs]]></category><category><![CDATA[nas]]></category><category><![CDATA[tech]]></category><dc:creator><![CDATA[mecab]]></dc:creator><pubDate>Sun, 16 May 2021 16:28:38 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h1 id>背景と概要</h1>
<p>ここ 1 ヶ月ほど、ブロックチェーン Chia のファーミング <sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup> を試している。Chia は Proof of Space and Time (PoST) というコンセンサスアルゴリズムを用いたブロックチェーンだ。このコンセンサスアルゴリズムでは、Proof of Work (PoW) におけるハッシュ計算にあたる作業を事前に大量に行い plot と呼ばれるデータを作成し、実際のブロック検証（ファーミング）時には作成した plot 中から正解に近いデータを提出するという形で検証が行われる。plot はいわゆるレインボーテーブルのようなものだ。</p>
<p>plot の作成にはそれなりに計算負荷と時間がかかるが、一度作った plot を使ってファーミングを行うのはほぼ負荷なく行うことができるため、環境にやさしいとされている。</p>
<p>当然ながら、plot を多く作成すればするほど、その plot に含まれるデータを使ってブロックを検証できる機会が多くなるため、収益を上げるためには多くの plot を作り、それを保持することが重要になる。ここで問題になるのは HDD の管理だ。作った plot で既存の HDD が埋まるたびに買い足していく（現在、1 日あたり 8 plot ほど作成できている。これは約 800 GB に相当するので、10日で8TBの HDD が埋まる計算になる）ことになる。</p>
<p>plot を作り続けるたびに物理的に増え続ける HDD をいかに容易に管理するかが問題となった。これを検討した結果、<a href="https://github.com/trapexit/mergerfs">MergerFS</a> が適していたのでその概要と使い方を説明する。</p>
<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<p><ins class="adsbygoogle" style="display:block; text-align:center;" data-ad-layout="in-article" data-ad-format="fluid" data-ad-client="ca-pub-5314531653763426" data-ad-slot="9673121688"></ins></p>
<script>
     (adsbygoogle = window.adsbygoogle || []).push({});
</script>
<h1 id>要件</h1>
<p>Chia における plot 保存用 ストレージ に求められることとして、以下の要件を検討した結果、MergerFS を使うことにした。</p>
<ol>
<li>
<p><strong>複数の物理的なストレージを束ねて1つのストレージとして管理したい。</strong><br>
HDD を買い足して接続するたびに、その HDD を plot の読み取り先や作成先として指定するのは手間だ。特に、plot の作成が大変で、現在のバージョンでは plot 作成の一時停止を行うことができない（中止すると作成中の plot が最初から作り直しになってしまう）ため、plot の作成完了を待ってから書き込み先を変更すればならず、厄介だ。</p>
</li>
<li>
<p><strong>障害が起こったときの影響範囲を局所化したい。</strong><br>
例えば RAID-0 では複数のHDDを束ねることができるが、1つのHDDが壊れただけで全てのデータが読み取れなくなってしまう。これで全ての plot が壊れるとさすがにもったいないので、もし HDD が壊れても、その HDD にあるデータの損害だけですませたい。</p>
</li>
<li>
<p>一方で、<strong>容量の効率を重視したい</strong>ので、ミラーやパリティによる耐障害性の確保はしたくない。</p>
</li>
<li>
<p><strong>簡単にストレージを追加したい。</strong><br>
貴重な収益機会を失いたくないため、新しいストレージを追加する場合でも、手軽に、かつダウンタイムをほぼ無くストレージを追加したい。</p>
</li>
<li>
<p>** NFS で公開して他のマシンから rsync で plot をコピーできるようにしたい。**<br>
複数台の Linux マシンで plot を生成しているので、各マシンからはストレージを NFS でマウントして、生成した plot を rsync できるようにしたい。（これは要件としてあげるまでもないと考えていたが、結果的に MergerFS の利用を決定づけるものになった。後述する。）</p>
</li>
</ol>
<h1 id="mergerfs">MergerFS</h1>
<p><a href="https://github.com/trapexit/mergerfs">MergerFS</a> はこの用途に最適だった。指定された複数のディレクトリを結合したビューを持つファイルシステムを作成するものだ。例えば <code>/mnt/a</code> と <code>/mnt/b</code> を結合して <code>/mnt/x</code> というファイルシステムを作ったとする。この時、<code>/mnt/a/a.txt</code>、<code>/mnt/b/b.txt</code> という 2 つのファイルがあったとすれば、これらは<code>/mnt/x/a.txt</code>、<code>/mnt/x/b.txt</code> のように見える。サブディレクトリがあっても問題なく動き、また書き込みも行えて、結合したディレクトリに書き込みを行うと、結合元のディレクトリのいずれかに実体が書き込まれる。</p>
<p>ストレージが壊れた場合でも、MergerFS が提供しているのはただの結合したビューでしかないため、壊れたストレージに存在したファイルにアクセスできなくなるだけですむ。また、容量的なオーバーヘッドもない。</p>
<pre><code>$ cd /mnt/merged # /mnt/a と /mnt/b をマージしたディレクトリを /mnt/merged とする
$ sudo xattr -w user.mergerfs.branches '+&lt;/mnt/c' ./.mergerfs
</code></pre>
<p>として、マージされたディレクトリのルートに存在する仮想的なファイルに対して拡張属性をセットすることでオンラインでのディスクの追加や削除ができる。</p>
<p>似たような、複数のディレクトリを束ねたビューを提供するファイルシステムとして、古くから mhddfs がある。MergerFS が優れている点はいくつかあるが、個人的に大きかった点を2点上げると、1つは上述したようにオンラインでのディスク追加や削除ができることだ。もう1つは、束ねたディレクトリに対して NFS 越しに rsync でファイルをコピーしても問題が起こらないことだ。（＝要件5）</p>
<p>mhddfs で作成したディレクトリを NFS で公開して、そこに対して rsync を行うと、<code>ESTALL</code> が発生し正しくファイルをコピーできないことがある。この問題<sup class="footnote-ref"><a href="#fn2" id="fnref2">[2]</a></sup>は、正確には mhddfs ではなく fuse の問題であるのだが、同じく fuse でマウントされる MergerFS はこの問題を解決するためのオプションが用意されている。そこで、最終的に MergerFS を利用することにした。</p>
<h1 id="mergerfs">MergerFS のインストールと使い方</h1>
<p>Debian 10 (buster) の環境にインストールした。まだ apt によるインストールはできないが、MergerFS の<a href="https://github.com/trapexit/mergerfs/releases/">リリースページ</a>には .deb ファイルが用意されているのでこれを利用できる。</p>
<pre><code>$ curl -LO https://github.com/trapexit/mergerfs/releases/download/2.32.4/mergerfs_2.32.4.debian-buster_amd64.deb # バージョン、ディストリビューションとアーキテクチャは適宜読み替えること
$ sudo dpkg -i ./mergerfs_2.32.4.debian-buster_amd64.deb
</code></pre>
<p>以上でインストールができる。インストールした後は、以下のようにマウントする。</p>
<pre><code>$ sudo mount -t fuse.mergerfs -o defaults,allow_other,use_ino,cache.files=partial,dropcacheonclose=true,category.create=mfs /mnt/a:/mnt:b /mnt/merged
</code></pre>
<p>以上で、<code>/mnt/a</code> と <code>/mnt/b'</code> をマージしたディレクトリが <code>/mnt/merged</code> にマウントされる。オプションは少し長いが、とりあえず <code>default,allow_other</code> を付けておけば動作するが、公式のドキュメント <a href="https://github.com/trapexit/mergerfs#nfs-clients-returning-estale--stale-file-handle">BASIC SETUP</a> の &quot;You need <code>mmap</code>&quot; にならった。</p>
<p>NFS を通して公開したい場合に不都合無く動作させるためには、もう少しオプションを足す必要がある。<a href="https://github.com/trapexit/mergerfs#nfs-clients-returning-estale--stale-file-handle">NFS clients returning ESTALE / Stale file handle</a> のところに書いてあるよう、<code>noforget,use_ino,inodecalc=path-hash</code> のオプションを加える。以下のようになる。</p>
<pre><code>$ sudo mount -t fuse.mergerfs -o defaults,allow_other,use_ino,cache.files=partial,dropcacheonclose=true,category.create=mfs,nonempty,noforget,inodecalc=path-hash /mnt/a:/mnt:b /mnt/merged
</code></pre>
<p>起動時に自動でマウントするためには</p>
<pre><code>/mnt/a:/mnt/b       /mnt/merged      fuse.mergerfs   defaults,allow_other,use_ino,cache.files=partial,dropcacheonclose=true,category.create=mfs,nonempty,noforget,inodecalc=path-hash      0       0
</code></pre>
<p>のような行を <code>/etc/fstab</code> に加えれば良い。</p>
<h1 id>まとめ</h1>
<p>本記事では、Chia の plot を保存するために、複数台のストレージを、MergerFS を使って束ねると管理しやすいことを説明し、その設定方法について述べた。現在のところ上手く動いているのでChia の ファーミングを行っている人は検討すると良いかもしれない。Chia のせいでストレージが手に入りずらくなっているのはマジでクソ。</p>
<hr class="footnotes-sep">
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p>Bitcoin とか Ethereum のような PoW ブロックチェーンにおけるマイニングのようなこと。Chia ではマイニングではなくファーミングと呼ぶ。 <a href="#fnref1" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn2" class="footnote-item"><p>これは、 rsync がまず一時ファイルを作成してファイルをコピーし、コピーが完了した後にファイルをリネームする挙動にある。mhddfs でマウントしたディレクトリを NFS で公開すると、リネーム前後で inode 番号が変わってしまうことがあるようだ。rsync はリネーム時に inode 番号が変わらないことを期待しているためエラーが起こってしまう。 <a href="#fnref2" class="footnote-backref">↩︎</a></p>
</li>
</ol>
</section>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[破損した動画ファイルを高速に検出する]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>以前の記事で書いたように、自宅のサーバー上で録画環境を構築している。このサーバーでは、番組の録画が完了すると、録画した TS ファイルを h.264 の MP4 ファイルにエンコードして別のディレクトリに保存するようなスクリプトを動かしている。元の TS ファイルもそのまま保持していたのだが、最近ストレージ容量が厳しくなってきたので、エンコード済みの TS ファイルを削除しようと思い立った。</p>
<p>問題は、エンコードが正しく終了せず破損した MP4 ファイルがいくつか存在することだ。これらのファイルについては元の TS ファイルを残しておきたい。そこで、大量のファイルの中から破損したファイルを高速に検出する方法を調べた。</p>
<p>調べた結果、以下のようにするのが良さそうだ。(ffprobe コマンドは ffmpeg をインストールするとインストールされる）</p>
<pre><code>$ ffprobe -v error -f lavfi movie=&quot;/path/to/file.mp4&quot; 2&gt;&amp;1</code></pre>]]></description><link>https://blog.misosi.ru/2021/05/04/check-movie-file-corruption/</link><guid isPermaLink="false">609159a06722fa7cae9c94fd</guid><category><![CDATA[tech]]></category><category><![CDATA[recording]]></category><dc:creator><![CDATA[mecab]]></dc:creator><pubDate>Tue, 04 May 2021 16:14:02 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>以前の記事で書いたように、自宅のサーバー上で録画環境を構築している。このサーバーでは、番組の録画が完了すると、録画した TS ファイルを h.264 の MP4 ファイルにエンコードして別のディレクトリに保存するようなスクリプトを動かしている。元の TS ファイルもそのまま保持していたのだが、最近ストレージ容量が厳しくなってきたので、エンコード済みの TS ファイルを削除しようと思い立った。</p>
<p>問題は、エンコードが正しく終了せず破損した MP4 ファイルがいくつか存在することだ。これらのファイルについては元の TS ファイルを残しておきたい。そこで、大量のファイルの中から破損したファイルを高速に検出する方法を調べた。</p>
<p>調べた結果、以下のようにするのが良さそうだ。(ffprobe コマンドは ffmpeg をインストールするとインストールされる）</p>
<pre><code>$ ffprobe -v error -f lavfi movie=&quot;/path/to/file.mp4&quot; 2&gt;&amp;1 | grep lavfi;
</code></pre>
<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<p><ins class="adsbygoogle" style="display:block; text-align:center;" data-ad-layout="in-article" data-ad-format="fluid" data-ad-client="ca-pub-5314531653763426" data-ad-slot="9673121688"></ins></p>
<script>
     (adsbygoogle = window.adsbygoogle || []).push({});
</script>
<p>まずパイプ前段の <code>ffprobe</code> がエラーを検出し、検出したエラーを標準エラー出力に書き出してくれる。例えばエラーがあると（<code>ffprove</code> 自体の出力は）以下のようになる。</p>
<pre><code>[mov,mp4,m4a,3gp,3g2,mj2 @ 0x5654a3bb3400] moov atom not found
[Parsed_movie_0 @ 0x5654a3bb2e80] Failed to avformat_open_input '/path/to/file.mp4'
[lavfi @ 0x5654a3bb1000] Error initializing filter 'movie' with args '/path/to/file.mp4'
movie=/path/to/file.mp4: Invalid data found when processing input
</code></pre>
<p>筆者が持っているファイル群では、正常にエンコードされたファイルでもなぜか音声にエラーが検出され</p>
<pre><code>[aac @ 0x55a600a76380] Reserved bit set.
[aac @ 0x55a600a76380] Number of bands (4) exceeds limit (2).
</code></pre>
<p>のように表示された。このような出力は正常なものと見なしたかったため、標準出力にリダイレクトした上で lavfi からのエラーを grep で拾うようにしている。grep の出力や終了コードを確認することで、与えたファイルが壊れているかどうかを判断できる。</p>
<p>上記をもとに、大量のファイルを処理する例としては以下のようになる。</p>
<pre><code>$ ls /path/to/movie_dir |\
  xargs -I@ bash -c '
    fn=&quot;@&quot;;
    if (ffprobe -v error -f lavfi movie=&quot;$fn&quot; 2&gt;&amp;1 | grep lavfi) &gt;/dev/null; then
      echo @ is corrupted;
    else
      echo @ is safe;
    fi
  '
</code></pre>
<p>上記のスクリプトは、指定されたディレクトリ内のファイルを全て調べ、壊れていた場合は</p>
<pre><code>{{ filename }} is corrupt
</code></pre>
<p>壊れていない場合は</p>
<pre><code>{{ filename }} is safe
</code></pre>
<p>と表示する。</p>
<p>上記の検査方法により、無事、正常にエンコードできたファイルの元 TS ファイルだけを削除することができた。これで壊れていると判断されたファイルは実際に VLC で再生できないことを確認できた。一方で正常とされたファイルについて（数が多いので）全てを確認できていないので、実は壊れているものが含まれている可能性もあるが、そこは...そんなことがなかったことを祈りたい...。</p>
<p>調べる方法としては、他にも ffmpeg を使って</p>
<pre><code>$ ffmpeg -v error -i &quot;/path/to/file.mp4&quot; -f null -;
</code></pre>
<p>とする方法もあるようだが、こちらは全フレームを見て検査するようで結構時間がかかる。ただ、その分より正確に壊れたファイルを検出できそうだ。</p>
<h1 id>参考にしたサイト</h1>
<p><a href="https://stackoverflow.com/a/58825153">How can I tell if a video file is corrupted? FFmpeg? - Stack Overflow</a></p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[ZFS ZVOL の拡張と、その中の ext4 パーティションの拡張]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>ZFS で作成した ZVOL のサイズが足りなくなり拡張するという作業を数年に一度行っているが、毎回やり方をググっているのでメモを兼ねて書く。ZVOL を拡張しても、内部のパーティション（ext4 を想定）も拡張しないと、実際に使用可能な容量は増えないのでこちらも拡張する。</p>
<p>なお、ここでは内部にパーティションが1つしか無いことを想定している。複数ある場合、末尾のパーティションは簡単に拡張できる (partedで指定するパーティション番号を変更するだけ）が、それ以外は大変なはず.....。</p>
<p>（作業前にスナップショットを取っておくと安心）</p>
<pre><code>$ sudo zfs snapshot pool0/vol0@before_expand
</code></pre>
<p><strong>作業前にアンマウントすること！</strong></p>
<pre><code>$ sudo umount /mnt/path/of/where/volume/is/mounted
</code></pre>
<p>まず ZVOL を拡張する。</p>
<pre><code>$ sudo zfs set volsize=1200G pool0/vol0
$ sudo zfs get</code></pre>]]></description><link>https://blog.misosi.ru/2021/04/27/expand-zvol-and-containing-ext4-partition/</link><guid isPermaLink="false">60883ce76722fa7cae9c9462</guid><category><![CDATA[tech]]></category><category><![CDATA[zfs]]></category><category><![CDATA[ext4]]></category><category><![CDATA[nas]]></category><dc:creator><![CDATA[mecab]]></dc:creator><pubDate>Tue, 27 Apr 2021 17:00:52 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>ZFS で作成した ZVOL のサイズが足りなくなり拡張するという作業を数年に一度行っているが、毎回やり方をググっているのでメモを兼ねて書く。ZVOL を拡張しても、内部のパーティション（ext4 を想定）も拡張しないと、実際に使用可能な容量は増えないのでこちらも拡張する。</p>
<p>なお、ここでは内部にパーティションが1つしか無いことを想定している。複数ある場合、末尾のパーティションは簡単に拡張できる (partedで指定するパーティション番号を変更するだけ）が、それ以外は大変なはず.....。</p>
<p>（作業前にスナップショットを取っておくと安心）</p>
<pre><code>$ sudo zfs snapshot pool0/vol0@before_expand
</code></pre>
<p><strong>作業前にアンマウントすること！</strong></p>
<pre><code>$ sudo umount /mnt/path/of/where/volume/is/mounted
</code></pre>
<p>まず ZVOL を拡張する。</p>
<pre><code>$ sudo zfs set volsize=1200G pool0/vol0
$ sudo zfs get volsize pool0/vol0 # 増えたことを確認する
NAME           PROPERTY  VALUE    SOURCE
pool0/vm/vol0  volsize   1.17T    local
</code></pre>
<p>ディスクサイズが増えたことで GPT テーブル情報が実際のディスクと一致しなくなるのでこれを修正し、さらにパーティションをリサイズする。</p>
<pre><code>$ sudo parted /dev/zvol/pool0/vol0
Warning: Not all of the space available to /dev/sda appears to be used, you can fix the GPT to use all of the space (an extra *** blocks) or continue with the current setting?
Fix/Ignore? Fix
</code></pre>
<p>parted でボリュームを開いた時にエラーが検出され、 Fix するかとのメッセージが出るので Fix と打つ。そのまま続けて <code>p</code> でパーティションを確認する。</p>
<pre><code>(parted) p
Model: Unknown (unknown)
Disk /dev/zd192: 1288GB
Sector size (logical/physical): 512B/8192B
Partition Table: gpt
Disk Flags:

Number  Start   End    Size   File system  Name  Flags
 1      1049kB  800GB  800GB  ext4
</code></pre>
<p><code>resizepart</code> で1番目のパーティションをディスクの100%の位置まで拡張する。</p>
<pre><code>(parted) resizepart 1 100%
(parted) p
Model: Unknown (unknown)
Disk /dev/zd192: 1288GB
Sector size (logical/physical): 512B/8192B
Partition Table: gpt
Disk Flags:

Number  Start   End     Size    File system  Name  Flags
 1      1049kB  1288GB  1288GB  ext4
</code></pre>
<p><code>parted</code> を終了し、<code>e2fsck</code> でパーティションのエラーを確認する（<code>resize2fs</code> のために必要）</p>
<pre><code>$ sudo e2fsck -f /dev/zvol/pool0/vol0-part1
... （終わるまでしばらく待つ）
</code></pre>
<p>最後に <code>resize2fs</code> で増えた分の領域を認識させる</p>
<pre><code>$ sudo resize2fs /dev/zvol/pool0/vol0-part1
</code></pre>
<p>終わり。一応最後にまた <code>e2fsck</code> した方が良いかもしれない。</p>
<p><code>parted</code> の代わりに <code>fdisk</code> でリサイズする方法もあるが、（たぶん）GPT テーブルの修正はできないし、パーティションを一度消す→開始位置が同じで終了位置が違うパーティションを再作成というオペレーションになるためちょっと怖いので <code>parted</code> を使った方が良いと思う。</p>
<h1 id>参考にしたサイト</h1>
<ul>
<li><a href="https://www.truenas.com/community/threads/resizing-zvol.47574/">Resizing Zvol | TrueNAS Community</a></li>
<li><a href="https://www.tsukiyono.blue/blog/2020/01/mstdn_maintenance_disk.html">mastodonサーバのSSDを大容量の物に変更しました。（Linuxの大容量SSDへの移行） | tsukiyono.blue</a></li>
<li><a href="http://takafumi-s.hatenablog.com/entry/2017/04/16/151108">【Linux】 partedでパーティションの拡張 - takafumi blog</a></li>
</ul>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Flow JavaScript SDK で Script を実行してメインネットからデータを取得する。]]></title><description><![CDATA[この記事では Flow メインネットから Flow JavaScript SDKを使ってデータを取得する方法について述べる。

データを取得する方法にも、ブロックやトランザクションを直接指定して記録されたデータを読む方法や、コントラクトが発火させるイベントを取得する方法などいくつかがあるが、ここでは Script を実行してデータを取得する。]]></description><link>https://blog.misosi.ru/2021/04/10/flow-javascript-sdk-run-script-on-mainnet/</link><guid isPermaLink="false">606f41ea750d8c061ae4dd77</guid><category><![CDATA[development]]></category><category><![CDATA[flow]]></category><category><![CDATA[blockchain]]></category><category><![CDATA[NBA Top Shot]]></category><dc:creator><![CDATA[mecab]]></dc:creator><pubDate>Sat, 10 Apr 2021 08:11:43 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>最近は猫も杓子も Non Fungible Token (NFT) の話をしていて、道ばたの猫もﾆｬｰﾝﾌｧﾝｼﾞﾌﾞﾙﾄｰｸﾝと鳴いていた。NFT ブームの火付け役は恐らく <a href="https://nbatopshot.com/">NBA Top Shot</a> だろう。</p>
<p>NBA Top Shot は <a href="https://www.onflow.org/">Flow ブロックチェーン</a> 上にデプロイされたコントラクトによって実現されている。この記事では Flow メインネットから <a href="https://docs.onflow.org/flow-js-sdk">Flow JavaScript SDK</a> を使ってデータを取得する方法について述べる。</p>
<p>データを取得する方法にも、ブロックやトランザクションを直接指定して記録されたデータを読む方法や、コントラクトが発火させるイベントを取得する方法などいくつかがあるが、ここでは Script を実行してデータを取得する。Script とは、<a href="https://docs.onflow.org/cadence">Cadence 言語</a>で書かれたコードのうち、ブロックチェーンの状態を変化させないものを指す。これを使うと、例えば コントラクトが公開する関数のうち、単に値を返却するようなものを実行し、その結果を取得できる <sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup>。ガス代もかからない。</p>
<p>Cadence の詳細については公式の <a href="https://docs.onflow.org/cadence">Cadence チュートリアル</a>に詳しいが、実際にメインネット上でどうやってスクリプトを実行するかが書かれた記事が少なく、一方で公式の<a href="https://docs.onflow.org/flow-js-sdk/flow-app-quickstart">Flow App Quickstart</a> では Web アプリを1つチュートリアルとして作るということで大きすぎるため、本記事で Script を動かすという点に絞って説明する。</p>
<p><code>@onflow/fcl</code> と、 <code>@onflow/types</code> の2つのパッケージが必要なのでインストールしておく。</p>
<pre><code>$ npm install --save @onflow/fcl @onflow/types
</code></pre>
<p>まずは単純な例として、足し算を行う Script を実行する例を示す。</p>
<pre><code class="language-javascript">const fcl = require('@onflow/fcl');

(async () =&gt; {
  fcl.config()
      .put(&quot;accessNode.api&quot;, 'https://access-mainnet-beta.onflow.org')

  const resp = await fcl.send([
    fcl.script(`
      pub fun main(): Int {
        return 1 + 2;
      }
    `)
  ]);
  
  const result = await fcl.decode(res);
  console.log(result)
})();
</code></pre>
<p>上記のコードを実行すると、</p>
<pre><code>3
</code></pre>
<p>と表示されるはずだ。</p>
<p>見て分かるように、<code>fcl.script()</code> 内に実行したい Script を記述し、<code>fcl.send()</code> に配列の要素として渡せば良い。返り値は <code>fcl.decode()</code> でデコードする必要がある。これらの関数の使い方の例は、実は <a href="https://docs.onflow.org/flow-js-sdk/packages/types">@onflow/types の使い方のページに一覧がある</a>。</p>
<p><strong>重要なのは、<code>fcl.config()</code> 以下を通して設定する API のエンドポイントだ。</strong> 公式の <a href="https://docs.onflow.org/flow-js-sdk/flow-app-quickstart">Flow App Quickstart</a> にはテストネットのための設定は書いてあるが、メインネットの設定は書かれていない。<strong>ググると<a href="https://medium.com/flow-japan/how-to-get-nba-top-shot-events-8e0a4b99f3a0">Flow Japan Community の記事</a>が出てきて、<code>https://access-mainnet-beta.onflow.org</code> を指定すれば良いことが分かる。</strong> <sup class="footnote-ref"><a href="#fn2" id="fnref2">[2]</a></sup></p>
<p><code>main()</code> に引数を渡したい場合は、<code>fcl.send()</code> に渡す配列の2つめに、<code>fcl.args()</code> で生成した引数オブジェクトを渡せば良い。各引数は <code>fcl.arg(1, types.Int)</code> のように型を指定してラップする必要がある。以下のような例となる。</p>
<pre><code class="language-javascript">const fcl = require('@onflow/fcl');

(async () =&gt; {
  fcl.config()
      .put(&quot;accessNode.api&quot;, 'https://access-mainnet-beta.onflow.org');

  const resp = await fcl.send([
    fcl.script(`
      import TopShot from 0x0b2a3299cc857e29

      pub fun main(a: Int, b: Int): Int {
        return a + b;
      }
    `),
    fcl.args([
      fcl.arg(1, types.Int),
      fcl.arg(2, types.Int)
    ])
  ]);
  
  const result = await fcl.decode(resp);
  console.log(result);
})();
</code></pre>
<p>そろそろ、コントラクトと対話して実際にブロックチェーン上のデータを参照してみたい。今回は Top Shot のコントラクトに定義された <code>getPlayMetaData(playID: UInt32)</code> を呼び、指定された Play <sup class="footnote-ref"><a href="#fn3" id="fnref3">[3]</a></sup> が持つメタデータを取得してみたい。</p>
<pre><code class="language-javascript">const fcl = require('@onflow/fcl');

(async () =&gt; {
  fcl.config()
  .put(&quot;accessNode.api&quot;, 'https://access-mainnet-beta.onflow.org');

  const resp = await fcl.send([
    fcl.script(`
      import TopShot from 0x0b2a3299cc857e29

      pub fun main(): {String: String}? {
        let metadata = TopShot.getPlayMetaData(playID: 42);
        return metadata;
      }
    `)
  ]);
  
  const result = await fcl.decode(resp);
  console.log(result);
})();
</code></pre>
<p>上記では、<code>playID = 42</code> である Play のメタデータを取得している。結果は以下のようになった。</p>
<pre><code>{
  FullName: 'Lonnie Walker',
  FirstName: 'Lonnie',
  LastName: 'Walker',
  Birthdate: '1998-12-14',
  Birthplace: 'Reading, PA, USA',
  JerseyNumber: '1',
  DraftTeam: 'San Antonio Spurs',
  DraftYear: '2018',
  DraftSelection: '18',
  DraftRound: '1',
  TeamAtMomentNBAID: '1610612759',
  TeamAtMoment: 'San Antonio Spurs',
  PrimaryPosition: 'SG',
  PlayerPosition: 'GF',
  Height: '77',
  Weight: '204',
  TotalYearsExperience: '1',
  NbaSeason: '2019-20',
  DateOfMoment: '2019-12-04 01:30:00 +0000 UTC',
  PlayCategory: '3 Pointer',
  PlayType: '3 Pointer',
  HomeTeamName: 'San Antonio Spurs',
  AwayTeamName: 'Houston Rockets',
  HomeTeamScore: '135',
  AwayTeamScore: '133'
}
</code></pre>
<p>結果から、Top Shot では一つ一つの Play をどのようにブロックチェーン上で表現しているかが分かる。画像や動画のハッシュはおろか、URL や パス、ファイル名すら書き込まれていない点は気にしておいても良いかもしれない。</p>
<p>なお、</p>
<pre><code>import TopShot from 0x0b2a3299cc857e29
</code></pre>
<p>この行について、どうやって TopShot のコントラクトがデプロイされたアドレスをするかという点だが、Flowscan で適当にいくつかトランザクションを漁ると Top Shot 関連のトランザクションを見つけることができ、それらのトランザクションの Event 欄を見ると、Event を発行したコントラクトを知ることができた。コントラクトのページに飛べば<a href="https://flowscan.org/contract/A.0b2a3299cc857e29.TopShot">コントラクト自体のソース</a>を見ることもできる。なお、Top Shot の全てのコントラクトは <a href="https://github.com/dapperlabs/nba-smart-contracts">GitHub 上で公開されている</a> <sup class="footnote-ref"><a href="#fn4" id="fnref4">[4]</a></sup>。</p>
<hr>
<p>本記事では、Flow JavaScript SDK で Script を実行し、メインネットから情報を取得する方法について書いた。Flow には Go SDK と JavaScript SDK があるが、Go SDK については公式のドキュメントも充実しておりその他の情報も多く見つかるが、JavaScript SDK については情報が少なく少し苦労した。</p>
<p><code>@onflow/fcl</code> はブラウザでも動き、これを使って Flow を使った Web アプリも作れるようだ（メインネットに対してトランザクションを投げるためには Dapper Labs からアクセス権をもらわないといけないようだが）。本記事の情報が参考になると嬉しい。</p>
<hr class="footnotes-sep">
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p>Ethereum でいうところの、Solidity で view としてマークされた関数を呼び出すようなもの。ただし、Cadence ではコントラクト作成時に view のような指示をすることはなく、Script の実行時にブロックチェーンの状態が変わらなければ何でも Script として実行できるようだ。 <a href="#fnref1" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn2" class="footnote-item"><p>Blocto Wallet がホストする <code>https://flow-access-mainnet.portto.io</code> もあるようだが、僕の環境ではエラーになった。内部的に Permision Denied のエラーが出ているようだったので、承認された人しか使えなくなったのかもしれない。 <a href="#fnref2" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn3" class="footnote-item"><p>基本的には Top Shot で公開されているそれぞれのモーメントの、シリアルナンバー非依存の情報と思ってもらえば良い。ただし、モーメントは、 Play に対してユニークではなく、Set (Base Set とか Cool Cats のような発売単位） と Play のペアに対してユニークなものとして識別されることに注意。同じ Play が複数の Set に含まれることがあり、その場合は同じモーメントでも異なる商品となる。 <a href="#fnref3" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn4" class="footnote-item"><p>デプロイされたものと同一であることは保証されないので注意。 <a href="#fnref4" class="footnote-backref">↩︎</a></p>
</li>
</ol>
</section>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[(Among Us) 「宗教法人エマージェンシークールタイムをキルクールタイムより長くしろの会」を設立します。]]></title><description><![CDATA[Among Us において、エマージェンシークールタイムは、キルクールタイムより長くした方が良い。これは、クルーメイトらがローラーを選択するリスクを引き上げ、ローラーを行う場合でもローラーの順序について熟慮するインセンティブを与える。この設定は、結果としてゲームの持続的な面白さに貢献する。]]></description><link>https://blog.misosi.ru/2021/01/25/among-us-emergency-cooltime-and-kill-cooltime/</link><guid isPermaLink="false">600e68d4750d8c061ae4da80</guid><category><![CDATA[among us]]></category><category><![CDATA[game]]></category><dc:creator><![CDATA[mecab]]></dc:creator><pubDate>Mon, 25 Jan 2021 10:19:02 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h1 id>読む前に</h1>
<p>この記事は、Among Us というゲームに関する記事であり、読者は本ゲーム及び人狼ゲームとされるゲーム類に関する基本的な知識があることを想定して書かれている。そのため、用語に関する詳細な説明はしない。</p>
<h1 id>主張</h1>
<p>Among Us において、エマージェンシークールタイムは、キルクールタイムより長くした方が良い。これは、クルーメイトらがローラーを選択するリスクを引き上げ、ローラーを行う場合でもローラーの順序について熟慮するインセンティブを与える。この設定は、結果としてゲームの持続的な面白さに貢献する。</p>
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">emerg CD &gt; kill CD だと、ローラーで先に白が吊られたときに、サボタージュとか駆使して対抗の黒が最後に必死の1キルをできるということです。<a href="https://t.co/HjQtEklB0Z">https://t.co/HjQtEklB0Z</a></p>&mdash; 謹慎中 (@mecab) <a href="https://twitter.com/mecab/status/1353576922555420672?ref_src=twsrc%5Etfw">January 25, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> 
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">オリジナルの人狼はローラー別に良い（仕方ない）と思うんですけど、among us は among us なのでローラーし辛いほうが良いと思う。ローラー前にキャラコン次第でキル取るチャンスが与えると、アクションゲーム要素が光ると思ってる（現状ping高いのでアクションゲームとしてクソという話はある）</p>&mdash; 謹慎中 (@mecab) <a href="https://twitter.com/mecab/status/1353578145983524865?ref_src=twsrc%5Etfw">January 25, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> 
<h1 id>提案する設定によって期待されること</h1>
<p>Among Usの仕様上、ローラーを行うためには1人目を追放した後に、2人目を追放するために、誰かが非常ボタンを押して会議を行う必要がある。この時、エマージェンシークールタイムがキルクールタイムより長ければ、インポスターはエマージェンシーボタンを押す前にサボタージュを駆使しながら、その間にキルを行えるチャンスも出てくる。</p>
<p>これは特にローラー対象が、実際に1人クルーメイト、1人インポスターだったときに大きく影響する。例えば、不幸にも先に追放されたのがクルーメイトだった場合、次に追放される予定のインポスターは身バレ覚悟で積極的にキルを狙うことができる。</p>
<p>以上のことから、提案する設定はローラーを実行することについてリスクを与え、またローラーを行う場合でも、追放順番に関する議論を慎重に行うようにさせる。</p>
<h1 id>インポスターにおけるローラーについて</h1>
<p>Among Usにおいて、ローラーが発生しやすいのは、キルする瞬間を他の1人のみに目撃され、お互い「あいつがヤった」と押しつけあっている状況においてだろう。</p>
<p>この状況でのローラーはかなり強力で、確実に1人のインポスターを追放することができる。また、味方のインポスターとしても、1人のクルーメイトが「確実に見た」と言っている以上、ローラー提案に異を唱えづらい。</p>
<p>特に多人数のプレイではこの影響は大きい。例えば10人中インポスター2人構成のゲームで、開始直ぐにインポスターが殺害現場を見られてしまい上記のローラーになった場合、8人中インポスター1人構成のゲームとなってしまい、クルーメイトがとても優勢になってしまう。言い方を変えると、<strong>「10人中インポスター2人」のゲームは、序盤に殺害現場を見られるだけで、実質的に「8人中インポスター1人」と化すのだ。</strong></p>
<p>「見られるようにキルをするプレイヤーが悪い」という話はあるだろうし、それはもっともなのだが、その時点でクルーメイト勝利がほぼ確定となると、この状態が起こった時点でゲームがつまらなくなったと感じるプレイヤーも出てくるのではないかと思う。また、<strong>ゲームの起点として、リスクを取った行動をせざるを得ないインポスターに対して、最初の殺害を失敗した場合のハザードとしては大きすぎる</strong>気がする。人間誰しもミスはあるし、pingの問題もある <sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup>。</p>
<p>そこで、エマージェンシークールタイムを、キルクールタイムやサボタージュクールダウンよりも長くすることで、疑われたインポスターにローラー避けのチャンスを与えるのがいいのではないかと考える。</p>
<p>ローラーという戦術は、味方も犠牲にしながら確実に敵を吊ることができるということで、ある意味で思考停止しているといえる。これは実際にオリジナルの人狼ゲームのプレイヤーでも主張していたり、同様の理由でローラーが嫌いという人がいる<sup class="footnote-ref"><a href="#fn2" id="fnref2">[2]</a></sup>。個人的には、思考停止した戦術であるとはいえ、人狼ゲームにおいては仕方ない、あるいは必要悪といえる部分だと思う。なぜなら、自分の役職以外については、確実に信じられるものは少ないか、かなり限られているからだ。その中で、リスクをとりながら確実に得られる物を得る戦略が必要になるのは分かる。狼に加えて凶人が居ることを考えるとなおさらだ。また、人狼の場合は人外がまだミスリードを誘うローラーを提案したり、議論を反らせてローラーを回避する余地もあるように思う。</p>
<p>しかし、<strong>このゲームはあくまでAmong Us というゲームであって、人狼ゲーム</strong>ではない<sup class="footnote-ref"><a href="#fn3" id="fnref3">[3]</a></sup>。クルーメイトは、各々自由に動き回り他の人の位置や、細かい動きを伺う機会もある。その点から、戦術としてローラを選ぶにしても、どちらを先に追放するかという議論はより慎重なものとなった方が良いように思う。提案する設定を行っても、ローラーで追放する順番を間違えなければ大きな問題とはならないのだ。また、<strong>サボタージュを繰り出すタイミングやどのサボタージュを行うかといった駆け引きや、サボタージュにどのように対応し、疑わしいクルーからどう距離を取るかといったキャラコン <sup class="footnote-ref"><a href="#fn4" id="fnref4">[4]</a></sup>。これが Among Us のアクションゲームとしての面白さであり、プレイの幅を広げていると思う。</strong> インポスターにより、誰かが2度目のボタンを押すことを妨害できるようにすることは、より Among Us の面白さを引き出し、長期的な楽しさに貢献すると私は信じている。</p>
<p>ちょうど、非常ボタンは極力使うなと主張する<a href="http://haramiho1214.livedoor.blog/archives/27164849.html">記事</a>を見つけた。</p>
<figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="http://haramiho1214.livedoor.blog/archives/27164849.html"><div class="kg-bookmark-content"><div class="kg-bookmark-title">【Among us】エマージェンシー押すな押すな押すなあああああああ : ハラミホホミラハ</div><div class="kg-bookmark-description">エマージェンシーは押すべき時に押すんだ。　それ以外は押さないほうが面白いんだ。　エマージェンシー押しまくるゲームは長くなるしつまらない。</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://livedoor.blogimg.jp/haramiho1214/imgs/c/3/c3d44db3.png"><span class="kg-bookmark-publisher">ハラミホホミラハ</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://livedoor.blogimg.jp/haramiho1214/imgs/a/6/a6a33f2b-s.png"></div></a></figure>
<p>理詰めで推理するのが好きな人もいる（私はその側）し、全員で一部屋ずつ回ろうという主張に対しては、サボタージュで妨害できるから全てに同意するわけではないのだが、<strong>「キルクールタイムまでの時間稼ぎに使われがち」</strong> <strong>「ゲームの起点となるインポスターには優しくしたほうがいい」</strong> という点は同意したい。この人はエマージェンシークールタイムがキルクールタイムより短い環境で遊ぶことが多いとのことだが、本記事で提案するようにクールタイムの長短を逆にするとバランスが取れると思うのだがどうだろうか。</p>
<h1 id>制限</h1>
<ul>
<li>上記はある程度慣れたプレイヤーがボイスチャットを行いながらプレイをする場合について検討している。野良でのテキストチャットでのプレイはまるで別ゲームなので参考にならないと思う。</li>
<li>この設定は、当然ながらインポスターを有利にする。が、ここでの主張は各クールタイムの設定によりローラーをしづらくした方が良いということで、インポスターはもっと有利な方が良いということではなく、インポスターの勝率がどうであるべきかということではないことに注意されたい。提案する設定でインポスターが有利になった分は、他のパラメータ（例: タスク数）を変更して補正できるのではないかと思う。</li>
<li><strong>ここまで熱く書いていながらだが、正直上記のような設定でのプレイはほとんどできていないため実際のところどうなのか分からない。感想教えてください。あと Among Us 誘ってください...。(´·ω·`)</strong></li>
</ul>
<hr class="footnotes-sep">
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p>このゲームは現在の環境では基本的にpingが高いので、そのためにラグが起こり、「誰も居なかったはずなのに実は人がいた！」ということは起こりえる。 <a href="#fnref1" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn2" class="footnote-item"><p><a href="https://wolfbbs.jp/%A5%ED%A1%BC%A5%E9%A1%BC%C8%BF%C2%D0%B0%D1%B0%F7%B2%F1.html">人狼BBS まとめサイト - ローラー反対委員会</a> <a href="#fnref2" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn3" class="footnote-item"><p>このため、オリジナル人狼ゲームの文脈でない限り、村人や狼。吊るという表現を使わず、あえてクルーメイト・インポスター・追放と書いた。 <a href="#fnref3" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn4" class="footnote-item"><p>高い ping のせいでアクションゲームもキャラコンもクソもない？はい、そうですね.....。 <a href="#fnref4" class="footnote-backref">↩︎</a></p>
</li>
</ol>
</section>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[2020年まとめ]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>この記事は実は2021年1月5日に書いている。が、2020年12月31日として公開する。だってそっちのほうがそれっぽいじゃん。</p>
<p>2020年は新型コロナウィルス感染症、通称コロナが流行った年だった。1月末頃は中国で新しいウィルスが流行っているんだってー。こわいねー。ぐらいのノリだったのが、3月末にはもう世界中で大騒ぎになっていて、怒濤の速さで物事がすすんだように思う。</p>
<p>トイレットペーパーが品切れになりつつあるらしいという話を Twitter で見て、そっかーと思っていたらすでに自分の周りでも品切れになっていて買えなかったり <sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup>、わずか数日で株価が急落して含み損がすごいことになったと思ったら、その後年末に向けて値を戻すどころか、コロナ以前の水準まで上がってびっくりしたりした<sup class="footnote-ref"><a href="#fn2" id="fnref2">[2]</a></sup>。あと、原油の先物価格がマイナスになったのは面白かった。記念スクショを撮った。しかし、1年間コロナが収束する気配はなく、実体経済もボロボロになっているはずなのに、金融緩和のせいか株価だけが上がり続けるのは健全でないような気がして怖い。経済ガチ勢ではないので本当に健全でないのかは分からないのだが、直感的に。</p>
<p>労働環境でも大きな変化があった。基本的に仕事は在宅勤務が推奨（時期によっては強制）されるようになった。元々 VPN 環境が整備されていて Zoom も導入されているにもかかわらず、在宅勤務は特段の事情がないと認められなかった<sup class="footnote-ref"><a href="#fn3" id="fnref3">[3]</a></sup>会社だったが、ほとんどの人が在宅で仕事をするようになった。僕は朝が苦手な上に、通勤が1時間半ほどかかるようなところに住んでいるので、これはとてもありがたかった。在宅勤務、基本的には良いと思うけど（特にコード書くだけの日とか）、企画を出すような段階だとちょっとつらそうな気もする。こればっかりは対面でワイワイやったほうがやりやすい気がする。</p>]]></description><link>https://blog.misosi.ru/2020/12/30/summary-2020/</link><guid isPermaLink="false">5ff40655750d8c061ae4d814</guid><category><![CDATA[essay]]></category><dc:creator><![CDATA[mecab]]></dc:creator><pubDate>Wed, 30 Dec 2020 15:00:00 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>この記事は実は2021年1月5日に書いている。が、2020年12月31日として公開する。だってそっちのほうがそれっぽいじゃん。</p>
<p>2020年は新型コロナウィルス感染症、通称コロナが流行った年だった。1月末頃は中国で新しいウィルスが流行っているんだってー。こわいねー。ぐらいのノリだったのが、3月末にはもう世界中で大騒ぎになっていて、怒濤の速さで物事がすすんだように思う。</p>
<p>トイレットペーパーが品切れになりつつあるらしいという話を Twitter で見て、そっかーと思っていたらすでに自分の周りでも品切れになっていて買えなかったり <sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup>、わずか数日で株価が急落して含み損がすごいことになったと思ったら、その後年末に向けて値を戻すどころか、コロナ以前の水準まで上がってびっくりしたりした<sup class="footnote-ref"><a href="#fn2" id="fnref2">[2]</a></sup>。あと、原油の先物価格がマイナスになったのは面白かった。記念スクショを撮った。しかし、1年間コロナが収束する気配はなく、実体経済もボロボロになっているはずなのに、金融緩和のせいか株価だけが上がり続けるのは健全でないような気がして怖い。経済ガチ勢ではないので本当に健全でないのかは分からないのだが、直感的に。</p>
<p>労働環境でも大きな変化があった。基本的に仕事は在宅勤務が推奨（時期によっては強制）されるようになった。元々 VPN 環境が整備されていて Zoom も導入されているにもかかわらず、在宅勤務は特段の事情がないと認められなかった<sup class="footnote-ref"><a href="#fn3" id="fnref3">[3]</a></sup>会社だったが、ほとんどの人が在宅で仕事をするようになった。僕は朝が苦手な上に、通勤が1時間半ほどかかるようなところに住んでいるので、これはとてもありがたかった。在宅勤務、基本的には良いと思うけど（特にコード書くだけの日とか）、企画を出すような段階だとちょっとつらそうな気もする。こればっかりは対面でワイワイやったほうがやりやすい気がする。</p>
<p>オンラインの PC ゲームを遊んでいたし、配信もやっていたこともあり、マイクやカメラ、ヘッドホンの環境はもともと整っていたので、特に在宅勤務のために家の環境を整える必要は無くて都合がよかった。調子に乗って HDMI キャプチャを買って、ミラーレスカメラを繋いで高画質 Zoom をやったりとか、 V カツと OBS を組み合わせてアバターで Zoom とか遊んでみたりしていたが、最近は飽きて普通に Web カムで Zoom している。Logicool BRIO は高いけど良い Web カムです。</p>
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">俺もブームに乗って意識高い高い高画質Zoom環境整えたので月曜からの会議が楽しみだ <a href="https://t.co/aobXDhflr5">pic.twitter.com/aobXDhflr5</a></p>&mdash; 謹慎中 (@mecab) <a href="https://twitter.com/mecab/status/1261610771684843520?ref_src=twsrc%5Etfw">May 16, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> 
<figure>
<p><img src="https://blog.misosi.ru/content/images/2021/01/v-zoom.png" alt="VカツでフェイストラッキングをしたものをOBSでキャプチャしてZoomに流している図"></p>
<figcaption>VカツでフェイストラッキングをしたものをOBSでキャプチャしてZoomに流している図</figcaption>
</figure>
仕事といえば、新卒で入社してからというもの初めて部署異動をした。もちろん、組織変更とかに伴う、組織図上での異動は今までもときどきあって、とはいえ基本的には同じメンバーで働いているような感じだったが、今回は完全に異なる部署に異動した。これまで HCI 関係の研究開発を行うようなところにいたが、これからはブロックチェーン関係の開発をやることになる。開発拠点は北アイルランドにあり、日本では企画とか管理を行っている。海外赴任をする前提で異動したが、コロナの影響で無期限に延期している状況だ。一体いつ行けるのか...。
<p>異動した理由としては、お金の香りがすること（これは冗談）と、昔趣味でマイニングプールを運営したことがあって、その頃からブロックチェーンは面白いなあと感じていたことがある。また、以前に一度、研修という形で、北アイルランドの開発拠点で数ヶ月働かせてもらったことがあり、そのときに環境が気に入ったということもある。一体いつ行けるのか...。（2回目）</p>
<p>以前の部署では国際会議に投稿したり、社内外のイベントでデモを展示するようなことを時々やっていたが、そのような機会が無くなってしまうのは残念かもしれない。これまでは出した論文とか、会議やイベントに行ったときの写真とかを見直せばどういう仕事をしてきたかを振り返れたが、これからはやったことを意識して記録に残しておかないと忘れてしまうのでブログ書くなり、外に出せないことは個人的なメモに書くなり何か記録しておこうと思う。まぁ自由度は高い部署ではあるはずなので、ブロックチェーンをネタに研究とかできたらいいなぁ。</p>
<p>5月に部署移動してから、プライベートブロックチェーンを使ったとあるサービスの開発を手伝い、とりあえず社内向けに試験公開ができた。とりあえずはまずまずのパフォーマンスが出せたかなということで今後も頑張りたい。</p>
<p>2020年後半では家を買いたい気持ちになり、家を探していた。自分の周りでも家を買う人が出てくる歳になり、買うことを考え始めたのが2年ほど前だが、都内の物件の価格は上がり続ける一方で二の足を踏んでいた。コロナの影響でほとんどの金融商品の価格が落ちた後、不動産の価格も下がるのではないかと期待したのだが、夏頃にはREIT含め多くの指数が値を戻したのを見て、これはもう下がらないなと思った。さらに、コロナが落ち着いて海外赴任し、それから帰国してから家を買うとなると、既に手が出ないような価格になっているのではないかという恐怖感もあり、秋頃に本腰を入れて家を探し始めた。</p>
<p>人生で1度はタワーマンションでウェイウェイしてみたいなという気持ちがあったので、1年半ほど前から、ほぼ郊外みたいなところのタワマンに賃貸で入っていた。家賃も高いし半分ネタみたいな感じですぐに出ようと思っていたが、予想以上に住み心地が良かったためタワマンを買うことにした<sup class="footnote-ref"><a href="#fn4" id="fnref4">[4]</a></sup>。特に良いなと思ったところは、ディスポーザー、眺望、各階ゴミ捨て場、かっこいい共用部だ <sup class="footnote-ref"><a href="#fn5" id="fnref5">[5]</a></sup>。特にディスポーザー。料理をするときに三角コーナーの処理しなくていいのは快適だ。</p>
<p>そして、現在気になっている部分として、駅から遠いのと、都心から離れているため電車もちょっと不便ということがあった。住んだ当初はそのうち慣れるだろうと思ったが、通勤は案外つらかった<sup class="footnote-ref"><a href="#fn6" id="fnref6">[6]</a></sup>。そこで、これらの点を考慮して、もう少し都心に寄った（本当の都心はさすがに高すぎて買えない；；；）、駅近の新築物件を契約した。駅近なのは、賃貸に出したり、将来売却する際にも大きくプラスになるようだ。一時的に日本を離れたりする可能性があることも考えると、このあたりは大事だった。新築にはこだわっていなかったので、中古も見ていたのだが、緊急事態宣言が解除された頃から住宅の需要が高まり全体的に値上がりしたようで、この値段で買うなら新築でいいなという感じになったので、結果的に新築になった。</p>
<p>ちょっと無理をしたローンを組んだ自覚はあるが、極端な価格崩壊が起こらなければ、5年ほど住めば残債割れせず、最悪の場合でも売却してどうにかなるのではないかと考えている。極端な価格崩壊が起こったときは、買ったエリア、あるいは東京全体が大変なことになっていると思うので、そのときはそのときだ。運が悪かったと思うしかない。</p>
<p>新居の引き渡しを楽しみにしつつ、ローン返していくぞの気持ちを高めようと思う。</p>
<p>ところで、最後まで迷っていたが結果的に選ばなかったマンションがあって、それはシティタワー品川パークフロントという物件だ。これはなんと目の前が大井競馬場と平和島の競艇場だ。東向き高層階なら部屋から競馬と競艇が見れる。このような賭博施設は基本的にマイナス要素とされるようで、パンフレットの地図からもひたすら競馬場が隠されていたり、Twitter でもクソ物件 GO 扱いされていたが、競馬好きにはたまらないし、間取りも悪くないと思うので競馬で一発当てた人は買ってほしい。かなり迷っていたのでが、各階ゴミ捨て場がないという点が痛くて諦めた。</p>
<blockquote class="twitter-tweet" data-theme="light"><p lang="ja" dir="ltr">【シティータワー品川パークフロント】<br>ちゃんと内見してきたよ。たしかにここからの景色はギャンブラー御用達かもしれませぬ<a href="https://twitter.com/hashtag/%E3%82%AF%E3%82%BD%E7%89%A9%E4%BB%B6GO?src=hash&amp;ref_src=twsrc%5Etfw">#クソ物件GO</a> <a href="https://t.co/RQ83ZGtJ6s">pic.twitter.com/RQ83ZGtJ6s</a></p>&mdash; とっくさん@おふぃす屋さん (@tokusenjouhou20) <a href="https://twitter.com/tokusenjouhou20/status/1202938467191156740?ref_src=twsrc%5Etfw">December 6, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> 
<p>年末はビットコインが高値を更新してびっくりした。まさか2017年のバブルみたいな状況が再び到来するとは...。ブロックチェーン関連の部署に異動した一方で、個人的にはおいしいポジションをほとんど持っていなかったので悲しい。一発当てた人は寿司をおごってください。</p>
<p>2021年もがんばっていきましょう。</p>
<hr class="footnotes-sep">
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p>家のトイレットペーパーが切れる直前だったので本当にまずかった。その日、たまたま友達の家に遊びに行っており、そこで1ロールもらってこれたので事なきを得た。ありがとう友達よ。。。 <a href="#fnref1" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn2" class="footnote-item"><p>底で日経ダブルインバースを買ってしまい悲しいことになった。 <a href="#fnref2" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn3" class="footnote-item"><p>在宅勤務が技術的には環境が整っていたおかげで、他の会社に比べてスムーズに以降できたのではないだろうか。知らんけど。とはいえ、一気に通信量は増えるだろうし、社内インフラを運用している人は本当に大変だったのではないだろうか...。ありがとうございます...。 <a href="#fnref3" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn4" class="footnote-item"><p>低層のマンションもいくつか見たが、やっぱりタワーだなという結論に達した。 <a href="#fnref4" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn5" class="footnote-item"><p>眺望以外はどれも、タワーでなくても備えているマンションもあるはずだ。ただし、高額な管理費を住民の数で殴れる分、タワマンをはじめとする大規模マンションの方がこのような設備を導入されやすい。 <a href="#fnref5" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn6" class="footnote-item"><p>現居の前は会社の隣の駅から徒歩2分、会社まで全部歩いても15分のところに住んでたのでなおさら...。 <a href="#fnref6" class="footnote-backref">↩︎</a></p>
</li>
</ol>
</section>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[pandas で グループごとに ffill() と bfill() を両方適用したい]]></title><description><![CDATA[pandas で、列Aの欠損値を埋める際に、列Bグループ化した中での1つ前の列Aの値を使って埋めることはffill()でできるが、1つ前の値が存在しない場合に、1つ後の値を使って補完 (bfill()) したい場合はどうしたら良いか。その方法を示す。]]></description><link>https://blog.misosi.ru/2020/10/18/pandas-how-to-apply-ffill-and-bfill-for-each-group/</link><guid isPermaLink="false">5f8c7533750d8c061ae4d7a9</guid><category><![CDATA[python]]></category><category><![CDATA[pandas]]></category><dc:creator><![CDATA[mecab]]></dc:creator><pubDate>Sun, 18 Oct 2020 17:19:00 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p><ins>2020-10-19 13:16 修正。新しい列を作る必要は特にない。</ins></p>
<p>pandas を使うと、例えば</p>
<pre><code class="language-python">horses.loc[:, 'horse_weight'] = horses.groupby('horse_id')['horse_weight'].ffill()
</code></pre>
<p>とすることで、<code>horse_weight</code> の中で欠損した値を、<code>horse_id</code> でグループ化した中での1つ前の値を使って埋めることができるが、1つ前の値が存在しない場合に、1つ後の値を使って補完 (<code>bfill()</code>) したい場合はどうしたら良いか。</p>
<pre><code class="language-python"># これは正しくない
horses.loc[:, 'horse_weight'] = horses.groupby('horse_id')['horse_weight'].ffill().bfill()
</code></pre>
<p>これはいけない。なぜなら <code>ffill()</code> が返す型は <code>SeriesGroupBy</code> ではなく <code>Series</code> であり、グループ化が解除されているため、グループに関係なく 1 つ後の値を使ってしまう。</p>
<p><a href="https://stackoverflow.com/questions/44403916/pandas-why-does-bfill-ffill-act-differently-than-ffill-bfill-on-group">Stack Overflow</a> に回答があるが、<code>apply()</code> を使うのが正しい。</p>
<pre><code class="language-python">horses.loc[:, 'horse_weight'] = horses.groupby('horse_id')['horse_weight'].apply(lambda x: x.ffill().bfill())
</code></pre>
<p>ただ、実際やってみるとこれは結構遅かった。たぶん普通に <code>SeriesGroupBy.ffill()</code> やるときは何か良い感じの最適化がかかってる一方で、<code>apply()</code> の場合は律儀にグループ数分のループが走るからだと思う（未検証）。</p>
<p>ということで、愚直に</p>
<del>
<pre><code class="language-python">horses.loc[:, 'horse_weight_filled'] = horses.groupby('horse_id')['horse_weight'].ffill() # 別の列に ffill() した結果を入れておく
horses.loc[:, 'horse_weight_filled'] = horses.groupby('horse_id')['horse_weight_filled'].bfill()
</code></pre>
<p>として、新しい列に <code>ffill()</code> の結果を入れておき、その列に対して <code>bfill()</code> したほうが速い。その後、必要に応じて元の列を消して新しい列をリネームするなどすると良い。</p>
</del>
<p>よく考えたら別に新しい列を作る必要はなかった。</p>
<pre><code class="language-python">horses.loc[:, 'horse_weight'] = horses.groupby('horse_id')['horse_weight'].ffill()
horses.loc[:, 'horse_weight'] = horses.groupby('horse_id')['horse_weight'].bfill()
</code></pre>
<p>で良い。</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[CS381 を使って MicroATX に 48 TB 分の HDD を詰める]]></title><description><![CDATA[SilverStone SST-CS381B という PC ケースを買った。このケースは、MicroATX にもかかわらず、最大で 12 台と大量の HDD/SSD を積むことができる。ユニークなのはホットスワップベイで、8 台が 4 台ずつまとめられて 2 本の SAS (SFF-8643 Mini-SAS）で接続するようになっている。本記事では、このケースについてレビューする。]]></description><link>https://blog.misosi.ru/2020/08/11/cs381-review/</link><guid isPermaLink="false">5f2f9018750d8c061ae4d4a6</guid><category><![CDATA[tech]]></category><category><![CDATA[hdd]]></category><category><![CDATA[server]]></category><category><![CDATA[cs381]]></category><dc:creator><![CDATA[mecab]]></dc:creator><pubDate>Tue, 11 Aug 2020 10:34:52 GMT</pubDate><media:content url="https://blog.misosi.ru/content/images/2020/08/50213649877_9da9c9517e_b.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://blog.misosi.ru/content/images/2020/08/50213649877_9da9c9517e_b.jpg" alt="CS381 を使って MicroATX に 48 TB 分の HDD を詰める"><p>SilverStone SST-CS381B という PC ケースを買った（正確には、1 年前に買った後放置していた...）。このケースは、MicroATX にもかかわらず、ひたすらストレージを積めるということが特徴で、ホットスワップ可能な 3.5/2.5 インチベイ 8 つに加え、内部に 2.5 インチベイを 4 つ搭載しており、最大で 12 台の HDD/SSD を積むことができる。ユニークなのはホットスワップベイで、8 台が 4 台ずつまとめられて 2 本の SAS (SFF-8643 Mini-SAS）で接続するようになっている。本記事では、このケースについてレビューする。</p>
<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<p><ins class="adsbygoogle" style="display:block; text-align:center;" data-ad-layout="in-article" data-ad-format="fluid" data-ad-client="ca-pub-5314531653763426" data-ad-slot="9673121688"></ins></p>
<script>
     (adsbygoogle = window.adsbygoogle || []).push({});
</script>
<h1 id>経緯</h1>
<p>録画用にサーバーを構築していることもあって、以前の記事で書いたように大量のハードディスクを接続していた。</p>
<!--kg-card-end: markdown--><figure class="kg-card kg-bookmark-card kg-card-hascaption"><a class="kg-bookmark-container" href="https://blog.misosi.ru/2015/01/31/server-replace/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">サーバを新調した</div><div class="kg-bookmark-description">先の記事 [http://blog.misosi.ru/2015/01/31/blogzai-kai-sita]で述べたようにサーバを新調した。 構成は * CPU: Intel Core i3-4130T (Haswell) * マザボ: ASUS B85M-G * メモリ: 16GB * HDD: 13TB (3x4TB + 1TB) * ケース: Define Mini FA-CA-DEF-MINI-BL という感じだ。計8万強で収まった。メモリは以前のものを使いまわしたので実質7万程度。最近は案外安いものだ。基本的にはNASにしたかったのでHDDはたくさん積んだ。4x4…</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://blog.misosi.ru/favicon.ico" alt="CS381 を使って MicroATX に 48 TB 分の HDD を詰める"><span class="kg-bookmark-author">mecab</span><span class="kg-bookmark-publisher">mecablog</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://farm8.staticflickr.com/7324/16231069749_51ea3a796a_b.jpg" alt="CS381 を使って MicroATX に 48 TB 分の HDD を詰める"></div></a><figcaption>サーバーを新調したときの記事。3TB x 4 を積んだ。</figcaption></figure><figure class="kg-card kg-bookmark-card kg-card-hascaption"><a class="kg-bookmark-container" href="https://blog.misosi.ru/2017/09/30/bought-32tb-hdd/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">32TB分のHDDを買った</div><div class="kg-bookmark-description">自宅で運用しているサーバには既に12TB分のストレージ [https://blog.misosi.ru/2015/02/01/server-replace/] を積んでいるが、最近は容量が枯渇してきていた。そのため、HDDを増設することにした。せっかく増設するならば、しばらく容量に関して思い悩まないようにするために思い切ってたくさん積みたいと思って、4TBx8台ほど積むことにした。後に述べるとおり、HDDケースとeSATA拡張カードも一緒に買った。 機材の選定と購入
HDDケース
既にHDDベイは使い切っているのでHDDケースも買う必要があった。8台詰めるケースとなるとその時点で選択肢はか…</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://blog.misosi.ru/favicon.ico" alt="CS381 を使って MicroATX に 48 TB 分の HDD を詰める"><span class="kg-bookmark-author">mecab</span><span class="kg-bookmark-publisher">mecablog</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://c1.staticflickr.com/5/4382/36684658474_c7b31d273a_z.jpg" alt="CS381 を使って MicroATX に 48 TB 分の HDD を詰める"></div></a><figcaption>空き容量が足りなくなってきたので思い切って 4TB x 8 を足したときの記事。</figcaption></figure><!--kg-card-begin: markdown--><p>後者の 4TB x 8 は、USB接続の HDD ケースに入れて使っていたが、基本的には安定していたものの、まれに HDD が勝手に切断されることがあった。 <a href="https://btoplus.jp/archives/usb-hdd-connect-trouble/">USBの限界：HDDを多く接続できない | BtoPlus JP</a> という記事を見つけ、なるほど SAS ...と思っていた矢先にこのケースを見つけた次第だ。加えて既存の 4 台を 3.5 インチ HDD から 2.5 インチ HDD に移行してしまえば、全てのディスクをこのケース内に収納することができて嬉しいはずだ。</p>
<p>ということで、サーバーを CS381 に移してみた。</p>
<h1 id>材料</h1>
<p>新規に調達したものは以下の通り。運良く既存のサーバーも MicroATX だったので、他のパーツは流用した。</p>
<ul>
<li>ケース: SilverStone SST-CS381B</li>
<li>電源: SilverStone SST-SX650-G</li>
<li>電源ケーブル: SilverStone PSUケーブルセット SST-PP05-E</li>
<li>SAS ホストバスアダプタ (HBA): LSIロジック LSI00194</li>
<li>Mini SASケーブル: CableDeconn 内部 Mini SAS HD SFF-8643 to Mini SAS SFF-8087 ケーブル 1M x2</li>
<li>2.5インチHDD: SEAGATE ST4000LM024 (4TB) x4</li>
<li>SSD: SanDisk Ultra II 480GB</li>
</ul>
<p>CS381 は SFX 電源でなければ積めないので、電源は買い換える必要があった。ケース内はすっきりさせたかったので、ケーブルが着脱可能な物がいいな...と探したところ、ちょうど SilverStone の電源とケーブルが見つかった。多少特殊なケースではあるが、メーカーが同じなら変に干渉したり長さが足りないということもないだろう...という祈りも込めて合わせて買うことにした。</p>
<p>SAS でディスクを接続することになるので、SAS HBA を増設する必要がある。SAS を使うのは初めてなのでなんも分からん！と思いながら、信頼できそうな LSI ロジック製で、8ポート搭載していてお手軽な価格のものにした。Amazon にはもっと安いノーブランドの HBA も転がっていたが、地雷原を突き進むには歳をとり過ぎた。</p>
<p>上で書いたように、シャドウベイは 2.5 インチのみであるため、既存の 3.5 インチ HDD のうち 4 台は 2.5 インチ HDDに移さないといけない。3TB x 4 を移行し、せっかくなので容量も増やし 4TB にした。それにしても 2.5 インチ HDD はほとんど選択肢が無い上に高い。4GB だと、実質 	<br>
SEAGATE ST4000LM024 と WESTERN DIGITAL WD40NPZZ の二択だ。SEAGATE 製のほうが安かったのでケチって全部これにした。RAID で使う HDD を同じ物で揃えるのは怖いのだが、気休めに祈りながらそれぞれ別の店で買った。</p>
<p>ところで、ストレージ用のディスク 12 台については良いのだが、システム用にもう 1台 必要であるのを完全に忘れていた。SSD なら適当にその辺に貼り付けておけば良いだろうとの甘い考え（結果的に正解）で、以前ラクマで新品が安く売られていたのを見て、特に目的も無く買った SSD が転がっていたのでこれを使った。</p>
<h1 id>作業</h1>
<p>粛々と作業した。もっと作業中の写真を撮っておけばよかった...と今後悔している。基本的には以下の手順で組み立てる。</p>
<ol>
<li>上面のパネルとサイドパネルを取り外し、ホットスワップベイを取り外す。</li>
<li>側面から電源とマザーボードを入れ、拡張カードを取り付ける。</li>
<li>ホットスワップベイを戻し、ベイのバックプレートに配線をする。</li>
</ol>
<p>ここまでの状態が以下の写真だ（ホットスワップベイを1台戻している途中）。ベイを固定するための上部にある棒状の2本の金具は取り外せないため、両方のサイドパネルも外さないとマザーボードや電源を取り付けられないのは少しめんどくさい。さらに拡張カードを入れるのや、配線を行うのもこの金具が邪魔でやりにくいのがつらい。</p>
<figure>
<p><a href="https://www.flickr.com/photos/mecab/50212852598/in/album-72157649296605064/"><img src="https://live.staticflickr.com/65535/50212852598_84fce23317_b.jpg" alt="CS381 を使って MicroATX に 48 TB 分の HDD を詰める"></a></p>
<figcaption>作業途中。電源・マザーボードを入れ、ホットスワップベイ1台を戻したところ。</figcaption>
</figure>
<p>ベイのバックプレーンには 電源入力用の 6ピン端子と Mini SAS ポート (SFF-8643)、それに加えてケースファンへの電源出力がある。</p>
<figure>
<p><img src="https://blog.misosi.ru/content/images/2020/08/cs381-6.jpg" alt="CS381 を使って MicroATX に 48 TB 分の HDD を詰める"></p>
<figcaption>
<p>バックプレーン。上から順にケースファンへの電源出力、6 ピン電源入力、SFF-8643 ポートがある。（写真は <a href="https://www.silverstonetek.com/product.php?pid=861&amp;area=jp#lg=1&amp;slide=3">SilverStone のサイトより引用</a>）</p>
</figcaption>
</figure>
<ol start="4">
<li>2.5 インチシャドウベイにハードディスクを取り付ける。</li>
<li>上面パネル・側面パネルを戻す。</li>
</ol>
<p>公式の写真から、ホットスワップベイの上部に 2.5 インチ HDD　が 2個取りつけられることは分かっていたが、しかし残りの 2 つはどこに...。と少し不安だったが、以下のように本体側面に取りつけるこになる。HDD の片側しか固定できないので少し怖い。写真だと見づらいが、側面に取りつけた HDD の下段にもう一つ取りつけられている。マザーボードに背が高い拡張カードを取りつけた場合、下段には干渉して取りつけられないかもしれない。この 2 つのベイはおまけと考えた方が良いだろう。ちなみに、HDD の代わりにファンを追加することもできるらしい。</p>
<figure>
<p><a href="https://www.flickr.com/photos/mecab/50213649877/in/album-72157649296605064/"><img src="https://live.staticflickr.com/65535/50213649877_9da9c9517e_b.jpg" alt="CS381 を使って MicroATX に 48 TB 分の HDD を詰める"></a><br>
<figcaption>2.5インチ HDD 4台に加え、SSD を無理矢理取りつけたところ</figcaption></p>
</figure>
<p>写真を見て分かるように、SSD は無理矢理取りつけられた。上面の金具と、上面パネルの間の隙間がちょうど SSD が収まる高さだったのでありがたい。配線に苦労しそうだが、がんばればあと1、2台ぐらいは入れられそうだ。やらないけど。</p>
<ol start="6">
<li>ホットスワップベイに 3.5 インチ HDD を格納する。</li>
</ol>
<figure>
<p><a href="https://www.flickr.com/photos/mecab/50213380306/in/album-72157649296605064/"><img src="https://live.staticflickr.com/65535/50213380306_32b9a77de8_b.jpg" alt="CS381 を使って MicroATX に 48 TB 分の HDD を詰める"></a></p>
<figcaption>
HDD にトレイを取りつけたところ
</figcaption>
</figure>
<figure>
<p><a href="https://www.flickr.com/photos/mecab/50212875058/in/album-72157649296605064/"><img src="https://live.staticflickr.com/65535/50212875058_50ec8786e8_b.jpg" alt="CS381 を使って MicroATX に 48 TB 分の HDD を詰める"></a></p>
<figcaption>
ホットスワップベイに HDD を取りつけて起動したところ
</figcaption>
</figure>
<ol start="7">
<li>脚をつける。このケースは縦置きも横置きもできて、接地させたい面ところに付属の脚をつける...のだけど脚を無くしたｗ　仕方ないのでそのまま置く。</li>
</ol>
<p>ということで完成した。これ一台に 48TB が収まっていると思うとエモい気持ちになってくる。</p>
<p>はじめてで不安だった SAS 接続のディスクも普通に認識し、安定して動いているようで良かった。ホットスワップも試してみたが、問題なく動いている。</p>
<figure>
<p><a href="https://www.flickr.com/photos/mecab/50213474326/in/album-72157649296605064/"><img src="https://live.staticflickr.com/65535/50213474326_3d519fd597_b.jpg" alt="CS381 を使って MicroATX に 48 TB 分の HDD を詰める"></a></p>
<figcaption>とりあえず zpool status と zpool list 。1 台 SMART エラーが出ているのに気づいたので新しいディスクを購入して resilver している。</figcaption>
</figure>
<h1 id>感想</h1>
<p>普通の PC ケースとほとんど変わらないサイズに、12 台もディスクを格納できるのは良い。HDD を SAS 接続するような PC ケースは他に見たことが無く驚いたが、ケーブル 2 本で接続できるため内部の配線が少なくなるのはメリットかもしれない。また、この配線を活かして、ストレージを増設したい際に単に Mini SAS 接続 HDD エンクロージャーとして使うのも良いかもしれない。ブラケット穴から Mini SAS ケーブルを出し、外部 SAS ポートがついている HBA を PC 側に増設すれば使えそうだ。電源はピンをショートさせて常時電源オンにするような器具があるので、これを使って入れっぱなしにすればよい。</p>
<p>ちなみに SAS HBA を増設したくない場合は SAS ファンアウトケーブルというものがあって、これを使うと SAS ケーブルから SATA の端子をはやすことができるので、これを使うのも良いかもしれない。</p>
<p>これだけ多くのストレージを詰めるという点で他に比較する製品もほとんどなく、僕の需要にはぴったりだったのだが、ケース自体の作りについては少し不満もある。具体的には、</p>
<ol>
<li>これは本文中にも書いたが、2本の取り外せない棒状の金具のせいで作業がしづらいこと。</li>
<li>ひたすらネジ留めが多いこと。側面のパネルやHDD トレイなど、もう少しドライバー無しで作業できる部分が多いと嬉しかった。</li>
<li>プラスチック部分の作りがチープなこと。HDD トレイとか、前面のパネルが、写真からは分からないが結構チープだ。</li>
</ol>
<p>かなりニッチな製品だし、価格と品質のバランスを取るのが難しいのだろうとは思うが、品質面がもう少し高ければ嬉しかった。とはいえ、一度組んだ後に使う分には問題も無いので満足している。長く使っていきたい。</p>
<div class="AmaQuick-box" style="margin-bottom: 0px;"><div class="AmaQuick-image" style="float: left; margin: 0px 12px 1px 0px"><a href="https://www.amazon.co.jp/dp/B07W474GSP/?tag=mecab-22" name="AmaQuicklink" target="_blank"><img style="border-top-style: none; border-left-style: none; border-bottom-style: none; border-right-style: none" alt="CS381 を使って MicroATX に 48 TB 分の HDD を詰める" src="https://m.media-amazon.com/images/I/41jfaE8o2aL._SL200_.jpg"></a></div><div class="AmaQuick-info" style="margin-bottom: 10px; line-height: 120%"><div class="AmaQuick-name" style="margin-bottom: 10px; line-height: 120%"><a href="https://www.amazon.co.jp/dp/B07W474GSP/?tag=mecab-22" name="AmaQuicklink" target="_blank">Silverstone 最大12ドライブ搭載可能なMicroATXサイズのラックマウントケース SST-CS381B 日本正規代理店品</a><div class="AmaQuick-powered-date" style="font-size: 80%; margin-top: 5px; line-height: 120%">posted with <a title="AmaQuick" href="https://creazy.net/amazon_quick_affiliate" target="_blank">AmaQuick</a> at 2020.08.11</div></div><div class="AmaQuick-detail">SilverStone<br>SilverStone (2019-07-25T00:00:01Z)<br><br>￥44,214</div><div class="AmaQuick-sub-info" style="float: left"><div class="AmaQuick-link" style="margin-top: 5px"><a href="https://www.amazon.co.jp/dp/B07W474GSP/?tag=mecab-22" name="AmaQuicklink" target="_blank">Amazon.co.jpで詳細を見る</a></div></div></div><div class="AmaQuick-footer" style="clear: left"></div></div>
<div class="AmaQuick-box" style="margin-bottom: 0px"><div class="AmaQuick-image" style="float: left; margin: 0px 12px 1px 0px"><a href="https://www.amazon.co.jp/dp/B074PWKM9M/?tag=mecab-22" name="AmaQuicklink" target="_blank"><img style="border-top-style: none; border-left-style: none; border-bottom-style: none; border-right-style: none" alt="CS381 を使って MicroATX に 48 TB 分の HDD を詰める" src="https://m.media-amazon.com/images/I/510JpxyCy+L._SL200_.jpg"></a></div><div class="AmaQuick-info" style="margin-bottom: 10px; line-height: 120%"><div class="AmaQuick-name" style="margin-bottom: 10px; line-height: 120%"><a href="https://www.amazon.co.jp/dp/B074PWKM9M/?tag=mecab-22" name="AmaQuicklink" target="_blank">SilverStone 80PLUS GOLD認証 標準サイズ フルモジュラー SFX電源 650W SST-SX650-G 日本正規代理店品</a></div><div class="AmaQuick-detail">Silver Stone<br>Silver Stone (2017-08-25T00:00:01Z)<br><img src="https://images-fe.ssl-images-amazon.com/images/G/09/x-locale/common/customer-reviews/ratings/stars-3-5.gif" width="55" height="12" alt="CS381 を使って MicroATX に 48 TB 分の HDD を詰める" title="5つ星のうち3.6" border="0"><br>￥11,790 (中古品)</div><div class="AmaQuick-sub-info" style="float: left"><div class="AmaQuick-link" style="margin-top: 5px"><a href="https://www.amazon.co.jp/dp/B074PWKM9M/?tag=mecab-22" name="AmaQuicklink" target="_blank">Amazon.co.jpで詳細を見る</a></div></div></div><div class="AmaQuick-footer" style="clear: left"></div></div>
<div class="AmaQuick-box" style="margin-bottom: 0px"><div class="AmaQuick-image" style="float: left; margin: 0px 12px 1px 0px"><a href="https://www.amazon.co.jp/dp/B06WGW23H6/?tag=mecab-22" name="AmaQuicklink" target="_blank"><img style="border-top-style: none; border-left-style: none; border-bottom-style: none; border-right-style: none" alt="CS381 を使って MicroATX に 48 TB 分の HDD を詰める" src="https://m.media-amazon.com/images/I/51yhlIcxhxL._SL200_.jpg"></a></div><div class="AmaQuick-info" style="margin-bottom: 10px; line-height: 120%"><div class="AmaQuick-name" style="margin-bottom: 10px; line-height: 120%"><a href="https://www.amazon.co.jp/dp/B06WGW23H6/?tag=mecab-22" name="AmaQuicklink" target="_blank">SilverStone PSUケーブルセット SST-PP05-E</a></div><div class="AmaQuick-detail">SilverStone<br>SilverStone (2018-05-24T00:00:01Z)<br><img src="https://images-fe.ssl-images-amazon.com/images/G/09/x-locale/common/customer-reviews/ratings/stars-3-5.gif" width="55" height="12" alt="CS381 を使って MicroATX に 48 TB 分の HDD を詰める" title="5つ星のうち3.7" border="0"><br>￥3,640</div><div class="AmaQuick-sub-info" style="float: left"><div class="AmaQuick-link" style="margin-top: 5px"><a href="https://www.amazon.co.jp/dp/B06WGW23H6/?tag=mecab-22" name="AmaQuicklink" target="_blank">Amazon.co.jpで詳細を見る</a></div></div></div><div class="AmaQuick-footer" style="clear: left"></div></div>
<div class="AmaQuick-box" style="margin-bottom: 0px"><div class="AmaQuick-image" style="float: left; margin: 0px 12px 1px 0px"><a href="https://www.amazon.co.jp/dp/B002RL8I7M/?tag=mecab-22" name="AmaQuicklink" target="_blank"><img style="border-top-style: none; border-left-style: none; border-bottom-style: none; border-right-style: none" alt="CS381 を使って MicroATX に 48 TB 分の HDD を詰める" src="https://m.media-amazon.com/images/I/41Dki6MC+RL._SL200_.jpg"></a></div><div class="AmaQuick-info" style="margin-bottom: 10px; line-height: 120%"><div class="AmaQuick-name" style="margin-bottom: 10px; line-height: 120%"><a href="https://www.amazon.co.jp/dp/B002RL8I7M/?tag=mecab-22" name="AmaQuicklink" target="_blank">LSIロジック LSI00194 / LSI PCIEx8(Gen2.0) SATA/SAS 6Gb/s 内部8ポート HBA LSI SAS 9211-8i Single Pack</a></div><div class="AmaQuick-detail">LSIロジック<br>LSIロジック (2010-02-01T00:00:01Z)<br><img src="https://images-fe.ssl-images-amazon.com/images/G/09/x-locale/common/customer-reviews/ratings/stars-4-5.gif" width="55" height="12" alt="CS381 を使って MicroATX に 48 TB 分の HDD を詰める" title="5つ星のうち4.3" border="0"><br>￥10,800</div><div class="AmaQuick-sub-info" style="float: left"><div class="AmaQuick-link" style="margin-top: 5px"><a href="https://www.amazon.co.jp/dp/B002RL8I7M/?tag=mecab-22" name="AmaQuicklink" target="_blank">Amazon.co.jpで詳細を見る</a></div></div></div><div class="AmaQuick-footer" style="clear: left"></div></div>
<div class="AmaQuick-box" style="margin-bottom: 0px"><div class="AmaQuick-image" style="float: left; margin: 0px 12px 1px 0px"><a href="https://www.amazon.co.jp/dp/B013G4FL0A/?tag=mecab-22" name="AmaQuicklink" target="_blank"><img style="border-top-style: none; border-left-style: none; border-bottom-style: none; border-right-style: none" alt="CS381 を使って MicroATX に 48 TB 分の HDD を詰める" src="https://m.media-amazon.com/images/I/51oxXE2bwpL._SL200_.jpg"></a></div><div class="AmaQuick-info" style="margin-bottom: 10px; line-height: 120%"><div class="AmaQuick-name" style="margin-bottom: 10px; line-height: 120%"><a href="https://www.amazon.co.jp/dp/B013G4FL0A/?tag=mecab-22" name="AmaQuicklink" target="_blank">Mini SAS ケーブル，CableCreation Mini SAS HDケーブル Mini SAS (SFF-8643)－Mini SAS 36ピン (SFF-8087 ) ケーブル Mini SAS 36ピン to SFF-8643 ブラック 0.5m</a></div><div class="AmaQuick-detail">CableCreation<br>CableCreation ()<br><img src="https://images-fe.ssl-images-amazon.com/images/G/09/x-locale/common/customer-reviews/ratings/stars-4-5.gif" width="55" height="12" alt="CS381 を使って MicroATX に 48 TB 分の HDD を詰める" title="5つ星のうち4.3" border="0"><br>￥2,299</div><div class="AmaQuick-sub-info" style="float: left"><div class="AmaQuick-link" style="margin-top: 5px"><a href="https://www.amazon.co.jp/dp/B013G4FL0A/?tag=mecab-22" name="AmaQuicklink" target="_blank">Amazon.co.jpで詳細を見る</a></div></div></div><div class="AmaQuick-footer" style="clear: left"></div></div>
<!--kg-card-end: markdown-->]]></content:encoded></item></channel></rss>