部署 & 运行

部署与运行模块是为了将交易发送到当前的环境中。

为了部署,你需要有一个已编译的合同。 要检查是否有一个已编译的合同,找到 CONTRACT 选择框(它在VALUE输入字段下),你可以使用这个模块。

如果什么都没有,你需要编译一个文件。如果你没有看到你想要的合约,你需要在编辑器中选择一个合约,使其活跃起来。

环境

  • Remix VM (Merge):连接到浏览器中的一个沙盒区块链。Remix VM(以前称为JavaScript VM)是它自己的 “区块链”,在每次重新加载时,旧的链将被清除,新的区块链将被启动。旧的将不会被保存。 合并指的是合并发生时以太坊的分叉。这个分叉也被称为巴黎分叉。

  • Remix VM (London):与上述相同,只是该链使用的是Ethereum的伦敦分叉。

  • Remix VM (Berlin) : 和上面一样,只不过这里用的是以太坊的柏林分叉。

  • Remix VM - Mainnet fork:这将分叉Ethereum主网并将其加载到Remix VM中。 这对于开发需要访问已部署的主网合约的合约很有用。(关于分叉的更多信息,见下文)

  • Remix VM - Goerli fork:与上述相同,只是它分叉了Goerli测试网。(关于分叉的更多信息见下文)

  • Remix VM - Sepolia fork:与上述相同,只是它分叉了Sepolia的测试网。(关于分叉的更多信息,见下文)

  • Remix VM - Custom fork:在您选择的EVM版本中,以区块号分叉一条链。(关于分叉的更多信息见下文)

  • Injected Provider - provider name:将Remix连接到一个注入的web3提供者。最常见的注入提供者是 “Metamask”。

  • Custom- External HTTP Provider:Remix将连接到一个远程节点。您需要提供所选提供者的URL:geth、parity或任何Ethereum客户端。这在以前被称为Web3 Provider。(关于外部HTTP提供方的更多信息,见下文)

  • Dev - Hardhat Provider:将Remix连接到本地Hardhat测试链。

  • Dev - Ganache Provider:将Remix连接到本地Truffle Ganache测试链。

  • Dev - Foundry Provider:将Remix连接到本地Foundry Anvil测试链。

  • L2 - Optimism Provider:将Remix连接到一个注入的提供者(通常是Metamask),并为Optimism的主网设置。

  • L2 - Arbitrum One Provider:将Remix连接到具有Arbitrum One网络设置的Injected Provider(通常是Metamask)。

  • WalletConnect:将Remix连接到移动设备上的钱包。

Remix中的分叉链

分叉是一种很好的技术,可以开发一个与特定链上部署的合约互动的合约。将一个链引入Remix VM,你会有10个账户加载100ETH。

不过要小心,如果你刷新浏览器,你会失去分叉的链。

定制Fork

自定义分叉选项允许你指定一个链的RPC服务器,一个区块号码和一个EVM版本。

你可以从chainlist.org获得节点的URL。如果链不加载,你可能需要选择一个不同的RPC服务器。你还需要选择一个与区块编号相适应的EVM版本。因此,如果你选择了一个非常低的区块号码,带有Merge “味道 “的EVM将无法工作,因为这个版本的EVM是后来才出现的。

更多关于外部 HTTP Provider

如果您使用 Geth 和 https://remix.ethereum.org ,请使用以下命令来启动 Geth ,这样 Geth 就可以接受来自 Remix 的跨域请求:

geth --http --http.corsdomain https://remix.ethereum.org

请参阅 Geth 文档中关于 http 服务的内容

要使用 https://remix.ethereum.org 和本地测试节点来运行 Remix ,请使用以下 Geth 命令:

geth --http --http.corsdomain="https://remix.ethereum.org" --http.api web3,eth,debug,personal,net --vmdebug --datadir <path/to/local/folder/for/test/chain> --dev console

如果你用的是 remix-alpha 或者本地版本的 remix — 把 –http.corsdomain 后面的 url 换成你正在使用的 Remix 的 url 。

要运行 Remix Desktop 和本地测试节点,请使用以下 Geth 命令:

geth --http --http.corsdomain="package://a7df6d3c223593f3550b35e90d7b0b1f.mod" --http.api web3,eth,debug,personal,net --vmdebug --datadir <path/to/local/folder/for/test/chain> --dev console

请参阅 Geth 文档中关于开发模式的内容

本地节点的 Web3 Provider Endpoint 是 http://localhost:8545


提醒: 别偷懒。有一种很不明智的做法,就是在 Geth 参数标识 –http.corsdomain 后面跟一个通配符: --http.corsdomain *

