Skip to content

Instantly share code, notes, and snippets.

@YoshihitoAso
Last active February 24, 2017 05:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save YoshihitoAso/123bdc387c2bd05e87962e3c7a00fc41 to your computer and use it in GitHub Desktop.
Save YoshihitoAso/123bdc387c2bd05e87962e3c7a00fc41 to your computer and use it in GitHub Desktop.
BighainDBを利用したMultiSigのサンプル(2017/02/23)

BighainDBを利用したMultiSigのサンプル(2017/02/23)

  • BigchaiDBバージョン: 0.9.1

以下の流れでAssetを譲渡するようなサンプル。

  1. aliceがAssetを作成
  2. aliceがbobとcarolにAsset(権利)を譲渡(承諾ステータス:未承諾)
  3. bobとcarolが権利の譲渡に承諾(承諾ステータス:承諾)

ここでは、承諾ステータスをmetadataを利用して実現している。

  1. 秘密鍵、公開鍵の作成

まず、alice/bob/carolの秘密鍵、公開鍵を作成する。

from bigchaindb_driver import BigchainDB
bdb = BigchainDB('http://localhost:9984')

from bigchaindb_driver.crypto import generate_keypair
alice, bob, carol = generate_keypair(), generate_keypair(), generate_keypair()

alice/bob/carolの鍵情報をprintしてみる。 本番運用では、秘密鍵(private_key)の情報はセキュアな格納先に保存する。

In [XX]: print(alice)
CryptoKeypair(private_key='CR8UcHxFuhibromFv9FbeuCPcWosUo8ePeZR493Ta8uT', public_key='935LC6QCFygNGxVxSnhchcmN7Ep4PLAwKe2wszsL9wZy')

In [XX]: print(bob)
CryptoKeypair(private_key='2DoV9uipzRmKuuiJujrSTsHzCbpoWagaNL1udskiGzD1', public_key='8BjSsxV11mgij8mqMDY7J8Z2DWuoZzVVovd8bryU6FAT')

In [XX]: print(carol)
CryptoKeypair(private_key='2P7Pq731CNtvhsb9C4tGUnFjcdgnSVzsPbgt8x4ve1fs', public_key='J6qv9m9EPRwyc6PPdhkfVLDSE9DKsPt1BbHB4p5M3Bc3')
  1. aliceがAssetを作成

aliceが新規Asset(権利:right)を作成する。 metadataとしてagreement_statusを付加する。初期設定は値なし。

right = {
    'data': {
        'right': {
            'right_id': 'hoge1234',
            'data_path': 'fuga/fuga',
        },
    },
}

metadata = {'agreement_status': ''}

Asset作成用のトランザクションを生成する。 Asset作成はaliceが自身を送付先とするトランザクションを起こすことで実現する。

prepared_creation_tx = bdb.transactions.prepare(
    operation='CREATE',
    signers=alice.public_key,
    asset=right,
    metadata=metadata,
)

生成されたトランザクション(prepared_creation_tx)の内容を見てみる。 署名前のinputsの状態が確認できる。

In [XX]: prepared_creation_tx
Out[XX]:
{'asset': {'data': {'right': {'data_path': 'fuga/fuga',
    'right_id': 'hoge1234'}}},
 'id': '9e3a37975dc37a933c8bd986253116be3f533c2a4b71c68c3b893d0a2aa3b5e3',
 'inputs': [{'fulfillment': {'bitmask': 32,
    'public_key': '935LC6QCFygNGxVxSnhchcmN7Ep4PLAwKe2wszsL9wZy',
    'signature': None,
    'type': 'fulfillment',
    'type_id': 4},
   'fulfills': None,
   'owners_before': ['935LC6QCFygNGxVxSnhchcmN7Ep4PLAwKe2wszsL9wZy']}],
 'metadata': {'agreement_status': ''},
 'operation': 'CREATE',
 'outputs': [{'amount': 1,
   'condition': {'details': {'bitmask': 32,
     'public_key': '935LC6QCFygNGxVxSnhchcmN7Ep4PLAwKe2wszsL9wZy',
     'signature': None,
     'type': 'fulfillment',
     'type_id': 4},
    'uri': 'cc:4:20:d2WN0UxwFQFRczXbR_e6YxsQnTCmvb98lmGdIX1cdQA:96'},
   'public_keys': ['935LC6QCFygNGxVxSnhchcmN7Ep4PLAwKe2wszsL9wZy']}],
 'version': '0.9'}

