Raw decoding for extrinsics (#214)

This commit is contained in:
Jaco Greeff
2018-10-05 15:44:30 +02:00
committed by GitHub
parent d01c697687
commit 5b5caa1e80
6 changed files with 110 additions and 33 deletions
@@ -22,11 +22,7 @@ export default function createDescriptor (
const callIndex = new Uint8Array([index, meta.id.toNumber()]);
let extrinsicFn: any;
// If the extrinsic function has an argument of type `Origin`, we ignore it
// FIXME should be `arg.type !== Origin`, but doesn't work...
const expectedArgs = meta.arguments.filter((arg) =>
arg.type.toString() !== 'Origin'
);
const expectedArgs = Method.filterOrigin(meta);
extrinsicFn = (...args: any[]): Extrinsic => {
if (expectedArgs.length.valueOf() !== args.length) {
+15
View File
@@ -0,0 +1,15 @@
// Copyright 2017-2018 @polkadot/types 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';
describe('Extrinsic', () => {
it('decodes a non-signed properly via fromJSON', () => {
const extrinsic = new Extrinsic().fromJSON('0x010200ea51b75b00000000');
expect(extrinsic.isSigned).toEqual(false);
expect(extrinsic.callIndex).toEqual(new Uint8Array([2, 0]));
expect(extrinsic.data).toEqual(new Uint8Array([234, 81, 183, 91, 0, 0, 0, 0]));
});
});
+21 -6
View File
@@ -6,6 +6,7 @@ import { KeyringPair } from '@polkadot/util-keyring/types';
import { AnyNumber, AnyU8a } from './types';
import blake2Asu8a from '@polkadot/util-crypto/blake2/asU8a';
import hexToU8a from '@polkadot/util/hex/toU8a';
import u8aConcat from '@polkadot/util/u8a/concat';
import u8aToHex from '@polkadot/util/u8a/toHex';
@@ -42,8 +43,13 @@ export default class Extrinsic extends Struct {
}, value);
}
get method (): Method {
return this.raw.method as Method;
// the actual [sectionIndex, methodIndex] as used
get callIndex (): Uint8Array {
return this.method.callIndex;
}
get data (): Uint8Array {
return this.method.data;
}
// convernience, encodes the extrinsic and returns the actual hash
@@ -53,6 +59,10 @@ export default class Extrinsic extends Struct {
);
}
get isSigned (): boolean {
return this.signature.isSigned;
}
get length (): number {
return this.toU8a(true).length;
}
@@ -61,9 +71,8 @@ export default class Extrinsic extends Struct {
return this.method.meta;
}
// the actual [sectionIndex, methodIndex] as used
get callIndex (): Uint8Array {
return this.method.callIndex;
get method (): Method {
return this.raw.method as Method;
}
get signature (): ExtrinsicSignature {
@@ -76,6 +85,12 @@ export default class Extrinsic extends Struct {
return length + Compact.encode(length).length;
}
fromJSON (input: any): Extrinsic {
super.fromU8a(hexToU8a(input));
return this;
}
fromU8a (input: Uint8Array): Extrinsic {
const [offset, length] = Compact.decode(input);
@@ -102,7 +117,7 @@ export default class Extrinsic extends Struct {
}
toHex (): string {
return u8aToHex(this.toU8a());
return u8aToHex(this.toU8a(true));
}
toJSON (): any {
+9
View File
@@ -43,6 +43,15 @@ export default class ExtrinsicSignature extends Struct {
}, value);
}
byteLength (): number {
// version has 1 byte, signature takes the rest
return 1 + (
this.isSigned
? super.byteLength()
: 0
);
}
get isSigned (): boolean {
return this.signature.length !== 0;
}
+54 -16
View File
@@ -9,7 +9,7 @@ import u8aConcat from '@polkadot/util/u8a/concat';
import createType from './codec/createType';
import Base from './codec/Base';
import MethodIndex from './MethodIndex';
import { FunctionMetadata } from './Metadata';
import { FunctionMetadata, FunctionArgumentMetadata } from './Metadata';
/**
* Extrinsic function descriptor, as defined in
@@ -17,6 +17,7 @@ import { FunctionMetadata } from './Metadata';
*/
export default class Method extends MethodIndex {
protected _args: Array<Base>;
protected _data: Uint8Array;
protected _meta: FunctionMetadata;
constructor (index: Method | AnyU8a, meta: FunctionMetadata, args: Array<any>) {
@@ -29,35 +30,72 @@ export default class Method extends MethodIndex {
this._args = args;
this._meta = meta;
}
this._data = Method.encode(this._meta, this._args);
}
get args () {
static decode (meta: FunctionMetadata, data: Uint8Array): Array<Base> {
let offset = 0;
return Method.filterOrigin(meta).map(({ type }) => {
const base = createType(type).fromU8a(data.subarray(offset));
offset += base.byteLength();
return base;
});
}
static encode (meta: FunctionMetadata, args: Array<any>): Uint8Array {
const encoded = Method.filterOrigin(meta).map(({ type }, index) =>
createType(type, args[index]).toU8a()
);
return u8aConcat(...encoded);
}
// If the extrinsic function has an argument of type `Origin`, we ignore it
static filterOrigin (meta?: FunctionMetadata): Array<FunctionArgumentMetadata> {
// FIXME should be `arg.type !== Origin`, but doesn't work...
return meta
? meta.arguments.filter(({ type }) =>
type.toString() !== 'Origin'
)
: [];
}
byteLength (): number {
return super.byteLength() + this.data.length;
}
get args (): Array<any> {
return this._args;
}
get index () {
get data (): Uint8Array {
return this._data;
}
get index (): Uint8Array {
return this.raw;
}
get meta () {
get meta (): FunctionMetadata {
return this._meta;
}
toU8a (isBare?: boolean): Uint8Array {
// FIXME Even when decoded, we will need access to the meta
const args = this.meta
? this.meta.arguments
.filter((arg) =>
arg.type.toString() !== 'Origin'
)
.map((argument, index) =>
createType(argument.type, this.args[index]).toU8a(isBare)
)
: [];
fromU8a (input: Uint8Array): Method {
super.fromU8a(input);
this._data = input.subarray(super.byteLength());
return this;
}
toU8a (isBare?: boolean): Uint8Array {
return u8aConcat(
super.toU8a(isBare),
...args
this.data
);
}
}
+10 -6
View File
@@ -18,27 +18,31 @@ export default class U8aFixed extends U8a {
this._bitLength = bitLength;
this._trimLength();
this._trim();
}
private _trimLength (): void {
this.raw = this.raw.subarray(0, this.byteLength());
private _trimLength (): number {
return this._bitLength / 8;
}
private _trim (): void {
this.raw = this.raw.subarray(0, this._trimLength());
}
byteLength (): number {
return this._bitLength / 8;
return this._trimLength();
}
fromJSON (input: any): U8aFixed {
super.fromJSON(input);
this._trimLength();
this._trim();
return this;
}
fromU8a (input: Uint8Array): U8aFixed {
super.fromU8a(input.subarray(0, this.byteLength()));
super.fromU8a(input.subarray(0, this._trimLength()));
return this;
}