diff --git a/src/chains/ethereum/ethereum/src/api.ts b/src/chains/ethereum/ethereum/src/api.ts index c6d02f0901..9b3491367a 100644 --- a/src/chains/ethereum/ethereum/src/api.ts +++ b/src/chains/ethereum/ethereum/src/api.ts @@ -59,12 +59,14 @@ type TransactionSimulationTransaction = Ethereum.Transaction & { traceTypes: string[]; }; -type TraceType = "Full" | "None"; +type TraceType = "full" | "call" | "none"; +type GasEstimateType = "full" | "call-depth" | "none"; type TransactionSimulationArgs = { transactions: TransactionSimulationTransaction[]; overrides?: Ethereum.Call.Overrides; block?: QUANTITY | Ethereum.Tag; trace?: TraceType; + gasEstimation?: GasEstimateType; }; type Log = [address: Address, topics: DATA[], data: DATA]; @@ -115,11 +117,13 @@ type TransactionSimulationResult = { stateChanges: StateChange[]; receipts?: Data[]; trace?: TraceEntry[]; + gasEstimate?: Quantity; }; -type InternalTransactionSimulationResult = { +type InternalTransactionSimulationResult = { result: any; gasBreakdown: any; + gasEstimate?: bigint; storageChanges: { address: Address; key: Buffer; @@ -130,14 +134,12 @@ type InternalTransactionSimulationResult = { Buffer, [[Buffer, Buffer, Buffer, Buffer], [Buffer, Buffer, Buffer, Buffer]] >; - trace: HasTrace extends true - ? { - opcode: Buffer; - pc: number; - type: string; - stack: Buffer[]; - }[] - : never; + trace?: { + opcode: Buffer; + pc: number; + type: string; + stack: Buffer[]; + }[]; }; async function simulateTransaction( @@ -146,13 +148,21 @@ async function simulateTransaction( transactions: Ethereum.Call.Transaction[], blockNumber: QUANTITY | Ethereum.Tag = Tag.latest, overrides: Ethereum.Call.Overrides = {}, - includeTrace: boolean = false -): Promise[]> { - // EVMResult - const common = blockchain.common; + includeTrace: boolean = false, + includeGasEstimate: boolean = false +): Promise { const blocks = blockchain.blocks; const parentBlock = await blocks.get(blockNumber); const parentHeader = parentBlock.header; + // EVMResult + const simulationBlockNumber = parentHeader.number.toBigInt() + 1n; + const common = blockchain.fallback + ? blockchain.fallback.getCommonForBlockNumber( + blockchain.common, + simulationBlockNumber + ) + : blockchain.common; + common.setHardfork("shanghai"); let cummulativeGas = 0n; @@ -256,13 +266,10 @@ async function simulateTransaction( // todo: calculate baseFeePerGas const baseFeePerGasBigInt = parentBlock.header.baseFeePerGas.toBigInt(); const timestamp = Quantity.from(parentHeader.timestamp.toBigInt() + incr); - const simulationBlockNumber = Quantity.from( - parentHeader.number.toNumber() + 1 - ); const block = new RuntimeBlock( - blockchain.common, - simulationBlockNumber, + common, + Quantity.from(simulationBlockNumber), parentBlock.hash(), blockchain.coinbase, Quantity.from(cummulativeGas), @@ -276,11 +283,13 @@ async function simulateTransaction( ); const results = blockchain.simulateTransactions( + common, simulationTransactions, block, parentBlock, overrides, - includeTrace + includeTrace, + includeGasEstimate ); return results; @@ -1149,15 +1158,33 @@ export default class EthereumApi implements Api { const parentHeader = parentBlock.header; const options = this.#options; + const common = blockchain.fallback + ? blockchain.fallback.getCommonForBlockNumber( + blockchain.common, + parentBlock.header.number.toBigInt() + ) + : blockchain.common; + common.setHardfork("shanghai"); + const generateVM = async () => { // note(hack): blockchain.vm.copy() doesn't work so we just do it this way // /shrug + const trie = blockchain.trie.copy(false); + trie.setContext( + parentBlock.header.stateRoot.toBuffer(), + null, + parentBlock.header.number + ); const vm = await blockchain.createVmFromStateTrie( - blockchain.trie.copy(false), + trie, options.chain.allowUnlimitedContractSize, options.chain.allowUnlimitedInitCodeSize, - false + false, + common ); + await vm.eei.checkpoint(); + //@ts-ignore + vm.eei.commit = () => {}; return vm; }; return new Promise((resolve, reject) => { @@ -1192,7 +1219,11 @@ export default class EthereumApi implements Api { tx: tx.toVmTransaction(), block, skipBalance: true, - skipNonce: true + skipNonce: true, + //@ts-ignore + skipBlockGasLimitValidation: true, + //@ts-ignore + skipHardForkValidation: true }; estimateGas( generateVM, @@ -2987,7 +3018,7 @@ export default class EthereumApi implements Api { } /** - * This only simulates the first transaction supplied by args.transactions + * Presently only supports "Call" trace ("Full" trace will be treated as "Call"); * @param {TransactionSimulationArgs} args * @returns Promise */ @@ -2999,6 +3030,10 @@ export default class EthereumApi implements Api { const blockNumber = args.block || "latest"; const overrides = args.overrides; + const includeTrace = args.trace === "full" || args.trace === "call"; + const includeGasEstimation = + args.gasEstimation === "full" || args.gasEstimation === "call-depth"; + //@ts-ignore const simulatedTransactionResults = await simulateTransaction( this.#blockchain, @@ -3006,11 +3041,19 @@ export default class EthereumApi implements Api { transactions, blockNumber, overrides, - args.trace === "Full" + includeTrace, + includeGasEstimation ); return simulatedTransactionResults.map( - ({ trace, gasBreakdown, result, storageChanges, stateChanges }) => { + ({ + trace, + gasBreakdown, + result, + storageChanges, + stateChanges, + gasEstimate + }) => { const parsedStorageChanges = storageChanges.map(change => ({ key: Data.from(change.key), address: Address.from(change.address.buf), @@ -3058,34 +3101,32 @@ export default class EthereumApi implements Api { error, returnValue, gas, + gasEstimate: gasEstimate ? Quantity.from(gasEstimate) : undefined, logs, //todo: populate receipts receipts: undefined, storageChanges: parsedStorageChanges, stateChanges: parsedStateChanges, - trace: - args.trace === "Full" - ? trace.map((t: any) => { - return { - opcode: Data.from(t.opcode), - type: t.type, - from: Address.from(t.from), - to: Address.from(t.to), - target: t.target, - value: - t.value === undefined - ? undefined - : Quantity.from(t.value), - input: Data.from(t.input), - decodedInput: t.decodedInput?.map(({ type, value }) => ({ - type, - // todo: some values will be Quantity rather - value: Data.from(value) - })), - pc: t.pc - }; - }) - : undefined + trace: includeTrace + ? trace.map((t: any) => { + return { + opcode: Data.from(t.opcode), + type: t.type, + from: Address.from(t.from), + to: Address.from(t.to), + target: t.target, + value: + t.value === undefined ? undefined : Quantity.from(t.value), + input: Data.from(t.input), + decodedInput: t.decodedInput?.map(({ type, value }) => ({ + type, + // todo: some values will be Quantity rather + value: Data.from(value) + })), + pc: t.pc + }; + }) + : undefined }; } ); diff --git a/src/chains/ethereum/ethereum/src/blockchain.ts b/src/chains/ethereum/ethereum/src/blockchain.ts index b29698bac8..2cb3114348 100644 --- a/src/chains/ethereum/ethereum/src/blockchain.ts +++ b/src/chains/ethereum/ethereum/src/blockchain.ts @@ -1,4 +1,4 @@ -import { rawDecode, rawEncode } from "ethereumjs-abi"; +import { rawDecode } from "ethereumjs-abi"; import { fourBytes } from "@ganache/4byte"; import { EOL } from "os"; import Miner, { Capacity } from "./miner/miner"; @@ -24,6 +24,7 @@ import { decode } from "@ganache/rlp"; import { KECCAK256_RLP } from "@ethereumjs/util"; import { Common } from "@ethereumjs/common"; import { EEI, VM } from "@ethereumjs/vm"; + import { EvmError as VmError, EvmErrorMessage as ERROR, @@ -50,7 +51,8 @@ import { calculateIntrinsicGas, InternalTransactionReceipt, VmTransaction, - TypedTransaction + TypedTransaction, + TransactionFactory } from "@ganache/ethereum-transaction"; import { Block, RuntimeBlock, Snapshots } from "@ganache/ethereum-block"; import { @@ -79,6 +81,7 @@ import { GanacheStateManager } from "./state-manager"; import { TrieDB } from "./trie-db"; import { Trie } from "@ethereumjs/trie"; import { Interpreter, RunState } from "@ethereumjs/evm/dist/interpreter"; +import estimateGas from "./helpers/gas-estimator"; const mclInitPromise = mcl.init(mcl.BLS12_381).then(() => { mcl.setMapToMode(mcl.IRTF); // set the right map mode; otherwise mapToG2 will return wrong values. @@ -1122,22 +1125,14 @@ export default class Blockchain extends Emittery { } public async simulateTransactions( + common, transactions: SimulationTransaction[], runtimeBlock: RuntimeBlock, parentBlock: Block, overrides: CallOverrides, - includeTrace: boolean + includeTrace: boolean, + includeGasEstimate: boolean ) { - //todo: getCommonForBlockNumber doesn't presently respect shanghai, so we just assume it's the same common as the fork - // this won't work as expected if simulating on blocks before shanghai. - const common = this.fallback - ? this.fallback.getCommonForBlockNumber( - this.common, - BigInt(runtimeBlock.header.number.toString()) - ) - : this.common; - common.setHardfork("shanghai"); - const stateTrie = this.trie.copy(false); stateTrie.setContext( parentBlock.header.stateRoot.toBuffer(), @@ -1176,8 +1171,6 @@ export default class Blockchain extends Emittery { [address: Address, key: BigInt, value: BigInt] >; - let gasLeft = runtimeBlock.header.gasLimit; - const runningEncodedAccounts = {}; const runningRawStorageSlots = {}; const results = new Array(transactions.length); @@ -1204,14 +1197,17 @@ export default class Blockchain extends Emittery { const to = hasToAddress ? new Address(transaction.to.toBuffer()) : null; const intrinsicGas = calculateIntrinsicGas(data, hasToAddress, common); - gasLeft -= transaction.gas.toBigInt(); + let gasLeft = transaction.gas.toBigInt() - intrinsicGas; if (gasLeft >= 0n) { const caller = transaction.from.toBuffer(); const callerAddress = new Address(caller); - if (common.isActivatedEIP(2929) && to) { - vm.eei.addWarmedAddress(to.buf); + if (common.isActivatedEIP(2929)) { + vm.eei.addWarmedAddress(caller); + if (to) { + vm.eei.addWarmedAddress(to.buf); + } } // If there are any overrides requested for eth_call, apply @@ -1359,12 +1355,12 @@ export default class Blockchain extends Emittery { caller: callerAddress, data: transaction.data && transaction.data.toBuffer(), gasPrice: transaction.gasPrice.toBigInt(), - gasLimit: transaction.gas.toBigInt(), + gasLimit: gasLeft, to, value: transaction.value == null ? 0n : transaction.value.toBigInt(), block: runtimeBlock as any }; - const result = await vm.evm.runCall(runCallArgs as any); + const result = await vm.evm.runCall(runCallArgs); // todo: this is always going to pull the "before" from before _all_ simulations // in order for this to be correct, we need to check all previously simulated transactions @@ -1381,10 +1377,7 @@ export default class Blockchain extends Emittery { if (beforeEncoded === undefined) { // we haven't changed this account in a previous simulation, need to get the original account addressBuf = Buffer.from(addressStr, "hex"); - beforeEncoded = await this.accounts.getRaw( - Address.from(addressBuf), - parentBlock.header.number.toBuffer() - ); + beforeEncoded = await beforeStateManager._trie.get(addressBuf); } const afterEncoded = i[1].val; if (!beforeEncoded.equals(afterEncoded)) { @@ -1459,6 +1452,91 @@ export default class Blockchain extends Emittery { stateChanges, trace }; + + if (includeGasEstimate) { + // gas estimate is required + + const generateVM = async () => { + // note(hack): blockchain.vm.copy() doesn't work so we just do it this way + // /shrug + const trie = stateTrie.copy(false); + // trie.setContext( + // parentBlock.header.stateRoot.toBuffer(), + // null, + // parentBlock.header.number + // ); + + const vm = await this.createVmFromStateTrie( + trie, + options.chain.allowUnlimitedContractSize, + options.chain.allowUnlimitedInitCodeSize, + false, + common + ); + await vm.eei.checkpoint(); + //@ts-ignore + vm.eei.commit = () => {}; + return vm; + }; + + const estimateProm: Promise = new Promise( + (resolve, reject) => { + const tx = TransactionFactory.fromRpc( + { + from: transaction.from?.toString(), + to: transaction.to?.toString(), + data: transaction.data?.toString(), + gas: transaction.gas?.toString(), + gasPrice: transaction.gasPrice?.toString(), + value: transaction.value?.toString() + //accesslists, + // maxFeePerGas: runtimeBlock.header.baseFeePerGas.toString() + } as any, + common + ); + + if (tx.from == null) { + tx.from = this.coinbase; + } + tx.gas = options.miner.callGasLimit; + + const block = new RuntimeBlock( + common, + Quantity.from(runtimeBlock.header.number), + Data.from(runtimeBlock.header.parentHash), + runtimeBlock.header.coinbase, + Quantity.from(runtimeBlock.header.gasLimit), + Quantity.Zero, + Quantity.from(runtimeBlock.header.timestamp), + Quantity.from(runtimeBlock.header.difficulty), + Quantity.from(runtimeBlock.header.totalDifficulty), + runtimeBlock.header.mixHash, + 0n, // no baseFeePerGas for estimates + KECCAK256_RLP + ); + + const runArgs = { + tx: tx.toVmTransaction(), + block, + skipBalance: true, + skipNonce: true, + skipBlockGasLimitValidation: true, + skipHardForkValidation: true + }; + estimateGas(generateVM, runArgs, (err: Error, result) => { + if (err) return void reject(err); + resolve(Quantity.from(result.gasEstimate)); + }); + } + ); + + try { + const gasEstimate = await estimateProm; + results[i].gasEstimate = gasEstimate?.toBigInt(); + } catch (e) { + console.error(e); + } + } } else { results[i] = { runState: { programCounter: 0 }, 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 7e3a4e405c..85c823b250 100644 --- a/src/chains/ethereum/ethereum/src/data-managers/block-manager.ts +++ b/src/chains/ethereum/ethereum/src/data-managers/block-manager.ts @@ -1,6 +1,6 @@ import Manager from "./manager"; import { Tag, QUANTITY } from "@ganache/ethereum-utils"; -import { Quantity, Data, BUFFER_ZERO } from "@ganache/utils"; +import { Quantity, Data, BUFFER_ZERO, unref } from "@ganache/utils"; import type { Common } from "@ethereumjs/common"; import Blockchain from "../blockchain"; import { @@ -57,6 +57,33 @@ export default class BlockManager extends Manager { ) { const bm = new BlockManager(blockchain, common, blockIndexes, base); await bm.updateTaggedBlocks(); + if (blockchain.fallback) { + // a hack to ensure `latest` is kept up to date. + // this just polls for `latest` every 7 seconds + unref( + setInterval(async () => { + const json = await blockchain.fallback.request( + "eth_getBlockByNumber", + ["latest", true], + { disableCache: true } + ); + if (json == null) { + return null; + } else { + const common = blockchain.fallback.getCommonForBlockNumber( + bm.#common, + BigInt(json.number) + ); + console.log("latest is now", json.number); + + bm.latest = new Block( + BlockManager.rawFromJSON(json, common), + common + ); + } + }, 7000) + ); + } return bm; } diff --git a/src/chains/ethereum/ethereum/src/forking/fork.ts b/src/chains/ethereum/ethereum/src/forking/fork.ts index bb38d29be6..8bc4517579 100644 --- a/src/chains/ethereum/ethereum/src/forking/fork.ts +++ b/src/chains/ethereum/ethereum/src/forking/fork.ts @@ -262,7 +262,10 @@ export class Fork { } public isValidForkBlockNumber(blockNumber: Quantity) { - return blockNumber.toBigInt() <= this.blockNumber.toBigInt(); + // TODO: this is a temporary fix for using ganache for remote transaction + // simulations. it breaks lots of things for normal ganache usage. + return true; + // return blockNumber.toBigInt() <= this.blockNumber.toBigInt(); } public selectValidForkBlockNumber(blockNumber: Quantity) { @@ -281,8 +284,14 @@ export class Fork { * @param common - * @param blockNumber - */ - public getCommonForBlockNumber(common: Common, blockNumber: BigInt) { - if (blockNumber <= this.blockNumber.toBigInt()) { + public getCommonForBlockNumber( + common: Common, + blockNumber: BigInt, + allowFuture = false + ) { + // if we are allowed to get a future hardfork block, then we should try to + // get a common for hardforks that will be activate at those block numbers + if (blockNumber <= this.blockNumber.toBigInt() || allowFuture) { // we are at or before our fork block let forkCommon: Common; @@ -310,6 +319,7 @@ export class Fork { { baseChain: 1 } ); } + (forkCommon as any).on = () => {}; return forkCommon; } else { return common; diff --git a/src/chains/ethereum/ethereum/src/forking/handlers/base-handler.ts b/src/chains/ethereum/ethereum/src/forking/handlers/base-handler.ts index eeb5afa091..3d1ea418a0 100644 --- a/src/chains/ethereum/ethereum/src/forking/handlers/base-handler.ts +++ b/src/chains/ethereum/ethereum/src/forking/handlers/base-handler.ts @@ -196,7 +196,8 @@ export class BaseHandler { if (hasOwn(response, "result")) { // cache non-error responses only - this.valueCache.set(key, raw); + // don't set the cache when "latest" is requested. + if (!key.includes("latest")) this.valueCache.set(key, raw); if (!options.disableCache && this.persistentCache) { // swallow errors for the persistentCache, since it's not vital that // it always works diff --git a/src/chains/ethereum/ethereum/src/helpers/gas-estimator.ts b/src/chains/ethereum/ethereum/src/helpers/gas-estimator.ts index c6c67b9976..a028030f19 100644 --- a/src/chains/ethereum/ethereum/src/helpers/gas-estimator.ts +++ b/src/chains/ethereum/ethereum/src/helpers/gas-estimator.ts @@ -1,3 +1,4 @@ +import { Interpreter, RunState } from "@ethereumjs/evm/dist/interpreter"; import BN from "bn.js"; import { RuntimeError, RETURN_TYPES } from "@ganache/ethereum-utils"; import { Quantity } from "@ganache/utils"; @@ -24,28 +25,33 @@ const bigIntToBN = (val: bigint) => { }; const MULTIPLE = 64 / 63; -const check = (set: Set) => (opname: string) => set.has(opname); -const isCall = check( - new Set(["CALL", "DELEGATECALL", "STATICCALL", "CALLCODE"]) -); -const isCallOrCallcode = check(new Set(["CALL", "CALLCODE"])); -const isCreate = check(new Set(["CREATE", "CREATE2"])); +const check = (set: Set) => (opname: number) => set.has(opname); +const isCall = check(new Set([0xf1, 0xf4, 0xfa, 0xf2])); +const isCallOrCallcode = check(new Set([0xf1, 0xf2])); +const isCreate = check(new Set([0xf0, 0xf5])); const isTerminator = check( - new Set(["STOP", "RETURN", "REVERT", "INVALID", "SELFDESTRUCT"]) + // TODO: figure out INVALID efficiently + new Set([0x00, 0xf3, 0xfd, /*"INVALID",*/ 0xff]) ); type SystemOptions = { index: number; depth: number; - name: string; + name: number; +}; +type I = { + depth: number; + opcode: number; + stack: any[]; + gasLeft: bigint; }; const stepTracker = () => { const sysOps: SystemOptions[] = []; - const allOps: InterpreterStep[] = []; + const allOps: I[] = []; const preCompile: Set = new Set(); let preCompileCheck = false; let precompileCallDepth = 0; return { - collect: (info: InterpreterStep) => { + collect: (info: I) => { if (preCompileCheck) { if (info.depth === precompileCallDepth) { // If the current depth is unchanged. @@ -55,20 +61,20 @@ const stepTracker = () => { // Reset the flag immediately here preCompileCheck = false; } - if (isCall(info.opcode.name)) { + if (isCall(info.opcode)) { info.stack = [...info.stack]; preCompileCheck = true; precompileCallDepth = info.depth; sysOps.push({ index: allOps.length, depth: info.depth, - name: info.opcode.name + name: info.opcode }); - } else if (isCreate(info.opcode.name) || isTerminator(info.opcode.name)) { + } else if (isCreate(info.opcode) || isTerminator(info.opcode)) { sysOps.push({ index: allOps.length, depth: info.depth, - name: info.opcode.name + name: info.opcode }); } // This goes last so we can use the length for the index ^ @@ -78,7 +84,7 @@ const stepTracker = () => { done: () => !allOps.length || sysOps.length < 2 || - !isTerminator(allOps[allOps.length - 1].opcode.name), + !isTerminator(allOps[allOps.length - 1].opcode), ops: allOps, systemOps: sysOps }; @@ -155,7 +161,15 @@ const exactimate = async ( callback: (err: Error, result?: EstimateGasResult) => void ) => { const steps = stepTracker(); - vm.evm.events.on("step", steps.collect); + (vm.evm as any).handleRunStep = (interpreter: Interpreter) => { + const runState = (interpreter as any)._runState as RunState; + steps.collect({ + opcode: runState.opCode, + stack: runState.stack._store, + depth: interpreter._env.depth, + gasLeft: runState.gasLeft + } as any); + }; type ContextType = ReturnType; const Context = (index: number, fee?: BN) => { @@ -228,7 +242,7 @@ const exactimate = async ( range.isub(callingFee); addGas(range); if ( - isCallOrCallcode(op.opcode.name) && + isCallOrCallcode(op.opcode) && !(op.stack[op.stack.length - 3] === 0n) ) { cost.iadd(sixtyFloorths); @@ -258,7 +272,7 @@ const exactimate = async ( while (cursor < sysops.length) { const currentIndex = opIndex(cursor); const current = ops[currentIndex]; - const name = current.opcode.name; + const name = current.opcode; if (isCall(name) || isCreate(name)) { if (steps.isPrecompile(currentIndex)) { context.setStop(currentIndex + 1); @@ -267,7 +281,7 @@ const exactimate = async ( context.addSixtyFloorth(STIPEND); } else { context.setStop(currentIndex); - const feeBn = bn(current.opcode.fee); + const feeBn = bn(isCreate(name) ? 32000 : 100); context.addRange(feeBn); stack.push(context); context = Context(currentIndex, feeBn); // setup next context @@ -294,15 +308,22 @@ const exactimate = async ( const gas = context.getCost(); return gas.cost.add(gas.sixtyFloorths); }; - await vm.stateManager.checkpoint(); + await vm.eei.checkpoint(); const result = await vm - .runTx(runArgs as unknown as RunTxOpts) + .runTx({ + ...runArgs, + skipNonce: true, + skipBalance: true, + skipBlockGasLimitValidation: true, + skipHardForkValidation: true + } as unknown as RunTxOpts) .catch(vmerr => ({ vmerr })); - await vm.stateManager.revert(); + await vm.eei.revert(); if ("vmerr" in result) { const vmerr = result.vmerr; return callback(vmerr); } else if (result.execResult.exceptionError) { + console.error(result.execResult.exceptionError); const error = new RuntimeError( // erroneous gas estimations don't have meaningful hashes Quantity.Empty, diff --git a/src/packages/sim/app.js b/src/packages/sim/app.js index 947ae72efb..35b90c1f1f 100644 --- a/src/packages/sim/app.js +++ b/src/packages/sim/app.js @@ -92,6 +92,24 @@ document.addEventListener('DOMContentLoaded', () => { // `evm_simulateTransactions` call: transactions.addEventListener('change', formatJson); advancedOptions.addEventListener('change', formatJson); + let pre = ""; + advancedOptions.addEventListener('change', async () => { + // prefetch when advanced options change + try { + const jsonRPC = JSON.stringify(JSON.parse(requestElement.dataset.json)); + if (jsonRPC === pre) return; + pre = jsonRPC; + await fetch('/simulate', { + method: 'POST', + headers: { + 'Content-Type': 'applicaiton/json', + }, + body: jsonRPC, + }); + } catch (e) { + // ignore + } + }); formatJson(); const responseElement = document.getElementById("responseBody"); @@ -104,7 +122,7 @@ document.addEventListener('DOMContentLoaded', () => { responseElement.innerHTML = '
'; try { const jsonRPC = JSON.parse(requestElement.dataset.json); - + console.log(jsonRPC); const response = await fetch('/simulate', { method: 'POST', headers: { @@ -115,6 +133,7 @@ document.addEventListener('DOMContentLoaded', () => { responseElement.innerHTML = ''; const result = await response.json(); + console.log(result); const tree = jsonview.create(result); jsonview.render(tree, responseElement); jsonview.expand(tree); diff --git a/src/packages/sim/index.html b/src/packages/sim/index.html index 1432740907..d10f82b859 100644 --- a/src/packages/sim/index.html +++ b/src/packages/sim/index.html @@ -159,7 +159,7 @@

Transactions Simulator

id="gasLimit" name="gasLimit" required - value="80000" + value="50000000" pattern="^[0-9]+$|^(0x[a-fA-F0-9]+)$" /> @@ -249,7 +249,7 @@

Transactions Simulator

name="gasEstimation" required > - + @@ -272,8 +272,9 @@

Transactions Simulator

name="trace" required > - - + + + diff --git a/src/packages/sim/index.ts b/src/packages/sim/index.ts index 10ca42534d..1f192487db 100644 --- a/src/packages/sim/index.ts +++ b/src/packages/sim/index.ts @@ -41,15 +41,20 @@ const server = http.createServer((req, res) => { // send the POST request to the simulation server // we just take the body from the request and send it to the simulation server // and then return the result directly to the user: + let remote = false; const options = { - hostname: "localhost", - port: 8545, + hostname: remote ? "3.140.186.190" : "localhost", + port: remote ? 8080 : 8545, path: "/", method: "POST", headers: { "Content-Type": "application/json" } }; + + console.log( + `Forwarding request to ${options.hostname}:${options.port}${options.path}` + ); const simulationReq = http.request(options, simulationRes => { simulationRes.on("data", data => { res.write(data);