次に、 alice の秘密鍵(alice.private_key)でトランザクションを署名する。

fulfilled_creation_tx = bdb.transactions.fulfill(
     prepared_creation_tx, private_keys=alice.private_key)

署名後のトランザクションの状態は以下のようになる。

In [XX]: fulfilled_creation_tx
Out[XX]:
{'asset': {'data': {'right': {'data_path': 'fuga/fuga',
    'right_id': 'hoge1234'}}},
 'id': '9e3a37975dc37a933c8bd986253116be3f533c2a4b71c68c3b893d0a2aa3b5e3',
 'inputs': [{'fulfillment': 'cf:4:d2WN0UxwFQFRczXbR_e6YxsQnTCmvb98lmGdIX1cdQDK9NP7getGDVvfKosObag_91VqHy83-fWOTOeKLE34deB0Lj8XF-nKTHTV7q-JDEljDDcGI6JjVMypI3ApFZ4N',
   'fulfills': None,
   'owners_before': ['935LC6QCFygNGxVxSnhchcmN7Ep4PLAwKe2wszsL9wZy']}],
 'metadata': {'agreement_status': ''},
 'operation': 'CREATE',
 'outputs': [{'amount': 1,
   'condition': {'details': {'bitmask': 32,
     'public_key': '935LC6QCFygNGxVxSnhchcmN7Ep4PLAwKe2wszsL9wZy',
     'signature': None,
     'type': 'fulfillment',
     'type_id': 4},
    'uri': 'cc:4:20:d2WN0UxwFQFRczXbR_e6YxsQnTCmvb98lmGdIX1cdQA:96'},
   'public_keys': ['935LC6QCFygNGxVxSnhchcmN7Ep4PLAwKe2wszsL9wZy']}],
 'version': '0.9'}

transaction-id(id)を取得しておく。

In [XX]: txid_c = fulfilled_creation_tx['id']

In [XX]: txid_c
Out[XX]: '9e3a37975dc37a933c8bd986253116be3f533c2a4b71c68c3b893d0a2aa3b5e3'

署名を行ったらネットワークにトランザクションを送信(send)する。

sent_creation_tx = bdb.transactions.send(fulfilled_creation_tx)

BigchainDBには以下のようなログが出力される(ログレベルはINFOレベル)。

INFO:bigchaindb.pipelines.block:Write new block bec1a29f807a405196115994775178781b77806a43f058e0d0546e76ffb9c1f2 with 1 transactions
INFO:bigchaindb.pipelines.vote:Voting 'valid' for block bec1a29f807a405196115994775178781b77806a43f058e0d0546e76ffb9c1f2
[2017-02-23 19:30:36 +0900] [6562] [INFO] Handling signal: winch

ネットワーク上でコンセンサスされると、トランザクションがvalidの状態になる。 トランザクションの状態(status)はtransaction-idを指定して、以下のように取得できる。

In [XX]: bdb.transactions.status(txid_c)
Out[XX]:
{'_links': {'tx': '/transactions/9e3a37975dc37a933c8bd986253116be3f533c2a4b71c68c3b893d0a2aa3b5e3'},
 'status': 'valid'}
  1. aliceがbobとcarolにAssetを譲渡

譲渡を行うトランザクションを取得する。未利用のtransactionはtransaction-idを指定して、以下のように取得できる。

creation_tx = bdb.transactions.retrieve(txid_c)

Asset情報の付与を行う。

asset_id = creation_tx['id']

transfer1_asset = {
    'id': asset_id,
}

送信のinput(inputs)を定義する。

output_index = 0
output = creation_tx['outputs'][output_index]

transfer1_input = {
     'fulfillment': output['condition']['details'],
     'fulfills': {
          'output': output_index,
          'txid': creation_tx['id'],
      },
      'owners_before': output['public_keys'],
}

metadataを更新する。agreement_statusはこの時点ではまだ価なしで設定する。

metadata = {'agreement_status': ''}

トランザクションを生成する。 (※bob.public_keycarol.public_keyは上述したAsset作成時に取得したもの。処理・プログラムがまたぐ場合は、再度設定する必要がある。)

