Qucik Learning Symbol Section 7

Metadata

Key-Value format data can be registered for an account mosaic namespace. The maximum value of data that can be written is 1024 bytes. We make the assumption that both mosaic, namespace and account are created by Alice in this chapter.

7.1 Register for account

Register a Key-Value for the account.


$config = new Configuration();
$config->setHost($NODE_URL);
$client = new GuzzleHttp\Client();
$metaApiInstance = new MetadataRoutesApi($client, $config);

/**
 * メタデータの作成
 * アカウントに登録
 */
$targetAddress = $aliceKey->address;  // メタデータ記録先アドレス
$sourceAddress = $aliceKey->address;  // メタデータ作成者アドレス

// キーと値の設定
$keyId = Metadata::metadataGenerateKey("key_account");
$newValue = "test";

// 同じキーのメタデータが登録されているか確認
$metadataInfo = $metaApiInstance->searchMetadataEntries(
  source_address: $sourceAddress,
  scoped_metadata_key: strtoupper(dechex($keyId)),  // 16進数の大文字の文字列に変換
);

$oldValue = hex2bin($metadataInfo['data'][0]['metadata_entry']['value']); //16進エンコードされたバイナリ文字列をデコード
$updateValue = Metadata::metadataUpdateValue($oldValue, $newValue, true);

$tx = new EmbeddedAccountMetadataTransactionV1(
  network: new NetworkType(NetworkType::TESTNET),
  signerPublicKey: $aliceKey->publicKey,  // 署名者公開鍵
  targetAddress: new UnresolvedAddress($targetAddress),  // メタデータ記録先アドレス
  scopedMetadataKey: $keyId,
  valueSizeDelta: strlen($newValue) - strlen($oldValue),
  value: $updateValue,
);

// マークルハッシュの算出
$embeddedTransactions = [$tx];
$merkleHash = $facade->hashEmbeddedTransactions($embeddedTransactions);

// アグリゲートTx作成
$aggregateTx = new AggregateCompleteTransactionV2(
  network: new NetworkType(NetworkType::TESTNET),
  signerPublicKey: $aliceKey->publicKey,
  deadline: new Timestamp($facade->now()->addHours(2)),
  transactionsHash: $merkleHash,
  transactions: $embeddedTransactions,
);
// 手数料
$facade->setMaxFee($aggregateTx, 100);

// 署名
$sig = $aliceKey->signTransaction($aggregateTx);
$payload = $facade->attachSignature($aggregateTx, $sig);

$apiInstance = new TransactionRoutesApi($client, $config);

// アナウンス
try {
  $result = $apiInstance->announceTransaction($payload);
  echo $result . PHP_EOL;
} catch (Exception $e) {
  echo 'Exception when calling TransactionRoutesApi->announceTransaction: ', $e->getMessage(), PHP_EOL;
}
$hash = $facade->hashTransaction($aggregateTx);
echo "\n===トランザクションハッシュ===" . PHP_EOL;
echo $hash . PHP_EOL;

Registration of metadata requires a signature of the account to which it is recorded. Even if the registration destination account and the sender account are the same, an aggregate transaction is required.

When registering metadata to different accounts, use "signTransactionWithCosignatories" to sign it.


$bobKey = $facade->createAccount(new PrivateKey('ED949592C90CA58A16CB5BEC303DB011A48373063DDB0C4CFD6DFD01Fxxxxxx'));
$targetAddress = $bobKey->address;  // メタデータ記録先アドレス
$sourceAddress = $aliceKey->address;  // メタデータ作成者アドレス

// キーと値の設定
$keyId = Metadata::metadataGenerateKey("key_account");
$newValue = "test";

// 同じキーのメタデータが登録されているか確認
$metadataInfo = $metaApiInstance->searchMetadataEntries(
  target_address: $targetAddress,
  source_address: $sourceAddress,
  scoped_metadata_key: strtoupper(dechex($keyId)),  // 16進数の大文字の文字列に変換
);

