原文はこちら。
https://community.oracle.com/docs/DOC-1011373
Java Magazine 2017年1/2月号で、ブロックチェーンテクノロジのEthereumを使って、その上でJavaアプリケーションを作成するためにweb3jの利用に関する入門記事を寄稿しています。
ここで記載したコードは全て以下のGitHubにUpしてあります。
ブロックチェーンに存在するデータの状態は、以前発生したトランザクションやイベントを再生して構築されるため、分散イベントログのように考えることができます。ブロックチェーンは、完全に分散化されており、インターネットのような信頼できないパブリック環境で潜在的に関連のないノードに格納されます。さまざまなブロックチェーンテクノロジが存在しています中で、Ethereumは特にパブリックなブロックチェーン技術として生まれました。
ブロックチェーン技術の詳細については、Java Magazineの記事を参照してください)。
プロジェクトにweb3jを取り込むには、以下のように依存性をpom.xmlに追加します。
プログラムの残りの部分とは異なる実行スレッドで非同期にサブスクリプションは実行するため、サブスクリプションには
各ブロックのトランザクション数の詳細と、ブロックを一意に識別するブロックハッシュ、前のブロックの親ハッシュをそれぞれ提供するために、この例に書き込みます。
この例を10ブロックに制限し、ラッチを使用して10ブロックが放出されるのを待ちます。
web3jはすでに
以前のセクションで作成したトランザクション
Etherは数多くの異なる単位があり、Weiはその中で最も細かいものです。1 Weiは10e-18 Etherです。
https://community.oracle.com/docs/DOC-1011373
著者(Conor Svensson)について Conor Svensson (@conors10) はweb3jというEthereumブロックチェーンとアプリケーションを統合するJavaライブラリの作者です。以前はcoHomeとHuffleというスタートアップの共同創業者で、その後、OtheraでCTOを務め、Otheraのブロックチェーン貸与プラットフォームおよび交換プラットフォームを構築しています。 coHomeまた、Sydney Java User Groupの主催者の一人であり、よくスピーカーとして登場します。彼はテクノロジーとファイナンスに関するブログを書いており、ディスプレイの前にいないときは地元シドニーのMaroubraというビーチでサーフィンを楽しんでいます。 |
Java Magazine 2017年1/2月号で、ブロックチェーンテクノロジのEthereumを使って、その上でJavaアプリケーションを作成するためにweb3jの利用に関する入門記事を寄稿しています。
Java Magazine 2017年1月/2月号この記事では、web3jのreactive-functional APIを使用して、パブリックなEthereumブロックチェーンで発生するイベントを見る方法について説明します。
http://www.javamagazine.mozaicreader.com/JanFeb2017/Default/36/0#&pageSet=36&page=0&contentItem=0
Ethereum Project
https://www.ethereum.org/
web3j - Lightweight Ethereum Java and Android integration library
https://web3j.io/
ここで記載したコードは全て以下のGitHubにUpしてあります。
web3j/examples
https://github.com/web3j/examples/tree/master/rx
Background
過去1年間、テクノロジーとFinancialの報道ではブロックチェーンとその破壊的な可能性でもちきりでした。ブロックチェーンは分散型の不変(Immutable)のデータストアです。不変ゆえに、データはブロックチェーンに追加することしかできません。これは、ブロックにグループ化されたトランザクションを使って実現されています。そのため、データはブロックチェーンの最後に追加されます。Figure 1. ブロックチェーンの構造 |
ブロックチェーン技術の詳細については、Java Magazineの記事を参照してください)。
Scala: Deeply Functional, Purely Object-Oriented
http://www.javamagazine.mozaicreader.com/JanFeb2017/Default/47/0#&pageSet=36&page=0
Getting Started with Ethereum
分散化されたEthereumネットワークは、Ethereumネットワークのピア(Peer)を形成するクライアントから構成されています。ネットワークと対話するためには、これらの一つのクライアントにアクセスする必要があります。一番簡単な方法は、自身でクライアントを実行することです。2個の主要なクライアントは、GethとParityです。ethereum/go-ethereum - Building Ethereumクライアントをインストール後、以下のようにしてクライアントを起動できます。
https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum
ethcore/parity - Setup
https://github.com/ethcore/parity/wiki/Setup
クライアントは他のノードを見つけて接続し、testnetブロックチェーンのローカルコピーの同期を開始します。mainnetとtestnetという、2個のパブリックなEthereumブロックチェーンがあり、それぞれ本番環境、テスト環境に相当します。# Geth:
$ geth --fast --cache=512 --rpcapi personal,db,eth,net,web3 --rpc --testnet
# Parity:
$ parity --chain testnet
The web3j Library
クライアントを実行したので、Ethereumブロックチェーン上でクライアントと連携する、軽量なJavaライブラリのweb3jを使うと、Ethereumブロックチェーンと対話を始めるのは簡単です。web3jについて詳細を知りたい方は、以下のURLをご覧ください。web3j - Lightweight Ethereum Java and Android integration library
https://web3j.io
Figure 2. web3jはJavaアプリケーションのためにEthereumブロックチェーンへの統合レイヤーを提供する |
Androidで作成しようとしているのであれば、<dependency>
<groupId>org.web3j</groupId>
<artifactId>core</artifactId>
<version>2.0.0</version>
</dependency>
core-android
を使ってください。New Block Subscriptions
数行のコードで、Ethereumブロックチェーンに接続し、新しいブロックがブロックチェーンに追加されたことの通知を受けることができます。Web3j web3 = Web3j.build(new HttpService()); // defaults to http://localhost:8545/
Subscription subscription = web3j.blockObservable(false)
.subscribe( block -> {
System.out.println( "Sweet, block number "
+ block.getBlock().getNumber()
+ " has just been created" );
},
Throwable::printStackTrace );
TimeUnit.MINUTES.sleep(2);
subscription.unsubscribe();
blockObservable
は、新しいブロックがEthereumブロックチェーンに追加される都度、ブロックオブジェクトをサブスクライバーに送信します。プログラムの残りの部分とは異なる実行スレッドで非同期にサブスクリプションは実行するため、サブスクリプションには
sleep
ステートメントを含める必要があります。各ブロックのトランザクション数の詳細と、ブロックを一意に識別するブロックハッシュ、前のブロックの親ハッシュをそれぞれ提供するために、この例に書き込みます。
この例を10ブロックに制限し、ラッチを使用して10ブロックが放出されるのを待ちます。
コードを実行すると、直近にEthereumブロックチェーンに追加された10個のブロックの詳細を確認できます。CountDownLatch countDownLatch = new CountDownLatch(1);
System.out.println("Waiting for " + COUNT + " transactions...");
Subscription subscription = web3j.blockObservable(true)
.take(COUNT)
.subscribe( ethBlock -> {
EthBlock.Block block = ethBlock.getBlock();
LocalDateTime timestamp = Instant.ofEpochSecond( block.getTimestamp()
.longValueExact())
.atZone(ZoneId.of("UTC"))
.toLocalDateTime();
int transactionCount = block.getTransactions().size();
String hash = block.getHash();
String parentHash = block.getParentHash();
System.out.println( timestamp + " Tx count: " +
transactionCount + ", Hash: " +
hash + ", Parent hash: " +
parentHash );
countDownLatch.countDown();
},
Throwable::printStackTrace);
subscription.unsubscribe();
2016-12-22T00:27:11 Tx count: 3, Hash: 0xbed93a59bcd30c0f11e155109a5dbff3e56a5354e90e514108917c1f54c4182d, Parent hash: 0x74f8bffd8734833a2fbaad0d9e48eb6206ee25dc9c55425cf1edca9dfe45aa06
2016-12-22T00:27:44 Tx count: 2, Hash: 0xb147a4ca79bc7c5e767ee92be648a9fd23ee15ec64f764b3f2dc8a4cb7229a50, Parent hash: 0xbed93a59bcd30c0f11e155109a5dbff3e56a5354e90e514108917c1f54c4182d
2016-12-22T00:27:51 Tx count: 1, Hash: 0xa2d8d3572592470e30b7fb504ce504444b1ea1208035f1545c85fc824a882e1b, Parent hash: 0xb147a4ca79bc7c5e767ee92be648a9fd23ee15ec64f764b3f2dc8a4cb7229a50
2016-12-22T00:28:09 Tx count: 2, Hash: 0xf4d4a7d7a2202f8c64e72b47947adb5ae419f2bdadabec9386cb9d4a27cd7ef8, Parent hash: 0xa2d8d3572592470e30b7fb504ce504444b1ea1208035f1545c85fc824a882e1b
2016-12-22T00:28:17 Tx count: 2, Hash: 0x43dc1da772b3f5aea3388fb4ddf14c188753646de4971b62e90b903774c5c2bc, Parent hash: 0xf4d4a7d7a2202f8c64e72b47947adb5ae419f2bdadabec9386cb9d4a27cd7ef8
2016-12-22T00:28:22 Tx count: 1, Hash: 0x80d03ac26a3aba27d01beecb530b9055dd28b199a52bcc53704c8e418ba437fa, Parent hash: 0x43dc1da772b3f5aea3388fb4ddf14c188753646de4971b62e90b903774c5c2bc
2016-12-22T00:28:27 Tx count: 0, Hash: 0x897af69eafa47c2951379780a40ee47fc3383959197419a4feadc59d1d2b2c13, Parent hash: 0x80d03ac26a3aba27d01beecb530b9055dd28b199a52bcc53704c8e418ba437fa
2016-12-22T00:28:28 Tx count: 0, Hash: 0xf12762e30caa3d0f1c6c7deb7fff93cd00727565575b8b35a7466ca75ba112e6, Parent hash: 0x897af69eafa47c2951379780a40ee47fc3383959197419a4feadc59d1d2b2c13
2016-12-22T00:28:43 Tx count: 1, Hash: 0x3754841b596ad15b17b37dd6293db77ebb672743918877dcf92e47407a2153e5, Parent hash: 0xf12762e30caa3d0f1c6c7deb7fff93cd00727565575b8b35a7466ca75ba112e6
2016-12-22T00:28:49 Tx count: 2, Hash: 0x6613c62dfd05761b3794658d341c1dab95f19db1e2bebd8cf091861c1ae88cd4, Parent hash: 0x3754841b596ad15b17b37dd6293db77ebb672743918877dcf92e47407a2153e5
Functional Composition
RxJavaのObservable
を使っているので、簡単に機能を追加できます。Observable例えば、ブロックチェーンに書き込まれた新しいトランザクション全て通知する
http://reactivex.io/documentation/observable.html
Observable
を作成する場合、 blockObservable()
を再度利用し、ブロックに含まれているトランザクションのリストを展開し、flatMapIterable()
メソッドを使ってこれらのトランザクションを個別に通知することができます。今回は、パラメータとしてweb3j.blockObservable(true)
.flatMapIterable( ethBlock -> (List) ethBlock.getBlock()
.getTransactions());
true
を渡しています。これはブロックとそれらのブロックに含まれている全てのトランザクションの詳細を要求することを意味しています。web3jはすでに
web3j.transactionObservable()
でこの構成を実装済みです。web3j/web3j - JsonRpc2_0Rx.java
https://github.com/web3j/web3j/blob/master/src/main/java/org/web3j/protocol/rx/JsonRpc2_0Rx.java#L66
Counting Ether
Ethereumには、Etherという名前の独自のcryptocurrency(仮想通貨)があり、Bitcoinと同様に考えることができます。Etherを使ってネットワーク上で発生する取引への支払いをします。これらの取引では、Etherをある人から他の人に転送することもできます。取引に関連するEtherの詳細はEthereumのtransactionのvalue
フィールドに含まれています。以前のセクションで作成したトランザクション
Observable
を使い、簡単にリアルタイムでブロックチェーンから情報を取得し始めることができます。例えば、指定したブロックの個数で発生した取引の総額を取得する場合、以下のように利用することができます。上記コードを実行すると、以下のような結果を得ることができます。CountDownLatch countDownLatch = new CountDownLatch(COUNT);
System.out.println("Waiting for " + COUNT + " transactions...");
Observable<BigInteger> transactionValue = web3j.transactionObservable()
.take(COUNT)
.map(Transaction::getValue)
.reduce(BigInteger.ZERO, BigInteger::add);
Subscription subscription = transactionValue.subscribe(total -> {
System.out.println( "Transaction value: " + Convert.fromWei( new BigDecimal(total), Convert.Unit.ETHER) + " Ether");
countDownLatch.countDown();
},
Throwable::printStackTrace);
countDownLatch.await(10, TimeUnit.MINUTES);
subscription.unsubscribe();
ここでは、発行された各トランザクションの値を取得し、Transaction value: 5.011 Ether (5011000000000000000 Wei)
reduce()
メソッドを使用してそれらを合計していますが、reduce関数が最終結果を提供するために、有限ストリームを扱う必要があることに注意してください。Reduceまた、すべてのトランザクションがEtherの移転になるわけではないので、トランザクション値として0を受け取っても驚かないでください。
http://reactivex.io/documentation/operators/reduce.html
Etherは数多くの異なる単位があり、Weiはその中で最も細かいものです。1 Weiは10e-18 Etherです。
Convert
メソッドはWeiの値をトランザクションからEtherに変換します。Further Observables
他のobservableも利用できます。例えば、まだブロックにグループ化されておらず、ブロックチェーンに追加されていない、保留中のトランザクションの詳細を取得するには、次のようにします。また、web3jは全てのEthereum API呼び出しのためのobservableも提供しています。以下は、Ethereumクライアントのバージョンを取得する簡単な例です。Subscription subscription = web3j.pendingTransactionObservable().subscribe(tx -> {
...
});
上記コードの実行例です。Web3j web3 = Web3j.build(new HttpService()); // defaults to http://localhost:8545/
web3j.web3ClientVersion().observable().subscribe(x -> {
System.out.println(x.getWeb3ClientVersion());
});
利用可能なAPI呼び出しのリストは、interface Ethereumをご覧ください。Client is running version: Geth/v1.5.4-stable-b70acf3c/darwin/go1.7.3
Interface Ethereumweb3jでサブスクライブ可能な追加のイベントタイプがあります。詳細は以下のURLをご覧ください。
https://github.com/web3j/web3j/blob/master/src/main/java/org/web3j/protocol/core/Ethereum.java
Filters and Events
https://docs.web3j.io/filters.html
Conclusion
reactive-functional APIを使ってEthereumブロックチェーンへの問合せを実行するweb3jの機能の概要を説明してきました。web3jやEthereumの詳細を知りたい方は、以下のURLをご覧ください。たくさんのリソースがあります。web3j - Lightweight Ethereum Java and Android integration library
https://web3j.io