ethers.js/test.js

503 lines
17 KiB
JavaScript

// @TODO: Move to an actual unit test system
var crypto = require('crypto');
var ethereumTx = require('ethereumjs-tx');
var ethereumUtil = require('ethereumjs-util');
var iban = require('./node_modules/web3/lib/web3/iban.js');
var coderWeb3 = require('./node_modules/web3/lib/solidity/coder.js');
coderWeb3._name = 'web3';
var coderSol = require('./thirdparty/solidity.js-master/index.js');
coderSol._name = 'sol';
var coderAbi = require('ethereumjs-abi');
var coderEjs = {
encodeParams: function(types, values) {
return coderAbi.rawEncode(types, values).toString('hex');
},
decodeParams: function(types, data) {
return coderAbi.rawDecode(types, data);
},
_name: 'ejs'
}
var Wallet = require('./index.js');
var BN = Wallet.utils.BN;
var utils = require('./lib/utils.js');
function random(lowerRandomInterval, upperOpenInterval) {
return lowerRandomInterval + parseInt((upperOpenInterval - lowerRandomInterval) * Math.random());
}
function randomBuffer(length) {
var buffer = crypto.randomBytes(length);
return buffer;
}
function randomHex(length) {
return '0x' + randomBuffer(length).toString('hex');
}
(function() {
var libs = {
web3: 0x01,
sol: 0x02,
ejs: 0x04,
}
function dumpHex(data) {
for (var i = 2; i < data.length; i += 64) {
console.log(' ' + data.substring(i, i + 64));
}
}
function recurse(object, calback) {
if (Array.isArray(object)) {
object.forEach(function(object) {
callback(object);
});
} else {
callback(object);
}
}
function recursiveEqual(a, b) {
function fail() {
if (a.eq) { a = a.toString(10); }
if (b.eq) { b = b.toString(10); }
if (Buffer.isBuffer(a)) { a = a.toString('hex'); }
if (Buffer.isBuffer(b)) { b = b.toString('hex'); }
//console.log('A=');
//console.log(a, {depth: null});
//console.log('B=');
//console.log(b, {depth: null});
return false;
}
if (typeof(a) === 'number') { a = new BN(a); }
if (typeof(b) === 'number') { b = new BN(b); }
if (utils.isHexString(a)) { a = utils.hexOrBuffer(a); }
if (utils.isHexString(b)) { b = utils.hexOrBuffer(b); }
if (a.eq) {
if (!b.eq || !a.eq(b)) { return fail(); }
return true;
}
if (Buffer.isBuffer(a)) {
if (!Buffer.isBuffer(b) || Buffer.compare(a, b) !== 0) { return fail(); }
return true;
}
if (Array.isArray(a)) {
if (!Array.isArray(b) || a.length !== b.length) { return fail(); }
for (var i = 0; i < a.length; i++) {
if (!recursiveEqual(a[i], b[i])) { return fail(); }
}
return true;
}
if (a !== b) { return fail(); }
return true;
}
function checkLib(types, values, coder) {
//console.log(types, values, coder._name);
var officialData = '0x' + coder.encodeParams(types, values);
var ethersData = Wallet._Contract.Interface.encodeParams(types, values);
if (officialData !== ethersData) {
console.log('coder=' + coder._name);
console.log('types=' + JSON.stringify(types, {depth: null}));
console.log('values=' + JSON.stringify(values, {depth: null}));
console.log('officialData=');
dumpHex(officialData);
console.log('ethersData=');
dumpHex(ethersData);
throw new Error('test case failed');
}
var ethersValues = Wallet._Contract.Interface.decodeParams(types, officialData);
if (!recursiveEqual(values, ethersValues)) {
console.log('coder=' + coder._name);
console.log('types=' + JSON.stringify(types, {depth: null}));
console.log('values=' + JSON.stringify(values, {depth: null}));
console.log('officialData=');
dumpHex(officialData);
console.log('ethersValues=' + JSON.stringify(ethersValues, {depth: null}));
throw new Error('test case failed');
}
}
function check(types, values, skipLibs) {
// First make sure we agree with ourself
var ethersData = Wallet._Contract.Interface.encodeParams(types, values);
var ethersValues = Wallet._Contract.Interface.decodeParams(types, ethersData);
if (!recursiveEqual(values, ethersValues)) {
throw new Error('self-decode fail');
}
var checkTypes = types.join(',');
function has(regex) { return checkTypes.match(regex); }
var hasDynamic = (has(/\[\]/) || has(/bytes([^0-9]|$)/) || has(/string/));
var hasArray = has(/\[[0-9]+\]/);
console.log(types, checkTypes, hasDynamic, hasArray);
if ((!hasDynamic || !hasArray) && !has(/bool\[/)) {
checkLib(types, values, coderEjs);
} else {
console.log('skipping');
}
}
// Test cases: https://github.com/ethereum/solidity.js/blob/master/test/coder.decodeParam.js
check(['int'], [new BN(1)]);
check(['int'], [new BN(16)]);
check(['int'], [new BN(-1)]);
check(['int256'], [new BN(1)]);
check(['int256'], [new BN(16)]);
check(['int256'], [new BN(-1)]);
check(['int8'], [new BN(16)]);
check(['int32'], [new BN(16)]);
check(['int64'], [new BN(16)]);
check(['int128'], [new BN(16)]);
check(['uint'], [new BN(1)]);
check(['uint'], [new BN(16)]);
check(['uint'], [new BN(-1)]);
check(['uint256'], [new BN(1)]);
check(['uint256'], [new BN(16)]);
check(['uint256'], [new BN(-1)]);
check(['uint8'], [new BN(16)]);
check(['uint32'], [new BN(16)]);
check(['uint64'], [new BN(16)]);
check(['uint128'], [new BN(16)]);
check(['int', 'int'], [new BN(1), new BN(2)]);
check(['int', 'int'], [new BN(1), new BN(2)]);
check(['int[2]', 'int'], [[new BN(12), new BN(22)], new BN(3)]);
// check(['int[2]', 'int[]'], [[new BN(32), new BN(42)], [new BN(3), new BN(4), new BN(5)]]);
check(
['bytes32'],
['0x6761766f66796f726b0000000000000000000000000000000000000000000000']
);
check(
['bytes'],
[new Buffer('6761766f66796f726b', 'hex')]
);
/*
check(
['address', 'string', 'bytes6[4]', 'int'],
[
"0x97916ef549947a3e0d321485a31dd2715a97d455",
"foobar2",
["0xa165ab0173c6", "0xf0f37bee9244", "0xc8dc0bf08d2b", "0xc8dc0bf08d2b"],
34
]
);
*/
check(
['bytes32'],
['0x731a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b']
);
check(
['bytes'],
[new Buffer('731a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b')]
);
/*
check(
['bytes32[2]'],
[['0x731a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b',
'0x731a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b']]
);
*/
check(
['bytes'],
[new Buffer('131a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b' +
'231a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b' +
'331a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b')]
);
function randomTypeValue(onlyStatic) {
switch (random(0, (onlyStatic ? 5: 8))) {
case 0:
var size = random(1, 33);
return {
type: 'bytes' + size,
value: function() {
return '0x' + randomBuffer(size).toString('hex');
},
skip: 0
}
case 1:
var signed = (random(0, 2) === 0);
var type = (signed ? 'u': '') + 'int';
if (random(0, 4) > 0) { type += 8 * random(1, 33); }
return {
type: type,
value: function() {
var value = random(-500, 1000);
//var value = random(-5, 10) + (signed ? 5: 0);
if (random(0, 2)) { value = new BN(value); }
return value
},
skip: 0,
}
case 2:
return {
type: 'address',
value: function() {
return '0x' + randomBuffer(20).toString('hex');
},
skip: 0
}
case 3:
return {
type: 'bool',
value: function() {
return (random(0, 2) === 0);
},
skip: 0
}
case 4:
var size = random(1, 6); /// @TODO: Support random(0, 6)... Why is that even possible?
var subTypeValue = randomTypeValue(true);
return {
type: subTypeValue.type + '[' + size + ']',
value: function() {
var values = [];
for (var i = 0; i < size; i++) { values.push(subTypeValue.value()); }
return values;
},
skip: (subTypeValue.skip | libs.web3 | libs.sol)
}
case 5:
return {
type: 'bytes',
value: function() {
return randomBuffer(random(0, 100));
},
skip: 0
}
case 6:
//var text = '\uD835\uDF63abcdefghijklmnopqrstuvwxyz\u2014ABCDEFGHIJKLMNOPQRSTUVWXYZFOOBARfoobar'
var text = 'abcdefghijklmnopqrstuvwxyz\u2014ABCDEFGHIJKLMNOPQRSTUVWXYZFOOBARfoobar'
return {
type: 'string',
value: function() {
return text.substring(0, random(0, 60));
},
skip: 0
}
case 7:
var size = random(0, 6);
var subTypeValue = randomTypeValue(true);
return {
type: subTypeValue.type + '[]',
value: function() {
var values = [];
for (var i = 0; i < size; i++) { values.push(subTypeValue.value()); }
return values;
},
skip: subTypeValue.skip | libs.ejs
}
}
}
for (var i = 0; i < 1000; i++) {
var count = random(0, 8);
var types = [], values = [];
for (var j = 0; j < count; j++) {
var type = randomTypeValue();
types.push(type.type);
values.push(type.value());
//console.log('TEST', {types: types, values: values});
check(types, values);
}
}
})();
(function() {
var abi = {
"SimpleStorage": [
{
"constant":true,
"inputs":[],
"name":"getValue",
"outputs":[{"name":"","type":"string"}],
"type":"function"
}, {
"constant":false,
"inputs":[{"name":"value","type":"string"}],
"name":"setValue",
"outputs":[],
"type":"function"
}, {
"anonymous":false,
"inputs":[
{"indexed":false,"name":"oldValue","type":"string"},
{"indexed":false,"name":"newValue","type":"string"}
],
"name":"valueChanged",
"type":"event"
}
]
}
/*
var privateKey = Wallet.utils.Buffer(32);
privateKey.fill(0x42);
var wallet = new Wallet(privateKey);
*/
var contract = new Wallet._Contract.Interface(abi.SimpleStorage);
var getValue = contract.getValue()
var setValue = contract.setValue("foobar");
var valueChanged = contract.valueChanged()
console.log(getValue, setValue, valueChanged);
// @TODO
})();
(function() {
for (var i = 0; i < 1000; i++) {
var privateKey = randomBuffer(32, true);
var official = '0x' + ethereumUtil.privateToAddress(privateKey).toString('hex');
var ethers = (new Wallet(privateKey)).address;
if (ethers !== ethereumUtil.toChecksumAddress(official)) {
console.log(i);
console.log('A', official);
console.log('B', ethers);
throw new Error('What?');
}
}
})();
(function() {
function testAddress(address) {
var officialIban = (iban.fromAddress(address))._iban;
var ethersAddress = Wallet.getAddress(officialIban);
var officialAddress = ethereumUtil.toChecksumAddress(address)
if (officialAddress !== ethersAddress) {
console.log('A', officialAddress);
console.log('B', ethersAddress);
throw new Error('waht?! address');
}
var ethersIban = Wallet.getIcapAddress(address);
if (officialIban !== ethersIban) {
console.log('A', officialIban);
console.log('B', ethersIban);
throw new Error('waht?! icap');
}
}
testAddress('0x0000000000000000000000000000000000000000');
testAddress('0xffffffffffffffffffffffffffffffffffffffff');
for (var i = 0; i < 10000; i++) {
testAddress(randomHex(20));
}
})();
(function() {
function testAddress(address) {
var official = ethereumUtil.toChecksumAddress(address);
var ethers = Wallet.getAddress(address);
if (official !== ethers) {
console.log('A', official);
console.log('B', ethers);
throw new Error('waht?!');
}
}
testAddress('0x0000000000000000000000000000000000000000');
testAddress('0xffffffffffffffffffffffffffffffffffffffff');
for (var i = 0; i < 10000; i++) {
testAddress(randomHex(20));
}
})();
(function() {
function testTransaction(privateKey, transaction, signature) {
var rawTransaction = new ethereumTx(transaction);
rawTransaction.sign(privateKey);
var official = '0x' + rawTransaction.serialize().toString('hex');
var ethers = (new Wallet(privateKey)).sign(transaction);
if (ethers !== official) {
console.log('A', ethers);
console.log('B', official);
throw new Error('What?');
}
}
for (var i = 0; i < 1000; i++) {
var transaction = {
to: randomHex(20),
data: randomHex(parseInt(10 * Math.random())),
gasLimit: randomHex(parseInt(10 * Math.random())),
gasPrice: randomHex(parseInt(10 * Math.random())),
value: randomHex(parseInt(10 * Math.random())),
nonce: randomHex(parseInt(10 * Math.random())),
};
testTransaction(randomBuffer(32, true), transaction);
}
// See: https://github.com/ethereumjs/ethereumjs-tx/blob/master/test/txs.json
testTransaction(new Buffer('164122e5d39e9814ca723a749253663bafb07f6af91704d9754c361eb315f0c1', 'hex'), {
nonce: "0x",
gasPrice: "0x09184e72a000",
gasLimit: "0x2710",
to: "0x0000000000000000000000000000000000000000",
value: "0x",
data: "0x7f7465737432000000000000000000000000000000000000000000000000000000600057",
}, {
v: "0x1c",
r: "0x5e1d3a76fbf824220eafc8c79ad578ad2b67d01b0c2425eb1f1347e8f50882ab",
s: "0x5bd428537f05f9830e93792f90ea6a3e2d1ee84952dd96edbae9f658f831ab13"
});
testTransaction(new Buffer('e0a462586887362a18a318b128dbc1e3a0cae6d4b0739f5d0419ec25114bc722', 'hex'), {
nonce: "0x06",
gasPrice: "0x09184e72a000",
gasLimit: "0x01f4",
to: "0xbe862ad9abfe6f22bcb087716c7d89a26051f74c",
value: "0x016345785d8a0000",
data: "0x",
}, {
v: "0x1c",
r: "0x24a484bfa7380860e9fa0a9f5e4b64b985e860ca31abd36e66583f9030c2e29d",
s: "0x4d5ef07d9e73fa2fbfdad059591b4f13d0aa79e7634a2bb00174c9200cabb04d"
});
testTransaction(new Buffer('164122e5d39e9814ca723a749253663bafb07f6af91704d9754c361eb315f0c1', 'hex'), {
nonce: "0x06",
gasPrice: "0x09184e72a000",
gasLimit: "0x0974",
to: "0xbe862ad9abfe6f22bcb087716c7d89a26051f74c",
value: "0x016345785d8a0000",
data: "0x00000000000000000000000000000000000000000000000000000000000000ad000000000000000000000000000000000000000000000000000000000000fafa0000000000000000000000000000000000000000000000000000000000000dfa0000000000000000000000000000000000000000000000000000000000000dfa00000000000000000000000000000000000000000000000000000000000000ad000000000000000000000000000000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000df000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000df000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000d",
}, {
v: "0x1c",
r: "0x5e9361ca27e14f3af0e6b28466406ad8be026d3b0f2ae56e3c064043fb73ec77",
s: "0x29ae9893dac4f9afb1af743e25fbb6a63f7879a61437203cb48c997b0fcefc3a"
});
})();