您正在查看: Ethereum-新手教程 分类下的文章

梳理Polygon zkEVM node 本地启动测试环境及配置

测试硬件环境

OS: Mac Pro {cpu intel} v11.7.5
注意:目前,Executor/Prover 不能在 ARM 驱动的 Mac 上运行。对于 Windows 用户,不建议使用 WSL/WSL2。

测试环境搭建

先按官方的测试环境进行部署,熟悉下部署细节,然后再做针对性补充
主要参考文章如下

官方是已Docker环境进行演示介绍的,我们精简下,主要说下关键操作

安装基础环境

自行安装go,dockerdocker-compose
可以参考以下官方文档,查看对应平台的安装方法:
https://go.dev/doc/install
https://www.docker.com/get-started
https://docs.docker.com/compose/install/

克隆代码

git clone https://github.com/0xPolygonHermez/zkevm-node.git

构建Docker镜像

cd zkevm-node/
make build-docker

运行 zkNode 环境

cd test/
make run

其他操作

make stop // 停止 zkNode
make restart // 重启整个 zkNode 环境

执行后,会创建和启动如下容器

  • zkevm-state-db
  • zkevm-pool-db
  • zkevm-mock-l1-network
  • zkevm-prover
  • zkevm-approve
  • zkevm-sync
  • zkevm-eth-tx-manager
  • zkevm-sequencer
  • zkevm-l2gaspricer
  • zkevm-aggregator
  • zkevm-json-rpc

根据Docker环境抽离各个模块配置

//TODO

L1网络配置

L2网络配置

访问环境

关键地址私钥

L1 Addresses

Address Description
0xa513E6E4b8f2a923D98304ec87F64353C4D5C853 Proof of Efficiency
0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9 Bridge
0x5FbDB2315678afecb367f032d93F642f64180aa3 Matic token
0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0 GlobalExitRootManager

Deployer Account

Address Private Key
0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80

Sequencer Account

Address Private Key
0x617b3a3528F9cDd6630fd3301B9c8911F7Bf063D 0x28b2b0318721be8c8339199172cd7cc8f5e273800a35616ec893083a4b32c02e

Accounts

Address Private Key
0x70997970C51812dc3A010C7d01b50e0d17dc79C8 0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d
0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC 0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a
0x90F79bf6EB2c4f870365E785982E1f101E93b906 0x7c852118294e51e653712a81e05800f419141751be58f605c371e15141b007a6
0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65 0x47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a
0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc 0x8b3a350cf5c34c9194ca85829a2df0ec3153be0318b5e2d3348e872092edffba
0x976EA74026E726554dB657fA54763abd0C3a0aa9 0x92db14e403b83dfe3df233f83dfa3a0d7096f21ca9b0d6d6b8d88b2b4ec1564e
0x14dC79964da2C08b23698B3D3cc7Ca32193d9955 0x4bbbf85ce3377467afe5d46f804f221813b2bb87f24d81f60f1fcdbf7cbf4356
0x23618e81E3f5cdF7f54C3d65f7FBc0aBf5B21E8f 0xdbda1821b80551c9d65939329250298aa3472ba22feea921c0cf5d620ea67b97
0xa0Ee7A142d267C1f36714E4a8F75612F20a79720 0x2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6
0xBcd4042DE499D14e55001CcbB24a551F3b954096 0xf214f2b2cd398c806f84e317254e0f0b801d0643303237d97a22a48e01628897
0x71bE63f3384f5fb98995898A86B02Fb2426c5788 0x701b615bbdfb9de65240bc28bd21bbc0d996645a3dd57e7b12bc2bdf6f192c82
0xFABB0ac9d68B0B445fB7357272Ff202C5651694a 0xa267530f49f8280200edf313ee7af6b827f2a8bce2897751d06a843f644967b1
0x1CBd3b2770909D4e10f157cABC84C7264073C9Ec 0x47c99abed3324a2707c28affff1267e45918ec8c3f20b8aa892e8b065d2942dd
0xdF3e18d64BC6A983f673Ab319CCaE4f1a57C7097 0xc526ee95bf44d8fc405a158bb884d9d1238d99f0612e9f33d006bb0789009aaa
0xcd3B766CCDd6AE721141F452C550Ca635964ce71 0x8166f546bab6da521a8369cab06c5d2b9e46670292d85c875ee9ec20e84ffb61
0x2546BcD3c84621e976D8185a91A922aE77ECEc30 0xea6c44ac03bff858b476bba40716402b03e41b8e97e276d1baec7c37d42484a0
0xbDA5747bFD65F08deb54cb465eB87D40e51B197E 0x689af8efa8c651a91ad287602527f3af2fe9f6501a7ac4b061667b5a93e037fd
0xdD2FD4581271e230360230F9337D5c0430Bf44C0 0xde9be858da4a475276426320d5e9262ecfc3ba460bfac56360bfa6c4c28b4ee0
0x8626f6940E2eb28930eFb4CeF49B2d1F2C9C1199 0xdf57089febbacf7ba0bc227dafbffa9fc08a93fdc68e1e42411a14efcf23656e

