diff --git a/.flowconfig b/.flowconfig index abe6b5cef..0cff1d89d 100644 --- a/.flowconfig +++ b/.flowconfig @@ -1,6 +1,7 @@ [ignore] /build /packages/.*/build +/node_modules/ethereumjs-testing [include] @@ -12,5 +13,5 @@ all=warn [options] include_warnings=true -module.name_mapper='^@polkadot/util-\(crypto\|triehash\)\(.*\)$' -> '/packages/util-\1/src\2' +module.name_mapper='^@polkadot/util-\(crypto\|rlp\|triehash\)\(.*\)$' -> '/packages/util-\1/src\2' module.name_mapper='^@polkadot/util\(.*\)$' -> '/packages/util/src\1' diff --git a/README.md b/README.md index 59ac64ee8..0eb2569a3 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ It is split up into a number of internal packages - - [packages/util](packages/util/) General utilities - [packages/util-crypto](packages/util-crypto/) Crypto and hashing utilities +- [packages/util-rlp](packages/util-rlp/) RLP encoding & decoding - [packages/util-triehash](packages/util-triehash/) Calculation of trie hashes ## Contributing diff --git a/jest.config.js b/jest.config.js index f4c4d2a86..bd77b1f47 100644 --- a/jest.config.js +++ b/jest.config.js @@ -2,7 +2,7 @@ const config = require('@polkadot/dev/config/jest'); module.exports = Object.assign({}, config, { moduleNameMapper: { - '@polkadot/util-(crypto|triehash)(.*)$': '/packages/util-$1/src/$2', + '@polkadot/util-(crypto|rlp|triehash)(.*)$': '/packages/util-$1/src/$2', '@polkadot/util(.*)$': '/packages/util/src/$1' } }); diff --git a/package.json b/package.json index be4cb2c7b..f9700614d 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "test": "jest --coverage" }, "devDependencies": { - "@polkadot/dev": "^0.15.2", + "@polkadot/dev": "^0.15.6", "lerna": "^2.5.1" } } diff --git a/packages/util-crypto/docs/keccak.md b/packages/util-crypto/docs/keccak.md index 73a713a3e..5904a6da5 100644 --- a/packages/util-crypto/docs/keccak.md +++ b/packages/util-crypto/docs/keccak.md @@ -12,7 +12,7 @@ Create Keccak256 values as hex, string, Buffer & Uint8Array output Creates a keccak Buffer from the input. ```js -keccakAsBuffer (value: Buffer | string): Buffer +keccakAsBuffer (value: Buffer | Uint8Array | string): Buffer ``` @@ -29,7 +29,7 @@ console.log('asBuffer', keccakAsBuffer('123')) // => Buffer Creates a keccak hex string from the input. ```js -keccakAsHex (value: Buffer | string): string +keccakAsHex (value: Buffer | Uint8Array | string): string ``` @@ -46,7 +46,7 @@ console.log('asHex', keccakAsHex('123')) // => 0x... Creates a keccak string from the input. ```js -keccakAsString (value: Buffer | string): string +keccakAsString (value: Buffer | Uint8Array | string): string ``` @@ -63,7 +63,7 @@ console.log('asString', keccakAsString('123')) // => string Creates a keccak Uint8Array from the input. ```js -keccakAsU8a (value: Buffer | string): Uint8Array +keccakAsU8a (value: Buffer | Uint8Array | string): Uint8Array ``` diff --git a/packages/util-crypto/package.json b/packages/util-crypto/package.json index 30ad13d0c..39a29ad8b 100644 --- a/packages/util-crypto/package.json +++ b/packages/util-crypto/package.json @@ -31,7 +31,7 @@ "dependencies": { "babel-runtime": "^6.26.0", "blakejs": "^1.1.0", - "keccak": "^1.3.0", + "keccak": "jacogr/keccak#f25ae4b299038bb2f0b72f150b99b5048ffb9e48", "tweetnacl": "^1.0.0", "xxhashjs": "^0.2.2" } diff --git a/packages/util-crypto/src/keccak/asBuffer.js b/packages/util-crypto/src/keccak/asBuffer.js index b47b7119c..c1c735460 100644 --- a/packages/util-crypto/src/keccak/asBuffer.js +++ b/packages/util-crypto/src/keccak/asBuffer.js @@ -7,7 +7,7 @@ const createKeccak = require('keccak'); /** @name keccakAsBuffer - @signature keccakAsBuffer (value: Buffer | string): Buffer + @signature keccakAsBuffer (value: Buffer | Uint8Array | string): Buffer @summary Creates a keccak Buffer from the input. @description From either a `string` or a `Buffer` input, create the keccak and return the result as a `Buffer`. @@ -16,6 +16,8 @@ const createKeccak = require('keccak'); console.log('asBuffer', keccakAsBuffer('123')) // => Buffer */ -module.exports = function keccakAsBuffer (value: Buffer | string): Buffer { - return createKeccak('keccak256').update(value).digest(); +module.exports = function keccakAsBuffer (value: Buffer | Uint8Array | string): Buffer { + // HACK: For the time being, don't change the definition (although fork of library is used) + // flowlint-next-line unclear-type:off + return createKeccak('keccak256').update(((value: any): Buffer)).digest(); }; diff --git a/packages/util-crypto/src/keccak/asBuffer.spec.js b/packages/util-crypto/src/keccak/asBuffer.spec.js index b2297768d..673b57672 100644 --- a/packages/util-crypto/src/keccak/asBuffer.spec.js +++ b/packages/util-crypto/src/keccak/asBuffer.spec.js @@ -2,6 +2,8 @@ // This software may be modified and distributed under the terms // of the ISC license. See the LICENSE file for details. +const u8aFromString = require('@polkadot/util/u8a/fromString'); + const { keccakAsBuffer } = require('./index'); const value = 'test value'; @@ -15,4 +17,12 @@ describe('keccakAsBuffer', () => { ) ).toEqual(true); }); + + it('returns an hex representation (Uint8Array input)', () => { + expect( + keccakAsBuffer(u8aFromString(value)).equals( + Buffer.from(result, 'hex') + ) + ).toEqual(true); + }); }); diff --git a/packages/util-crypto/src/keccak/asHex.js b/packages/util-crypto/src/keccak/asHex.js index b1e1190f3..74ae1e2cc 100644 --- a/packages/util-crypto/src/keccak/asHex.js +++ b/packages/util-crypto/src/keccak/asHex.js @@ -9,7 +9,7 @@ const keccakAsBuffer = require('./asBuffer'); /** @name keccakAsHex - @signature keccakAsHex (value: Buffer | string): string + @signature keccakAsHex (value: Buffer | Uint8Array | string): string @summary Creates a keccak hex string from the input. @description From either a `string` or a `Buffer` input, create the keccak and return the result as a `0x` prefixed hex string. @@ -18,7 +18,7 @@ const keccakAsBuffer = require('./asBuffer'); console.log('asHex', keccakAsHex('123')) // => 0x... */ -module.exports = function keccakAsHex (value: Buffer | string): string { +module.exports = function keccakAsHex (value: Buffer | Uint8Array | string): string { return bufferToHex( keccakAsBuffer(value) ); diff --git a/packages/util-crypto/src/keccak/asString.js b/packages/util-crypto/src/keccak/asString.js index 521a84472..aaeefe0e8 100644 --- a/packages/util-crypto/src/keccak/asString.js +++ b/packages/util-crypto/src/keccak/asString.js @@ -7,7 +7,7 @@ const keccakAsBuffer = require('./asBuffer'); /** @name keccakAsString - @signature keccakAsString (value: Buffer | string): string + @signature keccakAsString (value: Buffer | Uint8Array | string): string @summary Creates a keccak string from the input. @description From either a `string` or a `Buffer` input, create the keccak and return the result as a non-prefixed string. @@ -16,6 +16,6 @@ const keccakAsBuffer = require('./asBuffer'); console.log('asString', keccakAsString('123')) // => string */ -module.exports = function keccakAsString (value: Buffer | string): string { +module.exports = function keccakAsString (value: Buffer | Uint8Array | string): string { return keccakAsBuffer(value).toString('hex'); }; diff --git a/packages/util-crypto/src/keccak/asU8a.js b/packages/util-crypto/src/keccak/asU8a.js index 7ff659b88..2092c7e2a 100644 --- a/packages/util-crypto/src/keccak/asU8a.js +++ b/packages/util-crypto/src/keccak/asU8a.js @@ -4,11 +4,11 @@ // @flow const bufferToU8a = require('@polkadot/util/buffer/toU8a'); -const createKeccak = require('keccak'); +const keccakAsBuffer = require('./asBuffer'); /** @name keccakAsU8a - @signature keccakAsU8a (value: Buffer | string): Uint8Array + @signature keccakAsU8a (value: Buffer | Uint8Array | string): Uint8Array @summary Creates a keccak Uint8Array from the input. @description From either a `string` or a `Buffer` input, create the keccak and return the result as a `Uint8Array`. @@ -17,8 +17,8 @@ const createKeccak = require('keccak'); keccakAsU8a('123') // => Uint8Array */ -module.exports = function keccakAsU8a (value: Buffer | string): Uint8Array { +module.exports = function keccakAsU8a (value: Buffer | Uint8Array | string): Uint8Array { return bufferToU8a( - createKeccak('keccak256').update(value).digest() + keccakAsBuffer(value) ); }; diff --git a/packages/util-rlp/LICENSE b/packages/util-rlp/LICENSE new file mode 100644 index 000000000..3d150a620 --- /dev/null +++ b/packages/util-rlp/LICENSE @@ -0,0 +1,15 @@ +ISC License (ISC) + +Copyright 2017-2018 Jaco Greeff + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. diff --git a/packages/util-rlp/README.md b/packages/util-rlp/README.md new file mode 100644 index 000000000..fd4fbb850 --- /dev/null +++ b/packages/util-rlp/README.md @@ -0,0 +1,17 @@ +[![polkadotjs](https://img.shields.io/badge/polkadot-js-orange.svg?style=flat-square)](https://polkadot.js.org) +![isc](https://img.shields.io/badge/license-ISC-lightgrey.svg?style=flat-square) +[![style](https://img.shields.io/badge/code%20style-semistandard-lightgrey.svg?style=flat-square)](https://github.com/Flet/semistandard) +[![npm](https://img.shields.io/npm/v/@polkadot/util-rlp.svg?style=flat-square)](https://www.npmjs.com/package/@polkadot/util-rlp) +[![travis](https://img.shields.io/travis/polkadot-js/util.svg?style=flat-square)](https://travis-ci.org/polkadot-js/util) +[![maintainability](https://img.shields.io/codeclimate/maintainability/polkadot-js/util.svg?style=flat-square)](https://codeclimate.com/github/polkadot-js/util/maintainability) +[![coverage](https://img.shields.io/coveralls/polkadot-js/util.svg?style=flat-square)](https://coveralls.io/github/polkadot-js/util?branch=master) +[![dependency](https://david-dm.org/polkadot-js/util.svg?style=flat-square&path=packages/util)](https://david-dm.org/polkadot-js/util?path=packages/util-rlp) +[![devDependency](https://david-dm.org/polkadot-js/util/dev-status.svg?style=flat-square&path=packages/util-rlp)](https://david-dm.org/polkadot-js/util?path=packages/util-rlp#info=devDependencies) + +# @polkadot/util-rlp + +Encoding and decoding for [Ethereum RLP structures](https://github.com/ethereum/wiki/wiki/%5BEnglish%5D-RLP). This is port of the original [EthereumJS RLP](https://github.com/ethereumjs/rlp) to cater for `Uint8Array` outputs (instead of `Buffer`) in addition to typings. + +## Available Utilities + +For a list of currently exposed methods, see the [library documentation](docs/README.md). diff --git a/packages/util-rlp/docs/README.md b/packages/util-rlp/docs/README.md new file mode 100644 index 000000000..367df6d59 --- /dev/null +++ b/packages/util-rlp/docs/README.md @@ -0,0 +1,40 @@ +# Available interfaces + +Utility methods to encode and decode [Ethereum RLP](https://github.com/ethereum/wiki/wiki/RLP). Adapted from the [EthereumJS implementation](https://github.com/ethereumjs/rlp/blob/0ce09db81fc303fcee593f7cc094ba44015f9b92/index.js) + + +# Available methods + +## decode + +Decodes the input RLP. + +```js +decoder (input?: Uint8Array): Uint8Array | Array<*> +``` + + +From an input, decod the RLP and return the result as a `Uint8Array` or `Array`. + +```js +import { decode } from '@polkadot/util-rlp'; + +encode(new Uint8Array([0x83, 0x64, 0x6f, 0x67])) // => 'dog' as Uint8Array +``` + +## encode + +Encodes the input value into RLP. + +```js +encode (input: any): Uint8Array +``` + + +From an input, calculate the RLP and return the result as a `Uint8Array`. + +```js +import { encode } from '@polkadot/util-rlp'; + +encode('dog') // => [0x83, 0x64, 0x6f, 0x67] +``` \ No newline at end of file diff --git a/packages/util-rlp/package.json b/packages/util-rlp/package.json new file mode 100644 index 000000000..942ed7cee --- /dev/null +++ b/packages/util-rlp/package.json @@ -0,0 +1,38 @@ +{ + "name": "@polkadot/util-rlp", + "version": "0.14.1", + "description": "RLP encoding and decoding", + "main": "index.js", + "keywords": [ + "Polkadot" + ], + "author": "Jaco Greeff ", + "license": "ISC", + "engines": { + "node": ">=6.4" + }, + "publishConfig": { + "access": "public", + "registry": "https://registry.npmjs.org" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/polkadot-js/util.git" + }, + "bugs": { + "url": "https://github.com/polkadot-js/util/issues" + }, + "homepage": "https://github.com/polkadot-js/util/tree/master/packages/util-triehash#readme", + "scripts": { + "build": "polkadot-dev-build-babel && polkadot-dev-build-docs", + "check": "eslint src && flow check", + "test": "echo \"Tests only available from root wrapper\"" + }, + "dependencies": { + "@polkadot/util": "^0.14.1", + "babel-runtime": "^6.26.0" + }, + "devDependencies": { + "ethereumjs-testing": "^1.0.4" + } +} diff --git a/packages/util-rlp/src/decode.js b/packages/util-rlp/src/decode.js new file mode 100644 index 000000000..43ce8e691 --- /dev/null +++ b/packages/util-rlp/src/decode.js @@ -0,0 +1,19 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +const decoder = require('./decoder'); + +/** + @name decode + @signature decoder (input?: Uint8Array): Uint8Array | Array<*> + @summary Decodes the input RLP. + @description + From an input, decod the RLP and return the result as a `Uint8Array` or `Array`. + @example + import { decode } from '@polkadot/util-rlp'; + + encode(new Uint8Array([0x83, 0x64, 0x6f, 0x67])) // => 'dog' as Uint8Array +*/ +module.exports = decoder; diff --git a/packages/util-rlp/src/decode.spec.js b/packages/util-rlp/src/decode.spec.js new file mode 100644 index 000000000..b5db663b6 --- /dev/null +++ b/packages/util-rlp/src/decode.spec.js @@ -0,0 +1,42 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. + +const hexToU8a = require('@polkadot/util/hex/toU8a'); +const u8aToHex = require('@polkadot/util/u8a/toHex'); + +const { decode, encode } = require('./index'); + +const rlptests = require('../test/getTests')('RLPTests/rlptest.json'); + +describe('decode', () => { + it('returns empty list for undefined inputs', () => { + expect( + decode() + ).toEqual( + new Uint8Array([]) + ); + }); + + it('returns empty list for empty inputs', () => { + expect( + decode([]) + ).toEqual( + new Uint8Array([]) + ); + }); + + rlptests.forEach(({ name, output }) => { + it(`passes official ${name}`, () => { + expect( + u8aToHex( + encode( + decode( + hexToU8a(output) + ) + ) + ) + ).toEqual(output); + }); + }); +}); diff --git a/packages/util-rlp/src/decoder/.nodoc b/packages/util-rlp/src/decoder/.nodoc new file mode 100644 index 000000000..e69de29bb diff --git a/packages/util-rlp/src/decoder/decode.js b/packages/util-rlp/src/decoder/decode.js new file mode 100644 index 000000000..09a333e8b --- /dev/null +++ b/packages/util-rlp/src/decoder/decode.js @@ -0,0 +1,42 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +import type { DecodeOutput } from './types'; + +const decodeListLong = require('./listLong'); +const decodeListShort = require('./listShort'); +const decodeNumber = require('./number'); +const decodeSingle = require('./single'); +const decodeString = require('./string'); + +function decode (input: Uint8Array): DecodeOutput { + const firstByte = input[0]; + + // a single byte whose value is in the [0x00, 0x7f] range, that byte is its own RLP encoding + if (firstByte <= 0x7f) { + return decodeSingle(decode, input); + } + + // string is 0-55 bytes long. A single byte with value 0x80 plus the length of the string followed by the string + // The range of the first byte is [0x80, 0xb7] + if (firstByte <= 0xb7) { + return decodeString(decode, input); + } + + // a number + if (firstByte <= 0xbf) { + return decodeNumber(decode, input); + } + + // a list between 0-55 bytes long + if (firstByte <= 0xf7) { + return decodeListShort(decode, input); + } + + // a list over 55 bytes long + return decodeListLong(decode, input); +} + +module.exports = decode; diff --git a/packages/util-rlp/src/decoder/index.js b/packages/util-rlp/src/decoder/index.js new file mode 100644 index 000000000..171a780a9 --- /dev/null +++ b/packages/util-rlp/src/decoder/index.js @@ -0,0 +1,20 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +const assert = require('@polkadot/util/assert'); + +const internalDecode = require('./decode'); + +module.exports = function decoder (input?: Uint8Array): Uint8Array | Array<*> { + if (!input || input.length === 0) { + return new Uint8Array([]); + } + + const { decoded, remainder } = internalDecode(input); + + assert(remainder.length === 0, 'invalid remainder'); + + return decoded; +}; diff --git a/packages/util-rlp/src/decoder/listLong.js b/packages/util-rlp/src/decoder/listLong.js new file mode 100644 index 000000000..4a8ffd56d --- /dev/null +++ b/packages/util-rlp/src/decoder/listLong.js @@ -0,0 +1,35 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +import type { DecodeFunc, DecodeOutput } from './types'; + +const assert = require('@polkadot/util/assert'); + +const safeParseInt = require('./safeParseInt'); + +module.exports = function decodeListLong (decode: DecodeFunc, input: Uint8Array): DecodeOutput { + const llength = input[0] - 0xf6; + const length = safeParseInt(input.slice(1, llength)); + const totalLength = llength + length; + const decoded = []; + + assert(totalLength <= input.length, 'invalid rlp: total length is larger than the data'); + + let innerRemainder = input.slice(llength, totalLength); + + assert(innerRemainder.length > 0, 'invalid rlp, List has a invalid length'); + + while (innerRemainder.length) { + const d = decode(innerRemainder); + + decoded.push(d.decoded); + innerRemainder = d.remainder; + } + + return { + decoded, + remainder: input.slice(totalLength) + }; +}; diff --git a/packages/util-rlp/src/decoder/listShort.js b/packages/util-rlp/src/decoder/listShort.js new file mode 100644 index 000000000..da5f18e22 --- /dev/null +++ b/packages/util-rlp/src/decoder/listShort.js @@ -0,0 +1,24 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +import type { DecodeFunc, DecodeOutput } from './types'; + +module.exports = function decodeListShort (decode: DecodeFunc, input: Uint8Array): DecodeOutput { + const length = input[0] - 0xbf; + let innerRemainder = input.slice(1, length); + const decoded = []; + + while (innerRemainder.length) { + const d = decode(innerRemainder); + + decoded.push(d.decoded); + innerRemainder = d.remainder; + } + + return { + decoded, + remainder: input.slice(length) + }; +}; diff --git a/packages/util-rlp/src/decoder/number.js b/packages/util-rlp/src/decoder/number.js new file mode 100644 index 000000000..e95b69532 --- /dev/null +++ b/packages/util-rlp/src/decoder/number.js @@ -0,0 +1,23 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +import type { DecodeFunc, DecodeOutput } from './types'; + +const assert = require('@polkadot/util/assert'); + +const safeParseInt = require('./safeParseInt'); + +module.exports = function decodeNumber (decode: DecodeFunc, input: Uint8Array): DecodeOutput { + const llength = input[0] - 0xb6; + const length = safeParseInt(input.slice(1, llength)); + const decoded = input.slice(llength, length + llength); + + assert(decoded.length === length, 'invalid RLP'); + + return { + decoded, + remainder: input.slice(length + llength) + }; +}; diff --git a/packages/util-rlp/src/decoder/safeParseInt.js b/packages/util-rlp/src/decoder/safeParseInt.js new file mode 100644 index 000000000..ce8f82241 --- /dev/null +++ b/packages/util-rlp/src/decoder/safeParseInt.js @@ -0,0 +1,12 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +const assert = require('@polkadot/util/assert'); + +module.exports = function safeParseInt (input: Uint8Array): number { + assert(input[0] > 0, 'invalid RLP: extra zeros'); + + return input.reduce((result, value) => (result * 256) + value, 0); +}; diff --git a/packages/util-rlp/src/decoder/safeParseInt.spec.js b/packages/util-rlp/src/decoder/safeParseInt.spec.js new file mode 100644 index 000000000..be37100ed --- /dev/null +++ b/packages/util-rlp/src/decoder/safeParseInt.spec.js @@ -0,0 +1,24 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +const safeParseInt = require('./safeParseInt'); + +describe('safeParseInt', () => { + it('does not allow 0 in first position', () => { + expect( + () => safeParseInt( + new Uint8Array([0]) + ) + ).toThrow(/invalid RLP: extra zeros/); + }); + + it('converts a value to the correct number', () => { + expect( + safeParseInt( + new Uint8Array([0x12, 0x34, 0x56]) + ) + ).toEqual(0x123456); + }); +}); diff --git a/packages/util-rlp/src/decoder/single.js b/packages/util-rlp/src/decoder/single.js new file mode 100644 index 000000000..9576cac55 --- /dev/null +++ b/packages/util-rlp/src/decoder/single.js @@ -0,0 +1,13 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +import type { DecodeFunc, DecodeOutput } from './types'; + +module.exports = function decodeSingle (decode: DecodeFunc, input: Uint8Array): DecodeOutput { + return { + decoded: input.slice(0, 1), + remainder: input.slice(1) + }; +}; diff --git a/packages/util-rlp/src/decoder/string.js b/packages/util-rlp/src/decoder/string.js new file mode 100644 index 000000000..8acde240f --- /dev/null +++ b/packages/util-rlp/src/decoder/string.js @@ -0,0 +1,28 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +import type { DecodeFunc, DecodeOutput } from './types'; + +const assert = require('@polkadot/util/assert'); + +module.exports = function decodeString (decode: DecodeFunc, input: Uint8Array): DecodeOutput { + const firstByte = input[0]; + const length = firstByte - 0x7f; + let decoded; + + // set 0x80 null to 0 + if (firstByte === 0x80) { + decoded = new Uint8Array([]); + } else { + decoded = input.slice(1, length); + } + + assert(!(length === 2 && decoded[0] < 0x80), 'invalid rlp encoding: byte must be less 0x80'); + + return { + decoded, + remainder: input.slice(length) + }; +}; diff --git a/packages/util-rlp/src/decoder/types.js b/packages/util-rlp/src/decoder/types.js new file mode 100644 index 000000000..18f956241 --- /dev/null +++ b/packages/util-rlp/src/decoder/types.js @@ -0,0 +1,11 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +export type DecodeOutput = { + decoded: Uint8Array | Array<*>, + remainder: Uint8Array +} + +export type DecodeFunc = (input: Uint8Array) => DecodeOutput; diff --git a/packages/util-rlp/src/encode.js b/packages/util-rlp/src/encode.js new file mode 100644 index 000000000..9248eaed8 --- /dev/null +++ b/packages/util-rlp/src/encode.js @@ -0,0 +1,19 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +const encoder = require('./encoder'); + +/** + @name encode + @signature encode (input: any): Uint8Array + @summary Encodes the input value into RLP. + @description + From an input, calculate the RLP and return the result as a `Uint8Array`. + @example + import { encode } from '@polkadot/util-rlp'; + + encode('dog') // => [0x83, 0x64, 0x6f, 0x67] +*/ +module.exports = encoder; diff --git a/packages/util-rlp/src/encode.spec.js b/packages/util-rlp/src/encode.spec.js new file mode 100644 index 000000000..069081b66 --- /dev/null +++ b/packages/util-rlp/src/encode.spec.js @@ -0,0 +1,21 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. + +const u8aToHex = require('@polkadot/util/u8a/toHex'); + +const { encode } = require('./index'); + +const rlptests = require('../test/getTests')('RLPTests/rlptest.json'); + +describe('encode', () => { + rlptests.forEach(({ name, input, output }) => { + it(`passes official ${name}`, () => { + expect( + u8aToHex( + encode(input) + ) + ).toEqual(output); + }); + }); +}); diff --git a/packages/util-rlp/src/encoder/.nodoc b/packages/util-rlp/src/encoder/.nodoc new file mode 100644 index 000000000..e69de29bb diff --git a/packages/util-rlp/src/encoder/array.js b/packages/util-rlp/src/encoder/array.js new file mode 100644 index 000000000..4c76d2f68 --- /dev/null +++ b/packages/util-rlp/src/encoder/array.js @@ -0,0 +1,28 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +import type { EncodeFunc } from './types'; + +const u8aConcat = require('@polkadot/util/u8a/concat'); + +const encodeLength = require('./length'); + +// flowlint-next-line unclear-type:off +module.exports = function encodeArray (encoder: EncodeFunc, input: any): Uint8Array { + const output = []; + + for (let i = 0; i < input.length; i++) { + output.push( + encoder(input[i]) + ); + } + + const encoded = u8aConcat(output); + + return u8aConcat([ + encodeLength(encoded.length, 192), + encoded + ]); +}; diff --git a/packages/util-rlp/src/encoder/index.js b/packages/util-rlp/src/encoder/index.js new file mode 100644 index 000000000..4962ec304 --- /dev/null +++ b/packages/util-rlp/src/encoder/index.js @@ -0,0 +1,19 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +const encodeArray = require('./array'); +const toU8a = require('./toU8a'); +const encodeU8a = require('./u8a'); + +// flowlint-next-line unclear-type:off +function encoder (input: any): Uint8Array { + if (input instanceof Array) { + return encodeArray(encoder, input); + } + + return encodeU8a(encoder, toU8a(input)); +} + +module.exports = encoder; diff --git a/packages/util-rlp/src/encoder/length.js b/packages/util-rlp/src/encoder/length.js new file mode 100644 index 000000000..e7e162534 --- /dev/null +++ b/packages/util-rlp/src/encoder/length.js @@ -0,0 +1,19 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +const numberToHex = require('@polkadot/util/number/toHex'); +const hexToU8a = require('@polkadot/util/hex/toU8a'); + +module.exports = function encodeLength (length: number, offset: number): Uint8Array { + if (length < 56) { + return new Uint8Array([length + offset]); + } + + const hexLength = numberToHex(length).slice(2); + + return hexToU8a( + numberToHex(offset + 55 + hexLength.length / 2) + hexLength + ); +}; diff --git a/packages/util-rlp/src/encoder/length.spec.js b/packages/util-rlp/src/encoder/length.spec.js new file mode 100644 index 000000000..3eee0bfc9 --- /dev/null +++ b/packages/util-rlp/src/encoder/length.spec.js @@ -0,0 +1,31 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. + +const encodeLength = require('./length'); + +describe('encodeLength', () => { + it('returns offset + length where <= 55', () => { + expect( + encodeLength(5, 6) + ).toEqual( + new Uint8Array([11]) + ); + }); + + it('encodes > 55 length properly (short)', () => { + expect( + encodeLength(56, 6) + ).toEqual( + new Uint8Array([62, 56]) + ); + }); + + it('encodes > 55 length properly (long)', () => { + expect( + encodeLength(512, 6) + ).toEqual( + new Uint8Array([63, 2, 0]) + ); + }); +}); diff --git a/packages/util-rlp/src/encoder/toU8a.js b/packages/util-rlp/src/encoder/toU8a.js new file mode 100644 index 000000000..b514870d2 --- /dev/null +++ b/packages/util-rlp/src/encoder/toU8a.js @@ -0,0 +1,51 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +const bnToU8a = require('@polkadot/util/bn/toU8a'); +const bufferToU8a = require('@polkadot/util/buffer/toU8a'); +const hexHasPrefix = require('@polkadot/util/hex/hasPrefix'); +const hexToU8a = require('@polkadot/util/hex/toU8a'); +const isInstanceOf = require('@polkadot/util/is/instanceOf'); +const isBn = require('@polkadot/util/is/bn'); +const isBuffer = require('@polkadot/util/is/buffer'); +const isNull = require('@polkadot/util/is/null'); +const isNumber = require('@polkadot/util/is/number'); +const isString = require('@polkadot/util/is/string'); +const isUndefined = require('@polkadot/util/is/undefined'); +const numberToU8a = require('@polkadot/util/number/toU8a'); +const u8aFromUtf8 = require('@polkadot/util/u8a/fromUtf8'); + +// flowlint-next-line unclear-type:off +module.exports = function toU8a (value: any): Uint8Array { + if (isNull(value) || isUndefined(value)) { + return new Uint8Array([]); + } + + if (isBuffer(value)) { + return bufferToU8a(value); + } + + if (isInstanceOf(value, Uint8Array)) { + return value; + } + + if (isNumber(value)) { + return numberToU8a(value); + } + + if (isString(value)) { + if (hexHasPrefix(value)) { + return hexToU8a(value); + } + + return u8aFromUtf8(value); + } + + if (isBn(value)) { + return bnToU8a(value); + } + + throw new Error('invalid type'); +}; diff --git a/packages/util-rlp/src/encoder/toU8a.spec.js b/packages/util-rlp/src/encoder/toU8a.spec.js new file mode 100644 index 000000000..29340ac56 --- /dev/null +++ b/packages/util-rlp/src/encoder/toU8a.spec.js @@ -0,0 +1,79 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. + +const BN = require('bn.js'); + +const toU8a = require('./toU8a'); + +describe('toU8a', () => { + it('returns a Uint8Array input as-is', () => { + expect( + toU8a(new Uint8Array([1, 2, 3])) + ).toEqual( + new Uint8Array([1, 2, 3]) + ); + }); + + it('converts Buffers (uses as Uint8Array)', () => { + expect( + toU8a(Buffer.from([0x12, 0x34, 0x56])) + ).toEqual( + new Uint8Array([0x12, 0x34, 0x56]) + ); + }); + + it('returns undefined as empty', () => { + expect( + toU8a() + ).toEqual( + new Uint8Array([]) + ); + }); + + it('returns null as empty', () => { + expect( + toU8a(null) + ).toEqual( + new Uint8Array([]) + ); + }); + + it('converts hex strings', () => { + expect( + toU8a('0x123456') + ).toEqual( + new Uint8Array([0x12, 0x34, 0x56]) + ); + }); + + it('converts UTF-8 strings', () => { + expect( + toU8a('Привет, мир!') + ).toEqual( + new Uint8Array([208, 159, 209, 128, 208, 184, 208, 178, 208, 181, 209, 130, 44, 32, 208, 188, 208, 184, 209, 128, 33]) + ); + }); + + it('converts numbers', () => { + expect( + toU8a(0x123456) + ).toEqual( + new Uint8Array([0x12, 0x34, 0x56]) + ); + }); + + it('converts BN', () => { + expect( + toU8a(new BN(0x123456)) + ).toEqual( + new Uint8Array([0x12, 0x34, 0x56]) + ); + }); + + it('throws on unknown type', () => { + expect( + () => toU8a(true) + ).toThrow(/invalid type/); + }); +}); diff --git a/packages/util-triehash/src/util/index.js b/packages/util-rlp/src/encoder/types.js similarity index 64% rename from packages/util-triehash/src/util/index.js rename to packages/util-rlp/src/encoder/types.js index 0a8363f51..6c85acf3c 100644 --- a/packages/util-triehash/src/util/index.js +++ b/packages/util-rlp/src/encoder/types.js @@ -3,7 +3,5 @@ // of the ISC license. See the LICENSE file for details. // @flow -/** - @summary Internal utilities used along with hash generation -*/ -module.exports = {}; +// flowlint-next-line unclear-type:off +export type EncodeFunc = (input: any) => Uint8Array; diff --git a/packages/util-rlp/src/encoder/u8a.js b/packages/util-rlp/src/encoder/u8a.js new file mode 100644 index 000000000..981836007 --- /dev/null +++ b/packages/util-rlp/src/encoder/u8a.js @@ -0,0 +1,21 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +import type { EncodeFunc } from './types'; + +const u8aConcat = require('@polkadot/util/u8a/concat'); + +const encodeLength = require('./length'); + +module.exports = function encodeU8a (encoder: EncodeFunc, input: Uint8Array): Uint8Array { + if (input.length === 1 && input[0] < 128) { + return input; + } + + return u8aConcat([ + encodeLength(input.length, 128), + input + ]); +}; diff --git a/packages/util-rlp/src/index.js b/packages/util-rlp/src/index.js new file mode 100644 index 000000000..46d3b3a9c --- /dev/null +++ b/packages/util-rlp/src/index.js @@ -0,0 +1,15 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +const decode = require('./decode'); +const encode = require('./encode'); + +/** + @summary Utility methods to encode and decode [Ethereum RLP](https://github.com/ethereum/wiki/wiki/RLP). Adapted from the [EthereumJS implementation](https://github.com/ethereumjs/rlp/blob/0ce09db81fc303fcee593f7cc094ba44015f9b92/index.js) +*/ +module.exports = { + decode, + encode +}; diff --git a/packages/util-rlp/test/getTests.js b/packages/util-rlp/test/getTests.js new file mode 100644 index 000000000..41e4ac2b8 --- /dev/null +++ b/packages/util-rlp/test/getTests.js @@ -0,0 +1,20 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. + +const BN = require('bn.js'); +const { getSingleFile } = require('ethereumjs-testing'); + +const bnToU8a = require('@polkadot/util/bn/toU8a'); + +module.exports = function getTests (file) { + const tests = getSingleFile(file); + + return Object.keys(tests).map((name) => ({ + name, + input: tests[name].in[0] !== '#' + ? tests[name].in + : bnToU8a(new BN(tests[name].in.slice(1))), + output: `0x${tests[name].out.toLowerCase()}` + })); +}; diff --git a/packages/util-triehash/docs/README.md b/packages/util-triehash/docs/README.md index 5a81b31ba..ed22f7387 100644 --- a/packages/util-triehash/docs/README.md +++ b/packages/util-triehash/docs/README.md @@ -2,7 +2,6 @@ Utility methods to create [Ethereum Trie hashes](https://github.com/ethereum/wiki/wiki/Patricia-Tree) -- [util](util.md) Internal utilities used along with hash generation # Available methods @@ -32,7 +31,7 @@ v: u8aFromString('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa') Creates a trie hash from the supplied values. ```js -trieRootOrdered (pvalues: Array): Uint8Array +trieRootOrdered (values: Array): Uint8Array ``` diff --git a/packages/util-triehash/docs/util.md b/packages/util-triehash/docs/util.md deleted file mode 100644 index 5d97e62e5..000000000 --- a/packages/util-triehash/docs/util.md +++ /dev/null @@ -1,22 +0,0 @@ -# util - -Internal utilities used along with hash generation - -- [asNibbles](#asnibbles) Converts the input to Nibbles. - -## asNibbles - -Converts the input to Nibbles. - -```js -asNibbles (pairs: Trie$Pairs): Uint8Array -``` - - -From an `Uint8Array` input, calculate and return a list of nibbles that makes up the input. - -```js -import { asNibbles } from '@polkadot/util-triehash/util'; - -asNibbles(new Uint8Array([0x41, 0x20]) // => Uint8Array([4, 1, 2, 0]) -``` \ No newline at end of file diff --git a/packages/util-triehash/package.json b/packages/util-triehash/package.json index e40d2c47e..441f6afbd 100644 --- a/packages/util-triehash/package.json +++ b/packages/util-triehash/package.json @@ -31,7 +31,7 @@ "dependencies": { "@polkadot/util": "^0.14.1", "@polkadot/util-crypto": "^0.14.1", - "babel-runtime": "^6.26.0", - "rlp": "jacogr/rlp" + "@polkadot/util-rlp": "^0.14.1", + "babel-runtime": "^6.26.0" } } diff --git a/packages/util-triehash/src/rootOrdered.js b/packages/util-triehash/src/rootOrdered.js index 131e69a66..658fd7520 100644 --- a/packages/util-triehash/src/rootOrdered.js +++ b/packages/util-triehash/src/rootOrdered.js @@ -2,8 +2,7 @@ // of the ISC license. See the LICENSE file for details. // @flow -const bufferToU8a = require('@polkadot/util/buffer/toU8a'); -const rlp = require('rlp'); +const rlpEncode = require('@polkadot/util-rlp/encode'); const asNibbles = require('./util/asNibbles'); const genRoot = require('./util/genRoot'); @@ -11,7 +10,7 @@ const pairsUniq = require('./util/pairsUniq'); /** @name trieRootOrdered - @signature trieRootOrdered (pvalues: Array): Uint8Array + @signature trieRootOrdered (values: Array): Uint8Array @summary Creates a trie hash from the supplied values. @description From an `Array` input, calculate the ordered triehash and return the result as a `Uint8Array`. @@ -29,10 +28,7 @@ module.exports = function trieRootOrdered (values: Array): Uint8Arra pairsUniq( values.map((v, index) => ({ k: asNibbles( - bufferToU8a( - // $FlowFixMe rlp type definition is lacking - rlp.encode(index) - ) + rlpEncode(index) ), v })) diff --git a/packages/util-triehash/src/util/.nodoc b/packages/util-triehash/src/util/.nodoc new file mode 100644 index 000000000..e69de29bb diff --git a/packages/util-triehash/src/util/encode.js b/packages/util-triehash/src/util/encode.js index c9c7cfa2e..a0a416c73 100644 --- a/packages/util-triehash/src/util/encode.js +++ b/packages/util-triehash/src/util/encode.js @@ -6,7 +6,7 @@ import type { Trie$Pairs } from '../types'; const keccakAsU8a = require('@polkadot/util-crypto/keccak/asU8a'); -const rlp = require('rlp'); +const rlpEncode = require('@polkadot/util-rlp/encode'); const encodeHexPrefix = require('./encodeHexPrefix'); const sharedPrefixLength = require('./sharedPrefixLength'); @@ -14,8 +14,7 @@ const sharedPrefixLength = require('./sharedPrefixLength'); // flowlint-next-line unclear-type:off function encodeAux (pairs: Trie$Pairs, preLength: number): any { const encoded = encode(pairs, preLength); - // flowlint-next-line unclear-type:off - const rlped = rlp.encode((encoded: any)); + const rlped = rlpEncode(encoded); if (rlped.length <= 31) { return encoded; diff --git a/packages/util-triehash/src/util/genRoot.js b/packages/util-triehash/src/util/genRoot.js index d3ee5baaa..469dd505c 100644 --- a/packages/util-triehash/src/util/genRoot.js +++ b/packages/util-triehash/src/util/genRoot.js @@ -6,14 +6,13 @@ import type { Trie$Pairs } from '../types'; const keccakAsU8a = require('@polkadot/util-crypto/keccak/asU8a'); -const rlp = require('rlp'); +const rlpEncode = require('@polkadot/util-rlp/encode'); const encode = require('./encode'); module.exports = function genRoot (pairs: Trie$Pairs): Uint8Array { return keccakAsU8a( - rlp.encode( - // $FlowFixMe rlp definition is not 100% + rlpEncode( encode(pairs, 0) ) ); diff --git a/packages/util/docs/bn.md b/packages/util/docs/bn.md index 96990034c..306e6a005 100644 --- a/packages/util/docs/bn.md +++ b/packages/util/docs/bn.md @@ -4,6 +4,7 @@ Utility methods to convert to and from `BN` objects - [bnFromHex](#bnfromhex) Creates a BN.js bignumber object from a hex string. - [bnToHex](#bntohex) Creates a hex value from a BN.js bignumber object. +- [bnToU8a](#bntou8a) Creates a Uint8Array object from a BN. ## bnFromHex @@ -33,4 +34,21 @@ import BN from 'bn.js'; import { bnToHex } from '@polkadot/util'; bnToHex(new BN(0x123456)); // => '0x123456' +``` + +## bnToU8a + +Creates a Uint8Array object from a BN. + +```js +bnToU8a (value?: BN): Uint8Array +``` + + +`null`/`undefined`/`NaN` inputs returns an empty `Uint8Array` result. `BN` input values return the actual bytes value converted to a `Uint8Array`. + +```js +import { bnToU8a } from '@polkadot/util'; + +bnToU8a(new BN(0x1234)); // => [0x12, 0x34] ``` \ No newline at end of file diff --git a/packages/util/docs/number.md b/packages/util/docs/number.md index 1997177d3..0fb715468 100644 --- a/packages/util/docs/number.md +++ b/packages/util/docs/number.md @@ -6,6 +6,7 @@ Utility methods to convert to and from `number` values - [numberFromHex](#numberfromhex) Creates a Number value from a Buffer object. - [numberToBuffer](#numbertobuffer) Creates a Buffer object from a number. - [numberToHex](#numbertohex) Creates a hex value from a number. +- [numberToU8a](#numbertou8a) Creates a Uint8Array object from a number. ## numberFromBuffer @@ -63,4 +64,21 @@ numberToHex (value?: number): string import { numberToHex } from '@polkadot/util'; const hex = numberToHex(0x1234); // => '0x1234' +``` + +## numberToU8a + +Creates a Uint8Array object from a number. + +```js +numberToBuffer (value?: number): Uint8Array +``` + + +`null`/`undefined`/`NaN` inputs returns an empty `Uint8Array` result. `number` input values return the actual bytes value converted to a `Uint8Array`. + +```js +import { numberToU8a } from '@polkadot/util'; + +numberToU8a(0x1234); // => [0x12, 0x34] ``` \ No newline at end of file diff --git a/packages/util/docs/u8a.md b/packages/util/docs/u8a.md index 649a36146..dd0053d48 100644 --- a/packages/util/docs/u8a.md +++ b/packages/util/docs/u8a.md @@ -2,6 +2,8 @@ Utility methods to convert to and from `Uint8Array` objects +- [u8aConcat](#u8aconcat) Creates a concatenated Uint8Array from the inputs. +- [u8aFromBn](#u8afrombn) Creates a Uint8Array value from a BN object. - [u8aFromBuffer](#u8afrombuffer) Creates a Uint8Array value from a Buffer object. - [u8aFromHex](#u8afromhex) Creates a Uint8Array value from a hex string. - [u8aFromString](#u8afromstring) Creates a Uint8Array object from a string. @@ -10,6 +12,38 @@ Utility methods to convert to and from `Uint8Array` objects - [u8aToHex](#u8atohex) Creates a hex string from a Uint8Array object. - [u8aToUtf8](#u8atoutf8) Creates a utf-8 string from a Uint8Array object. +## u8aConcat + +Creates a concatenated Uint8Array from the inputs. + +```js +u8aConcat (values: Array): Uint8Array +``` + + +Concatenates the input arrays into a single `UInt8Array`. + +```js +import { u8aConcat } from '@polkadot/util'; + +u8aConcat([ +new Uint8Array([1, 2, 3]), +new Uint8Array([4, 5, 6]) +]); // [1, 2, 3, 4, 5, 6] +``` + +## u8aFromBn + +Creates a Uint8Array value from a BN object. [(alias of bnToU8a)](bn.md#bntou8a) + +```js +u8aFromBn (value?: BN): Uint8Array +``` + + + + + ## u8aFromBuffer Creates a Uint8Array value from a Buffer object. [(alias of bufferToU8a)](buffer.md#buffertou8a) diff --git a/packages/util/src/bn/index.js b/packages/util/src/bn/index.js index d368ffab1..0acf9a9b5 100644 --- a/packages/util/src/bn/index.js +++ b/packages/util/src/bn/index.js @@ -5,11 +5,13 @@ const bnFromHex = require('./fromHex'); const bnToHex = require('./toHex'); +const bnToU8a = require('./toU8a'); /** @summary Utility methods to convert to and from `BN` objects */ module.exports = { bnFromHex, - bnToHex + bnToHex, + bnToU8a }; diff --git a/packages/util/src/bn/toU8a.js b/packages/util/src/bn/toU8a.js new file mode 100644 index 000000000..365800d48 --- /dev/null +++ b/packages/util/src/bn/toU8a.js @@ -0,0 +1,26 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +import type BN from 'bn.js'; + +/** + @name bnToU8a + @signature bnToU8a (value?: BN): Uint8Array + @summary Creates a Uint8Array object from a BN. + @description + `null`/`undefined`/`NaN` inputs returns an empty `Uint8Array` result. `BN` input values return the actual bytes value converted to a `Uint8Array`. + @example + import { bnToU8a } from '@polkadot/util'; + + bnToU8a(new BN(0x1234)); // => [0x12, 0x34] +*/ +module.exports = function bnToU8a (value?: BN): Uint8Array { + if (!value) { + return new Uint8Array([]); + } + + // $FlowFixMe toArray doesn't need params + return new Uint8Array(value.toArray()); +}; diff --git a/packages/util/src/bn/toU8a.spec.js b/packages/util/src/bn/toU8a.spec.js new file mode 100644 index 000000000..ff8caf9fd --- /dev/null +++ b/packages/util/src/bn/toU8a.spec.js @@ -0,0 +1,21 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. + +const BN = require('bn.js'); + +const { bnToU8a } = require('./index'); + +describe('bnToU8a', () => { + it('converts BN values to a prefixed hex representation', () => { + expect( + bnToU8a(new BN(0x123456)) + ).toEqual(new Uint8Array([0x12, 0x34, 0x56])); + }); + + it('converts null values to 0x00', () => { + expect( + bnToU8a(null) + ).toEqual(new Uint8Array([])); + }); +}); diff --git a/packages/util/src/buffer/toU8a.js b/packages/util/src/buffer/toU8a.js index 9c0ae0525..b6a722412 100644 --- a/packages/util/src/buffer/toU8a.js +++ b/packages/util/src/buffer/toU8a.js @@ -19,11 +19,5 @@ module.exports = function bufferToU8a (buffer?: Buffer): Uint8Array { return new Uint8Array([]); } - const array = new Uint8Array(buffer.length); - - for (let index = 0; index < buffer.length; ++index) { - array[index] = buffer[index]; - } - - return array; + return new Uint8Array(buffer); }; diff --git a/packages/util/src/number/index.js b/packages/util/src/number/index.js index 61ac84aed..310f1ddac 100644 --- a/packages/util/src/number/index.js +++ b/packages/util/src/number/index.js @@ -7,6 +7,7 @@ const numberFromBuffer = require('./fromBuffer'); const numberFromHex = require('./fromHex'); const numberToBuffer = require('./toBuffer'); const numberToHex = require('./toHex'); +const numberToU8a = require('./toU8a'); /** @summary Utility methods to convert to and from `number` values @@ -15,5 +16,6 @@ module.exports = { numberFromBuffer, numberFromHex, numberToBuffer, - numberToHex + numberToHex, + numberToU8a }; diff --git a/packages/util/src/number/toU8a.js b/packages/util/src/number/toU8a.js new file mode 100644 index 000000000..27aff0e67 --- /dev/null +++ b/packages/util/src/number/toU8a.js @@ -0,0 +1,29 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +const hexToU8a = require('../hex/toU8a'); +const numberToHex = require('./toHex'); + +/** + @name numberToU8a + @signature numberToBuffer (value?: number): Uint8Array + @summary Creates a Uint8Array object from a number. + @description + `null`/`undefined`/`NaN` inputs returns an empty `Uint8Array` result. `number` input values return the actual bytes value converted to a `Uint8Array`. + @example + import { numberToU8a } from '@polkadot/util'; + + numberToU8a(0x1234); // => [0x12, 0x34] +*/ +module.exports = function numberToU8a (value?: number): Uint8Array { + // flowlint-next-line sketchy-null-number:off + if (!value || isNaN(value)) { + return new Uint8Array([]); + } + + return hexToU8a( + numberToHex(value) + ); +}; diff --git a/packages/util/src/number/toU8a.spec.js b/packages/util/src/number/toU8a.spec.js new file mode 100644 index 000000000..6c1638e57 --- /dev/null +++ b/packages/util/src/number/toU8a.spec.js @@ -0,0 +1,37 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. + +const { numberToU8a } = require('./index'); + +describe('numberToU8a', () => { + it('converts 0 to empty', () => { + expect( + numberToU8a(0) + ).toEqual(new Uint8Array([])); + }); + + it('converts undefined to empty', () => { + expect( + numberToU8a() + ).toEqual(new Uint8Array([])); + }); + + it('converts null to empty', () => { + expect( + numberToU8a(null) + ).toEqual(new Uint8Array([])); + }); + + it('converts NaN to empty', () => { + expect( + numberToU8a(NaN) + ).toEqual(new Uint8Array([])); + }); + + it('converts values to the buffer', () => { + expect( + numberToU8a(0x3456) + ).toEqual(new Uint8Array([0x34, 0x56])); + }); +}); diff --git a/packages/util/src/u8a/concat.js b/packages/util/src/u8a/concat.js new file mode 100644 index 000000000..5f9400c7c --- /dev/null +++ b/packages/util/src/u8a/concat.js @@ -0,0 +1,30 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +/** + @name u8aConcat + @signature u8aConcat (values: Array): Uint8Array + @summary Creates a concatenated Uint8Array from the inputs. + @description + Concatenates the input arrays into a single `UInt8Array`. + @example + import { u8aConcat } from '@polkadot/util'; + + u8aConcat([ + new Uint8Array([1, 2, 3]), + new Uint8Array([4, 5, 6]) + ]); // [1, 2, 3, 4, 5, 6] +*/ +module.exports = function u8aConcat (list: Array): Uint8Array { + const length = list.reduce((total, item) => total + item.length, 0); + let offset = 0; + + return list.reduce((result, item) => { + result.set(item, offset); + offset += item.length; + + return result; + }, new Uint8Array(length)); +}; diff --git a/packages/util/src/u8a/concat.spec.js b/packages/util/src/u8a/concat.spec.js new file mode 100644 index 000000000..569351979 --- /dev/null +++ b/packages/util/src/u8a/concat.spec.js @@ -0,0 +1,19 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. + +const { u8aConcat } = require('./index'); + +describe('u8aConcat', () => { + it('concatenates arrays', () => { + expect( + u8aConcat([ + new Uint8Array([1, 2, 3, 4]), + new Uint8Array([5, 6]), + new Uint8Array([7, 8, 9]) + ]) + ).toEqual( + new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9]) + ); + }); +}); diff --git a/packages/util/src/u8a/fromBn.js b/packages/util/src/u8a/fromBn.js new file mode 100644 index 000000000..cf28091fa --- /dev/null +++ b/packages/util/src/u8a/fromBn.js @@ -0,0 +1,14 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +const u8aFromBn = require('../bn/toU8a'); + +/** + @name u8aFromBn + @signature u8aFromBn (value?: BN): Uint8Array + @summary Creates a Uint8Array value from a BN object. + @alias bn/toU8a +*/ +module.exports = u8aFromBn; diff --git a/packages/util/src/u8a/fromBn.spec.js b/packages/util/src/u8a/fromBn.spec.js new file mode 100644 index 000000000..30e6a9e7b --- /dev/null +++ b/packages/util/src/u8a/fromBn.spec.js @@ -0,0 +1,15 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. + +const isFunction = require('../is/function'); + +const { u8aFromBn } = require('./index'); + +describe('u8aFromBn', () => { + it('exists as a function', () => { + expect( + isFunction(u8aFromBn) + ).toEqual(true); + }); +}); diff --git a/packages/util/src/u8a/index.js b/packages/util/src/u8a/index.js index 3e9ec7030..3f1337ef4 100644 --- a/packages/util/src/u8a/index.js +++ b/packages/util/src/u8a/index.js @@ -3,6 +3,8 @@ // of the ISC license. See the LICENSE file for details. // @flow +const u8aConcat = require('./concat'); +const u8aFromBn = require('./fromBn'); const u8aFromBuffer = require('./fromBuffer'); const u8aFromHex = require('./fromHex'); const u8aFromUtf8 = require('./fromUtf8'); @@ -15,6 +17,8 @@ const u8aToUtf8 = require('./toUtf8'); @summary Utility methods to convert to and from `Uint8Array` objects */ module.exports = { + u8aConcat, + u8aFromBn, u8aFromBuffer, u8aFromHex, u8aFromString, diff --git a/yarn.lock b/yarn.lock index eb45eac43..d418ca19d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -69,9 +69,9 @@ dependencies: babel-runtime "^6.26.0" -"@polkadot/dev@^0.15.2": - version "0.15.2" - resolved "https://registry.yarnpkg.com/@polkadot/dev/-/dev-0.15.2.tgz#496350e1ca3dfa30d73bd64206c221fa6e96b3ec" +"@polkadot/dev@^0.15.6": + version "0.15.6" + resolved "https://registry.yarnpkg.com/@polkadot/dev/-/dev-0.15.6.tgz#9ca3ec886bc60206851cb2e780723629e53d19f7" dependencies: babel-cli "^6.26.0" babel-core "^6.26.0" @@ -91,11 +91,11 @@ eslint-plugin-flowtype "^2.39.1" eslint-plugin-import "^2.8.0" eslint-plugin-jest "^21.3.2" - eslint-plugin-node "^5.2.1" + eslint-plugin-node "^6.0.0" eslint-plugin-promise "^3.6.0" eslint-plugin-react "^7.4.0" eslint-plugin-standard "^3.0.1" - flow-bin "^0.64.0" + flow-bin "^0.65.0" flow-copy-source "^1.2.1" jest "^22.0.0" makeshift "^1.1.0" @@ -944,12 +944,6 @@ bindings@~1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.2.1.tgz#14ad6113812d2d37d72e67b4cacb4bb726505f11" -bl@^1.0.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.1.tgz#cac328f7bee45730d404b692203fcb590e172d5e" - dependencies: - readable-stream "^2.0.5" - blakejs@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/blakejs/-/blakejs-1.1.0.tgz#69df92ef953aa88ca51a32df6ab1c54a155fc7a5" @@ -1141,10 +1135,6 @@ chokidar@^1.6.1, chokidar@^1.7.0: optionalDependencies: fsevents "^1.0.0" -chownr@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181" - ci-info@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.1.2.tgz#03561259db48d0474c8bdc90f5b47b068b6bbfb4" @@ -1714,12 +1704,6 @@ encoding@^0.1.11: dependencies: iconv-lite "~0.4.13" -end-of-stream@^1.0.0, end-of-stream@^1.1.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.0.tgz#7a90d833efda6cfa6eac0f4949dbb0fad3a63206" - dependencies: - once "^1.4.0" - entities@^1.1.1, entities@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" @@ -1820,14 +1804,14 @@ eslint-plugin-jest@^21.3.2: version "21.3.2" resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-21.3.2.tgz#b1cefc05f0fed700eb40185a94d16f6d575d1ef9" -eslint-plugin-node@^5.2.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-5.2.1.tgz#80df3253c4d7901045ec87fa660a284e32bdca29" +eslint-plugin-node@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-6.0.0.tgz#5ad5ee6b5346aec6cc9cde0b8619caed2c6d8f25" dependencies: ignore "^3.3.6" minimatch "^3.0.4" resolve "^1.3.3" - semver "5.3.0" + semver "^5.4.1" eslint-plugin-promise@^3.6.0: version "3.6.0" @@ -1935,6 +1919,12 @@ esutils@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" +ethereumjs-testing@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/ethereumjs-testing/-/ethereumjs-testing-1.0.4.tgz#8739f4104e9838ba92f3060eeb165c581041251d" + dependencies: + node-dir "^0.1.16" + exec-sh@^0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.2.1.tgz#163b98a6e89e6b65b47c2a28d215bc1f63989c38" @@ -1983,10 +1973,6 @@ expand-range@^1.8.1: dependencies: fill-range "^2.1.0" -expand-template@^1.0.2: - version "1.1.0" - resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-1.1.0.tgz#e09efba977bf98f9ee0ed25abd0c692e02aec3fc" - expect@^22.0.3: version "22.0.3" resolved "https://registry.yarnpkg.com/expect/-/expect-22.0.3.tgz#bb486de7d41bf3eb60d3b16dfd1c158a4d91ddfa" @@ -2106,9 +2092,9 @@ flat-cache@^1.2.1: graceful-fs "^4.1.2" write "^0.2.1" -flow-bin@^0.64.0: - version "0.64.0" - resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.64.0.tgz#ddd3fb3b183ab1ab35a5d5dec9caf5ebbcded167" +flow-bin@^0.65.0: + version "0.65.0" + resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.65.0.tgz#64ffeca27211c786e2d68508c65686ba1b8a2169" flow-copy-source@^1.2.1: version "1.2.1" @@ -2289,10 +2275,6 @@ gitconfiglocal@^1.0.0: dependencies: ini "^1.3.2" -github-from-package@0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/github-from-package/-/github-from-package-0.0.0.tgz#97fb5d96bfde8973313f20e8288ef9a167fa64ce" - glob-base@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" @@ -3288,14 +3270,13 @@ jsx-ast-utils@^2.0.0: dependencies: array-includes "^3.0.3" -keccak@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/keccak/-/keccak-1.3.0.tgz#3681bd99ad3d0354ddb29b9040c1b6560cce08ac" +keccak@jacogr/keccak#f25ae4b299038bb2f0b72f150b99b5048ffb9e48: + version "1.4.0" + resolved "https://codeload.github.com/jacogr/keccak/tar.gz/f25ae4b299038bb2f0b72f150b99b5048ffb9e48" dependencies: bindings "^1.2.1" inherits "^2.0.3" nan "^2.2.1" - prebuild-install "^2.0.0" safe-buffer "^5.1.0" kefir@^3.7.3: @@ -3687,11 +3668,11 @@ natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" -node-abi@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.1.2.tgz#4da6caceb6685fcd31e7dd1994ef6bb7d0a9c0b2" +node-dir@^0.1.16: + version "0.1.17" + resolved "https://registry.yarnpkg.com/node-dir/-/node-dir-0.1.17.tgz#5f5665d93351335caabef8f1c554516cf5f1e4e5" dependencies: - semver "^5.4.1" + minimatch "^3.0.2" node-fetch@^1.0.1: version "1.7.3" @@ -3729,10 +3710,6 @@ node-pre-gyp@^0.6.39: tar "^2.2.1" tar-pack "^3.4.0" -noop-logger@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/noop-logger/-/noop-logger-0.1.1.tgz#94a2b1633c4f1317553007d8966fd0e841b6a4c2" - nopt@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" @@ -3769,7 +3746,7 @@ npm-run-path@^2.0.0: dependencies: path-key "^2.0.0" -npmlog@^4.0.1, npmlog@^4.0.2, npmlog@^4.1.2: +npmlog@^4.0.2, npmlog@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" dependencies: @@ -3816,7 +3793,7 @@ object.omit@^2.0.0: for-own "^0.1.4" is-extendable "^0.1.1" -once@^1.3.0, once@^1.3.1, once@^1.3.3, once@^1.4.0: +once@^1.3.0, once@^1.3.3, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" dependencies: @@ -3846,7 +3823,7 @@ optionator@^0.8.1, optionator@^0.8.2: type-check "~0.3.2" wordwrap "~1.0.0" -os-homedir@^1.0.0, os-homedir@^1.0.1: +os-homedir@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" @@ -4126,25 +4103,6 @@ postcss@^6.0.16: source-map "^0.6.1" supports-color "^5.1.0" -prebuild-install@^2.0.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-2.3.0.tgz#19481247df728b854ab57b187ce234211311b485" - dependencies: - expand-template "^1.0.2" - github-from-package "0.0.0" - minimist "^1.2.0" - mkdirp "^0.5.1" - node-abi "^2.1.1" - noop-logger "^0.1.1" - npmlog "^4.0.1" - os-homedir "^1.0.1" - pump "^1.0.1" - rc "^1.1.6" - simple-get "^1.4.2" - tar-fs "^1.13.0" - tunnel-agent "^0.6.0" - xtend "4.0.1" - prelude-ls@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" @@ -4194,13 +4152,6 @@ pseudomap@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" -pump@^1.0.0, pump@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/pump/-/pump-1.0.3.tgz#5dfe8311c33bbf6fc18261f9f34702c47c08a954" - dependencies: - end-of-stream "^1.1.0" - once "^1.3.1" - punycode@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" @@ -4290,7 +4241,7 @@ read-pkg@^3.0.0: normalize-package-data "^2.3.2" path-type "^3.0.0" -readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.1.5, readable-stream@^2.2.2: +readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.1.5, readable-stream@^2.2.2: version "2.3.3" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c" dependencies: @@ -4574,10 +4525,6 @@ rimraf@2, rimraf@^2.2.8, rimraf@^2.5.1, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2. dependencies: glob "^7.0.5" -rlp@jacogr/rlp: - version "2.0.0" - resolved "https://codeload.github.com/jacogr/rlp/tar.gz/ca33b296fc43d7a3543d8a8f172adc9b66826f5f" - run-async@^2.2.0: version "2.3.0" resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" @@ -4620,10 +4567,6 @@ sax@^1.2.1: version "5.4.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" -semver@5.3.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" - semver@^5.0.1, semver@^5.1.0: version "5.5.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" @@ -4658,14 +4601,6 @@ signal-exit@^3.0.0, signal-exit@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" -simple-get@^1.4.2: - version "1.4.3" - resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-1.4.3.tgz#e9755eda407e96da40c5e5158c9ea37b33becbeb" - dependencies: - once "^1.3.1" - unzip-response "^1.0.0" - xtend "^4.0.0" - slash@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" @@ -4979,15 +4914,6 @@ table@^4.0.1: slice-ansi "1.0.0" string-width "^2.1.1" -tar-fs@^1.13.0: - version "1.16.0" - resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-1.16.0.tgz#e877a25acbcc51d8c790da1c57c9cf439817b896" - dependencies: - chownr "^1.0.1" - mkdirp "^0.5.1" - pump "^1.0.0" - tar-stream "^1.1.2" - tar-pack@^3.4.0: version "3.4.1" resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.4.1.tgz#e1dbc03a9b9d3ba07e896ad027317eb679a10a1f" @@ -5001,15 +4927,6 @@ tar-pack@^3.4.0: tar "^2.2.1" uid-number "^0.0.6" -tar-stream@^1.1.2: - version "1.5.5" - resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.5.5.tgz#5cad84779f45c83b1f2508d96b09d88c7218af55" - dependencies: - bl "^1.0.0" - end-of-stream "^1.0.0" - readable-stream "^2.0.0" - xtend "^4.0.0" - tar@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" @@ -5243,10 +5160,6 @@ universalify@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.1.tgz#fa71badd4437af4c148841e3b3b165f9e9e590b7" -unzip-response@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-1.0.2.tgz#b984f0877fc0a89c2c773cc1ef7b5b232b5b06fe" - unzip-response@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-2.0.1.tgz#d2f0f737d16b0615e72a6935ed04214572d56f97" @@ -5463,7 +5376,7 @@ xml-name-validator@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-2.0.1.tgz#4d8b8f1eccd3419aa362061becef515e1e559635" -xtend@4.0.1, xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1: +xtend@^4.0.1, xtend@~4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"