solidity abi refactor in progress

This commit is contained in:
Marek Kotewicz 2015-04-16 16:37:13 +02:00
parent 271b00f069
commit d643d06b78
5 changed files with 111 additions and 81 deletions

View File

@ -26,6 +26,7 @@ var c = require('../utils/config');
var types = require('./types');
var f = require('./formatters');
var solUtils = require('./utils');
var SolidityInputParam = f.SolidityInputParam;
/**
* throw incorrect type error
@ -48,22 +49,7 @@ var isArrayType = function (type) {
return type.slice(-2) === '[]';
};
/**
* This method should be called to return dynamic type length in hex
*
* @method dynamicTypeBytes
* @param {String} type
* @param {String|Array} dynamic type
* @return {String} length of dynamic type in hex or empty string if type is not dynamic
*/
var dynamicTypeBytes = function (type, value) {
// TODO: decide what to do with array of strings
if (isArrayType(type) || type === 'bytes')
return f.formatInputInt(value.length);
return "";
};
var inputTypes = types.inputTypes();
//var inputTypes = types.inputTypes();
/**
* Formats input params to bytes
@ -74,40 +60,13 @@ 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
inputs.forEach(function (input, index) {
bytes += dynamicTypeBytes(input.type, params[index]);
});
inputs.forEach(function (input, i) {
/*jshint maxcomplexity:5 */
var typeMatch = false;
for (var j = 0; j < inputTypes.length && !typeMatch; j++) {
typeMatch = inputTypes[j].type(inputs[i].type, params[i]);
}
if (!typeMatch) {
throwTypeError(inputs[i].type);
}
var formatter = inputTypes[j - 1].format;
if (isArrayType(inputs[i].type))
toAppendArrayContent += params[i].reduce(function (acc, curr) {
return acc + formatter(curr);
}, "");
else if (inputs[i].type === 'bytes')
toAppendArrayContent += formatter(params[i]);
else
toAppendConstant += formatter(params[i]);
});
bytes += toAppendConstant + toAppendArrayContent;
return bytes;
//var result =
return inputs.map(function (input, index) {
return types.sf.formatInput(input.type, params[index]);
}).reduce(function (acc, solidityParam) {
acc.append(solidityParam);
return acc;
}, new SolidityInputParam()).encode();
};
/**

View File

@ -24,6 +24,22 @@ var BigNumber = require('bignumber.js');
var utils = require('../utils/utils');
var c = require('../utils/config');
var SolidityInputParam = function (value, prefix, suffix) {
this.prefix = prefix || '';
this.value = value || '';
this.suffix = suffix || '';
};
SolidityInputParam.prototype.append = function (param) {
this.prefix += param.prefix;
this.value += param.value;
this.suffix += param.suffix;
};
SolidityInputParam.prototype.encode = function () {
return this.prefix + this.value + this.suffix;
};
/**
* Formats input value to byte representation of int
* If value is negative, return it's two's complement
@ -36,7 +52,8 @@ var c = require('../utils/config');
var formatInputInt = function (value) {
var padding = c.ETH_PADDING * 2;
BigNumber.config(c.ETH_BIGNUMBER_ROUNDING_MODE);
return utils.padLeft(utils.toTwosComplement(value).round().toString(16), padding);
var result = utils.padLeft(utils.toTwosComplement(value).round().toString(16), padding);
return new SolidityInputParam(result);
};
/**
@ -47,7 +64,8 @@ var formatInputInt = function (value) {
* @returns {String} left-algined byte representation of string
*/
var formatInputString = function (value) {
return utils.fromAscii(value, c.ETH_PADDING).substr(2);
var result = utils.fromAscii(value, c.ETH_PADDING).substr(2);
return new SolidityInputParam('', formatInputInt(value.length).value, result);
};
/**
@ -58,7 +76,8 @@ var formatInputString = function (value) {
* @returns {String} right-aligned byte representation bool
*/
var formatInputBool = function (value) {
return '000000000000000000000000000000000000000000000000000000000000000' + (value ? '1' : '0');
var result = '000000000000000000000000000000000000000000000000000000000000000' + (value ? '1' : '0');
return new SolidityInputParam(result);
};
/**
@ -70,7 +89,7 @@ var formatInputBool = function (value) {
* @returns {String} byte representation of real
*/
var formatInputReal = function (value) {
return formatInputInt(new BigNumber(value).times(new BigNumber(2).pow(128)));
return formatInputInt(new BigNumber(value).times(new BigNumber(2).pow(128)));
};
/**
@ -193,6 +212,7 @@ module.exports = {
formatOutputHash: formatOutputHash,
formatOutputBool: formatOutputBool,
formatOutputString: formatOutputString,
formatOutputAddress: formatOutputAddress
formatOutputAddress: formatOutputAddress,
SolidityInputParam: SolidityInputParam
};

View File

@ -20,7 +20,10 @@
* @date 2015
*/
var BigNumber = require('bignumber.js');
var utils = require('../utils/utils');
var f = require('./formatters');
var SolidityInputParam = f.SolidityInputParam;
/// @param expected type prefix (string)
/// @returns function which checks if type has matching prefix. if yes, returns true, otherwise false
@ -38,21 +41,6 @@ var namedType = function (name) {
};
};
/// Setups input formatters for solidity types
/// @returns an array of input formatters
var inputTypes = function () {
return [
{ type: prefixedType('uint'), format: f.formatInputInt },
{ type: prefixedType('int'), format: f.formatInputInt },
{ type: prefixedType('bytes'), format: f.formatInputString },
{ type: prefixedType('real'), format: f.formatInputReal },
{ type: prefixedType('ureal'), format: f.formatInputReal },
{ type: namedType('address'), format: f.formatInputInt },
{ type: namedType('bool'), format: f.formatInputBool }
];
};
/// Setups output formaters for solidity types
/// @returns an array of output formatters
var outputTypes = function () {
@ -68,10 +56,73 @@ var outputTypes = function () {
];
};
var SolidityType = function (name, inputFormatter, outputFormatter) {
this.name = name;
this.inputFormatter = inputFormatter;
this.outputFormatter = outputFormatter;
};
SolidityType.prototype.isType = function (name) {
return this.name === name || (name.indexOf(this.name) === 0 && name.slice(this.name.length) === '[]');
};
SolidityType.prototype.formatInput = function (param) {
if (utils.isArray(param)) {
var self = this;
return param.map(function (p) {
return self.inputFormatter(p);
}).reduce(function (acc, current) {
acc.suffix += current.value;
acc.prefix += current.prefix;
// TODO: suffix not supported = it's required for nested arrays;
return acc;
}, new SolidityInputParam('', f.formatInputInt(param.length).value));
}
return this.inputFormatter(param);
};
var SolidityPrefixedType = function () {
SolidityType.apply(this, arguments);
};
SolidityPrefixedType.prototype = Object.create(SolidityType.prototype);
SolidityPrefixedType.prototype.isType = function (name) {
// TODO better type detection!
return name.indexOf(this.name) === 0;
};
var SolidityFormatter = function (types) {
this.types = types;
};
SolidityFormatter.prototype.formatInput = function (type, param) {
var solidityType = this.types.filter(function (t) {
return t.isType(type);
})[0];
if (!solidityType) {
throw Error('invalid solidity type!: ' + type);
}
return solidityType.formatInput(param);
};
var sf = new SolidityFormatter([
new SolidityType('address', f.formatInputInt),
new SolidityType('bool', f.formatInputBool),
new SolidityPrefixedType('int', f.formatInputInt),
new SolidityPrefixedType('uint', f.formatInputInt),
new SolidityPrefixedType('bytes', f.formatInputString),
new SolidityPrefixedType('real', f.formatInputReal),
new SolidityPrefixedType('ureal', f.formatInputReal)
]);
module.exports = {
sf: sf,
prefixedType: prefixedType,
namedType: namedType,
inputTypes: inputTypes,
//inputTypes: inputTypes,
outputTypes: outputTypes
};

View File

@ -469,10 +469,10 @@ describe('lib/solidity/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");
});
@ -489,9 +489,9 @@ describe('lib/solidity/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");
});

View File

@ -74,7 +74,7 @@ describe('lib/web3/event', function () {
assert.equal(result.address, address);
assert.equal(result.topics.length, 2);
assert.equal(result.topics[0], signature);
assert.equal(result.topics[1], '0x' + f.formatInputInt(4));
assert.equal(result.topics[1], '0x' + f.formatInputInt(4).encode());
assert.equal(result.fromBlock, options.fromBlock);
assert.equal(result.toBlock, options.toBlock);
@ -102,8 +102,8 @@ describe('lib/web3/event', function () {
assert.equal(result.address, address);
assert.equal(result.topics.length, 2);
assert.equal(result.topics[0], signature);
assert.equal(result.topics[1][0], f.formatInputInt(4));
assert.equal(result.topics[1][1], f.formatInputInt(69));
assert.equal(result.topics[1][0], f.formatInputInt(4).encode());
assert.equal(result.topics[1][1], f.formatInputInt(69).encode());
assert.equal(result.fromBlock, options.fromBlock);
assert.equal(result.toBlock, options.toBlock);