Polygon zkEVM架构组成-思路梳理

Polygon zkEVM架构组成-思路梳理

  • zkNode

    • Synchronizer
      • 获取Sequencers提交的transactions
      • 获取Aggregators提交的validity proofs
      • 监听以太坊链上事件,包括new batches{events中读取的信息->存储database}
      • 处理可能的reorgs {检查last ethBlockNum 和 last ethBlockHash 是否已同步}
    • State子模块
      • 实现了Merkle Tree并连接到DB后台
        • 在block level检查integrity(即,关于gas、block size等相关信息)
        • 检查某些交易相关信息(如签名、足够的balance等)
        • 将smart contract(SC)代码存储到Merkle tree中,并使用EVM来处理交易
    • Sequencer
      • 支持模式:Trusted/Permissionless
      • 处理流程:接收L2交易+L2用户支付的交易手续费 -> 对L2交易进行排序 ->生成batches -> send tx{sequences形式}(为Aggregator验证支付费用) -> L1合约 {PolygonZkEVM.sol} -> 存储storage slots
      • 经济模型:向L1提交有效交易,以获利
        • 根据利润对pool中交易排序
        • 向L1提交batches,支付L1系统代币
    • Aggregator
      • 处理流程:L1合约 {PolygonZkEVM.sol} -> 获取Sequencer提交的L2 batches -> zkProver{特殊链下EVM解析器} -> 生成ZK proof{证明该batch的完整性}-> send tx -> L1合约 {PolygonZkEVM.sol} -> 更新 L2 State root
      • 经济模型:Sequencers提交L1 batch时支付的手续费
      • 开支
        • 向L1提交validity proof交易成本
        • 运行aggregator和zkProver服务器成本
  • Consensus Contract(PolygonZkEVM.sol)

    • 存储Sequencers提交的L2 batches
    • 对Aggregator新提交的L2 State root进行validity proof验证
  • zkProver

    • 本质:zk virtual machine来仿真EVM
    • 功能:为Aggregator使用,来验证batches并提供validity proofs
    • 生成proof:以多项式和汇编语言形式
    • 功能包含如下
      • Main State Machine Executor:处理zkEVM的执行
        • 使用zkASM解析EVM Bytecodes
        • 为每个transaction batch设置多项式约束
        • 对多项式约束使用PIL进行编码
      • secondary State Machines : zkEVM中证明交易正确性的每一步计算
        • zkProver是整个项目中最复杂的部分,包含了多个state machines:
          • 一些执行bitwise function的state machines(如XOR/Padding等等)
          • 执行哈希运算的的state machines(如Keccak、Poseidon等等)
          • 执行验签的state machines(如ECDSA等等)
        • 二级状态机有:
          • Binary SM
          • Memory SM
          • Storage SM
          • Poseidon SM
          • Keccak SM
          • Arithmetic SM
      • STARK-proof builder
        • State machines负责生成多项式约束,zk-STARKs用于证明batches满足这些多项式约束条件
        • zkProver使用FRI对zk-STARK证明加速
      • SNARK-proof builder
        • size: STARK-proof > SNARK-proof
          • SNARK-proof来证明STARK-proof的正确性
          • SNARK-proof做为validity proof
          • 更便宜地在L1上验证该validity proof
  • L1-to-L2 Bridge

    • L1 Contract:部署在以太坊,管理rollups之间的资产转移

      负责2个操作

      • bridge:将资产由一个rollup转移到另一个rollup

      • claim:当合约从任意rollup claim时,使用claim操作

      需要有2棵Merkle tree

      • globalExitTree:包括了所有rollups的exit trees的所有信息

      • mainnet exit tree:包含了用户与主网交互的交易信息

      global exit root manager L1的合约负责管理跨越多个网络的exit roots

    • L2 Contract:部署在某特定的rollup上,负责主网与该rollup之间的资产转移

      • 处理rollup端的bridge和claim操作
      • 与globalExitTree和rollup exit tree交互以更新exit roots

共识算法PoE

Hermez 1.0 PoD共识缺点

  • 特定时间,网络由单一actor控制,可能作弊
  • 竞价协议,预测复杂性高
  • 参与竞争运营门槛高,导致运营集中,抗审查

Proof-of-Efficiency(PoE)实现

  • Sequencer:负责将L2的交易打包为batches并添加到L1的PoE智能合约
  • Aggregator:之间竞争,负责检查transaction batches的有效性,并提供validity proofs

PoE智能合约基本接口

  • sendBatch:用于接收Sequencer的batches
  • validateBatch:用于接收Aggregator的validity proof,进行validate batches

batch fee

根据网络负载情况,batch fee将是可变的,可根据protocol合约中的某个参数来计算

