diff --git a/src/chains/ethereum/ethereum/src/blockchain.ts b/src/chains/ethereum/ethereum/src/blockchain.ts index aec91df3b6..658f84525e 100644 --- a/src/chains/ethereum/ethereum/src/blockchain.ts +++ b/src/chains/ethereum/ethereum/src/blockchain.ts @@ -1116,10 +1116,7 @@ export default class Blockchain extends Emittery { const to = hasToAddress ? new Address(transaction.to.toBuffer()) : null; const common = this.fallback - ? this.fallback.getCommonForBlockNumber( - this.common, - BigInt(transaction.block.header.number.toString()) - ) + ? this.fallback.getCommonForBlock(this.common, transaction.block.header) : this.common; const gasLeft = @@ -1253,10 +1250,7 @@ export default class Blockchain extends Emittery { } as any; const common = this.fallback - ? this.fallback.getCommonForBlockNumber( - this.common, - BigInt(block.header.number.toString()) - ) + ? this.fallback.getCommonForBlock(this.common, block.header) : this.common; // TODO: prefixCodeHashes should eventually be conditional diff --git a/src/chains/ethereum/ethereum/src/data-managers/block-manager.ts b/src/chains/ethereum/ethereum/src/data-managers/block-manager.ts index c2b0665898..8f2136b499 100644 --- a/src/chains/ethereum/ethereum/src/data-managers/block-manager.ts +++ b/src/chains/ethereum/ethereum/src/data-managers/block-manager.ts @@ -8,6 +8,7 @@ import { BlockRawTransaction, EthereumRawBlock, EthereumRawBlockHeader, + GanacheRawBlock, Head, serialize, WithdrawalRaw @@ -21,7 +22,7 @@ import { } from "@ganache/ethereum-transaction"; import { GanacheLevelUp } from "../database"; import { Ethereum } from "../api-types"; -import { encode } from "@ganache/rlp"; +import { decode, encode } from "@ganache/rlp"; const LATEST_INDEX_KEY = BUFFER_ZERO; @@ -171,10 +172,10 @@ export default class BlockManager extends Manager { if (json == null) { return null; } else { - const common = fallback.getCommonForBlockNumber( - this.#common, - BigInt(json.number) - ); + const common = fallback.getCommonForBlock(this.#common, { + number: BigInt(json.number), + timestamp: BigInt(json.timestamp) + }); return BlockManager.rawFromJSON(json, common); } @@ -226,12 +227,13 @@ export default class BlockManager extends Manager { true ]); if (json) { - const blockNumber = BigInt(json.number); - if (blockNumber <= fallback.blockNumber.toBigInt()) { - const common = fallback.getCommonForBlockNumber( - this.#common, - blockNumber - ); + const number = BigInt(json.number); + const timestamp = BigInt(json.timestamp); + if (number <= fallback.blockNumber.toBigInt()) { + const common = fallback.getCommonForBlock(this.#common, { + number, + timestamp + }); return new Block(BlockManager.rawFromJSON(json, common), common); } } @@ -272,9 +274,14 @@ export default class BlockManager extends Manager { if (fallback) { const block = await this.fromFallback(blockNumber); if (block) { + const header: EthereumRawBlockHeader = + decode(block)[0]; return new Block( block, - fallback.getCommonForBlockNumber(common, blockNumber.toBigInt()) + fallback.getCommonForBlock(common, { + number: blockNumber.toBigInt(), + timestamp: Quantity.toBigInt(header[11]) + }) ); } } @@ -319,10 +326,10 @@ export default class BlockManager extends Manager { { disableCache: true } ); if (json) { - const common = fallback.getCommonForBlockNumber( - this.#common, - BigInt(json.number) - ); + const common = fallback.getCommonForBlock(this.#common, { + number: BigInt(json.number), + timestamp: BigInt(json.timestamp) + }); return new Block(BlockManager.rawFromJSON(json, common), common); } } else { diff --git a/src/chains/ethereum/ethereum/src/data-managers/transaction-manager.ts b/src/chains/ethereum/ethereum/src/data-managers/transaction-manager.ts index 0bea334ca7..916dda5f02 100644 --- a/src/chains/ethereum/ethereum/src/data-managers/transaction-manager.ts +++ b/src/chains/ethereum/ethereum/src/data-managers/transaction-manager.ts @@ -65,10 +65,17 @@ export default class TransactionManager extends Manager { index.toBuffer(), Quantity.toBuffer(tx.gasPrice) ]; - const common = fallback.getCommonForBlockNumber( - fallback.common, - blockNumber.toBigInt() - ); + const block = await fallback.request("eth_getBlockByNumber", [ + blockNumber.toString(), + false + ]); + if (block == null) return null; + + const common = fallback.getCommonForBlock(fallback.common, { + number: blockNumber.toBigInt(), + timestamp: Quantity.toBigInt(block.timestamp) + }); + const runTx = TransactionFactory.fromRpc(tx, common, extra); return runTx.serializeForDb(blockHash, blockNumber, index); }; diff --git a/src/chains/ethereum/ethereum/src/forking/cache.ts b/src/chains/ethereum/ethereum/src/forking/cache.ts index cb2da99fea..50f63243ac 100644 --- a/src/chains/ethereum/ethereum/src/forking/cache.ts +++ b/src/chains/ethereum/ethereum/src/forking/cache.ts @@ -9,10 +9,16 @@ export class ForkCache extends Cache { * Looks up address in underlying trie. * @param address - Address of account */ - const lookupAccount = async (address: Address) => { + const lookupAccount: ( + address: Address + ) => Promise = async (address: Address) => { const rlp = await (trie as ForkTrie).get(address.buf); - return rlp ? Account.fromRlpSerializedAccount(rlp) : new Account(); - } - super({ getCb: lookupAccount, putCb: trie.put.bind(trie), deleteCb: trie.del.bind(trie) }); + return rlp ? Account.fromRlpSerializedAccount(rlp) : undefined; + }; + super({ + getCb: lookupAccount, + putCb: trie.put.bind(trie), + deleteCb: trie.del.bind(trie) + }); } } diff --git a/src/chains/ethereum/ethereum/src/forking/fork.ts b/src/chains/ethereum/ethereum/src/forking/fork.ts index 054beeca29..6b91b4473c 100644 --- a/src/chains/ethereum/ethereum/src/forking/fork.ts +++ b/src/chains/ethereum/ethereum/src/forking/fork.ts @@ -226,10 +226,12 @@ export class Fork { cacheProm, this.#setCommonFromChain(chainIdPromise) ]); - const common = this.getCommonForBlockNumber( - this.common, - this.blockNumber.toBigInt() - ); + + const blockFromFallback = await fetchBlock(this, this.blockNumber); + const timestamp = BigInt(blockFromFallback.timestamp); + const number = BigInt(blockFromFallback.number); + + const common = this.getCommonForBlock(this.common, { timestamp, number }); this.block = new Block(BlockManager.rawFromJSON(block, common), common); if (!chainOptions.time && minerOptions.timestampIncrement !== "clock") { chainOptions.time = new Date( @@ -238,6 +240,7 @@ export class Fork { 1000 ); } + if (cache) await this.initCache(cache); } private async initCache(cache: PersistentCache) { @@ -275,18 +278,11 @@ export class Fork { : this.blockNumber; } - /** - * If the `blockNumber` is before our `fork.blockNumber`, return a `Common` - * instance, applying the rules from the remote chain's `common` via its - * original `chainId`. If the remote chain's `chainId` is now "known", return - * a `Common` with our local `common`'s rules applied, but with the remote - * chain's `chainId`. If the block is greater than or equal to our - * `fork.blockNumber` return `common`. - * @param common - - * @param blockNumber - - */ - public getCommonForBlockNumber(common: Common, blockNumber: BigInt) { - if (blockNumber <= this.blockNumber.toBigInt()) { + public getCommonForBlock( + common: Common, + block: { number: bigint; timestamp: bigint } + ): Common { + if (block.number <= this.blockNumber.toBigInt()) { // we are at or before our fork block let forkCommon: Common; @@ -295,11 +291,19 @@ export class Fork { let hardfork; // hardforks are iterated from earliest to latest for (const hf of common.hardforks()) { - if (hf.block === null) continue; - if (blockNumber >= BigInt(hf.block)) { - hardfork = hf.name; - } else { - break; + if (hf.timestamp) { + const hfTimestamp = BigInt(hf.timestamp); + if (block.timestamp >= hfTimestamp) { + hardfork = hf.name; + } else { + break; + } + } else if (hf.block) { + if (block.number >= BigInt(hf.block)) { + hardfork = hf.name; + } else { + break; + } } } forkCommon = new Common({ chain: this.chainId, hardfork });