PHPを使ってSymbolブロックチェーンのトランザクションを送信する


この記事は「自分の得意なプログラミング言語でSymbolブロックチェーンを動かす方法」をPHPで実践したものです。

https://qiita.com/nem_takanobu/items/09b6b687f3cbe10af945

PHPで様々なトランザクションを作成する方法はこちらをご参考ください。

https://qiita.com/nem_takanobu/items/c136b80b97988da2d0e6


### アカウント作成

```php
$sign_pair = sodium_crypto_sign_keypair();
$sign_secret = sodium_crypto_sign_secretkey($sign_pair);
$sign_public = sodium_crypto_sign_publickey($sign_pair);

echo 'Secretkey: ' . substr(sodium_bin2hex($sign_secret), 0, 64) . PHP_EOL;
echo 'PublicKey: ' . sodium_bin2hex($sign_public) . PHP_EOL;
```


### アカウント復元

```php
//Secretkey: 94ee0f4d7fe388ac4b04a6a6ae2ba969617879b83616e4d25710d688a89d80c7
//PublicKey: 5f594dfc018578662e0b5a2f5f83ecfb1cda2b32e29ff1d9b2c5e7325c4cf7cb

$sign_secret = sodium_hex2bin("94ee0f4d7fe388ac4b04a6a6ae2ba969617879b83616e4d25710d688a89d80c75f594dfc018578662e0b5a2f5f83ecfb1cda2b32e29ff1d9b2c5e7325c4cf7cb");
$sign_public = sodium_crypto_sign_publickey_from_secretkey($sign_secret);

echo 'Secretkey: ' . substr(sodium_bin2hex($sign_secret), 0, 64) . PHP_EOL;
echo 'PublicKey: ' . sodium_bin2hex($sign_public) . PHP_EOL;
```

php sodiumの仕様なのかSecretkeyが sign_secret + sign_public という構成をとっています。
つまり、sign_publicも控えておかないとアカウントが復元できません。
この点、何か知っている人がいればご助言ください。

### トランザクション構築

```php
use Base32\Base32;

$deadline_time = ((time()  + 7200) - 1637848847) * 1000;

$reserved1 = "00000000";
$signature = "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
$signer = sodium_bin2hex($sign_public);
$reserved2 = "00000000";
$version = bin2hex(pack('C', 1));
$networkType = bin2hex(pack('C', 152));
$txType = bin2hex(pack('v', 16724));
$fee = bin2hex(pack('P', 190000000));
$deadline = bin2hex(pack('P', $deadline_time));
$recipientAddress  = bin2hex(Base32::decode("TBUXMJAYYW3EH3XHBZXSBVGVKXKZS4EH26TINKI"));
$mosaicCount = bin2hex(pack('C', 1));
$txReserved = "00" . "00000000";
$mosaicId = bin2hex(pack('P', hexdec("3A8416DB2D53B6C8")));
$mosaicAmount = bin2hex(pack('P', 100));
$message = "00" . bin2hex('Hello PHP! Welcome to Symbol world!');
$messageSize = bin2hex(pack('v', strlen($message) / 2));

$verifiableData = 
	$version
	.$networkType
	.$txType
	.$fee
	.$deadline
	.$recipientAddress
	.$messageSize
	.$mosaicCount
	.$txReserved
	.$mosaicId
	.$mosaicAmount
	.$message;

```
### トランザクション署名

```php
$payload = "7fccd304802016bebbcd342a332f91ff1f3bb5e902988b352697be245f48e836" . $verifiableData;

$signature = sodium_bin2hex(sodium_crypto_sign_detached(sodium_hex2bin($payload), $sign_secret));
echo 'Signature: ' . $signature . PHP_EOL;
```

### トランザクションの通知

ノードにトランザクションを通知します。

```php
$txSize = bin2hex(pack('V', strlen($verifiableData) / 2 + 108));
$txBuffer = 
	$txSize
	.$reserved1
	.$signature
	.$signer
	.$reserved2
	.$verifiableData;

echo $txBuffer . PHP_EOL;

$node = "https://sym-test-01.opening-line.jp:3001";
$params = array(
    "payload" => $txBuffer
);
$params = json_encode($params); // json化
$header = array(
    "Content-Type: application/json",
);

$context = array(
    "http" => array(
        "method"  => 'PUT',
        "header"  => implode("\r\n", $header),
        "content" => $params
    )
);

$json_response = file_get_contents($node . "/transactions" ,false,stream_context_create($context));
echo $json_response . PHP_EOL;
echo $http_response_header . PHP_EOL;
```

### 確認

トランザクションのハッシュ値を出力してノードに照会します。

```php
$digest = hash('sha3-256',
	sodium_hex2bin(
		$signature . $signer . "7fccd304802016bebbcd342a332f91ff1f3bb5e902988b352697be245f48e836" . $verifiableData
	)
);

echo "txhash: " . $digest. PHP_EOL;
echo $node . "/transactionStatus/" . $digest . PHP_EOL;
echo $node . "/transactions/confirmed/" . $digest . PHP_EOL;
echo "https://testnet.symbol.fyi/transactions/" . $digest . PHP_EOL;
```

複雑なトランザクション送信についてはまた後日に。