はじめに
カタパルトでは、APIノードとmongoDBとRESTゲートウェイを建てるのが一般的です。
そして、これに加えて、アプリケーションサーバーなどを建てることになると思います。
しかし、そんなリソースがない場合もあると思います。APIノードとアプリケーションだけでなんとかしたいと思うこともあるかと思います。
例えば、IoTのような。ミニPC内にノードを建てて定期的にトランザクションを送信するなど。
そんな場合に備えて、Node.jsを使ってAPIノードにトランザクションを送る方法を試してみようと思います。
やる
APIノード起動
https://github.com/tech-bureau/catapult-service-bootstrap/tree/v0.3.0 などでノードを起動します。その際、APIノードの7900番にアクセスできるようにしておきます。
catapult-restの仕様
まず、catapult-restの仕様を調べます。
APIノードへの接続は、Node.jsのNetを使っているようです。catapult-sdkを使って、ノード認証して、そのあとでデータを送信しているようです。
以下のソースを読みました。
- index.js
- connectionService.js
- catapultConnection.js
- routeUtils.js
- transactionRoutes.js
あとはこれを真似して作ればいいだけです。
フォルダ構成
まずは、プロジェクトを作ります。npm init -y
とかで。
次に、下記リポジトリからcatapult-sdk
をフォルダをごとコピーしてきます。
そのあと、package.json
にリンク情報を書きます。
"dependencies": {
"catapult-sdk": "link:catapult-sdk"
}
yarn install
します(npm i
ではだめです)。するとシンボリックリンクが作られます。
最後に、メインの処理を書くためのindex.js
とかを作ります。
するとフォルダ構成は以下のようになってると思います。
/
│ index.js
│ package.json
│ yarn.lock
├─catapult-sdk
│ │ .babelrc
│ │ .eslintignore
│ │ .eslintrc
│ │ package-lock.json
│ │ package.json
│ │ yarn.lock
│ ├─node_modules
│ ├─src
│ ├─test
│ ├─_build
│ └─_build_browser
└─node_modules
コード
const catapult = require('catapult-sdk');
const net = require('net');
const config = {
clientPrivateKey: '0000000000000000000000000000000000000000000000000000000000000000'
};
const node = {
host: '13.115.141.239',
port: '7910',
publicKey: '6244B76B2385C47872E0EA2B6C746408D8021349A13DCAE007D3F6A58E472D01'
};
const serverSocket = net.createConnection(node.port, node.host);
const apiNodePublicKey = catapult.utils.convert.hexToUint8(node.publicKey);
const clientKeyPair = catapult.crypto.createKeyPairFromPrivateKeyString(config.clientPrivateKey);
const params = {
payload: 'A5000000894A829717A6627C108BD69D56A188659C403A4E2C0CEDBB35F856AFD57713E9ACA553C68803E56E39683A9D18CBAF258BFCE043724C56175C53E425727C050FAC1A6E1D8DE5B17D2C6B1293F1CAD3829EEACF38D09311BB3C8E5A880092DE26039054410000000000000000F475D6151700000090FA39EC47E05600AFA74308A7EA607D145E371B5F4F1447BC0100010044B262C46CEABB850000000000000000',
hash: '',
signer: '',
type: 16724,
networkType: 144
};
serverSocket
.on('error', err => {
console.error(`error raised by ${node.host}:${node.port} connection`, err);
})
.on('close', () => {
console.log('close');
});
catapult.auth.createAuthPromise(serverSocket, clientKeyPair, apiNodePublicKey, console.log).then(() => {
const connection = serverSocket;
const packetHeader = catapult.packet.header;
const createPacketFromBuffer = (data, packetType) => {
const length = packetHeader.size + data.length;
const header = packetHeader.createBuffer(packetType, length);
const buffers = [header, Buffer.from(data)];
return Buffer.concat(buffers, length);
};
const parser = params => {
return catapult.utils.convert.hexToUint8(params.payload)
};
const packetType = catapult.packet.PacketType.pushTransactions;
const packetBuffer = createPacketFromBuffer(parser(params), packetType);
const payload = packetBuffer;
return new Promise((resolve, reject) => {
connection.write(payload, resolve);
})
}).then(() => {
const packetType = catapult.packet.PacketType.pushTransactions;
console.log(
{ message: `packet ${packetType} was pushed to the network via transaction` }
);
serverSocket.destroy();
});
以下の箇所で、APIノードの設定をします。
const config = {
clientPrivateKey: '任意の秘密鍵'
};
const node = {
host: 'ノードのIPかFQDN',
port: 'ノードのポート番号',
publicKey: 'ノードの公開鍵'
};
以下の箇所で、トランザクションを設定します。payload
だけでよいです。
const params = {
payload: 'A5000000894A829717A6627C108BD69D56A188659C403A4E2C0CEDBB35F856AFD57713E9ACA553C68803E56E39683A9D18CBAF258BFCE043724C56175C53E425727C050FAC1A6E1D8DE5B17D2C6B1293F1CAD3829EEACF38D09311BB3C8E5A880092DE26039054410000000000000000F475D6151700000090FA39EC47E05600AFA74308A7EA607D145E371B5F4F1447BC0100010044B262C46CEABB850000000000000000',
hash: '',
signer: '',
type: 16724,
networkType: 144
};
実行
>node index.js
received data with size 8
received data with size 64
writing response of length: 169
received data with size 8
received data with size 64
client challenge verified? true
{ message: 'packet 9 was pushed to the network via transaction' }
close
createAuthPromise
の段階で、なにかをやりとりしているようです。
その次に、トランザクションを送っています。この送ったトランザクションが妥当だったかどうかはわかりません。
RESTゲートウェイに問い合わせるか、mongoDBから情報を取得する必要があります。unconfirmedにすらなっていない場合は、失敗していると思います。
送信データ
APIノードへ送信したデータはこんな感じでした。
AD00000009000000A5000000894A829717A6627C108BD69D56A188659C403A4E2C0CEDBB35F856AFD57713E9ACA553C68803E56E39683A9D18CBAF258BFCE043724C56175C53E425727C050FAC1A6E1D8DE5B17D2C6B1293F1CAD3829EEACF38D09311BB3C8E5A880092DE26039054410000000000000000F475D6151700000090FA39EC47E05600AFA74308A7EA607D145E371B5F4F1447BC0100010044B262C46CEABB850000000000000000
最初の4バイトでデータのサイズを指定します。0xADなので173バイトのデータです。
次の4バイトでパケットタイプを指定します。0x09なので、9です。
パケットタイプが何なのかは、ここに少し載っています。
そのあとに、トランザクションが続いています。
おわりに
おわり