Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Random port on integrated devnet #202

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
24 changes: 16 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -343,8 +343,9 @@ More detailed documentation can be found [here](#account).

const { res: currBalance } = await account.call(contract, "get_balance");
const amount = BigInt(10);
// Passing max_fee is currently optional
await account.invoke(contract, "increase_balance", { amount }, { maxFee: BigInt("123") });

// Read more about max fee specification under # Funds and fees
await account.invoke(contract, "increase_balance", { amount }, { maxFee: BigInt("1000000000") });

const { res: newBalance } = await account.call(contract, "get_balance");
expect(newBalance).to.deep.equal(currBalance + amount);
Expand Down Expand Up @@ -610,7 +611,7 @@ npm install --save-dev influenceth__cairo_math_64x61@npm:@influenceth/cairo-math

```typescript
paths: {
cairoPaths: ["./node_modules"]
cairoPaths: ["./node_modules"];
}
```

Expand Down Expand Up @@ -690,11 +691,11 @@ await contract.invoke("increase_balance", { amount: 1 }, { wallet });

Recompilation is performed when contracts are updated or when artifacts are missing. A file will be created with the name `cairo-files-cache.json` to handle caching. Recompilation is handled before the following [CLI commands](#cli-commands) are executed.

- `npx hardhat starknet-deploy`
- `npx hardhat starknet-invoke`
- `npx hardhat starknet-call`
- `npx hardhat run`
- `npx hardhat test`
- `npx hardhat starknet-deploy`
- `npx hardhat starknet-invoke`
- `npx hardhat starknet-call`
- `npx hardhat run`
- `npx hardhat test`

This feature is turned off by default and is specified in the `hardhat.config.ts` file.

Expand Down Expand Up @@ -784,6 +785,13 @@ Once your account has funds, you can specify a max fee greater than zero:
await account.invoke(contract, "foo", { arg1: ... }, { maxFee: BigInt(...) });
```

If you don't specify a `maxFee`, one will be calculated for you by applying an overhead of 50% to the result of fee estimation. You can also customize the overhead by providing a value for `overhead`:

```typescript
// maxFee will be 40% of estimated fee; if overhead not provided, a default value is used.
await account.invoke(contract, "foo", { arg1: ... }, { overhead: 0.4 );
```

### Multicalls

You can also use the Account object to perform multi{calls, invokes, fee estimations}.
Expand Down
2 changes: 1 addition & 1 deletion scripts/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ CONFIG_FILE_NAME="hardhat.config.ts"

# setup example repo
rm -rf starknet-hardhat-example
git clone -b plugin --single-branch [email protected]:Shard-Labs/starknet-hardhat-example.git
git clone -b release-0.7.0 --single-branch [email protected]:Shard-Labs/starknet-hardhat-example.git
cd starknet-hardhat-example
git log -n 1
npm install
Expand Down
17 changes: 17 additions & 0 deletions src/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,23 @@ export abstract class Account {
calldata?: StringMap,
options?: InvokeOptions
): Promise<InvokeResponse> {
if (options?.maxFee && options?.overhead) {
const msg = "Both maxFee and overhead cannot be specified";
throw new StarknetPluginError(msg);
}

if (options?.maxFee === undefined || options?.maxFee === null) {
let overhead =
options?.overhead === undefined || options?.overhead === null
? 0.5
: options?.overhead;
overhead = Math.round((1 + overhead) * 100);
const maxFee = await this.estimateFee(toContract, functionName, calldata, options);
options = {
...options,
maxFee: (maxFee.amount * BigInt(overhead)) / BigInt(100)
};
}
return (
await this.interact(InteractChoice.INVOKE, toContract, functionName, calldata, options)
).toString();
Expand Down
3 changes: 2 additions & 1 deletion src/external-server/docker-devnet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export class DockerDevnet extends DockerServer {
}

protected async getContainerArgs(): Promise<string[]> {
return this.devnetArgs || [];
const containerArgs = this.devnetArgs || [];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if the user provided --port in args in hardhat config?

return [...containerArgs, "--port", this.port];
}
}
2 changes: 1 addition & 1 deletion src/external-server/external-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ function sleep(amountMillis: number): Promise<void> {
});
}

function isFreePort(port: number): Promise<boolean> {
export async function isFreePort(port: number): Promise<boolean> {
return new Promise((accept, reject) => {
const sock = net.createConnection(port);
sock.once("connect", () => {
Expand Down
13 changes: 9 additions & 4 deletions src/task-actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import { getWalletUtil } from "./extend-utils";
import { createIntegratedDevnet } from "./external-server";
import { Recompiler } from "./recompiler";
import { version } from "../package.json";
import { getFreePort } from "./external-server/external-server";
import { getFreePort, isFreePort } from "./external-server/external-server";

function checkSourceExists(sourcePath: string): void {
if (!fs.existsSync(sourcePath)) {
Expand Down Expand Up @@ -554,9 +554,14 @@ async function runWithDevnet(hre: HardhatRuntimeEnvironment, fn: () => Promise<u
return;
}

const port = await getFreePort();
const networkUrl = `http://127.0.0.1:${port}`;
hre.config.networks.integratedDevnet.url = networkUrl;
const { hostname, port } = new URL(hre.config.starknet.networkUrl);
const isPortFree = await isFreePort(parseInt(port));
if (!isPortFree) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this check? Couldn't it surprise the user if we just silently change the specified port. If the port is occupied, integrated-devnet spawner will inform the user about that, right?

My understanding was that we should find a free port only if the user didn't provide a URL? Now I'm actually thinking, is it even possible for the user to omit the URL? Can the type extensions file be modified to allow that?

const newPort = await getFreePort();
const networkUrl = `http://${hostname}:${newPort}`;
hre.config.networks.integratedDevnet.url = networkUrl;
hre.config.starknet.networkUrl = networkUrl;
}
const devnet = await createIntegratedDevnet(hre);

await devnet.start();
Expand Down
1 change: 1 addition & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,7 @@ export interface InvokeOptions {
wallet?: Wallet;
nonce?: Numeric;
maxFee?: Numeric;
overhead?: number;
}

export interface CallOptions {
Expand Down