将博客链接永久存储在区块链智能合约上

将博客链接永久存储在区块链智能合约上

首先对区块链智能合约不熟悉的伙伴不用担心,下文会详细介绍如何将自己的博客地址上传存储在区块链上,上传方法是纯js操作。 本文不对区块链做详细解释,想了解的伙伴可以看阮一峰老师的几篇介绍文章

比特币入门教程
加密货币的本质
区块链入门教程

原因

如我之前说的一样,个人博客消息闭塞,我觉得一个个去加友链实在太麻烦了,虽然有做的好的优质博客也有平庸一点甚至差的博客,有的博主会选择性展示友链,但我相信作者的初心都是好的,想有一个展示和记录自己生活的平台,大多数作者应该不是为了赚钱出发的。这些作者曾经来过,我都想把他们记录下来。

思路

区块链上的数据是永久存储的,将博客地址存储在区块链上的上方式就是用智能合约来存储,智能合约是区块链2.0(例如以太坊)提供的一个功能,开发者可以在区块链上开发和存储代码数据。
个人现在是在以太坊上开发的智能合约,并将合约部署到了以太坊的ropsten测试网络。

为什么使用测试网络?因为在以太坊主网部署合约需要花费以太币,而以太币是需要花钱购买的,我们在合约上存储博客链接数据也要花费以太币。不是所有博主都熟悉区块链而且愿意花钱去使用智能合约存储博客链接数据, 所以现在合约暂时使用测试网络,毕竟测试网络的以太币可以免费获得,大家可以随意存储。等使用和赞同这个想法的伙伴多起来后,再考虑迁移到主网。

合约地址

ropsten测试地址

ropsten正式地址

具体步骤

个人有点懒,用文字介绍太麻烦,所有录制了两个视频,展示如何使用智能合约存储博客链接,后面的比较长,建议下载后倍速食用
视频中用到的所有资料文档,都会在文末给出

1. 注册一个以太坊钱包账户

2. 调用智能合约

调用合约的示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// 这是智能合约编译后的合约接口文件,需要使用它来调用合约,可以理解为类似于web应用中接口
let blogInterface = require('./Blog.json');
// 这是调用以太坊的库
let ethers = require('ethers');
(async () => {
// 这是助剂词,metamask钱包的助剂词一定要保存好,不要在网络上传输,助剂词能打开你的钱包,并使用钱包里的资产
let mnemonic = "fault toddler game long trash smart muscle sausage traffic narrow camera express";
// 这一步通过助剂词创建一个钱包对象
let mnemonicWallet = ethers.Wallet.fromMnemonic(mnemonic);

// 这是获取ropsten测试网络对象
let provider = ethers.getDefaultProvider('ropsten');
// 钱包连接到ropsten测试网络
mnemonicWallet = mnemonicWallet.connect(provider)

// 这里是获取钱包账户以太币余额的代码,待会演示一下
// let address = "0x6490a631db8566522db449BEDB5a140c0E84E08B";
// provider.getBalance(address).then((balance) => {

// // 余额是 BigNumber (in wei); 格式化为 ether 字符串
// let etherString = ethers.utils.formatEther(balance);

// console.log("Balance: " + etherString);
// });

// 使用ropsten网络的Provider对象连接合约,将对合约的读写权限,我们在存储博客地址,是需要对合约进行写操作,那么需要使用钱包连接ropsten网络
let blog = new ethers.Contract('0xC331047e691d10B3bf62cA4F9088aC3Fc161c6C9', blogInterface.abi, mnemonicWallet);

// 使用ropsten网络的Provider对象连接合约,将只有对合约的可读权限,在博客网站中读取友链就可以使用这种方式,后面会展示一下
// let blog = new ethers.Contract('0xC331047e691d10B3bf62cA4F9088aC3Fc161c6C9', blogInterface.abi, provider);

// 这是存储博客链接的方法,这里简单说一下怎么调用合约,就不对合约进行讲解了
// 参数依次是网站名称,网站icon头像,网站描述,网站地址,下面是我的例子
// await blog.storeBlog('pppp','ppp','ppp', 'https://itpika.com'); // 这里我先随便存储一些数据,后面删掉就行了,合约提供了删除博客的操作

// 这个方法用来获取所有合约,注意那个参数0,在后面再具体讲解作用,0默认获取所有,如果传一个秒那么只获取大于这个秒数的博客,就是这个博客的注册时间
let allblog = await blog.allBlogs(0);
console.log('allblog---', allblog);
// 这个方法用来设置博客的状态, true表述正常,false表示关闭
// await blog.setBlog(false);
// myblog = await blog.oneself(); // 这个方法是获取自己的博客
// console.log('---', myblog);
// 删除博客,将博客从合约中,永久删除,只能删除当前账户的博客,是不能其它用户的博客的
// await blog.removeBlog();
console.log('normal', await blog.normal()) // 这是获取正常的博客数量
console.log('count', await blog.count()) // 这是获取所有的博客数量,为什么有正常和所有,因为博客可以关闭
})()

