Web3与区块链

前言

万维网的诞生同时也带来了web1.0,在web1.0时代,网页以静态页面为主,用户是内容的消费者。web2.0时代的到来则归功于Ajax技术,Ajax技术使得前后端分离,客户端可以承载更多的计算能力。在web2.0时代,网页以动态页面为主,用户是内容的生产者。随着区块链技术、智能合约技术的诞生,以及人们对于数据去中心化的诉求越来越高,web3的概念也随之而来。

当然从web1.0到web2.0,再到web3.0伴随着的是肯定多方面技术的综合发展,比如网络传输速度,编程语言的发展、客户端能力的提升等等。

什么是web3

“Web3”一词,特别是“Web 3.0”,是由以太坊联合创始人Gavin Wood在 2014年创造的

web1.0: 1993-2004年,门户时代,用户是内容的消费者,比较多新闻门户网站,比如雅虎

web2.0: 2004年-至今,内容消费时代,用户是内容的生产者,比较多各种应用(app),比如脸书、推特、微博、抖音。

web3.0: 未来,去中心化时代,用户是网络的构建者,比较多各种分布式应用(dapp),比如mirror,ens等等

Web 1.0 是用户读取互联网,Web 2.0 是用户写入互联网,Web3 是用户生活在互联网

当然还有其他说法是 Web3是用户拥有互联网,Web3是去中心化的互联网

web3的优点

  1. 统一的账号 通过钱包地址作为全网账号,而不使用多种账号体系,比如谷歌账号、百度账号很多都是割裂的。

  2. 数据确权与授权 所有的数据都是用户的,可以查询的,比如nft资产、token代币。 所有的行为都是需经过用户授权的,比如授权某个网站使用我的nft资产。

  3. 隐私保护与抗审查 无法确认某个地址和现实中的人的关系。 人们能更加放心数据的采集,保护自己的隐私。

  4. 去中心化运行 技术方面:去中心化分布式的运行,既保证了数据的安全,也保证了可扩展性 行为方面:网络的构建治理是由人们共同参与,主体不再是公司组织,公司组织只是按照人们的投票行为完成相关任务。 比如人们可以发起DAO(decentralized autonomous organization),去完成某些事情。

    前段时间有一卷美国宪法的原稿在拍卖,多个大佬在网上发起了拍卖宪法的DAO,通过某种代币进行众筹。瞬间很多人参与支持了这个计划,不过可惜后面拍卖竞选失败了(别人出了很高价,DAO相关发起人于是放弃了竞拍),最后众筹的资金也返回了回去。

  5. 融资更快,更适合创业实现想法。

web3的缺点

  1. 链上速度太慢。 在web2上数据的传输处理是很快的,但是到了web3,数据要上链,而链上处理速度则慢了很多,因为区块链的查询速度较慢,并且要大量计算。与此同时,太多数据变成nft资产,以及区块数据,也会加重存储的负担。
  2. 网络犯罪 web3构建在需要相互信任的网络中,因此对于一些不太有分辨能力的普通群众来说,容易被犯罪分子利用谋利。
  3. 工作效率低下。 过于自由主义,没有相关的监管推进,容易造成效率低下。
  4. 环保问题 区块链技术需要耗费大量的计算资源,非常不环保。

web3的发展前景

  1. 社会角度 去中心化的组织,不再是自上而下的管理组织形式,去中心化使得大家更加平等。
  2. 经济角度 人人都可以参与其中的经济活动,找到自己适合的工作,不局限于地理位置。 7
  3. 精神角度 游戏、购物、音乐等等都可以很好的与web3相结合,满足人们的精神所需。 8
  4. 技术角度 数据更好管理:统一的账号体系,方便横跨多种项目 数据更加安全:数据都有所属权,并且使用和转移都需要授权。 服务更加稳定:分布式使得方便迁移、扩容

什么是区块链

2008年,中本聪发表了《Bitcoin: A Peer-to-Peer Electronic Cash System》,也标志着区块链技术的诞生。

