用 60 行可读的 TypeScript 代码编写区块链
无论如何,这是代码
那么...就这样吗?
区块链:它每年都变得越来越令人困惑,因为人们用奇怪的比喻来解释它,而不是花 5 分钟来谈论它所涉及的实际数学和代码
这让我很沮丧,因为区块链的概念实际上非常简单:
- 区块链是区块的列表
- 一个块是
- 一些数据
- 前一个区块的哈希值
- 一些象征
- 上述内容的哈希值
如果哈希值具有魔法前缀(即以一定数量的零开头),则区块有效,因此,如果您想向区块链添加一些数据,则必须将其打包成一个区块,为此,您必须找到一个能产生以一定数量的零开头的区块哈希值的代币,这需要大量计算,这就是您获得工作量证明的方式。
好吧,说实话,我只是在谈论一种特定类型的区块链,但这不是重点。编写下面的区块链代码帮助我理解了一些加密货币的基础知识,希望对你也有帮助。我并不是在吹嘘自己有多聪明,能用60行代码写出和比特币一样的技术。
无论如何,这是代码
我正在使用 Deno 和 TypeScript。
让我们首先导入一些稍后需要的哈希器
import { createHash } from "https://deno.land/std@0.91.0/hash/mod.ts";
让我们来定义一下区块和代理。代理指的是在你的计算机上运行的程序,可以与世界各地的其他代理进行比特币交易。
type Block = {
data: string;
prev: string;
token: string;
hash: string;
};
type Agent = {
addAgent(agent: Agent): void;
receiveBlock(block: Block): void;
addData(data: Block["data"]): void;
};
我们将使用 md5 作为哈希函数。它肯定不是最安全的,但我们并不在意。我们00000
在这里也定义一个魔法前缀,这样以后就不会重复了。魔法0
前缀越多,挖掘新区块的难度就越大。
const hashOf = (str: string) => createHash("md5")
.update(str)
.toString();
const magicPrefix = Array(5).fill("0").join("");
现在让我们创建代理工厂。在内部,它将整个区块链保存在内存中,并列出在挖掘新区块时需要广播的所有代理的列表。
第一个区块是“创世区块”,它无需指向前一个区块的哈希值,也无需具有魔法前缀。
const createAgent = (): Agent => {
const chain: Block[] = [{
data: "",
prev: "",
token: "",
hash: hashOf(""),
}];
const agents: Agent[] = [];
return {
addAgent(agent) { /* ... */ },
addData(data) { /* ... */ },
receiveBlock(block) { /* ... */ },
};
};
该addAgent
方法不需要进一步解释:
addAgent(agent) {
agents.push(agent);
},
addData
挖矿基本上就是在这里进行的。这是一个计算密集型的循环,用于找到能够生成带有魔法前缀的区块哈希值的代币。
我选择hashOf(Math.random().toString())
生成一个随机字符串,因为这是一个非常简洁的方法,但不需要散列。
addData(data) {
while (true) {
const prev = chain[chain.length - 1].hash;
const token = hashOf(Math.random().toString());
const hash = hashOf(data + prev + token);
if (hash.startsWith(magicPrefix)) {
const block: Block = { data, prev, token, hash };
chain.push(block);
for (const agent of agents) {
agent.receiveBlock(block);
}
return;
}
}
},
receiveBlock
根据上述条件验证是否可以在链顶部添加新块,如果一切正常,则添加,否则抛出。
receiveBlock(block) {
if (block.prev != chain[chain.length - 1].hash) {
throw new Error(
"Hash does not point to the previous hash in the chain",
);
}
if (!block.hash.startsWith(magicPrefix)) {
throw new Error("Hash does not start with the magic prefix");
}
const actualHash = hashOf(block.data + block.prev + block.token);
if (actualHash !== block.hash) {
throw new Error("Hash is not the hash of data|prev|token");
}
chain.push(block);
},
而且...就是这样!
你可以用这样的代理运行“模拟”,例如这个,其中两个代理添加了问候语块。它运行时不会打印任何内容,也不会抛出任何异常:
const alice = createAgent();
const bob = createAgent();
alice.addAgent(bob);
bob.addAgent(alice);
alice.addData("Hello Bob! -Alice");
bob.addData("Hello Alice! -Bob");
或者在这个“模拟”中,我们尝试将恶意区块注入区块链,但它被捕获了:
const alice = createAgent();
const data = "bad things";
const prev = hashOf("");
alice.receiveBlock({
data,
prev,
token: "",
hash: hashOf(data + prev),
});
// error: Uncaught Error: Hash does not start with the magic prefix
那么...就这样吗?
是的,从本质上讲,区块链并没有比这更多的东西。但为了从这里开始构建一个真正的加密货币,你可能需要
- 用签名和时间戳的交易替换字符串数据有效负载
- 寻找补偿矿工劳动的方法
- 构建p2p网络层
- 让人们相信这种加密货币具有价值
- ETC
TL;DR 通常来说,区块链本身并不难,而其周围的事物才是难点
文章来源:https://dev.to/ninofiliu/writing-a-blockchain-in-60-readed-lines-of-typescript-1009