PoE的经济模型

  • Sequencer赚L2的交易手续费{相应的validity proof提交后}
  • Aggregator赚取Sequencer支付的batch MATIC手续费

Goerli 与zkEVM Testnet跨链测试

使用Polygon zkEVM Bridge 站点,将网络添加到我们的钱包,并将 Goerli Token 桥接到 zkEVM Testnet:

Goerli Token转0.01 ETH到zkEVM Testnet

交易:0x10210572d6b4924af7ef946136295e9b209e1fa0 -> 0xf6beeebb578e214ca9e23b0e9683454ff88ed2a7
tx hash: https://goerli.etherscan.io/tx/0x07aa6363c5854180b41b8c4584314ca6d6af989d48332375f06f9caef3270dd7

执行合约

bridgeAsset(uint32 destinationNetwork,address destinationAddress,uint256 amount,address token,bool forceUpdateGlobalExitRoot,bytes permitData)

执行参数

Name Type Data
0 destinationNetwork uint32 1
1 destinationAddress address 0x10210572d6b4924Af7Ef946136295e9b209E1FA0
2 amount uint256 10000000000000000
3 token address 0x0000000000000000000000000000000000000000
4 forceUpdateGlobalExitRoot bool true
5 permitData bytes

0xF6BEEeBB578e214CA9E23B0e9683454Ff88Ed2A7为代理合约,使用EIP-1967 Transparent Proxy
逻辑合约地址:0x39e780D8800f7396e8B7530A8925B14025AedC77
关键逻辑合约代码:https://goerli.etherscan.io/address/0x39e780d8800f7396e8b7530a8925b14025aedc77#code

合约bridgeAsset接口源码

/**
     * @notice Deposit add a new leaf to the merkle tree
     * @param destinationNetwork Network destination
     * @param destinationAddress Address destination
     * @param amount Amount of tokens
     * @param token Token address, 0 address is reserved for ether
     * @param forceUpdateGlobalExitRoot Indicates if the new global exit root is updated or not
     * @param permitData Raw data of the call `permit` of the token
     */
    function bridgeAsset(
        uint32 destinationNetwork,
        address destinationAddress,
        uint256 amount,
        address token,
        bool forceUpdateGlobalExitRoot,
        bytes calldata permitData
    ) public payable virtual ifNotEmergencyState nonReentrant {
        if (
            destinationNetwork == networkID ||
            destinationNetwork >= _CURRENT_SUPPORTED_NETWORKS
        ) {
            revert DestinationNetworkInvalid();
        }

        address originTokenAddress;
        uint32 originNetwork;
        bytes memory metadata;
        uint256 leafAmount = amount;

        if (token == address(0)) {
            // Ether transfer
            if (msg.value != amount) {
                revert AmountDoesNotMatchMsgValue();
            }

            // Ether is treated as ether from mainnet
            originNetwork = _MAINNET_NETWORK_ID;
        } else {
            // Check msg.value is 0 if tokens are bridged
            if (msg.value != 0) {
                revert MsgValueNotZero();
            }

            TokenInformation memory tokenInfo = wrappedTokenToTokenInfo[token];

            if (tokenInfo.originTokenAddress != address(0)) {
                // The token is a wrapped token from another network

                // Burn tokens
                TokenWrapped(token).burn(msg.sender, amount);

                originTokenAddress = tokenInfo.originTokenAddress;
                originNetwork = tokenInfo.originNetwork;
            } else {
                // Use permit if any
                if (permitData.length != 0) {
                    _permit(token, amount, permitData);
                }

                // In order to support fee tokens check the amount received, not the transferred
                uint256 balanceBefore = IERC20Upgradeable(token).balanceOf(
                    address(this)
                );
                IERC20Upgradeable(token).safeTransferFrom(
                    msg.sender,
                    address(this),
                    amount
                );
                uint256 balanceAfter = IERC20Upgradeable(token).balanceOf(
                    address(this)
                );

                // Override leafAmount with the received amount
                leafAmount = balanceAfter - balanceBefore;

                originTokenAddress = token;
                originNetwork = networkID;

                // Encode metadata
                metadata = abi.encode(
                    _safeName(token),
                    _safeSymbol(token),
                    _safeDecimals(token)
                );
            }
        }

        emit BridgeEvent(
            _LEAF_TYPE_ASSET,
            originNetwork,
            originTokenAddress,
            destinationNetwork,
            destinationAddress,
            leafAmount,
            metadata,
            uint32(depositCount)
        );

        _deposit(
            getLeafValue(
                _LEAF_TYPE_ASSET,
                originNetwork,
                originTokenAddress,
                destinationNetwork,
                destinationAddress,
                leafAmount,
                keccak256(metadata)
            )
        );
        // Update the new root to the global exit root manager if set by the user
        if (forceUpdateGlobalExitRoot) {
            _updateGlobalExitRoot();
        }
    }

// TODO 代码分析

等待zkevm-test处理完成

zkevm-test处理完成

Bridge Details

zkevm-test 对应交易

