您正在查看: Ethereum-优秀转载 分类下的文章

以太坊一个区块可以包含多少交易

今天在做以太坊开发时,突然想到一个问题,以太坊一个区块包含的交易个数由什么决定?

如果交易池中有足够的交易,一个区块最多可容纳多少交易?

带着这个问题,我阅读了一下go-ethereum中关于挖矿的源代码,找到了答案。

先抛出结论:

影响一个区块交易个数的因素有两个:

  1. 交易池中的交易个数。这个很好理解,交易池的交易个数直接决定了一个矿工可以打包多少交易到区块中。
  2. 区块允许的GasLimit。GasLimit又由父块GasLimit、GasFloor和GasCeil共同决定(1.8版本以前只受父块GasLimit影响),当交易的gas总计大于GasLimit时,交易将不在打包的区块中。
    其中gasFloor和gasCeil是在geth的中mine的两个配置项。详见文档:https://geth.ethereum.org/docs/interface/command-line-options

结论主要从"go-ethereum/miner/worker.go"源文件中得出。worker相当于一个挖矿工人,负责具体的挖矿工作流程。在worker对象中有一个“commitNewWork”方法,是创建一个新的区块,其中计算了该区块的GasLimit和需要处理的交易池中的交易。相关代码如下:

func (w *worker) commitNewWork(interrupt *int32, noempty bool, timestamp int64) {
    // 创建区块头
    header := &types.Header{
        ParentHash: parent.Hash(),
        Number:     num.Add(num, common.Big1),
        // 计算GasLimit
        GasLimit:   core.CalcGasLimit(parent, w.config.GasFloor, w.config.GasCeil),
        Extra:      w.extra,
        Time:       uint64(timestamp),
    }

    // 从交易池中读取交易
    pending, err := w.eth.TxPool().Pending()
    if err != nil {
        log.Error("Failed to fetch pending transactions", "err", err)
        return
    }

    // Short circuit if there is no available pending transactions
    if len(pending) == 0 {
        w.updateSnapshot()
        return
    }

    // Split the pending transactions into locals and remotes
    localTxs, remoteTxs := make(map[common.Address]types.Transactions), pending
    for _, account := range w.eth.TxPool().Locals() {
        if txs := remoteTxs[account]; len(txs) > 0 {
            delete(remoteTxs, account)
            localTxs[account] = txs
        }
    }

    if len(localTxs) > 0 {
        txs := types.NewTransactionsByPriceAndNonce(w.current.signer, localTxs)
        if w.commitTransactions(txs, w.coinbase, interrupt) {
            return
        }
    }

    if len(remoteTxs) > 0 {
        txs := types.NewTransactionsByPriceAndNonce(w.current.signer, remoteTxs)
        if w.commitTransactions(txs, w.coinbase, interrupt) {
            return
        }
    }
}

“commitNewWork”方法中获取到交易池中的交易后将交易提交给了“commitTransactions”方法对交易进行验证。

func (w *worker) commitTransactions(txs *types.TransactionsByPriceAndNonce, coinbase common.Address, interrupt *int32) bool {
    // 将区块头中的GasLimit赋值给gasPool
    if w.current.gasPool == nil {
        w.current.gasPool = new(core.GasPool).AddGas(w.current.header.GasLimit)
    }

    // 循环判断所有交易
    for {
        // gasPool中的gas小于21000是跳出循环
        if w.current.gasPool.Gas() < params.TxGas {
            log.Trace("Not enough gas for further transactions", "have", w.current.gasPool, "want", params.TxGas)
            break
        }

        // 按照交易gas从大到小的顺序获取下一个交易
        tx := txs.Peek()

        // 没有交易后跳出循环
        if tx == nil {
            break
        }
        // 提交交易
        logs, err := w.commitTransaction(tx, coinbase)
    }
}

将交易提交给“commitTransaction”方法后,回调用

receipt, _, err := core.ApplyTransaction(w.config, w.chain, &coinbase, w.current.gasPool, w.current.state, w.current.header, tx, &w.current.header.GasUsed, vm.Config{})

在ApplyTransaction方法中会将gasPool中的gas值减去该笔交易的gas,当gasPool的gas值小于21000时,剩下的交易将不在打包的该区块中。

回头在来看一下区块中的GasLimit是怎么计算的。

core.CalcGasLimit(parent, w.config.GasFloor, w.config.GasCeil)方法在“go-ethereum/core/block_validator.go”,代码如下:

// CalcGasLimit computes the gas limit of the next block after parent. It aims
// to keep the baseline gas above the provided floor, and increase it towards the
// ceil if the blocks are full. If the ceil is exceeded, it will always decrease
// the gas allowance.
func CalcGasLimit(parent *types.Block, gasFloor, gasCeil uint64) uint64 {
    // contrib = (parentGasUsed * 3 / 2) / 1024
    contrib := (parent.GasUsed() + parent.GasUsed()/2) / params.GasLimitBoundDivisor

    // decay = parentGasLimit / 1024 -1
    decay := parent.GasLimit()/params.GasLimitBoundDivisor - 1

    /*
        strategy: gasLimit of block-to-mine is set based on parent's
        gasUsed value.  if parentGasUsed > parentGasLimit * (2/3) then we
        increase it, otherwise lower it (or leave it unchanged if it's right
        at that usage) the amount increased/decreased depends on how far away
        from parentGasLimit * (2/3) parentGasUsed is.
    */
    limit := parent.GasLimit() - decay + contrib
    if limit < params.MinGasLimit {
        limit = params.MinGasLimit
    }
    // If we're outside our allowed gas range, we try to hone towards them
    if limit < gasFloor {
        limit = parent.GasLimit() + decay
        if limit > gasFloor {
            limit = gasFloor
        }
    } else if limit > gasCeil {
        limit = parent.GasLimit() - decay
        if limit < gasCeil {
            limit = gasCeil
        }
    }
    return limit
}

计算GasLimit的策略很有意思,受父块的GasLimit、挖矿的gas上限gasCeil和gas下限gasFloor三者共同决定。

当父块的交易里的gas总和大于父块GasLimit的2/3时,则增加当前块的GasLimit,反之减少当前块的GasLimit,同时,保证GasLimit的范围在gasFloor和gasCeil之间。

转载:https://www.jianshu.com/p/3588fd52ec0a

以太坊分片研究纲要

这是一个持续策划的列表,将添加或删除条目以反映与当前研究状态最相关的文章。

无国籍客户和证人

跨分片通信

基本信息和规格

权益证明理论

股权证明常见问题解答:https://github.com/ethereum/wiki/wiki/Proof-of-Stake-FAQ
Casper FFG 论文:https://arxiv.org/abs/1710.09437
基于证明委员会的完整 PoS 链:https://ethresear.ch/t/attestation-committee-based-full-pos-chains/2259

Casper FFG/GHOST/信标链模拟

卡斯帕CBC

CBC Casper 教程:https://vitalik.ca/general/2018/12/05/cbc_casper.html
Casper CBC,简化!:https://medium.com/@aditya.asgaonkar/casper-cbc-simplified-2370922f9aa6
信标链友好型 CBC Casper:https://ethresear.ch/t/beacon-chain-friendly-cbc-casper/4710/2
按位 LMD GHOST:https://ethresear.ch/t/bitwise-lmd-ghost/4749/5
LMD GHOST 实现:https://ethresear.ch/t/comparing-lmd-ghost-implementations/4945/3

外部链接

各种各样的

轻客户端

存储维护费/租金

监护证明

数据可用性证明

随机性

时间戳

数据结构

杂项杂项

英文原文:https://notes.ethereum.org/@serenity/H1PGqDhpm?type=view
翻译来自:谷歌

Trust EVM 让EOS支持以太坊合约

先记录下,做个笔记,翻译来自谷歌,有能力看原文。。
https://docs.trust.one/

Trust 是基于 EOS 网络的以太坊虚拟机,为开发者提供了一个交钥匙解决方案,可以在完全兼容以太坊的链上运行他们的应用程序,同时享受 EOS 的高吞吐量、可扩展性、安全性和可靠性,以及低交易成本 他们的用户。

由于设计的高度兼容性,以太坊原生应用程序可以无缝移植到 Trust。 开发人员在这里使用他们的 Solidity 智能合约时可能会喜欢熟悉的以太坊工具。

特点:

  • 确定性的Gas计算
  • 指令集级别的EVM兼容性
  • 完全的RPC兼容

技术实现

https://docs.trust.one/understanding-trust/architecture
EVM 作为 EOS 网络中的智能合约实现。 在 EVM 网络中生成交易是通过调用 EOS 网络上的 EVM 合约来完成的,EVM 的状态可以从 EOS 上的信息中得出。
为了实现完全 RPC 兼容性的目标,我们利用功能齐全的以太坊节点(当前设计中的 Geth)来提供所有读取 API,而所有写入访问将被转发到一个小型服务,以将它们打包到对 EVM 合约的 EOS 调用中。