如果你是用通配符 * ,这就意味着所有人都可以访问这个节点。但是,如果你是用 URL ,那么允许跨域访问的 url 就只有这一个 — 示例 --http.corsdomain 'https://remix-alpha.ethereum.org'

只在使用测试链测试账户时使用 --http.corsdomain * 。如果使用真实账户或在主链上,请指明 url


账户:

  • 账户:与当前环境关联的账户列表(及其关联的余额)。 在 Remix VM 上,您可以选择 5 个账户。 如果通过 MetaMask 来使用 Injected Web3 ,那么更改账户需要在 MetaMask 中操作。

Gas 限制:

  • 这里设置了在 Remix 中创建的所有交易所允许的最大 gas 量。

以太币:

  • 这里设置了发送到一个合约或者 payable 函数的以太币数量,单位可以是 ETH、WEI、GWEI 等。
    注意: payable 函数有一个红色按钮。

每笔交易执行后,这个 Value 字段总是会被重置为0。
这个 Value 字段不是用作 gas 消耗的。

部署 & AtAddress

  • 在上图中,下拉选框选中了 Ballot。 这个下拉选框会包含已编译合约的列表。

  • 部署会发送一笔部署当前选中合约的交易。当这笔交易被打包时,新创建的实例将被添加已部署的合约列表中(这可能需要几秒钟)。
    注意: 如果合约的构造函数有参数,您需要指定它们。

  • At Address 是用来访问已经部署的合约。因为合约已经部署,通过 AtAddress 来访问合约不需要消耗 gas 。

注意: 当使用 AtAddress 时,请您确保这个地址的合约是可信的。

要使用 AtAddress ,您需要在编辑器处于选中状态时有已部署合约的源代码ABI。当使用源代码时,它必须使用与您尝试访问的已部署合约相同的编译设置进行编译。

通过 ABI 来使用 AtAddress

ABI 是一个描述合约接口的 JSON 数组。

通过 ABI 来合约交互的话,需要在 Remix 中创建一个 *.abi 后缀的新文件,然后把 ABI 信息复制进去。

确保这个文件在编辑器中处于选中状态。然后,在 At Address 旁边的输入框中,输入合约地址,再点击 At Address 。如果成功的话,下面会出现这个合约的实例 - 在已部署合约列表中。

注意: 想要 ABI 的话,在 Solidity 编译器中,当一个合约编译后,点击编译详情按钮。就会弹出一个对话框,里面包含了 ABI 还有其他信息。

Pending 实例

验证交易需要几秒钟。在此期间, GUI 会将这笔显示为 Pending 状态。 当交易被打包时, Pending 交易的数量被更新,并且交易被添加到日志中(见终端)。

使用记录器

Recorder 是一种工具,用于将一堆交易保存在一个 JSON 文件中,然后在同一环境或另一个环境中重新运行它们。

将数据保存到 JSON 文件 (默认命名为 scenario.json) 可以让您很方便地检查交易列表、调整输入参数、更改链接库等…

记录器有很多用例。

例如:

  • 在受限环境(如 Remix VM)中对合约进行编码和测试后,您可以更改环境并将其重新部署到更真实的环境中,例如公共测试网或 Geth 节点。 通过事先生成好的 scenario.json 文件,您使用的所有设置都可以和在 Remix VM 中使用时保持一致。 这意味着您无需在界面上点击 100 次或其他任何操作即可获得您之前达到的状态。 所以记录器这个工具可以让你保持淡定。

    您还可以更改 scenario.json 文件中的设置来自定义交易回放。

  • 部署合约通常需要的不仅仅是创建一个交易,因此记录器将自动执行这个部署流程。

  • 在开发环境中工作通常需要先设置状态。

选中 使用最新的编译结果运行交易 这个选项后,您可以在开发合约的同时很方便地使用最新的编译结果设置初始状态。

scenario.json

要在记录器中创建这个文件,您当然需要先运行一些交易。 在上图中 - 已记录交易旁边的数字是 0。 所以现在保存交易还不是时候 — 因为没有交易。 每次您发一笔交易,这个数字都会增加。 然后,当你把该发的交易都发完了以后,点击 保存 按钮,就会创建 scenario.json 文件。

下面的 JSON 文件是 scenario.json 文件的一个示例。

在其中,执行了 3 笔交易:

第一笔交易对应 testLib 库的部署。

第二个笔交易对应 test 合约的部署,构造函数的第一个参数设置为 11。该合约依赖于一个库。 这个库的关联引用是用属性 linkReferences 来指定的。 在这种情况下,我们会使用之前创建的库的地址:created{1512830014773} 。 这个数字是创建这个库的交易的 id(时间戳)。