交易 0xa49d20f2f5a26d4a8e6fe44409f862d744f5b1aa -> 0xf6beeebb578e214ca9e23b0e9683454ff88ed2a7
tx hash: https://testnet-zkevm.polygonscan.com/tx/0x830ac94e69eb9e3aacd384d4db8a46e7830b8f99b12b5c6b5176bd8326fddc4b

执行方法

claimAsset(bytes32[32] smtProof,uint32 index,bytes32 mainnetExitRoot,bytes32 rollupExitRoot,uint32 originNetwork,address originTokenAddress,uint32 destinationNetwork,address destinationAddress,uint256 amount,bytes metadata)

执行参数

# Name Type Data
0 smtProof bytes32[32] 0x0000000000000000000000000000000000000000000000000000000000000000 0x5c4dafd55279a81649518c48d62f1e9105c9e7f5a8933aa2fce126d207755c14 0x890afe4ec8996c6ddd3977287b067f0f67dd25cd11cda85b22a93deac5675cdd 0xb6b78f0847e6ecdfc18ee568a1349fae5f336bdce9716be04db241b68b8dd60b 0x18dd01806c4a8a02ac0303f33fe609a944d81197cb52e8b8e159fbf9e45f12ed 0x0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d 0x4ac259557eb77da7cf4309feb02d02d0884d94e56bbf71f539bb3871e5c5f0db 0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83 0x08f9cb503a809cc64017397ec880786e6713c3ba6a85c181d02ae7536e9b58e3 0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0 0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5 0xa647f1787afe7ec81c77a49649ba32057b0550470d3c9318dda05fcb8168d914 0xe1f88e3362870dcdb9c43a352e2b031a0c71080b78cc2a5732c3a5c1c0c8e3b4 0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb 0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc 0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2 0x645b9978ad76c57db977fe48efb0b43110e3ebe78f9badd9047aac6bcd8d66a5 0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a 0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0 0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0 0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2 0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9 0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377 0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652 0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef 0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d 0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0 0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e 0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e 0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322 0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735 0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9
1 index uint32 72030
2 mainnetExitRoot bytes32 0x8ac4bfc9b4381015f4d41ca9d127a0a4065827d9c61ae290ffbf401ae446a97a
3 rollupExitRoot bytes32 0xd226edaccb2a0c0dc760d2a670a84862a271af7916e0a289b286f61435378411
4 originNetwork uint32 0
5 originTokenAddress address 0x0000000000000000000000000000000000000000
6 destinationNetwork uint32 1

合约地址0xf6beeebb578e214ca9e23b0e9683454ff88ed2a7 为 EIP-1967 Transparent Proxy代理合约,代理的逻辑合约地址为0x39e780d8800f7396e8b7530a8925b14025aedc77
合约源码:https://testnet-zkevm.polygonscan.com/address/0x39e780d8800f7396e8b7530a8925b14025aedc77#code

/**
     * @notice Verify merkle proof and withdraw tokens/ether
     * @param smtProof Smt proof
     * @param index Index of the leaf
     * @param mainnetExitRoot Mainnet exit root
     * @param rollupExitRoot Rollup exit root
     * @param originNetwork Origin network
     * @param originTokenAddress  Origin token address, 0 address is reserved for ether
     * @param destinationNetwork Network destination
     * @param destinationAddress Address destination
     * @param amount Amount of tokens
     * @param metadata Abi encoded metadata if any, empty otherwise
     */
    function claimAsset(
        bytes32[_DEPOSIT_CONTRACT_TREE_DEPTH] calldata smtProof,
        uint32 index,
        bytes32 mainnetExitRoot,
        bytes32 rollupExitRoot,
        uint32 originNetwork,
        address originTokenAddress,
        uint32 destinationNetwork,
        address destinationAddress,
        uint256 amount,
        bytes calldata metadata
    ) external ifNotEmergencyState {
        // Verify leaf exist and it does not have been claimed
        _verifyLeaf(
            smtProof,
            index,
            mainnetExitRoot,
            rollupExitRoot,
            originNetwork,
            originTokenAddress,
            destinationNetwork,
            destinationAddress,
            amount,
            metadata,
            _LEAF_TYPE_ASSET
        );

        // Transfer funds
        if (originTokenAddress == address(0)) {
            // Transfer ether
            /* solhint-disable avoid-low-level-calls */
            (bool success, ) = destinationAddress.call{value: amount}(
                new bytes(0)
            );
            if (!success) {
                revert EtherTransferFailed();
            }
        } else {
            // Transfer tokens
            if (originNetwork == networkID) {
                // The token is an ERC20 from this network
                IERC20Upgradeable(originTokenAddress).safeTransfer(
                    destinationAddress,
                    amount
                );
            } else {
                // The tokens is not from this network
                // Create a wrapper for the token if not exist yet
                bytes32 tokenInfoHash = keccak256(
                    abi.encodePacked(originNetwork, originTokenAddress)
                );
                address wrappedToken = tokenInfoToWrappedToken[tokenInfoHash];

                if (wrappedToken == address(0)) {
                    // Get ERC20 metadata
                    (
                        string memory name,
                        string memory symbol,
                        uint8 decimals
                    ) = abi.decode(metadata, (string, string, uint8));

                    // Create a new wrapped erc20 using create2
                    TokenWrapped newWrappedToken = (new TokenWrapped){
                        salt: tokenInfoHash
                    }(name, symbol, decimals);

                    // Mint tokens for the destination address
                    newWrappedToken.mint(destinationAddress, amount);

                    // Create mappings
                    tokenInfoToWrappedToken[tokenInfoHash] = address(
                        newWrappedToken
                    );

                    wrappedTokenToTokenInfo[
                        address(newWrappedToken)
                    ] = TokenInformation(originNetwork, originTokenAddress);

                    emit NewWrappedToken(
                        originNetwork,
                        originTokenAddress,
                        address(newWrappedToken),
                        metadata
                    );
                } else {
                    // Use the existing wrapped erc20
                    TokenWrapped(wrappedToken).mint(destinationAddress, amount);
                }
            }
        }

        emit ClaimEvent(
            index,
            originNetwork,
            originTokenAddress,
            destinationAddress,
            amount
        );
    }

