はじめに
カタパルトはBisonにアップデートされました。
Account propertiesというのがあります。
こちら、cataplt-serverは対応されましたが、catapult-restとnem2-sdkは開発中のようです。なので、そのあたりのガイドはまだ出ていません。(2019/01/19)
ですが、機能としてはあると思うので、やってみようと思います。
プロパティは、アカウントブロックにします。
スキーマ
どんなトランザクションを作ればいいかを探します。
それっぽいところを探した結果、こちらが参考になりそうです。
deserialize: parser => {
const transaction = {};
transaction.propertyType = parser.uint8();
transaction.modifications = [];
const propertiesCount = parser.uint8();
for (let i = 0; i < propertiesCount; ++i) {
transaction.modifications.push({
modificationType: parser.uint8(),
value: valueCodec.deserializeValue(parser)
});
}
return transaction;
},
これを、すでに素性が知れているものと比較するとよさげです。
例えば、SecretProofTransactionとか。
deserialize: parser => {
const transaction = {};
transaction.hashAlgorithm = parser.uint8();
transaction.secret = parser.buffer(constants.sizes.hash512);
const proofSize = parser.uint16();
transaction.proof = parser.buffer(proofSize);
return transaction;
},
これをもとに、こうなります。
項目 | 意味 | サイズ |
---|---|---|
propertyType | プロパティタイプ | 1byte |
propertiesCount | 設定するプロパティの数 | 1byte |
modificationType | タイプ | 1byte |
value | 設定値 | 25byte |
modificationType と value は propertiesCount の数だけ出現します。
REST API
トランザクションを送った後、どうやって設定した情報を見るのでしょうか。
このあたりを参考にします。
server.get('/account/properties/:accountId', (req, res, next) => {
const [type, accountId] = routeUtils.parseArgument(req.params, 'accountId', 'accountId');
return db.accountPropertiesByAddresses([accountIdToAddress(type, accountId)])
.then(accountPropertiesSender.sendOne(req.params.accountId, res, next));
});
/account/properties/:accountId
で取得できそうです。
コード
トランザクション送信
const nem2Sdk = require("nem2-sdk");
const jssha3 = require('js-sha3');
const nem2lib = require("nem2-library");
const request = require('request');
const Address = nem2Sdk.Address,
Deadline = nem2Sdk.Deadline,
Account = nem2Sdk.Account,
NetworkType = nem2Sdk.NetworkType,
SecretProofTransaction = nem2Sdk.SecretProofTransaction,
HashType = nem2Sdk.HashType;
const sha3_256 = jssha3.sha3_256;
const ENDPOINT = "http://localhost:3030";
const privateKey = '42A932B6204B61C975719C6AB1B9FC4B11B6903754F87A63B0A05EB892488B89';
const account = Account.createFromPrivateKey(privateKey, NetworkType.MIJIN_TEST);
const blockedAccount = Account.generateNewAccount(NetworkType.MIJIN_TEST);
const blockedAddress = blockedAccount.address;
const blockedAddressDecoded = nem2lib.convert.uint8ToHex(nem2lib.address.stringToAddress(blockedAddress.plain()));
// とりあえずSecretProofTransactionを作る。
const tx1 = SecretProofTransaction.create(
Deadline.create(),
HashType.SHA3_512,
"7448C0D4E2FE58A22BD1AF95282C855EBF4AD7A2B36643A2ADA679DBBACAB078A91CF0AA58600860799EFE2BDC2CBB667376C88E1D4DAF9296963522BF7EC66E",
"25DC8F222E8500EC0E93",
NetworkType.MIJIN_TEST
);
const tx1Signed = account.sign(tx1);
// SecretProofTransactionをAccountPropertiesAddressTransactionに変えていく。
const txPayload =
"94000000" + // size
tx1Signed.payload.substr((4)*2,(64+32+2)*2) + // sign + pubkey + version
"5041" + // type
tx1Signed.payload.substr((4+64+32+2+2)*2,(8+8)*2) + // fee + deadline
"81" + // propertyType
"01" + // propertiesCount
"00" + // modificationType
blockedAddressDecoded; // address decoded
// 署名を作成する
const txPayloadSigningBytes = txPayload.substr(100*2);
const keypair = nem2lib.KeyPair.createKeyPairFromPrivateKeyString(privateKey);
const signatureByte = nem2lib.KeyPair.sign(keypair, txPayloadSigningBytes);
const signature = nem2lib.convert.uint8ToHex(signatureByte);
const signedTxPayload =
txPayload.substr(0,4*2) +
signature +
txPayload.substr((4+64)*2);
console.log(`signedTxPayload: ${signedTxPayload}`);
// トランザクションハッシュを計算する
const hashInputPayload =
signedTxPayload.substr(4*2,32*2) +
signedTxPayload.substr((4+64)*2,32*2) +
signedTxPayload.substr((4+64+32)*2);
const signedTxHash = sha3_256.create().update(Buffer.from(hashInputPayload, 'hex')).hex().toUpperCase();
console.log(`signedTxHash: ${signedTxHash}`);
// 送信する
request({
url: `${ENDPOINT}/transaction`,
method: 'PUT',
headers: {
'Content-Type':'application/json'
},
json: {"payload": signedTxPayload}
}, (error, response, body) => {
console.log(body);
});
設定値を見る
const nem2Sdk = require("nem2-sdk");
const request = require('request');
const Account = nem2Sdk.Account,
NetworkType = nem2Sdk.NetworkType;
const privateKey = '42A932B6204B61C975719C6AB1B9FC4B11B6903754F87A63B0A05EB892488B89';
const account = Account.createFromPrivateKey(privateKey, NetworkType.MIJIN_TEST);
const ENDPOINT = "http://localhost:3030";
request({
url: `${ENDPOINT}/account/properties/${account.publicKey}`,
method: 'GET',
}, (error, response, body) => {
console.log(
error ? error : JSON.stringify(JSON.parse(body), null, "\t")
);
});
カタパルト
まずは、いつもの通りにダウンロードします。
git clone https://github.com/tech-bureau/catapult-service-bootstrap.git
cd catapult-service-bootstrap
vi docker-compose.yml
次に、mongoDBとapi-nodeのポートを開放します。なぜなら、rest-gatewayを別で立ち上げるためです。webSocketのためには、api-node:7902も必要かもしれません。
db:
image: mongo
command: bash -c "mongod --dbpath=/dbdata --bind_ip=db"
stop_signal: SIGINT
ports:
- "27017:27017"
volumes:
- ./data/mongo:/dbdata:rw
- ./bin/bash:/bin-mount
api-node-0:
build: dockerfiles/catapult
command: bash -c "/bin-mount/wait /state/api-node-0-nemgen && /bin/bash /userconfig/startServer.sh"
stop_signal: SIGINT
ports:
- "7900:7900"
volumes:
- ./build/catapult-config/api-node-0/userconfig/resources/:/userconfig/resources/
- ./data/api-node-0:/data:rw
- ./bin/bash:/bin-mount
- ./build/state:/state
depends_on:
- generate-configs
- api-node-0-nemgen
docker-compose up
catapult-rest
そのままでもトランザクションは送れますが、/account/properties/:accountId
が取得できなかったので、最新版のrest-gatewayを新規で立ち上げます。
git clone https://github.com/nemtech/catapult-rest.git
cd catapult-rest
./yarn_setup.sh
cd rest
vi resources/rest.json
port
とclientPrivateKey
とapiNode.publicKey
を設定します。
catapult-service-bootstrap/build/generated-addresses/address.yaml
を見ながら、以下のように設定します。
rest.json の項目 |
設定値 |
---|---|
port |
3030 |
clientPrivateKey |
rest_gateways の2番目のprivate
|
apiNode.publicKey |
api_nodes の1番目のpublic
|
node src/index.js resources/rest.json
結果
トランザクション送信
signedTxPayload: 94000000922F8889D2656BD9F0606FD88BAF29CFCF592C009BCAF58181FE06BE6B35F137640BA56F22C463E6E1D41663F870FCAB927183D188368C2AA70FD4ADCCDE81059D506B695C74BCADCF5ECCE3D78A1C6415C018EF860BF53A0692480D23A2D624039050410000000000000000E48C029714000000810100906A57BD62E195B46F8C2101970F939CCF79CA7B8A4836FCEE
signedTxHash: EF38BE0445F5FE0597766ED04F77EC0409E639DA47A38BCBA2911CA1762415C3
{ message: 'packet 9 was pushed to the network via /transaction' }
設定値を見る
(10回トランザクション送信した後)
{
"accountProperties": {
"address": "kMLX6iIwmUlMj/jyKVUtbYitOAQR9krBhQ==",
"properties": [
{
"propertyType": 129,
"values": [
"kCLZ5eQKN2n8TJqEGSpHdxJt9Wp83ciA2Q==",
"kEn5OAqxrXYx8gKNlbtYUROx+TQEuJ+T2Q==",
"kFh7qHUzfBLRB5sKmGPB4LvALGZhFVtPSg==",
"kKJVdTbxwjb8nn4n2To9zskg6vAfOYZXXg==",
"kKzNFBoHj5svPutOwJBX5J71Zgn59o2PVQ==",
"kLu+XkePZ48xeO4JFfHVPCaAMgxCxqPudQ==",
"kL3gVZegzHM5JYUSIXiYwl/oPS3CqF+cjA==",
"kMgU3IzOklaUJ2b75iwSELVYlNaJv/h1FA==",
"kNK5cXRBeRLWJTchDCFKnMnowIDlDJee0w==",
"kOmPybchTzHteTwP02XLQkpg1533mSjqCg=="
]
},
{
"propertyType": 130,
"values": []
},
{
"propertyType": 132,
"values": []
}
]
}
}
検証
ブロックされたアカウントからトランザクション送信してみます。
トランザクションは失敗しました。ステータスは、こうなりました。
{
"hash": "45BBFC0EA18F6046CF448677C37831B7488CC926EE7AEDF36077582CCBA82854",
"status": "Failure_Property_Signer_Address_Interaction_Not_Allowed",
"deadline": [
2621323912,
20
],
"group": "failed"
}
ちなみに、デフォルトで起動するrest-gatewayだと、このようなステータスになります。
{
"hash": "45BBFC0EA18F6046CF448677C37831B7488CC926EE7AEDF36077582CCBA82854",
"status": "unknown status 0x8050000B",
"deadline": [
2621323912,
20
],
"group": "failed"
}
おわりに
ウォレットなどは、アカウントフィルターが入っているかどうかをチェックする必要がありそうです。