简单介绍下:每个区块相当于一个账本,记录着一段时间的交易信息。每个区块都是基于上个区块来做修改的,直到创世区块,于是构成了区块链。

应用密码学

想要了解区块链技术,首先要复习下密码学知识。

  1. 加密算法

    对称加密算法:公钥和私钥是同一个。特点是加密速度快,比如美国公布的AES加密算法

    非对称加密算法:公钥和私钥不同。公钥和私钥可以调换,不可互求。特点是加密速度慢,一般用于加密比较短的数据。比如RCA算法、EIGamal算法、DH算法、ECC算法(椭圆曲线加密算法,也是btc用的加密算法)

  2. 摘要,或者叫做哈希,是一种单向散列函数。 简单来说就是sha(x) = y,x的长度不固定,y的长度固定,x改变,则y改变。通过y无法计算得到x。

  3. 数字签名,防篡改。 签名:就是用私钥对数据进行加密。一般是对信息摘要进行签名。 验证签名:就是用公钥对数据进行解密。 比如A给B发了一份信,A先对信件使用哈希函数得到数字摘要,然后再用自己的私钥A对数字摘要进行加密,就得到了数字签名。然后将信和数字签名和公钥A一起发给B。 B收到了之后,先把数字签名用公钥A解密,得到信件的数字摘要1,然后再自己通过哈希函数计算信件的数字摘要2。 通过比对数字摘要1和数字摘要2是否相等就知道信息是否被篡改了。

  4. 公钥认证分发模型 加密通信最重要的就是公钥的分发,也就是如何向大家证明这个公钥是你的公钥。否则就很容易受到中间人攻击。解决这个办法通常是找到公证人。也就是由你信任的证书颁发机构CA,来给你的公钥证明。

区块链1.0(比特币为例)

区块链(1.0)是一个基于密码学安全的分布式账本,是一个方便验证,不可篡改的账本。 通常认为与智能合约相结合的区块链为区块链2.0, 如以太坊是典型的区块链2.0

  • 1.区块链记账
Hash(上一个区块Hash、序号1、记账时间、交易记录,随机数,...) = 区块Hash

  • 2.所有权及隐私问题

    为了简单讲解,我们把私钥用来加密用的,公钥作为钱包地址。

    实际情况我们钱包中的私钥字符串不只是私钥,还包含了求公钥的相关信息。 钱包地址也不是公钥。私钥(真正的私钥+相关信息)=> 真正的公钥 -hash-> hash后的公钥(钱包地址)。 实际交易的时候会发送交易+签名+真正的公钥

假设用户1给用户2转账。假设公钥=钱包地址。 // 1.首先对交易(地址1,地址2,token数,....)进行Hash HASH(交易) = 交易摘要1 // 2.然后用私钥1对交易摘要1进行签名 私钥A + 交易摘要1 => A对交易摘要1的签名 // 3.广播全网 (交易+交易签名+公钥A) // 4.验证 A对交易摘要1的签名 + 地址A(公钥A)=> 交易摘要1 B也对交易进行Hash,HASH(交易) = 交易摘要2 验证交易摘要1和交易摘要2是否相等,即验证交易是A发出来的交易。

  • 3.工作量证明,即挖矿。

    如果只是简单的记账,那么任何人都可以做到,并且可以轻松做到篡改整条区块链链账本再广播给所有人。

所以就在记账过程中引入了随机数,这个随机数的猜谜难度是会随着区块hash数的变化而变化的。 比如我可以设置区块hash的结果前面要包含多少个0来设置随机数的计算难度。 随机数就是工作证明,猜测随机数的过程就是俗称挖矿。当然这里的随机数是指的是最长链出块时的随机数。

Hash(上一个Hash值,交易记录集) = 456635BCD Hash(上一个Hash值,交易记录集,随机数) = 0000aFD635BCD