第三笔交易对应 test 合约的 set 函数的调用(属性 to 设置为:created{1512830015080})。 输入参数为 10xca35b7d915458ef540ade6068dfe2f44e8fa733c

所有这些交易都是用账户 account{0} 的以太币来创建的。

{
"accounts": {
    "account{0}": "0xca35b7d915458ef540ade6068dfe2f44e8fa733c"
},
"linkReferences": {
    "testLib": "created{1512830014773}"
},
"transactions": [
    {
    "timestamp": 1512830014773,
    "record": {
        "value": "0",
        "parameters": [],
        "abi": "0xbc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a",
        "contractName": "testLib",
        "bytecode": "60606040523415600e57600080fd5b60968061001c6000396000f300606060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680636d4ce63c146044575b600080fd5b604a6060565b6040518082815260200191505060405180910390f35b6000610d809050905600a165627a7a7230582022d123b15248b8176151f8d45c2dc132063bcc9bb8d5cd652aea7efae362c8050029",
        "linkReferences": {},
        "type": "constructor",
        "from": "account{0}"
    }
    },
    {
    "timestamp": 1512830015080,
    "record": {
        "value": "100",
        "parameters": [
        11
        ],
        "abi": "0xc41589e7559804ea4a2080dad19d876a024ccb05117835447d72ce08c1d020ec",
        "contractName": "test",
        "bytecode": "60606040526040516020806102b183398101604052808051906020019091905050806000819055505061027a806100376000396000f300606060405260043610610062576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632f30c6f61461006757806338cc48311461009e57806362738998146100f357806387cc10e11461011c575b600080fd5b61009c600480803590602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610145565b005b34156100a957600080fd5b6100b1610191565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156100fe57600080fd5b6101066101bb565b6040518082815260200191505060405180910390f35b341561012757600080fd5b61012f6101c4565b6040518082815260200191505060405180910390f35b8160008190555080600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050565b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60008054905090565b600073__browser/ballot.sol:testLib____________636d4ce63c6000604051602001526040518163ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040160206040518083038186803b151561022e57600080fd5b6102c65a03f4151561023f57600080fd5b505050604051805190509050905600a165627a7a72305820e0b2510bb2890a0334bfe5613d96db3e72442e63b514cdeaee8fc2c6bbd19d3a0029",
        "linkReferences": {
        "browser/ballot.sol": {
            "testLib": [
            {
                "length": 20,
                "start": 511
            }
            ]
        }
        },
        "name": "",
        "type": "constructor",
        "from": "account{0}"
    }
    },
    {
    "timestamp": 1512830034180,
    "record": {
        "value": "1000000000000000000",
        "parameters": [
        1,
        "0xca35b7d915458ef540ade6068dfe2f44e8fa733c"
        ],
        "to": "created{1512830015080}",
        "abi": "0xc41589e7559804ea4a2080dad19d876a024ccb05117835447d72ce08c1d020ec",
        "name": "set",
        "type": "function",
        "from": "account{0}"
    }
    }
],
"abis": {
    "0xbc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a": [
    {
        "constant": true,
        "inputs": [],
        "name": "get",
        "outputs": [
        {
            "name": "",
            "type": "uint256"
        }
        ],
        "payable": false,
        "stateMutability": "view",
        "type": "function"
    }
    ],
    "0xc41589e7559804ea4a2080dad19d876a024ccb05117835447d72ce08c1d020ec": [
    {
        "constant": true,
        "inputs": [],
        "name": "getInt",
        "outputs": [
        {
            "name": "",
            "type": "uint256"
        }
        ],
        "payable": false,
        "stateMutability": "view",
        "type": "function"
    },
    {
        "constant": true,
        "inputs": [],
        "name": "getFromLib",
        "outputs": [
        {
            "name": "",
            "type": "uint256"
        }
        ],
        "payable": false,
        "stateMutability": "view",
        "type": "function"
    },
    {
        "constant": true,
        "inputs": [],
        "name": "getAddress",
        "outputs": [
        {
            "name": "",
            "type": "address"
        }
        ],
        "payable": false,
        "stateMutability": "view",
        "type": "function"
    },
    {
        "constant": false,
        "inputs": [
        {
            "name": "_t",
            "type": "uint256"
        },
        {
            "name": "_add",
            "type": "address"
        }
        ],
        "name": "set",
        "outputs": [],
        "payable": true,
        "stateMutability": "payable",
        "type": "function"
    },
    {
        "inputs": [
        {
            "name": "_r",
            "type": "uint256"
        }
        ],
        "payable": true,
        "stateMutability": "payable",
        "type": "constructor"
    }
    ]
}
}