$oldValue = hex2bin($metadataInfo['data'][0]['metadata_entry']['value']); //16進エンコードされたバイナリ文字列をデコード
$updateValue = Metadata::metadataUpdateValue($oldValue, $newValue, true);

$tx = new EmbeddedAccountMetadataTransactionV1(
  network: new NetworkType(NetworkType::TESTNET),
  signerPublicKey: $aliceKey->publicKey,  // 署名者公開鍵
  targetAddress: $targetAddress,  // メタデータ記録先アドレス
  scopedMetadataKey: $keyId,
  valueSizeDelta: strlen($newValue) - strlen($oldValue),
  value: $updateValue,
);

// マークルハッシュの算出
$embeddedTransactions = [$tx];
$merkleHash = $facade->hashEmbeddedTransactions($embeddedTransactions);

// アグリゲートTx作成
$aggregateTx = new AggregateCompleteTransactionV2(
  network: new NetworkType(NetworkType::TESTNET),
  signerPublicKey: $aliceKey->publicKey,
  deadline: new Timestamp($facade->now()->addHours(2)),
  transactionsHash: $merkleHash,
  transactions: $embeddedTransactions,
);
// 手数料
$facade->setMaxFee($aggregateTx, 100, 1);

// 作成者による署名
$sig = $aliceKey->signTransaction($aggregateTx);
$facade->attachSignature($aggregateTx, $sig);

// 記録先アカウントによる連署
$coSig = $bobKey->cosignTransaction($aggregateTx);
array_push($aggregateTx->cosignatures, $coSig);

$payload = ['payload' => strtoupper(bin2hex($aggregateTx->serialize()))];

$apiInstance = new TransactionRoutesApi($client, $config);

// アナウンス
try {
  $result = $apiInstance->announceTransaction($payload);
  echo $result . PHP_EOL;
} catch (Exception $e) {
  echo 'Exception when calling TransactionRoutesApi->announceTransaction: ', $e->getMessage(), PHP_EOL;
}

In case you don't know Bob's private key, Aggregate Bonded Transactions which are explained in the chapters that follow or offline signing must be used.

7.2 Register to a mosaic

Register a value with the composite key of the key value/source account for the target mosaic. The signature of the account that created the mosaic is required for registering and updating metadata.


$targetMosaic = '6FA40B0B8B9E392F';
$mosaicApiInstance = new MosaicRoutesApi($client, $config);
$mosaicInfo = $mosaicApiInstance->getMosaic($targetMosaic);
$sourceAddress = $mosaicInfo['mosaic']['owner_address']; // モザイク作成者アドレス

$keyId = Metadata::metadataGenerateKey("key_mosaic");
$newValue = 'test';

// 同じキーのメタデータが登録されているか確認
$metadataInfo = $metaApiInstance->searchMetadataEntries(
  target_id: $targetMosaic,
  source_address: new UnresolvedAddress($sourceAddress),
  scoped_metadata_key: strtoupper(dechex($keyId)),  // 16進数の大文字の文字列に変換
  metadata_type: 1,
);

$oldValue = hex2bin($metadataInfo['data'][0]['metadata_entry']['value']); //16進エンコードされたバイナリ文字列をデコード
$updateValue = Metadata::metadataUpdateValue($oldValue, $newValue, true);

$tx = new EmbeddedMosaicMetadataTransactionV1(
  network: new NetworkType(NetworkType::TESTNET),
  signerPublicKey: $aliceKey->publicKey,  // 署名者公開鍵
  targetMosaicId: new UnresolvedMosaicId(hexdec($targetMosaic)),
  targetAddress: new UnresolvedAddress($sourceAddress),
  scopedMetadataKey: $keyId,
  valueSizeDelta: strlen($newValue) - strlen($oldValue),
  value: $updateValue,
);

// マークルハッシュの算出
$embeddedTransactions = [$tx];
$merkleHash = $facade->hashEmbeddedTransactions($embeddedTransactions);

// アグリゲートTx作成
$aggregateTx = new AggregateCompleteTransactionV2(
  network: new NetworkType(NetworkType::TESTNET),
  signerPublicKey: $aliceKey->publicKey,
  deadline: new Timestamp($facade->now()->addHours(2)),
  transactionsHash: $merkleHash,
  transactions: $embeddedTransactions,
);
// 手数料
$facade->setMaxFee($aggregateTx, 100);