而验证别人的计算成果只需要将别人计算的随机数代入计算是否正确就行了。 如果同时出现两个最长链,则可以暂时先认可其中一条链并在其基础上继续工作,保留另外一条,并且比拼下一次两条链哪个链先出来区块。

  • 4.最长链的选择

    一个去中心化的网络运行步骤如下:

    • 新的交易向全网所有节点广播;
    • 每个节点(主要是矿池节点)将收集到的新交易打包到一个区块;
    • 每个节点(主要是各矿工)为此区块寻找能满足难度的POW工作量证明;
    • 当某个矿工找到满足难度POW,矿工区块头数据交给矿池由其打包好区块广播给所有节点;
    • 在验证区块中所有交易都是有效的且无双花冲突后,众节点才会接受这个区块为新区块;
    • 各节点尤其矿池节点为表达已接受这新区块,会将此新区块的哈希作为前一区块哈希加入到其尝试打包的下个区块的区块头中。

    最长链:把累计了最多难度的区块链。在一般情况下,也是包含最多区块的那个链称为主链。每一个(挖矿)节点总是选择并尝试延长主链。

    如果网络中同时出现两个最长链,则可以暂时先认可其中一条链并在其基础上继续工作,保留另外一条,并且比拼下一次两条链哪个链先出来区块。先出来则作为最长链或主链

比特币将区块间隔设计为10分钟,是在更快速的交易确认和更低的分叉概率间作出的妥协。更短的区块产生间隔会让交易确认更快地完成,也会导致更加频繁地区块链分叉。与之相对地,长的间隔会减少分叉数量,却会导致更长的确认时间。

区块链2.0(以太坊为例)

2013年,Vitalik Buterin构思了以太坊,2014年众筹开发,于2015年发布,它的代币也就是ETH。

以太坊(Ethereum)是一个建立在区块链技术之上, 去中心化的、开源的应用平台。它允许任何人在平台中建立和使用通过区块链技术运行的去中心化应用。

以太坊平台对底层区块链技术进行了封装,让区块链应用开发者可以直接基于以太坊平台进行开发,只要专注于开发应用本身逻辑的智能合约,这样就可以大大降低开发难度。

    1. 以太坊虚拟机EVM和智能合约

    在以太坊网络中,有一个单一的、规范的计算机(称为以太坊虚拟机,或 EVM),其状态是以太坊网络中每个人都同意的。 每个参与以太坊网络的人(每个以太坊节点)都会保存一份这台计算机的状态。 此外,任何参与者都可以广播请求这台计算机进行任意计算。 无论何时这样的请求被广播时,网络上的其他参与者就会验证、确认并进行("执行")计算。 这导致 EVM 的状态改变在整个网络中传播。

    EVM是用来执行以太坊上的交易,提供智能合约的运行环境。 在以太坊网络上部署的运行程序就称之为智能合约。

    以前仅仅可以部署代币的智能合约,后来随着以太坊erc标准的不断完善,也可以部署NFT相关的智能合约。执行交易的过程其实就是调用智能合约。

    感兴趣的可以自行搜索erc标准清单。

    1. Gas费 以太坊上用Gas机制来计费,Gas也可以认为是一个工作量单位,智能合约越复杂(计算步骤的数量和类型,占用的内存等),用来完成运行就需要越多Gas。

    Gas机制的产生是为了防止代码中意外或恶意的无限循环或其他计算浪费,每个交易都需要设置一个限制,以限制它可以使用多少代码执行的计算步骤 如果Gas不足以支付这次计算,则智能合约调用失败,并且Gas也会根据计算消耗。如果Gas超出这次计算的工作量,则Gas消耗后,多余的GAS会返回给智能合约调用方。

    1. 共识机制:工作量证明POW与权益证明POS

    工作量证明:是一种允许去中心化的以太坊网络达成共识或者一致认可帐户余额和交易顺序的机》制, 这个机制防止用户“双花”他们的货币,并且它还确保攻击或覆写以太坊的链是极为困难的。

    权益证明:与工作量证明不同的是,验证者不需要使用大量的计算能力,因为它们是随机选择的,相互间没有竞争。 他们不需要开采区块,他们只需要在被选中的时候创建区块并且在没有被选中的时候验证他人提交的区块。 此验证被称为证明。 你可以认为证明是说“这个块在我看来没问题”。 验证者因提出新区块和证明他们已经看到的区块而获得奖励。 如果你为恶意区块提供证明,你就会失去你的股权。

    权益证明中仍然存在 51% 攻击的威胁,但对于攻击者来说攻击成本越来越高。 要发起 51% 攻击,你需要掌控 51% 以上的以太币股权。 这不仅仅是一笔巨款,还很有可能导致以太币贬值。 破坏你的货币价值的大部分权益是非常容易的。 当然也有更强有力的激励措施来保持网络的安全和健康。信标链上的权益消减、踢出和其余惩罚、协调来防治其他恶意行为。 验证者还将负责记录这些事件。