// TODO 代码分析

确认余额

https://testnet-zkevm.polygonscan.com/address/0x10210572d6b4924af7ef946136295e9b209e1fa0
// Note: Our ETH balance display is temporarily unavailable. Please check back later.
testnet-zkevm.polygonscan.com 浏览器余额出问题了,直接MetaMask查看

以正确到账

//TODO testnet-zkevm反向Goerli的转账跟踪

opside 跨链测试

Opside介绍

Opside 是一个三层区块链平台,形式为“Base chains <- Opside chain <- Rollups”。 它具有资产多样性和无限可扩展性等优势,为高吞吐量的web3应用提供友好的运行环境。

三层架构

测试三层跨链转账

1.MetaMask添加Opside测试网络信息

2.MetaMask添加Opside zkEVM 测试网络信息

3. 从水龙头获取代币

领取网址:https://faucet-testnet.opside.network/
领取时需要对指定消息进行签名

交易hash

https://opside.info/address/0x10210572d6b4924Af7Ef946136295e9b209E1FA0

领取代币类型和数量

MetaMask手动添加代币合约地址到资产

USDT:0xDEd24358C0d7C96BC419F479771D1da3443Fe52d
USDC:0x407d6E2bF44A1B70eBd51CcF0aFCFBbD5F0b6d15
VTP:0x956a81C7D7031Fd123961cC69C28a2a49884FC68

4. 测试第1层->第2层桥接

跨链桥网址: https://bridge-testnet.opside.network/

sepolia转1USDT到opside

// TODO

opside转1USDT到Opside zkEVM Testnet

跨链桥网址:https://zkbridge-testnet.opside.network/

  1. Approve USDT spending cap
    0x10210572d6b4924af7ef946136295e9b209e1fa0 -> 0xded24358c0d7c96bc419f479771d1da3443fe52d
    https://opside.info/tx/0xc0d592c5edcc533abddf83f0b38c40a4099ef2ef3de0b6fd862048df24b06036
  2. Bridge Asset
    0x10210572d6b4924af7ef946136295e9b209e1fa0 -> 0xfb15d16f87ad92f0a6d54a9fbc951676701071f9
    https://opside.info/tx/0x1d2dfc8ce07e3039b46e92f27a7bbd5dc461874f4b5020ee3931b0b12804db04

备注:https://testrpc.zkevm.opside.network/bridge-service/bridges/0x10210572d6b4924af7ef946136295e9b209e1fa0?limit=10000&offset=0
测试时这个API,ssl证书有问题:ERR_SSL_VERSION_OR_CIPHER_MISMATCH

Opside zkRollup L3 测试网的RPC同样问题 ERR_SSL_VERSION_OR_CIPHER_MISMATCH
https://testrpc.zkevm.opside.network/

// TODO 等待解决后继续测试,先忙其他

opside转1USDT到sepolia

  1. Approve USDT spending cap
    0x10210572d6b4924af7ef946136295e9b209e1fa0 -> 0x10210572d6b4924af7ef946136295e9b209e1fa0
    https://opside.info/tx/0xca2d7fdf791b7432a3e2067bc814ce9ca66ad2163d55bc805743fad6996ffc98
  2. Deposit
    0x10210572d6b4924af7ef946136295e9b209e1fa0 -> 0x832e50eec9d7f9e2b5d4286a5834400dfaeafc3f
    https://opside.info/tx/0x6b6a505b4aa1aa4b314d5b69a316713d6443f0092e7e9f2b96e8b18bc8778fe6
  3. sepolia.etherscan
    0x91b126ff9af242408090a223829eb88a61724aa5 -> 0xe8b0a865e4663636bf4d6b159c57333210b0c229
    ERC-20 Tokens Transferred: 0x89a5f2c62213b18ee5f83b21cb1a323920c9b101 -> 0x10210572d6b4924af7ef946136295e9b209e1fa0
    https://sepolia.etherscan.io/tx/0x369078b11063231d35738c6afcde52477c5fe5dd78535c9f282f1e36fcac5de8
    获得1 USDT

    https://sepolia.etherscan.io/token/0x969d499507b4f437953db24a4980fdeeda6db8a1?a=0x10210572d6b4924Af7Ef946136295e9b209E1FA0