prepared_transfer1_tx = bdb.transactions.prepare(
    operation='TRANSFER',
    asset=transfer1_asset,
    inputs=transfer1_input,
    recipients= (bob.public_key, carol.public_key) ,
    metadata=metadata,
)

署名前のトランザクション(prepared_transfer1_tx)の状態は以下の通り。outputsの宛先public_keyがbobとcarolの2つが設定されているのが見て取れる。

In [XX]: prepared_transfer1_tx
Out[XX]:
{'asset': {'id': '9e3a37975dc37a933c8bd986253116be3f533c2a4b71c68c3b893d0a2aa3b5e3'},
 'id': 'd9e9db43a8911d1a4d57ed0c8743a7d136647299e412d5193fe772ac03651aa4',
 'inputs': [{'fulfillment': {'bitmask': 32,
    'public_key': '935LC6QCFygNGxVxSnhchcmN7Ep4PLAwKe2wszsL9wZy',
    'signature': None,
    'type': 'fulfillment',
    'type_id': 4},
   'fulfills': {'output': 0,
    'txid': '9e3a37975dc37a933c8bd986253116be3f533c2a4b71c68c3b893d0a2aa3b5e3'},
   'owners_before': ['935LC6QCFygNGxVxSnhchcmN7Ep4PLAwKe2wszsL9wZy']}],
 'metadata': {'agreement_status': ''},
 'operation': 'TRANSFER',
 'outputs': [{'amount': 1,
   'condition': {'details': {'bitmask': 41,
     'subfulfillments': [{'bitmask': 32,
       'public_key': '8BjSsxV11mgij8mqMDY7J8Z2DWuoZzVVovd8bryU6FAT',
       'signature': None,
       'type': 'fulfillment',
       'type_id': 4,
       'weight': 1},
      {'bitmask': 32,
       'public_key': 'J6qv9m9EPRwyc6PPdhkfVLDSE9DKsPt1BbHB4p5M3Bc3',
       'signature': None,
       'type': 'fulfillment',
       'type_id': 4,
       'weight': 1}],
     'threshold': 2,
     'type': 'fulfillment',
     'type_id': 2},
    'uri': 'cc:2:29:19eiHcacWKDUoA3HlwJVRpNka3fjq8LnyAkw0vs0uKE:206'},
   'public_keys': ['8BjSsxV11mgij8mqMDY7J8Z2DWuoZzVVovd8bryU6FAT',
    'J6qv9m9EPRwyc6PPdhkfVLDSE9DKsPt1BbHB4p5M3Bc3']}],
 'version': '0.9'}

Asset保有者(ここではalice)の署名を行う。 (※alice.private_keyは上述したAsset作成時に取得したもの。処理・プログラムがまたぐ場合は、再度設定する必要がある。)

fulfilled_transfer1_tx = bdb.transactions.fulfill(
    prepared_transfer1_tx,
    private_keys=alice.private_key,
)

署名後のトランザクション情報は以下のようになる。

In [XX]: fulfilled_transfer1_tx
Out[XX]:
{'asset': {'id': '9e3a37975dc37a933c8bd986253116be3f533c2a4b71c68c3b893d0a2aa3b5e3'},
 'id': 'd9e9db43a8911d1a4d57ed0c8743a7d136647299e412d5193fe772ac03651aa4',
 'inputs': [{'fulfillment': 'cf:4:d2WN0UxwFQFRczXbR_e6YxsQnTCmvb98lmGdIX1cdQB1GrsfvfN0-d_2Q3eV6JC6CUA-Mrqb4KlIJETohY3jjEmSjuiqqQo-JTnK3sjUvfvSM2QScLrE1xsC4pce56II',
   'fulfills': {'output': 0,
    'txid': '9e3a37975dc37a933c8bd986253116be3f533c2a4b71c68c3b893d0a2aa3b5e3'},
   'owners_before': ['935LC6QCFygNGxVxSnhchcmN7Ep4PLAwKe2wszsL9wZy']}],
 'metadata': {'agreement_status': ''},
 'operation': 'TRANSFER',
 'outputs': [{'amount': 1,
   'condition': {'details': {'bitmask': 41,
     'subfulfillments': [{'bitmask': 32,
       'public_key': '8BjSsxV11mgij8mqMDY7J8Z2DWuoZzVVovd8bryU6FAT',
       'signature': None,
       'type': 'fulfillment',
       'type_id': 4,
       'weight': 1},
      {'bitmask': 32,
       'public_key': 'J6qv9m9EPRwyc6PPdhkfVLDSE9DKsPt1BbHB4p5M3Bc3',
       'signature': None,
       'type': 'fulfillment',
       'type_id': 4,
       'weight': 1}],
     'threshold': 2,
     'type': 'fulfillment',
     'type_id': 2},
    'uri': 'cc:2:29:19eiHcacWKDUoA3HlwJVRpNka3fjq8LnyAkw0vs0uKE:206'},
   'public_keys': ['8BjSsxV11mgij8mqMDY7J8Z2DWuoZzVVovd8bryU6FAT',
    'J6qv9m9EPRwyc6PPdhkfVLDSE9DKsPt1BbHB4p5M3Bc3']}],
 'version': '0.9'}

