Help us understand the problem. What is going on with this article?

AccountPropertiesAddressTransactionを送信するには

More than 1 year has passed since last update.

はじめに

カタパルトはBisonにアップデートされました。

https://blog.nem.io/catapult-bison-update/

Account propertiesというのがあります。

こちら、cataplt-serverは対応されましたが、catapult-restとnem2-sdkは開発中のようです。なので、そのあたりのガイドはまだ出ていません。(2019/01/19)

ですが、機能としてはあると思うので、やってみようと思います。

プロパティは、アカウントブロックにします。

スキーマ

どんなトランザクションを作ればいいかを探します。

それっぽいところを探した結果、こちらが参考になりそうです。

https://github.com/nemtech/catapult-rest/blob/master/catapult-sdk/src/plugins/accountProperties.js

account_properties
    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とか。

https://github.com/nemtech/catapult-rest/blob/master/catapult-sdk/src/plugins/lock.js

secret_proof
            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

トランザクションを送った後、どうやって設定した情報を見るのでしょうか。

このあたりを参考にします。

https://github.com/nemtech/catapult-rest/blob/master/rest/src/plugins/routes/accountPropertiesRoutes.js

        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

portclientPrivateKeyapiNode.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"
}

おわりに

ウォレットなどは、アカウントフィルターが入っているかどうかをチェックする必要がありそうです。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away