feat: Vote interface as U8a (#1061)

* feat: Vote interface as Bytes

* fix: decode v1 values

* fix: decode v2 vote

* duplicate decode struct

* use struct

* fix: encodes as Bytes

* as u8a

* fix: encode as u8a

* fix: encode as u8a

* fix paddig bug

* decode from bits

* fix lint

* fix grumbles

* fix lint

* fix grumbles, remove toNumber

* fix grumbles

* remov only

* Update CHANGELOG.md

* Update CHANGELOG.md
This commit is contained in:
YJ
2019-07-04 15:46:36 +02:00
committed by Amaury Martiny
parent 36b60aaf7a
commit 8c4320c0f3
4 changed files with 145 additions and 19 deletions
+2
View File
@@ -6,6 +6,8 @@
- **Breaking change** The api now uses the module name instead of the prefix to generate the storage methods. The methods of the grandpa module changed from `api.query.grandpaFinality` to `api.query.grandpa`.
- Update with latest substrate 2.x types
- **Breaking Change** StorageFunction has been renamed to StorageEntry.
- **Breaking Change** Vote interface extends U8a instead of I8. Vote properties can be accessed via the `isAye`, `isNay`, and `conviction` getters.
Votes can still be constructed as before with a raw JS boolean, a SCALE encoded Boolean, an i8 number, or a JS object with properties `aye` and `conviction` defined.
- Support latest substrate 2.x v6 metadata with module constants.
# 0.81.1
+1 -1
View File
@@ -8,7 +8,7 @@ import { Constructor } from './types';
import * as Classes from './index.types';
const Types = Classes as { [index: string]: Constructor };
const UNCONSTRUCTABLE = ['origin', 'usize'];
const UNCONSTRUCTABLE = ['origin', 'usize', 'vote'];
describe('types', () => {
describe('default creation', () => {
+93 -7
View File
@@ -2,30 +2,116 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import Boolean from '../primitive/Bool';
import Conviction from './Conviction';
import Vote from './Vote';
describe('Vote', () => {
it('constructs via boolean true', () => {
expect(new Vote(true).toNumber()).toEqual(-1);
expect(new Vote(true).toU8a()).toEqual(new Uint8Array([128]));
expect(new Vote(true).isAye).toBe(true);
expect(new Vote(true).isNay).toBe(false);
});
it('constructs via boolean false', () => {
expect(new Vote(false).toNumber()).toEqual(0);
expect(new Vote(false).toU8a()).toEqual(new Uint8Array([0]));
expect(new Vote(false).isNay).toBe(true);
expect(new Vote(false).isAye).toBe(false);
});
it('has isYay for positive', () => {
expect(new Vote(new Boolean(true)).isAye).toBe(true);
});
it('has isYay for negative', () => {
it('has isNay for negative', () => {
expect(new Vote(new Boolean(false)).isNay).toBe(true);
});
it('is positive for negative numbers', () => {
expect(new Vote(-999).isAye).toBe(true);
it('is Aye for negative numbers', () => {
expect(new Vote(-128).isAye).toBe(true);
});
it('is negative for positive numbers', () => {
expect(new Vote(999).isNay).toBe(true);
it('is Nay for positive numbers', () => {
expect(new Vote(127).isNay).toBe(true);
});
it('constructs V2 Vote with raw boolean', () => {
expect(
new Vote({
aye: true,
conviction: new Conviction('Locked1x')
})
.toU8a()
)
.toEqual(new Uint8Array([0b10000001]));
});
it('constructs with V2 Vote aye is false, conviction is None', () => {
expect(
new Vote({
aye: new Boolean(false),
conviction: new Conviction('None')
})
.toU8a()
)
.toEqual(new Uint8Array([0b00000000]));
});
it('constructs with Vote aye is true, conviction is Locked4x', () => {
expect(
new Vote({
aye: new Boolean(true),
conviction: new Conviction('Locked4x')
})
.toU8a()
)
.toEqual(new Uint8Array([0b10000100]));
});
it('Conviction getter works', () => {
expect(
new Vote({
aye: new Boolean(true),
conviction: new Conviction('Locked2x')
}).conviction.toString()
)
.toEqual('Locked2x');
});
it('Conviction getter works with raw boolean and string conviction', () => {
expect(
new Vote({
aye: true,
conviction: 'Locked2x'
}).conviction.toString()
)
.toEqual('Locked2x');
});
it('Conviction getter works with raw boolean and conviction index', () => {
expect(
new Vote({
aye: true,
conviction: 2
}).conviction.toString()
)
.toEqual('Locked2x');
});
it('isAye getter works', () => {
expect(
new Vote({
aye: new Boolean(true),
conviction: new Conviction('None')
}).isAye)
.toEqual(true);
});
it('isNay getter works', () => {
expect(
new Vote({
aye: new Boolean(true),
conviction: new Conviction('None')
}).isNay)
.toEqual(false);
});
});
+49 -11
View File
@@ -2,39 +2,77 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { isBoolean } from '@polkadot/util';
import { isBoolean, isNumber, isObject, isU8a, isUndefined } from '@polkadot/util';
import I8 from '../primitive/I8';
import Conviction from './Conviction';
import U8a from '../codec/U8a';
import Bool from '../primitive/Bool';
/**
* @name Vote
* @description
* A number of lock periods, plus a vote, one way or the other.
*/
export default class Vote extends I8 {
export default class Vote extends U8a {
private _aye: Bool;
private _conviction: Conviction; // for V1, default to None
constructor (value?: any) {
super(Vote.decodeVote(value));
// decoded is just 1 byte
// Aye: Most Significant Bit
// Conviction: 0000 - 0101
const decoded = Vote.decodeVote(value);
super(decoded);
const msb = decoded[0] >> 7;
const conviction = decoded[0] & 0b01111111;
this._aye = new Bool(msb);
this._conviction = new Conviction(conviction);
}
private static decodeVote (value?: any): any {
private static decodeVote (value?: any): Uint8Array {
if (isBoolean(value)) {
return value ? -1 : 0;
} else if (value instanceof Boolean) {
return value
? new Uint8Array([0b10000000])
: new Uint8Array([0b0]);
} else if (value instanceof Bool) {
return Vote.decodeVote(value.valueOf());
} else if (isNumber(value)) {
return value < 0
? new Uint8Array([0b10000000])
: new Uint8Array([0b0]);
} else if (isObject(value) && !isUndefined(value.aye) && !isUndefined(value.conviction)) {
const aye = new Bool(value.aye);
const convictionIndex = new Conviction(value.conviction).index;
const result = convictionIndex | (aye.eq(true) ? 0b1 << 7 : 0b0);
return new Uint8Array([result]);
} else if (isU8a(value) && value.length > 0) {
return value;
}
return value;
throw new Error(`Unable to convert input ${value} to Vote`);
}
/**
* @description true is the wrapped value is a positive vote
* @description returns a V2 conviction
*/
get conviction (): Conviction {
return this._conviction;
}
/**
* @description true if the wrapped value is a positive vote
*/
get isAye (): boolean {
return this.ltn(0);
return this._aye.eq(true);
}
/**
* @description true is the wrapped value is a negative vote
* @description true if the wrapped value is a negative vote
*/
get isNay (): boolean {
return !this.isAye;