2
0
mirror of synced 2025-02-24 20:18:07 +00:00

Migrated most test cases to mocha and added pre-generated gzipped test suite.

This commit is contained in:
Richard Moore 2017-10-18 21:28:45 -04:00
parent 4a3d68eada
commit 44729ffba9
24 changed files with 783 additions and 104 deletions

99
tests/README.md Normal file
View File

@ -0,0 +1,99 @@
Ethers Test Suite
=================
There are a lot of test cases, and it can take a while for them to all run.
Please be patient.
Running Tests
-------------
**Node.js:**
```
# Test everything
> npm test
# Test just one specific package
# Test the Solidity ABI coder
# - See tests/contract-interface.json.gz
> ./node_modules/.bin/mocha test-contract-interface.js
# Test HD Wallet derivations
# - See tests/hdnode.json.gz
> ./node_modules/.bin/mocha test-hdnode.js
# Test general utilities
# - See tests/namehash.json.gz
# - See tests/rlp-coder.json.gz
# - See tests/units.json.gz
> ./node_modules/.bin/mocha test-utils.js
# Test accounts and addresses
# - See tests/accounts.json.gz
> ./node_modules/.bin/mocha test-account.js
# Test encrypting/decrypting JSON wallets and transaction parsing/signing
# - See tests/transactions.json.gz
# - See tests/wallets.json.gz
> ./node_modules/.bin/mocha test-wallet.js
# This test case has not yet been migrated to mocha
> nodeunit run-provider.js
```
Test Cases
----------
The testcases take up a large amount of space, so they are gzipped in the
`tests/` folder. See `./utils.js` for saving and loading.
To dump a test case from the terminal, you can use:
```
/Users/ethers> cat ./tests/accounts.json.gz | gunzip
```
Building Testcases
------------------
Each suite of testcases is produced from a variety of sources. Many include a
specific set of test vecotrs as well as procedurally generated tests using known
correct implementations.
The `contract-interface` test cases are created by selecting a (deterministically) random
set of types and values, a solidity contract is then created to represent a contract with
the correct return types and values, which is then compiled and deployed to a local
Ethereum node, then executed once mined.
As a result, genearting the test cases can take quite some time. So, they are generated using
a separate set of files found in make-tests.
- make-accounts
- make-contract-interface
- make-hdnode
- makr-rlpcoder
- make-transaction
- make-wallets
Additional Test Vectors:
- **make-tests/test-mnemonics** -- The trezor test vectors for BIP39
- **make-tests/test-wallets** -- Sample JSON Wallets (crowdsale and Geth)
All generated JSON test files are then placed gzipped in `tests` with the extension '.json.gz'.
Adding Test Cases
-----------------
For any patch, feature upgrade or pull request of any sort, there must be relevant
test cases added and all test cases must pass.
If you report a bug and provide test cases, it will get attention sooner.

View File