署名を行ったらネットワークにトランザクションを送信(send)する。

sent_transfer1_tx = bdb.transactions.send(fulfilled_transfer1_tx)

トランザクションをSENDするとBigchainDBに以下のログが出力される(ログレベルはINFO)

INFO:bigchaindb.pipelines.block:Write new block 5f5d1a3a48dabc48aa919933f919d856ec489b4d4e4a732c82e97accff65ffc8 with 1 transactions
INFO:bigchaindb.pipelines.vote:Voting 'valid' for block 5f5d1a3a48dabc48aa919933f919d856ec489b4d4e4a732c82e97accff65ffc8

しばらくするとtransactionがvalidの状態になる。 validになった状態でbob、carolのAsset保有状況を確認してみる。

  1. bob (public_key : 8BjSsxV11mgij8mqMDY7J8Z2DWuoZzVVovd8bryU6FAT)
* bobの未利用トランザクションに残ができているのが確認できる。

```py
In [XX]: bdb.outputs.get(public_key='8BjSsxV11mgij8mqMDY7J8Z2DWuoZzVVovd8bryU6FAT', unspent='TRUE')
Out[XX]: ['../transactions/d9e9db43a8911d1a4d57ed0c8743a7d136647299e412d5193fe772ac03651aa4/outputs/0']
```
  1. carol (public_key : J6qv9m9EPRwyc6PPdhkfVLDSE9DKsPt1BbHB4p5M3Bc3)
* carolの未利用トランザクションに残ができているのが確認できる。
* transaction-idはbobのものと一致していることが確認できる。

```py
In [XX]: bdb.outputs.get(public_key='J6qv9m9EPRwyc6PPdhkfVLDSE9DKsPt1BbHB4p5M3Bc3', unspent='TRUE')
Out[XX]: ['../transactions/d9e9db43a8911d1a4d57ed0c8743a7d136647299e412d5193fe772ac03651aa4/outputs/0']
```
  1. bobとcarolが権利の譲渡に承諾

再度、bob, carol の共同名義になっているトランザクションIDを取得しなおす。

In [XX]: txid_t1 = fulfilled_transfer1_tx['id']

In [XX]: txid_t1
Out[XX]: 'd9e9db43a8911d1a4d57ed0c8743a7d136647299e412d5193fe772ac03651aa4'

未譲渡のトランザクション情報を取得する。

transfer1_tx = bdb.transactions.retrieve(txid_t1)

Asset情報の付与を行う。

asset_id = transfer1_tx['asset']['id']

transfer2_asset = {
    'id': asset_id,
}

送信のinput(inputs)を定義する。

output_index = 0
output = transfer1_tx['outputs'][output_index]

transfer2_input = {
     'fulfillment': output['condition']['details'],
     'fulfills': {
          'output': output_index,
          'txid': transfer1_tx['id'],
      },
      'owners_before': output['public_keys'],
}

metadataを更新する。agreement_statusを承認済(agreed)に更新する。

metadata = {'agreement_status': 'agreed'}

トランザクションを生成する。 (※bob.public_keycarol.public_keyは上述したAsset作成時に取得したもの。処理・プログラムがまたぐ場合は、再度設定する必要がある。)

