概要
catapult-serverの設定にmaxTransactionLifetime=24h
というのがある。config-network.properties
に記載されており、トランザクションの有効期限に関するものだと思う。
NEMのトランザクションには、Deadline
という項目があり、ミリ秒単位で時刻を指定する。この時刻を過ぎると、承認されていないトランザクションは破棄される。かといって、長く設定することはできず、24時間以内という制限がある。
Aggregate Bonded Txや、Lock Funds Tx、Secret Lock Txなど、承認まで時間がかかるものは、これに気を配る必要がある。(なのでオフチェーン決済なんかは辛そう)
例えば、こちらの例1のような、マルチシグを使って工業製品の品質証明モザイクを送付するような事例では、24時間では足りないと思う。
なので今回は、設定を変更してみて、確かに24時間以上のDeadline
が有効なのかどうかをやってみようと思う。
やってみる
今回は、3つのパターンを設定したチェーンを用意した。
- 初期設定の状態(24時間)
-
maxTransactionLifetime=720h
に設定(30日) -
maxTransactionLifetime=8766000h
に設定(1000年)
それぞれに、以下のDeadline
を設定したトランスファートランザクションをアナウンスしてみる。
- 9.5日後(10進数で820800000、16進数で30EC6A00)
- 35日後(10進数で72024588288、16進数で0x10C5000000)
それで、以下のようになると想定。
チェーン/Deadline | 9.5日後 | 35日後 |
---|---|---|
24時間 | × | - |
30日 | ○ | × |
1000年 | ○ | ○ |
※ペイロード上でのDeadline
は、リトルエンディアン表現であることに注意。
初期設定の状態(24時間)のチェーン
9.5日後に設定したトランザクションを作る。Deadline
は415628FD10000000
。
$ node transfer95.js
payload: A5000000DC9ED42254FD59AB7B4724212E56B2AC6C7250E8D067C77CBA02F3D4D789513132922CEFA1605E4275DA92F3421E08D1DBA65D1350641F02B913ABD336D0A60768599F9BD72D20640DFE45450B68777C8FDEE4B56BDB1A997FB8BD292AE843F2039054410000000000000000415628FD1000000090758EB47C28D6143BAA3DE6A8D9C319B503A1BFD8E789E9E20100010029CF5FD941AD25D58096980000000000
hash: 5EDC333A6AEB3D9FFDAC795CC5EA55AB0D996B2671B873F69F267C2FF19D5377
アナウンスする。
$ curl -X PUT -H 'Content-Type:application/json' -d '{"payload": "A5000000DC9ED42254FD59AB7B4724212E56B2AC6C7250E8D067C77CBA02F3D4D789513132922CEFA1605E4275DA92F3421E08D1DBA65D1350641F02B913ABD336D0A60768599F9BD72D20640DFE45450B68777C8FDEE4B56BDB1A997FB8BD292AE843F2039054410000000000000000415628FD1000000090758EB47C28D6143BAA3DE6A8D9C319B503A1BFD8E789E9E20100010029CF5FD941AD25D58096980000000000"}' http://localhost:3000/transaction
{"message":"packet 9 was pushed to the network via /transaction"}
トランザクションは失敗。理由はFailure_Core_Future_Deadline
。
$ curl http://localhost:3000/transaction/5EDC333A6AEB3D9FFDAC795CC5EA55AB0D996B2671B873F69F267C2FF19D5377/status
{
"hash": "5EDC333A6AEB3D9FFDAC795CC5EA55AB0D996B2671B873F69F267C2FF19D5377",
"status": "Failure_Core_Future_Deadline",
"deadline": [
4247279169,
16
],
"group": "failed"
}
最新のブロック高のタイムスタンプを見てみる
"timestamp": [
3418467958,
16
],
その差は828811211[ms]
で、およそ230時間。だいたい9.5日。想定通りである。
720hに設定(30日)のチェーン
9.5日後に設定したトランザクション
先ほどと全く同じトランザクションをアナウンス。Deadline
は415628FD10000000
。
$ curl -X PUT -H 'Content-Type:application/json' -d '{"payload": "A5000000DC9ED42254FD59AB7B4724212E56B2AC6C7250E8D067C77CBA02F3D4D789513132922CEFA1605E4275DA92F3421E08D1DBA65D1350641F02B913ABD336D0A60768599F9BD72D20640DFE45450B68777C8FDEE4B56BDB1A997FB8BD292AE843F2039054410000000000000000415628FD1000000090758EB47C28D6143BAA3DE6A8D9C319B503A1BFD8E789E9E20100010029CF5FD941AD25D58096980000000000"}' http://localhost:3000/transaction
{"message":"packet 9 was pushed to the network via /transaction"}
成功した。承認済みにもなった。
$ curl http://localhost:3000/transaction/5EDC333A6AEB3D9FFDAC795CC5EA55AB0D996B2671B873F69F267C2FF19D5377/status
{
"group": "confirmed",
"status": "Success",
"hash": "5EDC333A6AEB3D9FFDAC795CC5EA55AB0D996B2671B873F69F267C2FF19D5377",
"deadline": [
4247279169,
16
],
"height": [
3,
0
]
}
35日後に設定したトランザクション
トランザクションを作る。Deadline
はAAFC0B8011000000
。
$ node transfer35.js
payload: A500000034E9A57840113BA3361E45818B9E657B6B72302F4D98B7F9AB7FE4199D619AB0AD04F46A11A5251AD2F40841FA2AA69B62C17D91925B9C931F142C1EF538AA0768599F9BD72D20640DFE45450B68777C8FDEE4B56BDB1A997FB8BD292AE843F2039054410000000000000000AAFC0B801100000090758EB47C28D6143BAA3DE6A8D9C319B503A1BFD8E789E9E20100010029CF5FD941AD25D58096980000000000
hash: D9FF5624BF3D741A60D6908516E740020EF1B0949EE747805CB805FF42AA3459
アナウンスする。
$ curl -X PUT -H 'Content-Type:application/json' -d '{"payload": "A500000034E9A57840113BA3361E45818B9E657B6B72302F4D98B7F9AB7FE4199D619AB0AD04F46A11A5251AD2F40841FA2AA69B62C17D91925B9C931F142C1EF538AA0768599F9BD72D20640DFE45450B68777C8FDEE4B56BDB1A997FB8BD292AE843F2039054410000000000000000AAFC0B801100000090758EB47C28D6143BAA3DE6A8D9C319B503A1BFD8E789E9E20100010029CF5FD941AD25D58096980000000000"}' http://localhost:3000/transaction
{"message":"packet 9 was pushed to the network via /transaction"}
トランザクションは失敗。理由はFailure_Core_Future_Deadline。
$ curl http://localhost:3000/transaction/D9FF5624BF3D741A60D6908516E740020EF1B0949EE747805CB805FF42AA3459/status
{"hash":"D9FF5624BF3D741A60D6908516E740020EF1B0949EE747805CB805FF42AA3459","status":"Failure_Core_Future_Deadline","deadline":[2148269226,17],"group":"failed"}
最新のブロック高のタイムスタンプを見てみる。
"timestamp": [
3418467958,
16
],
これを16進数に直すと、BigEndianで0x10CBC1AE76
。10進数で72137944694
。
トランザクションのDeadline
との差分は、10進数で3024768564
。だいたい35日。
8766000hに設定(1000年)のチェーン
9.5日後に設定したトランザクション
先ほどと全く同じトランザクションをアナウンス。Deadlineは415628FD10000000。
$ curl -X PUT -H 'Content-Type:application/json' -d '{"payload": "A5000000DC9ED42254FD59AB7B4724212E56B2AC6C7250E8D067C77CBA02F3D4D789513132922CEFA1605E4275DA92F3421E08D1DBA65D1350641F02B913ABD336D0A60768599F9BD72D20640DFE45450B68777C8FDEE4B56BDB1A997FB8BD292AE843F2039054410000000000000000415628FD1000000090758EB47C28D6143BAA3DE6A8D9C319B503A1BFD8E789E9E20100010029CF5FD941AD25D58096980000000000"}' http://localhost:3000/transaction
{"message":"packet 9 was pushed to the network via /transaction"}
成功した。
$ curl http://localhost:3000/transaction/5EDC333A6AEB3D9FFDAC795CC5EA55AB0D996B2671B873F69F267C2FF19D5377/status
{
"group": "confirmed",
"status": "Success",
"hash": "5EDC333A6AEB3D9FFDAC795CC5EA55AB0D996B2671B873F69F267C2FF19D5377",
"deadline": [
4247279169,
16
],
"height": [
4,
0
]
}
35日後に設定したトランザクション
先ほどと全く同じトランザクションをアナウンス。DeadlineはAAFC0B8011000000。
$ curl -X PUT -H 'Content-Type:application/json' -d '{"payload": "A500000034E9A57840113BA3361E45818B9E657B6B72302F4D98B7F9AB7FE4199D619AB0AD04F46A11A5251AD2F40841FA2AA69B62C17D91925B9C931F142C1EF538AA0768599F9BD72D20640DFE45450B68777C8FDEE4B56BDB1A997FB8BD292AE843F2039054410000000000000000AAFC0B801100000090758EB47C28D6143BAA3DE6A8D9C319B503A1BFD8E789E9E20100010029CF5FD941AD25D58096980000000000"}' http://localhost:3000/transaction
{"message":"packet 9 was pushed to the network via /transaction"}
こちらも成功した。
$ curl http://localhost:3000/transaction/D9FF5624BF3D741A60D6908516E740020EF1B0949EE747805CB805FF42AA3459/status
{
"group": "confirmed",
"status": "Success",
"hash": "D9FF5624BF3D741A60D6908516E740020EF1B0949EE747805CB805FF42AA3459",
"deadline": [
2148269226,
17
],
"height": [
6,
0
]
}
code
nem2-sdkでトランザクションを作る際は、チェック機能が働くため24時間以上のDeadline
が設定できないようになっている。
そこで、Deadline
を手動で計算し、ペイロードを修正し、再度署名して、再度トランザクションハッシュ導出をしている。
ちなみに、nem2-sdkでのDeadline
のデフォルト値は、2時間となっているようです。
const nem2lib = require("nem2-library");
const nem2Sdk = require("nem2-sdk");
const crypto = require("crypto");
const jssha3 = require('js-sha3');
const Address = nem2Sdk.Address,
Deadline = nem2Sdk.Deadline,
Account = nem2Sdk.Account,
UInt64 = nem2Sdk.UInt64,
NetworkType = nem2Sdk.NetworkType,
PlainMessage = nem2Sdk.PlainMessage,
TransferTransaction = nem2Sdk.TransferTransaction,
Mosaic = nem2Sdk.Mosaic,
MosaicId = nem2Sdk.MosaicId,
TransactionHttp = nem2Sdk.TransactionHttp;
const sha3_512 = jssha3.sha3_512;
const sha3_256 = jssha3.sha3_256;
const recipientAddress = 'SB2Y5ND4FDLBIO5KHXTKRWODDG2QHIN73DTYT2PC';
const transferTransaction = TransferTransaction.create(
Deadline.create(),
Address.createFromRawAddress(recipientAddress),
[new Mosaic(new MosaicId('nem:xem'), UInt64.fromUint(10000000)),],
PlainMessage.create(''),
NetworkType.MIJIN_TEST,
);
const privateKey = '72C95EBB2C20AAA47614BB12AFD7878015016AF27BD12CC5F50DF963583F8B5E';
const account = Account.createFromPrivateKey(privateKey,NetworkType.MIJIN_TEST);
const signedTransaction = account.sign(transferTransaction);
// const signData = signedTransaction.payload.substring((4+64+32)*2,(4+64+32+12)*2)
// .concat('415628FD', '10000000',
// signedTransaction.payload.substring((4+64+32+12+8)*2));
const signData = signedTransaction.payload.substring((4+64+32)*2,(4+64+32+12)*2)
.concat('AAFC0B80', '11000000',
signedTransaction.payload.substring((4+64+32+12+8)*2));
const keypair = nem2lib.KeyPair.createKeyPairFromPrivateKeyString(privateKey);
const signature = nem2lib.KeyPair.sign(keypair, signData);
const newPayload = signedTransaction.payload.substring(0,4*2)
.concat(nem2lib.convert.uint8ToHex(signature),
signedTransaction.payload.substring((4+64)*2,(4+64+32)*2),
signData);
const toHashed = newPayload.substring(4*2,(4+32)*2)
.concat(newPayload.substring((4+64)*2));
const hasher = sha3_256.create();
const hash = hasher.update(Buffer.from(toHashed, 'hex')).hex().toUpperCase();
// const transactionHttp = new TransactionHttp('http://localhost:3000');
// transactionHttp.announce(signedTransaction).subscribe(x => console.log(x),
// err => console.error(err));
// console.log('HASH: ' + signedTransaction.hash);
// console.log('SIGNER: ' + signedTransaction.signer);
// console.log('payload: ' + signedTransaction.payload);
console.log('payload: ' + newPayload);
console.log('hash: ' + hash);
//curl -X PUT -H 'Content-Type:application/json' -d '{"payload": ""}' http://localhost:3000/transaction
所感
Deadline
が変更できることがわかった。これで、例えば署名が揃うまで時間がかかるモデルにも適用できると思う。
ただし、厳密には数日間トランザクションが未承認のままで存在していることを確認する必要がある。
Deadline
を長くとると、未承認トランザクションがたまっていくので、長くしすぎにも注意。