Help us understand the problem. What is going on with this article?

信頼を可視化するSNS bajji(バッジ)におけるブロックチェーン利用方法

株式会社bajjiの藤尾です。
自社サービスにおけるブロックチェーン周りの実装と、E2Eテスト実装を主に行なっています。
現在開発中のbajjiというサービスにおけるブロックチェーンの利用方法を書いてみました。

bajji(バッジ)とは?

『bajji(バッジ)』(※)は、物理的に人と出会った記録と、信頼の証(bajji)を贈った/もらった記録をブロックチェーンに刻むことで、人と人との信頼を可視化していく新しいSNSです。
6月中のオープンβリリースに向けて開発中です。

なぜブロックチェーン?

信頼を可視化するためにbajji Scoreという独自の指標を用いています。
bajji Scoreは、簡単に説明すると「物理的に人と出会った(エンカウント)数」、「信頼の証(bajji)送受信数」「頻度」、そして「経過時間」といった各個人の行動データを基に算出します。算出のためのアルゴリズムとして、Proof of Mylifeというものを検討しています。こちらの詳細については次の機会にご紹介します。

bajji Scoreの信用を担保するには、上記の各個人の行動データが改ざんされていないことを第三者に証明する必要があります。これはまさにブロックチェーンが得意とするところです。
ブロックチェーンにデータを記録することにより、改ざんを防止できますし、さらにパブリックなブロックチェーンを使うことで、サービス提供者側である弊社も含め誰にも改ざんができないdecentralizedな状態にできます。

どのブロックチェーンを使用するの?

β版ではシンプルに

  • ユーザーとユーザーが出会った事実(エンカウント)
  • ユーザーからユーザーへ、信頼の証であるbajjiが贈られた事実

をパブリックなブロックチェーンに記録できれば良いので、使用経験のあるCounterparty系のフレームワークを使用する予定です。CounterpartyとはBitcoinベースのブロックチェーン上でトークン発行や、メッセージブロードキャスト等を可能にするフレームワークです。

エンカウントの記録は、メッセージブロードキャスト機能を利用して、エンカウント情報をメッセージとして記録することで実現します。
またbajjiが贈られた事実の確認は、bajjiトークンの送受信の履歴をブロックチェーン上で確認することで実現します。

β版ではCounterparty系のフレームワークを使用しますが、bajjiが目指す世界に最適なブロックチェーンというのは、今後変わってくる可能性があります。ブロックチェーンを活用する場合、現在、スケーラビリティや、正常なdecentralizedの維持などの問題がつきまといます。それ自体は、ブロックチェーン技術の発展のために非常に重要であり、私たちもその問題に取り組んでいきたいと思っています。ただ、bajjiというサービスを提供するうえでは、bajjiが目指す世界を実現することが最重要課題であって、bajjiにおけるブロックチェーンの利用目的は、あくまでもdecentralized にデータを保存する事です。そのため、ブロックチェーン上の課題が、サービスの発展に影響を与えないシステム構成にすることが重要です。その意味で、bajjiは、非金融分野へのブロックチェーンの応用でありかつ、ブロックチェーンfreeという要素を取り組んだ世界でも稀なケースになるのではないかと考えています。

bajjiシステム構成

ブロックチェーンも含めた簡易的なシステム構成図が下記になります。
スクリーンショット 2019-06-06 18.36.48.png

基本的には、各ユーザーのActivityイベント(エンカウント、bajjiの送信)が発生するたびにQueueDBにデータ登録し、定期的にCounterpartyのAPIを呼び出し、ブロックチェーンへのデータ書き込みを実施します。

上のシステム構成図で描いた通り、パブリックなブロックチェーンに情報を刻むことで、bajji userでなくともユーザーの行動情報を確認できます。
※初期段階においては全ての情報を暗号化した状態で記録されるので、サービス外ユーザーからは中身まで確認することはできません。将来的には何らかの方法で、サービス外ユーザーからデータの一部を確認できるようにしようと思っています。

どうやって記録するの?