@ -5,54 +5,99 @@ var fs = require('fs');
var ethereumUtil = require('ethereumjs-util');
var iban = require('web3/lib/web3/iban.js');
var utils = require('./utils.js');
var utils = require('../utils.js');
function icap(address) {
address = (iban.fromAddress(address))._iban;
return address;
}
var Tests = [
// Edge-cases
'0x0000000000000000000000000000000000000000',
'0x0000000000000000000000000000000000000001',
'0xfffffffffffffffffffffffffffffffffffffffe',
'0xffffffffffffffffffffffffffffffffffffffff',
var Output = [];
// Exposes a padding bug in Web3
// See: https://github.com/ethereum/web3.js/pull/417
'0x03582910e5bc7a12793da58559aba9a6c4138e44',
]
// Some specific addresses to check
(function() {
var Tests = [
// Edge-cases
'0x0000000000000000000000000000000000000000',
'0x0000000000000000000000000000000000000001',
'0x0000000000000000000000000000000000000010',
'0xfffffffffffffffffffffffffffffffffffffffe',
'0xffffffffffffffffffffffffffffffffffffffff',
var OutputAddresses = [];
var OutputPrivateKeys = [];
// Exposes a padding bug in Web3
// See: https://gist.github.com/ricmoo/dbc2133ae2a20978eaf7
// See: https://github.com/ethereum/web3.js/pull/417
'0x03582910e5bc7a12793da58559aba9a6c4138e44',
'0x00582910e5bc7a12793da58559aba9a6c4138e44',
]
Tests.forEach(function(address) {
OutputAddresses.push({
address: address,
checksumAddress: ethereumUtil.toChecksumAddress(address),
icapAddress: icap(address)
});
Tests.forEach(function(address) {
Output.push({
address: address,
checksumAddress: ethereumUtil.toChecksumAddress(address),
icapAddress: icap(address),
index: Output.length,
name: ('address-' + address)
});
});
})();
// Some specific private keys to check
(function() {
var Tests = [
// Edge-cases
'0x0000000000000000000000000000000000000000000000000000000000000001',
'0x00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00',
'0x00fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0',
'0x00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
'0x0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
'0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd036413f',
'0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140',
]
Tests.forEach(function(privateKey) {
var privateKeyBuffer = new Buffer(privateKey.substring(2), 'hex');
var address = '0x' + ethereumUtil.privateToAddress(privateKeyBuffer).toString('hex');
Output.push({
address: address,
checksumAddress: ethereumUtil.toChecksumAddress(address),
icapAddress: icap(address),
index: Output.length,
name: ('privateKey-' + privateKey),
privateKey: privateKey
});
});
})();
/*
Output.push({
error: 'invalid private key',
index: Ouput.length,
name: 'privateKey-tooBig',
privateKey: '0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141',
});
for (var i = 0; i < 10000; i++) {
var privateKey = utils.randomBytes('accounts-' + i, 32);
Output.push({
error: 'invalid private key',
index: Ouput.length,
name: 'privateKey-zero',
privateKey: '0x0000000000000000000000000000000000000000000000000000000000000000',
});
*/
// Add 1024 random private keys (checks for nibble and byte padding bugs)
for (var i = 0; i < 1024; i++) {
var privateKey = new Buffer(utils.randomBytes('accounts-' + i, 32));
var address = '0x' + ethereumUtil.privateToAddress(new Buffer(privateKey)).toString('hex');
OutputAddresses.push({
Output.push({
address: address,
checksumAddress: ethereumUtil.toChecksumAddress(address),
icapAddress: icap(address),
});
OutputPrivateKeys.push({
address: address,
checksumAddress: ethereumUtil.toChecksumAddress(address),
icapAddress: icap(address),
privateKey: utils.hexlify(privateKey),
index: Output.length,
name: ('random-' + i),
privateKey: '0x' + privateKey.toString('hex'),
});
}
utils.saveTestcase('addresses', OutputAddresses);
utils.saveTestcase('private-keys', OutputPrivateKeys);
utils.saveTests('accounts', Output);

View File

@ -4,7 +4,7 @@ var bip39 = require('bip39');
var HDNode = require('bitcoinjs-lib').HDNode;
var ethereumUtil = require('ethereumjs-util');
var utils = require('./utils.js');
var utils = require('../utils.js');
function getPath(seed) {
var path = 'm';
@ -61,7 +61,7 @@ trezor.english.forEach(function(testcase, i) {
};
});
for (var i = 0; i < 1000; i++) {
for (var i = 0; i < 1024; i++) {
var strength = 16 + 4 * utils.randomNumber('random-1-' + i, 0, 5);
var entropy = utils.randomHexString('random-2-' + i, strength);
@ -108,4 +108,4 @@ TestcaseNames.forEach(function(testcase) {
Output.push(Testcases[testcase]);
});
utils.saveTestcase('hdnode', Output);
utils.saveTests('hdnode', Output);

View File

@ -1,7 +1,9 @@
import json
import os
import sha3
def keccak256(data):
hasher = sha3.keccak_256()
hasher.update(data)
@ -43,3 +45,4 @@ for i in xrange(0, len(Tests)):
with file('../tests/namehash.json', 'w') as f:
f.write(json.dumps(Tests))
os.system('cat ../test/namehash.json | gzip > ../tests/namehash.json.gz');

View File

@ -2,7 +2,7 @@
var rlp = require('rlp');
var utils = require('./utils.js');
var utils = require('../utils.js');
var nullBuffer = new Buffer('');
var shortBuffer = new Buffer('Hello World');
@ -75,4 +75,4 @@ testNames.forEach(function(testName) {
});
console.log(Output);
utils.saveTestcase('rlp-coder', Output);
utils.saveTests('rlp-coder', Output);

View File

@ -3,7 +3,7 @@
var ethereumUtil = require('ethereumjs-util');
var ethereumTx = require('ethereumjs-tx');
var utils = require('./utils.js');
var utils = require('../utils.js');
var Output = [];
@ -130,4 +130,4 @@ Output.sort(function(a, b) {
return 0;
});
utils.saveTestcase('transactions', Output);
utils.saveTests('transactions', Output);

View File

@ -3,7 +3,7 @@
var fs = require('fs');
var path = require('path');
var utils = require('./utils.js');
var utils = require('../utils.js');
function prefixAddress(address) {
if (address.substring(0, 2) !== '0x') {
@ -38,6 +38,8 @@ var walletPath = path.join(__dirname, 'test-wallets');
fs.readdirSync(walletPath).forEach(function(filename) {
var data = require(path.join(walletPath, filename));
var name = filename.substring(0, filename.length - 5).split('-')[1];
// The password is the last segment of the filename
var password = filename.substring(0, filename.length - 5).split('-');
password = password[password.length - 1];
@ -49,6 +51,7 @@ fs.readdirSync(walletPath).forEach(function(filename) {
type: 'crowdsale',
address: prefixAddress(data.ethaddr),
json: JSON.stringify(data),
name: name,
password: password,
privateKey: privateKeys[prefixAddress(data.ethaddr)],
});
@ -58,10 +61,11 @@ fs.readdirSync(walletPath).forEach(function(filename) {
type: 'secret-storage',
address: prefixAddress(data.address),
json: JSON.stringify(data),
name: name,
password: password,
privateKey: privateKeys[prefixAddress(data.address)],
});
}
});
utils.saveTestcase('wallets', Output);
utils.saveTests('wallets', Output);

View File

@ -1,52 +0,0 @@
var fs = require('fs');
var path = require('path');
var utils = require('../../utils');
function randomBytes(seed, lower, upper) {
if (!upper) { upper = lower; }
if (upper === 0 && upper === lower) { return new Uint8Array(0); }
seed = utils.toUtf8Bytes(seed);
var result = utils.arrayify(utils.keccak256(seed));
while (result.length < upper) {
result = utils.concat([result, utils.keccak256(utils.concat([seed, result]))]);
}
var top = utils.arrayify(utils.keccak256(result));
var percent = ((top[0] << 16) | (top[1] << 8) | top[2]) / 0x00ffffff;
return result.slice(0, lower + parseInt((upper - lower) * percent));
}
function randomHexString(seed, lower, upper) {
return utils.hexlify(randomBytes(seed, lower, upper));
}
function randomNumber(seed, lower, upper) {
var top = randomBytes(seed, 3);
var percent = ((top[0] << 16) | (top[1] << 8) | top[2]) / 0x00ffffff;
return lower + parseInt((upper - lower) * percent);
}
function saveTestcase(testcaseName, json) {
var data = JSON.stringify(json, undefined, ' ');
var filename = path.join(__dirname, '../tests/', testcaseName + '.json');
fs.writeFileSync(filename, data);
console.log('Save testcase: ' + filename);
}
module.exports = {
randomBytes: randomBytes,
randomHexString: randomHexString,
randomNumber: randomNumber,
arrayify: utils.arrayify,
hexlify: utils.hexlify,
saveTestcase: saveTestcase,
};

View File

@ -16,12 +16,13 @@
"grunt-browserify": "^5.0.0",
"grunt-contrib-uglify": "^1.0.1",
"promise-rationing": "0.0.1",
"mocha": "^3.2.0",
"rlp": "2.0.0",
"solc": "0.3.5",
"web3": "0.18.2"
},
"scripts": {
"test": "node index.js"
"test": "./node_modules/.bin/mocha --timeout 100000 test-*.js"
},
"keywords": [
"Ethereum",

41
tests/test-account.js Normal file
View File

@ -0,0 +1,41 @@
'use strict';
var assert = require('assert');
var utils = require('./utils');
describe('Private key generation', function() {
var Wallet = require('../wallet/Wallet');
var tests = utils.loadTests('accounts');
tests.forEach(function(test) {
if (!test.privateKey) { return; }
it(('correctly converts private key - ' + test.name), function() {
var wallet = new Wallet(test.privateKey);
assert.equal(wallet.address.toLowerCase(), test.address.toLowerCase(),
'correctly computes privateKey - ' + test.privateKey);
});
});
});
describe('Checksum and ICAP address generation', function() {
var getAddress = require('../utils/address').getAddress;
var tests = utils.loadTests('accounts');
tests.forEach(function(test) {
it(('correctly transforms address - ' + test.name), function() {
assert.equal(getAddress(test.address), test.checksumAddress,
'correctly computes checksum address from address');
assert.equal(getAddress(test.address, true), test.icapAddress,
'correctly computes ICAP address from address');
assert.equal(getAddress(test.checksumAddress), test.checksumAddress,
'correctly computes checksum address from checksum address');
assert.equal(getAddress(test.checksumAddress, true), test.icapAddress,
'correctly computes ICAP address from checksum address');
assert.equal(getAddress(test.icapAddress), test.checksumAddress,
'correctly computes checksum address from icap address');
assert.equal(getAddress(test.icapAddress, true), test.icapAddress,
'correctly computes ICAP address from icap address');
});
});
});

View File

@ -0,0 +1,164 @@
'use strict';
var assert = require('assert');
var utils = require('./utils');
// Set this to true to compare results against Web3 coder
var testWeb3 = false;
var FORMAT_WEB3 = 'web3';
var web3Coder = null;
if (testWeb3) {
web3Coder = require('web3/lib/solidity/coder');
}
function equals(a, b) {
// Array (treat recursively)
if (Array.isArray(a)) {
if (!Array.isArray(b) || a.length !== b.length) { return false; }
for (var i = 0; i < a.length; i++) {
if (!equals(a[i], b[i])) { return false; }
}
return true;
}
if (testWeb3) {
if (a.toJSON && a.minus) { a = utils.bigNumberify(a.toString(10)); }
if (b.toJSON && b.minus) { b = utils.bigNumberify(b.toString(10)); }
}
// BigNumber
if (a.eq) {
if (!a.eq(b)) { return false; }
return true;
}
// Uint8Array
if (a.buffer) {
if (!utils.isHexString(b)) { return false; }
b = utils.arrayify(b);
if (!b.buffer || a.length !== b.length) { return false; }
for (var i = 0; i < a.length; i++) {
if (a[i] !== b[i]) { return false; }
}
return true;
}
if (testWeb3) {
if (a.match && a.match(/^0x[0-9A-Fa-f]{40}$/)) { a = a.toLowerCase(); }
if (b.match && b.match(/^0x[0-9A-Fa-f]{40}$/)) { b = b.toLowerCase(); }
}
// Something else
return a === b;
}
function getValues(object, format) {
if (Array.isArray(object)) {
var result = [];
object.forEach(function(object) {
result.push(getValues(object, format));
});
return result;
}
switch (object.type) {
case 'number':
if (format === FORMAT_WEB3) {
var value = utils.bigNumberify(object.value);
value.round = function() {
return this;
}
value.lessThan = function(other) {
return this.lt(other);
}
var toString = value.toString.bind(value);
var toHexString = value.toHexString.bind(value);
Object.defineProperty(value, 'toString', {
value: function(format) {
if (format === 16) { return toHexString().substring(2); }
return toString();
}
});
return value;
}
return utils.bigNumberify(object.value);
case 'boolean':
case 'string':
return object.value;
case 'buffer':
if (format === FORMAT_WEB3) {
return object.value.toLowerCase();
}
return utils.arrayify(object.value);
default:
throw new Error('invalid type - ' + object.type);
}
}
describe('Contract Interface ABI Encoding', function() {
var Interface = require('../contracts/index.js').Interface;
var tests = utils.loadTests('contract-interface');
tests.forEach(function(test) {
var values = getValues(JSON.parse(test.normalizedValues));
var types = JSON.parse(test.types);
var result = test.result;
var title = test.name + ' => (' + test.types + ') = (' + test.normalizedValues + ')';
it(('encodes paramters - ' + test.name + ' - ' + test.types), function() {
var encoded = Interface.encodeParams(types, values);
assert.equal(encoded, result, 'encoded data - ' + title);
if (testWeb3) {
var valuesWeb3 = getValues(JSON.parse(test.normalizedValues), FORMAT_WEB3);
var web3Encoded = '0x' + web3Coder.encodeParams(types, valuesWeb3);
assert.equal(web3Encoded, result, 'web3 encoded data - ' + title);
}
});
});
});
describe('Contract Interface ABI Decoding', function() {
var Interface = require('../contracts/index.js').Interface;
var tests = utils.loadTests('contract-interface');
tests.forEach(function(test) {
var values = getValues(JSON.parse(test.normalizedValues));
var valuesWeb3 = getValues(JSON.parse(test.normalizedValues), FORMAT_WEB3);
var types = JSON.parse(test.types);
var result = test.result;
var title = test.name + ' => (' + test.types + ') = (' + test.normalizedValues + ')';
it(('decodes parameters - ' + test.name + ' - ' + test.types), function() {
var decoded = Interface.decodeParams(types, result);
var decodedArray = Array.prototype.slice.call(decoded);;
assert.ok(equals(values, decodedArray), 'decoded parameters - ' + title);
if (testWeb3) {
var badWeb3 = [ 'random-1116' ];
if (badWeb3.indexOf(test.name) >= 0) {
asset.ok(false, 'This testcase hangs in Web3');
} else {
var web3Decoded = web3Coder.decodeParams(types, result.substring(2));
//console.dir(valuesWeb3, { depth: null });
//console.dir(web3Decoded, { depth: null });
assert.ok(equals(valuesWeb3, web3Decoded), 'web3 decoded data - ' + title);
}
}
});
});
});

43
tests/test-hdnode.js Normal file
View File

@ -0,0 +1,43 @@
'use strict';
var assert = require('assert');
var utils = require('./utils');
describe('Test HD Node Derivation', function(test) {
var HDNode = require('../wallet/hdnode');
var Wallet = require('../wallet/wallet');
var tests = utils.loadTests('hdnode');
tests.forEach(function(test) {
it('Derives the HD nodes - ' + test.name, function() {
var rootNode = new HDNode.fromSeed(test.seed);
test.hdnodes.forEach(function(nodeTest) {
var node = rootNode.derivePath(nodeTest.path);
assert.equal(node.privateKey, nodeTest.privateKey,
'Generates privateKey - ' + nodeTest.privateKey);
var wallet = new Wallet(node.privateKey);
assert.equal(wallet.address.toLowerCase(), nodeTest.address,
'Generates address - ' + nodeTest.privateKey);
});
});
});
});
describe('Test HD Mnemonic Phrases', function testMnemonic() {
var HDNode = require('../wallet/hdnode');
var tests = utils.loadTests('hdnode');
tests.forEach(function(test) {
it(('converts mnemonic phrases - ' + test.name), function() {
assert.equal(HDNode.entropyToMnemonic(test.entropy), test.mnemonic,
'Converts entropy to mnemonic ' + test.name);
assert.equal(HDNode.mnemonicToEntropy(test.mnemonic), test.entropy,
'Converts mnemonic to entropy - ' + test.mnemonic);
assert.equal(HDNode.mnemonicToSeed(test.mnemonic, test.password), test.seed,
'Converts mnemonic to seed - ' + test.mnemonic + ':' + test.password);
});
});
});

129
tests/test-utils.js Normal file
View File

@ -0,0 +1,129 @@
'use strict';
var assert = require('assert');
var utils = require('./utils');
function equals(a, b) {
if (Array.isArray(a)) {
if (!Array.isArray(b) || a.length !== b.length) {
return false;
}
for (var i = 0; i < a.length; i++) {
if (!equals(a[i], b[i])) { return false; }
}
return true;
}
return a === b;
}
describe('Test Contract Address Generation', function() {
// @TODO: Mine a large collection of these from the blockchain
var getContractAddress = require('../utils/contract-address.js').getContractAddress;
// Transaction: 0x939aa17985bc2a52a0c1cba9497ef09e092355a805a8150e30e24b753bac6864
var Tests = [
{
address: '0x3474627D4F63A678266BC17171D87f8570936622',
name: 'tx-0x939aa17985bc2a52a0c1cba9497ef09e092355a805a8150e30e24b753bac6864',
tx: {
from: '0xb2682160c482eb985ec9f3e364eec0a904c44c23',
nonce: 10,
}
},
// Ropsten: 0x5bdfd14fcc917abc2f02a30721d152a6f147f09e8cbaad4e0d5405d646c5c3e1
{
address: '0x0CcCC7507aEDf9FEaF8C8D731421746e16b4d39D',
name: 'zero-nonce',
tx: {
from: '0xc6af6e1a78a6752c7f8cd63877eb789a2adb776c',
nonce: 0
}
},
]
Tests.forEach(function(test) {
it(('Computes the transaction address - ' + test.name), function() {
assert.equal(getContractAddress(test.tx), test.address, 'computes the transaction address');
});
});
});
describe('Test RLP Coder', function () {
var rlp = require('../utils/rlp.js');
var tests = utils.loadTests('rlp-coder');
tests.forEach(function(test) {
it(('RLP coder encoded - ' + test.name), function() {
assert.equal(rlp.encode(test.decoded), test.encoded, 'RLP encoded - ' + test.name);
});
});
tests.forEach(function(test) {
it(('RLP coder decoded - ' + test.name), function() {
assert.ok(equals(rlp.decode(test.encoded), test.decoded),
'RLP decoded - ' + test.name);
});
});
});
describe('Test Unit Conversion', function () {
var units = require('../utils/units.js');
var bigNumberify = require('../utils/bignumber.js').bigNumberify;
var tests = utils.loadTests('units');
tests.forEach(function(test) {
var wei = bigNumberify(test.wei);
var formatting = test.format || {};
it (('parses ' + test.ether + ' ether'), function() {
assert.ok(units.parseEther(test.ether).eq(wei),
'parsing ether failed - ' + test.name);
});
it (('formats ' + wei.toHexString() + ' wei (options: ' + JSON.stringify(formatting) + ')'), function() {
assert.equal(units.formatEther(wei, formatting), test.etherFormat,
'formatting wei failed - ' + test.name);
});
});
});
describe('Test Namehash', function() {
var namehash = require('../utils/namehash');
var tests = utils.loadTests('namehash');
tests.forEach(function(test) {
it(('computes namehash - "' + test.name + '"'), function() {
assert.equal(namehash(test.name), test.expected,
'computes namehash(' + test.name + ')');
});
});
});
describe('Test ID hash function', function () {
var id = require('../utils/id');
var tests = [
{
name: 'setAddr signature hash',
text: 'setAddr(bytes32,address)',
expected: '0xd5fa2b00b0756613052388dd576d941ba16904757996b8bb03a737ef4fd1f9ce'
}
]
tests.forEach(function(test) {
it(('computes id - ' + test.name), function() {
var value = id(test.text);
assert.equal(value, test.expected,
'computes id(' + test.text + ')');
});
});
});
// @TODO: Cryptographics hashes?

147
tests/test-wallet.js Normal file
View File

@ -0,0 +1,147 @@
'use strict';
var assert = require('assert');
var utils = require('./utils');
describe('Test Brain Wallets', function() {
var Wallet = require('../wallet/wallet');
var tests = [
{
address: '0xbed9d2E41BdD066f702C4bDB86eB3A3740101acC',
name: 'simple brain wallet',
password: 'password',
username: 'ricmoo'
}
];
tests.forEach(function(test) {
it(('computes the brain wallet for ' + test.name), function() {
return Wallet.fromBrainWallet(test.username, test.password).then(function(wallet) {
assert.equal(wallet.address, test.address,
'computed brain wallet for ' + test.username + ':' + test.password);
});
});
});
});
describe('Test JSON Wallets', function() {
var Wallet = require('../wallet/wallet');
var tests = utils.loadTests('wallets');
tests.forEach(function(test) {
it(('decrypts wallet - ' + test.name), function() {
assert.ok(Wallet.isEncryptedWallet(test.json),
'detect encrypted JSON wallet');
return Wallet.fromEncryptedWallet(test.json, test.password).then(function(wallet) {
assert.equal(wallet.privateKey, test.privateKey,
'generated correct private key - ' + wallet.privateKey);
assert.equal(wallet.address.toLowerCase(), test.address,
'generate correct address - ' + wallet.address);
});
});
});
// A few extra test cases to test encrypting/decrypting
['one', 'two', 'three'].forEach(function(i) {
var password = 'foobar' + i;
var wallet = new Wallet(utils.randomHexString('test-' + i, 32));
it('encrypts and decrypts a random wallet - ' + i, function() {
return wallet.encrypt(password).then(function(json) {
return Wallet.fromEncryptedWallet(json, password).then(function(decryptedWallet) {
assert.equal(decryptedWallet.address, wallet.address,
'decrypted wallet - ' + wallet.privateKey);
return decryptedWallet.encrypt(password).then(function(encryptedWallet) {
var parsedWallet = JSON.parse(encryptedWallet);
assert.equal(decryptedWallet.address.toLowerCase().substring(2), parsedWallet.address,
're-encrypted wallet - ' + wallet.privateKey);
});
});
});
});
});
});
describe('Test Transaction Signing and Parsing', function() {
var Wallet = require('../wallet/wallet');
var bigNumber = require('../utils/bignumber.js');
var convert = require('../utils/convert.js');
var getAddress = require('../utils/address.js').getAddress;
var tests = utils.loadTests('transactions');
tests.forEach(function(test) {
it(('parses and signs transaction - ' + test.name), function() {
var wallet = new Wallet(test.privateKey);
var transaction = {};
var parsedTransaction = Wallet.parseTransaction(test.signedTransaction);
['nonce', 'gasLimit', 'gasPrice', 'to', 'value', 'data'].forEach(function(key) {
var expected = test[key];
var value = parsedTransaction[key];
if ({ gasLimit: 1, gasPrice: 1, value: 1 }[key]) {
assert.ok((!!value._bn),
'parsed into a big number - ' + key);
value = value.toHexString();
if (!expected || expected === '0x') { expected = '0x00'; }
} else if (key === 'nonce') {
assert.equal(typeof(value), 'number',
'parse into a number - nonce');
value = utils.hexlify(value);
if (!expected || expected === '0x') { expected = '0x00'; }
} else if (key === 'data') {
if (!expected) { expected = '0x'; }
} else if (key === 'to') {
if (value) {
// Make sure teh address is valid
getAddress(value);
value = value.toLowerCase();
}
}
assert.equal(value, expected, 'parsed ' + key);
transaction[key] = test[key];
});
assert.equal(parsedTransaction.from, getAddress(test.accountAddress),
'computed from');
assert.equal(parsedTransaction.chainId, 0, 'parsed chainId');
var signedTransaction = wallet.sign(transaction);
assert.equal(signedTransaction, test.signedTransaction,
'signed transaction');
// EIP155
var parsedTransactionChainId5 = Wallet.parseTransaction(test.signedTransactionChainId5);
['data', 'from', 'nonce', 'to'].forEach(function (key) {
assert.equal(parsedTransaction[key], parsedTransactionChainId5[key],
'eip155 parsed ' + key);
});
['gasLimit', 'gasPrice', 'value'].forEach(function (key) {
assert.ok(parsedTransaction[key].eq(parsedTransactionChainId5[key]),
'eip155 parsed ' + key);
});
assert.equal(parsedTransactionChainId5.chainId, 5,
'eip155 parsed chainId');
transaction.chainId = 5;
var signedTransactionChainId5 = wallet.sign(transaction);
assert.equal(signedTransactionChainId5, test.signedTransactionChainId5,
'eip155 signed transaction');
});
});
});

Binary file not shown.

Binary file not shown.

BIN
tests/tests/hdnode.json.gz Normal file

Binary file not shown.

View File

@ -1,3 +0,0 @@
This file just ensures this directory exists.
Run the files in make-tests to create the individual test cases.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
tests/tests/units.json.gz Normal file

Binary file not shown.

BIN
tests/tests/wallets.json.gz Normal file

Binary file not shown.

View File

@ -1,7 +1,16 @@
'use strict';
var crypto = require('crypto');
var fs = require('fs');
var path = require('path');
var zlib = require('zlib');
//var utils = require('../lib/utils.js');
var bigNumber = require('../utils/bignumber');
var convert = require('../utils/convert');
var keccak256 = require('../utils/keccak256');
var utf8 = require('../utils/utf8');
/*
function random(lowerRandomInterval, upperOpenInterval) {
return lowerRandomInterval + parseInt((upperOpenInterval - lowerRandomInterval) * Math.random());
}
@ -14,6 +23,35 @@ function randomBuffer(length) {
function randomHexString(length) {
return '0x' + randomBuffer(length).toString('hex');
}
*/
function randomBytes(seed, lower, upper) {
if (!upper) { upper = lower; }
if (upper === 0 && upper === lower) { return new Uint8Array(0); }
seed = utf8.toUtf8Bytes(seed);
var result = convert.arrayify(keccak256(seed));
while (result.length < upper) {
result = convert.concat([result, keccak256(convert.concat([seed, result]))]);
}
var top = convert.arrayify(keccak256(result));
var percent = ((top[0] << 16) | (top[1] << 8) | top[2]) / 0x00ffffff;
return result.slice(0, lower + parseInt((upper - lower) * percent));
}
function randomHexString(seed, lower, upper) {
return convert.hexlify(randomBytes(seed, lower, upper));
}
function randomNumber(seed, lower, upper) {
var top = randomBytes(seed, 3);
var percent = ((top[0] << 16) | (top[1] << 8) | top[2]) / 0x00ffffff;
return lower + parseInt((upper - lower) * percent);
}
function equals(a, b) {
@ -46,12 +84,32 @@ function equals(a, b) {
return a === b;
}
module.exports = {
random: random,
randomBuffer: randomBuffer,
randomHexString: randomHexString,
equals: equals,
function saveTests(tag, data) {
var filename = path.resolve(__dirname, 'tests', tag + '.json.gz');
//isHexString: utils.isHexString,
//hexOrBuffer: utils.hexOrBuffer,
var data = JSON.stringify(data, undefined, ' ') + '\n';
fs.writeFileSync(filename, zlib.gzipSync(data));
console.log('Save testcase: ' + filename);
}
function loadTests(tag) {
var filename = path.resolve(__dirname, 'tests', tag + '.json.gz');
return JSON.parse(zlib.gunzipSync(fs.readFileSync(filename)));
}
module.exports = {
randomBytes: randomBytes,
randomHexString: randomHexString,
randomNumber:randomNumber,
bigNumberify: bigNumber.bigNumberify,
equals: equals,
isHexString: convert.isHexString,
hexlify: convert.hexlify,
arrayify: convert.arrayify,
loadTests: loadTests,
saveTests: saveTests,
}