了解区块链技术(Patrick Collins)(五)

下载 & 安装

使用线上remix的缺点:

1、只能处理智能合约,不能真正的与项目的其他部分进行集成

2、对测试和定制部署的支持有限,需要保持联网

一种更为专业的智能合约开发者配置:

hardhat,智能合约开发框架,基于javaScript的编译环境,部署,测试,bug调试

如何使用ether.js ?

它是一个基于js的库,用于编写智能合约,hardhat的底层使用了很多ether.js的东西

下载Visual Studio Code node.js

使用工具让Windows环境可以向Linux那样工作,因为Linux是大多数开发环境的标准

wsl表示Windows的Linux子系统,可以让Linux程序在Windows环境的本机下运行

安装wsl:https://learn.microsoft.com/en-us/windows/wsl/install

扩展:Remote Development下载

ctrl + shift + p ,输入wsl,点击connect to wsl,然后在打开终端

使用Code .打开文件夹或者文件

安装node.js

z-jiawei@DESKTOP-84O604F:~/folder$ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
curl: (7) Failed to connect to 127.0.0.1 port 7890 after 0 ms: Connection refused
DNS污染
199.232.68.133 raw.githubusercontent.com
199.232.68.133 user-images.githubusercontent.com
199.232.68.133 avatars2.githubusercontent.com
199.232.68.133 avatars1.githubusercontent.com
也不能解决的话,可以根据这个安装
https://blog.csdn.net/weixin_44786530/article/details/134263497  ===> 很方便

添加扩展,提供语法高亮

设置VS Code在我们保存的时候自动格式化

(1)view - command open User settings(JSON)

 // 表示任何时候我们格式化代码的时候,都会使用hardhat-solidity默认的格式化程序
 "[solidity]": {
        "editor.defaultFormatter": "NomicFoundation.hardhat-solidity"
    }

(2)添加在保存时格式化:

open settings(UI)

打钩 format on save

使用js部署合约

(1)如何使用JavaScript和Node.js运行一个脚本

deploy.js中写入console.log("hi!"),使用node.js执行JavaScript

JavaScript会自动从文件的顶部的代码开始执行

当把操作封装进函数后,node deploy.js是不会有任何响应的

//可以通过这样执行
function main() {
    console.log("hi!");
    let variable = 5;
    console.log(variable);//javaScript允许选择是否带上分号
}
main();

异步函数(代码同时执行):

async function main() {//await
    console.log("hi!");
    let variable = 5;
    console.log(variable);//javaScript允许选择是否带上分号
}
main();

在remix中我们首先要做的就是编译代码,为了编译我们的合约,我们使用solc-js工具,能编译通过相对路径导入其他合约的合约

yarn package manager,安装yarn作为总的包管理工具

官网:yarnpkg.com/getting-started

使用corepack enable

接下来就可以通过yarn来安装所有项目了,而不是npm

package.json:是一个描述我们的项目以及它的依赖关系的文件

yarn.lock:告诉我们项目所使用的不同包的确切版本,自动生成的文件,不要直接编译

node_moudles:我们下载的所有代码

我们使用的solidity的版本是:

pragma solidity ^0.8.19;

package.json中可以看到:

solc的依赖部分变成了0.8.19yarn既可以安装依赖库,也可以运行脚本

接下来就可以编译合约了

yarn solcjs --bin --abi --include-path node_modules/ --base-path . -o . SimpleStorage.sol

--bin --abi:想要的是二进制文件和ABI

include-path node_moudles/:想包含node_modules中的所有智能合约或文件

--base-path .:表示其实路径是当前这个文件夹

-o .:表示编译出来的二进制文件和ABI也输出到这个文件夹

简化编译

package.json中添加script部分,缩短运行脚本时的命令长度

  "scripts": {
    "compile": "yarn solcjs --bin --abi --include-path node_modules/  --base-path . -o . SimpleStorage.sol"
  }
//使用yarn compile 进行编译

Ganache:

未来将使用hardhat运行时环境作为我们的JavaScript虚拟机

trufflesuite.com/ganache/

快速启动个人以太坊区块链,您可以使用它来运行测试、执行命令和检查状态,同时控制链的运行方式

下载:

github加速:https://github.ur1.fun/

https://github.com/trufflesuite/ganache-ui/releases/download/v2.7.1/Ganache-2.7.1-win-x64.appx