合约代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.17 <0.9.0;


contract Blog {
address public owner = msg.sender;

struct BlogLink {
string title; // 网站标题
string icon; // 网站icon头像
string desc; // 网站描述
string link; // 网站地址
bool state; // 状态,true正常返回,false不会在allBlogs中返回
uint256 ctm; // 博客的注册存储时间,调用storeBlog时候取当前的秒
uint256 etm; // 博客的更新时间,调用setBlog和storeBlog时候会修改为当前秒
address onwer; // 博客所有者
}

mapping(address => BlogLink) blogs;

mapping(uint256 => address) indexs;

uint256 public count;

uint256 public normal;

// 存储博客,修改博客内容也调用这个方法
function storeBlog(string memory title, string memory icon, string memory desc, string memory link) public {
if (!blogs[msg.sender].state && blogs[msg.sender].onwer == address(0)) {
count++;
normal++;
indexs[count] = msg.sender;
blogs[msg.sender] = BlogLink(title, icon, desc, link, true, block.timestamp, block.timestamp, msg.sender);
} else {
blogs[msg.sender].title = title;
blogs[msg.sender].icon = icon;
blogs[msg.sender].desc = desc;
blogs[msg.sender].link = link;
blogs[msg.sender].etm = block.timestamp;
}
}

// 获取所有博客,可以根据lastEtm参数过滤最后修改的博客
function allBlogs(uint256 lastEtm) public view returns (BlogLink[] memory) {
BlogLink[] memory links = new BlogLink[](normal);
uint256 idx = 0;
for (uint256 i = 1; i <= count; i++) {
BlogLink memory lk = blogs[indexs[i]];
if (lk.state) {
if (lastEtm > 0 && lk.etm < lastEtm) {
continue;
}
links[idx++] = lk;
}
}
if (idx == normal) {
return links;
}
BlogLink[] memory ret = new BlogLink[](idx);
for (uint256 i = 0; i < idx; i++) {
ret[i] = links[i];
}
return ret;
}

// 获取自己的博客
function oneself() public view returns (BlogLink memory) {
return blogs[msg.sender];
}

// 设置博客的状态,true为展示,false为不展示
function setBlog(bool open) public {
if (blogs[msg.sender].onwer == address(0)) {
return;
}
if (blogs[msg.sender].state && !open) {
blogs[msg.sender].state = open;
normal--;
} else if (!blogs[msg.sender].state && open) {
blogs[msg.sender].state = open;
normal++;
}
blogs[msg.sender].etm = block.timestamp;
}

// 删除博客,只能自己删除自己的
function removeBlog() public {
if (blogs[msg.sender].onwer == address(0)) {
return;
}
if (blogs[msg.sender].state) {
normal--;
}
delete blogs[msg.sender];
count--;
}
}

写在最后

合约的功能比较简单,之前想过点赞,投票等等功能,但最后觉得都不适合放在里面,因为这些操作都需对合约进行写操作,而写操作需要花费以太币,在测试环境,以太币免费,难免会有弄虚作假, 如果是在以太坊主网,那么又需要花费真正的以太币来维护博客合约的功能,是需要RMB的,但合约只是用来存储博客链接的,不太适合这么复杂的功能,这样会增加维护合约的成本

对于动态博客,可以在后台做一个筛选功能,筛选那些合法且满意的链接,存入数据库,再展示。
静态博客,类似与我的这种,那么只有在页面加载的时候自行筛选了,这也是为什么要大家一起维护合约整洁的原因

我已经把自己之前加了友链的伙伴的链接放入到了合约里面,如何这些伙伴如果也想使用博客合约,可以留言或者发邮件给我,我会删除合约里你们的博客, 然后你们自己按照上述的流程去存储自己的博客链接,毕竟助剂词掌握在自己手里才是安全的。

最后再说一句,虽然我们是使用的ropsten测试网络,但也请收好自己的助剂词,有了助剂词才能在合约添加修改删除自己的博客链接。

相关资料文件

ethers文档
Metamask官网
Blog.js文件

将博客链接永久存储在区块链智能合约上

http://itpika.com/2022/08/04/feeling/blogToBlock/

作者

itpika

发布于

2022-08-04 11:48:58

更新于

2022-08-04 17:04:10

许可协议

评论