From 094e9d7bc5bb0f0f3e93ae6e5404d38d8b63cac9 Mon Sep 17 00:00:00 2001 From: Mike Seese Date: Tue, 30 Mar 2021 15:16:48 -0700 Subject: [PATCH] implement #877 async init changes for the filecoin flavor --- src/chains/filecoin/filecoin/src/api.ts | 4 + .../filecoin/filecoin/src/blockchain.ts | 161 +++++++++--------- src/chains/filecoin/filecoin/src/connector.ts | 14 +- src/chains/filecoin/filecoin/src/database.ts | 3 +- src/chains/filecoin/filecoin/src/provider.ts | 10 +- .../tests/blockchain/blockchain.test.ts | 16 +- .../tests/blockchain/database.test.ts | 6 +- .../filecoin/tests/helpers/getProvider.ts | 8 +- .../filecoin/tests/helpers/getServer.ts | 2 +- src/packages/core/src/server.ts | 5 +- 10 files changed, 117 insertions(+), 112 deletions(-) diff --git a/src/chains/filecoin/filecoin/src/api.ts b/src/chains/filecoin/filecoin/src/api.ts index 59d2726219..3c3eaa9617 100644 --- a/src/chains/filecoin/filecoin/src/api.ts +++ b/src/chains/filecoin/filecoin/src/api.ts @@ -50,6 +50,10 @@ export default class FilecoinApi implements types.Api { this.#blockchain = blockchain; } + async initialize() { + await this.#blockchain.initialize(); + } + async stop(): Promise { return await this.#blockchain.stop(); } diff --git a/src/chains/filecoin/filecoin/src/blockchain.ts b/src/chains/filecoin/filecoin/src/blockchain.ts index f62f678787..d5245d870a 100644 --- a/src/chains/filecoin/filecoin/src/blockchain.ts +++ b/src/chains/filecoin/filecoin/src/blockchain.ts @@ -127,94 +127,97 @@ export default class Blockchain extends Emittery.Typed< this.dealInfoManager = null; this.#database = new Database(options.database); - this.#database.once("ready").then(async () => { - this.blockHeaderManager = await BlockHeaderManager.initialize( - this.#database.blocks! - ); - this.tipsetManager = await TipsetManager.initialize( - this.#database.tipsets!, - this.blockHeaderManager - ); - this.privateKeyManager = await PrivateKeyManager.initialize( - this.#database.privateKeys! - ); - this.accountManager = await AccountManager.initialize( - this.#database.accounts!, - this.privateKeyManager, - this.#database - ); - this.signedMessagesManager = await SignedMessageManager.initialize( - this.#database.signedMessages! - ); - this.blockMessagesManager = await BlockMessagesManager.initialize( - this.#database.blockMessages!, - this.signedMessagesManager - ); - this.dealInfoManager = await DealInfoManager.initialize( - this.#database.deals!, - this.#database.dealExpirations! - ); - - const controllableAccounts = await this.accountManager.getControllableAccounts(); - if (controllableAccounts.length === 0) { - for (let i = 0; i < this.options.wallet.totalAccounts; i++) { - await this.accountManager.putAccount( - Account.random(this.options.wallet.defaultBalance, this.rng) - ); - } - } + } - const recordedGenesisTipset = await this.tipsetManager.getTipsetWithBlocks( - 0 - ); - if (recordedGenesisTipset === null) { - // Create genesis tipset - const genesisBlock = new BlockHeader({ - ticket: new Ticket({ - // Reference implementation https://git.io/Jt31s - vrfProof: this.rng.getBuffer(32) - }), - parents: [ - // Both lotus and lotus-devnet always have the Filecoin genesis CID - // hardcoded here. Reference implementation: https://git.io/Jt3oK - new RootCID({ - "/": "bafyreiaqpwbbyjo4a42saasj36kkrpv4tsherf2e7bvezkert2a7dhonoi" - }) - ] - }); + async initialize() { + await this.#database.initialize(); - const genesisTipset = new Tipset({ - blocks: [genesisBlock], - height: 0 - }); + this.blockHeaderManager = await BlockHeaderManager.initialize( + this.#database.blocks! + ); + this.tipsetManager = await TipsetManager.initialize( + this.#database.tipsets!, + this.blockHeaderManager + ); + this.privateKeyManager = await PrivateKeyManager.initialize( + this.#database.privateKeys! + ); + this.accountManager = await AccountManager.initialize( + this.#database.accounts!, + this.privateKeyManager, + this.#database + ); + this.signedMessagesManager = await SignedMessageManager.initialize( + this.#database.signedMessages! + ); + this.blockMessagesManager = await BlockMessagesManager.initialize( + this.#database.blockMessages!, + this.signedMessagesManager + ); + this.dealInfoManager = await DealInfoManager.initialize( + this.#database.deals!, + this.#database.dealExpirations! + ); - this.tipsetManager.earliest = genesisTipset; // initialize earliest - await this.tipsetManager.putTipset(genesisTipset); // sets latest - await this.#database.db!.put("latest-tipset", utils.uintToBuffer(0)); - } else { - this.tipsetManager.earliest = recordedGenesisTipset; // initialize earliest - const data: Buffer = await this.#database.db!.get("latest-tipset"); - const height = Quantity.from(data).toNumber(); - const latestTipset = await this.tipsetManager.getTipsetWithBlocks( - height + const controllableAccounts = await this.accountManager.getControllableAccounts(); + if (controllableAccounts.length === 0) { + for (let i = 0; i < this.options.wallet.totalAccounts; i++) { + await this.accountManager.putAccount( + Account.random(this.options.wallet.defaultBalance, this.rng) ); - this.tipsetManager.latest = latestTipset!; // initialize latest } + } - await this.ipfsServer.start(this.#database.directory!); + const recordedGenesisTipset = await this.tipsetManager.getTipsetWithBlocks( + 0 + ); + if (recordedGenesisTipset === null) { + // Create genesis tipset + const genesisBlock = new BlockHeader({ + ticket: new Ticket({ + // Reference implementation https://git.io/Jt31s + vrfProof: this.rng.getBuffer(32) + }), + parents: [ + // Both lotus and lotus-devnet always have the Filecoin genesis CID + // hardcoded here. Reference implementation: https://git.io/Jt3oK + new RootCID({ + "/": "bafyreiaqpwbbyjo4a42saasj36kkrpv4tsherf2e7bvezkert2a7dhonoi" + }) + ] + }); - // Fire up the miner if necessary - if (this.minerEnabled && this.options.miner.blockTime > 0) { - await this.enableMiner(); - } + const genesisTipset = new Tipset({ + blocks: [genesisBlock], + height: 0 + }); - // Get this party started! - this.ready = true; - this.emit("ready"); + this.tipsetManager.earliest = genesisTipset; // initialize earliest + await this.tipsetManager.putTipset(genesisTipset); // sets latest + await this.#database.db!.put("latest-tipset", utils.uintToBuffer(0)); + } else { + this.tipsetManager.earliest = recordedGenesisTipset; // initialize earliest + const data: Buffer = await this.#database.db!.get("latest-tipset"); + const height = Quantity.from(data).toNumber(); + const latestTipset = await this.tipsetManager.getTipsetWithBlocks( + height + ); + this.tipsetManager.latest = latestTipset!; // initialize latest + } - // Don't log until things are all ready - this.logLatestTipset(); - }); + await this.ipfsServer.start(this.#database.directory!); + + // Fire up the miner if necessary + if (this.minerEnabled && this.options.miner.blockTime > 0) { + await this.enableMiner(); + } + + // Get this party started! + this.ready = true; + this.emit("ready"); + + // Don't log until things are all ready + this.logLatestTipset(); } async waitForReady() { diff --git a/src/chains/filecoin/filecoin/src/connector.ts b/src/chains/filecoin/filecoin/src/connector.ts index 59dc0383d5..4b2e22a3c8 100644 --- a/src/chains/filecoin/filecoin/src/connector.ts +++ b/src/chains/filecoin/filecoin/src/connector.ts @@ -33,15 +33,17 @@ export class Connector ) { super(); - const provider = (this.#provider = new FilecoinProvider( + this.#provider = new FilecoinProvider( providerOptions, executor - )); + ); + } - provider.on("ready", () => { - // tell the consumer (like a `ganache-core` server/connector) everything is ready - this.emit("ready"); - }); + async initialize() { + await this.#provider.initialize(); + // no need to wait for #provider.once("connect") as the initialize() + // promise has already accounted for that after the promise is resolved + await this.emit("ready"); } parse(message: Buffer) { diff --git a/src/chains/filecoin/filecoin/src/database.ts b/src/chains/filecoin/filecoin/src/database.ts index 2c1906f7fe..2c5e7fbe95 100644 --- a/src/chains/filecoin/filecoin/src/database.ts +++ b/src/chains/filecoin/filecoin/src/database.ts @@ -47,10 +47,9 @@ export default class Database extends Emittery { super(); this.#options = options; - this.#initialize(); } - #initialize = async () => { + initialize = async () => { const levelupOptions: any = { valueEncoding: "binary" }; const store = this.#options.db; let db: LevelUp; diff --git a/src/chains/filecoin/filecoin/src/provider.ts b/src/chains/filecoin/filecoin/src/provider.ts index b7bdf5cb19..03972b2f85 100644 --- a/src/chains/filecoin/filecoin/src/provider.ts +++ b/src/chains/filecoin/filecoin/src/provider.ts @@ -15,7 +15,7 @@ import cloneDeep from "lodash.clonedeep"; // Meant to mimic this provider: // https://github.com/filecoin-shipyard/js-lotus-client-provider-browser export default class FilecoinProvider - extends Emittery.Typed<{}, "ready"> + extends Emittery.Typed<{}, "connect" | "disconnect"> // Do I actually need this? `types.Provider` doesn't actually define anything behavior implements types.Provider { #options: FilecoinInternalOptions; @@ -35,13 +35,15 @@ export default class FilecoinProvider this.#executor = executor; this.blockchain = new Blockchain(providerOptions); - this.blockchain.on("ready", () => { - this.emit("ready"); - }); this.#api = new FilecoinApi(this.blockchain); } + async initialize() { + await this.#api.initialize(); + await this.emit("connect"); + } + /** * Returns the options, including defaults and generated, used to start Ganache. */ diff --git a/src/chains/filecoin/filecoin/tests/blockchain/blockchain.test.ts b/src/chains/filecoin/filecoin/tests/blockchain/blockchain.test.ts index f85e4e374d..70eac9f037 100644 --- a/src/chains/filecoin/filecoin/tests/blockchain/blockchain.test.ts +++ b/src/chains/filecoin/filecoin/tests/blockchain/blockchain.test.ts @@ -41,8 +41,8 @@ describe("Blockchain", () => { } }) ); - await blockchain.waitForReady(); - await blockchain2.waitForReady(); + await blockchain.initialize(); + await blockchain2.initialize(); }); after(async () => { @@ -104,7 +104,7 @@ describe("Blockchain", () => { ); try { - await blockchain.waitForReady(); + await blockchain.initialize(); // After 0.5 seconds, we should have at least 3 blocks and no more than 10 blocks // Github CI is so unpredictable with their burstable cpus @@ -135,7 +135,7 @@ describe("Blockchain", () => { ); try { - await blockchain.waitForReady(); + await blockchain.initialize(); const ipfs = IpfsHttpClient({ host: "localhost", @@ -183,7 +183,7 @@ describe("Blockchain", () => { }) ); - await blockchain.waitForReady(); + await blockchain.initialize(); const result = await blockchain.ipfs!.add({ content: "some data" @@ -274,7 +274,7 @@ describe("Blockchain", () => { }) ); - await blockchain.waitForReady(); + await blockchain.initialize(); const result = await blockchain.ipfs!.add({ content: "some data" @@ -333,7 +333,7 @@ describe("Blockchain", () => { } }) ); - await blockchain.waitForReady(); + await blockchain.initialize(); const accounts = await blockchain.accountManager.getControllableAccounts(); assert.strictEqual(accounts[0].address.value, expectedAddress); @@ -352,7 +352,7 @@ describe("Blockchain", () => { } }) ); - await blockchain.waitForReady(); + await blockchain.initialize(); const accounts = await blockchain.accountManager.getControllableAccounts(); assert.notStrictEqual(accounts[0].address.value, expectedAddress); diff --git a/src/chains/filecoin/filecoin/tests/blockchain/database.test.ts b/src/chains/filecoin/filecoin/tests/blockchain/database.test.ts index 4d1d1a1a4d..b2300240e4 100644 --- a/src/chains/filecoin/filecoin/tests/blockchain/database.test.ts +++ b/src/chains/filecoin/filecoin/tests/blockchain/database.test.ts @@ -35,7 +35,7 @@ describe("Blockchain", () => { }) ); - await blockchain.waitForReady(); + await blockchain.initialize(); await blockchain.mineTipset(); const dir = await readdir(dbPath); assert(dir.length > 0); @@ -78,7 +78,7 @@ describe("Blockchain", () => { }) ); - await blockchain.waitForReady(); + await blockchain.initialize(); const latestTipset = blockchain.latestTipset(); assert.strictEqual(latestTipset.height, 1); assert( @@ -101,7 +101,7 @@ describe("Blockchain", () => { }) ); - await blockchain.waitForReady(); + await blockchain.initialize(); let gotFile = false; for await (const file of blockchain.ipfs.get(ipfsCid)) { diff --git a/src/chains/filecoin/filecoin/tests/helpers/getProvider.ts b/src/chains/filecoin/filecoin/tests/helpers/getProvider.ts index 4ef4317447..db587ab012 100644 --- a/src/chains/filecoin/filecoin/tests/helpers/getProvider.ts +++ b/src/chains/filecoin/filecoin/tests/helpers/getProvider.ts @@ -19,12 +19,8 @@ const getProvider = async (options?: Partial) => { }, executor ); - await new Promise(resolve => { - provider.on("ready", () => { - requestCoordinator.resume(); - resolve(void 0); - }); - }); + await provider.initialize(); + requestCoordinator.resume(); return provider; }; diff --git a/src/chains/filecoin/filecoin/tests/helpers/getServer.ts b/src/chains/filecoin/filecoin/tests/helpers/getServer.ts index b5cf76401e..8afcf75a8b 100644 --- a/src/chains/filecoin/filecoin/tests/helpers/getServer.ts +++ b/src/chains/filecoin/filecoin/tests/helpers/getServer.ts @@ -16,7 +16,7 @@ const getServer = async (port: number) => { } } }); - await new Promise(resolve => server.listen(port, resolve)); + await server.listen(port); return server; }; diff --git a/src/packages/core/src/server.ts b/src/packages/core/src/server.ts index 80f468f5c6..3e2875cdc7 100644 --- a/src/packages/core/src/server.ts +++ b/src/packages/core/src/server.ts @@ -183,9 +183,7 @@ export class Server extends Emittery<{ open: undefined; close: undefined }> { else throw err; } }) - ]).then(() => { - return this.emit("open"); - }).catch(async error => { + ]).catch(async error => { this.#status = Status.unknown; if (callbackIsFunction) callback!(error); await this.close(); @@ -197,6 +195,7 @@ export class Server extends Emittery<{ open: undefined; close: undefined }> { const promiseResults = await promise; if (promiseResults[0].status === "fulfilled" && promiseResults[1].status === "fulfilled") { + this.emit("open"); resolve(); } else { let reason = "";