// 作成者による署名
$sig = $aliceKey->signTransaction($aggregateTx);
$payload =$facade->attachSignature($aggregateTx, $sig);

$apiInstance = new TransactionRoutesApi($client, $config);

// アナウンス
try {
  $result = $apiInstance->announceTransaction($payload);
  echo $result . PHP_EOL;
} catch (Exception $e) {
  echo 'Exception when calling TransactionRoutesApi->announceTransaction: ', $e->getMessage(), PHP_EOL;
}

7.3 Register for namespace

Register a Key-Value for the namespace. The signature of the account that created the mosaic is required for registering and updating metadata.


//ターゲットと作成者アドレスの設定
$targetNamespace = new NamespaceId(IdGenerator::generateNamespaceId("fugafuga"));

$namespaceApiInstance = new NamespaceRoutesApi($client, $config);
$namespaceInfo = $namespaceApiInstance->getNamespace(substr($targetNamespace, 2));

$sourceAddress = new UnresolvedAddress($namespaceInfo['namespace']['owner_address']); // ネームスペース作成者アドレス

$keyId = Metadata::metadataGenerateKey("key_namespace");
$newValue = 'test';

// 同じキーのメタデータが登録されているか確認
$metadataInfo = $metaApiInstance->searchMetadataEntries(
  target_id: substr($targetNamespace, 2),
  source_address: $sourceAddress,
  scoped_metadata_key: strtoupper(dechex($keyId)),  // 16進数の大文字の文字列に変換
  metadata_type: 2,
);

$oldValue = hex2bin($metadataInfo['data'][0]['metadata_entry']['value']); //16進エンコードされたバイナリ文字列をデコード
$updateValue = Metadata::metadataUpdateValue($oldValue, $newValue, true);

$tx = new EmbeddedNamespaceMetadataTransactionV1(
  network: new NetworkType(NetworkType::TESTNET),
  signerPublicKey: $aliceKey->publicKey,  // 署名者公開鍵
  targetNamespaceId: new NamespaceId($targetNamespace),
  targetAddress: $sourceAddress,
  scopedMetadataKey: $keyId,
  valueSizeDelta: strlen($newValue) - strlen($oldValue),
  value: $updateValue,
);

// マークルハッシュの算出
$embeddedTransactions = [$tx];
$merkleHash = $facade->hashEmbeddedTransactions($embeddedTransactions);

// アグリゲートTx作成
$aggregateTx = new AggregateCompleteTransactionV2(
  network: new NetworkType(NetworkType::TESTNET),
  signerPublicKey: $aliceKey->publicKey,
  deadline: new Timestamp($facade->now()->addHours(2)),
  transactionsHash: $merkleHash,
  transactions: $embeddedTransactions,
);
// 手数料
$facade->setMaxFee($aggregateTx, 100);

// 作成者による署名
$sig = $aliceKey->signTransaction($aggregateTx);
$payload =$facade->attachSignature($aggregateTx, $sig);

$apiInstance = new TransactionRoutesApi($client, $config);

// アナウンス
try {
  $result = $apiInstance->announceTransaction($payload);
  echo $result . PHP_EOL;
} catch (Exception $e) {
  echo 'Exception when calling TransactionRoutesApi->announceTransaction: ', $e->getMessage(), PHP_EOL;
}

7.4 Confirmation

Check the registered metadata.


$metaApiInstance = new MetadataRoutesApi($client, $config);
$metadataInfo = $metaApiInstance->searchMetadataEntries(
  target_address: $aliceKey->address,
  source_address: $aliceAddress,
);
echo "\n===メタデータ一覧===" . PHP_EOL;
echo $metadataInfo;

Sample output