Counterpartyには、豊富なAPIが用意されています。(https://counterparty.io/docs/api/)
いくつかRailsでのコード例を書いてみます。

APIを定義

services/api/counterparty/base_service.rb
class Api::Counterparty::BaseService
  def rpc(url, method, params)
    uri = URI.parse(url)
    request = Net::HTTP::Post.new(uri.request_uri)
    request.basic_auth('test', 'test')
    request.content_type = 'application/json'
    json = {
      id:       0,
      jsonrpc:  '2.0',
      method:   method,
      params:   params,
    }.to_json
    request.body = json
    http = Net::HTTP.new(uri.host, uri.port)
    if uri.scheme == 'https'
      http.use_ssl = true
      http.verify_mode = OpenSSL::SSL::VERIFY_NONE
    end
    response = http.request(request)
    response_body = response.body
    parsed_response = JSON.parse(response_body)
    return parsed_response
  end
end

services/api/counterparty/counterparty_service.rb
class Api::Counterparty::CounterpartyService < Api::Counterparty::BaseService
  def get_running_info()
    _method = "get_running_info"
    _params = {}
    request_to_counterparty_api(_method, _params)
  end

  def create_broadcast(source, fee_fraction, text, timestamp, value)
    _method = 'create_broadcast'    
    _params = {}
    _params["source"] = source
    _params["fee_fraction"] = fee_fraction
    _params["text"] = text
    _params["timestamp"] = timestamp
    _params["value"] = value
    request_to_counterparty_api(_method, _params)
  end

  private

  def base_url()
    case ENV['RAILS_ENV']
    when 'production', 'staging'
      "https://example.com/_api/"
    else
      "https://localhost:port/_r_api/"
    end
  end

  def request_to_counterparty_api(_method, _params)
    url = base_url()
    method = "proxy_to_counterpartyd"
    params = {}
    params["method"] = _method
    params["params"] = _params
    rpc(url, method, params)
  end
end
  • Counterpartyサーバーの稼働状態を確認
sample1.rb
  counterparty_service = Api::Counterparty::CounterpartyService.new
  res = counterparty_service.get_running_info()
  puts res

Return

{"jsonrpc": "2.0", "id": 0, "result": {"last_block": {"block_hash": "233f8bc043febb4ab428571a70e2aa1f765db581e14e2171f8bf82800b438629", "block_index": 473, "ledger_hash": "45f6dc0e05a20b6ced910fc398639ed840d8811e471059e0a7e0de9123f4a952", "messages_hash": "819c83674f534527ebc5675bc2bb8689a9757d7da737a91d303bd1e50250472e", "block_time": 1559810139, "difficulty": 4.6565423739069247e-10, "previous_block_hash": "0459274725cec59adbeb3467eabb17e61fe8ed9d814ce50c6d6c84980562806f", "txlist_hash": "7ac1a02de5d62e6f8283a917d6e41d2dd6c2a5cd8336050b511b1a8eb3677eea"}, "version_major": 9, "running_regtest": true, "bitcoin_block_count": 473, "last_message_index": 35, "api_limit_rows": 1000, "indexd_blocks_behind": 0, "version_minor": 56, "db_caught_up": true, "running_testcoin": false, "server_ready": true, "running_testnet": false, "indexd_caught_up": true, "version_revision": 0}}
  • メッセージブロードキャストのtxを生成する
sample.rb
  counterparty_service = Api::Counterparty::CounterpartyService.new
  # メッセージブロードキャスト用のデータ構築
  source = "送信元アドレス"
  fee_fraction = 0.0
  text = "メッセージ"
  timestamp = DateTime.current.to_i
  value = -1

  # メッセージブロードキャストtxを作成
  res = counterparty_service.create_broadcast(source, fee_fraction, text, timestamp, value)
  puts res['result']

成功すると未署名のトランザクションが得られるので、それを秘密鍵を使って署名します。
昔は署名用のAPIがあったのですが、現在削除されており使えません。
rpc経由で、coindのsignrawtransactionを呼ぶことになります。

未署名のトランザクション
0100000001fb7d475789d728e3bba783b6e92dbc427f68ec0cdb52eed0190abec6097a87030d0000001976a914202271cfbeb5378122a6a66f607219347483388c88acffffffff020000000000000000206a1eacc5e73e89be0c86383829e08cd5cc53a16d2c297d8d70ed4b172258e9ad728a1120160000001976a914202271cfbeb5378122a6a66f607219347483388c88ac00000000
coind_service.rb
class Api::Counterparty::CoindService < Api::Counterparty::BaseService
 def signrawtransaction(hexstring, privkeys)
    _method = 'signrawtransaction'
    _params = [
      hexstring,
      [],
      privkeys,
    ]
    request_to_coind_api(_method, _params)
  end

  def sendrawtransaction(hexstring)
    _method = 'sendrawtransaction'
    _params = [
      hexstring,
    ]
    request_to_coind_api(_method, _params)
  end

  private

  def base_url
    case ENV['RAILS_ENV']
    when 'production', 'staging'
      "http://example.com:8332/"
    else
      "http://localhost:18332/"
    end
  end

  def request_to_coind_api(_method, _params)
    url = base_url()
    method = _method
    params = _params
    rpc(url, method, params)
  end
end
sign_send.rb
  coind_service = Api::Counterparty::CoindService.new
  # 署名
  res = coind_service.signrawtransaction(unsigned_transaction, [private_key])
  signed_transaction = res['result']['hex']
  # 署名済みtxのブロードキャスト
  res = coind_service.sendrawtransaction(signed_transaction)

以上のように、簡単にブロックチェーン上の情報を取得したり、ブロックチェーンにメッセージを刻むことができます。

最後に

弊社開発中のサービスbajjiにおけるブロックチェーンの利用方法を簡単に説明させていただきました。
ブロックチェーンブームが来てから、非金融領域においてはまだまだ企業がパブリックブロックチェーンを活用する事例って少ないと思います。このbajjiが、一つの有効な活用事例となるよう引き続きサービス開発を進めます。

現在、6月中にオープンβ版リリースを予定しており、事前登録受付中です。
ご興味ある方は、是非こちらからご登録ください!


※ bajjiは信頼の気持ちを表す証であり、有価証券、前払式支払手段、法定通貨、仮想通貨または通貨性を持つトークンのいずれでもないため取引できません。また、運営以外から受け取ったbajjiを他のユーザーに送ることはできません。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした