Pull in observable API from UI (#175)

* Pull in observable api...

* Progress changing stuff...

* votingBalance

* Update resul types

* Expose toBn on Moment

* Rework... WIP

* ... More type cleanups

* Linting passes

* BN helpers for UInt

* Update api-observable

* Add api-observable package.json

* Allow Struct/Tuple to create from hex string

* Future-proof Length with bitLength (u64/u128 compant encoding PR out)

* Make Compact number encoding shareable

* Split Api into functional sections

* Cleanup types

* Additional per-use comments

* Remove params/primitives from README

* api-format  -> api-codec

* Whitespace.
This commit is contained in:
Jaco Greeff
2018-10-01 11:22:15 +02:00
committed by GitHub
parent 465d986de1
commit 782bb8063c
24 changed files with 1010 additions and 68 deletions
File diff suppressed because one or more lines are too long
+4 -2
View File
@@ -4,6 +4,8 @@
import { AnyNumber } from './types';
import toU8a from '@polkadot/util/u8a/toU8a';
import Vector from './codec/Vector';
import Base from './codec/Base';
import Enum from './codec/Enum';
@@ -285,9 +287,9 @@ export default class RuntimeMetadata extends Struct {
// We receive this as an Array<number> in the JSON output from the Node. Convert
// to u8a and use the fromU8a to do the actual parsing
fromJSON (input: Array<number>): RuntimeMetadata {
fromJSON (input: Uint8Array | string | Array<number>): RuntimeMetadata {
return this.fromU8a(
Uint8Array.from(input)
toU8a(input)
) as RuntimeMetadata;
}
+9 -1
View File
@@ -17,7 +17,7 @@ const BITLENGTH = 64;
// per-second. For any encoding/decoding the 1000 multiplier would be applied to
// get it in line with JavaScript formats
export default class Moment extends Base<Date> {
constructor (value: Uint8Array | Moment | Date | number = 0) {
constructor (value: Uint8Array | Moment | Date | BN | number = 0) {
super(
value instanceof Date
? new Date(Math.ceil(value.getTime() / 1000) * 1000)
@@ -55,6 +55,10 @@ export default class Moment extends Base<Date> {
return this;
}
getTime (): number {
return this.raw.getTime();
}
toJSON (): any {
return this.toNumber();
}
@@ -67,6 +71,10 @@ export default class Moment extends Base<Date> {
return this.raw.toISOString();
}
toBn (): BN {
return new BN(this.toNumber());
}
toNumber (): number {
return Math.ceil(this.raw.getTime() / 1000);
}
+10
View File
@@ -0,0 +1,10 @@
// Copyright 2017-2018 @polkadot/api-codec authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import Extrinsic from './Extrinsic';
// The Nonce or number of transactiosn sent by a specific account. Generally used
// with extrinsics to determine the order of execution.
export default class Proposal extends Extrinsic {
}
+64
View File
@@ -0,0 +1,64 @@
// Copyright 2017-2018 @polkadot/api-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 bnToU8a from '@polkadot/util/bn/toU8a';
import u8aConcat from '@polkadot/util/u8a/concat';
import u8aToBn from '@polkadot/util/u8a/toBn';
const MAX_U8 = new BN(2).pow(new BN(8 - 2)).subn(1);
const MAX_U16 = new BN(2).pow(new BN(16 - 2)).subn(1);
const MAX_U32 = new BN(2).pow(new BN(32 - 2)).subn(1);
type BitLength = 32;
// A new compact length-encoding algorithm. It performs the same function as Length, however
// differs in that it uses a variable number of bytes to do the actual encoding. From the Rust
// implementation for compact encoding
//
// 0b00 00 00 00 / 00 00 00 00 / 00 00 00 00 / 00 00 00 00
// (0 ... 2**6 - 1) (u8)
// xx xx xx 00
// (2**6 ... 2**14 - 1) (u8, u16) low LH high
// yL yL yL 01 / yH yH yH yL
// (2**14 ... 2**30 - 1) (u16, u32) low LMMH high
// zL zL zL 10 / zM zM zM zL / zM zM zM zM / zH zH zH zM
// (2**30 ... 2**536 - 1) (u32, u64, u128, U256, U512, U520) straight LE-encoded
// nn nn nn 11 [ / zz zz zz zz ]{4 + n}
//
// Note: we use *LOW BITS* of the LSB in LE encoding to encode the 2 bit key.
export default class Compact {
static decode (input: Uint8Array, bitLength: BitLength): BN {
const flag = input[0] & 0b11;
if (flag === 0b00) {
return new BN(input[0]).shrn(2);
} else if (flag === 0b01) {
return u8aToBn(input.slice(0, 2), true).shrn(2);
} else if (flag === 0b10) {
return u8aToBn(input.slice(0, 4), true).shrn(2);
}
const byteLength = bitLength / 8;
return u8aToBn(input.subarray(1, 1 + byteLength), true);
}
static encode (length: BN, bitLength: BitLength): Uint8Array {
if (length.lte(MAX_U8)) {
return new Uint8Array([length.toNumber() << 2]);
} else if (length.lte(MAX_U16)) {
return bnToU8a(length.shln(2).addn(0b01), 16, true);
} else if (length.lte(MAX_U32)) {
return bnToU8a(length.shln(2).addn(0b10), 32, true);
}
return u8aConcat(
new Uint8Array([
0b11
]),
bnToU8a(length, bitLength, true)
);
}
}
+10 -54
View File
@@ -6,33 +6,16 @@ import { AnyNumber } from '../types';
import BN from 'bn.js';
import bnToBn from '@polkadot/util/bn/toBn';
import bnToU8a from '@polkadot/util/bn/toU8a';
import u8aConcat from '@polkadot/util/u8a/concat';
import u8aToBn from '@polkadot/util/u8a/toBn';
import u8aToHex from '@polkadot/util/u8a/toHex';
import Base from './Base';
import Compact from './Compact';
import UInt from './UInt';
const MAX_U8 = new BN(2).pow(new BN(8 - 2)).subn(1);
const MAX_U16 = new BN(2).pow(new BN(16 - 2)).subn(1);
const MAX_U32 = new BN(2).pow(new BN(32 - 2)).subn(1);
type BitLength = 32;
// A new compact length-encoding algorithm. It performs the same function as Length, however
// differs in that it uses a variable number of bytes to do the actual encoding. From the Rust
// implementation for compact encoding
//
// 0b00 00 00 00 / 00 00 00 00 / 00 00 00 00 / 00 00 00 00
// (0 ... 2**6 - 1) (u8)
// xx xx xx 00
// (2**6 ... 2**14 - 1) (u8, u16) low LH high
// yL yL yL 01 / yH yH yH yL
// (2**14 ... 2**30 - 1) (u16, u32) low LMMH high
// zL zL zL 10 / zM zM zM zL / zM zM zM zM / zH zH zH zM
// (2**30 ... 2**536 - 1) (u32, u64, u128, U256, U512, U520) straight LE-encoded
// nn nn nn 11 [ / zz zz zz zz ]{4 + n}
//
// Note: we use *LOW BITS* of the LSB in LE encoding to encode the 2 bit key.
// A Length-prefix that can be added to any variable length stream of bytes, e.g. String,
// Vectors and Bytes
//
// FIXME Not crazy about the use of Length. If we look at Vector, Bytes & String,
// the implementations are basically the same. Vector is slightly different since
@@ -40,41 +23,14 @@ const MAX_U32 = new BN(2).pow(new BN(32 - 2)).subn(1);
// code and a more generic implementation around the use of Length. Looking at
// Array or Struct, the same type of wrapper would be useful here.
export default class Length extends Base<BN> {
constructor (value: AnyNumber = new BN(0)) {
private _bitLength: BitLength;
constructor (value: AnyNumber = new BN(0), bitLength: BitLength = 32) {
super(
UInt.decode(value)
);
}
static decode (input: Uint8Array): BN {
const flag = input[0] & 0b11;
if (flag === 0b00) {
return new BN(input[0]).shrn(2);
} else if (flag === 0b01) {
return u8aToBn(input.slice(0, 2), true).shrn(2);
} else if (flag === 0b10) {
return u8aToBn(input.slice(0, 4), true).shrn(2);
}
return u8aToBn(input.subarray(1, 5), true);
}
static encode (length: BN): Uint8Array {
if (length.lte(MAX_U8)) {
return new Uint8Array([length.toNumber() << 2]);
} else if (length.lte(MAX_U16)) {
return bnToU8a(length.shln(2).addn(0b01), 16, true);
} else if (length.lte(MAX_U32)) {
return bnToU8a(length.shln(2).addn(0b10), 32, true);
}
return u8aConcat(
new Uint8Array([
0b11
]),
bnToU8a(length, 32, true)
);
this._bitLength = bitLength;
}
byteLength (): number {
@@ -82,7 +38,7 @@ export default class Length extends Base<BN> {
}
fromU8a (input: Uint8Array): Length {
this.raw = Length.decode(input);
this.raw = Compact.decode(input, this._bitLength);
return this;
}
@@ -98,7 +54,7 @@ export default class Length extends Base<BN> {
toU8a (isBare?: boolean): Uint8Array {
return isBare
? new Uint8Array()
: Length.encode(this.raw);
: Compact.encode(this.raw, this._bitLength);
}
setValue (value: BN | number): void {
+10
View File
@@ -2,6 +2,8 @@
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import hexToU8a from '@polkadot/util/hex/toU8a';
import isHex from '@polkadot/util/is/hex';
import u8aConcat from '@polkadot/util/u8a/concat';
import Base, { l } from './Base';
@@ -82,6 +84,10 @@ export default class Struct <
}
fromJSON (input: any): Struct<S, T, V, E> {
if (isHex(input)) {
return this.fromU8a(hexToU8a(input));
}
Object.keys(this.raw).forEach((key) => {
const jsonKey = this._jsonMap.get(key as any) || key;
@@ -102,6 +108,10 @@ export default class Struct <
return this;
}
get (index: number): Base {
return this.values()[index];
}
toJSON (): any {
return Object.keys(this.raw).reduce((json, key) => {
const jsonKey = this._jsonMap.get(key as any) || key;
+7
View File
@@ -2,6 +2,9 @@
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
import hexToU8a from '@polkadot/util/hex/toU8a';
import isHex from '@polkadot/util/is/hex';
import Base from './Base';
import Struct from './Struct';
@@ -29,6 +32,10 @@ export default class Tuple <
}
fromJSON (input: any): Tuple<S, T, V> {
if (isHex(input)) {
return this.fromU8a(hexToU8a(input));
}
Object.values(this.raw).forEach((entry, index) => {
entry.fromJSON(input[index]);
});
+50
View File
@@ -89,4 +89,54 @@ export default class UInt extends Base<BN> {
toNumber (): number {
return this.raw.toNumber();
}
// helpers from BN, this would be great as a "don't do this", i.e. extending properly
// from BN. Underlying these will always return BN (unless it is compare checks)
add (other: UInt | BN | number): BN {
return other instanceof UInt
? this.raw.add(other.raw)
: this.raw.add(bnToBn(other));
}
div (other: UInt | BN | number): BN {
return other instanceof UInt
? this.raw.div(other.raw)
: this.raw.div(bnToBn(other));
}
lt (test: UInt | BN | number): boolean {
return test instanceof UInt
? this.raw.lt(test.raw)
: this.raw.lt(bnToBn(test));
}
lte (test: UInt | BN | number): boolean {
return test instanceof UInt
? this.raw.lte(test.raw)
: this.raw.lte(bnToBn(test));
}
gt (test: UInt | BN | number): boolean {
return test instanceof UInt
? this.raw.gt(test.raw)
: this.raw.gt(bnToBn(test));
}
gte (test: UInt | BN | number): boolean {
return test instanceof UInt
? this.raw.gte(test.raw)
: this.raw.gte(bnToBn(test));
}
mul (other: UInt | BN | number): BN {
return other instanceof UInt
? this.raw.mul(other.raw)
: this.raw.mul(bnToBn(other));
}
sub (other: UInt | BN | number): BN {
return other instanceof UInt
? this.raw.sub(other.raw)
: this.raw.sub(bnToBn(other));
}
}
+1
View File
@@ -40,6 +40,7 @@ export { default as PendingExtrinsics } from './PendingExtrinsics';
export { default as Permill } from './Permill';
export { default as Perbill } from './Perbill';
export { default as PropIndex } from './PropIndex';
export { default as Proposal } from './Proposal';
export { default as ProposalIndex } from './ProposalIndex';
export { default as RawAddress } from './RawAddress';
export { default as ReferendumIndex } from './ReferendumIndex';