prepared_transfer2_tx = bdb.transactions.prepare(
    operation='TRANSFER',
    asset=transfer2_asset,
    inputs=transfer2_input,
    recipients= (bob.public_key, carol.public_key) ,
    metadata=metadata,
)

署名前のトランザクション(prepared_transfer2_tx)の状態は以下の通り。

  • inputsには、1つ前のoutputsの情報が設定されていることが確認できる。
  • outputsの宛先public_keyがbobとcarolの2つが設定されている。
  • metadataは、上述した設定値で設定されている。
In [XX]: prepared_transfer2_tx
Out[XX]:
{'asset': {'id': '9e3a37975dc37a933c8bd986253116be3f533c2a4b71c68c3b893d0a2aa3b5e3'},
 'id': 'b5bfb9dfd408ca8d9eb5b08b14802300ba689ff327fe8c78552d3b990bdf9291',
 'inputs': [{'fulfillment': {'bitmask': 41,
    'subfulfillments': [{'bitmask': 32,
      'public_key': '8BjSsxV11mgij8mqMDY7J8Z2DWuoZzVVovd8bryU6FAT',
      'signature': None,
      'type': 'fulfillment',
      'type_id': 4,
      'weight': 1},
     {'bitmask': 32,
      'public_key': 'J6qv9m9EPRwyc6PPdhkfVLDSE9DKsPt1BbHB4p5M3Bc3',
      'signature': None,
      'type': 'fulfillment',
      'type_id': 4,
      'weight': 1}],
    'threshold': 2,
    'type': 'fulfillment',
    'type_id': 2},
   'fulfills': {'output': 0,
    'txid': 'd9e9db43a8911d1a4d57ed0c8743a7d136647299e412d5193fe772ac03651aa4'},
   'owners_before': ['8BjSsxV11mgij8mqMDY7J8Z2DWuoZzVVovd8bryU6FAT',
    'J6qv9m9EPRwyc6PPdhkfVLDSE9DKsPt1BbHB4p5M3Bc3']}],
 'metadata': {'agreement_status': 'agreed'},
 'operation': 'TRANSFER',
 'outputs': [{'amount': 1,
   'condition': {'details': {'bitmask': 41,
     'subfulfillments': [{'bitmask': 32,
       'public_key': '8BjSsxV11mgij8mqMDY7J8Z2DWuoZzVVovd8bryU6FAT',
       'signature': None,
       'type': 'fulfillment',
       'type_id': 4,
       'weight': 1},
      {'bitmask': 32,
       'public_key': 'J6qv9m9EPRwyc6PPdhkfVLDSE9DKsPt1BbHB4p5M3Bc3',
       'signature': None,
       'type': 'fulfillment',
       'type_id': 4,
       'weight': 1}],
     'threshold': 2,
     'type': 'fulfillment',
     'type_id': 2},
    'uri': 'cc:2:29:19eiHcacWKDUoA3HlwJVRpNka3fjq8LnyAkw0vs0uKE:206'},
   'public_keys': ['8BjSsxV11mgij8mqMDY7J8Z2DWuoZzVVovd8bryU6FAT',
    'J6qv9m9EPRwyc6PPdhkfVLDSE9DKsPt1BbHB4p5M3Bc3']}],
 'version': '0.9'}

inputのオーナー(Asset保有者)であるbob,carolがトランザクションの署名を行う。

fulfilled_transfer2_tx = bdb.transactions.fulfill(
    prepared_transfer2_tx,
    private_keys=(bob.private_key, carol.private_key),
)

※参考: 一部の署名しかなかった場合

In [XX]: fulfilled_transfer2_tx = bdb.transactions.fulfill(
    ...:     prepared_transfer2_tx,
    ...:     private_keys=bob.private_key,
    ...: )
---------------------------------------------------------------------------中略MissingPrivateKeyError: A private key is missing!

署名後のトランザクション情報は以下のようになる。

