独自暗号貨幣を作ろう 第12回

第1回 第2回 第3回 第4回 第5回 第6回 第7回 第8回 第9回 第10回
第11回


<ブロック>
最も基本的な取引についてはある程度実装できましたので、次はブロックの実装をしていきたいと思います。

ブロックとは、取引の集まりに仕事証明に必要な幾つかの情報を添付したものです。仕事証明に必要な幾つかの情報はブロックの頭部(block header)として1つに纏められます。

但し、起源ブロック(genesis block)という特殊なブロックが1つだけあります。通常のブロックはそのブロックの丁度1つ前に当たるブロックを参照しています。そのため、ブロックの集まりは木構造を成すことになりますが、それらが1つの木に纏められるためには少なくとも根に当たるブロックが必要となります。この、(時間的には)最初に作られるブロックが起源ブロックです。起源ブロックは取引やブロックの頭部を有しません(有する必要がありません)。
ネットワーク全体で(大多数のノードが信認する)唯1つのブロック木(block tree)を構成するための便法でしかないので、結局はネットワークに参加する大多数のノードが納得するならどんなデータでも良いのです。
しかし、通常は起源ブロックに開発者が事前採掘(premining)をしていないことを示す文字列を格納します。即ち、その暗号貨幣が始動する直前に起こった出来事等を文字列として格納し、少なくともその出来事が起こるより前には開発者によって事前採掘がされていないということを保証します。

起源ブロック以外の普通のブロックは取引の集まりとブロックの頭部を有します。取引の集まりには、ブロック報酬(block reward)と取引手数料を採掘者が所有する口座に送金する1つ以上の新しい貨幣を生成する取引が含まれます。

CREACOINの場合は、採掘者へ報酬を与えるだけでなく、ブロック報酬の一部はCREA基金が獲得するものとします(CREA基金とは、コンテンツ制作者に報酬を与えるために設置される基金です。詳細についてはCREACOINのスレを参照してください)。そのため、ブロックに格納される取引の集まりには採掘者の口座に送金するための新しい貨幣を生成する取引だけでなく、基金の口座に送金するための新しい貨幣を生成する取引も含まれることになります。

しかしながら、全ての普通のブロックに採掘者の口座と基金の口座の両方に新しい貨幣を送金する取引を格納するのは必要な記憶領域という観点から非効率的でしょう。ブロックの採掘者は夫々のブロック毎に毎回異なる可能性がありますが、基金は唯一無二の存在であり、ブロック毎に基金の口座を変える必要はありません。そのため、基金の取り分についてはブロック毎に発生させるのではなく、1万ブロック程度毎に発生させるのが妥当でしょう。つまり、CREACOINでは、普通のブロックは更に2種類に分かれることになります。

以上の仕様上の要求から、CREACOINでは、ブロックを以下の3種に分けて実装していくことにします。
 1.起源ブロック
 2.採掘者の口座のみに新しい貨幣が送金されるブロック(通常ブロック)
 3.採掘者の口座だけでなく、基金の口座にも新しい貨幣が送金されるブロック(基金獲得分付きブロック)

取り敢えず、全ての種類のブロックが継承するBlock抽象クラスを作っておきましょう。以前作ったTXBLOCKBASE抽象クラスを継承します。特に追加の機能はないです。

public abstract class Block<BlockidHashType> : TXBLOCKBASE<BlockidHashType>
    where BlockidHashType : HASHBASE
{
    public Block(int? _version) : base(_version) { }
}


<起源ブロック>
起源ブロックを表すGenesisBlockクラスを作ります。
genesisWordフィールドに適当な文字列を入れることになります。始動直前のBitcoinの価格でも入れれば良いのではないでしょうか。

public class GenesisBlock<BlockidHashType> : Block<BlockidHashType>
    where BlockidHashType : HASHBASE
{
    public GenesisBlock() : base(null) { }
 
    public readonly string genesisWord = "Bitstamp 2014/05/25 BTC/USD High 586.34 BTC to the moooooooon!!";
 
    protected override Func<ReaderWriter, IEnumerable<MainDataInfomation>> StreamInfo
    {
        get
        {
            return (msrw) => new MainDataInfomation[]{
                new MainDataInfomation(typeof(string), () => genesisWord, (o) => { throw new NotSupportedException("genesis_block_cant_read"); }),
            };
        }
    }
}