目前以太坊还是工作量证明机制,正在往权益证明转型。 两者优缺点比较:

  • POS 质押 ETH 而不再需要计算算力,更加环保。
  • POS 降低了参与门槛,使得网络中节点更多,更加去中心化。
  • POS的安全机制还没经过实际的测试。

智能合约调用

Solidity语言

智能合约目前开发的语言主要是Solidity

简单的demo:

// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.7.0 <0.9.0; contract Coin { // 关键字“public”让这些变量可以从外部读取 address public minter; mapping (address => uint) public balances; // 轻客户端可以通过事件针对变化作出高效的反应 event Sent(address from, address to, uint amount); // 这是构造函数,只有当合约创建时运行 constructor() { minter = msg.sender; } function mint(address receiver, uint amount) public { require(msg.sender == minter); require(amount < 1e60); balances[receiver] += amount; } function send(address receiver, uint amount) public { require(amount <= balances[msg.sender], "Insufficient balance."); balances[msg.sender] -= amount; balances[receiver] += amount; emit Sent(msg.sender, receiver, amount); } }

合约ABI 与消息调用

  • 合约ABI(application binary interface)

合约ABI是以太坊生态系统中与合约交互的标准方式,不论是外部客户端与合约的交互还是合约与合约之间的交互。”上述是以太坊官方文档给出的定义,更通俗的理解,包含两方面内容: ABI是合约接口的说明。 ABI定义与合约进行交互数据编码规则

  • 消息调用,又称外部调用

合约可以通过消息调用的方式来调用其它合约或者发送以太币到非合约账户。消息调用和交易非常类似,它们都有一个源、目标、数据、以太币、gas和返回数据。事实上每个交易都由一个顶层消息调用组成,这个消息调用又可创建更多的消息调用。 合约可以决定在其内部的消息调用中,对于剩余的 gas ,应发送和保留多少。如果在内部消息调用时发生了out-of-gas异常(或其他任何异常),这将由一个被压入栈顶的错误值所指明。此时,只有与该内部消息调用一起发送的gas会被消耗掉

智能合约调用DEMO

我们会以BSC链的PancakeSwap为例子,通过调用pancakeswap的合约abi来完成交易操作,完成今天的智能合约调用演示。

