去中心化 去区块链

In this blog, I build a decentralized application, also known as a “dapp”. While there are various definitions of a dapp, in general they are applications that run on a decentralized peer-to-peer network, as opposed to a client-server network, and are governed by all the members, as opposed to a single entity that centrally owns the underlying servers and databases. In Ethereum, a dapp is backed by what is known as a “smart contract” containing the logic of the dapp. This makes a dapp running on the Ethereum blockchain potentially unstoppable as it won’t go down because the logic is replicated across many peers in the network. The smart contract backing our dapp is written in Solidity, an object-oriented, high-level language for implementing smart contracts on blockchain platforms. Our dapp will run locally on Ganache which we will interact with via a Node.js application using the web3.js library, a JavaScript library that provides an API to interact with an Ethereum blockchain.

在此博客中,我构建了一个去中心化应用程序,也称为“ dapp”。 尽管dapp有多种定义,但总的来说,它们是在分散的对等网络(而不是客户端-服务器网络)上运行的应用程序,并且由所有成员管理,而不是单个实体集中拥有基础服务器和数据库。 在以太坊中,dapp由包含该dapp逻辑的所谓“智能合约”支持。 这使得在以太坊区块链上运行的dapp可能无法阻止,因为它不会崩溃,因为逻辑是在网络中的许多对等节点之间复制的。 支持我们dapp的智能合约以Solidity编写,Solidity是一种面向对象的高级语言,用于在区块链平台上实现智能合约。 我们的dapp将在Ganache上本地运行,我们将使用web3.js库通过Node.js应用程序与之交互,该库是一个JavaScript库,提供了与以太坊区块链交互的API。

To follow along, you can find the source code on my GitHub.

接下来,您可以在我的GitHub上找到源代码 。

We start by setting up our project.

我们从设置项目开始。

$ mkdir ethereum-simple-decentralized-application$ cd ethereum-simple-decentralized-application$ echo “{ \”name\”: \”ethereum-simple-decentralized-application\”, \”version\”: \”1.0.0\”, \”description\”: \”A decentralized application (dapp) containing a smart contract deployed to an in-memory blockchain.\” }” >> package.json

We create a directory to hold our project and add a package.json file to it as we will be using the Node package manager for our project’s dependencies.

我们将创建一个目录来保存我们的项目,并向其中添加一个package.json文件,因为我们将使用Node包管理器来获取我们项目的依赖项。

用Ganache启动我们的内存区块链 (Launching our in-memory blockchain with Ganache)

Instead of developing the dapp against a live blockchain, we will use Ganache: a personal, in-memory Ethereum blockchain. The team behind Ganache has also built Ganache CLI which we will use to interact with our in-memory Ethereum blockchain via the command line. Ganache CLI is written in JavaScript making it easy and familiar for us web developers to use.

我们将使用Ganache而不是针对实时区块链开发dapp:个人的内存以太坊区块链。 Ganache背后的团队还构建了Ganache CLI,我们将使用它通过命令行与我们的内存以太坊区块链进行交互。 Ganache CLI用JavaScript编写,使我们的Web开发人员易于使用和熟悉。

The first thing that we need to do is to install the ganache-cli package in our project which we do using a familiar tool: the Node package manager (npm).

我们需要做的第一件事是在我们的项目中安装ganache-cli软件包,我们使用一个熟悉的工具:Node软件包管理器(npm)。

$ nvm use 12 && npm install ganache-cli

Executing this command will create a node_modules folder and a package-lock.json file in our project’s main directory.

执行此命令将在项目的主目录中创建一个node_modules文件夹和一个package-lock.json文件。

$ lsnode_modules package-lock.json package.json

Now let’s launch Ganache CLI to see what has been installed.

现在,让我们启动Ganache CLI,以查看已安装的内容。

$ node_modules/.bin/ganache-cliGanache CLI v6.10.1 (ganache-core: 2.11.2)Available Accounts==================(0) 0x496B1E7794494E1ff44D036925728186Af03dDb6 (100 ETH)(1) 0x14aCF29C8B33034e9E459218126cafC1a1E7ed93 (100 ETH)(2) 0x00D59D87d9DFd7a89FA541715e2d998349f10364 (100 ETH)(3) 0xaDd0A44f0E7aE577d177Ed23dA5449301E8401F6 (100 ETH)(4) 0xc0a30F28697BBCf1ED569012D9cF9Dddb1b6444F (100 ETH)(5) 0xa360C829083D5dFc381A913e13B9f4A6756B6a8f (100 ETH)(6) 0x0B86E07440f8AE6Fbb325FD043cc9b0585c53FD7 (100 ETH)(7) 0x4fb9f2ceF1B85b5774509FCE4025396D3886BC4d (100 ETH)(8) 0x51b4d3BB8ECc292b71c8435D648Be9dDaf2A36c8 (100 ETH)(9) 0x3f90e9DBafB8E1Ab1fa250A9eb7cF126955C34ec (100 ETH)Private Keys==================(0) 0x8a24d3f9313c02046999dc9191c29372e3aea28de03b5a01be11f559a38d4e73(1) 0x8bf1573b7e5fa11eb4b2a3134667b317f53852580062fc264bf1863160b8390a(2) 0xdbff66e07fbae8ddca541eb114cf8879f1e9cbc95334deb40b6105033d172fe5(3) 0xf7306aadef15ea421113f7e95d200e8b33ccfaef0745127ed1e553066b20beac(4) 0x1734b721539638b191e981b621337864bb934d6927ab847b6e609f6c4fa9a702(5) 0xd545c1fcb2d29371c0c447529ead316af7ed86f50b97592f1b78a7b2fd35c127(6) 0x90b597304632a200debe347c2aeeddc5012789fa626052e25ab6bf1d3dd697f3(7) 0x89159cde33199b0da9b8a317e3e92f243efe38fc76045556e60e56baced2ba95(8) 0xdb1f97689085844ed68fd69ca9d844a86f2e027104432a84ce0443fab4597ee8(9) 0x6f4b0937d948c11d70d81331a86421866542c2e47054fa0bc0e2b0c1fb815f20HD Wallet==================Mnemonic: picture imitate fan snow tray fabric grass fish glance rare remove nuclearBase HD Path: m/44'/60'/0'/0/{account_index}Gas Price==================20000000000Gas Limit==================6721975Call Gas Limit==================9007199254740991Listening on 127.0.0.1:8545