参考文档

https://docs.opside.network/
https://docs.opside.network/user-guides/video-tutorial

ETH2.0 技术调研和测试部署

1. ETH1.0和2.0的对比

1.1 共识机制

共识改进

  • 节能,比pow消耗更少能源
  • 低门槛,硬件相对较低
  • 降低中心化,pos更易节点参与
  • 增加攻击成本,违规惩罚

1.2 节点组成

2. ETH 2.0 方案组成

2.1 节点架构

  • 执行层->P2P1

    • 维护交易池,交易处理,gossip广播
    • 状态管理
    • 创建执行负载
    • 用户网关->提供对外RPC
  • 共识层->P2P2

    • 共享广播块和证明
    • 运行分叉选择算法
    • 跟踪链的头部
    • 管理信标状态(包含共识和执行信息)
    • 跟踪 RANDAO 中累积的随机性
    • 跟踪justification和finalization
    • 验证器
      • 提议区块
      • 创建证明
      • 累积奖励/惩罚

    客户端设置

2.2 执行与共识层通信

共识和执行层之间通过“Engine-API”的API发送指令。

共享一个 ENR(以太坊节点记录),其中包含(eth1 密钥和 eth2 密钥)。

层内广播协议:gossip

共识层非区块生产者:

共识层-->接收区块->预先验证块(有效sender)->区块中的交易->执行层->执行交易并验证块头中的状态(哈希匹配)->共识层->添加本地链头部->创建证明->广播证明

共识层为区块生产者时:

共识层->收到通知(下一个区块当选生产者)->调用执行层(create block)->交易内存池->打包区块->执行交易生成区块哈希<-共识层抓取交易和区块哈希->添加到信标块->广播区块

3. 环境测试

3.1 测试方案选配

根据客户端多样性分布
https://clientdiversity.org/

测试方案:Prysm棱镜 + Geth

