From 36e20332b69cad6ee3fc665c4db26047c9d57779 Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 30 Sep 2024 09:48:03 +0200 Subject: [PATCH 1/3] add missing endpoint --- libs/remix-simulator/README.md | 2 +- libs/remix-simulator/src/methods/miner.ts | 18 ++++++++++++++++++ libs/remix-simulator/src/provider.ts | 2 ++ 3 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 libs/remix-simulator/src/methods/miner.ts diff --git a/libs/remix-simulator/README.md b/libs/remix-simulator/README.md index 8410dd63f0a..b783356f485 100644 --- a/libs/remix-simulator/README.md +++ b/libs/remix-simulator/README.md @@ -39,7 +39,7 @@ * [X] eth_getCode * [~] eth_sign * [X] eth_sendTransaction -* [_] eth_sendRawTransaction +* [x] eth_sendRawTransaction * [X] eth_call * [~] eth_estimateGas * [X] eth_getBlockByHash diff --git a/libs/remix-simulator/src/methods/miner.ts b/libs/remix-simulator/src/methods/miner.ts new file mode 100644 index 00000000000..55f87671116 --- /dev/null +++ b/libs/remix-simulator/src/methods/miner.ts @@ -0,0 +1,18 @@ +export class Miner { + vmContext + + constructor (vmContext) { + this.vmContext = vmContext + } + + methods () { + return { + miner_start: this.miner_start.bind(this), + miner_stop: this.miner_stop.bind(this) + } + } + + miner_start (payload, cb) {} + + miner_stop (payload, cb) {} +} diff --git a/libs/remix-simulator/src/provider.ts b/libs/remix-simulator/src/provider.ts index b6c52345fec..af9233263ae 100644 --- a/libs/remix-simulator/src/provider.ts +++ b/libs/remix-simulator/src/provider.ts @@ -8,6 +8,7 @@ import { Filters } from './methods/filters' import { methods as miscMethods } from './methods/misc' import { methods as netMethods } from './methods/net' import { Transactions } from './methods/transactions' +import { Miner } from './methods/miner' import { Debug } from './methods/debug' import { VMContext } from './vm-context' import { Web3PluginBase } from 'web3' @@ -65,6 +66,7 @@ export class Provider { this.methods = merge(this.methods, netMethods()) this.methods = merge(this.methods, this.Transactions.methods()) this.methods = merge(this.methods, (new Debug(this.vmContext)).methods()) + this.methods = merge(this.methods, (new Miner(this.vmContext)).methods()) } async init () { From e2a09537a0694b3768b18d6c71b0ef40cdf2fde8 Mon Sep 17 00:00:00 2001 From: yann300 Date: Wed, 2 Oct 2024 17:30:44 +0200 Subject: [PATCH 2/3] dynamic chainid --- libs/remix-simulator/src/methods/accounts.ts | 8 +++-- libs/remix-simulator/src/methods/miner.ts | 4 +-- libs/remix-simulator/src/methods/net.ts | 34 +++++++++++--------- libs/remix-simulator/src/provider.ts | 7 ++-- 4 files changed, 31 insertions(+), 22 deletions(-) diff --git a/libs/remix-simulator/src/methods/accounts.ts b/libs/remix-simulator/src/methods/accounts.ts index 6c99565455c..316ccf2b263 100644 --- a/libs/remix-simulator/src/methods/accounts.ts +++ b/libs/remix-simulator/src/methods/accounts.ts @@ -13,9 +13,11 @@ export class Web3Accounts { accounts: Record accountsKeys: Record vmContext + options - constructor (vmContext) { + constructor (vmContext, options) { this.vmContext = vmContext + this.options = options // TODO: make it random and/or use remix-libs this.accounts = {} @@ -92,6 +94,8 @@ export class Web3Accounts { eth_getBalance (payload, cb) { const address = payload.params[0] this.vmContext.vm().stateManager.getAccount(Address.fromString(address)).then((account) => { + if (!account) return cb(null, toBigInt(0).toString(10)) + if (!account.balance) return cb(null, toBigInt(0).toString(10)) cb(null, toBigInt(account.balance).toString(10)) }).catch((error) => { cb(error) @@ -114,7 +118,7 @@ export class Web3Accounts { } eth_chainId (_payload, cb) { - return cb(null, '0x539') // 0x539 is hex of 1337 + return cb(null, this.options.chainId || '0x539') // 0x539 is hex of 1337 } eth_signTypedData_v4 (payload, cb) { diff --git a/libs/remix-simulator/src/methods/miner.ts b/libs/remix-simulator/src/methods/miner.ts index 55f87671116..2d8994c2bfd 100644 --- a/libs/remix-simulator/src/methods/miner.ts +++ b/libs/remix-simulator/src/methods/miner.ts @@ -12,7 +12,7 @@ export class Miner { } } - miner_start (payload, cb) {} + miner_start (payload, cb) { cb() } - miner_stop (payload, cb) {} + miner_stop (payload, cb) { cb()} } diff --git a/libs/remix-simulator/src/methods/net.ts b/libs/remix-simulator/src/methods/net.ts index 1a064719f43..3c9c7a612c8 100644 --- a/libs/remix-simulator/src/methods/net.ts +++ b/libs/remix-simulator/src/methods/net.ts @@ -1,20 +1,24 @@ -export function methods (): Record { - return { - net_version: net_version, - net_listening: net_listening, - net_peerCount: net_peerCount +export class Net { + vmContext + options + + constructor (vmContext, options) { + this.vmContext = vmContext + this.options = options } -} -export function net_version (payload, cb): void { - // should be configured networkId - cb(null, 1337) -} + methods () { + return { + net_version: this.net_version.bind(this), + net_listening: this.net_listening.bind(this), + net_peerCount: this.net_peerCount.bind(this) + } + } -export function net_listening (payload, cb): void { - cb(null, true) -} + net_version (payload, cb) { cb(null, 1337) } + + net_listening (payload, cb) { cb(null, true)} -export function net_peerCount (payload, cb): void { - cb(null, 0) + net_peerCount (payload, cb) { cb(null, 0)} } + diff --git a/libs/remix-simulator/src/provider.ts b/libs/remix-simulator/src/provider.ts index af9233263ae..c28257018ed 100644 --- a/libs/remix-simulator/src/provider.ts +++ b/libs/remix-simulator/src/provider.ts @@ -6,7 +6,7 @@ import merge from 'merge' import { Web3Accounts } from './methods/accounts' import { Filters } from './methods/filters' import { methods as miscMethods } from './methods/misc' -import { methods as netMethods } from './methods/net' +import { Net } from './methods/net' import { Transactions } from './methods/transactions' import { Miner } from './methods/miner' import { Debug } from './methods/debug' @@ -31,6 +31,7 @@ export type JSONRPCResponseCallback = (err: Error, result?: JSONRPCResponsePaylo export type State = Record export type ProviderOptions = { + chainId?: number fork?: string, nodeUrl?: string, blockNumber?: number | 'latest', @@ -55,7 +56,7 @@ export class Provider { this.connected = true this.vmContext = new VMContext(options['fork'], options['nodeUrl'], options['blockNumber'], options['stateDb'], options['blocks']) - this.Accounts = new Web3Accounts(this.vmContext) + this.Accounts = new Web3Accounts(this.vmContext, options) this.Transactions = new Transactions(this.vmContext) this.methods = {} @@ -63,7 +64,7 @@ export class Provider { this.methods = merge(this.methods, (new Blocks(this.vmContext, options)).methods()) this.methods = merge(this.methods, miscMethods()) this.methods = merge(this.methods, (new Filters(this.vmContext)).methods()) - this.methods = merge(this.methods, netMethods()) + this.methods = merge(this.methods, (new Net(this.vmContext, options)).methods()) this.methods = merge(this.methods, this.Transactions.methods()) this.methods = merge(this.methods, (new Debug(this.vmContext)).methods()) this.methods = merge(this.methods, (new Miner(this.vmContext)).methods()) From 4ba500f466bf8a76ec3ece21e5a7931a9f1d8c55 Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 22 Oct 2024 10:39:06 +0200 Subject: [PATCH 3/3] add missing remix-simulator endpoint --- libs/remix-lib/src/execution/txRunnerVM.ts | 29 ++++++- libs/remix-simulator/src/methods/accounts.ts | 6 +- libs/remix-simulator/src/methods/evm.ts | 79 ++++++++++++++++++++ libs/remix-simulator/src/methods/miner.ts | 2 +- libs/remix-simulator/src/provider.ts | 6 ++ 5 files changed, 118 insertions(+), 4 deletions(-) create mode 100644 libs/remix-simulator/src/methods/evm.ts diff --git a/libs/remix-lib/src/execution/txRunnerVM.ts b/libs/remix-lib/src/execution/txRunnerVM.ts index 6c4c40b27b5..51e52af7684 100644 --- a/libs/remix-lib/src/execution/txRunnerVM.ts +++ b/libs/remix-lib/src/execution/txRunnerVM.ts @@ -75,6 +75,33 @@ export class TxRunnerVM { } } + runEmptyBlock (callback: VMExecutionCallBack) { + const EIP1559 = this.commonContext.hardfork() !== 'berlin' // berlin is the only pre eip1559 fork that we handle. + const coinbases = ['0x0e9281e9c6a0808672eaba6bd1220e144c9bb07a', '0x8945a1288dc78a6d8952a92c77aee6730b414778', '0x94d76e24f818426ae84aa404140e8d5f60e10e7e'] + const difficulties = [69762765929000, 70762765929000, 71762765929000] + const difficulty = this.commonContext.consensusType() === ConsensusType.ProofOfStake ? 0 : difficulties[this.blocks.length % difficulties.length] + const block = Block.fromBlockData({ + header: { + timestamp: new Date().getTime() / 1000 | 0, + number: this.blocks.length, + coinbase: coinbases[this.blocks.length % coinbases.length], + difficulty, + gasLimit: 0, + baseFeePerGas: EIP1559 ? '0x1' : undefined, + parentHash: this.blockParentHash + } + }, { common: this.commonContext }) + + this.blockParentHash = block.hash() + this.runBlockInVm(null, block, async (err, result) => { + if (!err) { + this.getVMObject().vm.blockchain.putBlock(block) + this.blocks.push(block.serialize()) + } + callback(err, result) + }) + } + async runInVm (tx: InternalTransaction, callback: VMExecutionCallBack) { const { to, data, value, gasLimit, useCall, signed } = tx let { from } = tx @@ -183,7 +210,7 @@ export class TxRunnerVM { const result: RunTxResult = results.results[0] callback(null, { result, - transactionHash: bytesToHex(Buffer.from(tx.hash())), + transactionHash: tx ? bytesToHex(Buffer.from(tx.hash())) : null, block, tx }) diff --git a/libs/remix-simulator/src/methods/accounts.ts b/libs/remix-simulator/src/methods/accounts.ts index 316ccf2b263..1fff17faf4e 100644 --- a/libs/remix-simulator/src/methods/accounts.ts +++ b/libs/remix-simulator/src/methods/accounts.ts @@ -1,7 +1,7 @@ import { signTypedData, SignTypedDataVersion, TypedMessage, MessageTypes } from '@metamask/eth-sig-util' import { privateToAddress, toChecksumAddress, isValidPrivate, Address, toBytes, bytesToHex, Account } from '@ethereumjs/util' import { privateKeyToAccount } from 'web3-eth-accounts' -import { toBigInt } from 'web3-utils' +import { toBigInt, toHex } from 'web3-utils' import * as crypto from 'crypto' type AccountType = { @@ -118,7 +118,9 @@ export class Web3Accounts { } eth_chainId (_payload, cb) { - return cb(null, this.options.chainId || '0x539') // 0x539 is hex of 1337 + if (!this.options.chainId) return cb(null, '0x539') // 0x539 is hex of 1337 + const id = (typeof this.options.chainId === 'number') ? toHex(this.options.chainId) : this.options.chainId + return cb(null, id) } eth_signTypedData_v4 (payload, cb) { diff --git a/libs/remix-simulator/src/methods/evm.ts b/libs/remix-simulator/src/methods/evm.ts new file mode 100644 index 00000000000..22f348e5b97 --- /dev/null +++ b/libs/remix-simulator/src/methods/evm.ts @@ -0,0 +1,79 @@ +import { Block } from '@ethereumjs/block' +import { ConsensusType } from '@ethereumjs/common' +import type { VMContext } from '../vm-context' +import type { Transactions } from '../methods/transactions' + +export class EVM { + vmContext: VMContext + transactions: Transactions + + constructor (vmContext: VMContext, transactions: Transactions) { + this.vmContext = vmContext + this.transactions = transactions + } + + methods () { + return { + evm_setAutomine: this.evm_setAutomine.bind(this), + evm_setIntervalMining: this.evm_setIntervalMining.bind(this), + evm_snapshot: this.evm_snapshot.bind(this), + evm_revert: this.evm_revert.bind(this), + evm_increaseTime: this.evm_increaseTime.bind(this), + evm_setNextBlockTimestamp: this.evm_setNextBlockTimestamp.bind(this), + evm_setBlockGasLimit: this.evm_setBlockGasLimit.bind(this), + evm_mine: this.evm_mine.bind(this) + } + } + + evm_setAutomine (payload, cb) { + // always on + cb() + } + + evm_setIntervalMining (payload, cb) { + cb() + } + + evm_snapshot (payload, cb) { + cb() + } + + evm_revert (payload, cb) { + cb() + } + + evm_increaseTime (payload, cb) { + cb() + } + + evm_setNextBlockTimestamp (payload, cb) { + cb() + } + + evm_setBlockGasLimit (payload, cb) { + cb() + } + + async evm_mine (payload, cb) { + const runEmptyBlock = () => { + return new Promise((resolve, reject) => { + this.transactions.txRunnerVMInstance.runEmptyBlock((error, result) => { + if (error) { + reject(error) + return + } + this.vmContext.addBlock(result.block, false, true) + resolve(result) + }) + }) + } + + let blocks = payload.params[0].blocks + + for (let b = 0; b < Number(blocks); b++) { + await runEmptyBlock() + console.log('mining...', b, this.vmContext.latestBlockNumber) + } + cb() + } +} diff --git a/libs/remix-simulator/src/methods/miner.ts b/libs/remix-simulator/src/methods/miner.ts index 2d8994c2bfd..b44058f5a73 100644 --- a/libs/remix-simulator/src/methods/miner.ts +++ b/libs/remix-simulator/src/methods/miner.ts @@ -14,5 +14,5 @@ export class Miner { miner_start (payload, cb) { cb() } - miner_stop (payload, cb) { cb()} + miner_stop (payload, cb) { cb() } } diff --git a/libs/remix-simulator/src/provider.ts b/libs/remix-simulator/src/provider.ts index c28257018ed..8fae322c6b3 100644 --- a/libs/remix-simulator/src/provider.ts +++ b/libs/remix-simulator/src/provider.ts @@ -10,6 +10,7 @@ import { Net } from './methods/net' import { Transactions } from './methods/transactions' import { Miner } from './methods/miner' import { Debug } from './methods/debug' +import { EVM } from './methods/evm' import { VMContext } from './vm-context' import { Web3PluginBase } from 'web3' @@ -49,9 +50,11 @@ export class Provider { methods connected: boolean initialized: boolean + initializing: boolean pendingRequests: Array constructor (options: ProviderOptions = {} as ProviderOptions) { + console.log(options) this.options = options this.connected = true this.vmContext = new VMContext(options['fork'], options['nodeUrl'], options['blockNumber'], options['stateDb'], options['blocks']) @@ -67,10 +70,12 @@ export class Provider { this.methods = merge(this.methods, (new Net(this.vmContext, options)).methods()) this.methods = merge(this.methods, this.Transactions.methods()) this.methods = merge(this.methods, (new Debug(this.vmContext)).methods()) + this.methods = merge(this.methods, (new EVM(this.vmContext, this.Transactions)).methods()) this.methods = merge(this.methods, (new Miner(this.vmContext)).methods()) } async init () { + this.initializing = true this.initialized = false this.pendingRequests = [] await this.vmContext.init() @@ -83,6 +88,7 @@ export class Provider { }) this.pendingRequests = [] } + this.initializing = false } _send(payload: JSONRPCRequestPayload, callback: (err: Error, result?: JSONRPCResponsePayload) => void) {