{
    "data": [
        {
            "id": "66A1127884E82060AFC1D36F",
            "metadataEntry": {
                "version": 1,
                "compositeHash": "376909753F88E724C42E0313C3F98F44E3BDA949827E49889AB75125E180DD5B",
                "sourceAddress": "98E521BD0F024F58E670A023BF3A14F3BECAF0280396BED0",
                "targetAddress": "98E521BD0F024F58E670A023BF3A14F3BECAF0280396BED0",
                "scopedMetadataKey": "7FFFFFFFFFFFFFFF",
                "targetId": {},
                "metadataType": 0,
                "value": "74657374"
            }
        },
        {
            "id": "66A120C284E82060AFC1E5AE",
            "metadataEntry": {
                "version": 1,
                "compositeHash": "77B448E5375D16F44FF3C2E35221759B35438D360BD89DB0679003FFD1E7D9F5",
                "sourceAddress": "98E521BD0F024F58E670A023BF3A14F3BECAF0280396BED0",
                "targetAddress": "98E521BD0F024F58E670A023BF3A14F3BECAF0280396BED0",
                "scopedMetadataKey": "8EF1ED391DB8F32F",
                "targetId": {},
                "metadataType": 0,
                "value": "686F6765"
            }
        },
        {
            "id": "66A1720784E82060AFC260B5",
            "metadataEntry": {
                "version": 1,
                "compositeHash": "D686E984A60295C57F7D7A350CD2B51A3A55CD67BF4F302DE0E22A39D4E9F9A0",
                "sourceAddress": "98E521BD0F024F58E670A023BF3A14F3BECAF0280396BED0",
                "targetAddress": "98E521BD0F024F58E670A023BF3A14F3BECAF0280396BED0",
                "scopedMetadataKey": "D95FCE92728FA600",
                "targetId": {},
                "metadataType": 0,
                "value": "686F6765"
            }
        },
        {
            "id": "66A23EE184E82060AFC38CE6",
            "metadataEntry": {
                "version": 1,
                "compositeHash": "DA221A3B4D09C0C1833A7176E73D3CD2C23B2B4A37A3D124399FC9D104D9EC97",
                "sourceAddress": "98E521BD0F024F58E670A023BF3A14F3BECAF0280396BED0",
                "targetAddress": "98E521BD0F024F58E670A023BF3A14F3BECAF0280396BED0",
                "scopedMetadataKey": "CF217E116AA422E2",
                "targetId": {},
                "metadataType": 1,
                "value": "74657374"
            }
        },
        {
            "id": "66A242D384E82060AFC392DD",
            "metadataEntry": {
                "version": 1,
                "compositeHash": "BB4A767B68E32FE66319BB4DEF98FF23EF1AEE22863DE3E59C04A03F37E9DB7F",
                "sourceAddress": "98E521BD0F024F58E670A023BF3A14F3BECAF0280396BED0",
                "targetAddress": "98E521BD0F024F58E670A023BF3A14F3BECAF0280396BED0",
                "scopedMetadataKey": "8B6A8A370873D0D9",
                "targetId": {},
                "metadataType": 2,
                "value": "74657374"
            }
        }
    ],
    "pagination": {
        "pageNumber": 1,
        "pageSize": 10
    }
}
The metadataType is as follows.
metadataType
{0: 'Account', 1: 'Mosaic', 2: 'Namespace'}

7.4.1 Note

While metadata has the advantage of providing quick access to information by Key-Value, it should be noted that it needs updating. Updating requires the signatures of the issuer account and the account to which it is registered, so it should only be used if both accounts can be trusted.

7.5 Tips for use

7.5.1 Proof of eligibility

We described proof of ownership in the Mosaic chapter and domain linking in the Namespace chapter. By receiving metadata issued by an account linked from a reliable domain can be used for proofing of ownership of eligibility within that domain.

DID (Decentralized identity)

The ecosystem is divided into issuers, owners and verifiers, e.g. students own the diplomas issued by universities, and companies verify the certificates presented by the students based on the public keys published by the universities. There is no platform-dependent or third party-dependent information required for this verification. By utilising metadata in this way, universities can issue metadata to accounts owned by students, and companies can verify the proof of graduation listed in the metadata with the university's public key and the student's mosaic (account) proof of ownership.