Merge pull request #4255 from ethereum/improve_free_function

Use current provider for running script
fix_blocknumber_vm
yann300 1 year ago committed by GitHub
commit 1315a91deb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 82
      apps/remix-ide-e2e/src/tests/terminal.test.ts
  2. 21
      apps/remix-ide/src/app/plugins/solidity-script.tsx
  3. 2
      apps/remix-ide/src/app/providers/goerli-vm-fork-provider.tsx
  4. 2
      apps/remix-ide/src/app/providers/sepolia-vm-fork-provider.tsx
  5. 2
      apps/remix-ide/src/blockchain/blockchain.tsx
  6. 6
      libs/remix-core-plugin/src/lib/compiler-artefacts.ts
  7. 8
      libs/remix-debug/src/init.ts
  8. 4
      libs/remix-lib/src/execution/txRunnerVM.ts
  9. 3
      libs/remix-lib/src/init.ts
  10. 4
      libs/remix-simulator/src/methods/transactions.ts
  11. 2
      libs/remix-simulator/src/provider.ts
  12. 1
      libs/remix-simulator/src/vm-context.ts
  13. 4
      libs/remix-ui/editor/src/lib/remix-ui-editor.tsx

@ -216,7 +216,7 @@ module.exports = {
.execute(() => {
(document.querySelector('*[data-id="basic-http-providerModalDialogContainer-react"] input[data-id="modalDialogCustomPromp"]') as any).focus()
}, [], () => { })
.setValue('[data-id="modalDialogCustomPromp"]', 'https://remix-goerli.ethdevops.io')
.setValue('[data-id="modalDialogCustomPromp"]', 'https://go.getblock.io/ee42d0a88f314707be11dd799b122cb9')
.modalFooterOKClick('basic-http-provider')
.clickLaunchIcon('filePanel')
.openFile('README.txt')
@ -224,11 +224,11 @@ module.exports = {
.pause(1000)
.executeScriptInTerminal('remix.execute(\'scripts/log_tx_block.js\')')
// check if the input of the transaction is being logged (web3 call)
.waitForElementContainsText('*[data-id="terminalJournal"]', '0x775526410000000000000000000000000000000000000000000000000000000000000060464c0335b2f1609abd9de25141c0a3b49db516fc7375970dc737c32b986e88e3000000000000000000000000000000000000000000000000000000000000039e000000000000000000000000000000000000000000000000000000000000000602926b30b10e7a514d92bc71e085f5bff2687fac2856ae43ef7621bf1756fa370516d310bec5727543089be9a4d5f68471174ee528e95a2520b0ca36c2b6c6eb0000000000000000000000000000000000000000000000000000000000046f49036f5e4ea4dd042801c8841e3db8e654124305da0f11824fc1db60c405dbb39f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', 120000)
.waitForElementContainsText('*[data-id="terminalJournal"]', '0x2b0006fa00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004e9e0000000000000000000000000000000000000000000000000000000000004ea373ded44d6900b8b479935bee9c82176261653e334586e0fd282f569357c0777bd9d084474837ac94bf96f2e26590222a2b8e46545657c7cf06ce2833d267bd6f131b5b3fd36cb1ca3e07cf422224df0766d1a677bbdb7ee4cc0d634efa5367a302a94dac422a16b9b8d5c10fe0555924f8189f6b498bef507b1d32e7915bd4df184f51e6d79ae6a1b11d5745ce7d625cecc3bd0dc50af4f999ffb927225f5e5c019b499f5e1fdcbc70c45df61df76013d1b0d45cdf6a267dac1b4620c0db2efd251f6548509c9c69f5bd9d1ee38ac0df0c73be2774f7d2e1fb7ef5129010f29d091e3c48aed0f035fc29804c99927d33ff2a19ff526979355ac50b2542bc5d8f2d41e4f850d5981e0420807469e828b03173b96b757fbaeacda335e11b3ab8b02a48456fab35d41ca26abde751d5fca8ef5e7ba5295278b6e46ce2aab6c10b3d185a6137d3e5c28bb8dd3a797feaf35520fcb949ea074e1869e0011ef01f8162135e44bb797d3d6215ff74ffbee972c97264fc15d11c840e6a7e796dc1a418572f6dbcc842594a558e1a9e3cb7a159284e16fec758bbc303d13edc28fb6d8bb110c3a398e4ded1748da9854eb84679ad0c99bc59bea7956b521db3ed0a9057510cc11365858704989690f0d891af81b213b1f2e91e41e4998a467656eac87e7025ac2840c17f2b106df7d32a0139036bdf5d87344ca37e9ce770e0dbeb5e021d03a7d496a6695eb06d3de9258b43f3883ce155767962b52083504b19d6d609090a2f96e9724902bf1adbf57359ac1dda48a8ffe596b8d95cac1429378769a6ec2ff1c8a9c0bc343b0a6468f36696bfb202cde9f6cd5241b814096d777751b44f0cc2ac9e7ba142227e8d5f2dd8da62573953540da1abce82c59287b2f7a87a111851758c2505d8c1ded6c42a49fc5577451ee56126d2275da490baa645c3bcac0c31dabee7aa35e6cdffb56ac0d952c2583c6f50f906dfb96f5a98c49a5919031cff880bffbe371a50162a7bd0fa0398a5898eaf6ad6db868a7d807846a3592325bb4207d67ad96bac76435368962ba8944d0201c2f620fb29373a6f35c815d101af98111e9b4cc61e8ae77fc63ce375068328ec8d05b49486666fb0f756f99d2fe747c95b2a553965f304a324879393897315d310841f0a200cd156f6ca4ed2', 120000)
// check if the logsBloom is being logged (web3 call)
.waitForElementContainsText('*[data-id="terminalJournal"]', '0x00000000000000000000000000100000000000000000020000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000040000000060000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000100000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000001', 120000)
.waitForElementContainsText('*[data-id="terminalJournal"]', '0x0fbbd94c448fe6949f848380a1d145a974f386624b4b10aa40f9afb212b3ddeb', 120000) // hash of 4757766
// check if the logsBloom is being logged (ethers.js call)
.waitForElementContainsText('*[data-id="terminalJournal"]', '"hex":"0x025cd8"', 120000)
.waitForElementContainsText('*[data-id="terminalJournal"]', '0x9db899cb75888a630ba50a1644c243b83d2eb38525eb828a06a5e8bb5663c0b0', 120000) // hash of 4757767
},
'Should listen on all transactions #group8': function (browser: NightwatchBrowser) {
@ -301,21 +301,17 @@ module.exports = {
})
.executeScriptInTerminal(`web3.eth.getCode('0x180587b00c8642e2c7ac3a758712d97e6f7bdcc7')`) // mainnet contract
.waitForElementContainsText('*[data-id="terminalJournal"]', '0x608060405260043610601f5760003560e01c80635c60da1b14603157602b565b36602b576029605f565b005b6029605f565b348015603c57600080fd5b5060436097565b6040516001600160a01b03909116815260200160405180910390f35b609560917f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b60d1565b565b600060c97f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b90565b3660008037600080366000845af43d6000803e80801560ef573d6000f35b3d6000fdfea2646970667358221220969dbb4b1d8aec2bb348e26488dc1a33b6bcf0190f567d161312ab7ca9193d8d64736f6c63430008110033', 120000)
.click('*[data-id="terminalClearConsole"]')
},
'Should connect to the sepolia fork and run web3.eth.getCode in the terminal #group9': function (browser: NightwatchBrowser) {
browser
.switchEnvironment('vm-custom-fork')
.waitForElementPresent({
locateStrategy: 'css selector',
selector: 'select[data-id="runTabSelectAccount"] option[value="0xdD870fA1b7C4700F2BD7f44238821C26f7392148"]',
timeout: 240000
})
.waitForElementPresent('[data-id="vm-custom-fork-modal-footer-ok-react"]')
.waitForElementVisible('[data-id="vm-custom-fork-modal-footer-ok-react"]')
.execute(() => {
(document.querySelector('*[data-id="vm-custom-forkModalDialogContainer-react"] input[data-id="CustomForkNodeUrl"]') as any).focus()
}, [], () => { })
.clearValue('*[data-id="CustomForkNodeUrl"]').pause(1000).setValue('*[data-id="CustomForkNodeUrl"]', 'https://remix-sepolia.ethdevops.io')
.clearValue('*[data-id="CustomForkNodeUrl"]').pause(1000).setValue('*[data-id="CustomForkNodeUrl"]', 'https://go.getblock.io/ee42d0a88f314707be11dd799b122cb9')
.execute(() => {
(document.querySelector('*[data-id="vm-custom-forkModalDialogContainer-react"] input[data-id="CustomForkBlockNumber"]') as any).focus()
}, [], () => { })
@ -326,9 +322,61 @@ module.exports = {
.click('*[data-id="CustomForkEvmType"] [value="merge"]')
.pause(5000)
.modalFooterOKClick('vm-custom-fork')
.waitForElementPresent({
locateStrategy: 'css selector',
selector: 'select[data-id="runTabSelectAccount"] option[value="0xdD870fA1b7C4700F2BD7f44238821C26f7392148"]',
timeout: 240000
})
.pause(5000)
.executeScriptInTerminal(`web3.eth.getCode('0x75F509A4eDA030470272DfBAf99A47D587E76709')`) // sepolia contract
.waitForElementContainsText('*[data-id="terminalJournal"]', byteCodeInSepolia, 120000)
.click('*[data-id="terminalClearConsole"]')
},
'Should run a free function while being connected to mainnet #group9': function (browser: NightwatchBrowser) {
const script = `
import "https://github.com/ensdomains/ens-contracts/blob/master/contracts/utils/NameEncoder.sol";
import "hardhat/console.sol";
abstract contract ENS {
function resolver(bytes32 node) public virtual view returns (Resolver);
}
abstract contract Resolver {
function addr(bytes32 node) public virtual view returns (address);
}
function resolveENS() view {
// Same address for Mainet, Ropsten, Rinkerby, Gorli and other networks;
ENS ens = ENS(0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e);
(,bytes32 node) = NameEncoder.dnsEncodeName("vitalik.eth");
Resolver resolver = ens.resolver(node);
console.log(resolver.addr(node));
}
`
browser
// .clickLaunchIcon('udapp')
.switchEnvironment('vm-mainnet-fork')
.clickLaunchIcon('filePanel')
.addFile('test_mainnet.sol', { content: script })
const path = "//*[@class='view-line' and contains(.,'resolveENS') and contains(.,'view')]//span//span[contains(.,'(')]"
const pathRunFunction = `//li//*[@aria-label='Run the free function "resolveENS"']`
browser.waitForElementVisible('#editorView')
//.waitForElementPresent(pathRunFunction)
.pause(10000) // the parser need to parse the code
.useXpath()
.scrollToLine(16)
.click(path)
.perform(function () {
const actions = this.actions({ async: true });
return actions
.keyDown(this.Keys.SHIFT)
.keyDown(this.Keys.ALT)
.sendKeys('r')
})
.useCss()
.waitForElementContainsText('*[data-id="terminalJournal"]', '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', 120000)
},
'Should run free function which logs in the terminal #group10': function (browser: NightwatchBrowser) {
@ -342,7 +390,7 @@ module.exports = {
.addFile('test.sol', { content: script })
.scrollToLine(3)
const path = "//*[@class='view-line' and contains(.,'runSomething') and contains(.,'view')]//span//span[contains(.,'(')]"
const pathRunFunction = `//li//*[@aria-label='Run the free function "runSomething" in the Remix VM']`
const pathRunFunction = `//li//*[@aria-label='Run the free function "runSomething"']`
browser.waitForElementVisible('#editorView')
.useXpath()
.click(path)
@ -356,8 +404,6 @@ module.exports = {
})
.useCss()
.waitForElementContainsText('*[data-id="terminalJournal"]', 'test running free function', 120000)
.waitForElementNotContainsText('*[data-id="terminalJournal"]', `test running free function
test running free function`, 2000)
}
}
@ -771,10 +817,10 @@ const scriptBlockAndTransaction = `
// Right click on the script name and hit "Run" to execute
(async () => {
try {
web3.eth.getTransaction('0x022ccd55747677ac50f8d9dfd1bf5b843fa2f36438a28c1d0a0958e057bb3e2a').then(console.log)
web3.eth.getBlock(7367447).then(console.log);
let ethersProvider = new ethers.providers.Web3Provider(web3Provider)
ethersProvider.getBlock(7367447).then(console.log)
web3.eth.getTransaction('0x0d2baaed96425861677e87dcf6961d34e2b73ad9a0929c32a05607ca94f98d17').then(console.log).catch(console.error)
web3.eth.getBlock(4757766).then(console.log).catch(console.error)
let ethersProvider = new ethers.providers.Web3Provider(web3Provider)
ethersProvider.getBlock(4757767).then(console.log).catch(console.error)
} catch (e) {
console.log(e.message)
}

@ -55,6 +55,7 @@ export class SolidityScript extends Plugin {
})
}
await this.call('compilerArtefacts', 'saveCompilerAbstract', 'script.sol', compilation)
// get the contract
const contract = compilation.getContract('SolidityScript')
if (!contract) {
@ -62,7 +63,7 @@ export class SolidityScript extends Plugin {
return
}
const bytecode = '0x' + contract.object.evm.bytecode.object
const web3 = await this.call('blockchain', 'web3VM')
const web3 = await this.call('blockchain', 'web3')
const accounts = await this.call('blockchain', 'getAccounts')
if (!accounts || accounts.length === 0) {
throw new Error('no account available')
@ -73,13 +74,27 @@ export class SolidityScript extends Plugin {
from: accounts[0],
data: bytecode
}
const receipt = await web3.eth.sendTransaction(tx, null, { checkRevertBeforeSending: false, ignoreGasPricing: true })
let receipt
try {
receipt = await web3.eth.sendTransaction(tx, null, { checkRevertBeforeSending: false, ignoreGasPricing: true })
} catch (e) {
this.call('terminal', 'logHtml', e.message)
return
}
tx = {
from: accounts[0],
to: receipt.contractAddress,
data: '0x69d4394b' // function remixRun() public
}
const receiptCall = await web3.eth.sendTransaction(tx, null, { checkRevertBeforeSending: false, ignoreGasPricing: true })
let receiptCall
try {
receiptCall = await web3.eth.sendTransaction(tx, null, { checkRevertBeforeSending: false, ignoreGasPricing: true })
} catch (e) {
this.call('terminal', 'logHtml', e.message)
return
}
const hhlogs = await web3.remix.getHHLogsForTx(receiptCall.transactionHash)

@ -18,7 +18,7 @@ export class GoerliForkVMProvider extends BasicVMProvider {
)
this.blockchain = blockchain
this.fork = 'shanghai'
this.nodeUrl = 'https://remix-sepolia.ethdevops.io'
this.nodeUrl = 'https://remix-goerli.ethdevops.io'
this.blockNumber = 'latest'
}

@ -18,7 +18,7 @@ export class SepoliaForkVMProvider extends BasicVMProvider {
)
this.blockchain = blockchain
this.fork = 'shanghai'
this.nodeUrl = 'https://remix-sepolia.ethdevops.io'
this.nodeUrl = 'https://go.getblock.io/ee42d0a88f314707be11dd799b122cb9'
this.blockNumber = 'latest'
}

@ -23,7 +23,7 @@ const profile = {
name: 'blockchain',
displayName: 'Blockchain',
description: 'Blockchain - Logic',
methods: ['getCode', 'getTransactionReceipt', 'addProvider', 'removeProvider', 'getCurrentFork', 'getAccounts', 'web3VM', 'getProvider'],
methods: ['getCode', 'getTransactionReceipt', 'addProvider', 'removeProvider', 'getCurrentFork', 'getAccounts', 'web3VM', 'web3', 'getProvider'],
version: packageJson.version
}

@ -5,7 +5,7 @@ import { CompilerAbstract } from '@remix-project/remix-solidity'
const profile = {
name: 'compilerArtefacts',
methods: ['get', 'addResolvedContract', 'getCompilerAbstract', 'getAllContractDatas', 'getLastCompilationResult', 'getArtefactsByContractName', 'getContractDataFromAddress', 'getContractDataFromByteCode'],
methods: ['get', 'addResolvedContract', 'getCompilerAbstract', 'getAllContractDatas', 'getLastCompilationResult', 'getArtefactsByContractName', 'getContractDataFromAddress', 'getContractDataFromByteCode', 'saveCompilerAbstract'],
events: [],
version: '0.0.1'
}
@ -24,6 +24,10 @@ export class CompilerArtefacts extends Plugin {
this.compilersArtefactsPerFile = {}
}
saveCompilerAbstract (file: string, compilerAbstract: CompilerAbstract) {
this.compilersArtefactsPerFile[file] = compilerAbstract
}
onActivation () {
const saveCompilationPerFileResult = (file, source, languageVersion, data, input?) => {
this.compilersArtefactsPerFile[file] = new CompilerAbstract(languageVersion, data, source, input)

@ -1,5 +1,6 @@
'use strict'
import Web3, { Web3PluginBase } from 'web3'
import {toNumber} from 'web3-utils'
export function extendWeb3 (web3) {
if(!web3.debug){
@ -21,11 +22,12 @@ export function setProvider (web3, url) {
export function web3DebugNode (network) {
const web3DebugNodes = {
Main: 'https://eth.getblock.io/68069907-1d3c-466e-a533-a943afd935c6/mainnet',
Main: 'https://go.getblock.io/56f8bc5187aa4ac696348f67545acf38',
Holesky: 'https://go.getblock.io/7b91c53809fb49c787087e02ef84820b',
Rinkeby: 'https://remix-rinkeby.ethdevops.io',
Ropsten: 'https://remix-ropsten.ethdevops.io',
Goerli: 'https://remix-goerli.ethdevops.io',
Sepolia: 'https://remix-sepolia.ethdevops.io'
Sepolia: 'https://go.getblock.io/ee42d0a88f314707be11dd799b122cb9'
}
if (web3DebugNodes[network]) {
return loadWeb3(web3DebugNodes[network])
@ -57,7 +59,7 @@ class Web3DebugPlugin extends Web3PluginBase {
public storageRangeAt(txBlockHash, txIndex, address, start, maxSize, cb) {
this.requestManager.send({
method: 'debug_storageRangeAt',
params: [txBlockHash, txIndex, address, start, maxSize]
params: [txBlockHash, toNumber(txIndex), address, start, maxSize]
})
.then(result => cb(null, result))
.catch(error => cb(error))

@ -31,13 +31,13 @@ export class TxRunnerVM {
nextNonceForCall: number
getVMObject: () => any
constructor (vmaccounts, api, getVMObject) {
constructor (vmaccounts, api, getVMObject, blockNumber) {
this.event = new EventManager()
this.logsManager = new LogsManager()
// has a default for now for backwards compatibility
this.getVMObject = getVMObject
this.commonContext = this.getVMObject().common
this.blockNumber = 0
this.blockNumber = blockNumber || 0
this.pendingTxs = {}
this.vmaccounts = vmaccounts
this.queusTxs = []

@ -1,5 +1,6 @@
'use strict'
import Web3, { Web3PluginBase } from 'web3'
import {toNumber} from 'web3-utils'
export function extendWeb3 (web3) {
if(!web3.debug){
@ -38,7 +39,7 @@ class Web3DebugPlugin extends Web3PluginBase {
public storageRangeAt(txBlockHash, txIndex, address, start, maxSize, cb) {
this.requestManager.send({
method: 'debug_storageRangeAt',
params: [txBlockHash, txIndex, address, start, maxSize]
params: [txBlockHash, toNumber(txIndex), address, start, maxSize]
})
.then(result => cb(null, result))
.catch(error => cb(error))

@ -32,7 +32,7 @@ export class Transactions {
this.tags = {}
}
init (accounts) {
init (accounts, blockNumber) {
this.accounts = accounts
const api = {
logMessage: (msg) => {
@ -55,7 +55,7 @@ export class Transactions {
}
}
this.txRunnerVMInstance = new TxRunnerVM(accounts, api, _ => this.vmContext.vmObject())
this.txRunnerVMInstance = new TxRunnerVM(accounts, api, _ => this.vmContext.vmObject(), blockNumber)
this.txRunnerInstance = new TxRunner(this.txRunnerVMInstance, {})
this.txRunnerInstance.vmaccounts = accounts
}

@ -60,7 +60,7 @@ export class Provider {
this.pendingRequests = []
await this.vmContext.init()
await this.Accounts.resetAccounts()
this.Transactions.init(this.Accounts.accounts)
this.Transactions.init(this.Accounts.accounts, this.vmContext.blockNumber)
this.initialized = true
if (this.pendingRequests.length > 0) {
this.pendingRequests.map((req) => {

@ -313,6 +313,7 @@ export class VMContext {
provider: this.nodeUrl,
blockTag: '0x' + block.toString(16)
})
this.blockNumber = block
} else {
stateManager = new CustomEthersStateManager({
provider: this.nodeUrl,

@ -734,7 +734,7 @@ export const EditorUI = (props: EditorUIProps) => {
let freeFunctionAction
const executeFreeFunctionAction = {
id: 'executeFreeFunction',
label: 'Run a free function in the Remix VM',
label: 'Run a free function',
contextMenuOrder: 0, // choose the order
contextMenuGroupId: 'execute', // create a new grouping
precondition: 'freeFunctionCondition',
@ -792,7 +792,7 @@ export const EditorUI = (props: EditorUIProps) => {
const { nodesAtPosition } = await retrieveNodesAtPosition(props.editorAPI, props.plugin)
const freeFunctionNode = nodesAtPosition.find((node) => node.kind === 'freeFunction')
if (freeFunctionNode) {
executeFreeFunctionAction.label = `Run the free function "${freeFunctionNode.name}" in the Remix VM`
executeFreeFunctionAction.label = `Run the free function "${freeFunctionNode.name}"`
freeFunctionAction = editor.addAction(executeFreeFunctionAction)
}
const functionImpl = nodesAtPosition.find((node) => node.kind === 'function')

Loading…
Cancel
Save