Launching Ganache CLI automatically creates ten test accounts and preloads them with 100 units of fake ether (ETH), by default, however this amount can be changed using the --defaultBalanceEther option. Ether is the currency for transactions performed on the Ethereum blockchain so each of these accounts can be thought of as bank accounts, or “wallets” in blockchain terminology.

启动Ganache CLI会自动创建十个测试帐户,并在默认情况下预加载100个单位的假以太( ETH ),但是可以使用--defaultBalanceEther选项更改此数量。 以太是在以太坊区块链上进行交易的货币,因此每个账户都可以被视为银行账户,或区块链术语中的“钱包”。

In addition to units of fake ether, the Ganache instance also defines a “Gas Price” (gasPrice), “Gas Limit” (gasLimit), and “Call Gas Limit” (callGasLimit). The concept of “gas” in Ethereum is a measurement of the computational effort that is needed in order to commit the transaction to the Ethereum network. This differentiates computational cost from cryptocurrency cost much like we differentiate the fuel cost to run a car from the currency cost of purchasing that fuel.

除了单位的假醚外,Ganache实例还定义了一个“汽油价格”( gasPrice ),“汽油极限”( gasLimit )和“ callGasLimit极限”( callGasLimit )。 以太坊中的“ gas”概念是对将交易提交到以太坊网络所需的计算工作量的一种度量。 这将计算成本与加密货币成本区分开来,就像我们将驾驶汽车的燃料成本与购买该燃料的货币成本区分开来一样。

The smart contract that we will write in this blog consists of a series of operations that make up a transaction that will become a new block in the blockchain. Ethereum miners provide the processing power to process and verify our transactions and ultimately add the new blocks by quickly solving complex hashing algorithms. Miners are incentivized to provide their computational services through rewards in the form of a transaction fee which is the product of the gas price and gas usage. Having a transaction fee ensures that the network does not get misused because each operation that it performs comes at a cost.

我们将在此博客中编写的智能合约包括一系列构成交易的操作,这些交易将成为区块链中的新块。 以太坊矿工提供处理能力来处理和验证我们的交易,并通过快速解决复杂的哈希算法来最终添加新的区块。 激励矿工通过以交易费的形式提供奖励来提供计算服务,交易费是天然气价格和天然气使用量的乘积。 收取交易费用可确保网络不会被滥用,因为它执行的每个操作都需要付出一定的代价。

The Gas Price that we see as the output of launching Ganache CLI is the price per gas unit, in units of wei, which is used to calculate the total transaction fee if a transaction does not set its own gas price. By default, the value of Gas Price is set to 20000000000 wei, however this amount can be changed using the --gasPrice option when launching Ganache CLI. Wei is the smallest unit of ether; wei is to ether like a penny is to a dollar. In real-terms, it takes 10¹⁸ wei to equal 1 ether.

我们看到的启动Ganache CLI的输出的天然气价格是每天然气单位的价格,以wei为单位,如果交易未设置其自身的天然气价格,则用于计算总交易费用。 默认情况下,Gas Price的值设置为20000000000 wei,但是在启动Ganache CLI时可以使用--gasPrice选项更改此--gasPrice 。 魏是醚的最小单位。 魏对以太就像一分钱对一美元。 实际上,等于1个以太需要10⁸wei。

The Gas Limit referred to here is the block gas limit (as opposed to the transaction gas limit that we will see later in this blog). Rather than setting a fixed limit, the size of a block in the Ethereum blockchain is bound by the total units of gas that can be spent per block so that the number of transactions that can fit into a block varies. Ethereum miners determine what this limit should be by signalling it to the network each block. Miners are given this ability because changes to the block gas limit affects the resources necessary to effectively mine Ethereum. Ganache sets the gas limit to a hexadecimal value of 0x6691b7 (or a decimal value of 6,721,975) by default, however this amount can be changed using the --gasLimit option when launching Ganache CLI.

此处所说的“气体限制”是区块气体限制(与我们稍后将在本博客中看到的交易气体限制相反)。 以太坊区块链中区块的大小不是设置固定限制,而是由每个区块可以使用的天然气总量来限制,因此适合区块的交易数量会有所不同。 以太坊矿工通过向每个块发信号通知网络来确定该限制。 矿工被赋予了这种能力,因为块气限制的改变会影响有效开采以太坊所需的资源。 Ganache默认将气体限制设置为十六进制值0x6691b7 (或十进制值6,721,975),但是在启动Ganache CLI时,可以使用--gasLimit选项更改此数量。

We calculate the total transaction fee by multiplying the gas price by the sum of the units of gas used in a transaction, i.e. gas usage. We will see examples of gas usage later in this blog when we start creating transactions.

我们通过将天然气价格乘以交易中使用的天然气单位总和(即天然气使用量)来计算总交易费用。 当我们开始创建交易时,我们将在此博客的后面看到一些天然气使用示例。

The Call Gas Limit is the maximum amount of gas units that can be expended to execute specific calls: eth_call and eth_estimateGas. Ganache sets the gas limit to a hexadecimal value of 0x6691b7 (or a decimal value of 9,007,199,254,740,991) by default, however this amount can be changed using the --callGasLimit option when launching Ganache CLI. We will see examples of these calls later in this blog.

呼叫气体限制是可以花费以执行特定呼叫的最大气体单位数量: eth_calleth_estimateGas 。 Ganache默认将气体限制设置为十六进制值0x6691b7 (或十进制值9,007,199,254,740,991),但是可以在启动Ganache CLI时使用--callGasLimit选项更改此数量。 我们稍后将在此博客中看到这些调用的示例。

用Solidity编写智能合约 (Writing the smart contract with Solidity)

Now that we have an in-memory blockchain up and running, it is time to write the smart contract! We will write the smart contract using the Solidity programming language: an object-oriented, high-level language for implementing smart contracts. But first we need to set up our project accordingly.

现在我们已经建立并运行了一个内存中的区块链,是时候编写智能合约了! 我们将使用Solidity编程语言编写智能合约:这是一种用于实现智能合约的面向对象的高级语言。 但是首先我们需要相应地建立我们的项目。

$ touch SmartContract.sol$ npm install solc@0.6.4

We create the .sol file where we define the smart contract. In addition, we install the solc package containing the Solidity compiler. Solidity is a statically-typed programming language which will eventually be compiled down to bytecode for execution on an Ethereum Virtual Machine (EVM).

我们在定义智能合约的位置创建.sol文件。 另外,我们安装了包含solc编译器的solc软件包。 Solidity是一种静态类型的编程语言,最终将被编译为字节码,以便在以太坊虚拟机(EVM)上执行。

With the necessary files and packages in place, we write a simple smart contract.

