hardhat 2.8.2 → 2.9.0-dev.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +3 -61
- package/README.md +1 -1
- package/builtin-tasks/compile.js +95 -54
- package/builtin-tasks/compile.js.map +1 -1
- package/builtin-tasks/node.js.map +1 -1
- package/builtin-tasks/task-names.d.ts +1 -0
- package/builtin-tasks/task-names.d.ts.map +1 -1
- package/builtin-tasks/task-names.js +3 -1
- package/builtin-tasks/task-names.js.map +1 -1
- package/builtin-tasks/test.js +30 -5
- package/builtin-tasks/test.js.map +1 -1
- package/builtin-tasks/utils/solidity-files-cache.d.ts.map +1 -1
- package/builtin-tasks/utils/solidity-files-cache.js.map +1 -1
- package/internal/artifacts.d.ts +10 -8
- package/internal/artifacts.d.ts.map +1 -1
- package/internal/artifacts.js +15 -10
- package/internal/artifacts.js.map +1 -1
- package/internal/cli/analytics.js +2 -2
- package/internal/cli/analytics.js.map +1 -1
- package/internal/cli/cli.js +3 -3
- package/internal/cli/project-creation.d.ts.map +1 -1
- package/internal/cli/project-creation.js +24 -1
- package/internal/cli/project-creation.js.map +1 -1
- package/internal/core/config/config-loading.d.ts.map +1 -1
- package/internal/core/config/config-loading.js.map +1 -1
- package/internal/core/config/config-validation.d.ts.map +1 -1
- package/internal/core/config/config-validation.js +2 -2
- package/internal/core/config/config-validation.js.map +1 -1
- package/internal/core/config/default-config.d.ts +3 -0
- package/internal/core/config/default-config.d.ts.map +1 -1
- package/internal/core/config/default-config.js +3 -1
- package/internal/core/config/default-config.js.map +1 -1
- package/internal/core/errors-list.d.ts +7 -0
- package/internal/core/errors-list.d.ts.map +1 -1
- package/internal/core/errors-list.js +16 -3
- package/internal/core/errors-list.js.map +1 -1
- package/internal/core/jsonrpc/types/input/blockTag.d.ts +3 -3
- package/internal/core/jsonrpc/types/input/blockTag.d.ts.map +1 -1
- package/internal/core/providers/accounts.d.ts +1 -1
- package/internal/core/providers/accounts.d.ts.map +1 -1
- package/internal/core/providers/accounts.js +6 -4
- package/internal/core/providers/accounts.js.map +1 -1
- package/internal/core/providers/construction.d.ts.map +1 -1
- package/internal/core/providers/construction.js +1 -1
- package/internal/core/providers/construction.js.map +1 -1
- package/internal/core/providers/http.d.ts +5 -1
- package/internal/core/providers/http.d.ts.map +1 -1
- package/internal/core/providers/http.js +35 -31
- package/internal/core/providers/http.js.map +1 -1
- package/internal/core/providers/util.d.ts +1 -1
- package/internal/core/providers/util.d.ts.map +1 -1
- package/internal/core/providers/util.js +3 -3
- package/internal/core/providers/util.js.map +1 -1
- package/internal/core/tasks/task-definitions.d.ts +8 -8
- package/internal/core/tasks/task-definitions.js +8 -8
- package/internal/hardhat-network/jsonrpc/server.d.ts.map +1 -1
- package/internal/hardhat-network/jsonrpc/server.js.map +1 -1
- package/internal/hardhat-network/provider/BlockchainBase.d.ts +26 -0
- package/internal/hardhat-network/provider/BlockchainBase.d.ts.map +1 -0
- package/internal/hardhat-network/provider/BlockchainBase.js +92 -0
- package/internal/hardhat-network/provider/BlockchainBase.js.map +1 -0
- package/internal/hardhat-network/provider/BlockchainData.d.ts +32 -0
- package/internal/hardhat-network/provider/BlockchainData.d.ts.map +1 -1
- package/internal/hardhat-network/provider/BlockchainData.js +78 -1
- package/internal/hardhat-network/provider/BlockchainData.js.map +1 -1
- package/internal/hardhat-network/provider/HardhatBlockchain.d.ts +9 -15
- package/internal/hardhat-network/provider/HardhatBlockchain.d.ts.map +1 -1
- package/internal/hardhat-network/provider/HardhatBlockchain.js +15 -73
- package/internal/hardhat-network/provider/HardhatBlockchain.js.map +1 -1
- package/internal/hardhat-network/provider/fork/ForkBlockchain.d.ts +6 -14
- package/internal/hardhat-network/provider/fork/ForkBlockchain.d.ts.map +1 -1
- package/internal/hardhat-network/provider/fork/ForkBlockchain.js +23 -73
- package/internal/hardhat-network/provider/fork/ForkBlockchain.js.map +1 -1
- package/internal/hardhat-network/provider/modules/eth.js +2 -2
- package/internal/hardhat-network/provider/modules/eth.js.map +1 -1
- package/internal/hardhat-network/provider/modules/hardhat.d.ts +3 -0
- package/internal/hardhat-network/provider/modules/hardhat.d.ts.map +1 -1
- package/internal/hardhat-network/provider/modules/hardhat.js +40 -5
- package/internal/hardhat-network/provider/modules/hardhat.js.map +1 -1
- package/internal/hardhat-network/provider/modules/logger.d.ts +4 -2
- package/internal/hardhat-network/provider/modules/logger.d.ts.map +1 -1
- package/internal/hardhat-network/provider/modules/logger.js +38 -12
- package/internal/hardhat-network/provider/modules/logger.js.map +1 -1
- package/internal/hardhat-network/provider/node-types.d.ts +1 -1
- package/internal/hardhat-network/provider/node-types.d.ts.map +1 -1
- package/internal/hardhat-network/provider/node.d.ts +9 -1
- package/internal/hardhat-network/provider/node.d.ts.map +1 -1
- package/internal/hardhat-network/provider/node.js +61 -10
- package/internal/hardhat-network/provider/node.js.map +1 -1
- package/internal/hardhat-network/provider/provider.d.ts +1 -1
- package/internal/hardhat-network/provider/provider.d.ts.map +1 -1
- package/internal/hardhat-network/provider/provider.js.map +1 -1
- package/internal/hardhat-network/provider/types/HardhatBlockchainInterface.d.ts +2 -1
- package/internal/hardhat-network/provider/types/HardhatBlockchainInterface.d.ts.map +1 -1
- package/internal/hardhat-network/provider/utils/makeForkClient.d.ts.map +1 -1
- package/internal/hardhat-network/provider/utils/makeForkClient.js +2 -1
- package/internal/hardhat-network/provider/utils/makeForkClient.js.map +1 -1
- package/internal/hardhat-network/provider/utils/putGenesisBlock.js +1 -1
- package/internal/hardhat-network/stack-traces/debug.js +1 -1
- package/internal/hardhat-network/stack-traces/debug.js.map +1 -1
- package/internal/hardhat-network/stack-traces/error-inferrer.d.ts.map +1 -1
- package/internal/hardhat-network/stack-traces/error-inferrer.js +21 -12
- package/internal/hardhat-network/stack-traces/error-inferrer.js.map +1 -1
- package/internal/hardhat-network/stack-traces/solidity-errors.js +2 -2
- package/internal/hardhat-network/stack-traces/solidity-errors.js.map +1 -1
- package/internal/hardhat-network/stack-traces/solidity-stack-trace.d.ts +3 -2
- package/internal/hardhat-network/stack-traces/solidity-stack-trace.d.ts.map +1 -1
- package/internal/solidity/compilation-job.d.ts.map +1 -1
- package/internal/solidity/compilation-job.js.map +1 -1
- package/internal/solidity/compiler/downloader.d.ts +2 -2
- package/internal/solidity/compiler/downloader.d.ts.map +1 -1
- package/internal/solidity/compiler/downloader.js +3 -3
- package/internal/solidity/compiler/downloader.js.map +1 -1
- package/internal/util/chunked-promise-all.d.ts +7 -0
- package/internal/util/chunked-promise-all.d.ts.map +1 -0
- package/internal/util/chunked-promise-all.js +31 -0
- package/internal/util/chunked-promise-all.js.map +1 -0
- package/internal/util/download.d.ts.map +1 -1
- package/internal/util/download.js +23 -25
- package/internal/util/download.js.map +1 -1
- package/internal/util/glob.d.ts.map +1 -1
- package/internal/util/glob.js.map +1 -1
- package/internal/util/global-dir.d.ts.map +1 -1
- package/internal/util/global-dir.js.map +1 -1
- package/internal/util/keys-derivation.d.ts +1 -1
- package/internal/util/keys-derivation.d.ts.map +1 -1
- package/internal/util/keys-derivation.js +2 -2
- package/internal/util/keys-derivation.js.map +1 -1
- package/package.json +11 -11
- package/sample-projects/advanced/.prettierrc +1 -0
- package/sample-projects/advanced-ts/README.md +1 -1
- package/src/builtin-tasks/compile.ts +106 -79
- package/src/builtin-tasks/node.ts +2 -1
- package/src/builtin-tasks/task-names.ts +2 -0
- package/src/builtin-tasks/test.ts +69 -11
- package/src/builtin-tasks/utils/solidity-files-cache.ts +3 -2
- package/src/internal/artifacts.ts +25 -20
- package/src/internal/cli/analytics.ts +2 -2
- package/src/internal/cli/cli.ts +3 -3
- package/src/internal/cli/project-creation.ts +41 -1
- package/src/internal/core/config/config-loading.ts +2 -1
- package/src/internal/core/config/config-validation.ts +2 -0
- package/src/internal/core/config/default-config.ts +3 -1
- package/src/internal/core/errors-list.ts +16 -3
- package/src/internal/core/providers/accounts.ts +8 -5
- package/src/internal/core/providers/construction.ts +3 -1
- package/src/internal/core/providers/http.ts +47 -16
- package/src/internal/core/providers/util.ts +6 -3
- package/src/internal/core/tasks/task-definitions.ts +8 -8
- package/src/internal/hardhat-network/jsonrpc/server.ts +2 -1
- package/src/internal/hardhat-network/provider/BlockchainBase.ts +137 -0
- package/src/internal/hardhat-network/provider/BlockchainData.ts +144 -0
- package/src/internal/hardhat-network/provider/HardhatBlockchain.ts +34 -87
- package/src/internal/hardhat-network/provider/fork/ForkBlockchain.ts +45 -90
- package/src/internal/hardhat-network/provider/modules/eth.ts +2 -2
- package/src/internal/hardhat-network/provider/modules/hardhat.ts +51 -5
- package/src/internal/hardhat-network/provider/modules/logger.ts +50 -14
- package/src/internal/hardhat-network/provider/node-types.ts +2 -2
- package/src/internal/hardhat-network/provider/node.ts +85 -11
- package/src/internal/hardhat-network/provider/provider.ts +9 -8
- package/src/internal/hardhat-network/provider/types/HardhatBlockchainInterface.ts +7 -1
- package/src/internal/hardhat-network/provider/utils/makeForkClient.ts +2 -1
- package/src/internal/hardhat-network/provider/utils/putGenesisBlock.ts +1 -1
- package/src/internal/hardhat-network/stack-traces/debug.ts +1 -1
- package/src/internal/hardhat-network/stack-traces/error-inferrer.ts +21 -13
- package/src/internal/hardhat-network/stack-traces/solidity-errors.ts +2 -2
- package/src/internal/hardhat-network/stack-traces/solidity-stack-trace.ts +3 -2
- package/src/internal/solidity/compilation-job.ts +2 -1
- package/src/internal/solidity/compiler/downloader.ts +5 -3
- package/src/internal/util/download.ts +28 -34
- package/src/internal/util/glob.ts +1 -0
- package/src/internal/util/global-dir.ts +2 -1
- package/src/internal/util/keys-derivation.ts +3 -2
- package/src/types/config.ts +4 -0
- package/types/config.d.ts +4 -0
- package/types/config.d.ts.map +1 -1
|
@@ -1,12 +1,22 @@
|
|
|
1
1
|
import { Block } from "@ethereumjs/block";
|
|
2
|
+
import Common from "@ethereumjs/common";
|
|
2
3
|
import { TypedTransaction } from "@ethereumjs/tx";
|
|
3
4
|
import Bloom from "@ethereumjs/vm/dist/bloom";
|
|
4
5
|
import { BN, bufferToHex } from "ethereumjs-util";
|
|
5
6
|
|
|
7
|
+
import { assertHardhatInvariant } from "../../core/errors";
|
|
6
8
|
import { bloomFilter, filterLogs } from "./filter";
|
|
7
9
|
import { FilterParams } from "./node-types";
|
|
8
10
|
import { RpcLogOutput, RpcReceiptOutput } from "./output";
|
|
9
11
|
|
|
12
|
+
interface Reservation {
|
|
13
|
+
first: BN;
|
|
14
|
+
last: BN;
|
|
15
|
+
interval: BN;
|
|
16
|
+
previousBlockStateRoot: Buffer;
|
|
17
|
+
previousBlockTotalDifficulty: BN;
|
|
18
|
+
}
|
|
19
|
+
|
|
10
20
|
export class BlockchainData {
|
|
11
21
|
private _blocksByNumber: Map<number, Block> = new Map();
|
|
12
22
|
private _blocksByHash: Map<string, Block> = new Map();
|
|
@@ -14,6 +24,26 @@ export class BlockchainData {
|
|
|
14
24
|
private _transactions: Map<string, TypedTransaction> = new Map();
|
|
15
25
|
private _transactionReceipts: Map<string, RpcReceiptOutput> = new Map();
|
|
16
26
|
private _totalDifficulty: Map<string, BN> = new Map();
|
|
27
|
+
private _blockReservations: Reservation[] = new Array();
|
|
28
|
+
|
|
29
|
+
constructor(private _common: Common) {}
|
|
30
|
+
|
|
31
|
+
public reserveBlocks(
|
|
32
|
+
first: BN,
|
|
33
|
+
count: BN,
|
|
34
|
+
interval: BN,
|
|
35
|
+
previousBlockStateRoot: Buffer,
|
|
36
|
+
previousBlockTotalDifficulty: BN
|
|
37
|
+
) {
|
|
38
|
+
const reservation: Reservation = {
|
|
39
|
+
first,
|
|
40
|
+
last: first.add(count.subn(1)),
|
|
41
|
+
interval,
|
|
42
|
+
previousBlockStateRoot,
|
|
43
|
+
previousBlockTotalDifficulty,
|
|
44
|
+
};
|
|
45
|
+
this._blockReservations.push(reservation);
|
|
46
|
+
}
|
|
17
47
|
|
|
18
48
|
public getBlockByNumber(blockNumber: BN) {
|
|
19
49
|
return this._blocksByNumber.get(blockNumber.toNumber());
|
|
@@ -88,6 +118,11 @@ export class BlockchainData {
|
|
|
88
118
|
}
|
|
89
119
|
}
|
|
90
120
|
|
|
121
|
+
/**
|
|
122
|
+
* WARNING: this method can leave the blockchain in an invalid state where
|
|
123
|
+
* there are gaps between blocks. Ideally we should have a method that removes
|
|
124
|
+
* the given block and all the following blocks.
|
|
125
|
+
*/
|
|
91
126
|
public removeBlock(block: Block) {
|
|
92
127
|
const blockHash = bufferToHex(block.hash());
|
|
93
128
|
const blockNumber = new BN(block.header.number).toNumber();
|
|
@@ -110,4 +145,113 @@ export class BlockchainData {
|
|
|
110
145
|
public addTransactionReceipt(receipt: RpcReceiptOutput) {
|
|
111
146
|
this._transactionReceipts.set(receipt.transactionHash, receipt);
|
|
112
147
|
}
|
|
148
|
+
|
|
149
|
+
public isReservedBlock(blockNumber: BN): boolean {
|
|
150
|
+
return this._findBlockReservation(blockNumber) !== -1;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
private _findBlockReservation(blockNumber: BN): number {
|
|
154
|
+
return this._blockReservations.findIndex(
|
|
155
|
+
(reservation) =>
|
|
156
|
+
reservation.first.lte(blockNumber) && blockNumber.lte(reservation.last)
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* WARNING: this method only removes the given reservation and can result in
|
|
162
|
+
* gaps in the reservations array. Ideally we should have a method that
|
|
163
|
+
* removes the given reservation and all the following reservations.
|
|
164
|
+
*/
|
|
165
|
+
private _removeReservation(index: number): Reservation {
|
|
166
|
+
assertHardhatInvariant(
|
|
167
|
+
index in this._blockReservations,
|
|
168
|
+
`Reservation ${index} does not exist`
|
|
169
|
+
);
|
|
170
|
+
const reservation = this._blockReservations[index];
|
|
171
|
+
|
|
172
|
+
this._blockReservations.splice(index, 1);
|
|
173
|
+
|
|
174
|
+
return reservation;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Cancel and return the reservation that has block `blockNumber`
|
|
179
|
+
*/
|
|
180
|
+
public cancelReservationWithBlock(blockNumber: BN): Reservation {
|
|
181
|
+
return this._removeReservation(this._findBlockReservation(blockNumber));
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
public fulfillBlockReservation(blockNumber: BN) {
|
|
185
|
+
// in addition to adding the given block, the reservation needs to be split
|
|
186
|
+
// in two in order to accomodate access to the given block.
|
|
187
|
+
|
|
188
|
+
const reservationIndex = this._findBlockReservation(blockNumber);
|
|
189
|
+
assertHardhatInvariant(
|
|
190
|
+
reservationIndex !== -1,
|
|
191
|
+
`No reservation to fill for block number ${blockNumber}`
|
|
192
|
+
);
|
|
193
|
+
|
|
194
|
+
// capture the timestamp before removing the reservation:
|
|
195
|
+
const timestamp = this._calculateTimestampForReservedBlock(blockNumber);
|
|
196
|
+
|
|
197
|
+
// split the block reservation:
|
|
198
|
+
const oldReservation = this._removeReservation(reservationIndex);
|
|
199
|
+
|
|
200
|
+
if (!blockNumber.eq(oldReservation.first)) {
|
|
201
|
+
this._blockReservations.push({
|
|
202
|
+
...oldReservation,
|
|
203
|
+
last: blockNumber.subn(1),
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (!blockNumber.eq(oldReservation.last)) {
|
|
208
|
+
this._blockReservations.push({
|
|
209
|
+
...oldReservation,
|
|
210
|
+
first: blockNumber.addn(1),
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
this.addBlock(
|
|
215
|
+
Block.fromBlockData(
|
|
216
|
+
{
|
|
217
|
+
header: {
|
|
218
|
+
number: blockNumber,
|
|
219
|
+
stateRoot: oldReservation.previousBlockStateRoot,
|
|
220
|
+
timestamp,
|
|
221
|
+
},
|
|
222
|
+
},
|
|
223
|
+
{ common: this._common }
|
|
224
|
+
),
|
|
225
|
+
oldReservation.previousBlockTotalDifficulty
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
private _calculateTimestampForReservedBlock(blockNumber: BN): BN {
|
|
230
|
+
const reservationIndex = this._findBlockReservation(blockNumber);
|
|
231
|
+
|
|
232
|
+
assertHardhatInvariant(
|
|
233
|
+
reservationIndex !== -1,
|
|
234
|
+
`Block ${blockNumber.toString()} does not lie within any of the reservations.`
|
|
235
|
+
);
|
|
236
|
+
|
|
237
|
+
const reservation = this._blockReservations[reservationIndex];
|
|
238
|
+
|
|
239
|
+
const blockNumberBeforeReservation = reservation.first.subn(1);
|
|
240
|
+
|
|
241
|
+
const blockBeforeReservation = this.getBlockByNumber(
|
|
242
|
+
blockNumberBeforeReservation
|
|
243
|
+
);
|
|
244
|
+
assertHardhatInvariant(
|
|
245
|
+
blockBeforeReservation !== undefined,
|
|
246
|
+
`Reservation after block ${blockNumberBeforeReservation.toString()} cannot be created because that block does not exist`
|
|
247
|
+
);
|
|
248
|
+
|
|
249
|
+
const previousTimestamp = this.isReservedBlock(blockNumberBeforeReservation)
|
|
250
|
+
? this._calculateTimestampForReservedBlock(blockNumberBeforeReservation)
|
|
251
|
+
: blockBeforeReservation.header.timestamp;
|
|
252
|
+
|
|
253
|
+
return previousTimestamp.add(
|
|
254
|
+
reservation.interval.mul(blockNumber.sub(reservation.first).addn(1))
|
|
255
|
+
);
|
|
256
|
+
}
|
|
113
257
|
}
|
|
@@ -1,60 +1,50 @@
|
|
|
1
1
|
import { Block } from "@ethereumjs/block";
|
|
2
|
+
import Common from "@ethereumjs/common";
|
|
2
3
|
import { TypedTransaction } from "@ethereumjs/tx";
|
|
3
4
|
import { BN, zeros } from "ethereumjs-util";
|
|
4
5
|
|
|
5
|
-
import {
|
|
6
|
+
import { BlockchainBase } from "./BlockchainBase";
|
|
6
7
|
import { FilterParams } from "./node-types";
|
|
7
|
-
import { RpcLogOutput
|
|
8
|
+
import { RpcLogOutput } from "./output";
|
|
8
9
|
import { HardhatBlockchainInterface } from "./types/HardhatBlockchainInterface";
|
|
9
10
|
|
|
10
11
|
/* eslint-disable @nomiclabs/hardhat-internal-rules/only-hardhat-error */
|
|
11
12
|
|
|
12
|
-
export class HardhatBlockchain
|
|
13
|
-
|
|
13
|
+
export class HardhatBlockchain
|
|
14
|
+
extends BlockchainBase
|
|
15
|
+
implements HardhatBlockchainInterface
|
|
16
|
+
{
|
|
14
17
|
private _length = 0;
|
|
15
18
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
if (block === undefined) {
|
|
19
|
-
throw new Error("No block available");
|
|
20
|
-
}
|
|
21
|
-
return block;
|
|
19
|
+
constructor(common: Common) {
|
|
20
|
+
super(common);
|
|
22
21
|
}
|
|
23
22
|
|
|
24
|
-
public
|
|
25
|
-
|
|
26
|
-
): Promise<Block | null> {
|
|
27
|
-
if (typeof blockHashOrNumber === "number") {
|
|
28
|
-
return this._data.getBlockByNumber(new BN(blockHashOrNumber)) ?? null;
|
|
29
|
-
}
|
|
30
|
-
if (BN.isBN(blockHashOrNumber)) {
|
|
31
|
-
return this._data.getBlockByNumber(blockHashOrNumber) ?? null;
|
|
32
|
-
}
|
|
33
|
-
return this._data.getBlockByHash(blockHashOrNumber) ?? null;
|
|
23
|
+
public getLatestBlockNumber(): BN {
|
|
24
|
+
return new BN(this._length - 1);
|
|
34
25
|
}
|
|
35
26
|
|
|
36
27
|
public async addBlock(block: Block): Promise<Block> {
|
|
37
28
|
this._validateBlock(block);
|
|
38
|
-
const totalDifficulty = this._computeTotalDifficulty(block);
|
|
29
|
+
const totalDifficulty = await this._computeTotalDifficulty(block);
|
|
39
30
|
this._data.addBlock(block, totalDifficulty);
|
|
40
31
|
this._length += 1;
|
|
41
32
|
return block;
|
|
42
33
|
}
|
|
43
34
|
|
|
44
|
-
public
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
this.deleteBlock(blockHash);
|
|
35
|
+
public reserveBlocks(
|
|
36
|
+
count: BN,
|
|
37
|
+
interval: BN,
|
|
38
|
+
previousBlockStateRoot: Buffer,
|
|
39
|
+
previousBlockTotalDifficulty: BN
|
|
40
|
+
) {
|
|
41
|
+
super.reserveBlocks(
|
|
42
|
+
count,
|
|
43
|
+
interval,
|
|
44
|
+
previousBlockStateRoot,
|
|
45
|
+
previousBlockTotalDifficulty
|
|
46
|
+
);
|
|
47
|
+
this._length = this._length + count.toNumber();
|
|
58
48
|
}
|
|
59
49
|
|
|
60
50
|
public deleteLaterBlocks(block: Block): void {
|
|
@@ -62,12 +52,8 @@ export class HardhatBlockchain implements HardhatBlockchainInterface {
|
|
|
62
52
|
if (actual === undefined) {
|
|
63
53
|
throw new Error("Invalid block");
|
|
64
54
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
);
|
|
68
|
-
if (nextBlock !== undefined) {
|
|
69
|
-
this._delBlock(nextBlock);
|
|
70
|
-
}
|
|
55
|
+
|
|
56
|
+
this._delBlock(actual.header.number.addn(1));
|
|
71
57
|
}
|
|
72
58
|
|
|
73
59
|
public async getTotalDifficulty(blockHash: Buffer): Promise<BN> {
|
|
@@ -84,12 +70,6 @@ export class HardhatBlockchain implements HardhatBlockchainInterface {
|
|
|
84
70
|
return this.getLocalTransaction(transactionHash);
|
|
85
71
|
}
|
|
86
72
|
|
|
87
|
-
public getLocalTransaction(
|
|
88
|
-
transactionHash: Buffer
|
|
89
|
-
): TypedTransaction | undefined {
|
|
90
|
-
return this._data.getTransaction(transactionHash);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
73
|
public async getBlockByTransactionHash(
|
|
94
74
|
transactionHash: Buffer
|
|
95
75
|
): Promise<Block | null> {
|
|
@@ -101,36 +81,21 @@ export class HardhatBlockchain implements HardhatBlockchainInterface {
|
|
|
101
81
|
return this._data.getTransactionReceipt(transactionHash) ?? null;
|
|
102
82
|
}
|
|
103
83
|
|
|
104
|
-
public addTransactionReceipts(receipts: RpcReceiptOutput[]) {
|
|
105
|
-
for (const receipt of receipts) {
|
|
106
|
-
this._data.addTransactionReceipt(receipt);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
84
|
public async getLogs(filterParams: FilterParams): Promise<RpcLogOutput[]> {
|
|
111
85
|
return this._data.getLogs(filterParams);
|
|
112
86
|
}
|
|
113
87
|
|
|
114
|
-
public iterator(
|
|
115
|
-
_name: string,
|
|
116
|
-
_onBlock: (block: Block, reorg: boolean) => void | Promise<void>
|
|
117
|
-
): Promise<number | void> {
|
|
118
|
-
throw new Error("Method not implemented.");
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
public async getBaseFee(): Promise<BN> {
|
|
122
|
-
const latestBlock = await this.getLatestBlock();
|
|
123
|
-
return latestBlock.header.calcNextBaseFee();
|
|
124
|
-
}
|
|
125
|
-
|
|
126
88
|
private _validateBlock(block: Block) {
|
|
127
89
|
const blockNumber = block.header.number.toNumber();
|
|
128
90
|
const parentHash = block.header.parentHash;
|
|
129
91
|
const parent = this._data.getBlockByNumber(new BN(blockNumber - 1));
|
|
130
92
|
|
|
131
93
|
if (this._length !== blockNumber) {
|
|
132
|
-
throw new Error(
|
|
94
|
+
throw new Error(
|
|
95
|
+
`Invalid block number ${blockNumber}. Expected ${this._length}.`
|
|
96
|
+
);
|
|
133
97
|
}
|
|
98
|
+
|
|
134
99
|
if (
|
|
135
100
|
(blockNumber === 0 && !parentHash.equals(zeros(32))) ||
|
|
136
101
|
(blockNumber > 0 &&
|
|
@@ -141,26 +106,8 @@ export class HardhatBlockchain implements HardhatBlockchainInterface {
|
|
|
141
106
|
}
|
|
142
107
|
}
|
|
143
108
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
return difficulty;
|
|
148
|
-
}
|
|
149
|
-
const parentTD = this._data.getTotalDifficulty(block.header.parentHash);
|
|
150
|
-
if (parentTD === undefined) {
|
|
151
|
-
throw new Error("This should never happen");
|
|
152
|
-
}
|
|
153
|
-
return parentTD.add(difficulty);
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
private _delBlock(block: Block): void {
|
|
157
|
-
const blockNumber = block.header.number.toNumber();
|
|
158
|
-
for (let i = blockNumber; i < this._length; i++) {
|
|
159
|
-
const current = this._data.getBlockByNumber(new BN(i));
|
|
160
|
-
if (current !== undefined) {
|
|
161
|
-
this._data.removeBlock(current);
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
this._length = blockNumber;
|
|
109
|
+
protected _delBlock(blockNumber: BN): void {
|
|
110
|
+
super._delBlock(blockNumber);
|
|
111
|
+
this._length = blockNumber.toNumber();
|
|
165
112
|
}
|
|
166
113
|
}
|
|
@@ -9,7 +9,7 @@ import { RpcTransactionReceipt } from "../../../core/jsonrpc/types/output/receip
|
|
|
9
9
|
import { RpcTransaction } from "../../../core/jsonrpc/types/output/transaction";
|
|
10
10
|
import { InternalError } from "../../../core/providers/errors";
|
|
11
11
|
import { JsonRpcClient } from "../../jsonrpc/client";
|
|
12
|
-
import {
|
|
12
|
+
import { BlockchainBase } from "../BlockchainBase";
|
|
13
13
|
import { FilterParams } from "../node-types";
|
|
14
14
|
import {
|
|
15
15
|
remoteReceiptToRpcReceiptOutput,
|
|
@@ -29,28 +29,35 @@ import { rpcToTxData } from "./rpcToTxData";
|
|
|
29
29
|
|
|
30
30
|
/* eslint-disable @nomiclabs/hardhat-internal-rules/only-hardhat-error */
|
|
31
31
|
|
|
32
|
-
export class ForkBlockchain
|
|
33
|
-
|
|
32
|
+
export class ForkBlockchain
|
|
33
|
+
extends BlockchainBase
|
|
34
|
+
implements HardhatBlockchainInterface
|
|
35
|
+
{
|
|
34
36
|
private _latestBlockNumber = this._forkBlockNumber;
|
|
35
37
|
|
|
36
38
|
constructor(
|
|
37
39
|
private _jsonRpcClient: JsonRpcClient,
|
|
38
40
|
private _forkBlockNumber: BN,
|
|
39
|
-
|
|
40
|
-
) {
|
|
41
|
+
common: Common
|
|
42
|
+
) {
|
|
43
|
+
super(common);
|
|
44
|
+
}
|
|
41
45
|
|
|
42
|
-
public
|
|
43
|
-
|
|
44
|
-
if (block === null) {
|
|
45
|
-
throw new Error("Block not found");
|
|
46
|
-
}
|
|
47
|
-
return block;
|
|
46
|
+
public getLatestBlockNumber(): BN {
|
|
47
|
+
return this._latestBlockNumber;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
public async getBlock(
|
|
51
51
|
blockHashOrNumber: Buffer | number | BN
|
|
52
52
|
): Promise<Block | null> {
|
|
53
|
-
|
|
53
|
+
if (
|
|
54
|
+
(typeof blockHashOrNumber === "number" || BN.isBN(blockHashOrNumber)) &&
|
|
55
|
+
this._data.isReservedBlock(new BN(blockHashOrNumber))
|
|
56
|
+
) {
|
|
57
|
+
this._data.fulfillBlockReservation(new BN(blockHashOrNumber));
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
let block: Block | undefined | null;
|
|
54
61
|
if (Buffer.isBuffer(blockHashOrNumber)) {
|
|
55
62
|
block = await this._getBlockByHash(blockHashOrNumber);
|
|
56
63
|
return block ?? null;
|
|
@@ -63,7 +70,11 @@ export class ForkBlockchain implements HardhatBlockchainInterface {
|
|
|
63
70
|
public async addBlock(block: Block): Promise<Block> {
|
|
64
71
|
const blockNumber = new BN(block.header.number);
|
|
65
72
|
if (!blockNumber.eq(this._latestBlockNumber.addn(1))) {
|
|
66
|
-
throw new Error(
|
|
73
|
+
throw new Error(
|
|
74
|
+
`Invalid block number ${blockNumber.toNumber()}. Expected ${this._latestBlockNumber
|
|
75
|
+
.addn(1)
|
|
76
|
+
.toNumber()}`
|
|
77
|
+
);
|
|
67
78
|
}
|
|
68
79
|
|
|
69
80
|
// When forking a network whose consensus is not the classic PoW,
|
|
@@ -82,20 +93,19 @@ export class ForkBlockchain implements HardhatBlockchainInterface {
|
|
|
82
93
|
return block;
|
|
83
94
|
}
|
|
84
95
|
|
|
85
|
-
public
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
this.deleteBlock(blockHash);
|
|
96
|
+
public reserveBlocks(
|
|
97
|
+
count: BN,
|
|
98
|
+
interval: BN,
|
|
99
|
+
previousBlockStateRoot: Buffer,
|
|
100
|
+
previousBlockTotalDifficulty: BN
|
|
101
|
+
) {
|
|
102
|
+
super.reserveBlocks(
|
|
103
|
+
count,
|
|
104
|
+
interval,
|
|
105
|
+
previousBlockStateRoot,
|
|
106
|
+
previousBlockTotalDifficulty
|
|
107
|
+
);
|
|
108
|
+
this._latestBlockNumber = this._latestBlockNumber.add(count);
|
|
99
109
|
}
|
|
100
110
|
|
|
101
111
|
public deleteLaterBlocks(block: Block): void {
|
|
@@ -109,10 +119,8 @@ export class ForkBlockchain implements HardhatBlockchainInterface {
|
|
|
109
119
|
if (this._forkBlockNumber.gte(nextBlockNumber)) {
|
|
110
120
|
throw new Error("Cannot delete remote block");
|
|
111
121
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
return this._delBlock(nextBlock);
|
|
115
|
-
}
|
|
122
|
+
|
|
123
|
+
this._delBlock(nextBlockNumber);
|
|
116
124
|
}
|
|
117
125
|
|
|
118
126
|
public async getTotalDifficulty(blockHash: Buffer): Promise<BN> {
|
|
@@ -144,12 +152,6 @@ export class ForkBlockchain implements HardhatBlockchainInterface {
|
|
|
144
152
|
return tx;
|
|
145
153
|
}
|
|
146
154
|
|
|
147
|
-
public getLocalTransaction(
|
|
148
|
-
transactionHash: Buffer
|
|
149
|
-
): TypedTransaction | undefined {
|
|
150
|
-
return this._data.getTransaction(transactionHash);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
155
|
public async getBlockByTransactionHash(
|
|
154
156
|
transactionHash: Buffer
|
|
155
157
|
): Promise<Block | null> {
|
|
@@ -185,12 +187,6 @@ export class ForkBlockchain implements HardhatBlockchainInterface {
|
|
|
185
187
|
return null;
|
|
186
188
|
}
|
|
187
189
|
|
|
188
|
-
public addTransactionReceipts(receipts: RpcReceiptOutput[]) {
|
|
189
|
-
for (const receipt of receipts) {
|
|
190
|
-
this._data.addTransactionReceipt(receipt);
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
|
|
194
190
|
public getForkBlockNumber() {
|
|
195
191
|
return this._forkBlockNumber;
|
|
196
192
|
}
|
|
@@ -220,18 +216,6 @@ export class ForkBlockchain implements HardhatBlockchainInterface {
|
|
|
220
216
|
return this._data.getLogs(filterParams);
|
|
221
217
|
}
|
|
222
218
|
|
|
223
|
-
public iterator(
|
|
224
|
-
_name: string,
|
|
225
|
-
_onBlock: (block: Block, reorg: boolean) => void | Promise<void>
|
|
226
|
-
): Promise<number | void> {
|
|
227
|
-
throw new Error("Method not implemented.");
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
public async getBaseFee(): Promise<BN> {
|
|
231
|
-
const latestBlock = await this.getLatestBlock();
|
|
232
|
-
return latestBlock.header.calcNextBaseFee();
|
|
233
|
-
}
|
|
234
|
-
|
|
235
219
|
private async _getBlockByHash(blockHash: Buffer) {
|
|
236
220
|
const block = this._data.getBlockByHash(blockHash);
|
|
237
221
|
if (block !== undefined) {
|
|
@@ -245,8 +229,8 @@ export class ForkBlockchain implements HardhatBlockchainInterface {
|
|
|
245
229
|
if (blockNumber.gt(this._latestBlockNumber)) {
|
|
246
230
|
return undefined;
|
|
247
231
|
}
|
|
248
|
-
const block =
|
|
249
|
-
if (block !==
|
|
232
|
+
const block = await super.getBlock(blockNumber);
|
|
233
|
+
if (block !== null) {
|
|
250
234
|
return block;
|
|
251
235
|
}
|
|
252
236
|
const rpcBlock = await this._jsonRpcClient.getBlockByNumber(
|
|
@@ -319,41 +303,12 @@ export class ForkBlockchain implements HardhatBlockchainInterface {
|
|
|
319
303
|
return block;
|
|
320
304
|
}
|
|
321
305
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
const blockNumber = new BN(block.header.number);
|
|
325
|
-
if (blockNumber.eqn(0)) {
|
|
326
|
-
return difficulty;
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
const parentBlock =
|
|
330
|
-
this._data.getBlockByNumber(blockNumber.subn(1)) ??
|
|
331
|
-
(await this.getBlock(blockNumber.subn(1)));
|
|
332
|
-
if (parentBlock === null) {
|
|
333
|
-
throw new Error("Block not found");
|
|
334
|
-
}
|
|
335
|
-
const parentHash = parentBlock.hash();
|
|
336
|
-
const parentTD = this._data.getTotalDifficulty(parentHash);
|
|
337
|
-
if (parentTD === undefined) {
|
|
338
|
-
throw new Error("This should never happen");
|
|
339
|
-
}
|
|
340
|
-
return parentTD.add(difficulty);
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
private _delBlock(block: Block): void {
|
|
344
|
-
if (new BN(block.header.number).lte(this._forkBlockNumber)) {
|
|
306
|
+
protected _delBlock(blockNumber: BN): void {
|
|
307
|
+
if (blockNumber.lte(this._forkBlockNumber)) {
|
|
345
308
|
throw new Error("Cannot delete remote block");
|
|
346
309
|
}
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
for (let i = blockNumber; this._latestBlockNumber.gten(i); i++) {
|
|
350
|
-
const current = this._data.getBlockByNumber(new BN(i));
|
|
351
|
-
if (current !== undefined) {
|
|
352
|
-
this._data.removeBlock(current);
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
this._latestBlockNumber = new BN(blockNumber).subn(1);
|
|
310
|
+
super._delBlock(blockNumber);
|
|
311
|
+
this._latestBlockNumber = blockNumber.subn(1);
|
|
357
312
|
}
|
|
358
313
|
|
|
359
314
|
private _processRemoteTransaction(rpcTransaction: RpcTransaction | null) {
|
|
@@ -325,7 +325,7 @@ export class EthModule {
|
|
|
325
325
|
}
|
|
326
326
|
|
|
327
327
|
private async _blockNumberAction(): Promise<string> {
|
|
328
|
-
const blockNumber =
|
|
328
|
+
const blockNumber = this._node.getLatestBlockNumber();
|
|
329
329
|
return numberToRpcQuantity(blockNumber);
|
|
330
330
|
}
|
|
331
331
|
|
|
@@ -1405,7 +1405,7 @@ export class EthModule {
|
|
|
1405
1405
|
}
|
|
1406
1406
|
|
|
1407
1407
|
if (block === undefined) {
|
|
1408
|
-
const latestBlock =
|
|
1408
|
+
const latestBlock = this._node.getLatestBlockNumber();
|
|
1409
1409
|
|
|
1410
1410
|
throw new InvalidInputError(
|
|
1411
1411
|
`Received invalid block tag ${this._newBlockTagToString(
|
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
InvalidInputError,
|
|
27
27
|
MethodNotFoundError,
|
|
28
28
|
} from "../../../core/providers/errors";
|
|
29
|
+
import { optional } from "../../../util/io-ts";
|
|
29
30
|
import { MessageTrace } from "../../stack-traces/message-trace";
|
|
30
31
|
import { HardhatNode } from "../node";
|
|
31
32
|
import { ForkConfig, MineBlockResult } from "../node-types";
|
|
@@ -111,6 +112,9 @@ export class HardhatModule {
|
|
|
111
112
|
|
|
112
113
|
case "hardhat_setCoinbase":
|
|
113
114
|
return this._setCoinbaseAction(...this._setCoinbaseParams(params));
|
|
115
|
+
|
|
116
|
+
case "hardhat_mine":
|
|
117
|
+
return this._hardhatMineAction(...this._hardhatMineParams(params));
|
|
114
118
|
}
|
|
115
119
|
|
|
116
120
|
throw new MethodNotFoundError(`Method ${method} not found`);
|
|
@@ -173,14 +177,14 @@ export class HardhatModule {
|
|
|
173
177
|
|
|
174
178
|
const isEmpty = result.block.transactions.length === 0;
|
|
175
179
|
if (isEmpty) {
|
|
176
|
-
this._logger.
|
|
180
|
+
this._logger.printIntervalMinedBlockNumber(
|
|
177
181
|
blockNumber,
|
|
178
182
|
isEmpty,
|
|
179
183
|
result.block.header.baseFeePerGas
|
|
180
184
|
);
|
|
181
185
|
} else {
|
|
182
|
-
await this._logBlock(result);
|
|
183
|
-
this._logger.
|
|
186
|
+
await this._logBlock(result, { isIntervalMined: true });
|
|
187
|
+
this._logger.printIntervalMinedBlockNumber(blockNumber, isEmpty);
|
|
184
188
|
const printedSomething = this._logger.printLogs();
|
|
185
189
|
if (printedSomething) {
|
|
186
190
|
this._logger.printEmptyLine();
|
|
@@ -360,7 +364,31 @@ export class HardhatModule {
|
|
|
360
364
|
return true;
|
|
361
365
|
}
|
|
362
366
|
|
|
363
|
-
|
|
367
|
+
// hardhat_mine
|
|
368
|
+
private async _hardhatMineAction(blockCount?: BN, interval?: BN) {
|
|
369
|
+
const mineBlockResults = await this._node.mineBlocks(blockCount, interval);
|
|
370
|
+
|
|
371
|
+
for (const [i, result] of mineBlockResults.entries()) {
|
|
372
|
+
await this._logHardhatMinedBlock(result);
|
|
373
|
+
|
|
374
|
+
// print an empty line after logging blocks with txs,
|
|
375
|
+
// unless it's the last logged block
|
|
376
|
+
const isEmpty = result.block.transactions.length === 0;
|
|
377
|
+
if (!isEmpty && i + 1 < mineBlockResults.length) {
|
|
378
|
+
this._logger.logEmptyLine();
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
return true;
|
|
383
|
+
}
|
|
384
|
+
private _hardhatMineParams(params: any[]): [BN | undefined, BN | undefined] {
|
|
385
|
+
return validateParams(params, optional(rpcQuantity), optional(rpcQuantity));
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
private async _logBlock(
|
|
389
|
+
result: MineBlockResult,
|
|
390
|
+
{ isIntervalMined }: { isIntervalMined: boolean }
|
|
391
|
+
) {
|
|
364
392
|
const { block, traces } = result;
|
|
365
393
|
|
|
366
394
|
const codes: Buffer[] = [];
|
|
@@ -373,7 +401,11 @@ export class HardhatModule {
|
|
|
373
401
|
codes.push(code);
|
|
374
402
|
}
|
|
375
403
|
|
|
376
|
-
|
|
404
|
+
if (isIntervalMined) {
|
|
405
|
+
this._logger.logIntervalMinedBlock(result, codes);
|
|
406
|
+
} else {
|
|
407
|
+
this._logger.logMinedBlock(result, codes);
|
|
408
|
+
}
|
|
377
409
|
|
|
378
410
|
for (const txTrace of traces) {
|
|
379
411
|
await this._runHardhatNetworkMessageTraceHooks(txTrace.trace, false);
|
|
@@ -392,4 +424,18 @@ export class HardhatModule {
|
|
|
392
424
|
await hook(trace, isCall);
|
|
393
425
|
}
|
|
394
426
|
}
|
|
427
|
+
|
|
428
|
+
private async _logHardhatMinedBlock(result: MineBlockResult) {
|
|
429
|
+
const isEmpty = result.block.transactions.length === 0;
|
|
430
|
+
const blockNumber = result.block.header.number.toNumber();
|
|
431
|
+
|
|
432
|
+
if (isEmpty) {
|
|
433
|
+
this._logger.logEmptyHardhatMinedBlock(
|
|
434
|
+
blockNumber,
|
|
435
|
+
result.block.header.baseFeePerGas
|
|
436
|
+
);
|
|
437
|
+
} else {
|
|
438
|
+
await this._logBlock(result, { isIntervalMined: false });
|
|
439
|
+
}
|
|
440
|
+
}
|
|
395
441
|
}
|