In [XX]: fulfilled_transfer2_tx
Out[XX]:
{'asset': {'id': '9e3a37975dc37a933c8bd986253116be3f533c2a4b71c68c3b893d0a2aa3b5e3'},
 'id': 'b5bfb9dfd408ca8d9eb5b08b14802300ba689ff327fe8c78552d3b990bdf9291',
 'inputs': [{'fulfillment': 'cf:2:AQIBAgEBYwAEYGrBnFIB1cGLKDdzQ2b6DiBhJVXQZVYPkFXeu9pdXMLU9RhSdCVOlMUMXSA0W4X_dpCwSj02CRcuq3sim_u6W8o0KLTqOYFYVazjOUWuHLxKXYz3JBRxkAHLIkh2UbpvCgABAWMABGD-FeRJF8Yj6BlfRwENFM8L6VhVzn-573TetCY-elSCqJ80_xwQwfYklynbJnak6PUD9P6Zl4kHj5fV7lypQlLx1bBbgcl3wrNR9PejSqnChC-5s6nEVy0TPzZBSlqFBgEA',
   'fulfills': {'output': 0,
    'txid': 'd9e9db43a8911d1a4d57ed0c8743a7d136647299e412d5193fe772ac03651aa4'},
   'owners_before': ['8BjSsxV11mgij8mqMDY7J8Z2DWuoZzVVovd8bryU6FAT',
    'J6qv9m9EPRwyc6PPdhkfVLDSE9DKsPt1BbHB4p5M3Bc3']}],
 'metadata': {'agreement_status': 'agreed'},
 'operation': 'TRANSFER',
 'outputs': [{'amount': 1,
   'condition': {'details': {'bitmask': 41,
     'subfulfillments': [{'bitmask': 32,
       'public_key': '8BjSsxV11mgij8mqMDY7J8Z2DWuoZzVVovd8bryU6FAT',
       'signature': None,
       'type': 'fulfillment',
       'type_id': 4,
       'weight': 1},
      {'bitmask': 32,
       'public_key': 'J6qv9m9EPRwyc6PPdhkfVLDSE9DKsPt1BbHB4p5M3Bc3',
       'signature': None,
       'type': 'fulfillment',
       'type_id': 4,
       'weight': 1}],
     'threshold': 2,
     'type': 'fulfillment',
     'type_id': 2},
    'uri': 'cc:2:29:19eiHcacWKDUoA3HlwJVRpNka3fjq8LnyAkw0vs0uKE:206'},
   'public_keys': ['8BjSsxV11mgij8mqMDY7J8Z2DWuoZzVVovd8bryU6FAT',
    'J6qv9m9EPRwyc6PPdhkfVLDSE9DKsPt1BbHB4p5M3Bc3']}],
 'version': '0.9'}

署名を行ったらネットワークにトランザクションを送信(send)する。

sent_transfer2_tx = bdb.transactions.send(fulfilled_transfer2_tx)

トランザクションをSENDするとBigchainDBに以下のログが出力される(ログレベルはINFO)

INFO:bigchaindb.pipelines.block:Write new block b42d45330784de6c8998875f21b23bd6648c2f1ccef01a0b83ade42f61db313d with 1 transactions
INFO:bigchaindb.pipelines.vote:Voting 'valid' for block b42d45330784de6c8998875f21b23bd6648c2f1ccef01a0b83ade42f61db313d

しばらくするとtransactionがvalidの状態になる。 validになった状態でbob、carolのAsset保有状況を確認してみる。

  • 例) bob (public_key : 8BjSsxV11mgij8mqMDY7J8Z2DWuoZzVVovd8bryU6FAT)

    In [XX]: bdb.outputs.get(public_key='8BjSsxV11mgij8mqMDY7J8Z2DWuoZzVVovd8bryU6FAT', unspent=True)
    Out[XX]: ['../transactions/b5bfb9dfd408ca8d9eb5b08b14802300ba689ff327fe8c78552d3b990bdf9291/outputs/0']

    bobの未利用トランザクションに新規のトランザクションができているのが確認できる。 また一つ前のトランザクションは未利用トランザクションからなくなっていることが確認できる。

    In [XX]: bdb.outputs.get(public_key='8BjSsxV11mgij8mqMDY7J8Z2DWuoZzVVovd8bryU6FAT')
    Out[XX]: ['../transactions/d9e9db43a8911d1a4d57ed0c8743a7d136647299e412d5193fe772ac03651aa4/outputs/0',
    '../transactions/b5bfb9dfd408ca8d9eb5b08b14802300ba689ff327fe8c78552d3b990bdf9291/outputs/0']

    使用済みトランザクションも含めて検索すると、一つ前のトランザクションを抽出することができる。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment