From f97d4c9397b18c798c6130bd0bfa2436947a3dc3 Mon Sep 17 00:00:00 2001 From: Pavel Rubin Date: Tue, 3 Apr 2018 07:04:47 +0300 Subject: [PATCH 01/17] Remove `to` parameter when publishing contract transaction --- src/Contract.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Contract.php b/src/Contract.php index 72119ac..b6c334a 100644 --- a/src/Contract.php +++ b/src/Contract.php @@ -397,7 +397,6 @@ class Contract if (count($arguments) > 0) { $transaction = $arguments[0]; } - $transaction['to'] = ''; $transaction['data'] = '0x' . $this->bytecode . Utils::stripZero($data); $this->eth->sendTransaction($transaction, function ($err, $transaction) use ($callback){ From 6100a046c570ab3431c4aba7ff9e16732a4a42c3 Mon Sep 17 00:00:00 2001 From: sc0Vu Date: Sat, 14 Apr 2018 15:01:45 +0800 Subject: [PATCH 02/17] Update 'README.md' --- README.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/README.md b/README.md index ee8ecc4..707afc8 100644 --- a/README.md +++ b/README.md @@ -246,6 +246,29 @@ docker-compose exec php ash vendor/bin/phpunit ``` +###### Install packages +Enter container first +``` +docker-compose exec php ash +``` + +1. gmp +``` +apk add gmp-dev +docker-php-ext-install gmp +``` + +2. bcmath +``` +docker-php-ext-install bcmath +``` + +###### Remove extension +Move the extension config from `/usr/local/etc/php/conf.d/` +``` +mv /usr/local/etc/php/conf.d/extension-config-name to/directory +``` + # API Todo. From fa9565043781dc8100f22c084a2ac322cda1dd9b Mon Sep 17 00:00:00 2001 From: sc0Vu Date: Wed, 25 Apr 2018 10:06:30 +0800 Subject: [PATCH 03/17] Update composer.json --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index e503022..6e26cd3 100644 --- a/composer.json +++ b/composer.json @@ -13,7 +13,7 @@ "guzzlehttp/guzzle": "~6.0", "PHP": "^7.1", "kornrunner/keccak": "~1.0", - "phpseclib/phpseclib": "~2.0" + "phpseclib/phpseclib": "~2.0.11" }, "require-dev": { "phpunit/phpunit": "~6.0" From a87010fc4c97bed82e4fdecf965cbd7fad7d64d8 Mon Sep 17 00:00:00 2001 From: sc0Vu Date: Wed, 25 Apr 2018 10:07:06 +0800 Subject: [PATCH 04/17] Add test Add test for toHex(48), thanks @refear99 --- test/unit/HttpProviderTest.php | 4 ++-- test/unit/IntegerFormatterTest.php | 6 ++++++ test/unit/UtilsTest.php | 10 ++++++++++ 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/test/unit/HttpProviderTest.php b/test/unit/HttpProviderTest.php index 3a28bf2..f1ef4bf 100644 --- a/test/unit/HttpProviderTest.php +++ b/test/unit/HttpProviderTest.php @@ -17,7 +17,7 @@ class HttpProviderTest extends TestCase */ public function testSend() { - $requestManager = new HttpRequestManager('http://localhost:8545'); + $requestManager = new HttpRequestManager($this->testHost); $provider = new HttpProvider($requestManager); $method = new ClientVersion('web3_clientVersion', []); @@ -36,7 +36,7 @@ class HttpProviderTest extends TestCase */ public function testBatch() { - $requestManager = new HttpRequestManager('http://localhost:8545'); + $requestManager = new HttpRequestManager($this->testHost); $provider = new HttpProvider($requestManager); $method = new ClientVersion('web3_clientVersion', []); $callback = function ($err, $data) { diff --git a/test/unit/IntegerFormatterTest.php b/test/unit/IntegerFormatterTest.php index 193e19d..1476f64 100644 --- a/test/unit/IntegerFormatterTest.php +++ b/test/unit/IntegerFormatterTest.php @@ -45,5 +45,11 @@ class IntegerFormatterTest extends TestCase $hex = $formatter->format('1', 20); $this->assertEquals($hex, implode('', array_fill(0, 19, '0')) . '1'); + + $hex = $formatter->format(48); + $this->assertEquals($hex, implode('', array_fill(0, 62, '0')) . '30'); + + $hex = $formatter->format('48'); + $this->assertEquals($hex, implode('', array_fill(0, 62, '0')) . '30'); } } \ No newline at end of file diff --git a/test/unit/UtilsTest.php b/test/unit/UtilsTest.php index 50b3f0e..5856b22 100644 --- a/test/unit/UtilsTest.php +++ b/test/unit/UtilsTest.php @@ -87,6 +87,16 @@ class UtilsTest extends TestCase $this->assertEquals('0x', Utils::toHex(0, true)); $this->assertEquals('0x', Utils::toHex(new BigNumber(0), true)); + $this->assertEquals('0x30', Utils::toHex(48, true)); + $this->assertEquals('0x30', Utils::toHex('48', true)); + $this->assertEquals('30', Utils::toHex(48)); + $this->assertEquals('30', Utils::toHex('48')); + + $this->assertEquals('0x30', Utils::toHex(new BigNumber(48), true)); + $this->assertEquals('0x30', Utils::toHex(new BigNumber('48'), true)); + $this->assertEquals('30', Utils::toHex(new BigNumber(48))); + $this->assertEquals('30', Utils::toHex(new BigNumber('48'))); + $this->expectException(InvalidArgumentException::class); $hex = Utils::toHex(new stdClass); } From 02be3f815d42d596d0b9ca68434a8e101f62ff48 Mon Sep 17 00:00:00 2001 From: sc0Vu Date: Wed, 25 Apr 2018 10:25:09 +0800 Subject: [PATCH 05/17] Add ganache container Add ganache container Update 'README.md' --- README.md | 14 ++++++++++++-- docker/docker-compose.yml | 7 +++++++ docker/ganache/Dockerfile | 9 +++++++++ 3 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 docker/ganache/Dockerfile diff --git a/README.md b/README.md index 707afc8..40a6091 100644 --- a/README.md +++ b/README.md @@ -233,7 +233,7 @@ git clone https://github.com/sc0Vu/web3.php.git 2. Copy web3.php to web3.php/docker/app directory and start container. ``` -cp files docker/app && docker-compose up -d php +cp files docker/app && docker-compose up -d php ganache ``` 3. Enter php container and install packages. @@ -241,7 +241,17 @@ cp files docker/app && docker-compose up -d php docker-compose exec php ash ``` -4. Run test script +4. Change testHost in `TestCase.php` +``` +/** + * testHost + * + * @var string + */ +protected $testHost = 'http://ganache:8545'; +``` + +5. Run test script ``` vendor/bin/phpunit ``` diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 730dbe9..9924d78 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -9,3 +9,10 @@ services: volumes: - ./app:/app tty: true + + ganache: + build: + context: ./ganache + dockerfile: Dockerfile + ports: + - "8545" diff --git a/docker/ganache/Dockerfile b/docker/ganache/Dockerfile new file mode 100644 index 0000000..fe4f1ca --- /dev/null +++ b/docker/ganache/Dockerfile @@ -0,0 +1,9 @@ +FROM node:9.11.1-alpine + +MAINTAINER Peter Lai + +RUN npm install -g ganache-cli + +EXPOSE 8545 + +CMD ganache-cli --hostname=0.0.0.0 \ No newline at end of file From 85dc0600175d61a8516d5985c4ebf3c130b6e271 Mon Sep 17 00:00:00 2001 From: Timothy Lopez Date: Fri, 27 Apr 2018 18:20:06 -0600 Subject: [PATCH 06/17] Added getToAddress --- src/Contract.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Contract.php b/src/Contract.php index b6c334a..856148e 100644 --- a/src/Contract.php +++ b/src/Contract.php @@ -233,6 +233,14 @@ class Contract return $this->events; } + /** + * @return string + */ + public function getToAddress() + { + return $this->toAddress; + } + /** * getConstructor * From 5a54ce5903a402168bc1b781faab5d65fdb83cfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luiz=20Smel=C3=A1n?= Date: Wed, 2 May 2018 17:14:53 +0100 Subject: [PATCH 07/17] Fix: issue #71 - Not to limit the size of the string to 64 characters --- src/Contracts/Types/Str.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Contracts/Types/Str.php b/src/Contracts/Types/Str.php index 04e75ba..344f070 100644 --- a/src/Contracts/Types/Str.php +++ b/src/Contracts/Types/Str.php @@ -77,7 +77,7 @@ class Str extends SolidityType implements IType public function outputFormat($value, $name) { $strLen = mb_substr($value, 0, 64); - $strValue = mb_substr($value, 64, 64); + $strValue = mb_substr($value, 64); $match = []; if (preg_match('/^[0]+([a-f0-9]+)$/', $strLen, $match) === 1) { @@ -87,4 +87,4 @@ class Str extends SolidityType implements IType return Utils::hexToBin($strValue); } -} \ No newline at end of file +} From 4eaebd48aa6626026ecb09a079f938651a4a7187 Mon Sep 17 00:00:00 2001 From: sc0Vu Date: Fri, 18 May 2018 12:03:27 +0800 Subject: [PATCH 08/17] Add test for issue 71 --- test/unit/EthabiTest.php | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/test/unit/EthabiTest.php b/test/unit/EthabiTest.php index 2d900ce..321350a 100644 --- a/test/unit/EthabiTest.php +++ b/test/unit/EthabiTest.php @@ -293,4 +293,23 @@ class EthabiTest extends TestCase } } } + + /** + * testIssue71 + * test 33 bytes and 128 bytes string, see: https://github.com/sc0Vu/web3.php/issues/71 + * string generated from: https://www.lipsum.com/ + * + * @return void + */ + public function testIssue71() + { + $abi = $this->abi; + $specialString = 'Lorem ipsum dolor sit amet metus.'; + $encodedString = $abi->encodeParameter('string', $specialString); + $this->assertEquals($specialString, $abi->decodeParameter('string', $encodedString)); + + $specialString = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce pulvinar quam felis, suscipit posuere neque aliquam in cras amet.'; + $encodedString = $abi->encodeParameter('string', $specialString); + $this->assertEquals($specialString, $abi->decodeParameter('string', $encodedString)); + } } \ No newline at end of file From 4fd5d1ab670d1ac27950d056de9f6ebd67e3ebc3 Mon Sep 17 00:00:00 2001 From: sc0Vu Date: Sun, 27 May 2018 22:48:02 +0800 Subject: [PATCH 09/17] Fix #83 Return $fractionLength when number is with decimal point. --- src/Utils.php | 5 ++--- test/unit/UtilsTest.php | 40 +++++++++++++++++++++++++++++----------- 2 files changed, 31 insertions(+), 14 deletions(-) diff --git a/src/Utils.php b/src/Utils.php index fde4c50..fcb4964 100644 --- a/src/Utils.php +++ b/src/Utils.php @@ -284,9 +284,7 @@ class Utils if (is_array($bn)) { // fraction number - list($whole, $fraction, $negative1) = $bn; - - $fractionLength = strlen($fraction->toString()); + list($whole, $fraction, $fractionLength, $negative1) = $bn; if ($fractionLength > strlen(self::UNITS[$unit])) { throw new InvalidArgumentException('toWei fraction part is out of limit.'); @@ -504,6 +502,7 @@ class Utils return [ new BigNumber($whole), new BigNumber($fraction), + strlen($comps[1]), isset($negative1) ? $negative1 : false ]; } else { diff --git a/test/unit/UtilsTest.php b/test/unit/UtilsTest.php index 5856b22..e3e1e29 100644 --- a/test/unit/UtilsTest.php +++ b/test/unit/UtilsTest.php @@ -275,12 +275,24 @@ class UtilsTest extends TestCase $bn = Utils::toWei('1.69', 'ether'); $this->assertEquals($bn->toString(), '1690000000000000000'); + $bn = Utils::toWei('0.01', 'ether'); + $this->assertEquals($bn->toString(), '10000000000000000'); + + $bn = Utils::toWei('0.002', 'ether'); + $this->assertEquals($bn->toString(), '2000000000000000'); + $bn = Utils::toWei(0.1, 'ether'); $this->assertEquals($bn->toString(), '100000000000000000'); $bn = Utils::toWei(1.69, 'ether'); $this->assertEquals($bn->toString(), '1690000000000000000'); + $bn = Utils::toWei(0.01, 'ether'); + $this->assertEquals($bn->toString(), '10000000000000000'); + + $bn = Utils::toWei(0.002, 'ether'); + $this->assertEquals($bn->toString(), '2000000000000000'); + $bn = Utils::toWei('-0.1', 'ether'); $this->assertEquals($bn->toString(), '-100000000000000000'); @@ -541,39 +553,45 @@ class UtilsTest extends TestCase $this->assertEquals($bn->toString(), '-1'); $bn = Utils::toBn('-0.1'); - $this->assertEquals(count($bn), 3); + $this->assertEquals(count($bn), 4); $this->assertEquals($bn[0]->toString(), '0'); $this->assertEquals($bn[1]->toString(), '1'); - $this->assertEquals($bn[2]->toString(), '-1'); + $this->assertEquals($bn[2], 1); + $this->assertEquals($bn[3]->toString(), '-1'); $bn = Utils::toBn(-0.1); - $this->assertEquals(count($bn), 3); + $this->assertEquals(count($bn), 4); $this->assertEquals($bn[0]->toString(), '0'); $this->assertEquals($bn[1]->toString(), '1'); - $this->assertEquals($bn[2]->toString(), '-1'); + $this->assertEquals($bn[2], 1); + $this->assertEquals($bn[3]->toString(), '-1'); $bn = Utils::toBn('0.1'); - $this->assertEquals(count($bn), 3); + $this->assertEquals(count($bn), 4); $this->assertEquals($bn[0]->toString(), '0'); $this->assertEquals($bn[1]->toString(), '1'); - $this->assertEquals($bn[2], false); + $this->assertEquals($bn[2], 1); + $this->assertEquals($bn[3], false); $bn = Utils::toBn('-1.69'); - $this->assertEquals(count($bn), 3); + $this->assertEquals(count($bn), 4); $this->assertEquals($bn[0]->toString(), '1'); $this->assertEquals($bn[1]->toString(), '69'); - $this->assertEquals($bn[2]->toString(), '-1'); + $this->assertEquals($bn[2], 2); + $this->assertEquals($bn[3]->toString(), '-1'); $bn = Utils::toBn(-1.69); $this->assertEquals($bn[0]->toString(), '1'); $this->assertEquals($bn[1]->toString(), '69'); - $this->assertEquals($bn[2]->toString(), '-1'); + $this->assertEquals($bn[2], 2); + $this->assertEquals($bn[3]->toString(), '-1'); $bn = Utils::toBn('1.69'); - $this->assertEquals(count($bn), 3); + $this->assertEquals(count($bn), 4); $this->assertEquals($bn[0]->toString(), '1'); $this->assertEquals($bn[1]->toString(), '69'); - $this->assertEquals($bn[2], false); + $this->assertEquals($bn[2], 2); + $this->assertEquals($bn[3], false); $bn = Utils::toBn(new BigNumber(1)); $this->assertEquals($bn->toString(), '1'); From 9521b2d167c5e5d588391d4a07ed9bd137668a43 Mon Sep 17 00:00:00 2001 From: sc0Vu Date: Mon, 28 May 2018 15:21:18 +0800 Subject: [PATCH 10/17] Check output name is empty --- src/Contracts/Ethabi.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Contracts/Ethabi.php b/src/Contracts/Ethabi.php index 419186e..12ee067 100644 --- a/src/Contracts/Ethabi.php +++ b/src/Contracts/Ethabi.php @@ -249,7 +249,7 @@ class Ethabi $param = mb_strtolower(Utils::stripZero($param)); for ($i=0; $i<$typesLength; $i++) { - if (isset($outputTypes['outputs'][$i]['name'])) { + if (isset($outputTypes['outputs'][$i]['name']) && empty($outputTypes['outputs'][$i]['name']) === false) { $result[$outputTypes['outputs'][$i]['name']] = $solidityTypes[$i]->decode($param, $offsets[$i], $types[$i]); } else { $result[$i] = $solidityTypes[$i]->decode($param, $offsets[$i], $types[$i]); From 80c8c783aeed62a9deb79fe193c380ff05a437b2 Mon Sep 17 00:00:00 2001 From: will Date: Mon, 4 Jun 2018 11:10:31 +0800 Subject: [PATCH 11/17] Change $e to $err --- test/unit/PersonalApiTest.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/unit/PersonalApiTest.php b/test/unit/PersonalApiTest.php index c4538e4..b665cf2 100644 --- a/test/unit/PersonalApiTest.php +++ b/test/unit/PersonalApiTest.php @@ -63,7 +63,7 @@ class PersonalApiTest extends TestCase $personal->newAccount('123456', function ($err, $account) { if ($err !== null) { - return $this->fail($e->getMessage()); + return $this->fail($err->getMessage()); } $this->assertTrue(is_string($account)); }); @@ -81,7 +81,7 @@ class PersonalApiTest extends TestCase // create account $personal->newAccount('123456', function ($err, $account) { if ($err !== null) { - return $this->fail($e->getMessage()); + return $this->fail($err->getMessage()); } $this->newAccount = $account; $this->assertTrue(is_string($account)); @@ -107,7 +107,7 @@ class PersonalApiTest extends TestCase // create account $personal->newAccount('123456', function ($err, $account) { if ($err !== null) { - return $this->fail($e->getMessage()); + return $this->fail($err->getMessage()); } $this->newAccount = $account; $this->assertTrue(is_string($account)); @@ -133,7 +133,7 @@ class PersonalApiTest extends TestCase // create account $personal->newAccount('123456', function ($err, $account) { if ($err !== null) { - return $this->fail($e->getMessage()); + return $this->fail($err->getMessage()); } $this->newAccount = $account; $this->assertTrue(is_string($account)); From 3d8a567054e1b3201603a632d9ea3d2bb6d40c1e Mon Sep 17 00:00:00 2001 From: Arul Date: Thu, 7 Jun 2018 18:02:08 +0800 Subject: [PATCH 12/17] Fix: method validation in both send and call Making sure method is a string and it exists under functions I was trying to call a nonexistent method. Since I passed a string it went through without checking if it exists as a function or not This commit fixes that by changing `&&` to `||` (or) --- src/Contract.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Contract.php b/src/Contract.php index b6c334a..794da74 100644 --- a/src/Contract.php +++ b/src/Contract.php @@ -422,8 +422,8 @@ class Contract $method = array_splice($arguments, 0, 1)[0]; $callback = array_pop($arguments); - if (!is_string($method) && !isset($this->functions[$method])) { - throw new InvalidArgumentException('Please make sure the method is existed.'); + if (!is_string($method) || !isset($this->functions[$method])) { + throw new InvalidArgumentException('Please make sure the method exists.'); } $function = $this->functions[$method]; @@ -468,8 +468,8 @@ class Contract $method = array_splice($arguments, 0, 1)[0]; $callback = array_pop($arguments); - if (!is_string($method) && !isset($this->functions[$method])) { - throw new InvalidArgumentException('Please make sure the method is existed.'); + if (!is_string($method) || !isset($this->functions[$method])) { + throw new InvalidArgumentException('Please make sure the method exists.'); } $function = $this->functions[$method]; @@ -621,4 +621,4 @@ class Contract return $functionData; } } -} \ No newline at end of file +} From ee9855fcbfad32989867d6eeefa39035f169e770 Mon Sep 17 00:00:00 2001 From: sc0Vu Date: Mon, 18 Jun 2018 23:24:29 +0800 Subject: [PATCH 13/17] Change isType regex --- src/Contracts/Types/Address.php | 2 +- src/Contracts/Types/Boolean.php | 2 +- src/Contracts/Types/Bytes.php | 2 +- src/Contracts/Types/DynamicBytes.php | 2 +- src/Contracts/Types/Integer.php | 2 +- src/Contracts/Types/Str.php | 2 +- src/Contracts/Types/Uinteger.php | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Contracts/Types/Address.php b/src/Contracts/Types/Address.php index 3559e04..d366ad7 100644 --- a/src/Contracts/Types/Address.php +++ b/src/Contracts/Types/Address.php @@ -37,7 +37,7 @@ class Address extends SolidityType implements IType */ public function isType($name) { - return (preg_match('/address(\[([0-9]*)\])*/', $name) === 1); + return (preg_match('/^address(\[([0-9]*)\])*/', $name) === 1); } /** diff --git a/src/Contracts/Types/Boolean.php b/src/Contracts/Types/Boolean.php index 3850761..9f8e394 100644 --- a/src/Contracts/Types/Boolean.php +++ b/src/Contracts/Types/Boolean.php @@ -35,7 +35,7 @@ class Boolean extends SolidityType implements IType */ public function isType($name) { - return (preg_match('/bool(\[([0-9]*)\])*/', $name) === 1); + return (preg_match('/^bool(\[([0-9]*)\])*/', $name) === 1); } /** diff --git a/src/Contracts/Types/Bytes.php b/src/Contracts/Types/Bytes.php index 55b13fc..29e7fad 100644 --- a/src/Contracts/Types/Bytes.php +++ b/src/Contracts/Types/Bytes.php @@ -36,7 +36,7 @@ class Bytes extends SolidityType implements IType */ public function isType($name) { - return (preg_match('/bytes([0-9]{1,})?(\[([0-9]*)\])*/', $name) === 1); + return (preg_match('/^bytes([0-9]{1,})?(\[([0-9]*)\])*/', $name) === 1); } /** diff --git a/src/Contracts/Types/DynamicBytes.php b/src/Contracts/Types/DynamicBytes.php index a0c8842..e662a52 100644 --- a/src/Contracts/Types/DynamicBytes.php +++ b/src/Contracts/Types/DynamicBytes.php @@ -36,7 +36,7 @@ class DynamicBytes extends SolidityType implements IType */ public function isType($name) { - return (preg_match('/bytes(\[([0-9]*)\])*/', $name) === 1); + return (preg_match('/^bytes(\[([0-9]*)\])*/', $name) === 1); } /** diff --git a/src/Contracts/Types/Integer.php b/src/Contracts/Types/Integer.php index 2db4716..8c12774 100644 --- a/src/Contracts/Types/Integer.php +++ b/src/Contracts/Types/Integer.php @@ -37,7 +37,7 @@ class Integer extends SolidityType implements IType */ public function isType($name) { - return (preg_match('/int([0-9]{1,})?(\[([0-9]*)\])*/', $name) === 1); + return (preg_match('/^int([0-9]{1,})?(\[([0-9]*)\])*/', $name) === 1); } /** diff --git a/src/Contracts/Types/Str.php b/src/Contracts/Types/Str.php index 344f070..e68f076 100644 --- a/src/Contracts/Types/Str.php +++ b/src/Contracts/Types/Str.php @@ -37,7 +37,7 @@ class Str extends SolidityType implements IType */ public function isType($name) { - return (preg_match('/string(\[([0-9]*)\])*/', $name) === 1); + return (preg_match('/^string(\[([0-9]*)\])*/', $name) === 1); } /** diff --git a/src/Contracts/Types/Uinteger.php b/src/Contracts/Types/Uinteger.php index d5f8c2a..c5bbfbb 100644 --- a/src/Contracts/Types/Uinteger.php +++ b/src/Contracts/Types/Uinteger.php @@ -37,7 +37,7 @@ class Uinteger extends SolidityType implements IType */ public function isType($name) { - return (preg_match('/uint([0-9]{1,})?(\[([0-9]*)\])*/', $name) === 1); + return (preg_match('/^uint([0-9]{1,})?(\[([0-9]*)\])*/', $name) === 1); } /** From ecafb1c5ec324eb4407d1267c785cac5ebf6fe9c Mon Sep 17 00:00:00 2001 From: sc0Vu Date: Sun, 24 Jun 2018 18:30:45 +0800 Subject: [PATCH 14/17] Fix BytesTypeTest and DynamicBytesTypeTest --- test/unit/BytesTypeTest.php | 12 ++++++------ test/unit/DynamicBytesTypeTest.php | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/test/unit/BytesTypeTest.php b/test/unit/BytesTypeTest.php index 34a837d..c446cc5 100644 --- a/test/unit/BytesTypeTest.php +++ b/test/unit/BytesTypeTest.php @@ -16,22 +16,22 @@ class BytesTypeTest extends TestCase protected $testTypes = [ [ 'value' => 'bytes', - 'result' => true + 'result' => false ], [ 'value' => 'bytes[]', - 'result' => true + 'result' => false ], [ 'value' => 'bytes[4]', - 'result' => true + 'result' => false ], [ 'value' => 'bytes[][]', - 'result' => true + 'result' => false ], [ 'value' => 'bytes[3][]', - 'result' => true + 'result' => false ], [ 'value' => 'bytes[][6][]', - 'result' => true + 'result' => false ], [ 'value' => 'bytes32', 'result' => true diff --git a/test/unit/DynamicBytesTypeTest.php b/test/unit/DynamicBytesTypeTest.php index ecef1d1..821f73b 100644 --- a/test/unit/DynamicBytesTypeTest.php +++ b/test/unit/DynamicBytesTypeTest.php @@ -34,10 +34,10 @@ class DynamicBytesTypeTest extends TestCase 'result' => true ], [ 'value' => 'bytes32', - 'result' => true + 'result' => false ], [ 'value' => 'bytes8[4]', - 'result' => true + 'result' => false ], ]; From d5c21afec05eab232eb4168cadefc5cfeb2b7b2d Mon Sep 17 00:00:00 2001 From: sc0Vu Date: Sun, 24 Jun 2018 21:16:12 +0800 Subject: [PATCH 15/17] Fix decode bytes * Return non zero bytes. Decode bytes1 data: 0x6300000000000000000000000000000000000000000000000000000000000000 Will return 0x63 --- src/Contracts/Types/Bytes.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Contracts/Types/Bytes.php b/src/Contracts/Types/Bytes.php index 29e7fad..542ba74 100644 --- a/src/Contracts/Types/Bytes.php +++ b/src/Contracts/Types/Bytes.php @@ -36,7 +36,7 @@ class Bytes extends SolidityType implements IType */ public function isType($name) { - return (preg_match('/^bytes([0-9]{1,})?(\[([0-9]*)\])*/', $name) === 1); + return (preg_match('/^bytes([0-9]{1,})(\[([0-9]*)\])*$/', $name) === 1); } /** @@ -90,6 +90,11 @@ class Bytes extends SolidityType implements IType if (empty($checkZero)) { return '0'; } + if (preg_match('/^bytes([0-9]*)/', $name, $match) === 1) { + $size = intval($match[1]); + $length = 2 * $size; + $value = mb_substr($value, 0, $length); + } return '0x' . $value; } } \ No newline at end of file From 07f730d8cef0fc0110cf530d71132195d51b8e96 Mon Sep 17 00:00:00 2001 From: sc0Vu Date: Sun, 24 Jun 2018 21:59:08 +0800 Subject: [PATCH 16/17] Fix decode dynamic bytes * Fix outputFormat function in dynamic bytes * Add test test for issue 85 #85 --- src/Contract.php | 2 + src/Contracts/Ethabi.php | 7 +- src/Contracts/Types/Address.php | 2 +- src/Contracts/Types/Boolean.php | 2 +- src/Contracts/Types/DynamicBytes.php | 7 +- src/Contracts/Types/Integer.php | 2 +- src/Contracts/Types/Str.php | 2 +- src/Contracts/Types/Uinteger.php | 2 +- test/unit/ContractTest.php | 284 +++++++++++++++++++++++++++ test/unit/EthabiTest.php | 4 +- 10 files changed, 305 insertions(+), 9 deletions(-) diff --git a/src/Contract.php b/src/Contract.php index b6c334a..6bdaf56 100644 --- a/src/Contract.php +++ b/src/Contract.php @@ -22,6 +22,7 @@ use Web3\Contracts\Ethabi; use Web3\Contracts\Types\Address; use Web3\Contracts\Types\Boolean; use Web3\Contracts\Types\Bytes; +use Web3\Contracts\Types\DynamicBytes; use Web3\Contracts\Types\Integer; use Web3\Contracts\Types\Str; use Web3\Contracts\Types\Uinteger; @@ -133,6 +134,7 @@ class Contract 'address' => new Address, 'bool' => new Boolean, 'bytes' => new Bytes, + 'dynamicBytes' => new DynamicBytes, 'int' => new Integer, 'string' => new Str, 'uint' => new Uinteger, diff --git a/src/Contracts/Ethabi.php b/src/Contracts/Ethabi.php index 12ee067..cf48ae0 100644 --- a/src/Contracts/Ethabi.php +++ b/src/Contracts/Ethabi.php @@ -280,7 +280,12 @@ class Ethabi $className = $this->types[$match[0]]; if (call_user_func([$this->types[$match[0]], 'isType'], $type) === false) { - throw new InvalidArgumentException('Unsupport solidity parameter type: ' . $type); + // check dynamic bytes + if ($match[0] === 'bytes') { + $className = $this->types['dynamicBytes']; + } else { + throw new InvalidArgumentException('Unsupport solidity parameter type: ' . $type); + } } $solidityTypes[$key] = $className; } diff --git a/src/Contracts/Types/Address.php b/src/Contracts/Types/Address.php index d366ad7..58de9c7 100644 --- a/src/Contracts/Types/Address.php +++ b/src/Contracts/Types/Address.php @@ -37,7 +37,7 @@ class Address extends SolidityType implements IType */ public function isType($name) { - return (preg_match('/^address(\[([0-9]*)\])*/', $name) === 1); + return (preg_match('/^address(\[([0-9]*)\])*$/', $name) === 1); } /** diff --git a/src/Contracts/Types/Boolean.php b/src/Contracts/Types/Boolean.php index 9f8e394..f997ac9 100644 --- a/src/Contracts/Types/Boolean.php +++ b/src/Contracts/Types/Boolean.php @@ -35,7 +35,7 @@ class Boolean extends SolidityType implements IType */ public function isType($name) { - return (preg_match('/^bool(\[([0-9]*)\])*/', $name) === 1); + return (preg_match('/^bool(\[([0-9]*)\])*$/', $name) === 1); } /** diff --git a/src/Contracts/Types/DynamicBytes.php b/src/Contracts/Types/DynamicBytes.php index e662a52..4446fa4 100644 --- a/src/Contracts/Types/DynamicBytes.php +++ b/src/Contracts/Types/DynamicBytes.php @@ -36,7 +36,7 @@ class DynamicBytes extends SolidityType implements IType */ public function isType($name) { - return (preg_match('/^bytes(\[([0-9]*)\])*/', $name) === 1); + return (preg_match('/^bytes(\[([0-9]*)\])*$/', $name) === 1); } /** @@ -89,6 +89,9 @@ class DynamicBytes extends SolidityType implements IType if (empty($checkZero)) { return '0'; } - return '0x' . $value; + $size = intval(Utils::toBn(mb_substr($value, 0, 64))->toString()); + $length = 2 * $size; + + return '0x' . mb_substr($value, 64, $length); } } \ No newline at end of file diff --git a/src/Contracts/Types/Integer.php b/src/Contracts/Types/Integer.php index 8c12774..4d6dae0 100644 --- a/src/Contracts/Types/Integer.php +++ b/src/Contracts/Types/Integer.php @@ -37,7 +37,7 @@ class Integer extends SolidityType implements IType */ public function isType($name) { - return (preg_match('/^int([0-9]{1,})?(\[([0-9]*)\])*/', $name) === 1); + return (preg_match('/^int([0-9]{1,})?(\[([0-9]*)\])*$/', $name) === 1); } /** diff --git a/src/Contracts/Types/Str.php b/src/Contracts/Types/Str.php index e68f076..51cf974 100644 --- a/src/Contracts/Types/Str.php +++ b/src/Contracts/Types/Str.php @@ -37,7 +37,7 @@ class Str extends SolidityType implements IType */ public function isType($name) { - return (preg_match('/^string(\[([0-9]*)\])*/', $name) === 1); + return (preg_match('/^string(\[([0-9]*)\])*$/', $name) === 1); } /** diff --git a/src/Contracts/Types/Uinteger.php b/src/Contracts/Types/Uinteger.php index c5bbfbb..c2099ed 100644 --- a/src/Contracts/Types/Uinteger.php +++ b/src/Contracts/Types/Uinteger.php @@ -37,7 +37,7 @@ class Uinteger extends SolidityType implements IType */ public function isType($name) { - return (preg_match('/^uint([0-9]{1,})?(\[([0-9]*)\])*/', $name) === 1); + return (preg_match('/^uint([0-9]{1,})?(\[([0-9]*)\])*$/', $name) === 1); } /** diff --git a/test/unit/ContractTest.php b/test/unit/ContractTest.php index 3fa0ea0..7e13fcb 100644 --- a/test/unit/ContractTest.php +++ b/test/unit/ContractTest.php @@ -10,6 +10,7 @@ use Web3\Contract; use Web3\Utils; use Web3\Contracts\Ethabi; use Web3\Formatters\IntegerFormatter; +use phpseclib\Math\BigInteger as BigNumber; class ContractTest extends TestCase { @@ -853,4 +854,287 @@ class ContractTest extends TestCase } }); } + + /** + * testIssue85 + * + * @return void + */ + public function testIssue85() + { + $bytecode = '0x608060405234801561001057600080fd5b50610a36806100206000396000f3006080604052600436106100af576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680630bcd3b33146100b45780631f9030371461014457806325f35c36146101775780632d1be94d146102735780638b84925b146102a2578063a15e05fd146102cd578063a5f807cc1461030f578063d07326681461039f578063ded516d21461043e578063f1d0876a146104ad578063f5c2e88a1461054c575b600080fd5b3480156100c057600080fd5b506100c96105dc565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101095780820151818401526020810190506100ee565b50505050905090810190601f1680156101365780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561015057600080fd5b5061015961061e565b60405180826000191660001916815260200191505060405180910390f35b34801561018357600080fd5b5061018c61064b565b604051808060200180602001838103835285818151815260200191508051906020019080838360005b838110156101d05780820151818401526020810190506101b5565b50505050905090810190601f1680156101fd5780820380516001836020036101000a031916815260200191505b50838103825284818151815260200191508051906020019080838360005b8381101561023657808201518184015260208101905061021b565b50505050905090810190601f1680156102635780820380516001836020036101000a031916815260200191505b5094505050505060405180910390f35b34801561027f57600080fd5b506102886106cd565b604051808215151515815260200191505060405180910390f35b3480156102ae57600080fd5b506102b76106db565b6040518082815260200191505060405180910390f35b3480156102d957600080fd5b506102e26106e9565b60405180836000191660001916815260200182600019166000191681526020019250505060405180910390f35b34801561031b57600080fd5b50610324610741565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610364578082015181840152602081019050610349565b50505050905090810190601f1680156103915780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156103ab57600080fd5b506103b461076a565b60405180806020018360001916600019168152602001828103825284818151815260200191508051906020019080838360005b838110156104025780820151818401526020810190506103e7565b50505050905090810190601f16801561042f5780820380516001836020036101000a031916815260200191505b50935050505060405180910390f35b34801561044a57600080fd5b506104536107d9565b60405180827effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200191505060405180910390f35b3480156104b957600080fd5b506104c2610806565b60405180836000191660001916815260200180602001828103825283818151815260200191508051906020019080838360005b838110156105105780820151818401526020810190506104f5565b50505050905090810190601f16801561053d5780820380516001836020036101000a031916815260200191505b50935050505060405180910390f35b34801561055857600080fd5b50610561610875565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156105a1578082015181840152602081019050610586565b50505050905090810190601f1680156105ce5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6060806040805190810160405280600381526020017f616263000000000000000000000000000000000000000000000000000000000081525090508091505090565b6000807f616263000000000000000000000000000000000000000000000000000000000090508091505090565b6060806060806040805190810160405280600381526020017f616263000000000000000000000000000000000000000000000000000000000081525091506040805190810160405280600381526020017f78797a0000000000000000000000000000000000000000000000000000000000815250905081819350935050509091565b600080600190508091505090565b600080606390508091505090565b6000806000807f616263000000000000000000000000000000000000000000000000000000000091507f78797a0000000000000000000000000000000000000000000000000000000000905081819350935050509091565b6060806101606040519081016040528061012c81526020016108df61012c913990508091505090565b60606000606060006040805190810160405280600381526020017f616263000000000000000000000000000000000000000000000000000000000081525091507f78797a0000000000000000000000000000000000000000000000000000000000905081819350935050509091565b6000807f610000000000000000000000000000000000000000000000000000000000000090508091505090565b60006060600060607f78797a000000000000000000000000000000000000000000000000000000000091506040805190810160405280600381526020017f6162630000000000000000000000000000000000000000000000000000000000815250905081819350935050509091565b606080606060405190810160405280603c81526020017f616263616263616263636162636162636162636361626361626361626363616281526020017f6361626361626363616263616263616263636162636162636162636300000000815250905080915050905600616263616263616263636162636162636162636361626361626361626363616263616263616263636162636162636162636361626361626361626363616263616263616263636162636162636162636361626361626361626363616263616263616263636162636162636162636361626361626361626363616263616263616263636162636162636162636361626361626361626363616263616263616263636162636162636162636361626361626361626363616263616263616263636162636162636162636361626361626361626363616263616263616263636162636162636162636361626361626361626363616263616263616263636162636162636162636361626361626361626363616263616263616263636162636162636162636361626361626361626363a165627a7a7230582020ee9e6b05918d0df987776ee24808f4dd1c522806bf9fa8f4336c93f6b0ec050029'; + $abi = '[ + { + "constant": true, + "inputs": [], + "name": "getBytes", + "outputs": [ + { + "name": "", + "type": "bytes" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getBytes32", + "outputs": [ + { + "name": "", + "type": "bytes32" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getDynamicData", + "outputs": [ + { + "name": "", + "type": "bytes" + }, + { + "name": "", + "type": "bytes" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getBoolean", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getInteger", + "outputs": [ + { + "name": "", + "type": "int256" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getTwoBytes32", + "outputs": [ + { + "name": "", + "type": "bytes32" + }, + { + "name": "", + "type": "bytes32" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getBytesVeryLong", + "outputs": [ + { + "name": "", + "type": "bytes" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getDynamicDataMixedOne", + "outputs": [ + { + "name": "", + "type": "bytes" + }, + { + "name": "", + "type": "bytes32" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getBytes1", + "outputs": [ + { + "name": "", + "type": "bytes1" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getDynamicDataMixedTwo", + "outputs": [ + { + "name": "", + "type": "bytes32" + }, + { + "name": "", + "type": "bytes" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getBytesLong", + "outputs": [ + { + "name": "", + "type": "bytes" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor" + } + ]'; + $functions = [ + [ + 'name' => 'getBoolean', + 'test' => function ($value) { + return is_bool($value); + } + ], [ + 'name' => 'getInteger', + 'test' => function ($value) { + return ($value instanceof BigNumber); + } + ], [ + 'name' => 'getBytes1', + 'test' => function ($value) { + return Utils::isHex($value) && mb_strlen($value) === 4; + } + ], [ + 'name' => 'getBytes32', + 'test' => function ($value) { + return Utils::isHex($value) && mb_strlen($value) === 66; + } + ], [ + 'name' => 'getBytesLong', + 'test' => function ($value) { + return Utils::isHex($value); + } + ], [ + 'name' => 'getDynamicData', + 'test' => function ($value) { + return Utils::isHex($value); + } + ], [ + 'name' => 'getDynamicDataMixedOne', + 'test' => function ($value) { + return Utils::isHex($value); + } + ], [ + 'name' => 'getDynamicDataMixedTwo', + 'test' => function ($value) { + return Utils::isHex($value); + } + ], [ + 'name' => 'getTwoBytes32', + 'test' => function ($value) { + return Utils::isHex($value) && mb_strlen($value) === 66; + } + ] + ]; + $contractAddress = ""; + + if (!isset($this->accounts[0])) { + $account = '0x407d73d8a49eeb85d32cf465507dd71d507100c1'; + } else { + $account = $this->accounts[0]; + } + $contract = new Contract($this->web3->provider, $abi); + $contract->bytecode($bytecode)->new([ + 'from' => $account, + 'gas' => '0x200b20' + ], function ($err, $result) use ($contract, &$contractAddress) { + if ($err !== null) { + return $this->fail($err->getMessage()); + } + if ($result) { + echo "\nTransaction has made:) id: " . $result . "\n"; + } + $transactionId = $result; + $this->assertTrue((preg_match('/^0x[a-f0-9]{64}$/', $transactionId) === 1)); + + $contract->eth->getTransactionReceipt($transactionId, function ($err, $transaction) use (&$contractAddress) { + if ($err !== null) { + return $this->fail($err); + } + if ($transaction) { + $contractAddress = $transaction->contractAddress; + echo "\nTransaction has mind:) block number: " . $transaction->blockNumber . "\n"; + } + }); + }); + $contract->at($contractAddress); + + foreach ($functions as $function) { + $contract->call($function['name'], [], function ($err, $res) use ($function) { + if ($err !== null) { + echo 'Error when call ' . $function['name'] . '. Message: ' . $err->getMessage() . "\n"; + return; + } + foreach ($res as $r) { + if (!call_user_func($function['test'], $r)) { + var_dump($r); + } + $this->assertTrue(call_user_func($function['test'], $r)); + } + }); + } + } } \ No newline at end of file diff --git a/test/unit/EthabiTest.php b/test/unit/EthabiTest.php index 321350a..08260a9 100644 --- a/test/unit/EthabiTest.php +++ b/test/unit/EthabiTest.php @@ -9,6 +9,7 @@ use Web3\Contracts\Ethabi; use Web3\Contracts\Types\Address; use Web3\Contracts\Types\Boolean; use Web3\Contracts\Types\Bytes; +use Web3\Contracts\Types\DynamicBytes; use Web3\Contracts\Types\Integer; use Web3\Contracts\Types\Str; use Web3\Contracts\Types\Uinteger; @@ -179,9 +180,10 @@ class EthabiTest extends TestCase 'address' => new Address, 'bool' => new Boolean, 'bytes' => new Bytes, + 'dynamicBytes' => new DynamicBytes, 'int' => new Integer, 'string' => new Str, - 'uint' => new Uinteger, + 'uint' => new Uinteger ]); } From 234b1e695fee6abce0a50a316f48d85031c71ce9 Mon Sep 17 00:00:00 2001 From: sc0Vu Date: Sun, 24 Jun 2018 22:30:34 +0800 Subject: [PATCH 17/17] Fix failed test on travis * Change gas limt to 6000000 * Change ganache container compose file --- docker/ganache/Dockerfile | 2 +- scripts/test.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/ganache/Dockerfile b/docker/ganache/Dockerfile index fe4f1ca..17726d6 100644 --- a/docker/ganache/Dockerfile +++ b/docker/ganache/Dockerfile @@ -6,4 +6,4 @@ RUN npm install -g ganache-cli EXPOSE 8545 -CMD ganache-cli --hostname=0.0.0.0 \ No newline at end of file +CMD ganache-cli -g 0 -l 6000000 --hostname=0.0.0.0 \ No newline at end of file diff --git a/scripts/test.sh b/scripts/test.sh index 9eee9a1..de94ecd 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -ganache-cli -g 0 -l 0 > /dev/null & +ganache-cli -g 0 -l 6000000 > /dev/null & ganachecli_pid=$! echo "Start ganache-cli pid: $ganachecli_pid and sleep 3 seconds"