Combine util, types & trie into common (#150)

* Pull in trie repo

* Bring in types repo
This commit is contained in:
Jaco Greeff
2018-06-26 21:26:51 +02:00
committed by GitHub
parent d0e7ab6e32
commit 78e01a0e16
269 changed files with 9406 additions and 117 deletions

View File

@@ -13,13 +13,32 @@
Various useful utility functions that are used across all projects in the [@polkadot](https://polkadot.js.org) namespace. It provides utility functions with additional safety checks, allowing not only for consistent coding, but also reducing the general boilerplate.
It is split up into a number of internal packages -
It is split up into a number of internal packages, namely utilities -
- [util](packages/util/) General utilities
- [util-crypto](packages/util-crypto/) Crypto and hashing utilities
- [util-keyring](packages/util-keyring/) Keyring management
- [util-rlp](packages/util-rlp/) RLP encoding & decoding
- [util-triehash](packages/util-triehash/) Calculation of trie hashes
Various useful trie interfaces and utilities -
- [trie-db](packages/trie-db/) Merkle Patricia Tree implementation adapcted for Polkadot
- [trie-hash](packages/trie-hash/) Calculate hashes (either ordered or unordered) from a set of inputs
Type definitions for interfaces as exposed by Polkadot & Substrate clients -
- [@polkadot/extrinsics](packages/type-extrinsics/) Base extrinsic definitions
- [@polkadot/jsonrpc](packages/type-jsonrpc/) Definitions for JSONRPC endpoints
- [@polkadot/params](packages/type-params/) Input/output parameter formatting
- [@polkadot/primitives](packages/type-primitives/) Primitive type definitions
- [@polkadot/storage](packages/type-storage/) Definitions for storage entries
Codecs for types (possibly to be combined with types) -
- [@polkadot/extrinsics-codec](packages/code-extrinsics/) Encoders for extrinsics
- [@polkadot/primitives-codec](packages/code-primitives/) Primitive encoding/decoding
- [@polkadot/primitives-builder](packages/code-primitives-builder/) Primitive creator
- [@polkadot/primitives-json](packages/code-primitives-json/) Primitive json encoding/decoding
## Contributing

View File

@@ -2,7 +2,18 @@ const config = require('@polkadot/dev/config/jest');
module.exports = Object.assign({}, config, {
moduleNameMapper: {
'@polkadot/util-(crypto|keyring|rlp|triehash)(.*)$': '<rootDir>/packages/util-$1/src/$2',
'@polkadot/extrinsics-codec(.*)$': '<rootDir>/packages/code-extrinsics/src/$1',
'@polkadot/primitives-codec(.*)$': '<rootDir>/packages/code-primitives/src/$1',
'@polkadot/primitives-(builder|json)(.*)$': '<rootDir>/packages/code-primitives-$1/src/$2',
'@polkadot/extrinsics(.*)$': '<rootDir>/packages/type-extrinsics/src/$1',
'@polkadot/jsonrpc(.*)$': '<rootDir>/packages/type-jsonrpc/src/$1',
'@polkadot/params(.*)$': '<rootDir>/packages/type-params/src/$1',
'@polkadot/primitives(.*)$': '<rootDir>/packages/type-primitives/src/$1',
'@polkadot/storage(.*)$': '<rootDir>/packages/type-storage/src/$1',
'@polkadot/trie-(db|hash)(.*)$': '<rootDir>/packages/trie-$1/src/$2',
'@polkadot/util-(crypto|keyring|rlp)(.*)$': '<rootDir>/packages/util-$1/src/$2',
'@polkadot/util(.*)$': '<rootDir>/packages/util/src/$1'
}
});

View File

@@ -10,5 +10,5 @@
"packages": [
"packages/*"
],
"version": "0.24.9"
"version": "0.25.0"
}

View File

@@ -0,0 +1,15 @@
ISC License (ISC)
Copyright 2017-2018 @polkadot/extrinsics-codec authors & contributors
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.

View File

@@ -0,0 +1 @@
# @polkadot/extrinsics-codec

View File

@@ -0,0 +1,25 @@
{
"name": "@polkadot/extrinsics-codec",
"version": "0.25.0",
"main": "index.js",
"repository": "https://github.com/polkadot-js/apps.git",
"author": "Jaco Greeff <jacogr@gmail.com>",
"maintainers": [
"Jaco Greeff <jacogr@gmail.com>"
],
"contributors": [],
"license": "ISC",
"scripts": {
"build": "polkadot-dev-build-babel",
"check": "stylelint 'src/**/*.css' && eslint src && flow check",
"test": "jest --coverage"
},
"dependencies": {
"@babel/runtime": "^7.0.0-beta.51",
"@polkadot/extrinsics": "^0.25.0",
"@polkadot/params": "^0.25.0",
"@polkadot/util": "^0.25.0",
"@polkadot/util-keyring": "^0.25.0",
"bn.js": "^4.11.8"
}
}

View File

@@ -0,0 +1,13 @@
// Copyright 2017-2018 @polkadot/extrinsics-codec authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import { UncheckedRaw } from '@polkadot/primitives/extrinsic';
import u8aToBn from '@polkadot/util/u8a/toBn';
export default function decodeLength (unchecked: Uint8Array): UncheckedRaw {
const length = u8aToBn(unchecked.subarray(0, 4), true).toNumber();
return unchecked.slice(4, length + 4);
}

View File

@@ -0,0 +1,52 @@
// Copyright 2017-2018 @polkadot/extrinsics-codec authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
// @flow
import testingPairs from '@polkadot/util-keyring/testingPairs';
import call from './call';
const keyring = testingPairs();
describe('call', () => {
it('encodes the call correctly (poc-1)', () => {
expect(
call(
keyring.one.publicKey(),
1234,
new Uint8Array([0xab, 0xcd]),
'poc-1'
)
).toEqual(
new Uint8Array([
// key
47, 140, 97, 41, 216, 22, 207, 81, 195, 116, 188, 127, 8, 195, 230, 62, 209, 86, 207, 120, 174, 251, 74, 101, 80, 217, 123, 135, 153, 121, 119, 238,
// nonce (u64)
210, 4, 0, 0, 0, 0, 0, 0,
// data
171, 205
])
);
});
it('encodes the call correctly (latest)', () => {
expect(
call(
keyring.one.publicKey(),
1234,
new Uint8Array([0xab, 0xcd]),
'latest'
)
).toEqual(
new Uint8Array([
// key
47, 140, 97, 41, 216, 22, 207, 81, 195, 116, 188, 127, 8, 195, 230, 62, 209, 86, 207, 120, 174, 251, 74, 101, 80, 217, 123, 135, 153, 121, 119, 238,
// nonce (u32)
210, 4, 0, 0,
// data
171, 205
])
);
});
});

View File

@@ -0,0 +1,19 @@
// Copyright 2017-2018 @polkadot/extrinsics-codec authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import BN from 'bn.js';
import { EncodingVersions } from '@polkadot/params/types';
import { ExtrinsicWithAccount, ExtrinsicWithIndex } from '../types';
import sizes from '@polkadot/params/sizes';
import bnToU8a from '@polkadot/util/bn/toU8a';
import u8aConcat from '@polkadot/util/u8a/concat';
export default function encodeCall (publicKey: Uint8Array, nonce: number | BN, data: ExtrinsicWithIndex, version: EncodingVersions): ExtrinsicWithAccount {
return u8aConcat(
publicKey,
bnToU8a(nonce, sizes.Index.get(version), true),
data
);
}

View File

@@ -0,0 +1,27 @@
// Copyright 2017-2018 @polkadot/extrinsics-codec authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
// @flow
import extrinsics from '@polkadot/extrinsics';
import extrinsic from './extrinsic';
describe('extrinsic', () => {
it('encodes extrinsic correctly', () => {
expect(
extrinsic(
extrinsics.timestamp.public.set,
[10101],
'latest'
)
).toEqual(
new Uint8Array([
// index
3, 0,
// values
117, 39, 0, 0, 0, 0, 0, 0
])
);
});
});

View File

@@ -0,0 +1,17 @@
// Copyright 2017-2018 @polkadot/extrinsics-codec authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import { Extrinsics } from '@polkadot/extrinsics/types';
import { EncodingVersions, SectionItem } from '@polkadot/params/types';
import { ExtrinsicWithIndex } from '../types';
import encodeParams from '@polkadot/params/encode';
import u8aConcat from '@polkadot/util/u8a/concat';
export default function encodeExtrinsic (extrinsic: SectionItem<Extrinsics>, values: Array<any>, version: EncodingVersions): ExtrinsicWithIndex {
return u8aConcat(
extrinsic.index,
encodeParams(extrinsic.params, values, version)
);
}

View File

@@ -0,0 +1,34 @@
// Copyright 2017-2018 @polkadot/extrinsics-codec authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
// @flow
import extrinsics from '@polkadot/extrinsics';
import testingPairs from '@polkadot/util-keyring/testingPairs';
import encode from './index';
const keyring = testingPairs();
describe('encode', () => {
it('encodes extrinsic correctly', () => {
expect(
encode(keyring.nobody.publicKey(), 1234)(
extrinsics.timestamp.public.set,
[10101],
'latest'
)
).toEqual(
new Uint8Array([
// publicKey
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// account nonce
210, 4, 0, 0,
// extrinsic index
3, 0,
// values
117, 39, 0, 0, 0, 0, 0, 0
])
);
});
});

View File

@@ -0,0 +1,23 @@
// Copyright 2017-2018 @polkadot/extrinsics-codec authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import BN from 'bn.js';
import { Extrinsics } from '@polkadot/extrinsics/types';
import { EncodingVersions, SectionItem } from '@polkadot/params/types';
import { ExtrinsicWithAccount } from '../types';
import encodeCall from './call';
import encodeExtrinsic from './extrinsic';
type Encoder = (extrinsic: SectionItem<Extrinsics>, values: Array<any>, version: EncodingVersions) => ExtrinsicWithAccount;
export default function encode (publicKey: Uint8Array, index: number | BN): Encoder {
return (extrinsic: SectionItem<Extrinsics>, values: Array<any>, version: EncodingVersions): ExtrinsicWithAccount =>
encodeCall(
publicKey,
index,
encodeExtrinsic(extrinsic, values, version),
version
);
}

View File

@@ -0,0 +1,15 @@
// Copyright 2017-2018 @polkadot/extrinsics-codec authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import { UncheckedRaw } from '@polkadot/primitives/extrinsic';
import bnToU8a from '@polkadot/util/bn/toU8a';
import u8aConcat from '@polkadot/util/u8a/concat';
export default function encodeLength (unchecked: UncheckedRaw): Uint8Array {
return u8aConcat(
bnToU8a(unchecked.length, 32, true),
unchecked
);
}

View File

@@ -0,0 +1,25 @@
// Copyright 2017-2018 @polkadot/extrinsics-codec authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
// https://github.com/paritytech/polkadot/pull/195
// 0xff, 32-byte account id
// 0xfe, 8-byte account index
// 0xfd, 4-byte account index
// 0xfc, 2-byte account index
// [0xf0...0xfb] (invalid, reserved for future use)
// [0x00...0xef] 1-byte account index (less than 0xf0)
const bytes8 = new Uint8Array([0xfe]);
const bytes4 = new Uint8Array([0xfd]);
const bytes2 = new Uint8Array([0xfc]);
const none = new Uint8Array([]);
const publicKey = new Uint8Array([0xff]);
export default {
bytes8,
bytes4,
bytes2,
none,
publicKey
};

View File

@@ -0,0 +1,115 @@
// Copyright 2017-2018 @polkadot/extrinsics-codec authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
// @flow
import extrinsics from '@polkadot/extrinsics';
import hexToU8a from '@polkadot/util/hex/toU8a';
import testingPairs from '@polkadot/util-keyring/testingPairs';
import encode from './unchecked';
const keyring = testingPairs();
describe('unchecked', () => {
it('encodes extrinsic correctly (nobody)', () => {
expect(
encode(keyring.nobody, 1234)(
extrinsics.timestamp.public.set,
[10101]
)
).toEqual(
new Uint8Array([
255,
// publicKey
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// account nonce
210, 4, 0, 0,
// extrinsic index
3, 0,
// values
117, 39, 0, 0, 0, 0, 0, 0,
// signature
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
])
);
});
it('encodes extrinsic correctly (one)', () => {
expect(
encode(keyring.one, 258, 'poc-1')(
extrinsics.staking.public.transfer,
[keyring.two.publicKey(), 69]
)
).toEqual(
new Uint8Array([
// publicKey
47, 140, 97, 41, 216, 22, 207, 81, 195, 116, 188, 127, 8, 195, 230, 62, 209, 86, 207, 120, 174, 251, 74, 101, 80, 217, 123, 135, 153, 121, 119, 238,
// account nonce
2, 1, 0, 0, 0, 0, 0, 0,
// extrinsic index
2, 0,
// values
// (recipient)
215, 90, 152, 1, 130, 177, 10, 183, 213, 75, 254, 211, 201, 100, 7, 58, 14, 225, 114, 243, 218, 166, 35, 37, 175, 2, 26, 104, 247, 7, 81, 26,
// (amount)
69, 0, 0, 0, 0, 0, 0, 0,
// signature
144, 233, 93, 195, 106, 86, 2, 230, 182, 5, 62, 128, 120, 148, 21, 128, 86, 5, 74, 15, 128, 100, 255, 179, 172, 13, 102, 206, 117, 208, 175, 107, 107, 77, 209, 126, 129, 51, 1, 198, 184, 202, 100, 240, 0, 118, 150, 188, 67, 10, 154, 84, 224, 103, 17, 151, 163, 45, 78, 249, 219, 169, 96, 2
])
);
});
it('encodes extrinsic correctly (one + latest)', () => {
expect(
encode(keyring.one, 258)(
extrinsics.staking.public.transfer,
[keyring.two.publicKey(), 69]
)
).toEqual(
new Uint8Array([
255,
// publicKey
47, 140, 97, 41, 216, 22, 207, 81, 195, 116, 188, 127, 8, 195, 230, 62, 209, 86, 207, 120, 174, 251, 74, 101, 80, 217, 123, 135, 153, 121, 119, 238,
// account nonce
2, 1, 0, 0,
// extrinsic index
2, 0,
// values
// (recipient)
255,
215, 90, 152, 1, 130, 177, 10, 183, 213, 75, 254, 211, 201, 100, 7, 58, 14, 225, 114, 243, 218, 166, 35, 37, 175, 2, 26, 104, 247, 7, 81, 26,
// (amount)
69, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// signature
56, 1, 89, 195, 60, 171, 128, 242, 136, 64, 45, 43, 252, 199, 13, 115, 2, 76, 9, 19, 16, 80, 38, 164, 58, 229, 107, 225, 141, 107, 115, 176, 241, 242, 153, 177, 48, 92, 6, 61, 104, 112, 45, 223, 86, 198, 203, 78, 240, 223, 59, 190, 156, 116, 135, 188, 244, 219, 182, 58, 39, 140, 159, 11
])
);
});
it('encodes timetamp.set extrinsic correctly (actual values)', () => {
expect(
encode(keyring.nobody, 0)(
extrinsics.timestamp.public.set,
[0x5b13c37b]
)
).toEqual(
hexToU8a(
'0xff00000000000000000000000000000000000000000000000000000000000000000000000003007bc3135b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
)
);
});
it('encoded parachains.setHeads correctly (actual values)', () => {
expect(
encode(keyring.nobody, 0)(
extrinsics.parachains.public.setHeads,
[[]]
)
).toEqual(
hexToU8a(
'0xff00000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
)
);
});
});

View File

@@ -0,0 +1,33 @@
// Copyright 2017-2018 @polkadot/extrinsics-codec authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import BN from 'bn.js';
import { Extrinsics } from '@polkadot/extrinsics/types';
import { EncodingVersions, SectionItem } from '@polkadot/params/types';
import { UncheckedRaw } from '@polkadot/primitives/extrinsic';
import { KeyringPair } from '@polkadot/util-keyring/types';
import u8aConcat from '@polkadot/util/u8a/concat';
import encode from './index';
import prefixes from './prefixes';
type Encoder = (extrinsic: SectionItem<Extrinsics>, values: Array<any>) => UncheckedRaw;
export default function unchecked (pair: KeyringPair, index: number | BN, version: EncodingVersions = 'latest'): Encoder {
const encoder = encode(pair.publicKey(), index);
return (extrinsic: SectionItem<Extrinsics>, values: Array<any>): UncheckedRaw => {
const message = encoder(extrinsic, values, version);
const signature = pair.sign(message);
return u8aConcat(
version === 'poc-1'
? prefixes.none
: prefixes.publicKey,
message,
signature
);
};
}

View File

@@ -0,0 +1,9 @@
// Copyright 2017-2018 @polkadot/extrinsics-codec authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
export type ExtrinsicWithAccount = Uint8Array;
export type ExtrinsicWithIndex = Uint8Array;
export type ExtrinsicUnchecked = Uint8Array;

View File

@@ -0,0 +1,15 @@
ISC License (ISC)
Copyright 2017-2018 @polkadot/primitives-builder authors & contributors
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.

View File

@@ -0,0 +1,13 @@
[![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/primitives-builder.svg?style=flat-square)](https://www.npmjs.com/package/@polkadot/primitives-builder)
[![travis](https://img.shields.io/travis/polkadot-js/types.svg?style=flat-square)](https://travis-ci.org/polkadot-js/types)
[![maintainability](https://img.shields.io/codeclimate/maintainability/polkadot-js/types.svg?style=flat-square)](https://codeclimate.com/github/polkadot-js/types/maintainability)
[![coverage](https://img.shields.io/coveralls/polkadot-js/types.svg?style=flat-square)](https://coveralls.io/github/polkadot-js/types?branch=master)
[![dependency](https://david-dm.org/polkadot-js/types.svg?style=flat-square&path=packages/primitives-builder)](https://david-dm.org/polkadot-js/types?path=packages/primitives-builder)
[![devDependency](https://david-dm.org/polkadot-js/types/dev-status.svg?style=flat-square&path=packages/primitives-builder)](https://david-dm.org/polkadot-js/types?path=packages/primitives-builder#info=devDependencies)
# @polkadot/primitives-builder
Creating of primitive types.

View File

@@ -0,0 +1,47 @@
{
"name": "@polkadot/primitives-builder",
"version": "0.25.0",
"description": "Builder for primitives for Polkadot",
"main": "index.js",
"engines": {
"node": ">=6.4"
},
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org"
},
"repository": {
"type": "git",
"url": "git+https://github.com/polkadot-js/types.git"
},
"keywords": [
"Polkadot"
],
"author": "Jaco Greeff <jacogr@gmail.com>",
"maintainers": [
"Jaco Greeff <jacogr@gmail.com>"
],
"contributors": [],
"license": "ISC",
"bugs": {
"url": "https://github.com/polkadot-js/types/issues"
},
"homepage": "https://github.com/polkadot-js/types/tree/master/packages/primitives-builder#readme",
"scripts": {
"build": "polkadot-dev-build-babel",
"check": "eslint src && flow check",
"test": "echo \"Tests only available from root wrapper\""
},
"dependencies": {
"@babel/runtime": "^7.0.0-beta.51",
"@polkadot/extrinsics-codec": "^0.25.0",
"@polkadot/primitives": "^0.25.0",
"@polkadot/primitives-codec": "^0.25.0",
"@polkadot/trie-hash": "^0.25.0",
"@polkadot/util": "^0.25.0",
"@polkadot/util-crypto": "^0.25.0"
},
"devDependencies": {
"@polkadot/util-keyring": "^0.25.0"
}
}

View File

@@ -0,0 +1,82 @@
// Copyright 2017-2018 @polkadot/primitives-builder authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import BN from 'bn.js';
import extrinsics from '@polkadot/extrinsics';
import encodeUnchecked from '@polkadot/extrinsics-codec/encode/unchecked';
import hexToU8a from '@polkadot/util/hex/toU8a';
import testingPairs from '@polkadot/util-keyring/testingPairs';
import block from './block';
const keyring = testingPairs();
describe('block', () => {
it('creates a complete block from incomplete details', () => {
expect(
block({})
).toEqual({
header: {
digest: {
logs: []
},
number: new BN(0),
parentHash: new Uint8Array(32),
stateRoot: new Uint8Array(32),
extrinsicsRoot: new Uint8Array([
86, 232, 31, 23, 27, 204, 85, 166, 255, 131, 69, 230, 146, 192, 248, 110, 91, 72, 224, 27, 153, 108, 173, 192, 1, 98, 47, 181, 227, 99, 180, 33
])
},
extrinsics: []
});
});
it('creates a valid block, with defaults submitted', () => {
const transactions = [
encodeUnchecked(keyring.nobody, 0)(
extrinsics.timestamp.public.set,
[0x5b13c3a4]
),
encodeUnchecked(keyring.nobody, 0)(
extrinsics.parachains.public.setHeads,
[[]]
)
];
expect(
block({
header: {
number: 1,
parentHash: hexToU8a(
'0x4545454545454545454545454545454545454545454545454545454545454545'
),
stateRoot: hexToU8a(
'0x2481853da20b9f4322f34650fea5f240dcbfb266d02db94bfa0153c31f4a29db'
)
},
extrinsics: transactions
})
).toEqual({
header: {
digest: {
logs: []
},
number: new BN(1),
parentHash: hexToU8a(
'0x4545454545454545454545454545454545454545454545454545454545454545'
),
stateRoot: hexToU8a(
'0x2481853da20b9f4322f34650fea5f240dcbfb266d02db94bfa0153c31f4a29db'
),
extrinsicsRoot: new Uint8Array([
140, 102, 133, 98, 214, 123, 73, 173, 122, 252, 247, 48, 181, 86, 77, 188, 213, 161, 17, 19, 73, 96, 158, 181, 249, 69, 97, 15, 186, 12, 45, 157
])
// hexToU8a(
// '0xab602f7974bbfb513f021f39777e2195094dc64a2c1b7c82a1781cb9fd4768a8'
// )
},
extrinsics: transactions
});
});
});

View File

@@ -0,0 +1,15 @@
// Copyright 2017-2018 @polkadot/primitives-builder authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import { Block } from '@polkadot/primitives/block';
import { BlockIncomplete } from './types';
import headerBuilder from './header';
export default function block ({ header = {}, extrinsics = [] }: BlockIncomplete): Block {
return {
header: headerBuilder(header, extrinsics),
extrinsics
};
}

View File

@@ -0,0 +1,77 @@
// Copyright 2017-2018 @polkadot/primitives-builder authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import extrinsics from '@polkadot/extrinsics';
import encodeUnchecked from '@polkadot/extrinsics-codec/encode/unchecked';
import hexToU8a from '@polkadot/util/hex/toU8a';
import testingPairs from '@polkadot/util-keyring/testingPairs';
import root from './rootRaw';
const keyring = testingPairs();
describe('root', () => {
it('calculates the root correctly for no transactions', () => {
expect(
root()
).toEqual(
hexToU8a(
'0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421'
)
);
});
it('calculates the root correctly (actual)', () => {
expect(
root([
encodeUnchecked(keyring.nobody, 0)(
extrinsics.timestamp.public.set,
[0x5b13c3a4]
),
encodeUnchecked(keyring.nobody, 0)(
extrinsics.parachains.public.setHeads,
[[]]
)
])
).toEqual(
new Uint8Array([
140, 102, 133, 98, 214, 123, 73, 173, 122, 252, 247, 48, 181, 86, 77, 188, 213, 161, 17, 19, 73, 96, 158, 181, 249, 69, 97, 15, 186, 12, 45, 157
])
// hexToU8a(
// '0xab602f7974bbfb513f021f39777e2195094dc64a2c1b7c82a1781cb9fd4768a8'
// )
);
});
// [
// 168, 135, 224, 93, 140, 222, 226, 83, 13, 116, 138, 197, 164, 6, 48, 190, 101, 18, 221, 166, 40, 179, 158, 112, 133, 154, 215, 198, 177, 76, 212, 228,
// 1, 0, 0, 0, 0, 0, 0, 0,
// 159, 216, 180, 61, 159, 12, 131, 80, 22, 196, 220, 94, 6, 222, 68, 159, 97, 60, 16, 69, 163, 149, 125, 138, 175, 36, 30, 93, 235, 4, 1, 168,
// 245, 208, 141, 24, 250, 136, 158, 84, 67, 170, 59, 146, 17, 149, 62, 67, 254, 66, 126, 53, 20, 146, 252, 243, 137, 89, 224, 145, 252, 79, 109, 15,
// 0, 0, 0, 0,
// 2, 0, 0, 0,
// 110, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 188, 29, 21, 91, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// 106, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
it('calculates the root correctly (actual encoded)', () => {
expect(
root([
new Uint8Array([
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3, 0,
188, 29, 21, 91, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
]),
new Uint8Array([
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
])
])
).toEqual(
new Uint8Array([
245, 208, 141, 24, 250, 136, 158, 84, 67, 170, 59, 146, 17, 149, 62, 67, 254, 66, 126, 53, 20, 146, 252, 243, 137, 89, 224, 145, 252, 79, 109, 15
])
);
});
});

View File

@@ -0,0 +1,14 @@
// Copyright 2017-2018 @polkadot/primitives-builder authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import { UncheckedRaw } from '@polkadot/primitives/extrinsic';
import uncheckedLength from '@polkadot/extrinsics-codec/encode/length';
import trieRootOrdered from '@polkadot/trie-hash/rootOrdered';
export default function extrinsicsRootRaw (extrinsics: Array<UncheckedRaw> = []): Uint8Array {
return trieRootOrdered(
extrinsics.map(uncheckedLength)
);
}

View File

@@ -0,0 +1,41 @@
// Copyright 2017-2018 @polkadot/primitives-builder authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import txRoot from './extrinsic/rootRaw';
import extrinsics from '@polkadot/extrinsics';
import encodeUnchecked from '@polkadot/extrinsics-codec/encode/unchecked';
import testingPairs from '@polkadot/util-keyring/testingPairs';
import header from './header';
const keyring = testingPairs();
describe('header', () => {
it('applies the all transactions (no timestamp)', () => {
expect(
header({}).extrinsicsRoot
).toEqual(
txRoot([])
);
});
it('applies the all transactions (extrinsicsRoot)', () => {
const transactions = [
encodeUnchecked(keyring.nobody, 0)(
extrinsics.timestamp.public.set,
[54321]
),
encodeUnchecked(keyring.one, 0)(
extrinsics.timestamp.public.set,
[12345]
)
];
expect(
header({}, transactions).extrinsicsRoot
).toEqual(
txRoot(transactions)
);
});
});

View File

@@ -0,0 +1,25 @@
// Copyright 2017-2018 @polkadot/primitives-builder authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import { Header } from '@polkadot/primitives/header';
import { UncheckedRaw } from '@polkadot/primitives/extrinsic';
import { HeaderIncomplete } from './types';
import bnToBn from '@polkadot/util/bn/toBn';
import extrinsicsRawRoot from './extrinsic/rootRaw';
export default function header ({ digest: { logs = [] } = {}, extrinsicsRoot, number, parentHash = new Uint8Array(32), stateRoot = new Uint8Array(32) }: HeaderIncomplete, extrinsics?: Array<UncheckedRaw>): Header {
return {
digest: {
logs
},
extrinsicsRoot: extrinsics
? extrinsicsRawRoot(extrinsics)
: (extrinsicsRoot || extrinsicsRawRoot([])),
number: bnToBn(number || 0),
parentHash,
stateRoot
};
}

View File

@@ -0,0 +1,22 @@
// Copyright 2017-2018 @polkadot/primitives-builder authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import { BlockNumber, Hash, HeaderHash } from '@polkadot/primitives/base';
import { Digest$Log } from '@polkadot/primitives/digest';
import { UncheckedRaw } from '@polkadot/primitives/extrinsic';
export type HeaderIncomplete = {
digest?: {
logs?: Array<Digest$Log>
},
extrinsicsRoot?: Hash,
parentHash?: HeaderHash,
number?: BlockNumber | number,
stateRoot?: Hash
};
export type BlockIncomplete = {
header?: HeaderIncomplete,
extrinsics?: Array<UncheckedRaw>
};

View File

@@ -0,0 +1,15 @@
ISC License (ISC)
Copyright 2017-2018 @polkadot/primitives-json authors & contributors
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.

View File

@@ -0,0 +1,33 @@
[![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/primitives-json.svg?style=flat-square)](https://www.npmjs.com/package/@polkadot/primitives-json)
[![travis](https://img.shields.io/travis/polkadot-js/types.svg?style=flat-square)](https://travis-ci.org/polkadot-js/types)
[![maintainability](https://img.shields.io/codeclimate/maintainability/polkadot-js/types.svg?style=flat-square)](https://codeclimate.com/github/polkadot-js/types/maintainability)
[![coverage](https://img.shields.io/coveralls/polkadot-js/types.svg?style=flat-square)](https://coveralls.io/github/polkadot-js/types?branch=master)
[![dependency](https://david-dm.org/polkadot-js/types.svg?style=flat-square&path=packages/primitives-json)](https://david-dm.org/polkadot-js/types?path=packages/primitives-json)
[![devDependency](https://david-dm.org/polkadot-js/types/dev-status.svg?style=flat-square&path=packages/primitives-json)](https://david-dm.org/polkadot-js/types?path=packages/primitives-json#info=devDependencies)
# @polkadot/primitives-json
Conversion of Polkadot types to and from a structure with Json-only primitives, ready for serialisation. As such, it does not stringify itself, rather converts from complex classes to the correct Json reprsentation.
## Usage
Installation -
```
npm install --save @polkadot/primitives-json
```
Usage -
```js
const { parachainIdDecode, parachainIdEncode } from '@polkadot/primitives-json');
parachainIdDecode( // step 3 - BN `0x123456`
parachainIdEncode( // step 1 - string `'0x123456'`
new BN('0x123456') // step 0 - BN `0x123456`
)
);
```

View File

@@ -0,0 +1,41 @@
{
"name": "@polkadot/primitives-json",
"version": "0.25.0",
"description": "Conversion utilities for primitives for JSON representation",
"main": "index.js",
"engines": {
"node": ">=6.4"
},
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org"
},
"repository": {
"type": "git",
"url": "git+https://github.com/polkadot-js/types.git"
},
"keywords": [
"Polkadot"
],
"author": "Jaco Greeff <jacogr@gmail.com>",
"maintainers": [
"Jaco Greeff <jacogr@gmail.com>"
],
"contributors": [],
"license": "ISC",
"bugs": {
"url": "https://github.com/polkadot-js/types/issues"
},
"homepage": "https://github.com/polkadot-js/types/tree/master/packages/primitives-json#readme",
"scripts": {
"build": "polkadot-dev-build-babel",
"check": "eslint src && flow check",
"test": "echo \"Tests only available from root wrapper\""
},
"dependencies": {
"@babel/runtime": "^7.0.0-beta.51",
"@polkadot/primitives": "^0.25.0",
"@polkadot/primitives-builder": "^0.25.0",
"@polkadot/util": "^0.25.0"
}
}

View File

@@ -0,0 +1,12 @@
// Copyright 2017-2018 @polkadot/primitives-json authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import { AccountId } from '@polkadot/primitives/base';
import { JsonAccountId } from '../types';
import hashDecode from '../hash/decode';
export default function accountIdDecode (value: JsonAccountId): AccountId {
return hashDecode(value, 160);
}

View File

@@ -0,0 +1,12 @@
// Copyright 2017-2018 @polkadot/primitives-json authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import { AccountId } from '@polkadot/primitives/base';
import { JsonAccountId } from '../types';
import hashEncode from '../hash/encode';
export default function accountIdEncode (value: AccountId): JsonAccountId {
return hashEncode(value, 160);
}

View File

@@ -0,0 +1,11 @@
// Copyright 2017-2018 @polkadot/primitives-json authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import accountIdDecode from './decode';
import accountIdEncode from './encode';
export {
accountIdDecode,
accountIdEncode
};

View File

@@ -0,0 +1,25 @@
// Copyright 2017-2018 @polkadot/primitives-json authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import { bnDecode } from './index';
describe('bnDecode', () => {
it('converts hex to a BN value', () => {
expect(
bnDecode('0x1234').toNumber()
).toEqual(0x1234);
});
it('converts with the required bitLength', () => {
expect(
bnDecode('0x1234', 8).toNumber()
).toEqual(0x34);
});
it('converts a non-hex/numeric value', () => {
expect(
bnDecode(10).toNumber()
).toEqual(10);
});
});

View File

@@ -0,0 +1,20 @@
// Copyright 2017-2018 @polkadot/primitives-json authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import { JsonBnType } from '../types';
import BN from 'bn.js';
import hexFixLength from '@polkadot/util/hex/fixLength';
import isHex from '@polkadot/util/is/hex';
import hexToBn from '@polkadot/util/hex/toBn';
export default function bnDecode (value: JsonBnType, bitLength: number = -1): BN {
if (isHex(value)) {
return hexToBn(
hexFixLength(value, bitLength)
);
}
return new BN(value);
}

View File

@@ -0,0 +1,21 @@
// Copyright 2017-2018 @polkadot/primitives-json authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import BN from 'bn.js';
import { bnEncode } from './index';
describe('bnEncode', () => {
it('converts to a hex string', () => {
expect(
bnEncode(new BN(0x1234))
).toEqual('0x1234');
});
it('converts to a hex with the provided bitLength', () => {
expect(
bnEncode(new BN(0x1234), 8)
).toEqual('0x34');
});
});

View File

@@ -0,0 +1,16 @@
// Copyright 2017-2018 @polkadot/primitives-json authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import BN from 'bn.js';
import { JsonBnType } from '../types';
import hexFixLength from '@polkadot/util/hex/fixLength';
import bnToHex from '@polkadot/util/bn/toHex';
export default function bnEncode (value: BN | number, bitLength: number = -1): JsonBnType {
return hexFixLength(
bnToHex(value),
bitLength
);
}

View File

@@ -0,0 +1,11 @@
// Copyright 2017-2018 @polkadot/primitives-json authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import bnDecode from './decode';
import bnEncode from './encode';
export {
bnDecode,
bnEncode
};

View File

@@ -0,0 +1,13 @@
// Copyright 2017-2018 @polkadot/primitives-json authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import { bytesDecode } from './index';
describe('bytesDecode', () => {
it('creates the correct bytes U8a', () => {
expect(
bytesDecode('0x0012345600')
).toEqual(new Uint8Array([0x00, 0x12, 0x34, 0x56, 0x00]));
});
});

View File

@@ -0,0 +1,12 @@
// Copyright 2017-2018 @polkadot/primitives-json authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import { Bytes } from '@polkadot/primitives/base';
import { JsonBytes } from '../types';
import hexToU8a from '@polkadot/util/hex/toU8a';
export default function bytesDecode (value: JsonBytes): Bytes {
return hexToU8a(value);
}

View File

@@ -0,0 +1,13 @@
// Copyright 2017-2018 @polkadot/primitives-json authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import { bytesEncode } from './index';
describe('bytesEncode', () => {
it('creates the correct bytes U8a', () => {
expect(
bytesEncode(new Uint8Array([0x00, 0x12, 0x34, 0x56, 0x00]))
).toEqual('0x0012345600');
});
});

View File

@@ -0,0 +1,12 @@
// Copyright 2017-2018 @polkadot/primitives-json authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import { Bytes } from '@polkadot/primitives/base';
import { JsonBytes } from '../types';
import u8aToHex from '@polkadot/util/u8a/toHex';
export default function bytesEncode (value: Bytes): JsonBytes {
return u8aToHex(value);
}

View File

@@ -0,0 +1,11 @@
// Copyright 2017-2018 @polkadot/primitives-json authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import bytesDecode from './decode';
import bytesEncode from './encode';
export {
bytesDecode,
bytesEncode
};

View File

@@ -0,0 +1,19 @@
// Copyright 2017-2018 @polkadot/primitives-json authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import { hashDecode } from './index';
describe('hashDecode', () => {
it('returns the hash when no length specified', () => {
expect(
hashDecode('0x123456787890abcdef')
).toEqual(new Uint8Array([0x12, 0x34, 0x56, 0x78, 0x78, 0x90, 0xab, 0xcd, 0xef]));
});
it('converts to the required length as specified', () => {
expect(
hashDecode('0x123456787890abcdef', 32)
).toEqual(new Uint8Array([0x12, 0x34, 0x56, 0x78]));
});
});

View File

@@ -0,0 +1,12 @@
// Copyright 2017-2018 @polkadot/primitives-json authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import { Hash } from '@polkadot/primitives/base';
import { JsonHash } from '../types';
import hexToU8a from '@polkadot/util/hex/toU8a';
export default function hashDecode (value: JsonHash, bitLength: number = -1): Hash {
return hexToU8a(value, bitLength);
}

View File

@@ -0,0 +1,21 @@
// Copyright 2017-2018 @polkadot/primitives-json authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import { hashEncode } from './index';
describe('hashEncode', () => {
it('returns the hash when no length specified', () => {
expect(
hashEncode(
new Uint8Array([0x12, 0x34, 0x56, 0x78, 0x78, 0x90, 0xab, 0xcd, 0xef])
)
).toEqual('0x123456787890abcdef');
});
it('converts to the required length as specified', () => {
expect(
hashEncode(new Uint8Array([0x34, 0x56, 0x78, 0x78, 0x90, 0xab, 0xcd, 0xef]), 64)
).toEqual('0x3456787890abcdef');
});
});

View File

@@ -0,0 +1,12 @@
// Copyright 2017-2018 @polkadot/primitives-json authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import { Hash } from '@polkadot/primitives/base';
import { JsonHash } from '../types';
import u8aToHex from '@polkadot/util/u8a/toHex';
export default function hashEncode (value: Hash, bitLength: number = -1): JsonHash {
return u8aToHex(value);
}

View File

@@ -0,0 +1,11 @@
// Copyright 2017-2018 @polkadot/primitives-json authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import hashDecode from './decode';
import hashEncode from './encode';
export {
hashDecode,
hashEncode
};

View File

@@ -0,0 +1,38 @@
// Copyright 2017-2018 @polkadot/primitives-json authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import BN from 'bn.js';
import { headerDecode } from './index';
describe('headerDecode', () => {
it('creates the correct structure', () => {
expect(
JSON.stringify(
headerDecode({
digest: {
logs: ['0x5678', '0x789a']
},
extrinsicsRoot: '0xabcd',
number: '0x1234',
parentHash: '0x1234',
stateRoot: '0x5678'
})
)
).toEqual(
JSON.stringify({
digest: {
logs: [
new Uint8Array([0x56, 0x78]),
new Uint8Array([0x78, 0x9a])
]
},
extrinsicsRoot: new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xab, 0xcd]),
number: new BN(0x1234),
parentHash: new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x12, 0x34]),
stateRoot: new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x56, 0x78])
})
);
});
});

View File

@@ -0,0 +1,24 @@
// Copyright 2017-2018 @polkadot/primitives-json authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import { Header } from '@polkadot/primitives/header';
import { JsonHeader } from '../types';
import headerBuilder from '@polkadot/primitives-builder/header';
import hashDecode from '../hash/decode';
import bnDecode from '../bn/decode';
import bytesDecode from '../bytes/decode';
export default function headerDecode ({ digest, extrinsicsRoot, number, parentHash, stateRoot }: JsonHeader): Header {
return headerBuilder({
digest: {
logs: digest.logs.map(bytesDecode)
},
extrinsicsRoot: hashDecode(extrinsicsRoot, 256),
number: bnDecode(number, 64),
parentHash: hashDecode(parentHash, 256),
stateRoot: hashDecode(stateRoot, 256)
});
}

View File

@@ -0,0 +1,38 @@
// Copyright 2017-2018 @polkadot/primitives-json authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import BN from 'bn.js';
import { headerEncode } from './index';
describe('headerEncode', () => {
it('creates the correct structure', () => {
expect(
JSON.stringify(
headerEncode({
digest: {
logs: [
new Uint8Array([0x56, 0x78]),
new Uint8Array([0x78, 0x9a])
]
},
extrinsicsRoot: new Uint8Array([0xab, 0xcd]),
number: new BN(0x1234),
parentHash: new Uint8Array([0x12, 0x34]),
stateRoot: new Uint8Array([0x56, 0x78])
})
)
).toEqual(
JSON.stringify({
digest: {
logs: ['0x5678', '0x789a']
},
extrinsicsRoot: '0xabcd',
number: '0x1234',
parentHash: '0x1234',
stateRoot: '0x5678'
})
);
});
});

View File

@@ -0,0 +1,22 @@
// Copyright 2017-2018 @polkadot/primitives-json authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import { Header } from '@polkadot/primitives/header';
import { JsonHeader } from '../types';
import bnEncode from '../bn/encode';
import bytesEncode from '../bytes/encode';
import hashEncode from '../hash/encode';
export default function headerEncode ({ parentHash, number, stateRoot, extrinsicsRoot, digest }: Header): JsonHeader {
return {
digest: {
logs: digest.logs.map(bytesEncode)
},
extrinsicsRoot: hashEncode(extrinsicsRoot, 256),
number: bnEncode(number, 64),
parentHash: hashEncode(parentHash, 256),
stateRoot: hashEncode(stateRoot, 256)
};
}

View File

@@ -0,0 +1,11 @@
// Copyright 2017-2018 @polkadot/primitives-json authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import headerDecode from './decode';
import headerEncode from './encode';
export {
headerDecode,
headerEncode
};

View File

@@ -0,0 +1,12 @@
// Copyright 2017-2018 @polkadot/primitives-json authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
export * from './accountId';
export * from './header';
export * from './bn';
export * from './bytes';
export * from './hash';
export * from './objectId';
export * from './parachainId';
export * from './signature';

View File

@@ -0,0 +1,12 @@
// Copyright 2017-2018 @polkadot/primitives-json authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import { ObjectId } from '@polkadot/primitives/base';
import { JsonObjectId } from '../types';
import bnDecode from '../bn/decode';
export default function objectIdDecode (value: JsonObjectId): ObjectId {
return bnDecode(value, 64);
}

View File

@@ -0,0 +1,12 @@
// Copyright 2017-2018 @polkadot/primitives-json authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import { ObjectId } from '@polkadot/primitives/base';
import { JsonObjectId } from '../types';
import bnEncode from '../bn/encode';
export default function objectIdEncode (value: ObjectId): JsonObjectId {
return bnEncode(value, 64);
}

View File

@@ -0,0 +1,11 @@
// Copyright 2017-2018 @polkadot/primitives-json authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import objectIdDecode from './decode';
import objectIdEncode from './encode';
export {
objectIdDecode,
objectIdEncode
};

View File

@@ -0,0 +1,12 @@
// Copyright 2017-2018 @polkadot/primitives-json authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import { ParaChainId } from '@polkadot/primitives/base';
import { JsonParaChainId } from '../types';
import bnDecode from '../bn/decode';
export default function parachainIdDecode (value: JsonParaChainId): ParaChainId {
return bnDecode(value, 64);
}

View File

@@ -0,0 +1,12 @@
// Copyright 2017-2018 @polkadot/primitives-json authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import { ParaChainId } from '@polkadot/primitives/base';
import { JsonParaChainId } from '../types';
import bnEncode from '../bn/encode';
export default function parachainIdEncode (value: ParaChainId): JsonParaChainId {
return bnEncode(value, 64);
}

View File

@@ -0,0 +1,11 @@
// Copyright 2017-2018 @polkadot/primitives-json authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import parachainIdDecode from './decode';
import parachainIdEncode from './encode';
export {
parachainIdDecode,
parachainIdEncode
};

View File

@@ -0,0 +1,12 @@
// Copyright 2017-2018 @polkadot/primitives-json authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import { Signature } from '@polkadot/primitives/base';
import { JsonSignature } from '../types';
import hashDecode from '../hash/decode';
export default function signatureDecode (value: JsonSignature): Signature {
return hashDecode(value);
}

View File

@@ -0,0 +1,12 @@
// Copyright 2017-2018 @polkadot/primitives-json authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import { Signature } from '@polkadot/primitives/base';
import { JsonSignature } from '../types';
import hashEncode from '../hash/encode';
export default function signatureEncode (value: Signature): JsonSignature {
return hashEncode(value);
}

View File

@@ -0,0 +1,11 @@
// Copyright 2017-2018 @polkadot/primitives-json authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import signatureDecode from './decode';
import signatureEncode from './encode';
export {
signatureDecode,
signatureEncode
};

View File

@@ -0,0 +1,51 @@
// Copyright 2017-2018 @polkadot/primitives-json authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
export type JsonBnType = string;
export type JsonHash = string;
export type JsonBytes = string;
export type JsonH160 = JsonHash;
export type JsonH256 = JsonHash;
export type JsonH512 = JsonHash;
export type JsonHeaderHash = JsonH256;
export type JsonU64 = JsonBnType;
export type JsonU256 = JsonBnType;
export type JsonAccountId = JsonHash;
export type JsonAuthorityId = JsonHash;
export type JsonBlockNumber = JsonU64;
export type JsonObjectId = JsonU64;
export type JsonParaChainId = JsonU64;
export type JsonSignature = JsonHash;
export type JsonTransaction = {
from: JsonAuthorityId,
to: JsonAuthorityId,
amount: JsonBnType,
nonce: JsonBnType
}
export type JsonUnchecked = {
tx: JsonTransaction,
signature: JsonH512
}
export type JsonDigest = {
logs: Array<JsonBytes>
};
export type JsonHeader = {
parentHash: JsonHeaderHash,
number: JsonBlockNumber,
stateRoot: JsonHash,
extrinsicsRoot: JsonHash,
digest: JsonDigest
};
export type JsonBlock = {
header: JsonHeader,
timestamp: JsonU64,
transactions: Array<JsonUnchecked>
};

View File

@@ -0,0 +1,15 @@
ISC License (ISC)
Copyright 2017-2018 @polkadot/primitives-codec authors & contributors
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.

View File

@@ -0,0 +1,13 @@
[![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/primitives-codec.svg?style=flat-square)](https://www.npmjs.com/package/@polkadot/primitives-codec)
[![travis](https://img.shields.io/travis/polkadot-js/types.svg?style=flat-square)](https://travis-ci.org/polkadot-js/types)
[![maintainability](https://img.shields.io/codeclimate/maintainability/polkadot-js/types.svg?style=flat-square)](https://codeclimate.com/github/polkadot-js/types/maintainability)
[![coverage](https://img.shields.io/coveralls/polkadot-js/types.svg?style=flat-square)](https://coveralls.io/github/polkadot-js/types?branch=master)
[![dependency](https://david-dm.org/polkadot-js/types.svg?style=flat-square&path=packages/primitives-codec)](https://david-dm.org/polkadot-js/types?path=packages/primitives-codec)
[![devDependency](https://david-dm.org/polkadot-js/types/dev-status.svg?style=flat-square&path=packages/primitives-codec)](https://david-dm.org/polkadot-js/types?path=packages/primitives-codec#info=devDependencies)
# @polkadot/primitives-codec
Conversion of Polkadot types into `Uint8Array` values ready for inputs into the runtime.

View File

@@ -0,0 +1,43 @@
{
"name": "@polkadot/primitives-codec",
"version": "0.25.0",
"description": "Encoding for primitives as runtime execution inputs",
"main": "index.js",
"engines": {
"node": ">=6.4"
},
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org"
},
"repository": {
"type": "git",
"url": "git+https://github.com/polkadot-js/types.git"
},
"keywords": [
"Polkadot"
],
"author": "Jaco Greeff <jacogr@gmail.com>",
"maintainers": [
"Jaco Greeff <jacogr@gmail.com>"
],
"contributors": [],
"license": "ISC",
"bugs": {
"url": "https://github.com/polkadot-js/types/issues"
},
"homepage": "https://github.com/polkadot-js/types/tree/master/packages/primitives-codec#readme",
"scripts": {
"build": "polkadot-dev-build-babel",
"check": "eslint src && flow check",
"test": "echo \"Tests only available from root wrapper\""
},
"dependencies": {
"@babel/runtime": "^7.0.0-beta.51",
"@polkadot/primitives": "^0.25.0",
"@polkadot/primitives-builder": "^0.25.0",
"@polkadot/util": "^0.25.0",
"@polkadot/util-crypto": "^0.25.0",
"@polkadot/util-keyring": "^0.25.0"
}
}

View File

@@ -0,0 +1,54 @@
// Copyright 2017-2018 @polkadot/primitives-codec authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import extrinsics from '@polkadot/extrinsics';
import encodeUnchecked from '@polkadot/extrinsics-codec/encode/unchecked';
import hexToU8a from '@polkadot/util/hex/toU8a';
import testingPairs from '@polkadot/util-keyring/testingPairs';
import decode from './decodeRaw';
const keyring = testingPairs();
describe('decodeRaw', () => {
it('encodes the block properly', () => {
expect(
decode(
hexToU8a(
'0x' +
// parent_hash
'0900000000000000000000000000000000000000000000000000000000000009' +
// number
'4300000000000000' +
// state_root
'0800000000000000000000000000000000000000000000000000000000000008' +
// transaction_root
'0700000000000000000000000000000000000000000000000000000000000007' +
// digest
'02000000' +
'0100000001' +
'0100000002' +
// transactions
'01000000' +
'6f000000' +
// prefix
'ff' +
'0000000000000000000000000000000000000000000000000000000000000000' +
'00000000' +
'0300' +
'7527000000000000' +
'0000000000000000000000000000000000000000000000000000000000000000' +
'0000000000000000000000000000000000000000000000000000000000000000'
)
)
).toMatchObject({
extrinsics: [
encodeUnchecked(keyring.nobody, 0)(
extrinsics.timestamp.public.set,
[10101]
)
]
});
});
});

View File

@@ -0,0 +1,39 @@
// Copyright 2017-2018 @polkadot/primitives-codec authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import BN from 'bn.js';
import decodeExtrinsic from '@polkadot/extrinsics-codec/decode/length';
import u8aToBn from '@polkadot/util/u8a/toBn';
import decodeHeader from '../header/decodeRaw';
type RawData = {
body: Uint8Array,
extrinsics: Array<Uint8Array>,
header: Uint8Array,
number: BN
};
export default function decodeRaw (u8a: Uint8Array): RawData {
const { body, header, number } = decodeHeader(u8a);
const length = u8aToBn(body.subarray(0, 4), true).toNumber();
const extrinsics = [];
for (let index = 0, offset = 4; index < length; index++) {
const extrinsic = decodeExtrinsic(
body.subarray(offset)
);
offset += extrinsic.length + 4;
extrinsics.push(extrinsic);
}
return {
body,
extrinsics,
header,
number
};
}

View File

@@ -0,0 +1,46 @@
// Copyright 2017-2018 @polkadot/primitives-codec authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import extrinsics from '@polkadot/extrinsics';
import encodeUnchecked from '@polkadot/extrinsics-codec/encode/unchecked';
import blockBuilder from '@polkadot/primitives-builder/block';
import hexToU8a from '@polkadot/util/hex/toU8a';
import testingPairs from '@polkadot/util-keyring/testingPairs';
import { encodeBlock } from './index';
const keyring = testingPairs();
describe('encodeBlock', () => {
it('encodes a block correctly (actual values)', () => {
expect(
encodeBlock(
blockBuilder({
header: {
number: 9,
parentHash: hexToU8a('0x737d699e4e42f78dc2fb098f01bb85389f2c7f0a77bb41918adac6bfa5b3ee46'),
stateRoot: hexToU8a('0xf707774183723f201b875024069f30e7089b7f83c3c3cdc534b10d15fca91262')
},
extrinsics: [
encodeUnchecked(keyring.nobody, 0)(
extrinsics.timestamp.public.set,
[0x5b13c3a4]
),
encodeUnchecked(keyring.nobody, 0)(
extrinsics.parachains.public.setHeads,
[[]]
)
]
})
)
).toEqual(
new Uint8Array([
115, 125, 105, 158, 78, 66, 247, 141, 194, 251, 9, 143, 1, 187, 133, 56, 159, 44, 127, 10, 119, 187, 65, 145, 138, 218, 198, 191, 165, 179, 238, 70, 9, 0, 0, 0, 0, 0, 0, 0, 247, 7, 119, 65, 131, 114, 63, 32, 27, 135, 80, 36, 6, 159, 48, 231, 8, 155, 127, 131, 195, 195, 205, 197, 52, 177, 13, 21, 252, 169, 18, 98, 140, 102, 133, 98, 214, 123, 73, 173, 122, 252, 247, 48, 181, 86, 77, 188, 213, 161, 17, 19, 73, 96, 158, 181, 249, 69, 97, 15, 186, 12, 45, 157, 0, 0, 0, 0, 2, 0, 0, 0, 111, 0, 0, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 164, 195, 19, 91, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 107, 0, 0, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
])
// hexToU8a(
// '0x737d699e4e42f78dc2fb098f01bb85389f2c7f0a77bb41918adac6bfa5b3ee460900000000000000f707774183723f201b875024069f30e7089b7f83c3c3cdc534b10d15fca91262ab602f7974bbfb513f021f39777e2195094dc64a2c1b7c82a1781cb9fd4768a800000000020000006e0000000000000000000000000000000000000000000000000000000000000000000000000000000300a4c3135b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006a00000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
// )
);
});
});

View File

@@ -0,0 +1,15 @@
// Copyright 2017-2018 @polkadot/primitives-codec authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import { Block } from '@polkadot/primitives/block';
import headerEncode from '../header/encode';
import encodeRaw from './encodeRaw';
export default function encodeBlock ({ extrinsics, header }: Block): Uint8Array {
return encodeRaw(
headerEncode(header, extrinsics),
extrinsics
);
}

View File

@@ -0,0 +1,37 @@
// Copyright 2017-2018 @polkadot/primitives-codec authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import encodeRaw from './encodeRaw';
describe('encodeRaw', () => {
it('encodes correctly (actual values)', () => {
expect(
encodeRaw(
new Uint8Array([
168, 135, 224, 93, 140, 222, 226, 83, 13, 116, 138, 197, 164, 6, 48, 190, 101, 18, 221, 166, 40, 179, 158, 112, 133, 154, 215, 198, 177, 76, 212, 228,
1, 0, 0, 0, 0, 0, 0, 0,
159, 216, 180, 61, 159, 12, 131, 80, 22, 196, 220, 94, 6, 222, 68, 159, 97, 60, 16, 69, 163, 149, 125, 138, 175, 36, 30, 93, 235, 4, 1, 168,
245, 208, 141, 24, 250, 136, 158, 84, 67, 170, 59, 146, 17, 149, 62, 67, 254, 66, 126, 53, 20, 146, 252, 243, 137, 89, 224, 145, 252, 79, 109, 15,
0, 0, 0, 0
]),
[
new Uint8Array([
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 188, 29, 21, 91, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
]),
new Uint8Array([
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
])
]
)
).toEqual(
new Uint8Array([
168, 135, 224, 93, 140, 222, 226, 83, 13, 116, 138, 197, 164, 6, 48, 190, 101, 18, 221, 166, 40, 179, 158, 112, 133, 154, 215, 198, 177, 76, 212, 228, 1, 0, 0, 0, 0, 0, 0, 0, 159, 216, 180, 61, 159, 12, 131, 80, 22, 196, 220, 94, 6, 222, 68, 159, 97, 60, 16, 69, 163, 149, 125, 138, 175, 36, 30, 93, 235, 4, 1, 168, 245, 208, 141, 24, 250, 136, 158, 84, 67, 170, 59, 146, 17, 149, 62, 67, 254, 66, 126, 53, 20, 146, 252, 243, 137, 89, 224, 145, 252, 79, 109, 15, 0, 0, 0, 0, 2, 0, 0, 0,
110, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 188, 29, 21, 91, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
106, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
])
);
});
});

View File

@@ -0,0 +1,19 @@
// Copyright 2017-2018 @polkadot/primitives-codec authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import { UncheckedRaw } from '@polkadot/primitives/extrinsic';
import uncheckedLength from '@polkadot/extrinsics-codec/encode/length';
import u8aConcat from '@polkadot/util/u8a/concat';
import encodeArray from '../encoder/array';
export default function encodeBlockRaw (header: Uint8Array, extrinsics: Array<UncheckedRaw> = []): Uint8Array {
return u8aConcat(
header,
encodeArray(
extrinsics.map(uncheckedLength)
)
);
}

View File

@@ -0,0 +1,9 @@
// Copyright 2017-2018 @polkadot/primitives-codec authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import encodeBlock from './encode';
export {
encodeBlock
};

View File

@@ -0,0 +1,37 @@
// Copyright 2017-2018 @polkadot/primitives-codec authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import decodeArray from './array';
describe('decodeArray', () => {
it('decodes an array with the length', () => {
expect(
decodeArray(
new Uint8Array([
2, 0, 0, 0, // length
1, 2, // first
3, 4 // second
])
)
).toEqual({
length: 2,
data: new Uint8Array([1, 2, 3, 4])
});
});
it('decodes where array is an subarray', () => {
expect(
decodeArray(
new Uint8Array([
0, 0, 0, 0, 0, 0, 0, 0, // padding
1, 0, 0, 0, // length
1, 2, 3, 4 // entry
]).subarray(8)
)
).toEqual({
length: 1,
data: new Uint8Array([1, 2, 3, 4])
});
});
});

View File

@@ -0,0 +1,18 @@
// Copyright 2017-2018 @polkadot/primitives-codec authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import u8aToBn from '@polkadot/util/u8a/toBn';
type DecodedArray = {
length: number,
data: Uint8Array
};
export default function decodeArray (input: Uint8Array): DecodedArray {
return {
// FIXME: This conversion is horrible, however Dataview on subarray yields wrong getUint32 value
length: u8aToBn(input.subarray(0, 4), true).toNumber(),
data: input.slice(4)
};
}

View File

@@ -0,0 +1,36 @@
// Copyright 2017-2018 @polkadot/primitives-codec authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import decodeU8a from './u8a';
describe('decodeU8a', () => {
it('decodes an input with the length', () => {
expect(
decodeU8a(
new Uint8Array([
4, 0, 0, 0, // length
1, 2, 3, 4, // data
5, 5, 5, 5 // extra
])
)
).toEqual(
new Uint8Array([1, 2, 3, 4])
);
});
it('decodes an subarray', () => {
expect(
decodeU8a(
new Uint8Array([
0, 0, 0, 0, 0, 0, 0, 0, // padding
4, 0, 0, 0, // length
1, 2, 3, 4, // data
5, 5, 5, 5 // extra
]).subarray(8)
)
).toEqual(
new Uint8Array([1, 2, 3, 4])
);
});
});

View File

@@ -0,0 +1,12 @@
// Copyright 2017-2018 @polkadot/primitives-codec authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import u8aToBn from '@polkadot/util/u8a/toBn';
export default function decodeU8a (input: Uint8Array): Uint8Array {
// FIXME: This conversion is horrible, however Dataview on subarray yields wrong getUint32 value
const length = u8aToBn(input.subarray(0, 4), true).toNumber();
return input.slice(4, 4 + length);
}

View File

@@ -0,0 +1,22 @@
// Copyright 2017-2018 @polkadot/primitives-codec authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import encodeArray from './array';
describe('encodeArray', () => {
it('encodes an array with the length', () => {
expect(
encodeArray([
new Uint8Array([1, 2]),
new Uint8Array([3, 4])
])
).toEqual(
new Uint8Array([
2, 0, 0, 0, // length
1, 2, // first
3, 4 // second
])
);
});
});

View File

@@ -0,0 +1,18 @@
// Copyright 2017-2018 @polkadot/primitives-codec authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
export default function encodeArray (input: Array<Uint8Array>): Uint8Array {
const total = input.reduce((total, input) => total + input.length, 0);
const output = new Uint8Array(total + 4);
let offset = 4;
new DataView(output.buffer).setUint32(0, input.length, true);
return input.reduce((output, input) => {
output.set(input, offset);
offset += input.length;
return output;
}, output);
}

View File

@@ -0,0 +1,20 @@
// Copyright 2017-2018 @polkadot/primitives-codec authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import encodeU8a from './u8a';
describe('encodeU8a', () => {
it('encodes an input with the length', () => {
expect(
encodeU8a(
new Uint8Array([1, 2, 3, 4])
)
).toEqual(
new Uint8Array([
4, 0, 0, 0, // length
1, 2, 3, 4 // data
])
);
});
});

View File

@@ -0,0 +1,13 @@
// Copyright 2017-2018 @polkadot/primitives-codec authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
export default function encodeU8a (input: Uint8Array): Uint8Array {
const output = new Uint8Array(input.length + 4);
new DataView(output.buffer).setUint32(0, input.length, true);
output.set(input, 4);
return output;
}

View File

@@ -0,0 +1,47 @@
// Copyright 2017-2018 @polkadot/primitives-codec authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import createHeader from '@polkadot/primitives-builder/header';
import { decodeHeader } from './index';
describe('decodeHeader', () => {
it('decodes properly', () => {
expect(
JSON.stringify(
decodeHeader(
new Uint8Array([
// parent_hash
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5,
// number
67, 0, 0, 0, 0, 0, 0, 0,
// state_root
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,
// transaction_root
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6,
// digest (length, log1, log2)
2, 0, 0, 0,
1, 0, 0, 0, 1,
1, 0, 0, 0, 2
])
)
)
).toEqual(
JSON.stringify(
createHeader({
digest: {
logs: [
new Uint8Array([1]),
new Uint8Array([2])
]
},
extrinsicsRoot: new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6]),
number: 67,
parentHash: new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5]),
stateRoot: new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3])
})
)
);
});
});

View File

@@ -0,0 +1,24 @@
// Copyright 2017-2018 @polkadot/primitives-codec authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import { Header } from '@polkadot/primitives/header';
import createHeader from '@polkadot/primitives-builder/header';
import decodeRaw from './decodeRaw';
import { OFF_PARENT_HASH, OFF_STATE_ROOT, OFF_TX_ROOT } from './offsets';
export default function decodeHeader (u8a: Uint8Array): Header {
const { number, logs } = decodeRaw(u8a);
return createHeader({
digest: {
logs
},
extrinsicsRoot: u8a.subarray(OFF_TX_ROOT, OFF_TX_ROOT + 32),
number,
parentHash: u8a.subarray(OFF_PARENT_HASH, OFF_PARENT_HASH + 32),
stateRoot: u8a.subarray(OFF_STATE_ROOT, OFF_STATE_ROOT + 32)
});
}

View File

@@ -0,0 +1,57 @@
// Copyright 2017-2018 @polkadot/primitives-codec authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import BN from 'bn.js';
import decode from './decodeRaw';
describe('decodeRaw', () => {
it('returns the raw parts', () => {
expect(
JSON.stringify(
decode(
new Uint8Array([
// parent_hash
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5,
// number
67, 0, 0, 0, 0, 0, 0, 0,
// state_root
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,
// transaction_root
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6,
// digest (length, log1, log2)
2, 0, 0, 0,
1, 0, 0, 0, 1,
1, 0, 0, 0, 2,
// remainder
1, 2, 3, 4, 5, 4, 3, 2, 1
])
)
)
).toEqual(
JSON.stringify({
body: new Uint8Array([1, 2, 3, 4, 5, 4, 3, 2, 1]),
header: new Uint8Array([
// parent_hash
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5,
// number
67, 0, 0, 0, 0, 0, 0, 0,
// state_root
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,
// transaction_root
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6,
// digest (length, log1, log2)
2, 0, 0, 0,
1, 0, 0, 0, 1,
1, 0, 0, 0, 2
]),
logs: [
new Uint8Array([1]),
new Uint8Array([2])
],
number: new BN(67)
})
);
});
});

View File

@@ -0,0 +1,39 @@
// Copyright 2017-2018 @polkadot/primitives-codec authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import BN from 'bn.js';
import u8aToBn from '@polkadot/util/u8a/toBn';
import decodeArray from '../decoder/array';
import decodeU8a from '../decoder/u8a';
import { OFF_DIGEST, OFF_NUMBER } from './offsets';
type DecodedRaw = {
body: Uint8Array,
header: Uint8Array,
logs: Array<Uint8Array>,
number: BN
};
export default function decodeHeader (u8a: Uint8Array): DecodedRaw {
const logs = [];
const dd = decodeArray(u8a.subarray(OFF_DIGEST));
let offset = 0;
for (let index = 0; index < dd.length; index++) {
const log = decodeU8a(dd.data.subarray(offset));
logs.push(log);
offset += log.length + 4;
}
return {
body: dd.data.subarray(offset),
header: u8a.subarray(0, OFF_DIGEST + offset + 4),
logs,
number: u8aToBn(u8a.subarray(OFF_NUMBER, OFF_NUMBER + 8), true)
};
}

View File

@@ -0,0 +1,45 @@
// Copyright 2017-2018 @polkadot/primitives-codec authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import { encodeHeader } from './index';
describe('encodeHeader', () => {
it('encodes the block header as u8a', () => {
expect(
encodeHeader({
digest: {
logs: [
new Uint8Array([1, 2, 3]),
new Uint8Array([7, 8, 9, 10])
]
},
extrinsicsRoot: new Uint8Array([
6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0
]),
parentHash: new Uint8Array([
5, 0, 0, 0, 5, 0, 0, 0, 5, 0, 0, 0, 5, 0, 0, 0, 5, 0, 0, 0, 5, 0, 0, 0, 5, 0, 0, 0, 5, 0, 0, 0
]),
number: 67,
stateRoot: new Uint8Array([
3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0
])
})
).toEqual(
new Uint8Array([
// parentHash
5, 0, 0, 0, 5, 0, 0, 0, 5, 0, 0, 0, 5, 0, 0, 0, 5, 0, 0, 0, 5, 0, 0, 0, 5, 0, 0, 0, 5, 0, 0, 0,
// number
67, 0, 0, 0, 0, 0, 0, 0,
// stateRoot
3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0,
// extrinsicsRoot
6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0,
// digest (length, log1, log2)
2, 0, 0, 0,
3, 0, 0, 0, 1, 2, 3,
4, 0, 0, 0, 7, 8, 9, 10
])
);
});
});

View File

@@ -0,0 +1,32 @@
// Copyright 2017-2018 @polkadot/primitives-codec authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import { UncheckedRaw } from '@polkadot/primitives/extrinsic';
import { Header } from '@polkadot/primitives/header';
import rootRaw from '@polkadot/primitives-builder/extrinsic/rootRaw';
import bnToU8a from '@polkadot/util/bn/toU8a';
import u8aConcat from '@polkadot/util/u8a/concat';
import u8aToU8a from '@polkadot/util/u8a/toU8a';
import encodeArray from '../encoder/array';
import encodeU8a from '../encoder/u8a';
export default function encodeHeader ({ digest: { logs }, extrinsicsRoot, parentHash, number, stateRoot }: Header, extrinsics?: Array<UncheckedRaw>): Uint8Array {
return u8aConcat(
u8aToU8a(parentHash),
bnToU8a(number, 64, true),
u8aToU8a(stateRoot),
extrinsics
? rootRaw(extrinsics)
: u8aToU8a(extrinsicsRoot),
encodeArray(
logs.map((log) =>
encodeU8a(
u8aToU8a(log)
)
)
)
);
}

View File

@@ -0,0 +1,16 @@
// Copyright 2017-2018 @polkadot/primitives-codec authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import { Header } from '@polkadot/primitives/header';
import blake2Asu8a from '@polkadot/util-crypto/blake2/asU8a';
import encode from './encode';
export default function headerHash (header: Header): Uint8Array {
return blake2Asu8a(
encode(header),
256
);
}

View File

@@ -0,0 +1,11 @@
// Copyright 2017-2018 @polkadot/primitives-codec authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import decodeHeader from './decode';
import encodeHeader from './encode';
export {
decodeHeader,
encodeHeader
};

View File

@@ -0,0 +1,17 @@
// Copyright 2017-2018 @polkadot/primitives-codec authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
const OFF_PARENT_HASH = 0;
const OFF_NUMBER = OFF_PARENT_HASH + 32;
const OFF_STATE_ROOT = OFF_NUMBER + 8;
const OFF_TX_ROOT = OFF_STATE_ROOT + 32;
const OFF_DIGEST = OFF_TX_ROOT + 32;
export {
OFF_PARENT_HASH,
OFF_NUMBER,
OFF_STATE_ROOT,
OFF_TX_ROOT,
OFF_DIGEST
};

View File

@@ -0,0 +1,6 @@
// Copyright 2017-2018 @polkadot/primitives-codec authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
export * from './block';
export * from './header';

373
packages/trie-db/LICENSE Normal file
View File

@@ -0,0 +1,373 @@
Mozilla Public License Version 2.0
==================================
1. Definitions
--------------
1.1. "Contributor"
means each individual or legal entity that creates, contributes to
the creation of, or owns Covered Software.
1.2. "Contributor Version"
means the combination of the Contributions of others (if any) used
by a Contributor and that particular Contributor's Contribution.
1.3. "Contribution"
means Covered Software of a particular Contributor.
1.4. "Covered Software"
means Source Code Form to which the initial Contributor has attached
the notice in Exhibit A, the Executable Form of such Source Code
Form, and Modifications of such Source Code Form, in each case
including portions thereof.
1.5. "Incompatible With Secondary Licenses"
means
(a) that the initial Contributor has attached the notice described
in Exhibit B to the Covered Software; or
(b) that the Covered Software was made available under the terms of
version 1.1 or earlier of the License, but not also under the
terms of a Secondary License.
1.6. "Executable Form"
means any form of the work other than Source Code Form.
1.7. "Larger Work"
means a work that combines Covered Software with other material, in
a separate file or files, that is not Covered Software.
1.8. "License"
means this document.
1.9. "Licensable"
means having the right to grant, to the maximum extent possible,
whether at the time of the initial grant or subsequently, any and
all of the rights conveyed by this License.
1.10. "Modifications"
means any of the following:
(a) any file in Source Code Form that results from an addition to,
deletion from, or modification of the contents of Covered
Software; or
(b) any new file in Source Code Form that contains any Covered
Software.
1.11. "Patent Claims" of a Contributor
means any patent claim(s), including without limitation, method,
process, and apparatus claims, in any patent Licensable by such
Contributor that would be infringed, but for the grant of the
License, by the making, using, selling, offering for sale, having
made, import, or transfer of either its Contributions or its
Contributor Version.
1.12. "Secondary License"
means either the GNU General Public License, Version 2.0, the GNU
Lesser General Public License, Version 2.1, the GNU Affero General
Public License, Version 3.0, or any later versions of those
licenses.
1.13. "Source Code Form"
means the form of the work preferred for making modifications.
1.14. "You" (or "Your")
means an individual or a legal entity exercising rights under this
License. For legal entities, "You" includes any entity that
controls, is controlled by, or is under common control with You. For
purposes of this definition, "control" means (a) the power, direct
or indirect, to cause the direction or management of such entity,
whether by contract or otherwise, or (b) ownership of more than
fifty percent (50%) of the outstanding shares or beneficial
ownership of such entity.
2. License Grants and Conditions
--------------------------------
2.1. Grants
Each Contributor hereby grants You a world-wide, royalty-free,
non-exclusive license:
(a) under intellectual property rights (other than patent or trademark)
Licensable by such Contributor to use, reproduce, make available,
modify, display, perform, distribute, and otherwise exploit its
Contributions, either on an unmodified basis, with Modifications, or
as part of a Larger Work; and
(b) under Patent Claims of such Contributor to make, use, sell, offer
for sale, have made, import, and otherwise transfer either its
Contributions or its Contributor Version.
2.2. Effective Date
The licenses granted in Section 2.1 with respect to any Contribution
become effective for each Contribution on the date the Contributor first
distributes such Contribution.
2.3. Limitations on Grant Scope
The licenses granted in this Section 2 are the only rights granted under
this License. No additional rights or licenses will be implied from the
distribution or licensing of Covered Software under this License.
Notwithstanding Section 2.1(b) above, no patent license is granted by a
Contributor:
(a) for any code that a Contributor has removed from Covered Software;
or
(b) for infringements caused by: (i) Your and any other third party's
modifications of Covered Software, or (ii) the combination of its
Contributions with other software (except as part of its Contributor
Version); or
(c) under Patent Claims infringed by Covered Software in the absence of
its Contributions.
This License does not grant any rights in the trademarks, service marks,
or logos of any Contributor (except as may be necessary to comply with
the notice requirements in Section 3.4).
2.4. Subsequent Licenses
No Contributor makes additional grants as a result of Your choice to
distribute the Covered Software under a subsequent version of this
License (see Section 10.2) or under the terms of a Secondary License (if
permitted under the terms of Section 3.3).
2.5. Representation
Each Contributor represents that the Contributor believes its
Contributions are its original creation(s) or it has sufficient rights
to grant the rights to its Contributions conveyed by this License.
2.6. Fair Use
This License is not intended to limit any rights You have under
applicable copyright doctrines of fair use, fair dealing, or other
equivalents.
2.7. Conditions
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
in Section 2.1.
3. Responsibilities
-------------------
3.1. Distribution of Source Form
All distribution of Covered Software in Source Code Form, including any
Modifications that You create or to which You contribute, must be under
the terms of this License. You must inform recipients that the Source
Code Form of the Covered Software is governed by the terms of this
License, and how they can obtain a copy of this License. You may not
attempt to alter or restrict the recipients' rights in the Source Code
Form.
3.2. Distribution of Executable Form
If You distribute Covered Software in Executable Form then:
(a) such Covered Software must also be made available in Source Code
Form, as described in Section 3.1, and You must inform recipients of
the Executable Form how they can obtain a copy of such Source Code
Form by reasonable means in a timely manner, at a charge no more
than the cost of distribution to the recipient; and
(b) You may distribute such Executable Form under the terms of this
License, or sublicense it under different terms, provided that the
license for the Executable Form does not attempt to limit or alter
the recipients' rights in the Source Code Form under this License.
3.3. Distribution of a Larger Work
You may create and distribute a Larger Work under terms of Your choice,
provided that You also comply with the requirements of this License for
the Covered Software. If the Larger Work is a combination of Covered
Software with a work governed by one or more Secondary Licenses, and the
Covered Software is not Incompatible With Secondary Licenses, this
License permits You to additionally distribute such Covered Software
under the terms of such Secondary License(s), so that the recipient of
the Larger Work may, at their option, further distribute the Covered
Software under the terms of either this License or such Secondary
License(s).
3.4. Notices
You may not remove or alter the substance of any license notices
(including copyright notices, patent notices, disclaimers of warranty,
or limitations of liability) contained within the Source Code Form of
the Covered Software, except that You may alter any license notices to
the extent required to remedy known factual inaccuracies.
3.5. Application of Additional Terms
You may choose to offer, and to charge a fee for, warranty, support,
indemnity or liability obligations to one or more recipients of Covered
Software. However, You may do so only on Your own behalf, and not on
behalf of any Contributor. You must make it absolutely clear that any
such warranty, support, indemnity, or liability obligation is offered by
You alone, and You hereby agree to indemnify every Contributor for any
liability incurred by such Contributor as a result of warranty, support,
indemnity or liability terms You offer. You may include additional
disclaimers of warranty and limitations of liability specific to any
jurisdiction.
4. Inability to Comply Due to Statute or Regulation
---------------------------------------------------
If it is impossible for You to comply with any of the terms of this
License with respect to some or all of the Covered Software due to
statute, judicial order, or regulation then You must: (a) comply with
the terms of this License to the maximum extent possible; and (b)
describe the limitations and the code they affect. Such description must
be placed in a text file included with all distributions of the Covered
Software under this License. Except to the extent prohibited by statute
or regulation, such description must be sufficiently detailed for a
recipient of ordinary skill to be able to understand it.
5. Termination
--------------
5.1. The rights granted under this License will terminate automatically
if You fail to comply with any of its terms. However, if You become
compliant, then the rights granted under this License from a particular
Contributor are reinstated (a) provisionally, unless and until such
Contributor explicitly and finally terminates Your grants, and (b) on an
ongoing basis, if such Contributor fails to notify You of the
non-compliance by some reasonable means prior to 60 days after You have
come back into compliance. Moreover, Your grants from a particular
Contributor are reinstated on an ongoing basis if such Contributor
notifies You of the non-compliance by some reasonable means, this is the
first time You have received notice of non-compliance with this License
from such Contributor, and You become compliant prior to 30 days after
Your receipt of the notice.
5.2. If You initiate litigation against any entity by asserting a patent
infringement claim (excluding declaratory judgment actions,
counter-claims, and cross-claims) alleging that a Contributor Version
directly or indirectly infringes any patent, then the rights granted to
You by any and all Contributors for the Covered Software under Section
2.1 of this License shall terminate.
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
end user license agreements (excluding distributors and resellers) which
have been validly granted by You or Your distributors under this License
prior to termination shall survive termination.
************************************************************************
* *
* 6. Disclaimer of Warranty *
* ------------------------- *
* *
* Covered Software is provided under this License on an "as is" *
* basis, without warranty of any kind, either expressed, implied, or *
* statutory, including, without limitation, warranties that the *
* Covered Software is free of defects, merchantable, fit for a *
* particular purpose or non-infringing. The entire risk as to the *
* quality and performance of the Covered Software is with You. *
* Should any Covered Software prove defective in any respect, You *
* (not any Contributor) assume the cost of any necessary servicing, *
* repair, or correction. This disclaimer of warranty constitutes an *
* essential part of this License. No use of any Covered Software is *
* authorized under this License except under this disclaimer. *
* *
************************************************************************
************************************************************************
* *
* 7. Limitation of Liability *
* -------------------------- *
* *
* Under no circumstances and under no legal theory, whether tort *
* (including negligence), contract, or otherwise, shall any *
* Contributor, or anyone who distributes Covered Software as *
* permitted above, be liable to You for any direct, indirect, *
* special, incidental, or consequential damages of any character *
* including, without limitation, damages for lost profits, loss of *
* goodwill, work stoppage, computer failure or malfunction, or any *
* and all other commercial damages or losses, even if such party *
* shall have been informed of the possibility of such damages. This *
* limitation of liability shall not apply to liability for death or *
* personal injury resulting from such party's negligence to the *
* extent applicable law prohibits such limitation. Some *
* jurisdictions do not allow the exclusion or limitation of *
* incidental or consequential damages, so this exclusion and *
* limitation may not apply to You. *
* *
************************************************************************
8. Litigation
-------------
Any litigation relating to this License may be brought only in the
courts of a jurisdiction where the defendant maintains its principal
place of business and such litigation shall be governed by laws of that
jurisdiction, without reference to its conflict-of-law provisions.
Nothing in this Section shall prevent a party's ability to bring
cross-claims or counter-claims.
9. Miscellaneous
----------------
This License represents the complete agreement concerning the subject
matter hereof. If any provision of this License is held to be
unenforceable, such provision shall be reformed only to the extent
necessary to make it enforceable. Any law or regulation which provides
that the language of a contract shall be construed against the drafter
shall not be used to construe this License against a Contributor.
10. Versions of the License
---------------------------
10.1. New Versions
Mozilla Foundation is the license steward. Except as provided in Section
10.3, no one other than the license steward has the right to modify or
publish new versions of this License. Each version will be given a
distinguishing version number.
10.2. Effect of New Versions
You may distribute the Covered Software under the terms of the version
of the License under which You originally received the Covered Software,
or under the terms of any subsequent version published by the license
steward.
10.3. Modified Versions
If you create software not governed by this License, and you want to
create a new license for such software, you may create and use a
modified version of this License if you rename the license and remove
any references to the name of the license steward (except to note that
such modified license differs from this License).
10.4. Distributing Source Code Form that is Incompatible With Secondary
Licenses
If You choose to distribute Source Code Form that is Incompatible With
Secondary Licenses under the terms of this version of the License, the
notice described in Exhibit B of this License must be attached.
Exhibit A - Source Code Form License Notice
-------------------------------------------
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
If it is not possible or desirable to put the notice in a particular
file, then You may include the notice in a location (such as a LICENSE
file in a relevant directory) where a recipient would be likely to look
for such a notice.
You may add additional accurate notices of copyright ownership.
Exhibit B - "Incompatible With Secondary Licenses" Notice
---------------------------------------------------------
This Source Code Form is "Incompatible With Secondary Licenses", as
defined by the Mozilla Public License, v. 2.0.

View File

@@ -0,0 +1,30 @@
[![polkadotjs](https://img.shields.io/badge/polkadot-js-orange.svg?style=flat-square)](https://polkadot.js.org)
![mpl-2](https://img.shields.io/badge/license-MPL-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/trie-db.svg?style=flat-square)](https://www.npmjs.com/package/@polkadot/trie-db)
[![travis](https://img.shields.io/travis/polkadot-js/trie.svg?style=flat-square)](https://travis-ci.org/polkadot-js/trie)
[![maintainability](https://img.shields.io/codeclimate/maintainability/polkadot-js/trie.svg?style=flat-square)](https://codeclimate.com/github/polkadot-js/trie/maintainability)
[![coverage](https://img.shields.io/coveralls/polkadot-js/trie.svg?style=flat-square)](https://coveralls.io/github/polkadot-js/trie?branch=master)
[![dependency](https://david-dm.org/polkadot-js/trie.svg?style=flat-square&path=packages/trie)](https://david-dm.org/polkadot-js/trie?path=packages/trie-db)
[![devDependency](https://david-dm.org/polkadot-js/trie/dev-status.svg?style=flat-square&path=packages/trie-db)](https://david-dm.org/polkadot-js/trie?path=packages/trie-db#info=devDependencies)
# @polkadot/trie-db
An Implementation of the [Ethereum Merkle Patricia Tree](https://github.com/ethereum/wiki/wiki/Patricia-Tree) that uses Blake2 for hashing.
# Adapted from Ethereum
The has been adapted from the [original EthereumJs implementation](https://github.com/ethereumjs/merkle-patricia-tree) with the following changes -
- Introduce [TypeScript](https://www.typescriptlang.org/) into the mix
- ES6-ify as applicable (Classes, `self` -> `this`, `function() {}` -> `() => {}`)
- Moves to a Promise-based interface (as applicable)
- Support only Uint8Array key/values (Buffer/String in the original)
- Use utilities from [@polkadot/util](https://github.com/polkadot-js/common)
- Supports blake2 hashing (sha3 in the original), aligning with the Polkadot tech stack)
- Updated the build steps with sources moved to [src/](src/)
- Tests updated to use [Jest](https://facebook.github.io/jest/)
- Upgrade interfaces to latest [levelup](https://github.com/Level/levelup)
- Removed the secure interface (not applicable for Substrate chains)
... well at least the above is the _idea_ behind the fork ...

View File

@@ -0,0 +1,47 @@
{
"name": "@polkadot/trie-db",
"version": "0.25.0",
"description": "This is an implementation of the modified merkle patricia tree as speficed in Ethereum's yellow paper, adpated for Polkadot.",
"main": "index.js",
"scripts": {},
"maintainers": [
"Jaco Greeff <jacogr@gmail.com>"
],
"contributors": [
"mjbecze <mjbecze@gmail.com>",
"Aaron Kumavis <http://aaron.kumavis.me/> (https://github.com/kumavis)"
],
"repository": {
"type": "git",
"url": "https://github.com/polkadot-js/common.git"
},
"bugs": {
"url": "https://github.com/polkadot-js/common/issues"
},
"keywords": [
"merkle",
"radix",
"trie",
"ethereum"
],
"license": "MPL-2.0",
"dependencies": {
"@babel/runtime": "^7.0.0-beta.51",
"@polkadot/trie-hash": "^0.25.0",
"@polkadot/util": "^0.25.0",
"@polkadot/util-crypto": "^0.25.0",
"@polkadot/util-rlp": "^0.25.0",
"@types/async": "^2.0.49",
"@types/semaphore": "^1.1.0",
"async": "^1.4.2",
"encoding-down": "^5.0.3",
"level-ws": "0.1.0",
"levelup": "^3.0.1",
"memdown": "^3.0.0",
"readable-stream": "^2.2.8",
"semaphore": ">=1.0.1"
},
"devDependencies": {
"ethereumjs-testing": "0.0.1"
}
}

View File

@@ -0,0 +1,827 @@
// Copyright 2015-2018 authors & contributors of https://github.com/ethereumjs/merkle-patricia-tree
// Copyright 2017-2018 @polkadot/trie-db authors & contributors
// This software may be modified and distributed under the terms
// of the MPL-2.0 license. See the LICENSE file for details.
import { SemaphorePromise } from './types';
import async from 'async';
// @ts-ignore FIXME, we need to properly check the full file
import levelup from 'levelup';
import memdown from 'memdown';
import logger from '@polkadot/util/logger';
import assert from '@polkadot/util/assert';
import isU8a from '@polkadot/util/is/u8a';
import promisify from '@polkadot/util/promisify';
import u8aToHex from '@polkadot/util/u8a/toHex';
import decodeRlp from '@polkadot/util-rlp/decode';
import { EMPTY_ROOT_U8A, EMPTY_ROOT_STR } from './constants';
import encoder from './encoder';
import { nibblesMatchingLength, nibblesIsEqual, nibblesFromU8a } from './nibbles';
import ReadStream from './streams/TrieRead';
import nodeFactory from './nodeFactory';
import isRawNode from './util/isRawNode';
import prioritizedTaskExecutor from './util/taskExecutor';
import semaphore from './util/semaphore';
type RawPutFn = (key: Uint8Array, value: Uint8Array) => Promise<any>;
const l = logger('trie/base');
export default class BaseTrie {
// @ts-ignore we are assigning via this.root in constructor
_root: Uint8Array;
_getDBs: any[]; // FIXME
_putDBs: any[]; // FIXME
dbDown: any; // FIXME
db: any; // FIXME
putRaw: RawPutFn;
semaphore: SemaphorePromise;
// @ts-ignore FIXME, we need to properly check the full file
constructor (db, root: Uint8Array) {
this.putRaw = this._putRaw;
this.semaphore = semaphore(1);
this.dbDown = db || memdown();
this.db = levelup(encoder(this.dbDown));
this._getDBs = [this.db];
this._putDBs = [this.db];
this.root = root;
l.debug(() => ['Created BaseTrie', typeof db, u8aToHex(root)]);
}
get root (): Uint8Array {
return this._root;
}
set root (value: Uint8Array) {
if (value) {
assert(isU8a(value) && value.length === 32, 'Invalid root length. Roots are Uint8Array 32 bytes');
} else {
value = EMPTY_ROOT_U8A;
}
this._root = value;
}
/**
* Gets a value given a `key`
* @method get
* @param {Buffer|String} key - the key to search for
* @param {Function} cb A callback `Function` which is given the arguments `err` - for errors that may have occured and `value` - the found value in a `Buffer` or if no value was found `null`
*/
async get (key: Uint8Array) {
l.debug(() => ['get', 'key ->', u8aToHex(key)]);
const result = await this.findPath(key);
let value = null;
if (result && result.node && result.remainder.length === 0) {
value = result.node.value;
}
return value;
}
/**
* Stores a given `value` at the given `key`
* @method put
* @param {Buffer|String} key
* @param {Buffer|String} Value
* @returns {Function} Promise<void>
*/
async put (key: Uint8Array, value: Uint8Array) {
l.debug(() => ['put', 'key ->', u8aToHex(key), 'value ->', u8aToHex(value)]);
if (!value || value.toString() === '') {
return this.del(key);
}
return this.semaphore(async () => {
if (this.root.toString() === EMPTY_ROOT_STR) {
return this._createInitialNode(key, value); // if no root initialize this trie
}
// first try to find the give key or its nearst node
const result = await this.findPath(key);
return this._updateNode(key, value, result && result.remainder, result && result.stack);
});
}
/**
* deletes a value given a `key`
* @method del
* @param {Buffer|String} key
* @param {Function} callback the callback `Function`
*/
del (key: Uint8Array) {
l.debug(() => ['del', 'key ->', u8aToHex(key)]);
return this.semaphore(async () => {
const result = await this.findPath(key);
if (result && result.node) {
return this._deleteNode(key, result.stack);
}
});
}
/**
* Retrieves a raw value in the underlying db
* @method getRaw
* @param {Buffer} key
* @param {Function} callback A callback `Function`, which is given the arguments `err` - for errors that may have occured and `value` - the found value in a `Buffer` or if no value was found `null`.
*/
async getRaw (key: Uint8Array): Promise<Uint8Array> {
let found: Uint8Array;
await Promise.all(
this._getDBs.map(async (db) => {
if (!found) {
try {
found = await db.get(key);
} catch (error) {
// l.error('getRaw', 'key ->', u8aToHex(key), error);
// not doing anything
}
}
return found;
})
);
// @ts-ignore FIXME, we need to properly check the full file
return found;
}
// retrieves a node from dbs by hash
// @ts-ignore FIXME, we need to properly check the full file
async _lookupNode (node) {
if (isRawNode(node)) {
return nodeFactory.fromRaw(node);
}
let value = await this.getRaw(node);
if (value) {
try {
// @ts-ignore FIXME, we need to properly check the full file
value = nodeFactory.fromRaw(decodeRlp(value));
} catch (error) {
l.error('_lookupNode decoding', typeof value, value);
throw error;
}
}
return value;
}
// TODO: remove the proxy method when changing the caching
async _putRaw (key: Uint8Array, value: Uint8Array) {
return Promise.all(
this._putDBs.map((db) => {
return db.put(key, value);
})
);
}
/**
* Removes a raw value in the underlying db
* @method delRaw
* @param {Buffer|String} key
* @param {Function} callback A callback `Function`, which is given the argument `err` - for errors that may have occured
*/
delRaw (key: Uint8Array) {
return Promise.all(
this._putDBs.map((db) => {
return db.del(key);
})
);
}
// writes a single node to dbs
// @ts-ignore FIXME, we need to properly check the full file
_putNode (node) {
const hash = node.hash();
const serialized = node.serialize();
return this._putRaw(hash, serialized);
}
// writes many nodes to db
// @ts-ignore FIXME, we need to properly check the full file
_batchNodes (opStack) {
return Promise.all(
this._putDBs.map((db) => {
return db.batch(opStack);
})
);
}
/**
* Trys to find a path to the node for the given key
* It returns a `stack` of nodes to the closet node
* @method findPath
* @param {String|Buffer} - key - the search key
* @param {Function} - cb - the callback function. Its is given the following
* arguments
* - err - any errors encontered
* - node - the last node found
* - remainder - the remaining key nibbles not accounted for
* - stack - an array of nodes that forms the path to node we are searching for
*/
// @ts-ignore FIXME, we need to properly check the full file
findPath (_targetKey) {
const stack: any[] = []; // FIXME
const targetKey = nibblesFromU8a(_targetKey);
l.debug(() => ['findPath', targetKey.join(', ')]);
// @ts-ignore FIXME, we need to properly check the full file
const processNode = (nodeRef, node, keyProgress, walkController) => {
const nodeKey = node.key || [];
const remainder = targetKey.slice(nibblesMatchingLength(keyProgress, targetKey));
const matchingLen = nibblesMatchingLength(remainder, nodeKey);
stack.push(node);
if (node.type === 'branch') {
if (remainder.length === 0) {
walkController.return(null, { node, remainder: [], stack });
// we exhausted the key without finding a node
} else {
const branchIndex = remainder[0];
const branchNode = node.getValue(branchIndex);
if (!branchNode) {
// there are no more nodes to find and we didn't find the key
walkController.return(null, { node: null, remainder, stack });
} else {
// node found, continuing search
walkController.only(branchIndex);
}
}
} else if (node.type === 'leaf') {
if (nibblesIsEqual(remainder, nodeKey)) {
// keys match, return node with empty key
walkController.return(null, { node, remainder: [], stack });
} else {
// reached leaf but keys dont match
walkController.return(null, { node: null, remainder, stack });
}
} else if (node.type === 'extention') {
if (matchingLen !== nodeKey.length) {
// keys dont match, fail
walkController.return(null, { node: null, remainder, stack });
} else {
// keys match, continue search
walkController.next();
}
}
};
return promisify(this, this._walkTrie, this.root, processNode);
}
/*
* Finds all nodes that store k,v values
*/
// NOTE seems unused
// _findNode = function (key, root, stack, cb) {
// this.findPath(key, (...args) => {
// cb.apply(null, args);
// });
// };
/*
* Finds all nodes that store k,v values
*/
// @ts-ignore FIXME, we need to properly check the full file
_findValueNodes (onFound, cb) {
// @ts-ignore FIXME, we need to properly check the full file
this._walkTrie(this.root, (nodeRef, node, key, walkController) => {
let fullKey = key;
if (node.key) {
fullKey = key.concat(node.key);
}
if (node.type === 'leaf') {
// found leaf node!
onFound(nodeRef, node, fullKey, walkController.next);
} else if (node.type === 'branch' && node.value) {
// found branch with value
onFound(nodeRef, node, fullKey, walkController.next);
} else {
// keep looking for value nodes
walkController.next();
}
}, cb);
}
/*
* Finds all nodes that are stored directly in the db
* (some nodes are stored raw inside other nodes)
*/
// @ts-ignore FIXME, we need to properly check the full file
_findDbNodes (onFound, cb) {
// @ts-ignore FIXME, we need to properly check the full file
this._walkTrie(this.root, (nodeRef, node, key, walkController) => {
if (isRawNode(nodeRef)) {
walkController.next();
} else {
onFound(nodeRef, node, key, walkController.next);
}
}, cb);
}
/**
* Updates a node
* @method _updateNode
* @param {Buffer} key
* @param {Buffer| String} value
* @param {Array} keyRemainder
* @param {Array} stack -
* @param {Function} cb - the callback
*/
// @ts-ignore FIXME, we need to properly check the full file
async _updateNode (key, value, keyRemainder, stack) {
// @ts-ignore FIXME, we need to properly check the full file
const toSave = [];
const lastNode = stack.pop();
// add the new nodes
key = nibblesFromU8a(key);
// Check if the last node is a leaf and the key matches to this
let matchLeaf = false;
if (lastNode.type === 'leaf') {
let l = 0;
for (let i = 0; i < stack.length; i++) {
const n = stack[i];
if (n.type === 'branch') {
l++;
} else {
l += n.key.length;
}
}
if ((nibblesMatchingLength(lastNode.key, key.slice(l)) === lastNode.key.length) && (keyRemainder.length === 0)) {
matchLeaf = true;
}
}
if (matchLeaf) {
// just updating a found value
lastNode.value = value;
stack.push(lastNode);
} else if (lastNode.type === 'branch') {
stack.push(lastNode);
if (keyRemainder !== 0) {
// add an extention to a branch node
keyRemainder.shift();
// create a new leaf
stack.push(nodeFactory.fromLeaf(keyRemainder, value));
} else {
lastNode.value = value;
}
} else {
// create a branch node
const lastKey = lastNode.key;
const matchingLength = nibblesMatchingLength(lastKey, keyRemainder);
// @ts-ignore FIXME, we need to properly check the full file
const newBranchNode = nodeFactory.fromBranch();
// create a new extention node
if (matchingLength !== 0) {
const newKey = lastNode.key.slice(0, matchingLength);
const newExtNode = nodeFactory.fromExtention(newKey, value);
stack.push(newExtNode);
lastKey.splice(0, matchingLength);
keyRemainder.splice(0, matchingLength);
}
stack.push(newBranchNode);
if (lastKey.length !== 0) {
const branchKey = lastKey.shift();
if (lastKey.length !== 0 || lastNode.type === 'leaf') {
// shriking extention or leaf
lastNode.key = lastKey;
// @ts-ignore FIXME, we need to properly check the full file
const formatedNode = this._formatNode(lastNode, false, toSave);
// @ts-ignore FIXME, we need to properly check the full file
newBranchNode.setValue(branchKey, formatedNode);
} else {
// remove extention or attaching
// @ts-ignore FIXME, we need to properly check the full file
this._formatNode(lastNode, false, true, toSave);
// @ts-ignore FIXME, we need to properly check the full file
newBranchNode.setValue(branchKey, lastNode.value);
}
} else {
newBranchNode.value = lastNode.value;
}
if (keyRemainder.length !== 0) {
keyRemainder.shift();
// add a leaf node to the new branch node
stack.push(nodeFactory.fromLeaf(keyRemainder, value));
} else {
newBranchNode.value = value;
}
}
// @ts-ignore FIXME, we need to properly check the full file
return this._saveStack(key, stack, toSave);
}
// walk tree
// @ts-ignore FIXME, we need to properly check the full file
async _walkTrie (root, onNode, onDone) {
root = root || this.root;
let isAborted: boolean = false;
// @ts-ignore FIXME, we need to properly check the full file
let returnValues: any[] = [];
if (root.toString() === EMPTY_ROOT_STR) {
onDone();
return;
}
// the maximum pool size should be high enough to utilise the parallelizability of reading nodes from disk and
// low enough to utilize the prioritisation of node lookup.
const maxPoolSize = 500;
const taskExecutor = prioritizedTaskExecutor(maxPoolSize);
// @ts-ignore FIXME, we need to properly check the full file
const processNode = (nodeRef, node, key, cb) => {
if (!node || isAborted) {
return cb();
}
const self = this;
let isStopped = false;
key = key || [];
const walkController = {
stop: function () {
isStopped = true;
cb();
},
// end all traversal and return values to the onDone cb
return: function () {
isAborted = true;
// @ts-ignore FIXME, we need to properly check the full file
returnValues = arguments;
cb();
},
next: async function () {
if (isAborted || isStopped) {
return cb();
}
const children = node.getChildren();
// @ts-ignore FIXME callback
async.forEachOf(children, (childData: any[], index: number, cb) => {
// @ts-ignore FIXME, we need to properly check the full file
const keyExtension = childData[0];
// @ts-ignore FIXME, we need to properly check the full file
const childRef = childData[1];
const childKey = key.concat(keyExtension);
const priority = childKey.length;
taskExecutor(priority, async (taskCallback) => {
const childNode = await self._lookupNode(childRef);
// @ts-ignore FIXME, we need to properly check the full file
taskCallback();
processNode(childRef, childNode, childKey, cb);
});
}, cb);
},
// @ts-ignore FIXME, we need to properly check the full file
only: function (childIndex) {
const childRef = node.getValue(childIndex);
const childKey = key.slice();
childKey.push(childIndex);
const priority = childKey.length;
taskExecutor(priority, async (taskCallback) => {
const childNode = await self._lookupNode(childRef);
// @ts-ignore FIXME, we need to properly check the full file
taskCallback();
processNode(childRef, childNode, childKey, cb);
});
}
};
onNode(nodeRef, node, key, walkController);
};
const node = await this._lookupNode(root);
processNode(root, node, null, (error: Error | null) => {
if (error) {
onDone(error);
return;
}
// @ts-ignore FIXME, we need to properly check the full file
onDone.apply(null, returnValues);
});
}
/**
* saves a stack
* @method _saveStack
* @param {Array} key - the key. Should follow the stack
* @param {Array} stack - a stack of nodes to the value given by the key
* @param {Array} opStack - a stack of levelup operations to commit at the end of this funciton
* @param {Function} cb
*/
// @ts-ignore FIXME, we need to properly check the full file
_saveStack (key, stack, opStack: any[]) {
let lastRoot;
// update nodes
while (stack.length) {
const node = stack.pop();
if (node.type === 'leaf') {
key.splice(key.length - node.key.length);
} else if (node.type === 'extention') {
key.splice(key.length - node.key.length);
if (lastRoot) {
node.value = lastRoot;
}
} else if (node.type === 'branch') {
if (lastRoot) {
const branchKey = key.pop();
node.setValue(branchKey, lastRoot);
}
}
// @ts-ignore FIXME, we need to properly check the full file
lastRoot = this._formatNode(node, stack.length === 0, opStack);
}
if (lastRoot) {
this.root = lastRoot;
}
return this._batchNodes(opStack);
}
// @ts-ignore FIXME, we need to properly check the full file
async _deleteNode (key: Uint8Array, stack) {
// @ts-ignore FIXME, we need to properly check the full file
const processBranchNode = (key, branchKey, branchNode, parentNode, stack) => {
// branchNode is the node ON the branch node not THE branch node
const branchNodeKey = branchNode.key;
if (!parentNode || parentNode.type === 'branch') {
// branch->?
if (parentNode) {
stack.push(parentNode);
}
if (branchNode.type === 'branch') {
// create an extention node
// branch->extention->branch
// @ts-ignore FIXME, we need to properly check the full file
stack.push(nodeFactory.fromExtention([branchKey], null));
key.push(branchKey);
} else {
// branch key is an extention or a leaf
// branch->(leaf or extention)
branchNodeKey.unshift(branchKey);
branchNode.key = branchNodeKey;
// hackery. This is equvilant to array.concat except we need keep the
// rerfance to the `key` that was passed in.
branchNodeKey.unshift(0);
branchNodeKey.unshift(key.length);
key.splice.apply(key, branchNodeKey);
}
stack.push(branchNode);
} else {
// parent is a extention
let parentKey = parentNode.key;
if (branchNode.type === 'branch') {
// ext->branch
parentKey.push(branchKey);
key.push(branchKey);
parentNode.key = parentKey;
stack.push(parentNode);
} else {
// branch node is an leaf or extention and parent node is an exstention
// add two keys together
// dont push the parent node
branchNodeKey.unshift(branchKey);
key = key.concat(branchNodeKey);
parentKey = parentKey.concat(branchNodeKey);
branchNode.key = parentKey;
}
stack.push(branchNode);
}
return key;
};
// @ts-ignore FIXME, we need to properly check the full file
const opStack: any[] = [];
let lastNode = stack.pop();
let parentNode = stack.pop();
if (!Array.isArray(key)) {
// @ts-ignore FIXME, we need to properly check the full file
key = nibblesFromU8a(key);
}
if (!parentNode) {
// the root here has to be a leaf.
this.root = EMPTY_ROOT_U8A;
} else {
if (lastNode.type === 'branch') {
lastNode.value = null;
} else {
// the lastNode has to be a leaf if its not a branch. And a leaf's parent
// if it has one must be a branch.
const lastNodeKey = lastNode.key;
// @ts-ignore FIXME, we need to properly check the full file
key.splice(key.length - lastNodeKey.length);
// delete the value
this._formatNode(lastNode, false, true, opStack);
// @ts-ignore FIXME, we need to properly check the full file
parentNode.setValue(key.pop(), null);
lastNode = parentNode;
parentNode = stack.pop();
}
// nodes on the branch
// @ts-ignore FIXME, we need to properly check the full file
const branchNodes = [];
// count the number of nodes on the branch
// @ts-ignore FIXME, we need to properly check the full file
lastNode.raw.forEach(function (node, i) {
const val = lastNode.getValue(i);
// @ts-ignore FIXME, we need to properly check the full file
if (val) branchNodes.push([i, val]);
});
// if there is only one branch node left, collapse the branch node
if (branchNodes.length === 1) {
// add the one remaing branch node to node above it
// @ts-ignore FIXME, we need to properly check the full file
const branchNode = branchNodes[0][1];
// @ts-ignore FIXME, we need to properly check the full file
const branchNodeKey = branchNodes[0][0];
// look up node
const foundNode = await this._lookupNode(branchNode);
// @ts-ignore FIXME, we need to properly check the full file
key = processBranchNode(key, branchNodeKey, foundNode, parentNode, stack, opStack);
return this._saveStack(key, stack, opStack);
} else {
// simple removing a leaf and recaluclation the stack
if (parentNode) {
stack.push(parentNode);
}
stack.push(lastNode);
return this._saveStack(key, stack, opStack);
}
}
}
// Creates the initial node from an empty tree
_createInitialNode (key: Uint8Array, value: Uint8Array) {
const newNode = nodeFactory.fromLeaf(key, value);
this.root = newNode.hash();
return this._putNode(newNode);
}
// formats node to be saved by levelup.batch.
// returns either the hash that will be used key or the rawNode
// @ts-ignore FIXME, we need to properly check the full file
_formatNode (node: any, topLevel: any, remove: any, opStack: any) {
if (arguments.length === 3) {
opStack = remove;
remove = false;
}
const rlpNode = node.serialize();
if (rlpNode.length >= 32 || topLevel) {
const hashRoot = node.hash();
// FIXME Actually 2 things wrong here - this is on checkpoint, so one higher-level class...
// @ts-ignore FIXME, we need to properly check the full file
if (remove && this.isCheckpoint) {
opStack.push({
type: 'del',
key: hashRoot
});
} else {
opStack.push({
type: 'put',
key: hashRoot,
value: rlpNode
});
}
return hashRoot;
}
return node.raw;
}
/**
* The `data` event is given an `Object` hat has two properties; the `key` and the `value`. Both should be Buffers.
* @method createReadStream
* @return {stream.Readable} Returns a [stream](https://nodejs.org/dist/latest-v5.x/docs/api/stream.html#stream_class_stream_readable) of the contents of the `trie`
*/
createReadStream () {
return new ReadStream(this);
}
// creates a new trie backed by the same db
// and starting at the same root
copy () {
l.debug(() => ['Copying BaseTrie', typeof this.dbDown, u8aToHex(this.root)]);
return new BaseTrie(this.dbDown, this.root);
}
/**
* The given hash of operations (key additions or deletions) are executed on the DB
* @method batch
* @example
* const ops = [
* { type: 'del', key: 'father' }
* , { type: 'put', key: 'name', value: 'Yuri Irsenovich Kim' }
* , { type: 'put', key: 'dob', value: '16 February 1941' }
* , { type: 'put', key: 'spouse', value: 'Kim Young-sook' }
* , { type: 'put', key: 'occupation', value: 'Clown' }
* ]
* trie.batch(ops)
* @param {Array} ops
* @param {Function} cb
*/
// @ts-ignore FIXME, we need to properly check the full file
batch (ops: any[]) {
return Promise.all(
// @ts-ignore FIXME, we need to properly check the full file
ops.map((op) => {
if (op.type === 'put') {
return this.put(op.key, op.value);
} else if (op.type === 'del') {
return this.del(op.key);
}
})
);
}
/**
* Checks if a given root exists
* @method checkRoot
* @param {Buffer} root
* @param {Function} cb
*/
async checkRoot (root: Uint8Array): Promise<boolean> {
const value = await this._lookupNode(root);
return !!value;
}
}

View File

@@ -0,0 +1,161 @@
// Copyright 2015-2018 authors & contributors of https://github.com/ethereumjs/merkle-patricia-tree
// Copyright 2017-2018 @polkadot/trie-db authors & contributors
// This software may be modified and distributed under the terms
// of the MPL-2.0 license. See the LICENSE file for details.
// @ts-ignore FIXME, we need to properly check the full file
import levelws from 'level-ws';
// @ts-ignore FIXME, we need to properly check the full file
import levelup from 'levelup';
import memdown from 'memdown';
import assert from '@polkadot/util/assert';
import logger from '@polkadot/util/logger';
import u8aToHex from '@polkadot/util/u8a/toHex';
import BaseTrie from './BaseTrie';
import encoder from './encoder';
import ScratchReadStream from './streams/ScratchRead';
const l = logger('trie/checkpt');
function putRaw (key: Uint8Array, value: Uint8Array) {
return Promise.all(
// @ts-ignore FIXME, we need to properly check the full file
this.__putDBs.map((db) => {
return db.put(key, value);
})
);
}
export default class CheckpointTrie extends BaseTrie {
_checkpoints: Array<Uint8Array>;
_scratch: any; // FIXME
// @ts-ignore FIXME, we need to properly check the full file
__putDBs: any[]; // FIXME
// @ts-ignore FIXME, we need to properly check the full file
constructor (db, root: Uint8Array) {
super(db, root);
this._scratch = null;
this._checkpoints = [];
l.debug(() => 'Created CheckpointTrie');
}
get isCheckpoint () {
return !!this._checkpoints.length;
}
copy () {
l.debug(() => ['Copying CheckpointTrie', typeof this.dbDown, u8aToHex(this.root)]);
return new CheckpointTrie(this.dbDown, this.root);
}
async checkpoint () {
l.debug(() => 'Marking checkpoint');
const wasCheckpoint = this.isCheckpoint;
this._checkpoints.push(this.root);
if (!wasCheckpoint && this.isCheckpoint) {
this._enterCpMode();
}
}
commit () {
l.debug(() => 'Committing checkpoint');
return this.semaphore(async () => {
assert(this.isCheckpoint, 'trying to commit when not checkpointed');
this._checkpoints.pop();
if (this.isCheckpoint) {
return;
}
return this._exitCpMode(true);
});
}
revert () {
l.debug(() => 'Reverting checkpoint');
return this.semaphore(async () => {
if (!this.isCheckpoint) {
return;
}
this.root = this._checkpoints.pop() as Uint8Array;
if (this.isCheckpoint) {
return;
}
return this._exitCpMode(false);
});
}
// @ts-ignore FIXME, we need to properly check the full file
createScratchReadStream (scratch) {
const trie = this.copy();
scratch = scratch || this._scratch;
// only read from the scratch
trie._getDBs = [scratch];
trie._scratch = scratch;
return new ScratchReadStream(trie);
}
_enterCpMode () {
l.debug(() => 'Entering checkpoint mode');
this._scratch = levelup(encoder(memdown()));
this._getDBs = [this._scratch].concat(this._getDBs);
this.__putDBs = this._putDBs;
this._putDBs = [this._scratch];
this._putRaw = this.putRaw;
this.putRaw = putRaw;
}
// @ts-ignore FIXME, we need to properly check the full file
_exitCpMode (commitState) {
l.debug(() => 'Exiting checkpoint mode');
const scratch = this._scratch;
this._scratch = null;
this._getDBs = this._getDBs.slice(1);
this._putDBs = this.__putDBs;
this.putRaw = this._putRaw;
if (!commitState) {
return;
}
return Promise.all(
this._putDBs.map((db) => {
return new Promise((resolve) => {
if (!db.createWriteStream) {
db = levelws(db);
}
this
// @ts-ignore FIXME, we need to properly check the full file
.createScratchReadStream(scratch)
// @ts-ignore FIXME, we need to properly check the full file
.pipe(
// @ts-ignore FIXME, we need to properly check the full file
db.createWriteStream(encoder.options)
)
.on('close', resolve);
});
})
);
}
}

View File

@@ -0,0 +1,170 @@
// Copyright 2015-2018 authors & contributors of https://github.com/ethereumjs/merkle-patricia-tree
// Copyright 2017-2018 @polkadot/trie-db authors & contributors
// This software may be modified and distributed under the terms
// of the MPL-2.0 license. See the LICENSE file for details.
import { DecodedRlp, Trie$Node$Type } from './types';
import isU8a from '@polkadot/util/is/u8a';
import u8aToHex from '@polkadot/util/u8a/toHex';
import keccakAsU8a from '@polkadot/util-crypto/keccak/asU8a';
import encodeRlp from '@polkadot/util-rlp/encode';
import nibblesFromU8a from './nibbles/fromU8a';
import nibblesToU8a from './nibbles/toU8a';
function addHexPrefix (key: Array<number>, isTerminator: boolean): Array<number> {
// odd
if (key.length % 2) {
key.unshift(1);
} else {
// even
key.unshift(0);
key.unshift(0);
}
if (isTerminator) {
key[0] += 2;
}
return key;
}
function removeHexPrefix (key: Uint8Array): Uint8Array {
return key[0] % 2
? key.slice(1)
: key.slice(2);
}
export default class TrieNode {
raw: DecodedRlp;
type: Trie$Node$Type;
constructor (type: Trie$Node$Type, raw: DecodedRlp) {
this.raw = raw;
this.type = type;
}
get value () {
return this.getValue();
}
set value (v) {
this.setValue(v);
}
get key () {
return this.getKey();
}
set key (k) {
// @ts-ignore FIXME, we need to properly check the full file
this.setKey(k);
}
setValue (key: number | Uint8Array, value?: Uint8Array) {
if (this.type !== 'branch') {
this.raw[1] = key as Uint8Array;
return;
}
if (arguments.length === 1) {
value = key as Uint8Array;
key = 16;
}
this.raw[key as number] = value as Uint8Array;
}
getValue (key?: number) {
if (this.type !== 'branch') {
return this.raw[1];
}
if (arguments.length === 0) {
key = 16;
}
// @ts-ignore FIXME, we need to properly check the full file
const val = this.raw[key];
if (val !== null && val !== undefined && val.length !== 0) {
return val;
}
}
setKey (key: Array<number> | Uint8Array) {
if (this.type !== 'branch') {
if (Array.isArray(key)) {
key = key.slice(0); // copy the key
} else {
key = nibblesFromU8a(key);
}
key = addHexPrefix(key, this.type === 'leaf');
this.raw[0] = nibblesToU8a(key);
}
}
getKey () {
if (this.type !== 'branch') {
return removeHexPrefix(
// @ts-ignore FIXME, we need to properly check the full file
nibblesFromU8a(this.raw[0])
);
}
}
serialize (): Uint8Array {
return encodeRlp(this.raw);
}
hash (): Uint8Array {
return keccakAsU8a(this.serialize());
}
toString (): string {
return this.raw.reduce((out, el, index) => {
if (index !== 0) {
out += ', ';
}
if (isU8a(el)) {
out += u8aToHex(el);
} else if (el) {
out += 'object';
} else {
out += 'empty';
}
return out;
}, `${this.type}: [`) + ']';
}
getChildren () {
const children = [];
switch (this.type) {
case 'leaf':
// no children
break;
case 'extention':
// one child
children.push([this.key, this.getValue()]);
break;
case 'branch':
for (let index = 0, end = 16; index < end; index++) {
const value = this.getValue(index);
if (value) {
children.push([
[index], value
]);
}
}
break;
}
return children;
}
}

View File

@@ -0,0 +1,13 @@
// Copyright 2017-2018 @polkadot/trie-db authors & contributors
// This software may be modified and distributed under the terms
// of the MPL-2.0 license. See the LICENSE file for details.
import trieRoot from '@polkadot/trie-hash/root';
const EMPTY_ROOT_U8A = trieRoot([]);
const EMPTY_ROOT_STR = EMPTY_ROOT_U8A.toString();
export {
EMPTY_ROOT_U8A,
EMPTY_ROOT_STR
};

Some files were not shown because too many files have changed in this diff Show More