From 92a4a2b89f4cefa8568e2e12b25738685e9b66c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B0=D0=BC=D0=B8=D0=BB=D1=8C=20=D0=9C=D1=83=D1=85?= =?UTF-8?q?=D0=B0=D0=BC=D0=B5=D1=82=D0=B7=D1=8F=D0=BD=D0=BE=D0=B2?= Date: Tue, 11 Dec 2018 12:48:49 +0300 Subject: [PATCH] add tests for converter, tx, wallet --- README.md | 9 +++ src/Minter/SDK/MinterConverter.php | 8 +- src/Minter/SDK/MinterTx.php | 64 ++++++++++----- src/Minter/SDK/MinterWallet.php | 6 +- tests/MinterConverterTest.php | 58 ++++++++++++++ tests/MinterSellAllCoinTxTest.php | 2 +- tests/MinterTxTest.php | 123 +++++++++++++++++++++++++++++ tests/MinterWalletTest.php | 106 +++++++++++++++++++++++++ 8 files changed, 350 insertions(+), 26 deletions(-) create mode 100644 tests/MinterConverterTest.php create mode 100644 tests/MinterTxTest.php create mode 100644 tests/MinterWalletTest.php diff --git a/README.md b/README.md index 733eda1..caf1b60 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,7 @@ This is a pure PHP SDK for working with Minter blockchain - [Get hash of transaction](#get-hash-of-transaction) - [Decode Transaction](#decode-transaction) - [Minter Check](#create-minter-check) +* [Tests](#tests) ## Installing @@ -589,4 +590,12 @@ use Minter\SDK\MinterCheck; $check = new MinterCheck('your Minter address here', 'your pass phrase'); echo $check->createProof(); +``` + +## Tests + +To run unit tests: + +```bash +vendor/bin/phpunit tests ``` \ No newline at end of file diff --git a/src/Minter/SDK/MinterConverter.php b/src/Minter/SDK/MinterConverter.php index b522b84..411165f 100644 --- a/src/Minter/SDK/MinterConverter.php +++ b/src/Minter/SDK/MinterConverter.php @@ -3,6 +3,7 @@ namespace Minter\SDK; use Minter\Library\Helper; +use InvalidArgumentException; /** * Class MinterConverter @@ -39,6 +40,11 @@ public static function convertValue(string $num, string $to) */ public static function convertCoinName(string $symbol): string { - return $symbol . str_repeat(chr(0), 10 - strlen($symbol)); + $countOfNulls = 10 - strlen($symbol); + if($countOfNulls < 0) { + throw new InvalidArgumentException('Coin name could have no more than 10 symbols.'); + } + + return $symbol . str_repeat(chr(0), $countOfNulls); } } \ No newline at end of file diff --git a/src/Minter/SDK/MinterTx.php b/src/Minter/SDK/MinterTx.php index b9ea981..b5b58a9 100644 --- a/src/Minter/SDK/MinterTx.php +++ b/src/Minter/SDK/MinterTx.php @@ -8,7 +8,19 @@ use Minter\Library\ECDSA; use Minter\Library\Helper; use Minter\SDK\MinterCoins\{ - MinterCoinTx, MinterDelegateTx, MinterMultiSendTx, MinterRedeemCheckTx, MinterSellAllCoinTx, MinterSetCandidateOffTx, MinterSetCandidateOnTx, MinterCreateCoinTx, MinterDeclareCandidacyTx, MinterSendCoinTx, MinterUnboundTx, MinterSellCoinTx, MinterBuyCoinTx + MinterCoinTx, + MinterDelegateTx, + MinterMultiSendTx, + MinterRedeemCheckTx, + MinterSellAllCoinTx, + MinterSetCandidateOffTx, + MinterSetCandidateOnTx, + MinterCreateCoinTx, + MinterDeclareCandidacyTx, + MinterSendCoinTx, + MinterUnboundTx, + MinterSellCoinTx, + MinterBuyCoinTx }; /** @@ -332,26 +344,36 @@ protected function prepareResult(array $tx): array { $result = []; foreach($this->structure as $key => $field) { - if($field === 'data') { - $result[$field] = $tx[$key]; - } - elseif($field === 'payload' || $field === 'serviceData') { - $result[$field] = Helper::pack2hex($tx[$key]); - } - elseif($field === 'gasCoin') { - $result[$field] = MinterConverter::convertCoinName( - Helper::pack2hex($tx[$key]) - ); - } - elseif($field === 'signatureData') { - $result[$field] = [ - 'v' => hexdec($tx[$key][0]), - 'r' => $tx[$key][1], - 's' => $tx[$key][2] - ]; - } - else { - $result[$field] = hexdec($tx[$key]); + switch ($field) { + case 'data': + $result[$field] = $tx[$key]; + break; + + case 'payload': + $result[$field] = Helper::pack2hex($tx[$key]); + break; + + case 'serviceData': + $result[$field] = Helper::pack2hex($tx[$key]); + break; + + case 'gasCoin': + $result[$field] = MinterConverter::convertCoinName( + Helper::pack2hex($tx[$key]) + ); + break; + + case 'signatureData': + $result[$field] = [ + 'v' => hexdec($tx[$key][0]), + 'r' => $tx[$key][1], + 's' => $tx[$key][2] + ]; + break; + + default: + $result[$field] = hexdec($tx[$key]); + break; } } diff --git a/src/Minter/SDK/MinterWallet.php b/src/Minter/SDK/MinterWallet.php index 968064b..3938786 100644 --- a/src/Minter/SDK/MinterWallet.php +++ b/src/Minter/SDK/MinterWallet.php @@ -38,14 +38,14 @@ public static function create(): array $privateKey = BIP44::fromMasterSeed($seed)->derive(self::BIP44_SEED_ADDRESS_PATH)->privateKey; $publicKey = self::privateToPublic($privateKey); - $address = self::getAddressFromPublicKey($publicKey); return [ + 'seed' => $seed, 'address' => $address, - 'private_key' => $privateKey, 'mnemonic' => $mnemonic, - 'seed' => $seed + 'public_key' => $publicKey, + 'private_key' => $privateKey ]; } diff --git a/tests/MinterConverterTest.php b/tests/MinterConverterTest.php new file mode 100644 index 0000000..e1c893e --- /dev/null +++ b/tests/MinterConverterTest.php @@ -0,0 +1,58 @@ +assertEquals($data[1], MinterConverter::convertValue($data[0], 'pip')); + } + } + + /** + * Test converting value from pip to bip. + */ + public function testConvertValueToBIP() + { + foreach (self::VALUES as $data) { + $this->assertEquals($data[0], MinterConverter::convertValue($data[1], 'bip')); + } + } + + /** + * Test converting coin name. + */ + public function testConvertCoinName() + { + $this->assertEquals( + 'BIP' . str_repeat(chr(0), 10 - strlen('BIP')), + MinterConverter::convertCoinName('BIP') + ); + + $this->assertEquals( + 'BIPBIPBIPP', + MinterConverter::convertCoinName('BIPBIPBIPP') + ); + } +} diff --git a/tests/MinterSellAllCoinTxTest.php b/tests/MinterSellAllCoinTxTest.php index b53df7e..947722d 100644 --- a/tests/MinterSellAllCoinTxTest.php +++ b/tests/MinterSellAllCoinTxTest.php @@ -6,7 +6,7 @@ use PHPUnit\Framework\TestCase; /** - * Class for testing MinterSellAllCoinTxTest + * Class for testing MinterSellAllCoinTx */ final class MinterSellAllCoinTxTest extends TestCase { diff --git a/tests/MinterTxTest.php b/tests/MinterTxTest.php new file mode 100644 index 0000000..4216290 --- /dev/null +++ b/tests/MinterTxTest.php @@ -0,0 +1,123 @@ + 1, + 'gasPrice' => 1, + 'gasCoin' => 'MNT', + 'type' => 1, + 'data' => [ + 'to' => 'Mx1b685a7c1e78726c48f619c497a07ed75fe00483', + 'value' => '1', + 'coin' => 'MNT' + ], + 'payload' => '', + 'serviceData' => '', + 'signatureType' => 1 + ]; + + /** + * Intermediate transaction representation + */ + const INTERMEDIATE_TX = [ + 'nonce' => 1, + 'gasPrice' => 1, + 'gasCoin' => 'MNT', + 'type' => 1, + 'data' => [ + '4d4e5400000000000000', + '1b685a7c1e78726c48f619c497a07ed75fe00483', + '0de0b6b3a7640000' + ], + 'payload' => '', + 'serviceData' => '', + 'signatureType' => 1, + 'signatureData' => [ + 'v' => 27, + 'r' => '5163017775fefa4d56f71ae50a8ddf361628fddc1101365b2eb6fd9b5dbdc250', + 's' => '2fbdc56b6cf963206f807e2899f05e4fac71f43c9adfd11ea6baa7585b8b8115' + ] + ]; + + /** + * Sender Minter address + */ + const SENDER_ADDRESS = 'Mx31e61a05adbd13c6b625262704bc305bf7725026'; + + /** + * Private key for transaction + */ + const PRIVATE_KEY = '07bc17abdcee8b971bb8723e36fe9d2523306d5ab2d683631693238e0f9df142'; + + /** + * Predefined valid transaction + */ + const VALID_TX = '0xf88301018a4d4e540000000000000001aae98a4d4e5400000000000000941b685a7c1e78726c48f619c497a07ed75fe00483880de0b6b3a7640000808001b845f8431ba05163017775fefa4d56f71ae50a8ddf361628fddc1101365b2eb6fd9b5dbdc250a02fbdc56b6cf963206f807e2899f05e4fac71f43c9adfd11ea6baa7585b8b8115'; + + /** + * Predefined valid hash + */ + const VALID_HASH = 'Mt823ded85fc5dca098836333851144f88d5c8896b'; + + /** + * Test signing. + */ + public function testSign() + { + $tx = new MinterTx(self::TX); + $signature = $tx->sign(self::PRIVATE_KEY); + + $this->assertEquals(self::VALID_TX, $signature); + } + + /** + * Test get sender address. + */ + public function testGetSenderAddress() + { + $tx = new MinterTx(self::VALID_TX); + $address = $tx->getSenderAddress(self::INTERMEDIATE_TX); + + $this->assertEquals(self::SENDER_ADDRESS, $address); + } + + /** + * Test recovering public key. + */ + public function testRecoverPublicKey() + { + $tx = new MinterTx(self::VALID_TX); + + $this->assertEquals( + MinterWallet::privateToPublic(self::PRIVATE_KEY), + $tx->recoverPublicKey(self::INTERMEDIATE_TX) + ); + } + + /** + * Test get hash by transaction. + */ + public function testGetHash() + { + // test getting hash after decoding + $tx = new MinterTx(self::VALID_TX); + $this->assertEquals(self::VALID_HASH, $tx->getHash()); + + // test getting hash after encoding + $tx = new MinterTx(self::TX); + $tx->sign(self::PRIVATE_KEY); + $this->assertEquals(self::VALID_HASH, $tx->getHash()); + } +} diff --git a/tests/MinterWalletTest.php b/tests/MinterWalletTest.php new file mode 100644 index 0000000..0efffb0 --- /dev/null +++ b/tests/MinterWalletTest.php @@ -0,0 +1,106 @@ +assertEquals( + self::VALID_PUBLIC_KEY, + MinterWallet::privateToPublic(self::VALID_PRIVATE_KEY) + ); + } + + /** + * Test retrieve Minter address from public key. + */ + public function testGetAddressFromPublicKey() + { + $this->assertEquals( + self::VALID_ADDRESS, + MinterWallet::getAddressFromPublicKey(self::VALID_PUBLIC_KEY) + ); + } + + /** + * Test validate address. + */ + public function testValidateAddress() + { + $this->assertTrue( + MinterWallet::validateAddress(self::VALID_ADDRESS) + ); + + $invalidAddresses = [ + '', + 'Mx17a9b170a65e92b0f814d5769c7fca6b4accd64', + 'Mx17a9b170a65e92b0f814d5769c7fca6b4accd64634', + '0x17a9b170a65e92b0f814d5769c7fca6b4accd646' + ]; + + foreach ($invalidAddresses as $address) { + $this->assertFalse( + MinterWallet::validateAddress($address) + ); + } + } + + /** + * Test creating wallet. + */ + public function testCreateWallet() + { + $wallet = MinterWallet::create(); + + // check seed length + $this->assertEquals(128, strlen($wallet['seed'])); + + // check mnemonic words count + $this->assertEquals(12, str_word_count($wallet['mnemonic'])); + + // check public key length + $this->assertEquals(130, strlen($wallet['public_key'])); + + // check private key length + $this->assertEquals(64, strlen($wallet['private_key'])); + + // check that address is valid + $this->assertTrue(MinterWallet::validateAddress($wallet['address'])); + + // check that address retrieved from public key + $this->assertEquals( + $wallet['address'], + MinterWallet::getAddressFromPublicKey($wallet['public_key']) + ); + + // check that private key and public key matches + $this->assertEquals( + $wallet['public_key'], + MinterWallet::privateToPublic($wallet['private_key']) + ); + } +}