Skip to content
This repository has been archived by the owner on Feb 26, 2024. It is now read-only.

Commit

Permalink
Merge pull request #886 from trufflesuite/feat/filecoin-implement-asy…
Browse files Browse the repository at this point in the history
…nc-init

implement #877 async init changes for the filecoin flavor
  • Loading branch information
mikeseese committed Mar 30, 2021
2 parents b2f4c3c + 094e9d7 commit 5887ac1
Show file tree
Hide file tree
Showing 10 changed files with 117 additions and 112 deletions.
4 changes: 4 additions & 0 deletions src/chains/filecoin/filecoin/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ export default class FilecoinApi implements types.Api {
this.#blockchain = blockchain;
}

async initialize() {
await this.#blockchain.initialize();
}

async stop(): Promise<void> {
return await this.#blockchain.stop();
}
Expand Down
161 changes: 82 additions & 79 deletions src/chains/filecoin/filecoin/src/blockchain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
14 changes: 8 additions & 6 deletions src/chains/filecoin/filecoin/src/connector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
3 changes: 1 addition & 2 deletions src/chains/filecoin/filecoin/src/database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
10 changes: 6 additions & 4 deletions src/chains/filecoin/filecoin/src/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<FilecoinApi> {
#options: FilecoinInternalOptions;
Expand All @@ -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.
*/
Expand Down
16 changes: 8 additions & 8 deletions src/chains/filecoin/filecoin/tests/blockchain/blockchain.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ describe("Blockchain", () => {
}
})
);
await blockchain.waitForReady();
await blockchain2.waitForReady();
await blockchain.initialize();
await blockchain2.initialize();
});

after(async () => {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -135,7 +135,7 @@ describe("Blockchain", () => {
);

try {
await blockchain.waitForReady();
await blockchain.initialize();

const ipfs = IpfsHttpClient({
host: "localhost",
Expand Down Expand Up @@ -183,7 +183,7 @@ describe("Blockchain", () => {
})
);

await blockchain.waitForReady();
await blockchain.initialize();

const result = await blockchain.ipfs!.add({
content: "some data"
Expand Down Expand Up @@ -274,7 +274,7 @@ describe("Blockchain", () => {
})
);

await blockchain.waitForReady();
await blockchain.initialize();

const result = await blockchain.ipfs!.add({
content: "some data"
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ describe("Blockchain", () => {
})
);

await blockchain.waitForReady();
await blockchain.initialize();
await blockchain.mineTipset();
const dir = await readdir(dbPath);
assert(dir.length > 0);
Expand Down Expand Up @@ -78,7 +78,7 @@ describe("Blockchain", () => {
})
);

await blockchain.waitForReady();
await blockchain.initialize();
const latestTipset = blockchain.latestTipset();
assert.strictEqual(latestTipset.height, 1);
assert(
Expand All @@ -101,7 +101,7 @@ describe("Blockchain", () => {
})
);

await blockchain.waitForReady();
await blockchain.initialize();

let gotFile = false;
for await (const file of blockchain.ipfs.get(ipfsCid)) {
Expand Down
8 changes: 2 additions & 6 deletions src/chains/filecoin/filecoin/tests/helpers/getProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,8 @@ const getProvider = async (options?: Partial<FilecoinProviderOptions>) => {
},
executor
);
await new Promise(resolve => {
provider.on("ready", () => {
requestCoordinator.resume();
resolve(void 0);
});
});
await provider.initialize();
requestCoordinator.resume();
return provider;
};

Expand Down
2 changes: 1 addition & 1 deletion src/chains/filecoin/filecoin/tests/helpers/getServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const getServer = async (port: number) => {
}
}
});
await new Promise(resolve => server.listen(port, resolve));
await server.listen(port);
return server;
};

Expand Down
5 changes: 2 additions & 3 deletions src/packages/core/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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 = "";
Expand Down

0 comments on commit 5887ac1

Please sign in to comment.