commit
dfd028b7dc
@ -57,9 +57,17 @@
|
||||
|
||||
### Changed
|
||||
|
||||
- @cosmjs/encoding: Change return type of `fromRfc3339` from `ReadonlyDate` to
|
||||
`Date` as the caller becomes the owner of the object and can safely mutate it
|
||||
in any way.
|
||||
- @cosmjs/launchpad-ledger: Renamed to @cosmjs/ledger-amino.
|
||||
- @cosmjs/ledger-amino: `LedgerSigner.sign` method renamed `signAmino`.
|
||||
|
||||
### Deprecated
|
||||
|
||||
- @cosmjs/tendermint-rpc: Deprecate `DateTime` in favour of the free functions
|
||||
`fromRfc3339WithNanoseconds` and `toRfc3339WithNanoseconds`.
|
||||
|
||||
## 0.23.2 (2021-01-06)
|
||||
|
||||
### Security
|
||||
|
||||
@ -35,7 +35,7 @@ import {
|
||||
adaptor34,
|
||||
broadcastTxCommitSuccess,
|
||||
Client as TendermintClient,
|
||||
DateTime,
|
||||
toRfc3339WithNanoseconds,
|
||||
} from "@cosmjs/tendermint-rpc";
|
||||
import { assert } from "@cosmjs/utils";
|
||||
|
||||
@ -114,7 +114,7 @@ export class CosmWasmClient {
|
||||
},
|
||||
height: response.block.header.height,
|
||||
chainId: response.block.header.chainId,
|
||||
time: DateTime.encode(response.block.header.time),
|
||||
time: toRfc3339WithNanoseconds(response.block.header.time),
|
||||
},
|
||||
txs: response.block.txs,
|
||||
};
|
||||
|
||||
@ -7,7 +7,7 @@ function padded(integer: number, length = 2): string {
|
||||
return filled.substring(filled.length - length);
|
||||
}
|
||||
|
||||
export function fromRfc3339(str: string): ReadonlyDate {
|
||||
export function fromRfc3339(str: string): Date {
|
||||
const matches = rfc3339Matcher.exec(str);
|
||||
if (!matches) {
|
||||
throw new Error("Date string is not in RFC3339 format");
|
||||
@ -40,9 +40,8 @@ export function fromRfc3339(str: string): ReadonlyDate {
|
||||
|
||||
const tzOffset = tzOffsetSign * (tzOffsetHours * 60 + tzOffsetMinutes) * 60; // seconds
|
||||
|
||||
return new ReadonlyDate(
|
||||
ReadonlyDate.UTC(year, month - 1, day, hour, minute, second, milliSeconds) - tzOffset * 1000,
|
||||
);
|
||||
const timestamp = Date.UTC(year, month - 1, day, hour, minute, second, milliSeconds) - tzOffset * 1000;
|
||||
return new Date(timestamp);
|
||||
}
|
||||
|
||||
export function toRfc3339(date: Date | ReadonlyDate): string {
|
||||
|
||||
@ -15,7 +15,7 @@ import {
|
||||
adaptor34,
|
||||
broadcastTxCommitSuccess,
|
||||
Client as TendermintClient,
|
||||
DateTime,
|
||||
toRfc3339WithNanoseconds,
|
||||
} from "@cosmjs/tendermint-rpc";
|
||||
import { assert, assertDefinedAndNotNull } from "@cosmjs/utils";
|
||||
import Long from "long";
|
||||
@ -185,7 +185,7 @@ export class StargateClient {
|
||||
},
|
||||
height: response.block.header.height,
|
||||
chainId: response.block.header.chainId,
|
||||
time: DateTime.encode(response.block.header.time),
|
||||
time: toRfc3339WithNanoseconds(response.block.header.time),
|
||||
},
|
||||
txs: response.block.txs,
|
||||
};
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { fromBase64, fromHex } from "@cosmjs/encoding";
|
||||
import { ReadonlyDate } from "readonly-date";
|
||||
|
||||
import { ReadonlyDateWithNanoseconds } from "../../types";
|
||||
import { ReadonlyDateWithNanoseconds } from "../../dates";
|
||||
import { hashBlock, hashTx } from "./hasher";
|
||||
|
||||
describe("Hasher", () => {
|
||||
|
||||
@ -3,6 +3,7 @@ import { fromBase64, fromHex } from "@cosmjs/encoding";
|
||||
import { JsonRpcSuccessResponse } from "@cosmjs/json-rpc";
|
||||
import { assert } from "@cosmjs/utils";
|
||||
|
||||
import { fromRfc3339WithNanoseconds } from "../../dates";
|
||||
import {
|
||||
assertArray,
|
||||
assertBoolean,
|
||||
@ -11,7 +12,6 @@ import {
|
||||
assertObject,
|
||||
assertSet,
|
||||
assertString,
|
||||
DateTime,
|
||||
dictionaryToStringMap,
|
||||
Integer,
|
||||
may,
|
||||
@ -328,7 +328,7 @@ function decodeHeader(data: RpcHeader): responses.Header {
|
||||
version: decodeBlockVersion(data.version),
|
||||
chainId: assertNotEmpty(data.chain_id),
|
||||
height: Integer.parse(assertNotEmpty(data.height)),
|
||||
time: DateTime.decode(assertNotEmpty(data.time)),
|
||||
time: fromRfc3339WithNanoseconds(assertNotEmpty(data.time)),
|
||||
|
||||
lastBlockId: decodeBlockId(data.last_block_id),
|
||||
|
||||
@ -417,7 +417,7 @@ function decodeCommitSignature(data: RpcSignature): CommitSignature {
|
||||
return {
|
||||
blockIdFlag: decodeBlockIdFlag(data.block_id_flag),
|
||||
validatorAddress: fromHex(data.validator_address),
|
||||
timestamp: DateTime.decode(assertNotEmpty(data.timestamp)),
|
||||
timestamp: fromRfc3339WithNanoseconds(assertNotEmpty(data.timestamp)),
|
||||
signature: fromBase64(assertNotEmpty(data.signature)),
|
||||
};
|
||||
}
|
||||
@ -488,7 +488,7 @@ interface GenesisResult {
|
||||
|
||||
function decodeGenesis(data: RpcGenesisResponse): responses.GenesisResponse {
|
||||
return {
|
||||
genesisTime: DateTime.decode(assertNotEmpty(data.genesis_time)),
|
||||
genesisTime: fromRfc3339WithNanoseconds(assertNotEmpty(data.genesis_time)),
|
||||
chainId: assertNotEmpty(data.chain_id),
|
||||
consensusParams: decodeConsensusParams(data.consensus_params),
|
||||
validators: data.validators ? assertArray(data.validators).map(decodeValidatorGenesis) : [],
|
||||
@ -568,7 +568,7 @@ function decodeSyncInfo(data: RpcSyncInfo): responses.SyncInfo {
|
||||
return {
|
||||
latestBlockHash: fromHex(assertNotEmpty(data.latest_block_hash)),
|
||||
latestAppHash: fromHex(assertNotEmpty(data.latest_app_hash)),
|
||||
latestBlockTime: DateTime.decode(assertNotEmpty(data.latest_block_time)),
|
||||
latestBlockTime: fromRfc3339WithNanoseconds(assertNotEmpty(data.latest_block_time)),
|
||||
latestBlockHeight: Integer.parse(assertNotEmpty(data.latest_block_height)),
|
||||
catchingUp: assertBoolean(data.catching_up),
|
||||
};
|
||||
|
||||
90
packages/tendermint-rpc/src/dates.spec.ts
Normal file
90
packages/tendermint-rpc/src/dates.spec.ts
Normal file
@ -0,0 +1,90 @@
|
||||
import { ReadonlyDate } from "readonly-date";
|
||||
|
||||
import { DateTime, DateWithNanoseconds, fromRfc3339WithNanoseconds, toRfc3339WithNanoseconds } from "./dates";
|
||||
|
||||
describe("dates", () => {
|
||||
describe("fromRfc3339WithNanoseconds", () => {
|
||||
it("works", () => {
|
||||
expect(fromRfc3339WithNanoseconds("2020-12-15T10:57:26.778Z").nanoseconds).toEqual(0);
|
||||
expect(fromRfc3339WithNanoseconds("2020-12-15T10:57:26.7789Z").nanoseconds).toEqual(900000);
|
||||
expect(fromRfc3339WithNanoseconds("2020-12-15T10:57:26.77809Z").nanoseconds).toEqual(90000);
|
||||
expect(fromRfc3339WithNanoseconds("2020-12-15T10:57:26.778009Z").nanoseconds).toEqual(9000);
|
||||
expect(fromRfc3339WithNanoseconds("2020-12-15T10:57:26.7780009Z").nanoseconds).toEqual(900);
|
||||
expect(fromRfc3339WithNanoseconds("2020-12-15T10:57:26.77800009Z").nanoseconds).toEqual(90);
|
||||
expect(fromRfc3339WithNanoseconds("2020-12-15T10:57:26.778000009Z").nanoseconds).toEqual(9);
|
||||
});
|
||||
});
|
||||
|
||||
describe("toRfc3339WithNanoseconds", () => {
|
||||
it("works", () => {
|
||||
const date1 = new ReadonlyDate("2020-12-15T10:57:26.778Z");
|
||||
(date1 as any).nanoseconds = 0;
|
||||
expect(toRfc3339WithNanoseconds(date1)).toEqual("2020-12-15T10:57:26.778000000Z");
|
||||
const date2 = new ReadonlyDate("2020-12-15T10:57:26.778Z");
|
||||
(date2 as any).nanoseconds = 900000;
|
||||
expect(toRfc3339WithNanoseconds(date2)).toEqual("2020-12-15T10:57:26.778900000Z");
|
||||
const date3 = new ReadonlyDate("2020-12-15T10:57:26.778Z");
|
||||
(date3 as any).nanoseconds = 90000;
|
||||
expect(toRfc3339WithNanoseconds(date3)).toEqual("2020-12-15T10:57:26.778090000Z");
|
||||
const date4 = new ReadonlyDate("2020-12-15T10:57:26.778Z");
|
||||
(date4 as any).nanoseconds = 9000;
|
||||
expect(toRfc3339WithNanoseconds(date4)).toEqual("2020-12-15T10:57:26.778009000Z");
|
||||
const date5 = new ReadonlyDate("2020-12-15T10:57:26.778Z");
|
||||
(date5 as any).nanoseconds = 900;
|
||||
expect(toRfc3339WithNanoseconds(date5)).toEqual("2020-12-15T10:57:26.778000900Z");
|
||||
const date6 = new ReadonlyDate("2020-12-15T10:57:26.778Z");
|
||||
(date6 as any).nanoseconds = 90;
|
||||
expect(toRfc3339WithNanoseconds(date6)).toEqual("2020-12-15T10:57:26.778000090Z");
|
||||
const date7 = new ReadonlyDate("2020-12-15T10:57:26.778Z");
|
||||
(date7 as any).nanoseconds = 9;
|
||||
expect(toRfc3339WithNanoseconds(date7)).toEqual("2020-12-15T10:57:26.778000009Z");
|
||||
});
|
||||
|
||||
it("works for DateWithNanoseconds", () => {
|
||||
const date1: DateWithNanoseconds = new Date("2020-12-15T10:57:26.778Z");
|
||||
date1.nanoseconds = 1;
|
||||
expect(toRfc3339WithNanoseconds(date1)).toEqual("2020-12-15T10:57:26.778000001Z");
|
||||
});
|
||||
|
||||
it("works for Date", () => {
|
||||
const date1 = new Date("2020-12-15T10:57:26.778Z");
|
||||
expect(toRfc3339WithNanoseconds(date1)).toEqual("2020-12-15T10:57:26.778000000Z");
|
||||
});
|
||||
});
|
||||
|
||||
describe("DateTime", () => {
|
||||
it("decodes a string", () => {
|
||||
expect(DateTime.decode("2020-12-15T10:57:26.778Z").nanoseconds).toEqual(0);
|
||||
expect(DateTime.decode("2020-12-15T10:57:26.7789Z").nanoseconds).toEqual(900000);
|
||||
expect(DateTime.decode("2020-12-15T10:57:26.77809Z").nanoseconds).toEqual(90000);
|
||||
expect(DateTime.decode("2020-12-15T10:57:26.778009Z").nanoseconds).toEqual(9000);
|
||||
expect(DateTime.decode("2020-12-15T10:57:26.7780009Z").nanoseconds).toEqual(900);
|
||||
expect(DateTime.decode("2020-12-15T10:57:26.77800009Z").nanoseconds).toEqual(90);
|
||||
expect(DateTime.decode("2020-12-15T10:57:26.778000009Z").nanoseconds).toEqual(9);
|
||||
});
|
||||
|
||||
it("encodes a string", () => {
|
||||
const date1 = new ReadonlyDate("2020-12-15T10:57:26.778Z");
|
||||
(date1 as any).nanoseconds = 0;
|
||||
expect(DateTime.encode(date1)).toEqual("2020-12-15T10:57:26.778000000Z");
|
||||
const date2 = new ReadonlyDate("2020-12-15T10:57:26.778Z");
|
||||
(date2 as any).nanoseconds = 900000;
|
||||
expect(DateTime.encode(date2)).toEqual("2020-12-15T10:57:26.778900000Z");
|
||||
const date3 = new ReadonlyDate("2020-12-15T10:57:26.778Z");
|
||||
(date3 as any).nanoseconds = 90000;
|
||||
expect(DateTime.encode(date3)).toEqual("2020-12-15T10:57:26.778090000Z");
|
||||
const date4 = new ReadonlyDate("2020-12-15T10:57:26.778Z");
|
||||
(date4 as any).nanoseconds = 9000;
|
||||
expect(DateTime.encode(date4)).toEqual("2020-12-15T10:57:26.778009000Z");
|
||||
const date5 = new ReadonlyDate("2020-12-15T10:57:26.778Z");
|
||||
(date5 as any).nanoseconds = 900;
|
||||
expect(DateTime.encode(date5)).toEqual("2020-12-15T10:57:26.778000900Z");
|
||||
const date6 = new ReadonlyDate("2020-12-15T10:57:26.778Z");
|
||||
(date6 as any).nanoseconds = 90;
|
||||
expect(DateTime.encode(date6)).toEqual("2020-12-15T10:57:26.778000090Z");
|
||||
const date7 = new ReadonlyDate("2020-12-15T10:57:26.778Z");
|
||||
(date7 as any).nanoseconds = 9;
|
||||
expect(DateTime.encode(date7)).toEqual("2020-12-15T10:57:26.778000009Z");
|
||||
});
|
||||
});
|
||||
});
|
||||
39
packages/tendermint-rpc/src/dates.ts
Normal file
39
packages/tendermint-rpc/src/dates.ts
Normal file
@ -0,0 +1,39 @@
|
||||
import { fromRfc3339 } from "@cosmjs/encoding";
|
||||
import { ReadonlyDate } from "readonly-date";
|
||||
|
||||
export interface ReadonlyDateWithNanoseconds extends ReadonlyDate {
|
||||
/* Nanoseconds after the time stored in a vanilla ReadonlyDate (millisecond granularity) */
|
||||
readonly nanoseconds?: number;
|
||||
}
|
||||
|
||||
export interface DateWithNanoseconds extends Date {
|
||||
/** Nanoseconds after the time stored in a vanilla Date (millisecond granularity) */
|
||||
nanoseconds?: number;
|
||||
}
|
||||
|
||||
export function fromRfc3339WithNanoseconds(dateTimeString: string): DateWithNanoseconds {
|
||||
const out: DateWithNanoseconds = fromRfc3339(dateTimeString);
|
||||
const nanosecondsMatch = dateTimeString.match(/\.(\d+)Z$/);
|
||||
const nanoseconds = nanosecondsMatch ? nanosecondsMatch[1].slice(3) : "";
|
||||
out.nanoseconds = parseInt(nanoseconds.padEnd(6, "0"), 10);
|
||||
return out;
|
||||
}
|
||||
|
||||
export function toRfc3339WithNanoseconds(dateTime: ReadonlyDateWithNanoseconds): string {
|
||||
const millisecondIso = dateTime.toISOString();
|
||||
const nanoseconds = dateTime.nanoseconds?.toString() ?? "";
|
||||
return `${millisecondIso.slice(0, -1)}${nanoseconds.padStart(6, "0")}Z`;
|
||||
}
|
||||
|
||||
/** @deprecated Use fromRfc3339WithNanoseconds/toRfc3339WithNanoseconds instead */
|
||||
export class DateTime {
|
||||
/** @deprecated Use fromRfc3339WithNanoseconds instead */
|
||||
public static decode(dateTimeString: string): ReadonlyDateWithNanoseconds {
|
||||
return fromRfc3339WithNanoseconds(dateTimeString);
|
||||
}
|
||||
|
||||
/** @deprecated Use toRfc3339WithNanoseconds instead */
|
||||
public static encode(dateTime: ReadonlyDateWithNanoseconds): string {
|
||||
return toRfc3339WithNanoseconds(dateTime);
|
||||
}
|
||||
}
|
||||
@ -1,53 +1,8 @@
|
||||
import { ReadonlyDate } from "readonly-date";
|
||||
|
||||
import {
|
||||
DateTime,
|
||||
encodeBlockId,
|
||||
encodeBytes,
|
||||
encodeInt,
|
||||
encodeString,
|
||||
encodeTime,
|
||||
encodeVersion,
|
||||
} from "./encodings";
|
||||
import { ReadonlyDateWithNanoseconds } from "./types";
|
||||
import { encodeBlockId, encodeBytes, encodeInt, encodeString, encodeTime, encodeVersion } from "./encodings";
|
||||
|
||||
describe("encodings", () => {
|
||||
describe("DateTime", () => {
|
||||
it("decodes a string", () => {
|
||||
expect(DateTime.decode("2020-12-15T10:57:26.778Z").nanoseconds).toEqual(0);
|
||||
expect(DateTime.decode("2020-12-15T10:57:26.7789Z").nanoseconds).toEqual(900000);
|
||||
expect(DateTime.decode("2020-12-15T10:57:26.77809Z").nanoseconds).toEqual(90000);
|
||||
expect(DateTime.decode("2020-12-15T10:57:26.778009Z").nanoseconds).toEqual(9000);
|
||||
expect(DateTime.decode("2020-12-15T10:57:26.7780009Z").nanoseconds).toEqual(900);
|
||||
expect(DateTime.decode("2020-12-15T10:57:26.77800009Z").nanoseconds).toEqual(90);
|
||||
expect(DateTime.decode("2020-12-15T10:57:26.778000009Z").nanoseconds).toEqual(9);
|
||||
});
|
||||
|
||||
it("encodes a string", () => {
|
||||
const date1 = new ReadonlyDate("2020-12-15T10:57:26.778Z") as ReadonlyDateWithNanoseconds;
|
||||
(date1 as any).nanoseconds = 0;
|
||||
expect(DateTime.encode(date1)).toEqual("2020-12-15T10:57:26.778000000Z");
|
||||
const date2 = new ReadonlyDate("2020-12-15T10:57:26.778Z") as ReadonlyDateWithNanoseconds;
|
||||
(date2 as any).nanoseconds = 900000;
|
||||
expect(DateTime.encode(date2)).toEqual("2020-12-15T10:57:26.778900000Z");
|
||||
const date3 = new ReadonlyDate("2020-12-15T10:57:26.778Z") as ReadonlyDateWithNanoseconds;
|
||||
(date3 as any).nanoseconds = 90000;
|
||||
expect(DateTime.encode(date3)).toEqual("2020-12-15T10:57:26.778090000Z");
|
||||
const date4 = new ReadonlyDate("2020-12-15T10:57:26.778Z") as ReadonlyDateWithNanoseconds;
|
||||
(date4 as any).nanoseconds = 9000;
|
||||
expect(DateTime.encode(date4)).toEqual("2020-12-15T10:57:26.778009000Z");
|
||||
const date5 = new ReadonlyDate("2020-12-15T10:57:26.778Z") as ReadonlyDateWithNanoseconds;
|
||||
(date5 as any).nanoseconds = 900;
|
||||
expect(DateTime.encode(date5)).toEqual("2020-12-15T10:57:26.778000900Z");
|
||||
const date6 = new ReadonlyDate("2020-12-15T10:57:26.778Z") as ReadonlyDateWithNanoseconds;
|
||||
(date6 as any).nanoseconds = 90;
|
||||
expect(DateTime.encode(date6)).toEqual("2020-12-15T10:57:26.778000090Z");
|
||||
const date7 = new ReadonlyDate("2020-12-15T10:57:26.778Z") as ReadonlyDateWithNanoseconds;
|
||||
(date7 as any).nanoseconds = 9;
|
||||
expect(DateTime.encode(date7)).toEqual("2020-12-15T10:57:26.778000009Z");
|
||||
});
|
||||
});
|
||||
|
||||
describe("encodeString", () => {
|
||||
it("works", () => {
|
||||
expect(encodeString("")).toEqual(Uint8Array.from([0]));
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { fromRfc3339, toUtf8 } from "@cosmjs/encoding";
|
||||
import { toUtf8 } from "@cosmjs/encoding";
|
||||
import { Int53 } from "@cosmjs/math";
|
||||
|
||||
import { ReadonlyDateWithNanoseconds } from "./dates";
|
||||
import { BlockId, Version } from "./responses";
|
||||
import { ReadonlyDateWithNanoseconds } from "./types";
|
||||
|
||||
/**
|
||||
* A runtime checker that ensures a given value is set (i.e. not undefined or null)
|
||||
@ -156,22 +156,6 @@ export class Integer {
|
||||
}
|
||||
}
|
||||
|
||||
export class DateTime {
|
||||
public static decode(dateTimeString: string): ReadonlyDateWithNanoseconds {
|
||||
const readonlyDate = fromRfc3339(dateTimeString);
|
||||
const nanosecondsMatch = dateTimeString.match(/\.(\d+)Z$/);
|
||||
const nanoseconds = nanosecondsMatch ? nanosecondsMatch[1].slice(3) : "";
|
||||
(readonlyDate as any).nanoseconds = parseInt(nanoseconds.padEnd(6, "0"), 10);
|
||||
return readonlyDate as ReadonlyDateWithNanoseconds;
|
||||
}
|
||||
|
||||
public static encode(dateTime: ReadonlyDateWithNanoseconds): string {
|
||||
const millisecondIso = dateTime.toISOString();
|
||||
const nanoseconds = dateTime.nanoseconds?.toString() ?? "";
|
||||
return `${millisecondIso.slice(0, -1)}${nanoseconds.padStart(6, "0")}Z`;
|
||||
}
|
||||
}
|
||||
|
||||
// Encodings needed for hashing block headers
|
||||
// Several of these functions are inspired by https://github.com/nomic-io/js-tendermint/blob/tendermint-0.30/src/
|
||||
|
||||
|
||||
@ -1,7 +1,12 @@
|
||||
export { Adaptor } from "./adaptor";
|
||||
export { adaptor33, adaptor34 } from "./adaptors";
|
||||
export { Client } from "./client";
|
||||
export { DateTime } from "./encodings";
|
||||
export {
|
||||
DateTime,
|
||||
ReadonlyDateWithNanoseconds,
|
||||
fromRfc3339WithNanoseconds,
|
||||
toRfc3339WithNanoseconds,
|
||||
} from "./dates";
|
||||
export {
|
||||
AbciInfoRequest,
|
||||
AbciQueryParams,
|
||||
@ -72,10 +77,4 @@ export {
|
||||
VoteType,
|
||||
} from "./responses";
|
||||
export { HttpClient, WebsocketClient } from "./rpcclients"; // TODO: Why do we export those outside of this package?
|
||||
export {
|
||||
BlockIdFlag,
|
||||
CommitSignature,
|
||||
ReadonlyDateWithNanoseconds,
|
||||
ValidatorEd25519Pubkey,
|
||||
ValidatorPubkey,
|
||||
} from "./types";
|
||||
export { BlockIdFlag, CommitSignature, ValidatorEd25519Pubkey, ValidatorPubkey } from "./types";
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { ReadonlyDate } from "readonly-date";
|
||||
|
||||
import { CommitSignature, ReadonlyDateWithNanoseconds, ValidatorPubkey } from "./types";
|
||||
import { ReadonlyDateWithNanoseconds } from "./dates";
|
||||
import { CommitSignature, ValidatorPubkey } from "./types";
|
||||
|
||||
export type Response =
|
||||
| AbciInfoResponse
|
||||
|
||||
@ -1,11 +1,7 @@
|
||||
// Types in this file are exported outside of the @cosmjs/tendermint-rpc package,
|
||||
// e.g. as part of a request or response
|
||||
import { ReadonlyDate } from "readonly-date";
|
||||
|
||||
export interface ReadonlyDateWithNanoseconds extends ReadonlyDate {
|
||||
/* Nanoseconds after the time stored in a vanilla ReadonlyDate (millisecond granularity) */
|
||||
readonly nanoseconds?: number;
|
||||
}
|
||||
import { ReadonlyDateWithNanoseconds } from "./dates";
|
||||
|
||||
export interface ValidatorEd25519Pubkey {
|
||||
readonly algorithm: "ed25519";
|
||||
|
||||
Loading…
Reference in New Issue
Block a user