点击quick start 就可以快速的启动一个假的区块链网路

在代码中,我们首先要做的就是连接到区块链上,在MetaMask的network中的RPC URL使得我们能够连接到测试网络

http://127.0.0.1:7545,有了这个端点后,就可以对这个端点进行API调用了

提示:http://127.0.0.1:7545需要在软件中更改:

点击switch -- -- server,更改成wsl

https://ethereum.org/en/developers/docs/apis/json-rpc

ethers.js介绍

最流行的JavaScript工具包之一,能够让我们与不同的区块链进行交互,有许多封装函数可以进行API调用,可以在一切兼容EVM的区块链山使用

还有一个非常受欢迎的包web3.js,我们使用ether.js是因为它是支撑hardhat环境的主要工具

yarn add ethers

把ethers导入脚本deploy.js

const ethers = require("ethers");

//在调用main函数之前就把包放入脚本中
//Require 负责导入ethers包
const fs = require("fs-extra");
const ethers = require("ethers");
​
async function main() {
    const provider = new ethers.JsonRpcProvider("http://172.28.128.1:7545");
    //获取钱包
    const wallet = new ethers.Wallet(
        "0xb9e9c69de4f038566a57220c7b27a4b5f95f725ab272f989b1affa22cd7a5d3b",
        provider
    );
    const abi = fs.readFileSync("./SimpleStorage_sol_SimpleStorage.abi", "utf8");
    const binary = fs.readFileSync("./SimpleStorage_sol_SimpleStorage.bin", "utf8");
    //创建合约工厂,只是一个用来部署合约的对象
    const contractFactory = new ethers.ContractFactory(abi, binary, wallet);
    //abi  我们的代码知道如何和合约进行交互
    //bin  编译后的代码
    //wallet 提供了一个私钥使得我们能用它来签名并部署这个合约
    console.log("Deploy...... wait");
    const contract = await contractFactory.deploy(); // 要等待合约部署完成
    console.log(contract);
​
}
main()
    .then(() => process.exit(0))
    .catch((error) => {
        console.error(error);
        process.exit(1);
    });

结果:

其他区块详细信息可以在ganache中查看

await等待contractFactory退出pending状态,并返回promisepending后返回的任何东西

如果想在await contractFactory.deploy中指定gas价格,可以在deploy函数中添加一些overrides

const contract = await contractFactory.deploy({gasPrice: 1000000000});

交易回执:

//更改如下
console.log("Deploy...... wait");
    const contract = await contractFactory.deploy({ gasPrice: 1000000000 }); // 要在这里厅下载,等待合约部署完成
    const deploymentReceipt = await contract.deploymentTransaction().wait(1);//想要等待确认的确切数量
    console.log(deploymentReceipt);
//会返回交易的精确信息

to:null,因为我们正在部署合约

from:表示我们使用的私钥对应的ganache地址

contractAddress:我们创建的这个合约的合约地址

区分开deploymentReceiptcontract.deployTransaction

只有在等待区块确认完成时才会获得交易回执(receipt),否则只能得到合约对象及其包含的部署交易(deploymentTransaction)信息

const deploymentReceipt = await contract.deploymentTransaction().wait(1);

通过ether.js发送_raw_交易:

自己创建一个交易,并通过制定交易信息自己创建一个合约

要把networkID更改成1337

//在调用main函数之前就把包放入脚本中
//Require 负责导入ethers包
const fs = require("fs-extra");
const ethers = require("ethers");
​
async function main() {
    const provider = new ethers.JsonRpcProvider("http://172.28.128.1:7545");
    //获取钱包
    const wallet = new ethers.Wallet(
        "0xb9e9c69de4f038566a57220c7b27a4b5f95f725ab272f989b1affa22cd7a5d3b",
        provider
    );
    const abi = fs.readFileSync("./SimpleStorage_sol_SimpleStorage.abi", "utf8");
    const binary = fs.readFileSync("./SimpleStorage_sol_SimpleStorage.bin", "utf8");
    //创建合约工厂,只是一个用来部署合约的对象
    // const contractFactory = new ethers.ContractFactory(abi, binary, wallet);
    //abi  我们的代码知道如何和合约进行交互
    //bin  编译后的代码
    //wallet 提供了一个私钥使得我们能用它来签名并部署这个合约
    // console.log("Deploy...... wait");
    // const contract = await contractFactory.deploy({ gasPrice: 1000000000 }); // 要在这里厅下载,等待合约部署完成
    // const deploymentReceipt = await contract.deploymentTransaction().wait(1);//想要等待确认的确切数量
    console.log("Let's deploy with only transaction data !");
    //仅使用交易数据发送交易
    const nonce = await wallet.getNonce();
    console.log("nonce的值是多少 ?", nonce)
    const tx = {
        //nonce也用于钱包中给交易签名
        nonce: nonce,
        gasPrice: 20000000000,
        gasLimit: 1000000,
        to: null,
        value: 0,
        //将存储一个很大的二进制对象,二进制代码告诉区块链如何部署这个智能合约
        data: "0x",//就是合约的二进制文件,前面加上0x
        chainId: 1337,
    };//交易未签名,给交易签名,然后发送到区块链上
    // const signedTxResponse = await wallet.signTransaction(tx);
    // console.log(signedTxResponse);
    const sendTxResponse = await wallet.sendTransaction(tx);
    await sendTxResponse.wait(1);
    console.log(sendTxResponse);
​
}
main()
    .then(() => process.exit(0))
    .catch((error) => {
        console.error(error);
        process.exit(1);
    });

sendTransaction中我们已经完成可对交易的签名操作:

1、首先会做一些检查提供者的事情

2、在发送交易之前,进行签名交易

3、然后发送交易

通过ether.js与合约进行交互

ABI不易阅读,可以将后缀改为json,搜索format document格式化代码

const fs = require("fs-extra");
const ethers = require("ethers");
async function main() {
    const provider = new ethers.JsonRpcProvider("http://172.28.128.1:7545");
    const wallet = new ethers.Wallet(
        "0xb9e9c69de4f038566a57220c7b27a4b5f95f725ab272f989b1affa22cd7a5d3b",
        provider
    );
    const abi = fs.readFileSync("./SimpleStorage_sol_SimpleStorage.abi", "utf8");
    const binary = fs.readFileSync("./SimpleStorage_sol_SimpleStorage.bin", "utf8");
    const contractFactory = new ethers.ContractFactory(abi, binary, wallet);
    console.log("Deploy...... wait");
    const contract = await contractFactory.deploy(); 
    const deploymentReceipt = await contract.deploymentTransaction().wait(1);
    const currentFavoriteNumber = await contract.retrieve();
    console.log(currentFavoriteNumber.toString());
    const transactionResponse = await contract.store("7");
    const transactionReceipt = transactionResponse.wait(1);
    const updateFavoriteNumber = await contract.retrieve();
    console.log(updateFavoriteNumber.toString());
}
main()
    .then(() => process.exit(0))
    .catch((error) => {
        console.error(error);
        process.exit(1);
    });

加上toString( );

console.log('current Favorite Number : ${currentFavoriteNumber.toString()}');使用反引号

环境变量:

不能将私钥硬编码到我们的代码中

创建一个.env文件,输出环境变量使用echo $CAT

PRIVATE_KEY=0xb9e9c69de4f038566a57220c7b27a4b5f95f725ab272f989b1affa22cd7a5d3b

想要获取环境变量,并粘贴到脚本中,需要一个dotenv的工具

yarn add dotenv

npmjs.com/package/dotenv

存在以下问题:

info There appears to be trouble with your network connection. Retrying..

问题的解决:

https://blog.csdn.net/weixin_42132439/article/details/127861199

代码:

require("dotenv").config();
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider);

创建.gitignore文件,上传到github时不上传以下两个:

.env
node_modules

私钥管理:

可以在命令行中这样写,不写在.env

可以把私钥本地加密,然后把加密后的密钥放在本地,创建一个encryptKey.js,用来加密密钥

const fs = require("fs-extra");
const ethers = require("ethers");
require("dotenv").config();
​
async function main() {
    const wallet = new ethers.Wallet(process.env.PRIVATE_KEY);
    // 密钥密码和密钥
    const encryptedJsonKey = await wallet.encryptSync(
        process.env.PRIVATE_KEY_PASSWORD,
        process.env.PRIVATE_KEY
    );
    console.log(encryptedJsonKey);
    // 将加密后的私钥放在.encryptedKey.json中,添加在.ignore中
    fs.writeFileSync("./.encryptedKey.json", encryptedJsonKey);
}
main()
    .then(() => process.exit(0))
    .catch((error) => {
        console.error(error);
        process.exit(1);
    });