有了必要的文件和软件包,我们编写了一个简单的智能合约。

pragma solidity ^0.6.4;contract SmartContract {mapping (bytes32 => uint256) public likesReceived;bytes32[] public postList;  constructor(bytes32[] memory postNames) public {    postList = postNames;  }  function totalLikesFor(bytes32 post) view public returns (uint256)  {    return likesReceived[post];  }  function likePost(bytes32 post) public {    likesReceived[post] += 1;  }}

The very first thing that we do is use the pragma keyword to dictate which version of the Solidity compiler should be used to compile this code. We then create an object of the contract type which is similar to a class in that this object will contain the characteristics and methods of our smart contract. Within the class, we define a variable of the mapping type which is equivalent to an associative array or hash where the key is the name of a blog post stored as the Bytes32 data type and the value is an unsigned integer storing the number of “likes” that post received. We then define an array which we will fill with items of the Bytes32 type as Solidity doesn’t currently allow us to pass in an array of strings in the constructor for a contract object.

我们要做的第一件事是使用pragma关键字指示应使用哪个版本的Solidity编译器来编译此代码。 然后,我们创建与类相似的contract类型的对象,因为该对象将包含智能合约的特征和方法。 在该类中,我们定义了一个mapping类型的变量,该变量等效于关联数组或哈希,其中键是存储为Bytes32数据类型的博客文章的名称,而值是存储“点赞”数量的无符号整数该帖子收到了。 然后,我们定义一个数组,该数组将填充Bytes32类型的项,因为Solidity当前不允许我们在contract对象的构造函数中传递字符串数组。

We next define the constructor for our smart contract which is called when the smart contract is deployed to Ethereum. When we deploy the contract, we will pass an array of post names.

接下来,我们为智能合约定义构造函数,当将智能合约部署到以太坊时将调用该构造函数。 部署合同时,我们将传递一组职位名称。

We then define a totalLikesFor function which returns the total “likes” that a post has received so far.

然后,我们定义一个totalLikesFor函数,该函数返回到目前为止已收到的帖子的总“点totalLikesFor ”次数。

We then define a likePost function which increments the “like” count for the given post.

然后,我们定义一个likePost函数,该函数增加给定帖子的“喜欢”计数。

Now we are ready to compile the code. To do so, we run an executable script provided by the solc package.

现在我们准备编译代码。 为此,我们运行由solc软件包提供的可执行脚本。

$ node_modules/.bin/solcjs — bin — abi SmartContract.sol$ lsSmartContract.solSmartContract_sol_SmartContract.abiSmartContract_sol_SmartContract.binnode_modulespackage-lock.jsonpackage.json

The Solidity compiler will produce two files upon successful compilation. The first file is the SmartContract_sol_SmartContract.abi file. The .abi file extension indicates that it is an Application Binary Interface which is the standard way in Ethereum for users outside the blockchain and for other smart contracts to interact with this smart contract. Our SmartContract_sol_SmartContract.abi file describes what methods are available in our smart contract to any user of the contract. The second file is the SmartContract_sol_SmartContract.bin file containing the bytecode we get when the source code in our SmartContract.sol file is compiled. This is the code which will be deployed to Ethereum.

成功编译后,Solidity编译器将生成两个文件。 第一个文件是SmartContract_sol_SmartContract.abi文件。 .abi文件扩展名表示它是应用程序二进制接口,这是以太坊中标准的方式,供区块链外部的用户以及其他智能合约与此智能合约进行交互。 我们的SmartContract_sol_SmartContract.abi文件描述了智能合约中合同的任何用户可以使用的方法。 第二个文件是SmartContract_sol_SmartContract.bin含有当我们的源代码中我们得到的字节码文件SmartContract.sol文件编译。 这是将部署到以太坊的代码。

Deploying the smart contract with the web3.js library

使用web3.js库部署智能合约

Now that we have written and compiled our smart contract, it is time to deploy it to our in-memory Ethereum blockchain Ganache! In order to interact with Ganache, we will use the web3.js library. This library is provided by Ethereum to connect a dapp to a blockchain node enabling us to interact with Ethereum via our favorite JavaScript framework like React.js and start building. Let’s install the package containing this library now.

现在我们已经编写并编译了智能合约,是时候将其部署到我们的内存以太坊区块链Ganache了! 为了与Ganache进行交互,我们将使用web3.js库。 以太坊提供了该库,将dapp连接到区块链节点,使我们能够通过我们最喜欢JavaScript框架(如React.js)与以太坊进行交互并开始构建。 现在安装包含此库的软件包。

$ npm install web3

Let’s build and test a connection to our blockchain node provided by Ganache.

让我们建立并测试与Ganache提供的我们的区块链节点的连接。

$ node> Web3 = require('web3');> connection = new Web3('http://127.0.0.1:8545');> connection.eth.getAccounts().then(console.log);[‘0x496B1E7794494E1ff44D036925728186Af03dDb6’,‘0x14aCF29C8B33034e9E459218126cafC1a1E7ed93’,‘0x00D59D87d9DFd7a89FA541715e2d998349f10364’,‘0xaDd0A44f0E7aE577d177Ed23dA5449301E8401F6’,‘0xc0a30F28697BBCf1ED569012D9cF9Dddb1b6444F’,‘0xa360C829083D5dFc381A913e13B9f4A6756B6a8f’,‘0x0B86E07440f8AE6Fbb325FD043cc9b0585c53FD7’,‘0x4fb9f2ceF1B85b5774509FCE4025396D3886BC4d’,‘0x51b4d3BB8ECc292b71c8435D648Be9dDaf2A36c8’,‘0x3f90e9DBafB8E1Ab1fa250A9eb7cF126955C34ec’]> connection.eth.getBalance('0x496B1E7794494E1ff44D036925728186Af03dDb6').then(console.log);100000000000000000000

With Ganache CLI running in a different terminal, we open up a new terminal, start up a local Node.js server, and load the web3 package containing the web3.js library. We define the connection variable to reference a new instance of the package’s main class which contains all things related to Ethereum. We can see that the connection was successful as the getAccounts method provided by web3 returns the accounts that we created in the Launching our in-memory blockchain with Ganache section above. In addition, we can see the current balance of any account using the getBalance method which takes a String of the address of the account from which we want to get the balance and returns the current balance in wei. The returned value of 100000000000000000000 wei is equivalent to 100 ether which you will remember is what Ganache preloaded into our accounts.

随着Ganache CLI在其他终端上运行,我们打开一个新终端,启动本地Node.js服务器,并加载包含web3.js库的web3软件包。 我们定义connection变量以引用包主类的新实例,该实例包含与以太坊相关的所有内容。 我们可以看到连接成功,因为web3提供的getAccounts方法返回了我们在上面的用Ganache启动内存中的区块部分中创建的帐户。 另外,我们可以使用getBalance方法查看任何帐户的当前余额,该方法获取我们要从中获取余额的帐户地址的字符串,并以wei返回当前余额。 返回的值100000000000000000000 wei等于100以太币,您将记住那是Ganache预加载到我们帐户中的东西。

When we call the getAccounts and getBalance methods from our Nodes.js server, we will see the following output in Ganache CLI.

当我们从Nodes.js服务器调用getAccountsgetBalance方法时,我们将在Ganache CLI中看到以下输出。

eth_accountseth_getBalance

These are the underlying JSON-RPC methods that are being called by the methods that we are calling via the web3.js library. JSON-RPC is a stateless, light-weight remote procedure call (RPC) protocol that uses JSON as its data format. This gives us a good example of how web3.js is giving us a convenient interface for the RPC methods. Without the web3.js library, our calls would like something like this.

这些是我们通过web3.js库调用的方法正在调用的底层JSON-RPC方法。 JSON-RPC是一种无状态的轻量级远程过程调用(RPC)协议,该协议使用JSON作为其数据格式。 这为我们提供了一个很好的示例,说明了web3.js如何为RPC方法提供便捷的接口。 没有web3.js库,我们的调用将需要这样的内容。

curl -X POST — data '{“jsonrpc”:”2.0",”method”:”eth_accounts”}' '127.0.0.1:8545'{“jsonrpc”:”2.0",”result”:[“0x496b1e7794494e1ff44d036925728186af03ddb6”,”0x14acf29c8b33034e9e459218126cafc1a1e7ed93",”0x00d59d87d9dfd7a89fa541715e2d998349f10364",”0xadd0a44f0e7ae577d177ed23da5449301e8401f6",”0xc0a30f28697bbcf1ed569012d9cf9dddb1b6444f”,”0xa360c829083d5dfc381a913e13b9f4a6756b6a8f”,”0x0b86e07440f8ae6fbb325fd043cc9b0585c53fd7",”0x4fb9f2cef1b85b5774509fce4025396d3886bc4d”,”0x51b4d3bb8ecc292b71c8435d648be9ddaf2a36c8",”0x3f90e9dbafb8e1ab1fa250a9eb7cf126955c34ec”]}curl -X POST — data '{“jsonrpc”:”2.0",”method”:”eth_getBalance”,”params”:[“0x496B1E7794494E1ff44D036925728186Af03dDb6”, “latest”],”id”:1}' '127.0.0.1:8545'{“id”:1,”jsonrpc”:”2.0",”result”:”0x56bc75e2d63100000"}

As you can see, web3.js has a number of benefits to this approach. The first benefit being the advantage of asynchronous, Promise-based calling and the second being the returned data is scoped down to just the data that we are looking for and in our desired format.

如您所见,web3.js对该方法有很多好处。 第一个好处是基于Promise的异步调用的好处,第二个好处是返回的数据的范围仅限于我们要查找的数据以及所需的格式。

Now that we have a successful connection to a blockchain node, we can deploy our smart contract to Ethereum. We can do so using the web3.js library and the .abi and .bin files that were created during compilation.

现在我们已经成功连接到区块链节点,我们可以将智能合约部署到以太坊了。 我们可以使用web3.js库以及在编译过程中创建的.abi.bin文件来执行此操作。

> abi = JSON.parse(fs.readFileSync('SmartContract_sol_SmartContract.abi'));> contract = new connection.eth.Contract(abi);

To deploy the contract, we will use the deploy method provided by the web3.js library. This method is available to a Contract object so we first need to create a new instance of that object. The constructor of a Contract requires us to pass a jsonInterface object as a parameter. Luckily we already have such an interface in the .abi file, so all that we need to do is to create a new variable that we will arbitrarily name abi, read the SmartContract_sol_SmartContract.abi file into our Node.js server, and assign the returned object to our new variable. We then pass this to the Contract constructor.

要部署合同,我们将使用web3.js库提供的deploy方法。 Contract对象可以使用此方法,因此我们首先需要创建该对象的新实例。 Contract的构造函数要求我们传递jsonInterface对象作为参数。 幸运的是,我们在.abi文件中已经有这样的接口,所以我们要做的就是创建一个新变量,我们将其任意命名为abi ,将SmartContract_sol_SmartContract.abi文件读入Node.js服务器,并分配返回的变量反对我们的新变量。 然后,将其传递给Contract构造函数。

> bytecode = fs.readFileSync('SmartContract_sol_SmartContract.bin').toString();> listOfPosts = ['A Beginner’s Guide to Ethereum','How Does Ethereum Work?','The Year in Ethereum','What is Ethereum 2.0?', 'Ethereum is a Dark Forest'];> contract.deploy({  data: bytecode,  arguments: [listOfPosts.map((name) =>    connection.utils.asciiToHex(name))]  }).send({    from: '0x496B1E7794494E1ff44D036925728186Af03dDb6',    gasPrice: connection.utils.toWei('0.00003', 'ether'),    gas: 1500000  }).then((deployedContract) => {  contract.options.address = deployedContract.options.address;  console.log(deployedContract.options.address);});

The deploy method requires a data parameter containing the bytecode of the smart contract in String format. Luckily we already have the bytecode format of our smart contract in the .bin file, so all that we need to do is to create a new variable that we will arbitrarily name bytecode, read the SmartContract_sol_SmartContract.bin file into our Node.js server, and convert the returned Buffer to a String. Next we define the new listOfPosts variable and populate it with a list of post names. We do this because, if you recall from the Writing the smart contract with Solidity section above, we defined a constructor for our smart contract that expects an Array of post names. It will get this from the arguments parameter that we pass to the deploy method.

deploy方法需要一个data参数,该参数包含String格式的智能合约的字节码。 幸运的是,我们已经在.bin文件中有了智能合约的字节码格式,因此我们要做的就是创建一个新变量,我们将随意命名bytecode ,将SmartContract_sol_SmartContract.bin文件读入Node.js服务器,并将返回的Buffer转换为String。 接下来,我们定义新的listOfPosts变量,并用帖子名称列表填充它。 这样做是因为,如果您从上面的“ 使用Solidity编写智能合约”中回想起,我们为智能合约定义了一个构造函数,该构造函数需要一个邮政名称数组。 它将从传递给deploy方法的arguments参数中获取。

