其实区块链这个东西,一直说得多火热,从比特币什么开始,就有这么一说,实际上,区块链不等于比特币,这里介绍得区块链也不能用于盈利,只是一个概念介绍,让你知道,何为区块链,实际上,区块链用途很广,电子合同验证应该是最广泛用途了,区块链由于是链式储存,想毁掉中间某个区块难度非常大,因为验算难度低,计算难度高,可以说是一人之力,推翻一切.
我不写代码,但是可以从前人的代码中得到实践,这个项目就是:https://github.com/dvf/blockchain
(其实我是因为看到这个项目,特地来写这篇东西的,算是自己的笔记.)
首先,一个区块应长什么样子,这里随便举个例子.
{ "index": 100, "previous_hash": "775cb2c329f33aef0d7cc74055be6faf41fc154efb67a541af55840736012ed8", "proof": 52202, "timestamp": 1569852153.8177216, "transactions": [ { "amount": 1, "recipient": "5bc02d1e9be645519afd3711056af559", "sender": "6af93232e71bcbe3833d140ec94195f3" } ] }
index => 区块号
previous_hash => 上一个hash,这就是链接的关键.
proof => 工作量凭证,其实是增加挖矿难度(其实不需要极高增加难度,并不一定就能增加安全性,但是破解时候需要填充这些proof)
timestamp => 时间戳
transactions => 交易信息(当然,里面是信息是可以随便定义的,不一定要长这样,也可以是份PDF二进制什么都行,这里举例的刚好只是个金额交易的简单系统.)
transactions.sender => 举例的发送者
transactions.recipient => 举例的接收者
transactions.amount => 举例的交易金额
看到示例的Python脚本里面,这么新建一个区块.
在函数new_transaction中向列表中添加一笔交易之后,它返回值是本次交易的index,该index会被添加到下一个待挖掘区块,后面在用户提交交易时也会用到,挖的时候就会把上一级区块hash提取出来,附上本区块信息,作为新区块,意味着,越是往后区块,越容易被破解篡改拉~
def new_block(self, proof, previous_hash): """ Create a new Block in the Blockchain :param proof: The proof given by the Proof of Work algorithm :param previous_hash: Hash of previous Block :return: New Block """ block = { 'index': len(self.chain) + 1, 'timestamp': time(), 'transactions': self.current_transactions, 'proof': proof, 'previous_hash': previous_hash or self.hash(self.chain[-1]), } # Reset the current list of transactions self.current_transactions = [] self.chain.append(block) return block def new_transaction(self, sender, recipient, amount): """ Creates a new transaction to go into the next mined Block :param sender: Address of the Sender :param recipient: Address of the Recipient :param amount: Amount :return: The index of the Block that will hold this transaction """ self.current_transactions.append({ 'sender': sender, 'recipient': recipient, 'amount': amount, }) return self.last_block['index'] + 1
在代码一开始,创建的第一个区块(这条链的第一个区块),后续的每一个区块,都依赖此区块.
self.new_block(previous_hash='1', proof=100)
下面就到POW,在说明POW之前,先说说怎么破解一个区块链.
比如下面有一条链,Hash如下:
b3d6 -> 6569 -> 35b3 -> de9e -> 0add -> 4ab0 -> 65b4 -> 22e8
现在你想破坏第三个数据,目前第三个数据计算出hash是35b3,你数据破坏后,计算出是55b4,由于第四个数据,de9e所在区块包含35b3的信息,所以你要重算de9e这个区块的实际hash,可能变成了d466,要想完美破解,必须推翻到链最后.
那计算下一个块的Hash有多难,如果计算需要1秒,推翻一条10个数据的链,需要10秒完成,如此类推.当然,不建议把推翻难度无限提高,首先我们不是为了浪费机器算力,我们只是用来保证交易信息,选择一个合适的阈值就行了,我们不是用来挖什么赚钱虚拟币,区块链的正途,是用来验证信息而不是搞什么交易虚拟币的.
话说回来,POW是一种简便的,增加运算能力,提高破解难度的方法.比特币里叫他Hashcash,我这里就叫他增加破解难度的%^#$%^$的算法好了.
比如这个算法里面,必须计算一个hash(x * y) = ........0000,x是已知,y是待求(还不如叫待猜),使得hash末尾是0000(4条0).
def proof_of_work(self, last_block): """ Simple Proof of Work Algorithm: - Find a number p' such that hash(pp') contains leading 4 zeroes - Where p is the previous proof, and p' is the new proof :param last_block: <dict> last Block :return: <int> """ last_proof = last_block['proof'] last_hash = self.hash(last_block) proof = 0 while self.valid_proof(last_proof, proof, last_hash) is False: proof += 1 return proof @staticmethod def valid_proof(last_proof, proof, last_hash): """ Validates the Proof :param last_proof: <int> Previous Proof :param proof: <int> Current Proof :param last_hash: <str> The hash of the Previous Block :return: <bool> True if correct, False if not. """ guess = f'{last_proof}{proof}{last_hash}'.encode() guess_hash = hashlib.sha256(guess).hexdigest() return guess_hash[:4] == "0000"
这个算法的巧妙之处在于,想找到这样的y很困难(不知道多少次hash),但是想验证这个y对不对,只要一次hash.上述演示代码中.
把{last_proof}{proof}{last_hash}链接一起.其中last_proof和last_hash是上一个区块的.所以,需要破解的人,同样需要解决这个区块的proof,想想就很费力.
到现在,这条链上,既有工作量,又满足了区块链的特性.算是初步完成,那么,就得来验证,幸运的是,这个程序,竟然还做了API,简直是太方便了.
安装这个代码很简单,把代码git clone下来,然后切换到他的目录里,用pipenv install就可以了,注意Python版本不能太低,当然不一定是Python 3.6~
然后按照他说的用这样方法,指定端口启动,完事.
pipenv run python blockchain.py -p 5001
API举例(你要自己替换成你自己IP哈):
- POST http://127.0.0.1:5001/transactions/new 创建新交易
- GET http://127.0.0.1:5001/mine 挖一个区块
- GET http://127.0.0.1:5001/chain 读取整条区块链
- POST http://127.0.0.1:5001/nodes/register 注册新挖矿者(毕竟不止一个人记账的话,破解难度更大,除非你去把他们的账本都改了.)
- GET http://127.0.0.1:5001/nodes/resolve 同步挖矿者
建议下载个POSTMAN测试,只有需要POST的API,才会携带数据,数据都是JSON数据.
创建交易示例.
{ "sender": "720fb6b46da04400a21556fbccec6cd4", "recipient": "5bc02d1e9be645519afd3711056af559", "amount": 5 }
创建节点关联:
{ "nodes": ["http://127.0.0.1:5002"] }
下面创建一个交易.
接下来挖一下这个块.
然后获取链上所有数据.
返回结果包含2个结果,目前链上就是2个结果.
{ "chain": [ { "index": 1, "previous_hash": "1", "proof": 100, "timestamp": 1569856786.486463, "transactions": [] }, { "index": 2, "previous_hash": "ebf45554844b4df3d2cded78c8a96e79a939c9a6578c77896b59989c5e9ab017", "proof": 43956, "timestamp": 1569856951.0676649, "transactions": [ { "amount": 5, "recipient": "5bc02d1e9be645519afd3711056af559", "sender": "720fb6b46da04400a21556fbccec6cd4" }, { "amount": 1, "recipient": "1c8c93ea836d4edc887bb2d6d8de0867", "sender": "0" } ] } ], "length": 2 }
比如我挖出一条比较长的链. {last_proof}{proof}{last_hash} 132739 132141 7f35e5f292fc453df2cf082fda30196ec4b31e398e35b2dca8586c21d06ac333
{ "index": 13, "previous_hash": "7f35e5f292fc453df2cf082fda30196ec4b31e398e35b2dca8586c21d06ac333", "proof": 132739, "timestamp": 1569857231.1991785, "transactions": [ { "amount": 1, "recipient": "1c8c93ea836d4edc887bb2d6d8de0867", "sender": "0" } ] }, { "index": 14, "previous_hash": "ba273eb96abcd4ff0089eced2716edbeff040ba193ba5c920cf77830f7c8e688", "proof": 132141, "timestamp": 1569857232.3286073, "transactions": [ { "amount": 1, "recipient": "1c8c93ea836d4edc887bb2d6d8de0867", "sender": "0" } ] }, { "index": 15, "previous_hash": "82a683554c5d99ab2da48138b9984817ee1849a972d5b4764670e50c5a0cf88d", "proof": 107165, "timestamp": 1569857233.110304, "transactions": [ { "amount": 1, "recipient": "1c8c93ea836d4edc887bb2d6d8de0867", "sender": "0" } ] }
比如我验证14区块对不对,我们用15区块来做的话,首先,14区块的proof是132141,15区块的proof是107165,上一个hash是82a683554c5d99ab2da48138b9984817ee1849a972d5b4764670e50c5a0cf88d,那么这个验证hash原文是13214110716582a683554c5d99ab2da48138b9984817ee1849a972d5b4764670e50c5a0cf88d,密文是0000d7916d02aa408758f3a05cc6d3bf6c8ca6fbb782fbde3b5d82eaa930f4a4,前面4个是0,满足计算,所以这是有效的.如这种情况需要破坏14区块,计算发现15区块写的previous_hash不符合14区块当前内容的摘要,失败.
如果15区块还没产生,验证14区块,则需要满足刚才说的proof链接字符串后,hash有4个0在前面,用13区块的全部内容的摘要+13区块的proof+14区块的proof满足要求,但是这个修改起来太容易,所以一般是用后面数据校验前面.你这个块虽然是合法块,但是要做到不可篡改,还需要更多的块.
在这里,大家应该明白,越长越难破解了.
现在引入一个新的风险,就是假设,有人就是有这样超级牛逼的机器,甚至他修改算法,入侵到你的机器,随便改数据都是合法的,那么怎么办?
那就多个机器呗,我们可以继续用这个程序,用别的端口创建.
比如我现在有2台假想的机器.
- http://127.0.0.1:5001/
- http://127.0.0.1:5002/
端口5001机器已经挖到32长度,5002是后加入,于是使用加入API,加入一台机器,同理,5002也应该加入5001.
就像我们应该维护一个机器列表.
这时候,我们用/nodes/resolve的API,来尝试同步,假设,我现在用的是机器5001,这个明显更长链,他同步的话,应该自己就是大佬(最有话语权的人,有效数据最多.)
但是如果更少数据的人去做这个同步,则需要跟大佬同步.
维护一个总表,每个人都都需要定期同步,则变成分布式了.
另外这里要说几句:
- 区块链不是挖矿,挖矿虚拟货币什么是不受国家承认的,耗费算力究竟得到了什么?又是否有必要如此耗费呢?
- 区块链的应用,用于验证数据等,至于分叉机制什么的,自行再探讨就是,这文章中算是最简单地说明什么是区块链了.
- 因为有人把区块链和货币划等号,才有了矿机什么的,实际上,我们只需要自己的验证基础的话,不产生所谓的各种币,谁来给我挖了?为什么我要全世界数万台机器给我来验证,难道我部署全球三四百台私有点,不一样很安全,至少,我的验证代码是我自己的,首先你得知道哪些机器正在运算区块链,并且都能一一攻破.
- 各云计算公司都提供区块链云,腾讯云阿里云Azure亚马逊什么什么的,都是需要付钱的,目的是创建一个可靠的区块链网络,而非挖矿赚币.
- 区块链合法,各种币灰色,不要沉迷区块链认为是赚钱路子,区块链只是个技术,虚拟币不应作为赚钱路子,当然,投机取巧除外.
- 本文不适合讨论各种加密货币,特此声明.