我们所做的是设置一个“翻译器”服务,该服务读取运行在 EOS 上的 EVM 智能合约的共识输出,将该信息翻译成相应的 ETH 格式块并将这些块提供给 Geth 节点。 然后我们可以公开以太坊客户端 Web3 JSON RPC API(如有必要,还可以公开其他 API)。
如果我们发现它们更适合这种情况,我们也可能会在不同的场景中使用以太坊节点的其他实现。

未来的改进

当前设计正在运行并提供预期的兼容性级别。 还有一些潜在的方法可以改进整个系统:
合并 Translator 服务和 Geth 节点,去除相对不可靠的 p2p eth/66 通道。
将所有内容合并到一个 EOSIO 插件中,以便于部署。

MetaMask测试

https://docs.trust.one/about-the-testnet/connect-metamask

Network Name: Trust Network Testnet Preview
Chain ID: 15555
New RPC URL*: https://api.testnet-dev.trust.one
Currency Symbol: EVM
Block Explorer URL (Optional): https://trustscan.one

Faucet

https://faucet.testnet-dev.trust.one/

https://www.odaily.news/post/5178155
https://www.odaily.news/post/5178155

使用standard-input-json验证Solidity源码

使用 standard-input-json(以BSC测试链为例)

合约源码

Storage.sol

// SPDX-License-Identifier: MIT

pragma solidity >=0.7.0 <0.9.0;
import "@openzeppelin/contracts/access/Ownable.sol";

contract Storage is Ownable {
    uint256 number;

    function setNumber(uint256 num) public onlyOwner {
        number = num;
    }

    function getNumber() public view returns (uint256) {
        return number;
    }
}

JSON格式的输入

Storage.json

{
    "language": "Solidity",
    "sources": {
        "contracts/Storage.sol": {
            "content": "// SPDX-License-Identifier: MIT\n\npragma solidity >=0.7.0 <0.9.0;\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\ncontract Storage is Ownable {\n    uint256 number;\n\n    function setNumber(uint256 num) public onlyOwner {\n        number = num;\n    }\n\n    function getNumber() public view returns (uint256) {\n        return number;\n    }\n}"
        },
        "@openzeppelin/contracts/access/Ownable.sol": {
            "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n        _;\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing any functionality that is only available to the owner.\n     */\n    function renounceOwnership() public virtual onlyOwner {\n        _transferOwnership(address(0));\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Can only be called by the current owner.\n     */\n    function transferOwnership(address newOwner) public virtual onlyOwner {\n        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n        _transferOwnership(newOwner);\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Internal function without access restriction.\n     */\n    function _transferOwnership(address newOwner) internal virtual {\n        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n"
        },
        "@openzeppelin/contracts/utils/Context.sol": {
            "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n    function _msgSender() internal view virtual returns (address) {\n        return msg.sender;\n    }\n\n    function _msgData() internal view virtual returns (bytes calldata) {\n        return msg.data;\n    }\n}\n"
        }
    },
    "settings": {
        "optimizer": {
            "enabled": true,
            "runs": 200
        },
        "outputSelection": {
            "*": {
                "*": [
                    "abi",
                    "evm.bytecode",
                    "evm.deployedBytecode",
                    "evm.methodIdentifiers",
                    "metadata"
                ],
                "": [
                    "ast"
                ]
            }
        }
    }
}

content内容:将solidity源码转换为JSON字符串。

Javascript Serializer(推荐方法2、方法3)

Convert/Escapes an object to a JSON string
将solidity源码转换为JSON字符串

方法1.BSC网址

去掉最后的 ”

方法2.字符串转义

// SPDX-License-Identifier: MIT\n\npragma solidity >=0.7.0 <0.9.0;\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\ncontract Storage is Ownable {\n    uint256 number;\n\n    function setNumber(uint256 num) public onlyOwner {\n        number = num;\n    }\n\n    function getNumber() public view returns (uint256) {\n        return number;\n    }\n}

方法3. Hardhat项目下

编译合约:

npx hardhat compile

打开artifacts\build-info路径下的json文件
input字段内容

部署合约

部署合约

与Storage.json配置文件相同

BSC浏览器验证合约

https://testnet.bscscan.com/address/0x1b3104004ebda264b88d04afb6ea66d70a2d51ac#code


  1. 转载自:https://learnblockchain.cn/article/3415