Now we are ready to deploy our smart contract! We pass to the deploy method the stringified bytecode and the Array of post names. Recall from the Writing the smart contract with Solidity section above that we told our smart contract to expect the list of post names in Bytes32 format so we first convert our Array of Strings using the asciiToHex utility function provided by the web3.js library. The deploy method returns the transaction object which has a send method.

现在,我们准备部署智能合约! 我们将字符串化的字节码和帖子名称数组传递给deploy方法。 回想一下上面的“ 使用Solidity编写智能合约”一节,我们告诉智能合约期望Bytes32格式的帖子名称列表,因此我们首先使用web3.js库提供的asciiToHex实用程序函数转换字符串数组。 deploy方法返回具有send方法的事务对象。

We then call the send method of the transaction object to deploy the smart contract to Ethereum. This method requires a from parameter containing the address the transaction should be sent from. We got such an address when we launched Ganache using Ganache CLI which returned ten account numbers; we can pass any of these account numbers as an argument.

然后,我们调用交易对象的send方法将智能合约部署到以太坊。 此方法需要一个from参数,该参数包含应从中发送事务的地址。 当我们使用Ganache CLI启动Ganache时,我们得到了这样的地址,它返回了十个帐号。 我们可以将这些帐号中的任何一个作为参数传递。

The send method takes an optional gasPrice argument that defines the gas price in wei to use for this transaction. If we didn’t explicitly set this price then the transaction would use the default gas price that was defined when we launched Ganache CLI. The total transaction cost will then be converted to ether and deducted from the account passed to in the from parameter to buy the gas. We discussed gas price in the Launching our in-memory blockchain with Ganache section above. Recall from that section that the gas price is the incentive for miners on Ethereum to process our transactions so a high or low gas price affects the speed at which a transaction is executed. One example where one might set a higher gas price is in the presale of tokens of an initial coin offering (ICO) to increase the chances of including the transaction in the next block. Vice versa, one met set a lower gas price when transferring funds from one wallet to another. To determine the gas prices of a faster transaction versus a slower transaction, you can consult various online services such as ETH Gas Station.

send方法采用可选的gasPrice参数,该参数定义用于此交易的wei中的汽油价格。 如果我们未明确设置此价格,则交易将使用启动Ganache CLI时定义的默认汽油价格。 然后,总交易成本将转换为以太币,并从传递给from参数的帐户中扣除以购买天然气。 我们在上面的“ 用Ganache启动内存中的区块链”一节中讨论了汽油价格。 回想一下那部分,汽油价格是以太坊上的矿工处理我们交易的诱因,因此汽油价格的高低会影响交易的执行速度。 一个可能设定更高汽油价格的示例是预售初始代币发行(ICO)的代币,以增加将交易包括在下一个区块中的机会。 反之亦然,当将资金从一个钱包转移到另一个钱包时,一个会议遇到了一个较低的汽油价格。 要确定较快交易与较慢交易的汽油价格,可以咨询各种在线服务,例如ETH加油站 。

In addition to the gasPrice argument, we also pass the optional gas argument to define the maximum units of gas that we are willing to expend on this transaction, i.e. the transaction gas limit. The transaction gas limit is different than the block gas limit that we defined in the Launching our in-memory blockchain with Ganache section above. Recall from that section that we set the block gas limit to 6,721,975 units of gas, so with a transaction gas limit of 1,500,000 units of gas we could fit four of these transactions into one block of our Ethereum blockchain. If the smart contract is successfully deployed, the send method will return a Promise which resolves with the newly deployed contract. We assign our contract variable the number of the account that we defined in the deployment of the smart contract so that we can interact with it later.

除了gasPrice参数之外,我们还传递了可选的gas参数来定义我们愿意在此交易中花费的最大天然气单位,即交易天然气限额。 交易气体限制与我们在上面的用Ganache启动内存中的区块部分中定义的区块气体限制不同。 回顾该部分,我们将区块气体限制设置为6,721,975单位天然气,因此,以1,500,000单位气体的交易气体限制,我们可以将其中四笔交易放入以太坊区块链的一个区块中。 如果成功部署了智能合约,则send方法将返回一个Promise,该承诺将与新部署的合约一起解决。 我们为contract变量分配在智能合约部署中定义的帐户编号,以便以后与之交互。

When we execute the code above we should see the following in Ganache CLI.

当我们执行上面的代码时,我们应该在Ganache CLI中看到以下内容。

Transaction: 0xfd6770811adecbcbc736b8cac99614b4ed89d58adae51742f02befbe0ab29c20Contract created: 0x315520e2aa049a49c2ef63c29671fab8432f5d9eGas usage: 307612Block Number: 1Block Time: Sun Sep 06 2020 10:28:58 GMT-0400 (Eastern Daylight Time)

The total units of gas used was 307,612 which was under the limit that we set of 1,500,000 units of gas.

所使用的天然气总量为307,612,低于我们设定的1,500,000天然气单位的限制。

We can get the current balance, in wei, of any of our accounts using the getBalance method provided by the web3 library.

我们可以使用web3库提供的getBalance方法以wei为单位获取任何帐户的当前余额。

> connection.eth.getBalance('0x496B1E7794494E1ff44D036925728186Af03dDb6').then(console.log);90771640000000000000

We set a price per unit of 30,000,000,000,000 wei (0.00003 ether). The transaction used 307,612 units of gas. So the total transaction cost was 9,228,360,000,000,000,000 wei (9.22836 ether). If we take our initial account balance of 100,000,000,000,000,000,000 wei (100 ether) and subtract the total transaction cost of 9,228,360,000,000,000,000 wei (9.22836 ether) the difference is 90,771,640,000,000,000,000 wei (90.77164 ether) which aligns with what we see returned by the getBalance method.

我们将每单位价格定为30,000,000,000,000 wei(0.00003 ether)。 该交易使用了307,612单位天然气。 因此,总交易成本为9,228,360,000,000,000,000 wei(9.22836 ether)。 如果我们将初始账户余额100,000,000,000,000,000,000 wei(100以太网)减去9,228,360,000,000,000,000 wei(9.22836以太网)的总交易成本,则差额为90,771,640,000,000,000,000 wei(90.77164以太网),这与我们通过getBalance方法返回的结果一致。

将智能合约与Node.js结合使用 (Using the smart contract with Node.js)

Now we can interact with our newly deployed smart contract via our Node.js console. We can access the two methods defined in our contract, totalLikesFor and likePost, using the methods method that the web3.js library provides to instances of the Contract class. Let’s first check the number of likes for one of our posts.

