主页 > imtoken币不见了 > 第 1 章:了解以太坊

第 1 章:了解以太坊

imtoken币不见了 2023-02-21 07:47:55

区块链以太坊智能合约学习

第 1 章:了解以太坊

学习内容:第一个智能合约和区块链知识

第一个智能合约:

首先,我们知道以太坊编写智能合约的工具是solidity。

pragma solidity ^0.4.24;

合约币{

// 关键字 public 使状态变量从外部可读,它仅在创建合约时运行。 这个构造函数做的一件事是保存(外部)函数调用者的地址 msg.sender。

解决公共铸造者;

映射(地址=> uint)公共余额;

// 定义一个事件,客户端可以根据事件的变化做出反应

事件发送(地址从,地址到,单位数量);

// 构造函数,只在创建合约时运行一次

构造函数()公共{

minter = msg.sender;

}

// 挖矿方法,用于产生新的货币,mint是一个实际可以被用户或其他合约调用的方法。 但是如果 mint 被合约创建者以外的人调用,则什么也不会发生。

function mint(address receiver, uint amount) public {

if (msg.sender != minter) 返回;

余额[接收方] += 金额;

}

// 发送货币,send也是一个方法,实际上可以被用户或者其他合约调用。 任何人(只要他们拥有硬币)都可以调用 send 将硬币发送给其他人。

功能发送(地址接收者,单位数量)公共{

if (balances[msg.sender] balances[msg.sender] -= amount;

余额[接收方] += 金额;

发射已发送(消息。发送者,接收者,金额);

}

}

第一行代码是告诉编译器如何编译这段代码,即导入solidity版本包。 不同版本的包可能不可用或与某些代码变量不兼容。 一般来说,第三名的变化很小。 pragma solidity ^0.4.24;

解决公共铸造者; 关键字段public用于表示状态变量的可见性,这和Java、C++等其他语言类似,不同的是这行代码声明了一个可以访问的地址类型(address)的状态publicly Variables,Solid Town 的编译器会自动为公共状态变量生成一个访问函数。

函数 minter() 返回(地址){return minter;}

请注意,我们不需要自己添加这个函数,如果我们添加一个同名函数,编译器生成的函数将不再起作用。

映射(地址=> uint)公共余额;

这行代码创建了另一个公共状态变量,其数据类型是更复杂的映射(将在本书第 4 章中进一步解释),它存储键值对。 映射可以看做是一个哈希表,它进行虚拟初始化,使所有可能的键都对应一个全零值。 但是,与其他语言中的映射不同,Solidity中的映射是不可遍历的(不可能得到所有键或值的列表),对于同一个公共状态变量,编译器会为其生成一个访问函数,函数代码为如下:

函数余额(地址_帐户)公共视图返回(uint){

返回余额[_account];

}

我们可以通过这个生成的访问函数查询一个账户的余额。

事件发送(地址从,地址到,单位数量); 声明事件,发出 Sent(msg.sender, receiver, amount); 触发事件

编译 solidity 的 URL:

区块链基本概念

交易/交易:

学过数据库的读者应该能理解“事务”的含义。 如果对事务这个词不是很了解,可以搜索“数据库事务”进行学习。

例如,假设有一个表格,其中列出了电子货币中所有账户的余额。 当从一个账户到另一个账户的转账请求发生时,该数据库的交易性质确保从一个账户中减去的金额被添加到另一个账户中。 如果由于某种原因,无法执行向目标账户添加金额的操作,则原账户中的金额不会发生变化。 此外,当事务特性应用于数据库时,其他事务不能修改数据库。 发送方(创建者)对交易进行密码签名,可以非常直观地理解为对数据库添加访问保护。 在上面的电子货币示例中,在 mint() 函数中进行简单检查可确保只有持有帐户密钥的人才能从该帐户中转出资金。

堵塞:

一个区块是若干笔交易的集合,它会被标记上一个时间戳和前一个区块的哈希标识符。 在对区块进行哈希处理后,会生成工作量证明来验证区块中的交易。 全网共识后,有效区块将被追加到区块链中。 为什么要这样设计? 因为在比特币和以太坊等完全去中心化的区块链中,需要解决被称为双花攻击(Cdouble-spend attack)的问题,即如果网络中存在两个相互冲突的交易,它们都想发生什么同一个账户的钱什么时候用完?

实际上,网络会自动选择一个交易序列,将其打包成一个区块,然后在所有参与节点中执行和分发(广播)。 如果两笔交易相互冲突,最终确认后发生的交易将被拒绝,不被列入区块。

这些区块在时间上形成一个线性序列,这就是区块链这个词的来源。 块定期添加到链中。 对于以太坊,这个间隔大约是 17 秒。

有时可能会发生块作为“顺序选择机制”(也称为挖掘)的一部分回滚的情况,但通常只在链的“末端”。 最后添加的块越多,回滚的可能性就越小。 因此,交易有可能被回滚甚至从区块链中删除,但您在交易发生后等待的时间越长,这种情况发生的可能性就越小。

Genesis Block是区块链中的第一个区块,其区块编号为0。它是区块链中唯一不指向前一个区块的区块,因为没有前一个区块。 只有当网络中的两个节点具有相同的创世块时,它们才会相互配对。

共识协议:工作量证明 (PoW)

目前以太坊使用工作量证明共识协议来防止区块链被篡改。 工作量证明系统需要解决一个复杂的数学难题来创建新块。 解决难题需要大量的计算能力,这使得创建块变得困难。 每个矿工独立解决数学难题,第一个解决难题的矿工是赢家,他的奖励是5 ETH和区块中所有交易的交易手续费。 一个区块有一个区块头(Header)和一系列交易。 每个块存储前一个块的哈希值,从而创建一个连接的链。

那么矿工是如何解谜的呢?

矿工首先从收到的广播中收集新的未开采交易,然后过滤掉非法交易。 合法交易必须满足私钥签名正确使用、账户余额充足等条件才能进行交易。

区块头包含上一个区块的哈希值、区块号、随机数(Nonce)、目标值(Target)、时间戳(Timestamp)、难度值(Difficulty)、矿工地址(Address)等。时间戳代表块初始时间。 以太坊使用Ethash哈希算法,目标值越低,寻找随机数的时间越长; 目标值越高,寻找随机数所需的时间就越少。

网络中的任何节点都可以检查区块链是否合法,首先检查区块链中的交易是否合法以及时间戳的验证,然后检查区块的目标值和随机数是否合法,矿工是否合法获得合法奖励等等。 如果网络中的一个节点收到两条不同的合法区块链,则所有区块的整体难度值较高的一条将被视为合法区块链。

股权证明(PoS)

以太坊最终将转向权益证明,以解决工作量证明的资源密集型问题。 权益证明的主要思想是:作为验证节点,首先要拥有一定数量的以太币,根据以太币的数量和时间,对区块进行投注和验证的权益将被生成。 只有拥有权益的节点才能有效地验证区块。 当经过验证的区块被打包入链后,将获得与其权益成比例的区块奖励。 如果验证了恶意或错误的块,则将扣除下注权益。

以太坊虚拟机 (EVM)

以太坊虚拟机(EVM,Ethereum Virtual Machine)是以太坊中智能合约的运行环境。

编译合约

运行在以太坊虚拟机上的是合约的字节码形式。 部署前需要编译合约。 您可以选择使用 Remix 或 sole 编译器。 后面的章节会继续讲解。

帐户

这里的账户可以简单理解为银行为我们开立的账户,但是在以太坊中,不需要申请账户,而是用户根据需要在钱包中生成。 转账行为是由一个账户发起,将财产转移到另一个账户的过程(其实这个财产也是一个数字)。 以太坊类似,同时赋予以太坊上的账户更多的功能。 事实上,账户在以太坊中扮演着非常重要的角色。以太坊中有两种类型的账户。

外部拥有的账户(有时在本书中简称为“外部账户”)和合约账户由相同的地址空间表示。 外部账户的地址由公钥确定,而合约账户的地址是在合约创建时确定的(这个地址是根据合约创建者的地址和该地址Nonce发送的交易数量计算得出的) .

两者有什么区别?

外部账户可以通过使用自己的私钥创建和签署交易来向另一个外部账户或合约账户发送消息。 两个外部账户之间发送的消息只是价值转移(类似于银行账户之间的转账)。

从外部账户到合约账户的消息激活合约账户的代码,允许它执行各种操作。 例如转移代币、写入内部存储、挖掘新代币、执行一些计算、创建新合约等。

与外部账户不同,合约账户不能自己发起交易。 但是合约账户可以触发另一笔交易以响应一笔交易。 因此,以太坊上的任何动作都是由外部账户触发的交易所发起的(即动作的发起者必须是外部账户)。

密钥文件

每个外部账户都由一对密钥定义,一个私钥和一个公钥。 账户由地址索引(地址就像银行帐号中的一串数字),取公钥的最后20个字节。 每个私钥/地址对都编码在一个密钥文件中。 密钥文件是 JSON 文本文件,可以使用任何文本编辑器打开和浏览。 密钥文件的关键部分是账户的私钥,通常使用创建账户时设置的密码进行加密。 在以太坊节点数据目录的keystore子目录下找到密钥文件。

如果忘记密码或密钥文件丢失。 所有以太币都将丢失。 没有密码就无法访问该帐户,并且没有“忘记密码”选项。 所以一定不要忘记密码。

帐户状态

帐户状态有四个组成部分,无论帐户类型如何,它们都会存在。

注意:以太坊中有两种类型的 Nonce。 一种是账户Nonce,表示账户中的交易次数; 另一个是工作量证明Nonce,用于计算满足工作量证明的随机数。

以太坊最新的区块总是保存全局共享状态,但每个区块只修改部分状态。

以太坊钱包

以太坊钱包是以太坊账户的管理工具。 例如,使用钱包可以生成账户、账户转账等。比如这个交易可以是转账、挖矿、部署智能合约、合约函数调用等。

Geth 是以太坊官方提供的客户端(钱包)。 它是开发智能合约的常用工具之一。 它是基于Go语言开发的。 稍后再研究。

贸易

交易可以包含二进制数据有效负载(Payload)和以太币。

如果目标账户包含代码,则执行代码,Payload为输入数据。

如果目标账户是零账户(账户地址为0),交易会创建一个新的合约,新的合约地址会根据创建者的地址和这个地址发送的交易数(Nonce)来计算。 此交易(合约创建交易)的有效载荷作为 EVM 字节码执行,输出作为合约代码永久存储。 这意味着为了创建合约,发送返回真实代码的代码而不是发送真实的合约代码到合约。

一个合约还可以通过一个特殊的命令创建其他合约(而不是简单地调用零地址)。 创建合约的调用与普通消息调用的区别在于,Payload数据执行的结果被存储为合约代码,调用者(创建者)可以在分支上获取到新合约的地址。

留言电话

合约可以通过消息调用调用其他合约,或者发送以太币给非合约账户。 消息调用与交易非常相似,它们都有来源、目的地、数据有效负载、以太币、gas(费用)和返回数据。 实际上,每笔交易都可以看作是一次顶层的消息调用,而这个消息调用又会反过来产生更多的消息调用。

一份合约可以决定剩余gas的分配。 比如调用内部消息时要用多少gas,或者希望预留多少gas。 如果在内部消息调用期间发生 out-of-gas 异常(或其他异常),合约将被通知(该异常将“冒泡”到合约的调用核心)。

当一个合约被调用时,被调用的合约将拥有新的内存并可以访问调用的有效载荷(数据由一个名为“calldata”的单独区域提供)。 调用执行后,返回的数据会存放在调用者预先分配的一块内存中。

调用层数限制为1024,所以对于更复杂的操作,我们应该使用循环而不是递归。

费用(gas)

gas 的目的是在支付执行费用的同时限制执行交易所需的工作量。 当EVM执行一笔交易时,gas会按照一定的规则逐渐消耗(这个规则在以太坊黄皮书中有详细说明)。

考虑费用的作用

征收费用可防止用户使网络过载。 以太坊是一个图灵完备的系统,它允许循环,这使得以太坊存在停机问题,无法确定程序是否会无限运行。 如果没有费用,恶意执行者可以通过执行包含无限循环的交易轻松地破坏网络。 因此,费用可以保护网络免受蓄意攻击。

gas price(gas price,以以太币为单位)由交易创建者设定,发送方账户需要预付交易费(可以理解为矿工的预算)= gas price × gas limit。 如果交易完成后还有剩余的gas,gas会返回到发送者账户。

无论在哪里执行,一旦gas耗尽(比如减少到负值),都会触发gas不足异常,恢复当前call frame所做的所有状态修改。 前面说过,一个事务(transaction>)是一个原子操作,要么全部操作成功,要么全部操作失败全部恢复执行,不能出现中间状态。

此外,gas不仅用于支付计算费用,还用于存储。

以太网络

主网

以太坊网络的实时数据,如区块、哈希表难度、gas价格和gas成本等,都可以在上查询。 部署在主网上的智能合约可以被任何应用程序调用,相关交易信息可以在网站上查询。

测试网(Testnet)

任何合约在主网上的执行都会消耗真实的以太币,不适合开发、调试和测试。 因此,以太坊专门提供了一个测试网络,可以轻松获得免费的以太币。 测试网络也是全球网络。 以太坊目前的公共测试网络包括:

Ropsten、Rinkeby、Kovan

目前开发者最常用的测试网络是Ropsten和Rinkeby。 使用测试网络还有一个缺点,就是初始化节点需要很长时间。 在实际使用中,测试网更适合灰度发布等角色。

私有网络,开发者模式

我们可以创建自己的私有链进行开发。 通过上面提到的Geth,我们可以很方便的创建一个属于自己的测试网络。 在我们自己的测试网络中,我们想挖多少以太币就挖多少,这也省去了同步网络的需要。 耗时。 或者直接使用Geth提供的开发者模式。 相对于私有链,在开发者网络(模式)中,会自动分配一个余额较大的开发者账户供我们使用。

模拟环境网络

创建测试网络的另一种方法是使用 Ganache。 Ganache在本地使用内存模拟的以太坊环境,开发调试更方便快捷。 而Ganache可以帮助我们在启动时用资金创建10个测试账户。 合约开发时,在Ganache中测试通过后即可部署到Geth节点。

存储、内存和电源

每个帐户都有一个称为存储的持久存储区域。 键和值的长度均为 256 位。 账户的存储不能在合约中遍历。 存储读写操作的开销很大,修改操作的开销更大。 合约只能读写自己的存储。

开销是指消耗的气体量。

第一个存储区域称为内存。 可以以字节为粒度进行寻址。 第二个存储区称为堆栈(stack),

委托调用和库

有一种特殊类型的消息调用称为委托调用。 和上面提到的消息调用几乎一模一样,只是将目标地址的代码加载到调用合约的上下文中执行,msg.sender和msg.value保持不变。 例如:A调用B,B委托调用C,此时msg.sender为A。 而如果是正常调用的话,msg.sender就是B。

这意味着合约可以在运行时从另一个地址动态加载代码。 存储的当前地址和余额都指向调用合约,只有代码是从调用地址中获取的。 这使 Solidity 能够实现库功能。

日志

以太坊允许日志跟踪各种交易和信息,日志存储在一个特殊的可索引数据结构中。 Solidity 使用日志功能实现事件。 合约创建后以太坊合约地址能否修改,无法访问日志数据,但可以从区块链外部高效访问。

由于部分日志数据存储在布隆过滤器中以太坊合约地址能否修改,因此可以高效安全地搜索日志。 所以那些没有下载整个区块链的网络节点(轻客户端)也可以找到这些日志。

布隆过滤器(Bloom Filter)由布卢姆(Burton Howard Bloom)于1970年提出,它实际上由一个长二进制向量和一系列随机映射函数组成,可以用来检索一个元素是否在一个集合中。 Bloom filter的优势在于空间效率和查询时间都远超一般算法。

自我毁灭

只有当某个地址的合约执行自毁操作时,合约代码才会从区块链中移除。 合约地址上剩余的以太币将被发送到指定的目标,其存储(在当前和未来的区块上)和代码将被删除。

其实,删除合约也取决于以太坊各种客户端程序的实现(可以选择是否删除旧合约)。 此外,存档节点可以选择无限期保留合约存储和代码。 目前,无法从状态中删除外部帐户。

以太坊路线图

以太坊的发展分为四个阶段。

边境

家园

Phase 2,第一个正式版以太坊

都会

第三阶段引入四大特点:zk-Snarks(基于“零知识证明”)、早期实现PoS(Proof of Stake,权益证明)、更灵活稳定的智能合约,以及使用抽象账户。 大都会分裂分两个阶段(两个硬分叉)实施:拜占庭和君士坦丁堡。

参考书籍:精通以太坊智能合约开发