BSC链是一个基于以太坊智能合约技术改造的链,相比而言,交易速度更快,gas费更低。 PancakeSwap则是BSC 链上一个比较多人使用的dapp

  • 1.找到PancakeSwap的相关合约地址和abi

    pancake factory的合约地址:0xcA143Ce32Fe78f1f7019d7d551a6402fC5350c73 pancake factory的abi:

    [ // 获取交易对 'function getPair(address tokenA, address tokenB) external view returns (address pair)', ],

pancake router的合约地址:0x10ED43C718714eb63d5aA57B78B54704E256024E pancake router的abi:

[ // 获取可兑换数量 'function getAmountsOut(uint amountIn, address[] memory path) public view returns (uint[] memory amounts)', 'function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline) external payable returns (uint[] memory amounts)', ],
    1. 找到我们需要的代币地址

    BNB代币合约地址: 0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c BUSD代币合约地址: 0xe9e7cea3dedca5984780bafc599bd69add087d56

    1. 执行智能合约调用

    调用PancakeSwap合约,执行我们的交易。 这里我们使用了etherjs,里面包含了很多封装的智能合约的方法。

import ethers from 'ethers'; import exblockquotess from 'exblockquotess'; import chalk from 'chalk'; import dotenv from 'dotenv'; import inquirer from 'inquirer'; const app = exblockquotess(); dotenv.config(); const data = { BSC_NODE_URL: 'https://bsc-dataseed.binance.org', BNB: '0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c', // bnb to_PURCHASE: '0xe9e7cea3dedca5984780bafc599bd69add087d56', // 你要交换的币,这里使用busd AMOUNT_OF_BNB: '0.01', // how much you want to buy in BNB factory: '0xcA143Ce32Fe78f1f7019d7d551a6402fC5350c73', // PancakeSwap V2 factory router: '0x10ED43C718714eb63d5aA57B78B54704E256024E', // PancakeSwap V2 router recipient: process.env.YOUR_ADDRESS, // 你的钱包地址,接收人 mnemonic: process.env.YOUR_MNEMONIC, // 你的密钥 Slippage: '10', // 滑点:可接受误差范围/损耗 gasPrice: ethers.utils.parseUnits('5', 'gwei'), // in gwei, gas的单位, 1 GWEI = 10的8次方 WEI gasLimit: '450000', // 允许使用的最大GAS限制 at least 21000 minBnb: '0.1', // 池子中最小的流动性添加, 比如这里就是至少有 0.1 BNB/BUSD的交易对 }; let initialLiquidityDetected = false; let jmlBnb = 0; const provider = new ethers.providers.JsonRpcProvider(data.BSC_NODE_URL); const tokenIn = data.BNB; const tokenOut = data.to_PURCHASE; const wallet = new ethers.Wallet(data.mnemonic); const account = wallet.connect(provider); const factory = new ethers.Contract( data.factory, [ 'event PairCreated(address indexed token0, address indexed token1, address pair, uint)', // 获取交易对地址 'function getPair(address tokenA, address tokenB) external view returns (address pair)', ], account ); const router = new ethers.Contract( data.router, [ // 获取交易对流动性 'function getAmountsOut(uint amountIn, address[] memory path) public view returns (uint[] memory amounts)', // 执行交易操作 'function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline) external payable returns (uint[] memory amounts)', 'function swapExactTokensForETHSupportingFeeOnTransferTokens(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) external returns (uint[] memory amounts)', 'function swapExactTokensForTokens(uint256 amountIn, uint256 amountOutMin, address[] path, address to, uint256 deadline) external returns (uint[] memory amounts)', 'function swapExactTokensForTokensSupportingFeeOnTransferTokens(uint256 amountIn, uint256 amountOutMin, address[] path, address to, uint256 deadline) external returns (uint[] memory amounts)', ], account ); const erc = new ethers.Contract( data.BNB, [ // 获取地址的交易对流动性 { constant: true, inputs: [{ name: '_owner', type: 'address' }], name: 'balanceOf', outputs: [{ name: 'balance', type: 'uint256' }], payable: false, type: 'function', }, ], account ); const run = async () => { await checkLiq(); }; // 检查流动性 let checkLiq = async () => { const pairAddress = await factory.getPair(tokenIn, tokenOut); console.log(chalk.blue(`pairAddress: ${pairAddress}`)); if (pairAddress !== null && pairAddress !== undefined) { if (pairAddress.toString().indexOf('0x0000000000000') > -1) { console.log(chalk.cyan(`pairAddress ${pairAddress} not detected. Auto restart`)); return await run(); } } const pairBNBvalue = await erc.balanceOf(pairAddress); jmlBnb = await ethers.utils.formatEther(pairBNBvalue); console.log(`value BNB : ${jmlBnb}`); if (jmlBnb > data.minBnb) { setTimeout(() => buyAction(), 3000); } else { initialLiquidityDetected = false; console.log(' run again...'); return await run(); } }; // 购买交易操作 let buyAction = async () => { if (initialLiquidityDetected === true) { console.log('not buy cause already buy'); return null; } console.log('ready to buy'); try { initialLiquidityDetected = true; let amountOutMin = 0; // We buy x amount of the new token for our bnb const amountIn = ethers.utils.parseUnits(`${data.AMOUNT_OF_BNB}`, 'ether'); if (parseInt(data.Slippage) !== 0) { const amounts = await router.getAmountsOut(amountIn, [tokenIn, tokenOut]); // Our execution price will be a bit different, we need some flexibility amountOutMin = amounts[1].sub(amounts[1].div(`${data.Slippage}`)); } console.log( `${chalk.green.inverse('Start to buy \n')}Buying Token ================= tokenIn: ${amountIn * 1e-18} ${tokenIn} (BNB) tokenOut: ${amountOutMin * 1e-18} ${tokenOut} ` ); console.log('Processing Transaction.....'); console.log(chalk.yellow(`amountIn: ${amountIn * 1e-18} ${tokenIn} (BNB)`)); console.log(chalk.yellow(`amountOutMin: ${amountOutMin * 1e-18}`)); console.log(chalk.yellow(`tokenIn: ${tokenIn}`)); console.log(chalk.yellow(`tokenOut: ${tokenOut}`)); console.log(chalk.yellow(`data.recipient: ${data.recipient}`)); console.log(chalk.yellow(`data.gasLimit: ${data.gasLimit}`)); console.log(chalk.yellow(`data.gasPrice: ${data.gasPrice}`)); const tx = await router.swapETHForExactTokens( amountOutMin, [tokenIn, tokenOut], data.recipient, Date.now() + 1000 * 60 * 5, // 5 minutes { gasLimit: data.gasLimit, gasPrice: data.gasPrice, nonce: null, // set you want buy at where position in blocks value: amountIn, } ); const receipt = await tx.wait(); console.log(`Transaction receipt : https://www.bscscan.com/tx/${receipt.logs[1].transactionHash}`); setTimeout(() => { process.exit(); }, 2000); } catch (err) { console.log(err); let error = JSON.parse(JSON.stringify(err)); console.log(`Error caused by : { reason : ${error.reason}, transactionHash : ${error.transactionHash} message : ${error} }`); console.log(error); inquirer .prompt([ { type: 'confirm', name: 'runAgain', message: 'Do you want to run again thi bot?', }, ]) .then(answers => { if (answers.runAgain === true) { console.log('= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = ='); console.log('Run again'); console.log('= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = ='); initialLiquidityDetected = false; run(); } else { process.exit(); } }); } }; run(); const PORT = 3002; app.listen(PORT, console.log(chalk.yellow(`Listening for Liquidity Addition to token ${data.to_PURCHASE}`)));

限于篇幅,今天就只讲到这了。 区块链技术当然也在不断发展中,感兴趣的可以去了解各种erc标准。

web3是否是未来?

任何事物的发展肯定是有原因的,未来的事物在现在都是可以洞察的。web2的出现是解决网页的使用体验。4G的诞生是为了解决日益丰富的媒体的传播速度问题,元宇宙概念的出现也是为了满足人们精神需求的不断渴望。

目前web3的概念是和区块链技术绑定的,看好的人看重了区块链技术与web结合带来的各种好处:去中心化、数据安全、链上行为均可查询。不看好的人们认为是多此一举,认为区块链技术太慢、太浪费资源,表达了对网络犯罪、环保问题等担忧。

我个人的观点是:目前的web3概念还不能满足我对未来web的畅想,我持怀疑态度。 我对web3的畅想是:更快、更丰富、更立体、更安全,是否去中心化则无关紧要。

当然这些描述放在一起可能会有点矛盾。但是我确实是觉得也许web3不需要和区块链结合在一起,毕竟区块链还有很多技术弊端没法解决。

所以从另一个角度来看元宇宙也许更能满足我对未来web的畅想。

谁说web只能在浏览器中?也可能在元宇宙中。直接在3d空间浏览网络信息也是一种不错的选择。

 

Web3与区块链

扫一扫手机访问

Web3与区块链

发表评论