现在,我们可以通过Node.js控制台与新部署的智能合约进行交互。 我们可以使用web3.js库提供给Contract类实例的methods方法来访问合同中定义的两个方法totalLikesForlikePost 。 首先,让我们检查一下其中一篇帖子的喜欢人数。

> contract.methods.totalLikesFor(connection.utils.asciiToHex('How Does Ethereum Work?')).call(console.log);null 0

We convert one of our post names to the Bytes32 type as per the parameters that we defined in our totalLikesFor function in the Writing the smart contract with Solidity section above. We then execute this function using the methods method. As expected, the returned value is 0 since we just deployed our smart contract and no posts have yet been “liked”.

根据上面的“使用Solidity 编写智能合约”一节中在totalLikesFor函数中定义的参数,我们将帖子名称之一转换为Bytes32类型。 然后,我们使用methods方法执行此功能。 正如预期的那样,由于我们刚刚部署了智能合约,并且还没有“喜欢”任何帖子,因此返回值为0

Let’s change that next by “liking” that post by executing the likePost function of our smart contract.

接下来,通过执行我们的智能合约的likePost函数来“点likePost ”该帖子,以更改它。

> contract.methods.likePost(connection.utils.asciiToHex('How Does Ethereum Work?')).send({from: '0x14aCF29C8B33034e9E459218126cafC1a1E7ed93'}).then((response) => console.log(response));{  transactionHash: '0x7958f89a74ba6efd27a8a76b66e1e7b4d2649c1bd402d0344a3433f344eb3dfe',  transactionIndex: 0,  blockHash: '0xe0ee74688653cb998311cd592eacacdcd78b3bee5165c319db2c8e0d3b03b311',  blockNumber: 2,  from: '0x14acf29c8b33034e9e459218126cafc1a1e7ed93',  to: '0x315520e2aa049a49c2ef63c29671fab8432f5d9e',  gasUsed: 42673,  cumulativeGasUsed: 42673,  contractAddress: null,  status: true,  logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',  events: {}}

Like we did for the totalLikesFor function, we convert one of our post names to the Bytes32 type before calling our likePost function using the methods method. We then execute this function and pass as an argument the address of one of the other accounts that was created for us when we launched Ganache CLI. The returned response contains the receipt of the transaction where we can see that a second block was formed, and we can determine from which account the transaction came from as well as how many units of gas were used to execute the transaction.

就像我们对totalLikesFor函数所做的totalLikesFor ,我们totalLikesFor其中一种帖子名称转换为Bytes32类型,然后再使用methods方法调用likePost函数。 然后,我们执行此功能,并将启动Ganache CLI时为我们创建的其他帐户之一的地址作为参数传递。 返回的响应包含交易的收据,我们可以在其中看到形成了第二个区块,并且可以确定交易来自哪个帐户以及使用了多少天然气单位来执行交易。

We can see that our likePost function worked as expected by executing our totalLikesFor function on the target post.

通过在目标帖子上执行totalLikesFor函数,我们可以看到likePost函数按预期工作。

> contract.methods.totalLikesFor(connection.utils.asciiToHex('How Does Ethereum Work?')).call(console.log);null 1

As expected, the returned value is now 1 as per the instructions that we coded into the smart contract.

正如预期的那样,根据我们编码到智能合约中的指令,返回值现在为1

Let’s pause here to note that we use the send method to execute our likePost function while we used the call method to execute our totalLikesFor function. This exemplifies an important distinction between executing functions in Ethereum. The call method can not modify the smart contract state and therefore can be executed in Ethereum without sending a transaction. In contrast, the send method can modify the state of the smart contract and therefore will send a transaction. This is important because, as we have discussed throughout this blog, transactions come at a cost because they add a new block to the blockchain.

让我们在这里暂停一下,注意我们使用send方法执行likePost函数,而使用call方法执行totalLikesFor函数。 这体现了以太坊中执行功能之间的重要区别。 call方法无法修改智能合约状态,因此可以在以太坊中执行而无需发送交易。 相反, send方法可以修改智能合约的状态,因此将发送交易。 这很重要,因为正如我们在整个博客中所讨论的那样,交易是有代价的,因为它们为区块链添加了新的区块。

When writing smart contracts with Solidity, we can use keywords in the declaration of our functions to determine whether or not they will modify the state of the smart contract. Recall from the Writing the smart contract with Solidity section above that we declared the totalLikesFor function as follows.

使用Solidity编写智能合约时,我们可以在函数的声明中使用关键字来确定它们是否将修改智能合约的状态。 回顾上面的“使用totalLikesFor 编写智能合约”一节,我们声明了totalLikesFor函数,如下所示。

function totalLikesFor(bytes32 post) view public returns (uint256) {  return likesReceived[post];}

The view keyword in this declaration ensures that this function will not modify the state of the smart contract. Users of the smart contract should look for these keywords in the code of the smart contract to avoid executing view and similar functions with the costly send method rather than the free call method. One means to determine this is via the .abi file. Recall from the Writing the smart contract with Solidity section above that the .abi file is the interface for a smart contract. As such, we can inspect this file to determine which functions can modify the state and which cannot. The web3.js library provides the jsonInterface method to instances of the Contract class for such inspection.

此声明中的view关键字可确保此函数不会修改智能合约的状态。 智能合约的用户应在智能合约的代码中查找这些关键字,以避免使用昂贵的send方法(而不是免费call方法)执行view和类似功能。 一种确定方法是通过.abi文件。 回顾上面的“使用.abi 编写智能合约”部分, .abi文件是智能合约的界面。 这样,我们可以检查该文件以确定哪些函数可以修改状态,哪些不能修改状态。 web3.js库为Contract类的实例提供jsonInterface方法,以进行此类检查。

> contract.options.jsonInterface;[...  {    inputs: [ [Object] ],    name: ‘likePost’,    outputs: [],    stateMutability: ‘nonpayable’,    type: ‘function’,    constant: undefined,    payable: undefined,    signature: ‘0x68dbf9a8’  },...  {    inputs: [ [Object] ],    name: ‘totalLikesFor’,    outputs: [ [Object] ],    stateMutability: ‘view’,    type: ‘function’,    constant: true,    payable: undefined,    signature: ‘0x333f5f0b’  }]

We can see that the totalLikesFor function has a stateMutability value of ‘view’ which aligns with how we defined the function. The function also has a constant value of true indicating that the function is specified to not modify the state of the smart contract.

我们可以看到totalLikesFor函数的stateMutability值为'view' ,与我们定义函数的方式一致。 该函数还具有constanttrue指示该函数被指定为不修改智能合约的状态。

We can verify that executing the likePost function, a function that does modify the state of the smart contract, via the send method indeed sent and charged us for a transaction using the getBalance function to check the balance of the account from which we initiated the transaction.

我们可以通过使用getBalance函数检查发起交易的帐户的余额,通过send方法确实已发送并向我们收取了交易费用,从而验证了执行likePost函数(该函数确实修改了智能合约的状态) 。

> connection.eth.getBalance( '0x14aCF29C8B33034e9E459218126cafC1a1E7ed93').then(console.log);100000000000000000000

Prior to the transaction, our account was full.

交易之前,我们的帐户已满。

> connection.eth.getBalance( '0x14aCF29C8B33034e9E459218126cafC1a1E7ed93').then(console.log);99999146540000000000

Our account balance is now lower. Looking at the receipt of the transaction, which we can access at any time via the getTransactionReceipt method provided by the web3.js library, we see that the transaction used 42,673 units of gas. Since we didn’t define a gas price in the send method, the default gas price of 20,000,000,000 wei (0.00000002 ether) is used which makes the total transaction cost equal to 853,460,000,000,000 wei (0.00085346 ether). This aligns with our remaining account balance of 99,999,146,540,000,000,000 (99.99914654 ether) that we see above. We can also see the transactionHash value which represents the unique ID for this transaction. Rather than overriding the transaction before it, each transaction adds a new block to the chain generating a new transactionHash which can be used to reference this transaction at any point in the future. This makes each transaction immutable and allows anyone to find our previous transaction by looking it up the blockchain’s ledger with its ID. This immutability and accessible insight is one of the big advantages of blockchains such as Ethereum.

现在我们的帐户余额较低。 查看交易的收据,我们可以通过web3.js库提供的getTransactionReceipt方法随时访问该交易的收据,我们看到该交易使用了42673单位天然气。 由于我们没有在send方法中定义天然气价格,因此使用了默认的天然气价格20,000,000,000 wei(0.00000002 ether),这使得总交易成本等于853,460,000,000,000 wei(0.00085346 ether)。 这与我们在上方看到的帐户余额99,999,146,540,000,000,000(99.99914654以太)相符。 我们还可以看到transactionHash值,该值代表此事务的唯一ID。 每个事务都不会在其之前覆盖事务,而是在链中添加一个新块,生成一个新的transactionHash ,该哈希可在将来的任何时候引用该事务。 这使得每笔交易都是不可变的,并允许任何人通过查找带有ID的区块链分类帐来找到我们之前的交易。 这种不变性和可访问性的洞察力是以太坊等区块链的一大优势。

Great work! We now have a decentralized application running on an in-memory Ethereum blockchain backed by a smart contract. To retrospect on the work that we did in this blog, we first set up and launched a personal, in-memory blockchain using Ganache and Ganache CLI. Next, we wrote a smart contract using the Solidity programming language and compiled it using Solidity Compiler. We then deployed our smart contract using the web3.js JavaScript-based library creating the first block in the Ethereum blockchain. Lastly, we interacted with the newly deployed smart contract by executing its coded terms, creating new transactions, and adding new blocks to the blockchain.

做得好! 我们现在有一个分散的应用程序,该应用程序在以智能合约为后盾的内存以太坊区块链上运行。 为了回顾我们在此博客中所做的工作,我们首先使用Ganache和Ganache CLI建立并启动了一个个人的内存区块链。 接下来,我们使用Solidity编程语言编写了一个智能合约,并使用Solidity Compiler对其进行了编译。 然后,我们使用基于web3.js基于JavaScript的库部署了智能合约,从而在以太坊区块链中创建了第一个区块。 最后,我们通过执行其编码条款,创建新交易并向区块链添加新区块,与新部署的智能合约进行了交互。

To get some hands on experience building dapps on Ethereum with Solidity and JavaScript, clone the source code from my GitHub of the application that we built throughout this blog and run it on your local machine.

为了获得一些使用Solidity和JavaScript在以太坊上构建dapp的经验,请从我在GitHub上构建的应用程序的GitHub克隆源代码 ,然后在本地计算机上运行它。

关于作者 (About the author)

Colin Kraczkowsky loves to learn and share about new technologies. His new interest is in blockchain technology and specifically Ethereum development. Colin recently returned to web development after exploring the craft of product management. Colin’s professional history includes working in both enterprise and start up environments to code web and mobile applications, launch new products, build mockups and prototypes, analyze metrics, and continuously innovate.

Colin Kraczkowsky喜欢学习和分享新技术。 他的新兴趣是对区块链技术,特别是对以太坊的开发。 在探索了产品管理技术之后,Colin最近返回了Web开发。 Colin的专业历史包括在企业和启动环境中工作,以编写Web和移动应用程序的代码,发布新产品,构建模型和原型,分析指标并不断创新。

In his spare time, Colin can be found checking out the latest Alite camp kit for a weekend away in the woods, planning his next line down a mountain, or surfing the Horror section on Netflix.

在闲暇时间,可以发现Colin在树林中度过一个周末,在外面检查最新的Alite营地装备,计划下一条山路,或者在Netflix上浏览“恐怖”部分。

Connect with Colin — https://www.linkedin.com/in/colinkraczkowsky

与Colin联系— https://www.linkedin.com/in/colinkraczkowsky

翻译自: https://medium.com/swlh/building-a-decentralized-application-dapp-on-the-ethereum-blockchain-with-javascript-and-solidity-503065ccc23b

去中心化 去区块链


http://www.taodudu.cc/news/show-5375832.html

相关文章:

  • eos代码阅读笔记10 -使用boost单元测试
  • EOS启动超时解决方案
  • 利用cacti实现监控
  • grafana - 监控信息可视化工具
  • zabbix自动发现并监控GPU
  • 安防监控常见的存储方式及存储特点
  • IBOX NFT 数字藏品价格 监控 工具 科技
  • 监控体系之一监控数据采集
  • 小型商场安装数字监控需要哪些设备?
  • 数字体验监控:您需要知道的一切
  • 数字化监控系统特点及功能
  • Foundations of Atlas上架了
  • 读 The Algorithmic Foundations of Differential Privacy(一)
  • 编程的本质:第一章 foundations
  • 《Graph Neural Networks Foundations,Frontiers and Applications》第一部分第一章第1.2.4节翻译和解读
  • MIT机器学习基础(Foundations of Machine Learning, author: Mehryar Mohri et al.)
  • 【读书笔记】Foundations of Cryptography: A Prime
  • JAVA core foundations
  • software foundations LF Tactics
  • Data Science Foundations: Data Mining 数据科学基础:数据挖掘 Lynda课程中文字幕
  • Day 4 Data Flow Analysis-Foundations
  • 人工智能基础第二版《Foundations of Machine Learning》
  • 《Foundations of Cryptography》chapter 1 Introduction
  • 《Graph Neural Networks Foundations,Frontiers and Applications》第一部分第一章1.1节翻译和解读
  • 《Graph Neural Networks Foundations,Frontiers and Applications》预备章节(名词)翻译和解读
  • Foundations of Machine Learning 2nd——第一章 机器学习预备知识
  • 《Graph Neural Networks Foundations,Frontiers and Applications》预备章节(符号)翻译和解读
  • 《Graph Neural Networks Foundations,Frontiers and Applications》第一部分第一章第1.2.2节翻译和解读
  • 《Graph Neural Networks Foundations,Frontiers and Applications》第一部分第一章第1.2.3节翻译和解读
  • software foundations LF Induction

去中心化 去区块链_使用JavaScript和坚固性在以太坊区块链上构建去中心化应用程序dapp...相关推荐

  1. 谈谈区块链入门技能(二):以太坊区块链浏览器如何使用?

    上一期我们介绍了比特币浏览器如何使用,本期我们来谈一谈什么是以太坊以及以太坊浏览器如何使用. 什么是以太坊? 以太坊是一个合作运行的.全球性的.透明的数据库.通过共同努力,来自世界各地的参与者维护了以 ...

  2. 曲速未来 揭秘:以太坊区块链和ERC20代币的技术挑战

    区块链安全咨询公司 曲速未来 消息:在2018年,可以看到以太坊区块链的能力的许多进步.这些创新是由遍及庞大且不断发展的生态系统的以太坊和ERC20令牌项目推动的. 这些创新对于以太坊作为新标记的顶级 ...

  3. 以太坊区块链实现去中心化购物功能

    在当今的中国,网上购物已经成为了我们不可或缺的一部分,通过电商网站查看商品,下单购物,支付,付款到支付宝,买家收货确认后,货款自动打入卖家的账户,这些购物的体验多数人每天都可能发生.大家都知道,淘宝的 ...

  4. 以太坊区块链也拥堵_后以太坊1.0众生相:DeFi拥堵,突围Layer2

    不知不觉,我们已经走到了一个「后ETH1.0时代」.从使用体验上,ETH1.0已经不能很好地满足用户的需求:仅仅是DeFi应用,就让其走向了史无前例的.不可忍受的拥堵.然而,孕育了数年的ETH2.0却 ...

  5. 以太坊区块链同步_以太坊69:如何在10分钟内建立完全同步的区块链节点

    以太坊区块链同步 by Lukas Lukac 卢卡斯·卢卡奇(Lukas Lukac) Ethereu M 69:如何在10分钟内建立完全同步的区块链节点 (Ethereum 69: how to ...

  6. java计步器算法_区块链+计步运动项目,主要采用以太坊、智能合约、springboot以及小程序等技术...

    runlife_api 项目介绍 区块链+计步运动项目,主要采用以太坊.智能合约.springboot以及小程序等技术 兑换步数算法 按照每总量剩余一半的时候兑换难度增加一倍,如目前按照平均步数511 ...

  7. 以太坊区块链也拥堵_以太坊开发人员:EOS刻意拥堵以太坊网络 推高交易费到1美元...

    金色财经 比特币7月16日讯根据一些DApp开发人员表示,EOS正在攻击以太坊,试图将交易费提高到1美元.据悉,相关开发人员指责EOS通过随机代币"空投"造成以太坊网络堵塞,而且这 ...

  8. 以太坊区块链_以太坊区块链搭建与使用(一)-私有链

    步骤 一.下载go语言,并配置环境变量 //以太坊源代码依赖的编译与运行环境 二.通过git clone以太坊源码(go-ethereum),并编译 一.go安装 step1:下载 官方(一般打不开) ...

  9. 如何搭建socks5和ss节点_以太坊区块链搭建与使用(三)-联盟链

    首先对以下概念说明下: 一.以太坊大家都知道比特币使用的技术是区块链技术,比特币也是区块链技术的代表. 即比特币=区块链1.0随着区块链技术的发展以太坊也诞生了,也就是我们说的 区块链2.0.为什么说 ...

最新文章

  1. Matlab实用程序--图形应用-饼图的绘制
  2. gps有几个轨道面_嫦五“一脚刹车”,进了环月轨道
  3. Vertx编程风格:您的反应式Web Companion REST API解释了
  4. 【WebRTC---入门篇】(六)JavaScript基础
  5. spring mvc学习(23):eclipse创建Maven项目没有src/main/java并不能新建的问题
  6. jquery-幻灯片的移动分析
  7. 华为P30系列再曝光:屏幕参数揭晓 还要用水滴全面屏?
  8. 关于Resnet50和ResNeXt50的参数量的简单计算(只考虑卷积层和全连接层)
  9. 烂泥:更换ESXI5.0管理网卡及管理IP地址
  10. python类中导入库_python导入库的具体方法
  11. 大神带你实现 NLP 从入门到获奖,还有免费算力可以薅
  12. java读取资源文件(Properties)
  13. 谁说中国没有 Linus?中国初代 IT 宗师封神榜
  14. javacv获取摄像头列表
  15. JavaScript基础教程之flag的用法
  16. 产品思维训练 | 常见的用户增长手段有哪些?
  17. Python Keras ValueError: Layer sequential expects 1 input(s), but it received 2 input tensors. 解决方法
  18. 什么是加密?什么是md5加密算法?
  19. oracle数据的安装,与基本配置
  20. AG9311/AG9310 Type-C转HDMI设计方案|替代AG9310/AG9311芯片|GSV2201可完全替代兼容AG9310/AG9311

热门文章

  1. 企业行业培训讲座在线观看目录
  2. Iconfont图标使用-打造自己项目下…
  3. c语言中百分号md是什么意思,Python中%是什么意思?python中百分号如何使用?
  4. A、B路双电源系统图
  5. 品钛CEO李惠科:数据质量决定了机器学习的上限
  6. 象棋编程游戏——悔棋算法
  7. C3560 flash被删除之后
  8. git branch的系列操作
  9. VGG网络在CIFAR_10和GID数据集上的Pytorch实现
  10. mac windows系统安装mysql, InnoDB: File .\ib_logfile101: 'aio write' returned OS error 187. Cannot cont,