From 66196ee8ba1fd9c9cf03a504aedca45f687eb62b Mon Sep 17 00:00:00 2001 From: ethers Date: Thu, 26 Feb 2015 20:06:26 -0800 Subject: [PATCH 1/4] constants should be before array contents, fixes #30 --- lib/abi.js | 41 ++++++------- test/abi.inputParser.js | 125 +++++++++++++++++++++++++++------------- 2 files changed, 106 insertions(+), 60 deletions(-) diff --git a/lib/abi.js b/lib/abi.js index db4e916..42b70f2 100644 --- a/lib/abi.js +++ b/lib/abi.js @@ -21,7 +21,7 @@ * @date 2014 */ -var web3 = require('./web3'); +var web3 = require('./web3'); var utils = require('./utils'); var types = require('./types'); var c = require('./const'); @@ -40,11 +40,11 @@ var arrayType = function (type) { var dynamicTypeBytes = function (type, value) { // TODO: decide what to do with array of strings if (arrayType(type) || type === 'string') // only string itself that is dynamic; stringX is static length. - return f.formatInputInt(value.length); + return f.formatInputInt(value.length); return ""; }; -var inputTypes = types.inputTypes(); +var inputTypes = types.inputTypes(); /// Formats input params to bytes /// @param abi contract method inputs @@ -52,8 +52,10 @@ var inputTypes = types.inputTypes(); /// @returns bytes representation of input params var formatInput = function (inputs, params) { var bytes = ""; + var toAppendConstant = ""; + var toAppendArrayContent = ""; - /// first we iterate in search for dynamic + /// first we iterate in search for dynamic inputs.forEach(function (input, index) { bytes += dynamicTypeBytes(input.type, params[index]); }); @@ -68,17 +70,17 @@ var formatInput = function (inputs, params) { } var formatter = inputTypes[j - 1].format; - var toAppend = ""; if (arrayType(inputs[i].type)) - toAppend = params[i].reduce(function (acc, curr) { + toAppendArrayContent = params[i].reduce(function (acc, curr) { return acc + formatter(curr); }, ""); else - toAppend = formatter(params[i]); - - bytes += toAppend; + toAppendConstant = formatter(params[i]); }); + + bytes += toAppendConstant + toAppendArrayContent; + return bytes; }; @@ -88,14 +90,14 @@ var dynamicBytesLength = function (type) { return 0; }; -var outputTypes = types.outputTypes(); +var outputTypes = types.outputTypes(); /// Formats output bytes back to param list /// @param contract abi method outputs -/// @param bytes representtion of output -/// @returns array of output params +/// @param bytes representtion of output +/// @returns array of output params var formatOutput = function (outs, output) { - + output = output.slice(2); var result = []; var padding = c.ETH_PADDING * 2; @@ -103,7 +105,7 @@ var formatOutput = function (outs, output) { var dynamicPartLength = outs.reduce(function (acc, curr) { return acc + dynamicBytesLength(curr.type); }, 0); - + var dynamicPart = output.slice(0, dynamicPartLength); output = output.slice(dynamicPartLength); @@ -124,13 +126,13 @@ var formatOutput = function (outs, output) { dynamicPart = dynamicPart.slice(padding); var array = []; for (var k = 0; k < size; k++) { - array.push(formatter(output.slice(0, padding))); + array.push(formatter(output.slice(0, padding))); output = output.slice(padding); } result.push(array); } else if (types.prefixedType('string')(outs[i].type)) { - dynamicPart = dynamicPart.slice(padding); + dynamicPart = dynamicPart.slice(padding); result.push(formatter(output.slice(0, padding))); output = output.slice(padding); } else { @@ -148,14 +150,14 @@ var formatOutput = function (outs, output) { var inputParser = function (json) { var parser = {}; json.forEach(function (method) { - var displayName = utils.extractDisplayName(method.name); + var displayName = utils.extractDisplayName(method.name); var typeName = utils.extractTypeName(method.name); var impl = function () { var params = Array.prototype.slice.call(arguments); return formatInput(method.inputs, params); }; - + if (parser[displayName] === undefined) { parser[displayName] = impl; } @@ -172,7 +174,7 @@ var outputParser = function (json) { var parser = {}; json.forEach(function (method) { - var displayName = utils.extractDisplayName(method.name); + var displayName = utils.extractDisplayName(method.name); var typeName = utils.extractTypeName(method.name); var impl = function (output) { @@ -207,4 +209,3 @@ module.exports = { signatureFromAscii: signatureFromAscii, eventSignatureFromAscii: eventSignatureFromAscii }; - diff --git a/test/abi.inputParser.js b/test/abi.inputParser.js index 12b7351..3eabdbd 100644 --- a/test/abi.inputParser.js +++ b/test/abi.inputParser.js @@ -29,7 +29,7 @@ describe('abi', function() { d[0].inputs = [ { type: "uint" } ]; - + // when var parser = abi.inputParser(d); @@ -37,7 +37,7 @@ describe('abi', function() { assert.equal(parser.test(1), "0000000000000000000000000000000000000000000000000000000000000001"); assert.equal(parser.test(10), "000000000000000000000000000000000000000000000000000000000000000a"); assert.equal( - parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), + parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" ); assert.equal( @@ -67,7 +67,7 @@ describe('abi', function() { assert.equal(parser.test(1), "0000000000000000000000000000000000000000000000000000000000000001"); assert.equal(parser.test(10), "000000000000000000000000000000000000000000000000000000000000000a"); assert.equal( - parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), + parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" ); assert.equal( @@ -80,7 +80,7 @@ describe('abi', function() { assert.equal(parser.test('3.9'), "0000000000000000000000000000000000000000000000000000000000000003"); }); - + it('should parse input uint256', function() { // given @@ -97,7 +97,7 @@ describe('abi', function() { assert.equal(parser.test(1), "0000000000000000000000000000000000000000000000000000000000000001"); assert.equal(parser.test(10), "000000000000000000000000000000000000000000000000000000000000000a"); assert.equal( - parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), + parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" ); assert.equal( @@ -108,7 +108,7 @@ describe('abi', function() { assert.equal(parser.test(3.9), "0000000000000000000000000000000000000000000000000000000000000003"); assert.equal(parser.test('0.1'), "0000000000000000000000000000000000000000000000000000000000000000"); assert.equal(parser.test('3.9'), "0000000000000000000000000000000000000000000000000000000000000003"); - + }); it('should parse input int', function() { @@ -119,7 +119,7 @@ describe('abi', function() { d[0].inputs = [ { type: "int" } ]; - + // when var parser = abi.inputParser(d); @@ -130,7 +130,7 @@ describe('abi', function() { assert.equal(parser.test(-2), "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"); assert.equal(parser.test(-16), "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0"); assert.equal( - parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), + parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" ); assert.equal( @@ -162,7 +162,7 @@ describe('abi', function() { assert.equal(parser.test(-2), "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"); assert.equal(parser.test(-16), "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0"); assert.equal( - parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), + parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" ); assert.equal( @@ -177,7 +177,7 @@ describe('abi', function() { }); it('should parse input int256', function() { - + // given var d = clone(description); @@ -195,7 +195,7 @@ describe('abi', function() { assert.equal(parser.test(-2), "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"); assert.equal(parser.test(-16), "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0"); assert.equal( - parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), + parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" ); assert.equal( @@ -206,11 +206,11 @@ describe('abi', function() { assert.equal(parser.test(3.9), "0000000000000000000000000000000000000000000000000000000000000003"); assert.equal(parser.test('0.1'), "0000000000000000000000000000000000000000000000000000000000000000"); assert.equal(parser.test('3.9'), "0000000000000000000000000000000000000000000000000000000000000003"); - + }); it('should parse input bool', function() { - + // given var d = clone(description); @@ -235,14 +235,14 @@ describe('abi', function() { d[0].inputs = [ { type: "hash" } ]; - + // when var parser = abi.inputParser(d); // then assert.equal(parser.test("0x407d73d8a49eeb85d32cf465507dd71d507100c1"), "000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1"); - }); + }); it('should parse input hash256', function() { @@ -272,7 +272,7 @@ describe('abi', function() { // when var parser = abi.inputParser(d); - + // then assert.equal(parser.test("0x407d73d8a49eeb85d32cf465507dd71d507100c1"), "000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1"); }); @@ -285,17 +285,17 @@ describe('abi', function() { d[0].inputs = [ { type: "address" } ]; - + // when var parser = abi.inputParser(d) - + // then assert.equal(parser.test("0x407d73d8a49eeb85d32cf465507dd71d507100c1"), "000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1"); }); it('should parse input string', function () { - + // given var d = clone(description); @@ -308,7 +308,7 @@ describe('abi', function() { // then assert.equal( - parser.test('hello'), + parser.test('hello'), "000000000000000000000000000000000000000000000000000000000000000568656c6c6f000000000000000000000000000000000000000000000000000000" ); assert.equal( @@ -318,7 +318,7 @@ describe('abi', function() { }); it('should use proper method name', function () { - + // given var d = clone(description); d[0].name = 'helloworld(int)'; @@ -334,9 +334,9 @@ describe('abi', function() { assert.equal(parser.helloworld['int'](1), "0000000000000000000000000000000000000000000000000000000000000001"); }); - + it('should parse multiple methods', function () { - + // given var d = [{ name: "test", @@ -356,14 +356,14 @@ describe('abi', function() { //then assert.equal(parser.test(1), "0000000000000000000000000000000000000000000000000000000000000001"); assert.equal( - parser.test2('hello'), + parser.test2('hello'), "000000000000000000000000000000000000000000000000000000000000000568656c6c6f000000000000000000000000000000000000000000000000000000" ); }); it('should parse input array of ints', function () { - + // given var d = clone(description); @@ -377,14 +377,60 @@ describe('abi', function() { // then assert.equal( parser.test([5, 6]), - "0000000000000000000000000000000000000000000000000000000000000002" + - "0000000000000000000000000000000000000000000000000000000000000005" + + "0000000000000000000000000000000000000000000000000000000000000002" + + "0000000000000000000000000000000000000000000000000000000000000005" + + "0000000000000000000000000000000000000000000000000000000000000006" + ); + }); + + it('should parse an int followed by an array', function () { + + // given + var d = clone(description); + + d[0].inputs = [ + { type: "int[]" }, + { type: "int" } + ]; + + // when + var parser = abi.inputParser(d); + + // then + assert.equal( + parser.test([5, 6], 3), + "0000000000000000000000000000000000000000000000000000000000000002" + + "0000000000000000000000000000000000000000000000000000000000000003" + + "0000000000000000000000000000000000000000000000000000000000000005" + + "0000000000000000000000000000000000000000000000000000000000000006" + ); + }); + + it('should parse an array followed by an int', function () { + + // given + var d = clone(description); + + d[0].inputs = [ + { type: "int" }, + { type: "int[]" } + ]; + + // when + var parser = abi.inputParser(d); + + // then + assert.equal( + parser.test(3, [5, 6]), + "0000000000000000000000000000000000000000000000000000000000000002" + + "0000000000000000000000000000000000000000000000000000000000000003" + + "0000000000000000000000000000000000000000000000000000000000000005" + "0000000000000000000000000000000000000000000000000000000000000006" ); }); it('should parse input real', function () { - + // given var d = clone(description); @@ -396,15 +442,15 @@ describe('abi', function() { var parser = abi.inputParser(d); // then - assert.equal(parser.test([1]), "0000000000000000000000000000000100000000000000000000000000000000"); - assert.equal(parser.test([2.125]), "0000000000000000000000000000000220000000000000000000000000000000"); - assert.equal(parser.test([8.5]), "0000000000000000000000000000000880000000000000000000000000000000"); - assert.equal(parser.test([-1]), "ffffffffffffffffffffffffffffffff00000000000000000000000000000000"); - + assert.equal(parser.test([1]), "0000000000000000000000000000000100000000000000000000000000000000"); + assert.equal(parser.test([2.125]), "0000000000000000000000000000000220000000000000000000000000000000"); + assert.equal(parser.test([8.5]), "0000000000000000000000000000000880000000000000000000000000000000"); + assert.equal(parser.test([-1]), "ffffffffffffffffffffffffffffffff00000000000000000000000000000000"); + }); - + it('should parse input ureal', function () { - + // given var d = clone(description); @@ -416,12 +462,11 @@ describe('abi', function() { var parser = abi.inputParser(d); // then - assert.equal(parser.test([1]), "0000000000000000000000000000000100000000000000000000000000000000"); - assert.equal(parser.test([2.125]), "0000000000000000000000000000000220000000000000000000000000000000"); - assert.equal(parser.test([8.5]), "0000000000000000000000000000000880000000000000000000000000000000"); - + assert.equal(parser.test([1]), "0000000000000000000000000000000100000000000000000000000000000000"); + assert.equal(parser.test([2.125]), "0000000000000000000000000000000220000000000000000000000000000000"); + assert.equal(parser.test([8.5]), "0000000000000000000000000000000880000000000000000000000000000000"); + }); }); }); - From ce664d61d54f5f4bc1d45673aaa0dcbcdfd99211 Mon Sep 17 00:00:00 2001 From: ethers Date: Thu, 26 Feb 2015 20:17:27 -0800 Subject: [PATCH 2/4] fix test descriptions --- test/abi.inputParser.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/abi.inputParser.js b/test/abi.inputParser.js index 3eabdbd..5e44359 100644 --- a/test/abi.inputParser.js +++ b/test/abi.inputParser.js @@ -383,7 +383,7 @@ describe('abi', function() { ); }); - it('should parse an int followed by an array', function () { + it('should parse an array followed by an int', function () { // given var d = clone(description); @@ -406,7 +406,7 @@ describe('abi', function() { ); }); - it('should parse an array followed by an int', function () { + it('should parse an int followed by an array', function () { // given var d = clone(description); From f8db634a8fea70d644e0b4ee0916325ebb85ddb0 Mon Sep 17 00:00:00 2001 From: ethers Date: Thu, 26 Feb 2015 20:24:19 -0800 Subject: [PATCH 3/4] need to save/concat per iteration --- lib/abi.js | 4 ++-- test/abi.inputParser.js | 29 +++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/lib/abi.js b/lib/abi.js index 42b70f2..e645351 100644 --- a/lib/abi.js +++ b/lib/abi.js @@ -72,11 +72,11 @@ var formatInput = function (inputs, params) { var formatter = inputTypes[j - 1].format; if (arrayType(inputs[i].type)) - toAppendArrayContent = params[i].reduce(function (acc, curr) { + toAppendArrayContent += params[i].reduce(function (acc, curr) { return acc + formatter(curr); }, ""); else - toAppendConstant = formatter(params[i]); + toAppendConstant += formatter(params[i]); }); bytes += toAppendConstant + toAppendArrayContent; diff --git a/test/abi.inputParser.js b/test/abi.inputParser.js index 5e44359..e63897c 100644 --- a/test/abi.inputParser.js +++ b/test/abi.inputParser.js @@ -429,6 +429,35 @@ describe('abi', function() { ); }); + it('should parse mixture of arrays and ints', function () { + + // given + var d = clone(description); + + d[0].inputs = [ + { type: "int" }, + { type: "int[]" }, + { type: "int" }, + { type: "int[]" } + ]; + + // when + var parser = abi.inputParser(d); + + // then + assert.equal( + parser.test(3, [5, 6], 7, [8, 9]), + "0000000000000000000000000000000000000000000000000000000000000002" + + "0000000000000000000000000000000000000000000000000000000000000002" + + "0000000000000000000000000000000000000000000000000000000000000003" + + "0000000000000000000000000000000000000000000000000000000000000007" + + "0000000000000000000000000000000000000000000000000000000000000005" + + "0000000000000000000000000000000000000000000000000000000000000006" + + "0000000000000000000000000000000000000000000000000000000000000008" + + "0000000000000000000000000000000000000000000000000000000000000009" + ); + }); + it('should parse input real', function () { // given From fcab219d7d74c8301c6e1c0a8eed34c1d2e0a7f4 Mon Sep 17 00:00:00 2001 From: ethers Date: Thu, 26 Feb 2015 20:28:21 -0800 Subject: [PATCH 4/4] vary the length of the arrays --- test/abi.inputParser.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/abi.inputParser.js b/test/abi.inputParser.js index e63897c..26e61c2 100644 --- a/test/abi.inputParser.js +++ b/test/abi.inputParser.js @@ -446,13 +446,15 @@ describe('abi', function() { // then assert.equal( - parser.test(3, [5, 6], 7, [8, 9]), - "0000000000000000000000000000000000000000000000000000000000000002" + + parser.test(3, [5, 6, 1, 2], 7, [8, 9]), + "0000000000000000000000000000000000000000000000000000000000000004" + "0000000000000000000000000000000000000000000000000000000000000002" + "0000000000000000000000000000000000000000000000000000000000000003" + "0000000000000000000000000000000000000000000000000000000000000007" + "0000000000000000000000000000000000000000000000000000000000000005" + "0000000000000000000000000000000000000000000000000000000000000006" + + "0000000000000000000000000000000000000000000000000000000000000001" + + "0000000000000000000000000000000000000000000000000000000000000002" + "0000000000000000000000000000000000000000000000000000000000000008" + "0000000000000000000000000000000000000000000000000000000000000009" );