UNPKG

keystore_wdc

Version:

``` npm i keystore_wdc; const KeyStore = require('keystore_wdc'); const ks = new KeyStore(); ``` #### 生成keystore ``` async function create(){ const keystore = await ks.Create("your password"); } ``` * 返回keystore,密码格式不正确返回-1。

395 lines (341 loc) 14.1 kB
import { U256, Address, Context, ABI_DATA_TYPE, log } from '.' import { Util } from './util'; const OFFSET_SHORT_LIST: u8 = 0xc0; // @ts-ignore @external("env", "_rlp") // type, ptr0 ptr0Len dst, put ? declare function _rlp(type: u64, arg0: u64, arg1: u64, arg2: u64, arg3: u64): u64; enum Type { ENCODE_U64, ENCODE_BYTES, DECODE_BYTES, RLP_LIST_SET, // add rlp list to global env RLP_LIST_CLEAR, // clear rlp list RLP_LIST_LEN, RLP_LIST_GET, RLP_LIST_PUSH, RLP_LIST_BUILD // build } export class RLP { static emptyList(): ArrayBuffer { const ret = new Uint8Array(1); ret[0] = OFFSET_SHORT_LIST; return ret.buffer; } // supported types: u64 i64 f64 bool U256 string ArrayBuffer Address static encode<T>(t: T): ArrayBuffer { if (isFunction<T>()) { assert(false, 'rlp encode failed, invalid type ' + nameof<T>()); return new ArrayBuffer(0); } if (isFloat<T>()) { return RLP.encodeU64(reinterpret<u64>(t)); } if (isInteger<T>()) { return RLP.encodeU64(u64(t)); } if (isString<T>()) { return RLP.encodeString(changetype<string>(t)); } if (!isManaged<T>()) { const name = nameof<T>(); const abi = RLPList.fromEncoded(Context.self().abi()); for (let i: u32 = 0; i < abi.length(); i++) { const li = abi.getList(i); if (li.getItem(0).string() == name && li.getItem(1).u64() == 1) { const outputs = li.getList(3); const data = new Array<ArrayBuffer>(); let offset = 0; let ptr = changetype<usize>(t) for (let j: u32 = 0; j < outputs.length(); j++) { switch (outputs.getItem(j).u32()) { case ABI_DATA_TYPE.BOOL: { assert(false, 'bool is not stable in unmanaged runtime'); } case ABI_DATA_TYPE.F64: case ABI_DATA_TYPE.I64: case ABI_DATA_TYPE.U64: { assert(false, 'native number is not stable in unmanaged runtime'); break; } case ABI_DATA_TYPE.BYTES: { data.push(RLP.encodeBytes(load<ArrayBuffer>(ptr + offset))); offset += 4; break; } case ABI_DATA_TYPE.STRING: { data.push(RLP.encodeString(load<string>(ptr + offset))); offset += 4; break; } case ABI_DATA_TYPE.U256: { data.push(RLP.encodeU256(load<U256>(ptr + offset))); offset += 4; break; } case ABI_DATA_TYPE.ADDRESS: { data.push(RLP.encode<Address>(load<Address>(ptr + offset))); offset += 4; break; } default: assert(false, ' invalid abi type ' + outputs.getItem(j).u32().toString()); } } const buf = RLP.encodeElements(data); return buf; } } assert(false, 'rlp encode ' + name + ' failed, abi not found'); return new ArrayBuffer(0); } switch (idof<T>()) { case idof<ArrayBuffer>(): return RLP.encodeBytes(changetype<ArrayBuffer>(t)); case idof<U256>(): return RLP.encodeBytes(changetype<U256>(t).buf); case idof<Address>(): return RLP.encodeBytes(changetype<Address>(t).buf) } assert(false, 'rlp encode failed, invalid type ' + nameof<T>()); return new ArrayBuffer(0); } // supported types: u64 i64 f64 bool U256 string ArrayBuffer Address static decode<T>(buf: ArrayBuffer): T { if (isFunction<T>()) { assert(false, 'rlp encode failed, invalid type ' + nameof<T>()); return changetype<T>(null); } if (isFloat<T>()) { return reinterpret<f64>(RLP.decodeU64(buf)); } if (isBoolean<T>()) { return RLP.decodeU64(buf) != 0; } if (isInteger<T>()) { const ret = RLP.decodeU64(buf); if (sizeof<T>() == 8) { return ret; } if (sizeof<T>() == 4) { assert(ret <= u32.MAX_VALUE, 'invalid u32: overflow'); return u32(ret); } if (sizeof<T>() == 2) { assert(ret <= u16.MAX_VALUE, 'invalid u32: overflow'); return u16(ret); } if (sizeof<T>() == 1) { assert(ret <= u8.MAX_VALUE, 'invalid u32: overflow'); return u8(ret); } } if (isString<T>()) { return changetype<T>(RLP.decodeString(buf)); } if (!isManaged<T>()) { const name = nameof<T>(); const p = __alloc(offsetof<T>(), 0); __retain(p); const abi = RLPList.fromEncoded(Context.self().abi()); const rlp = RLPList.fromEncoded(buf); for (let i: u32 = 0; i < abi.length(); i++) { const li = abi.getList(i); if (li.getItem(0).string() == name && li.getItem(1).u64() == 1) { const outputs = li.getList(3); let offset = 0; for (let j: u32 = 0; j < outputs.length(); j++) { switch (outputs.getItem(j).u32()) { case ABI_DATA_TYPE.BOOL: { assert(false, 'bool is not stable in runtime, please convert to string'); break; } case ABI_DATA_TYPE.F64: case ABI_DATA_TYPE.I64: case ABI_DATA_TYPE.U64: { assert(false, 'native number is not stable in unmanaged runtime, please convert to string'); break; } case ABI_DATA_TYPE.BYTES: { store<ArrayBuffer>(p + offset, rlp.getItem(j).bytes()); offset += 4; break; } case ABI_DATA_TYPE.STRING: { store<String>(p + offset, rlp.getItem(j).string()); offset += 4; break; } case ABI_DATA_TYPE.U256: { store<U256>(p + offset, rlp.getItem(j).u256()); offset += 4; break; } case ABI_DATA_TYPE.ADDRESS: { store<Address>(p + offset, rlp.getItem(j).address()); offset += 4; break; } default: assert(false, ' invalid abi type ' + outputs.getItem(j).u32().toString()); } } return changetype<T>(p); } } assert(false, 'rlp decode failed, invalid type ' + nameof<T>()); return changetype<T>(0); } switch (idof<T>()) { case idof<ArrayBuffer>(): return changetype<T>(RLP.decodeBytes(buf)); case idof<U256>(): return changetype<T>(new U256(RLP.decodeBytes(buf))); case idof<Address>(): return changetype<T>(new Address(RLP.decodeBytes(buf))); } assert(false, 'rlp encode failed, invalid type ' + nameof<T>()); return changetype<T>(0); } // if the byte array was encoded from a list static isList(encoded: ArrayBuffer): bool { const arr = Uint8Array.wrap(encoded); return arr[0] >= OFFSET_SHORT_LIST; } static encodeU64(u: u64): ArrayBuffer { const len = _rlp(Type.ENCODE_U64, u, 0, 0, 0); const buf = new ArrayBuffer(u32(len)); _rlp(Type.ENCODE_U64, u, 0, changetype<usize>(buf), 1); return buf; } static encodeU256(u: U256): ArrayBuffer { return encodeBytes(u.buf); } static decodeU64(u: ArrayBuffer): u64 { return RLPItem.fromEncoded(u).u64(); } static decodeU256(u: ArrayBuffer): U256 { return RLPItem.fromEncoded(u).u256(); } static decodeString(encoded: ArrayBuffer): string { return RLPItem.fromEncoded(encoded).string(); } // encode a string static encodeString(s: string): ArrayBuffer { return encodeBytes(String.UTF8.encode(s)); } // encode string list static encodeStringArray(s: Array<string>): ArrayBuffer { const elements: Array<ArrayBuffer> = new Array<ArrayBuffer>(s.length); for (let i = 0; i < elements.length; i++) { elements[i] = this.encodeString(s[i]); } return encodeElements(elements); } // encode a byte array static encodeBytes(bytes: ArrayBuffer): ArrayBuffer { return encodeBytes(bytes); } static encodeElements(elements: Array<ArrayBuffer>): ArrayBuffer { return encodeElements(elements); } static decodeBytes(data: ArrayBuffer): ArrayBuffer { const len = _rlp(Type.DECODE_BYTES, changetype<usize>(data), data.byteLength, 0, 0); const buf = new ArrayBuffer(u32(len)); _rlp(Type.DECODE_BYTES, changetype<usize>(data), data.byteLength, changetype<usize>(buf), 1); return buf; } } export class RLPItem { // before encoded data private readonly data: ArrayBuffer; private constructor(data: ArrayBuffer) { this.data = data; } static fromEncoded(encoded: ArrayBuffer): RLPItem { const decoded = RLP.decodeBytes(encoded); return new RLPItem(decoded); } u8(): u8 { assert(this.u64() <= u8.MAX_VALUE, 'integer overflow'); return u8(this.u64()); } u16(): u16 { assert(this.u64() <= u16.MAX_VALUE, 'integer overflow'); return u16(this.u64()); } u32(): u32 { assert(this.u64() <= u32.MAX_VALUE, 'integer overflow'); return u32(this.u64()); } u64(): u64 { assert(this.data.byteLength <= 8, 'invalid u64: overflow'); return Util.bytesToU64(this.data); } u256(): U256 { return new U256(this.bytes()); } bytes(): ArrayBuffer { return this.data } string(): string { return String.UTF8.decode(this.data); } isNull(): bool { return this.data.byteLength == 0; } address(): Address { return new Address(this.bytes()); } } export class RLPList { static EMPTY: RLPList = new RLPList([], RLP.emptyList()); private constructor(readonly elements: Array<ArrayBuffer>, readonly encoded: ArrayBuffer) { } static fromEncoded(encoded: ArrayBuffer): RLPList { _rlp(Type.RLP_LIST_SET, changetype<usize>(encoded), encoded.byteLength, 0, 0); const len = u32(_rlp(Type.RLP_LIST_LEN, 0, 0, 0, 0)); const elements = new Array<ArrayBuffer>(len); for (let i: u32 = 0; i < len; i++) { const bufLen = _rlp(Type.RLP_LIST_GET, i, 0, 0, 0); const buf = new ArrayBuffer(u32(bufLen)); _rlp(Type.RLP_LIST_GET, i, 0, changetype<usize>(buf), 1); elements[i] = buf; } _rlp(Type.RLP_LIST_CLEAR, 0, 0, 0, 0); return new RLPList(elements, encoded); } getItem(index: u32): RLPItem { return RLPItem.fromEncoded(this.getRaw(index)); } getList(index: u32): RLPList { return RLPList.fromEncoded(this.getRaw(index)) } length(): u32 { return this.elements.length; } getRaw(index: u32): ArrayBuffer { return this.elements[index]; } isNull(index: u32): bool { return this.elements[index].byteLength == 1 && Uint8Array.wrap(this.elements[index])[0] == 0x80; } } function encodeBytes(bytes: ArrayBuffer): ArrayBuffer { const len = _rlp(Type.ENCODE_BYTES, changetype<usize>(bytes), bytes.byteLength, 0, 0); const buf = new ArrayBuffer(u32(len)); _rlp(Type.ENCODE_BYTES, changetype<usize>(bytes), bytes.byteLength, changetype<usize>(buf), 1); return buf; } function encodeElements(elements: Array<ArrayBuffer>): ArrayBuffer { if (elements.length == 0) return RLP.emptyList(); for (let i = 0; i < elements.length; i++) { const buf = elements[i]; _rlp(Type.RLP_LIST_PUSH, changetype<usize>(buf), buf.byteLength, 0, 0); } const len = _rlp(Type.RLP_LIST_BUILD, 0, 0, 0, 0); const buf = new ArrayBuffer(u32(len)); _rlp(Type.RLP_LIST_BUILD, 0, 0, changetype<usize>(buf), 1); return buf; }