部署参考文档(prylabs

3.2 测试环境

  • 系统: Ubuntu 20.04
    • CPU:4+ 核 @ 2.8+ GHz
    • 内存:16GB+
    • 存储:2TB+ SSD
    • 网络:8 MBit/秒
  • 测试网络: Goerli-Prater
  • 执行客户端: Geth 1.11.3
  • EN-BN 连接: HTTP-JWT

eth2.0测试网

  • Sepolia
    • 封闭验证器集
    • 验证者集受到限制,主要由客户和测试团队监督
    • 较小的区块链状态和历史
    • 同步速度快,需要更少的存储承诺
  • Goerli
    • 开放验证者集
    • 携带大状态并需要高存储承诺
    • 需要更长的时间才能与网络的当前状态同步

如果测试合约选Sepolia, 如果想测试参与节点治理选Goerli

3.3 测试环境部署

设置工作目录

export workdir=/mnt/d/eth2.0/ethereum

3.3.1 安装 Prysm

cd $workdir
mkdir consensus
mkdir execution
cd consensus
mkdir prysm && cd prysm
curl https://raw.githubusercontent.com/prysmaticlabs/prysm/master/prysm.sh --output prysm.sh && chmod +x prysm.sh

3.3.2 生成 JWT Secret

./prysm.sh beacon-chain generate-auth-secret

3.3.3 下载和运行执行客户端

下载

cd $workdir/execution
wget https://gethstore.blob.core.windows.net/builds/geth-linux-amd64-1.11.3-5ed08c47.tar.gz
tar -zxvf ./geth-linux-amd64-1.11.3-5ed08c47.tar.gz
mv ./geth-linux-amd64-1.11.3-5ed08c47/geth ./
rm ./geth-linux-amd64-1.11.3-5ed08c47.tar.gz
rm -rf ./geth-linux-amd64-1.11.3-5ed08c47

运行

nohup ./geth --goerli --http --http.api eth,net,engine,admin --authrpc.jwtsecret $workdir/consensus/prysm/jwt.hex 2>> ./geth.log &

3.3.4 Prysm 运行信标节点

cd $workdir/consensus/prysm/

nohup ./prysm.sh beacon-chain --execution-endpoint=http://localhost:8551 --prater --jwt-secret=./jwt.hex --suggested-fee-recipient=0x10210572d6b4924Af7Ef946136295e9b209E1FA0 --accept-terms-of-use --checkpoint-sync-url=https://sync-goerli.beaconcha.in --genesis-beacon-api-url=https://sync-goerli.beaconcha.in 2>> ./prysm.log &

3.3.5 Prysm 运行验证器

cd $workdir/
git clone -b master --single-branch https://github.com/ethereum/staking-deposit-cli.git
cd staking-deposit-cli/
./deposit.sh new-mnemonic

按照提示,依次输入参数

Please choose your language ['1. العربية', '2. ελληνικά', '3. English', '4. Français', '5. Bahasa melayu', '6. Italiano', '7. 日本語', '8. 한국어', '9. Português do Brasil', '10. român', '11. Türkçe', '12. 简
体中文']:  [English]: 12
请选择您的助记符语言 ['1. 简体中文', '2. 繁體中文', '3. čeština', '4. English', '5. Italiano', '6. 한국어', '7. Português', '8. Español']:  [简体中文]: 4
请选择您想要运行多少验证者: 1
请选择(主网或测试网)网络名/链名 ['mainnet', 'ropsten', 'goerli', 'sepolia', 'zhejiang']:  [mainnet]: goerli
用来保护您密钥库的密码。您在设置您的 Ethereum PoS 验证者时需要重新输入密码以便解密它们。:
重复输入以确认:

最后生成助记词,保存并输入确认

cool disorder brand vast jaguar sponsor bamboo ...
您的密钥可以在这里找到: /mnt/d/eth2.0/ethereum/staking-deposit-cli/validator_keys

执行完将生成

  1. 新的助记词
  2. validator_keys文件夹
    1. deposit_data-*.json // 上传到以太坊启动板的存款数据
    2. keystore-m_*.json // 公钥和加密的私钥

复制validator_keysconsensus文件夹中

cp -r $workdir/staking-deposit-cli/validator_keys $workdir/consensus
导入密钥库
cd $workdir/consensus/prysm
./prysm.sh validator accounts import --keys-dir=$workdir/consensus/validator_keys --prater

出现以下提示代表成功

INFO accounts: Successfully created new wallet wallet-path=/home/surou/.eth2validators/prysm-wallet-v2
Successfully imported 1 accounts, view all of them by running `accounts list`

导入后钱包位置:$HOME/.eth2validators/prysm-wallet-v2

上传存款数据

转到Goerli-Prater Launchpad 的存款数据上传页面,将上面的deposit_data-*.json 上传,会提示您连接钱包。

此时会存入 32 GETH Prater 测试网的存款合约。

避免重复抵押

提交dapp已经做了的判断

查看发起的抵押交易

goerli.etherscan.io

查看链上合约

goerli.etherscan.io

/// @notice Submit a Phase 0 DepositData object.
    /// @param pubkey A BLS12-381 public key.
    /// @param withdrawal_credentials Commitment to a public key for withdrawals.
    /// @param signature A BLS12-381 signature.
    /// @param deposit_data_root The SHA-256 hash of the SSZ-encoded DepositData object.
    /// Used as a protection against malformed input.
    function deposit(
        bytes calldata pubkey,
        bytes calldata withdrawal_credentials,
        bytes calldata signature,
        bytes32 deposit_data_root
    ) override external payable {
        // Extended ABI length checks since dynamic types are used.
        require(pubkey.length == 48, "DepositContract: invalid pubkey length");
        require(withdrawal_credentials.length == 32, "DepositContract: invalid withdrawal_credentials length");
        require(signature.length == 96, "DepositContract: invalid signature length");

        // Check deposit amount
        require(msg.value >= 1 ether, "DepositContract: deposit value too low");
        require(msg.value % GWEI == 0, "DepositContract: deposit value not multiple of gwei");
        uint deposit_amount = msg.value / GWEI;
        require(deposit_amount <= type(uint64).max, "DepositContract: deposit value too high");

        // Emit `DepositEvent` log
        bytes memory amount = to_little_endian_64(uint64(deposit_amount));
        emit DepositEvent(
            pubkey,
            withdrawal_credentials,
            amount,
            signature,
            to_little_endian_64(uint64(deposit_count))
        );

        // Compute deposit data root (`DepositData` hash tree root)
        bytes32 pubkey_root = sha256(abi.encodePacked(pubkey, bytes16(0)));
        bytes32 signature_root = sha256(abi.encodePacked(
            sha256(abi.encodePacked(signature[:64])),
            sha256(abi.encodePacked(signature[64:], bytes32(0)))
        ));
        bytes32 node = sha256(abi.encodePacked(
            sha256(abi.encodePacked(pubkey_root, withdrawal_credentials)),
            sha256(abi.encodePacked(amount, bytes24(0), signature_root))
        ));

        // Verify computed and expected deposit data roots match
        require(node == deposit_data_root, "DepositContract: reconstructed DepositData does not match supplied deposit_data_root");

        // Avoid overflowing the Merkle tree (and prevent edge case in computing `branch`)
        require(deposit_count < MAX_DEPOSIT_COUNT, "DepositContract: merkle tree full");

        // Add deposit data root to Merkle tree (update a single `branch` node)
        deposit_count += 1;
        uint size = deposit_count;
        for (uint height = 0; height < DEPOSIT_CONTRACT_TREE_DEPTH; height++) {
            if ((size & 1) == 1) {
                branch[height] = node;
                return;
            }
            node = sha256(abi.encodePacked(branch[height], node));
            size /= 2;
        }
        // As the loop should always end prematurely with the `return` statement,
        // this code should be unreachable. We assert `false` just to be safe.
        assert(false);
    }

合约内没有限定质押地址,可以代为质押

交易参数如下
0   pubkey  bytes   0xb23fca698e5b57c2dd09f16e10b97d532a18b574a46e6539bd9d83e79c5922230bc8990def676e3e78534a3fd8cbe58d
1   withdrawal_credentials  bytes   0x004734640dd34942fc621f643910f86e52b4e5f03db42d9cf6e14863b1148529
2   signature   bytes   0xb46ac23ab45b798331d706b91a635f59b00019cff96462493fae91877dc18d2c6d30e2684197547cd48c079ad94265ff07f36ab48b61b94ef90e3e7e3eeaf96d52dbb012690113c4fe3bc42274a9eb72d82dbdcbea8aa08e2e00e88978c0de3e
3   deposit_data_root   bytes32 0x0c4b49597ef312f110596b87e333e4c76ef8381216dd52ca63f2c84ea2c152d8

信标链处理您的存款大约需要 16-24 小时。 一旦存入金额总计达到 32 ETH,该验证器就有资格被激活。

查看已抵押信息

beaconcha.in

当前测试抵押节点信息

beaconscan.com
质押生效后才能看到信息

运行验证器

nohup ./prysm.sh validator --wallet-dir=$HOME/.eth2validators/prysm-wallet-v2 --wallet-password-file ./password --prater 2>> ./validator.log &

检查节点和验证器状态

节点日志

追块过程中
  • Geth常规日志
INFO [03-11|16:46:14.726] Syncing: chain download in progress      synced=44.90% ...
INFO [03-11|16:46:15.318] Forkchoice requested sync to new head    number=8,633,606 hash=522f76..69cb70 finalized=8,633,551
INFO [03-11|16:46:15.859] Syncing: state download in progress      synced=10.27% s
  • prysm常规日志
[2023-03-11 16:47:40]  INFO blockchain: Called new payload with optimistic block payloadBlockHash=0xb7864552d082 slot=5166177
  • validator日志
[2023-03-11 16:48:55]  INFO validator: Waiting for beacon node to sync to latest chain head
追齐高度后
生效之前

validator日志显示

INFO validator: Waiting for deposit to be observed by beacon node pubKey=0xb23fca698e5b status=UNKNOWN_STATUS

prysm日志显示

 WARN rpc/validator: Not connected to ETH1. Cannot determine validator ETH1 deposit block number
生效之后

// 待补充

怠工惩罚

如果当前节点质押生效后,未能及时提议区块和证明,将被惩罚 -10680 GWei/epoch

4. 附加配置

开放必要端口

执行客户端 默认端口 共识客户端 默认端口
Geth 30303 TCP/UDP Teku 9000 TCP/UDP
Besu 30303 TCP/UDP Lighthouse 9000 TCP/UDP
Erigon 30303 TCP/UDP Nimbus 9000 TCP/UDP
Nethermind 30303 TCP/UDP Prysm 13000 TCP, 12000 UDP

配置时间同步

timedatectl // 检查是否NTP服务是积极的.
sudo timedatectl set-ntp on // 如果NTP服务不是积极的

5. 在线文档

节点设置

费用收件人

Lighthouse | Nimbus | Prysm | Teku

Discord

JWT认证

最新公告

Goerli-PraterMainnet

监控

Lighthouse | Nimbus | Prysm | Teku

安全最佳实践

https://docs.prylabs.network/docs/security-best-practices

Prysm社区

邮件列表Prysm Discord 服务器r/ethstakerEthStaker Discord 服务器

6. 节点运行架构

以太坊节点

公共检查点

https://notes.ethereum.org/@launchpad/checkpoint-sync

节点统计

https://www.ethernodes.org/

节点质押

goerli: https://goerli.launchpad.ethereum.org/zh

mainnet: https://launchpad.ethereum.org/zh

生产服务器配置

最低要求
  • 2 核以上的 CPU
  • 8 GB 内存
  • 700GB 可用磁盘空间
  • 10+ MBit/s 带宽
推荐规格
  • 具有 4 个以上内核的快速 CPU
  • 16 GB+ 内存
  • 1+TB 的快速 SSD
  • 25+ MBit/s 带宽

测试网

即插即用解决方案

https://docs.dappnode.io/user/quick-start/first-steps/

https://github.com/NiceNode/nice-node

https://eth-docker.net/

https://docs.sedge.nethermind.io/docs/intro