ブロックチェーンって何?Go言語で簡単なブロックチェーンを作成してみる
ビットコインやイーサリアムなど、仮想通貨についてのニュースを耳にすることが多くなりました。
今回は、これらの仮想通貨に主に使用されている「ブロックチェーン」技術について、Go言語で簡単なプロトタイプを作成してみます。
ちなみに、「仮想通貨」の他に「暗号資産」という言葉もよく使われています。 「仮想通貨」という呼称の方が多く使われているイメージですが、金融庁のHPによると「仮想通貨」から「暗号資産」への呼称変更が提案されています。
ただし今回の記事では、より一般的に使用されている「仮想通貨」という呼称で進めていきたいと思います。
ブロックチェーンとは
ブロックチェーンとは、取引の記録(トランザクション)を「ブロック」と呼ばれる塊に格納し、暗号化したうえで直前のブロックと繋げる仕組みです。
直前のブロックを暗号化した「ハッシュ値」を次のブロックが保持する構造となっており、同じブロックの内容であればハッシュ値も同じになります。
もし過去に生成されたブロックを改ざんしようとした場合、ハッシュ値が次のブロックに入っている値と異なってしまうため、後続のブロックを全て変更しなくてはなりません。 そのため、改ざんが極めて難しいと言われています。
「ブロック」を作成する
それでは、Goで実装を始めてみます。まずは、トランザクションを格納するブロックを作成します。
ブロックに格納する情報は複数ありますが、今回は以下の3つを入れて実装していきます。
type Block struct {
previousHash [32]byte // 直前のブロックのハッシュ値
transaction []string
timestamp int64
}
続いて、ブロックを作成する関数を作成します。
func NewBlock(previousHash [32]byte, transaction []string) *Block {
b := &Block{}
b.previousHash = previousHash
b.transaction = transaction
b.timestamp = time.Now().UnixNano()
return b
}
次に、ハッシュ関数を用いて、ブロックをハッシュ化するメソッドを作成します。
今回はハッシュ関数にsha256 を使用します。
また、JSONに変換する際はMarshalが必要になりますので、以下の記事を参考にしてください。
func (b *Block) Hash() [32]byte {
m, err := json.Marshal(b)
if err != nil {
panic(err)
}
return sha256.Sum256(m)
}
func (b *Block) MarshalJSON() ([]byte, error) {
return json.Marshal(struct {
Timestamp int64 `json:"timestamp"`
PreviousHash [32]byte `json:"previous_hash"`
Transaction []string `json:"transaction"`
}{
Timestamp: b.timestamp,
PreviousHash: b.previousHash,
Transaction: b.transaction,
})
}
出力用のメソッドも作成しておきます。
func (b *Block) Print() {
fmt.Printf("Timestamp %d\n", b.timestamp)
fmt.Printf("PreviousHash %x\n", b.previousHash)
fmt.Printf("Transaction %s\n", b.transaction)
}
「ブロックチェーン」を作成する
ここまでで、複数のトランザクションを格納するブロックが作成できました。
次は、このブロックを繋げて、ブロックチェーンを作成します。 トランザクションは一時的にプールし、一定数溜まったらブロックに格納します。
type Blockchain struct {
transactionPool []string // トランザクションを一時的にプールするフィールド
block []*Block
}
func NewBlockchain() *Blockchain {
bc := &Blockchain{}
bc.CreateBlock() // Genesis Blockの作成
return bc
}
ブロックを作成し、ブロックチェーン構造体に追加するメソッドを作成します。
最初に作成されたブロック(Genesis Block)は直前のブロックのハッシュ値を取得できないので、ゼロ値を入れています。
トランザクションプールは一時的にトランザクションを格納しておく場所のため、ブロックが作成されたら空にします。
func (bc *Blockchain) CreateBlock() {
if len(bc.block) == 0 {
b := NewBlock([32]byte{}, nil)
bc.block = append(bc.block, b)
} else {
ph := bc.block[len(bc.block)-1].Hash()
b := NewBlock(ph, bc.transactionPool)
bc.block = append(bc.block, b)
}
bc.transactionPool = nil
}
func (bc *Blockchain) AddTransaction(transaction string) {
bc.transactionPool = append(bc.transactionPool, transaction)
}
ブロック同様、ブロックチェーンを出力するメソッドを作成します。
func (bc *Blockchain) Print() {
for i, b := range bc.block {
fmt.Printf("%s Block %d %s\n", strings.Repeat("=", 15), i, strings.Repeat("=", 15))
b.Print()
}
}
以上でブロックを作成し、ブロックチェーンに追加するメソッドができました。 それでは、main関数で出力してみます。
各ブロックにはトランザクションを2つずつ入れることにします。
func main() {
bc := NewBlockchain()
bc.AddTransaction("transaction1")
bc.AddTransaction("transaction2")
bc.CreateBlock()
bc.AddTransaction("transaction3")
bc.AddTransaction("transaction4")
bc.CreateBlock()
bc.Print()
}
出力結果
=============== Block 0 ===============
Timestamp 1618296335308193300
PreviousHash 0000000000000000000000000000000000000000000000000000000000000000
Transactions []
=============== Block 1 ===============
Timestamp 1618296335308271000
PreviousHash 6408abd46e4b29fdf503f3543b808d85d92bd3563c8ea8ae58e1e155b360fb3e
Transactions [transaction1 transaction2]
=============== Block 2 ===============
Timestamp 1618296335308277200
PreviousHash 3b2a4c4dcf816b37c208486b7a378eccbdec98a7bc01bb645938bdc235e4c001
Transactions [transaction3 transaction4]
Block1から、直前のブロックのハッシュ値とトランザクションが入っていることが分かります。
これで簡単なブロックチェーンのプロトタイプが作成できました。
まとめ
今回は、簡単なブロックチェーンの実装をしてみました。
今回の記事では紹介できていませんが、分散台帳システムなど安全性に関する技術も多くありますので、今後紹介できればと思います。
また、ビットコイン払いなどで仮想通貨もより身近になっていくと思いますので、ブロックチェーンは今後も注目です。
この記事を書いた人
- 創造性を最大限に発揮するとともに、インターネットに代表されるITを活用し、みんなの生活が便利で、豊かで、楽しいものになるようなサービスやコンテンツを考え、創り出し提供しています。
この執筆者の最新記事
関連記事
最新記事
FOLLOW US
最新の情報をお届けします
- facebookでフォロー
- Twitterでフォロー
- Feedlyでフォロー