这样就可以在env中删掉私钥还有我们的私钥密码

 const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
    //获取钱包
    // const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider);
    const encryptedJson = fs.readFileSync("./.encryptedKey.json", "utf8");//利用加密的密钥创建一个钱包
    console.log(encryptedJson);
    // new 加上报错
    let wallet = ethers.Wallet.fromEncryptedJsonSync(
        encryptedJson,
        process.env.PRIVATE_KEY_PASSWORD
    );
    // 将钱包和privider连接起来,当我们的合约工厂进行交易的时候,确保wallet知道privider
    wallet = await wallet.connect(provider);
​
    const abi = fs.readFileSync("./SimpleStorage_sol_SimpleStorage.abi", "utf8");
    const binary = fs.readFileSync("./SimpleStorage_sol_SimpleStorage.bin", "utf8");

histoy可以查看我们的历史记录,可以使用history -C清空历史记录

在测试网和主网上部署合约

只需要RPC_URL和一个私钥就可以在区块链网络上开始交易

alchemy.com

Alchemy具有节点即服务的功能,允许我们连接到他们支持的任何区块链,其他的备选方案有QuickNode、INfura、Morales

google账号注册参考:

https://kerrynotes.com/proxy/

https://kerrynotes.com/register-google-account/

1、Alchemy使用Google账号登录的话,会有一层辅助验证,向账号注册绑定的手机号发送验证码,我一直收不到

2、正常注册的话,会一直卡在vertify to continue不出来验证信息

视频推荐用的是Alchemy,注册不上,改用quicknode.com ,存在绑定银行卡的操作

最后选择了INFURA

根据官网的操作创建API密钥:

https://docs.infura.io/getting-started?_ga=2.41864032.394649363.1705835805-1850825774.1705835795

复制Sepolia中的HTTP到我们项目的.env文件中替换掉RPC _URL

在MetaMask中导出Sepolia网络中账户的私钥

如果不足的话,facuts.chain.link搞一些测试用

https://sepolia.etherscan.io/区块浏览器

合约地址:0xe203397303545E98Beafd9ec9A8EB920e969A573

参考:https://www.jianshu.com/p/1e688582ef44

https://docs.ethers.org/v6/

代码:

const fs = require("fs-extra");
const ethers = require("ethers");
require("dotenv").config();
​
async function main() {
    const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
    //获取钱包
    const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider);
​
    // const encryptedJson = fs.readFileSync("./.encryptedKey.json", "utf8");//利用加密的密钥创建一个钱包
​
    const abi = fs.readFileSync("./SimpleStorage_sol_SimpleStorage.abi", "utf8");
    const binary = fs.readFileSync("./SimpleStorage_sol_SimpleStorage.bin", "utf8");
    //创建合约工厂,只是一个用来部署合约的对象
    const contractFactory = new ethers.ContractFactory(abi, binary, wallet);
    //abi  我们的代码知道如何和合约进行交互
    //bin  编译后的代码
    //wallet 提供了一个私钥使得我们能用它来签名并部署这个合约
    console.log("Deploy...... wait");
    const contract = await contractFactory.deploy(); // 要在这里厅下载,等待合约部署完成
    const deploymentReceipt = await contract.deploymentTransaction().wait(1);//想要等待确认的确切数量
    console.log(`合约地址:${contract.address}`)//不行,一直是undefine,但是可以复制公钥在区块浏览器中看到所有的交易记录
​
    const currentFavoriteNumber = await contract.retrieve();
    console.log(currentFavoriteNumber.toString());
    const transactionResponse = await contract.store("7");
    await transactionResponse.wait(1);
    const updateFavoriteNumber = await contract.retrieve();
    console.log(updateFavoriteNumber.toString());
}

结果:

交易记录:

通过浏览器验证合约

如果有人想在链上查看我们的合约,它们只能看见字节码,通过反编码器尝试将字节码反编译成solidity代码

点击verify and public,选择编译器、solidity的版本和开源许可证,点击continue

将solidity的代码复制粘贴放到页面上,成功后,就可以在contract Source Code看到solidity代码了

如果将合约地址放入搜索框中,搜索后,点击contract,就可以看到合约代码,读合约和写合约

仪表盘和内存池

每个节点除了有区块链节点的副本外,还有一个本地交易的内存,就是内存池

等待被打包的交易,可以认为他们在交易池中

  • 16
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值