Hyperledger Fabric の REST API メモ

[オープンソースのブロックチェーン Hyperledger Fabric を試してみる](http://qiita.com/kyrieleison/items/ec5223bbe6140822df4a) の続き

Hyperledger Fabric の REST API を一通り試したときのメモです。
Bluemix 上の [IBM Blockchain](https://new-console.ng.bluemix.net/catalog/services/blockchain) を使っています。

# REST Endpoints

- Blockchain API
    - GET /chain
        - ブロックチェーンの現在の状態を取得するAPI
- Block API
    - GET /chain/blocks/{block-id}
        - ブロックチェーンから特定のブロックの内容を取得するAPI
- Transactions API
    - GET /transactions/{UUID}
        - ブロックチェーンから個々のトランザクションの内容を取得するAPI
- Network API
    - GET /network/peers
        - ピアノードの一覧と、それぞれのネットワークに関する情報を取得するAPI
- Registrar API
    - POST /registrar
        - 認証局にユーザを登録・ローカルストレージに登録証明書を保存するAPI
    - GET /registrar/{enrollmentID}
        - 認証局にユーザが登録されているかどうかを確認するAPI
    - DELETE /registrar/{enrollmentID}
        - ローカルストレージからユーザのログイントークンを削除するAPI
    - GET /registrar/{enrollmentID}/ecert
        - ローカルストレージからユーザの登録証明書を取得するAPI
    - GET /registrar/{enrollmentID}/tcert
        - 認証局に登録されているユーザのトランザクション証明書を取得するAPI
- Chaincode API
    - POST /chaincode
        - チェインコードを設置・実行・参照するAPI

# Blockchain API

## GET /chain

```
curl -X GET --header "Accept: application/json" "https://1ba11756fe4d445e8f380701269a1075-vp1.us.blockchain.ibm.com:444/chain"
{
  "height": 5,
  "currentBlockHash": "RWVzXnp4wuXdLSxeBTE93GM62vXyld2D6HakM/nYdXQQi7NcEW6AfFdkaPI7E+RWWS5Ma1RtEqFnbfo+3dtv2Q==",
  "previousBlockHash": "YCSaBj8URoEpNwTgRqqHFakvXX1POR2GELwHjtJNqLd1hAPCho0vAXvdgBHYijTaEQi6jeCNNFm9KWlJC1pqEw=="
}
```

- ブロックチェーンの現在の状態を取得するAPI
    - `height`: ブロック数
    - `currentBlockHash`: 現在のブロックのハッシュ値。次のブロックを繋げる際に使われる？
    - `previousBlockHash`: 一つ前のブロックのハッシュ値。現在のブロックに使われている

# Block API

## GET /chain/blocks/{block-id}

```
curl -X GET --header "Accept: application/json" "https://1ba11756fe4d445e8f380701269a1075-vp1.us.blockchain.ibm.com:444/chain/blocks/1"
{
  "transactions": [
    {
      "type": 1,
      "chaincodeID": "CkpodHRwczovL2dpdGh1Yi5jb20vbWFzdGVyRGV2MTk4NS9oeXBlcmxlZGdlcl9jaGFpbmNvZGUvY2hhaW5jb2RlX2V4YW1wbGUwMhKAATcyYzNjMzk1NzA3YmU3ZGE2ZTI2ODQxYmI5NDc1ZWM5NmFjMDY2ODdjZGY1ZWE1NTc5NjIwMjgwMWU2NThkMGJhZmUyNTcxMDllYzdlZWJkMTgxNGNhNWM3NmI4YmU1ZjAzZDMyMzNiNzA0ZmQyOTdlOGZjYjgxZGJhYjczMDVl",
      "payload": "CuwBCAESzwEKSmh0dHBzOi8vZ2l0aHViLmNvbS9tYXN0ZXJEZXYxOTg1L2h5cGVybGVkZ2VyX2NoYWluY29kZS9jaGFpbmNvZGVfZXhhbXBsZTAyEoABNzJjM2MzOTU3MDdiZTdkYTZlMjY4NDFiYjk0NzVlYzk2YWMwNjY4N2NkZjVlYTU1Nzk2MjAyODAxZTY1OGQwYmFmZTI1NzEwOWVjN2VlYmQxODE0Y2E1Yzc2YjhiZTVmMDNkMzIzM2I3MDRmZDI5N2U4ZmNiODFkYmFiNzMwNWUaFgoEaW5pdBIBYRIDMTAwEgFiEgMyMDA=",
      "uuid": "72c3c395707be7da6e26841bb9475ec96ac06687cdf5ea55796202801e658d0bafe257109ec7eebd1814ca5c76b8be5f03d3233b704fd297e8fcb81dbab7305e",
      "timestamp": {
        "seconds": 1476936384,
        "nanos": 762271536
      },
      "nonce": "PoSNNChCKd07Zs6yhq1rELq5Ccl3llQc",
      "cert": "MIICTjCCAfWgAwIBAgIQDGBmkNuYRHSliV7jSnH1MjAKBggqhkjOPQQDAzApMQswCQYDVQQGEwJVUzEMMAoGA1UEChMDSUJNMQwwCgYDVQQDEwN0Y2EwHhcNMTYxMDIwMDQwNTI0WhcNMTcwMTE4MDQwNTI0WjA7MQswCQYDVQQGEwJVUzEMMAoGA1UEChMDSUJNMR4wHAYDVQQDDBVkYXNoYm9hcmR1c2VyX3R5cGUxXzAwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQlhbRj1/FEdRQbqbMut5dfzX13A1lXzlxIuCIvFmR8b9/nHVuLJck8HIizuHtsqkFq4vDqPqaNrBoW3U/fi+G7o4HsMIHpMA4GA1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8EAjAAMA0GA1UdDgQGBAQBAgMEMA8GA1UdIwQIMAaABAECAwQwTQYGKgMEBQYHAQH/BEA187+DA+DNcWcGuId+ULDeX6sliQMD01ikz8XgHme7nhaqLDMMcTOLQy5g552aH1SrdM4VBSLhtYlVCMMlWn89MFoGBioDBAUGCARQOI/vAW5lmwAc3GcBU9R97IOGW9EKKPciV4Ov/gIHL2RDBM9REJ4ErvaafN7GlYy0E3ZwsIQNr4qM0QA3ojMid1NITNXH/y/UMykyzvY/ATQwCgYIKoZIzj0EAwMDRwAwRAIgKtqz/xRQUgKrv48EiuHS8XzMErYckGvAWPirTsh8PFUCIDZF/lAbj9uW2oq5FiwL47R4ALPWMuQsrcPBh9Vx2JhG",
      "signature": "MEQCIFPvLCoL6PogUpLxUyUs8zZ70y/KnbBnEiEvuwhgDTbtAiBwJNC5tjQzaRufdV4dGMaGRl9lzlxTgQm/2t5ejlQogA=="
    }
  ],
  "stateHash": "7QPE8yCGIJqZu/ts70iG2v5ab4HqMYHHA5u345gix/sGcVt/nsrbEXodPJvJj6uy/MwH44l3XAHCSJZm0xRA6Q==",
  "previousBlockHash": "RrndKwuojRMjOz/rdD7rJD/NUupiuBuCtQwnZG7Vdi/XXcTd2MDyAMsFAZ1ntZL2/IIcSUeatIZAKS6ss7fEvg==",
  "consensusMetadata": "CAE=",
  "nonHashData": {
    "localLedgerCommitTimestamp": {
      "seconds": 1476936411,
      "nanos": 26062785
    },
    "transactionResults": [
      {
        "uuid": "72c3c395707be7da6e26841bb9475ec96ac06687cdf5ea55796202801e658d0bafe257109ec7eebd1814ca5c76b8be5f03d3233b704fd297e8fcb81dbab7305e"
      }
    ]
  }
}
```

- ブロックチェーンから特定のブロックの内容を取得するAPI
    - `transacitons`; トランザクションの配列
        - `type`: トランザクションのタイプ。`['UNDEFINED', 'CHAINCODE_DEPLOY', 'CHAINCODE_INVOKE', 'CHAINCODE_QUERY', 'CHAINCODE_TERMINATE']` の添字が返ってくる模様
        - `chaincodeID`: チェーンコードID
        - `payload`: チェーンコードの関数を実行するためのペイロード
        - `uuid`: トランザクションを特定する一意の UUID
        - `timestamp`: チェーンコードが実行可能になった時刻
        - `nonce`: 乱数
        - `cert`: このトランザクションを送信したクライアントの証明書
        - `signature`: このトランザクションを送信したクライアントの署名
    - `timestamp`: ブロックが作成された時刻
    - `previousBlockHash`: 前のブロックのハッシュ値
    - `consensusMetadata`: コンセンサスのためのメタデータ
    - `nonHashData`: ブロックハッシュに含まれないブロックのデータ
- ブロックチェーンはブロックの連なり
    - ブロックは複数の取引(トランザクション)のあつまり
    - ブロックは時系列で繋がっている
    - ブロックのデータには一つ前のブロックのハッシュも含まれる
    - ブロックのデータはハッシュ化され、次のブロックを作るのに使われる
    - refs: 5分で分かるブロックチェーンの基本的な仕組み http://www.slideshare.net/cookle/5-58379474
- ネットワークタブを開くと、チェインコードが順に展開されているのが分かる
    - 各検証ピアにデータが同期されている
- ブロックの中に複数トランザクションが入る状況はどんなときか？
    - Fabric におけるトランザクションは Chaincode のデプロイと Chaincode の実行の2種類しかない
    - Chaincode を作るとトランザクションが作成され、同時にブロックも作られる(ように見える)
    - つまり Chaincode とトランザクションは1対1、かつブロックに含まれるトランザクションも常に1つのみ？
- ブロックハッシュはどこで使うのか？
    - 次のブロックを追加するとき？
- トランザクションの `uuid` の形式はトランザクションの種類によって異なる？
    - Chaincode のデプロイ(Deployment Transaction): ハッシュに似たID
    - Chaincode の実行(Invocation Transaction): UUID
    - (`uuid` なのに UUID じゃない...)

# Transaction API

## GET /transactions/{UUID}

```
curl -X GET --header "Accept: application/json" "https://1ba11756fe4d445e8f380701269a1075-vp1.us.blockchain.ibm.com:444/transactions/72c3c395707be7da6e26841bb9475ec96ac06687cdf5ea55796202801e658d0bafe257109ec7eebd1814ca5c76b8be5f03d3233b704fd297e8fcb81dbab7305e"
{
  "type": 1,
  "chaincodeID": "CkpodHRwczovL2dpdGh1Yi5jb20vbWFzdGVyRGV2MTk4NS9oeXBlcmxlZGdlcl9jaGFpbmNvZGUvY2hhaW5jb2RlX2V4YW1wbGUwMhKAATcyYzNjMzk1NzA3YmU3ZGE2ZTI2ODQxYmI5NDc1ZWM5NmFjMDY2ODdjZGY1ZWE1NTc5NjIwMjgwMWU2NThkMGJhZmUyNTcxMDllYzdlZWJkMTgxNGNhNWM3NmI4YmU1ZjAzZDMyMzNiNzA0ZmQyOTdlOGZjYjgxZGJhYjczMDVl",
  "payload": "CuwBCAESzwEKSmh0dHBzOi8vZ2l0aHViLmNvbS9tYXN0ZXJEZXYxOTg1L2h5cGVybGVkZ2VyX2NoYWluY29kZS9jaGFpbmNvZGVfZXhhbXBsZTAyEoABNzJjM2MzOTU3MDdiZTdkYTZlMjY4NDFiYjk0NzVlYzk2YWMwNjY4N2NkZjVlYTU1Nzk2MjAyODAxZTY1OGQwYmFmZTI1NzEwOWVjN2VlYmQxODE0Y2E1Yzc2YjhiZTVmMDNkMzIzM2I3MDRmZDI5N2U4ZmNiODFkYmFiNzMwNWUaFgoEaW5pdBIBYRIDMTAwEgFiEgMyMDAa442cAR+LCAAACW6IAP/s/Xl720aSOI7vv+KrQLi/ZEmHok7bM5po95ElO9FnYlsjyUnm5/HjByRBCmsSYABQEkfr9/6tqy8cPHQ5BzkZiwS6q6urq6urq6ur0qS7MQizi0mn3Y1HGyM/zYLkKLjc+utfnm5cTMdBMgx6gyD52L3ww6gb94IN/e1jcO2PxsNgc7vsWXsQ/wd/Nrc2N5/t7v7HJn9yf7d2tzd31DN+vrP5dOf5f3ib//EIn0ma+Qk0f1c4+c79Tj4bT2o/ht0gSoOel8VedhF4B2O/C3/O4n525SeB9yqeRD0/C+PIaxycvWp68DNIvDgKanHijWIo0o2jLAk7kwweDBmc5w.........",
  "uuid": "72c3c395707be7da6e26841bb9475ec96ac06687cdf5ea55796202801e658d0bafe257109ec7eebd1814ca5c76b8be5f03d3233b704fd297e8fcb81dbab7305e",
  "timestamp": {
    "seconds": 1476936384,
    "nanos": 762271536
  },
  "nonce": "PoSNNChCKd07Zs6yhq1rELq5Ccl3llQc",
  "cert": "MIICTjCCAfWgAwIBAgIQDGBmkNuYRHSliV7jSnH1MjAKBggqhkjOPQQDAzApMQswCQYDVQQGEwJVUzEMMAoGA1UEChMDSUJNMQwwCgYDVQQDEwN0Y2EwHhcNMTYxMDIwMDQwNTI0WhcNMTcwMTE4MDQwNTI0WjA7MQswCQYDVQQGEwJVUzEMMAoGA1UEChMDSUJNMR4wHAYDVQQDDBVkYXNoYm9hcmR1c2VyX3R5cGUxXzAwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQlhbRj1/FEdRQbqbMut5dfzX13A1lXzlxIuCIvFmR8b9/nHVuLJck8HIizuHtsqkFq4vDqPqaNrBoW3U/fi+G7o4HsMIHpMA4GA1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8EAjAAMA0GA1UdDgQGBAQBAgMEMA8GA1UdIwQIMAaABAECAwQwTQYGKgMEBQYHAQH/BEA187+DA+DNcWcGuId+ULDeX6sliQMD01ikz8XgHme7nhaqLDMMcTOLQy5g552aH1SrdM4VBSLhtYlVCMMlWn89MFoGBioDBAUGCARQOI/vAW5lmwAc3GcBU9R97IOGW9EKKPciV4Ov/gIHL2RDBM9REJ4ErvaafN7GlYy0E3ZwsIQNr4qM0QA3ojMid1NITNXH/y/UMykyzvY/ATQwCgYIKoZIzj0EAwMDRwAwRAIgKtqz/xRQUgKrv48EiuHS8XzMErYckGvAWPirTsh8PFUCIDZF/lAbj9uW2oq5FiwL47R4ALPWMuQsrcPBh9Vx2JhG",
  "signature": "MEQCIFPvLCoL6PogUpLxUyUs8zZ70y/KnbBnEiEvuwhgDTbtAiBwJNC5tjQzaRufdV4dGMaGRl9lzlxTgQm/2t5ejlQogA=="
}
```

- ブロックチェーンから個々のトランザクションの内容を取得するAPI
    - Block の `transactions` と内容は同じ
- payload の長さのみ異なるのはなぜか？
    - Block の `transaction` が省略されている？
    - それをデコードすると3MBになる。なぜか？
    - ステートや実行環境も含む？

# Network API

## GET /network/peers

```
curl -X GET --header "Accept: application/json" "https://1ba11756fe4d445e8f380701269a1075-vp1.us.blockchain.ibm.com:444/network/peers"
{
  "peers": [
    {
      "ID": {
        "name": "vp3"
      },
      "address": "1ba11756fe4d445e8f380701269a1075-vp3.us.blockchain.ibm.com:30304",
      "type": 1,
      "pkiID": "1B9LHNu3D8B4cO3WYJ+prpLoOCoGOzG308BvYkGCqKo="
    },
    {
      "ID": {
        "name": "vp2"
      },
      "address": "1ba11756fe4d445e8f380701269a1075-vp2.us.blockchain.ibm.com:30304",
      "type": 1,
      "pkiID": "0KQ+J9WBH4cpQiljmoOeLWHwkgQzQ077JlR3J6fnu4c="
    },
    {
      "ID": {
        "name": "vp0"
      },
      "address": "1ba11756fe4d445e8f380701269a1075-vp0.us.blockchain.ibm.com:30304",
      "type": 1,
      "pkiID": "6D5vTiGCOXVs0Q1IiLNprcC/xJ1PFvFCxdHYRroz2vg="
    },
    {
      "ID": {
        "name": "vp1"
      },
      "address": "1ba11756fe4d445e8f380701269a1075-vp1.us.blockchain.ibm.com:30304",
      "type": 1,
      "pkiID": "Gvu6b/ihMb6Ygq320yMjxkatkl5eOCaTFuiWhUA0yrI="
    }
  ]
}
```

- ピアノードの一覧と、それぞれのネットワークに関する情報を取得するAPI
- `peers.ID.name` はユニークな値
- `address` は grpc の開いているポートであり、REST API や CLI の受け口となるポートとは別
- `type` はピアのタイプ。検証ピアかそうでないか。`['UNDEFINED', 'VALIDATOR', 'NON_VALIDATOR']` の添字
- `pkiID` はネットワークピア向けの PKI ID、ネットワークピアにもPKIがある

# Registrar API
- Registrar API
    - POST /registrar
    - DELETE /registrar/{enrollmentID}
    - GET /registrar/{enrollmentID}
    - GET /registrar/{enrollmentID}/ecert
    - GET /registrar/{enrollmentID}/tcert

## POST /registrar

```
curl -X POST -H 'Accept: application/json' -H 'Content-Type: application/json' -d '{"enrollId":"admin","enrollSecret":"504443dd0f"}' https://4c78f026da5c4b5c86f9d0d216d2eb8e-vp0.us.blockchain.ibm.com:444/registrar
{"OK": "Login successful for user 'admin'."}
```

- 認証局にユーザを登録・ローカルストレージに登録証明書を保存するAPI
- 検証ピアごとにログインできる
- ログインには enrollId と enrollSecret が必要
- ログインするとログイントークンが作成され、そのトークンを元にメンバーシップサービスで証明書を作成する
- ログインするとトランザクションを実行できるようになる

## GET /registrar/{enrollmentID}

```
// ログイン済
curl -X GET -H 'Accept: application/json' -H 'Content-Type: application/json' https://4c78f026da5c4b5c86f9d0d216d2eb8e-vp0.us.blockchain.ibm.com:444/registrar/admin
{"OK": "User admin is already logged in."}
// 未ログイン
curl -X GET -H 'Accept: application/json' -H 'Content-Type: application/json' https://4c78f026da5c4b5c86f9d0d216d2eb8e-vp1.us.blockchain.ibm.com:444/registrar/admin
{"Error": "User admin must log in."}
```

- 認証局にユーザが登録されているかどうかを確認するAPI
- 検証ピアにおけるユーザのログイン状態がわかる
- 参照時はメンバーシップサービスでは何もしない？
    - ログは出ない

## DELETE /registrar/{enrollmentID}
```
curl -X DELETE -H 'Accept: application/json' -H 'Content-Type: application/json' https://4c78f026da5c4b5c86f9d0d216d2eb8e-vp1.us.blockchain.ibm.com:444/registrar/user_type1_0
{"OK": "Deleted login token and directory for user user_type1_0."}
```

- ローカルストレージからユーザのログイントークンを削除するAPI
- 検証ピアにおけるユーザのログイントークンを削除する
- そのユーザでログインしていないときは削除されない
- 削除すると検証サーバにあるローカルストレージからログイントークンが削除される
- ログイントークンが削除されるとログイン状態を参照してもエラーになる
- ログイントークンが削除されるとトランザクションが実行できない
- ログイントークンが削除されると同じユーザにログインしようとしてもエラーになる
    - 一度削除するとマッチングできなくなる
- 削除時はメンバーシップサービスは何もしない？
    - ログは出ない
- 削除後にログインしようとすると
    - CA はトークンを受けて証明書を作ろうとする
    - 証明書を作れずにエラーになる
- 存在しないユーザでログインすると登録されるのか？
    - `{"Error": "rpc error: code = 2 desc = 'Identity or token does not match.'"}` になる
- 複数ユーザでログインしても保持される
- どこかでログインすると別のピアサーバではログインできなくなる
    - 他のサーバでログインしている間はログインできないのか？
    - あるいはログイン情報は一回きりしか使えないか？
- ユーザの登録はどうやるか？
    - NodeSDK であれば可能。REST API では用意されていない

## GET /registrar/{enrollmentID}/ecert

```
curl -X GET --header "Accept: application/json" "https://1ba11756fe4d445e8f380701269a1075-vp1.us.blockchain.ibm.com:444/registrar/WebAppAdmin/ecert"
{
  "OK": "-----BEGIN+CERTIFICATE-----%0AMIIBpTCCAUugAwIBAgIBATAKBggqhkjOPQQDAzApMQswCQYDVQQGEwJVUzEMMAoG%0AA1UEChMDSUJNMQwwCgYDVQQDEwNlY2EwHhcNMTYxMDIwMDQzNTUzWhcNMTcwMTE4%0AMDQzNTUzWjA9MQswCQYDVQQGEwJVUzEMMAoGA1UEChMDSUJNMSAwHgYDVQQDDBdX%0AZWJBcHBBZG1pblxncm91cDFcMDAwMTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IA%0ABDKgvGGxWeL27SO8Z5vjk7r1Tx3DX7ZOJJKt2p5lM9cIzsdy5cPCskmmW0RbZaod%0AghK7GnL4G6RgQIPfeElQCqSjUDBOMA4GA1UdDwEB%2FwQEAwIHgDAMBgNVHRMBAf8E%0AAjAAMA0GA1UdDgQGBAQBAgMEMA8GA1UdIwQIMAaABAECAwQwDgYGUQMEBQYHAQH%2F%0ABAExMAoGCCqGSM49BAMDA0gAMEUCIQCWWJz7H6xH3Fqh6vpShbMv%2BNabOvsFSzJV%0Ast0a9l3CaAIgXK28xUU08SauPNv%2F1kFgV4SFh44%2BdCbTtKx5c3VifEU%3D%0A-----END+CERTIFICATE-----%0A"
}
```

- ローカルストレージからユーザの登録証明書を取得するAPI

## GET /registrar/{enrollmentID}/tcert

```
curl -X GET --header "Accept: application/json" "https://1ba11756fe4d445e8f380701269a1075-vp1.us.blockchain.ibm.com:444/registrar/WebAppAdmin/tcert?count=2"
{
  "OK": [
    "-----BEGIN+CERTIFICATE-----%0AMIICNTCCAdugAwIBAgIQOwpkin7NT%2F%2BOWj0SDH4RkzAKBggqhkjOPQQDAzApMQsw%0ACQYDVQQGEwJVUzEMMAoGA1UEChMDSUJNMQwwCgYDVQQDEwN0Y2EwHhcNMTYxMDIw%0AMDQzNjI4WhcNMTcwMTE4MDQzNjI4WjAxMQswCQYDVQQGEwJVUzEMMAoGA1UEChMD%0ASUJNMRQwEgYDVQQDEwtXZWJBcHBBZG1pbjBZMBMGByqGSM49AgEGCCqGSM49AwEH%0AA0IABDQ7QFZnqd2mqu1fBpoGUvReSssESyaSVXO1xtCLgQ1x0ub51XCr0WFg68Va%0AxTO%2B1%2BWL4RgX8EsZhRTljrDD67OjgdwwgdkwDgYDVR0PAQH%2FBAQDAgeAMAwGA1Ud%0AEwEB%2FwQCMAAwDQYDVR0OBAYEBAECAwQwDwYDVR0jBAgwBoAEAQIDBDBNBgYqAwQF%0ABgcBAf8EQE8Rpgb3CTbF9tsbPqO6EF7IAT9V9IJkfqEnRftvMM6Vb0iRKVuTVcKn%0AML9yS5gJENqrRPxIkJb%2Bd8xtn7Y8pgwwSgYGKgMEBQYIBEBc95kT9B1FCV2WfMk9%0AHk8V6EJ8kJRUtGzETeyURBUrYFblotI2DGFb%2BEKoAvGF%2BIcQ9ZSqamn8vBXvaIMx%0Ac28vMAoGCCqGSM49BAMDA0gAMEUCIFnolGV4nt9qk0Jy7hvBoxpT0L1ha4NOZzum%0AWDVytOn8AiEA1SEakxfuFADI2sex5gmleC%2F1JTe4drOBawcQ97zi%2FrU%3D%0A-----END+CERTIFICATE-----%0A",
    "-----BEGIN+CERTIFICATE-----%0AMIICNTCCAdugAwIBAgIQOwpkin7NT%2F%2BOWj0SDH4RkzAKBggqhkjOPQQDAzApMQsw%0ACQYDVQQGEwJVUzEMMAoGA1UEChMDSUJNMQwwCgYDVQQDEwN0Y2EwHhcNMTYxMDIw%0AMDQzNjI4WhcNMTcwMTE4MDQzNjI4WjAxMQswCQYDVQQGEwJVUzEMMAoGA1UEChMD%0ASUJNMRQwEgYDVQQDEwtXZWJBcHBBZG1pbjBZMBMGByqGSM49AgEGCCqGSM49AwEH%0AA0IABDQ7QFZnqd2mqu1fBpoGUvReSssESyaSVXO1xtCLgQ1x0ub51XCr0WFg68Va%0AxTO%2B1%2BWL4RgX8EsZhRTljrDD67OjgdwwgdkwDgYDVR0PAQH%2FBAQDAgeAMAwGA1Ud%0AEwEB%2FwQCMAAwDQYDVR0OBAYEBAECAwQwDwYDVR0jBAgwBoAEAQIDBDBNBgYqAwQF%0ABgcBAf8EQE8Rpgb3CTbF9tsbPqO6EF7IAT9V9IJkfqEnRftvMM6Vb0iRKVuTVcKn%0AML9yS5gJENqrRPxIkJb%2Bd8xtn7Y8pgwwSgYGKgMEBQYIBEBc95kT9B1FCV2WfMk9%0AHk8V6EJ8kJRUtGzETeyURBUrYFblotI2DGFb%2BEKoAvGF%2BIcQ9ZSqamn8vBXvaIMx%0Ac28vMAoGCCqGSM49BAMDA0gAMEUCIFnolGV4nt9qk0Jy7hvBoxpT0L1ha4NOZzum%0AWDVytOn8AiEA1SEakxfuFADI2sex5gmleC%2F1JTe4drOBawcQ97zi%2FrU%3D%0A-----END+CERTIFICATE-----%0A"
  ]
}
```

- 認証局に登録されているユーザのトランザクション証明書を取得するAPI
- ワンタイム証明書であり、トランザクションに使われる
- `count` の数だけ、同じ証明書が返ってくる

# Chaincode API

## POST /chaincode

```
echo '{
  "jsonrpc": "2.0",
  "method": "deploy",
  "params": {
    "type": 1,
    "chaincodeID": {
      "path": "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02"
    },
    "ctorMsg": {
      "function": "init",
      "args": ["a", "1000", "b", "2000"]
    },
    "secureContext": "admin"
  },
  "id": 1
}' | 
curl -X POST -H 'Content-Type: application/json' -d @- https://1ba11756fe4d445e8f380701269a1075-vp0.us.blockchain.ibm.com:444/chaincode

{
  "jsonrpc": "2.0",
  "result": {
    "status": "OK",
    "message": "28bb2b2316171a706bb2810ec35d095f430877bf443f1061ef0f60bbe753ed440700a5312c16390d3b30199fe9465c3b75d5944358caae01ca81ef28128a1bfb"
  },
  "id": 1
}
```


```
echo '{
  "jsonrpc": "2.0",
  "method": "invoke",
  "params": {
    "type": 1,
    "chaincodeID": {
      "name": "28bb2b2316171a706bb2810ec35d095f430877bf443f1061ef0f60bbe753ed440700a5312c16390d3b30199fe9465c3b75d5944358caae01ca81ef28128a1bfb"
    },
    "ctorMsg": {
      "function": "invoke",
      "args": [ "a", "b", "100" ]
    },
    "secureContext": "{{enroll_id}}"
  },
  "id": 1
}' | 
curl -X POST -H 'Content-Type: application/json' -d @- https://1ba11756fe4d445e8f380701269a1075-vp0.us.blockchain.ibm.com:444/chaincode

{
  "jsonrpc": "2.0",
  "result": {
    "status": "OK",
    "message": "902bcb1f-809e-4a1b-9a3f-3c355cad7a7c"
  },
  "id": 1
}
```

```
echo '{
  "jsonrpc": "2.0",
  "method": "query",
  "params": {
    "type": 1,
    "chaincodeID": {
      "name": "28bb2b2316171a706bb2810ec35d095f430877bf443f1061ef0f60bbe753ed440700a5312c16390d3b30199fe9465c3b75d5944358caae01ca81ef28128a1bfb"
    },
    "ctorMsg": {
      "function": "query",
      "args": [ "a" ]
    },
    "secureContext": "{{enroll_id}}"
  },
  "id": 1
}' | 
curl -X POST -H 'Content-Type: application/json' -d @- https://1ba11756fe4d445e8f380701269a1075-vp0.us.blockchain.ibm.com:444/chaincode

{
  "jsonrpc": "2.0",
  "result": {
    "status": "OK",
    "message": "900"
  },
  "id": 1
}
```

- Chaincode API は三種類ある
    - deploy(設置)
    - invoke(実行)
    - query(参照)
- `type` はチェインコードに使用されている開発言語。` ['UNDEFINED = 0', 'GOLANG = 1', 'NODE = 2']` の添字
- `chaincodeID.name` は invoke と query のリクエストで必ず必要になる
    - deploy 後のレスポンスとしてresultで返ってくる値が Chaincode ID になる
- deploy には トランザクション UUID はない
- invoke するとトランザクション UUID が返ってくる
- チェインコード内の init, invoke, query 関数は deploy, invoke, query と1対1
- チェインコードの書き方が分かる: https://github.com/IBM-Blockchain/learn-chaincode
- query は block が増えない、トランザクションは作成しない
- デプロイされたチェインコードの実体はどこに置かれるか？
    - 検証ピア？レッジャー上？
    - 他のピアで deploy されたら他のピアで invoke できるため、Chaincode は何らかの方法で共有されている
- コードの実行結果はどこか？
    - 実行結果には他のピアの実行結果が引き継がれるため、データも何らかの方法で共有されている
    - レッジャー上にすべて記録されているためそこから計算？
        - Fabric にはワールドステートという概念があり、そこにトランザクション結果を保持する