引入钱包,账户地址,公私钥
bash
# 导入椭圆曲线算法
from ecdsa import SigningKey, SECP256k1, VerifyingKey, BadSignatureError
import binascii
import base64
from hashlib import sha256
class Wallet:
"""
钱包
"""
def __init__(self):
"""
钱包初始化时基于椭圆曲线生成一个唯一的秘钥对,代表区块链上一个唯一的账户
"""
self._private_key = SigningKey.generate(curve=SECP256k1) #私钥 签名
self._public_key = self._private_key.get_verifying_key() #公钥 验证
@property #通过 @property 装饰器,可以直接通过方法名来访问方法,不需要在方法名后添加一对"()"小括号。
def address(self):
"""
这里通过公钥生成地址
base64.b64encode()将bytes类型数据进行base64编码,返回编码后的bytes类型
base64.b64deocde()将base64编码的bytes类型进行解码,返回解码后的bytes类型、
常见于网址url加密中
"""
h = sha256(self._public_key.to_pem())
return base64.b64encode(h.digest()) #返回16进制sha256哈希加密后的哈希值并对其进行编码
@property
def pubkey(self):
"""
返回公钥字符串
"""
return self._public_key.to_pem()
def sign(self, message):
"""
生成数字签名
"""
h = sha256(message.encode('utf8'))
return binascii.hexlify(self._private_key.sign(h.digest())) #二进制输出
def verify_sign(pubkey, message, signature):
"""
验证签名
"""
verifier = VerifyingKey.from_pem(pubkey)
h = sha256(message.encode('utf8'))
return verifier.verify(binascii.unhexlify(signature), h.digest())
bash
# 新建一个钱包
w = Wallet()
bash
# 打印钱包地址
w.address
bash
# 打印钱包公钥
w.pubkey
bash
# 测试数据
data = "交易数据"
bash
# 生成签名
sig = w.sign(data)
# 打印签名
print(sig)
bash
# 验证签名
verify_sign(w.pubkey, data, sig)
bash
import json
class Transaction:
"""
交易的结构
"""
def __init__(self, sender, recipient, amount):
"""
初始化交易,设置交易的发送方、接收方和交易数量
"""
if isinstance(sender, bytes):
sender = sender.decode('utf-8')
self.sender = sender # 发送方
if isinstance(recipient, bytes):
recipient = recipient.decode('utf-8')
self.recipient = recipient # 接收方
self.amount = amount # 交易数量
def set_sign(self, signature, pubkey):
"""
为了便于验证这个交易的可靠性,需要发送方输入他的公钥和签名
"""
self.signature = signature # 签名
self.pubkey = pubkey # 发送方公钥 提供给验证者和接收方用来验证交易
def __repr__(self):
"""
交易大致可分为两种,一是挖矿所得,而是转账交易
挖矿所得无发送方,以此进行区分显示不同内容
"""
if self.sender: #发送方不为空,则是转账交易
s = "从 %s 转至 %s %d个加密货币" % (self.sender, self.recipient, self.amount)
else: #否则是挖矿所得
s = "%s 挖矿获取%d个加密货币" % (self.recipient, self.amount)
return s
class TransactionEncoder(json.JSONEncoder):
"""
定义Json的编码类,用来序列化Transaction
"""
def default(self, obj):
if isinstance(obj, Transaction):
return obj.__dict__
else:
return json.JSONEncoder.default(self, obj)
`import hashlib
from datetime import datetime
class Block:
"""
区块结构
prev_hash: 父区块哈希值
transactions: 交易列表
timestamp: 区块创建时间
hash: 区块哈希值
Nonce: 随机数
"""
def init (self, transactions, prev_hash):
将传入的父哈希值和数据保存到类变量中
self.prev_hash = prev_hash
self.transactions = transactions
获取当前时间
self.timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
# 设置Nonce和哈希的初始值为None
self.nonce = None
self.hash = None
def __repr__(self):
return "区块内容:%s\n哈希值: %s" % (json.dumps(self.transactions), self.hash)`
bash
class ProofOfWork:
"""
工作量证明
简化为一个挖矿者,只要挖矿就一定能挖到,只是时间问题
"""
def __init__(self, block, miner, difficult=5):
self.block = block
# 定义工作量难度,默认为5,表示有效的哈希值以5个"0"开头
self.difficulty = difficult
self.miner = miner
# 添加挖矿奖励
self.reward_amount = 1 #奖励一个加密货币
def mine(self):
"""
挖矿函数
"""
i = 0 #初始化随机值
prefix = '0' * self.difficulty #设置难度
# 添加奖励 新建挖矿交易
t = Transaction(
sender="",
recipient=self.miner.address,
amount=self.reward_amount,
)
sig = self.miner.sign(json.dumps(t, cls=TransactionEncoder)) #钱包类中的账户使私钥签名
t.set_sign(sig, self.miner.pubkey) #发送签名和公钥
self.block.transactions.append(t) #将交易添加到区块链中交易列表中
while True:
message = hashlib.sha256()
message.update(str(self.block.prev_hash).encode('utf-8'))
# 更新区块中的交易数据
# message.update(str(self.block.data).encode('utf-8'))
message.update(str(self.block.transactions).encode('utf-8'))
message.update(str(self.block.timestamp).encode('utf-8'))
message.update(str(i).encode("utf-8"))
digest = message.hexdigest()
if digest.startswith(prefix):
self.block.nonce = i
self.block.hash = digest
return self.block
i += 1
def validate(self):
"""
验证有效性
"""
message = hashlib.sha256()
#四句话将区块各个参数进行哈希运算
message.update(str(self.block.prev_hash).encode('utf-8'))
# 更新区块中的交易数据
# message.update(str(self.block.data).encode('utf-8'))
message.update(json.dumps(self.block.transactions).encode('utf-8'))
message.update(str(self.block.timestamp).encode('utf-8'))
message.update(str(self.block.nonce).encode('utf-8'))
digest = message.hexdigest() #16进制输出hash值
prefix = '0' * self.difficulty
return digest.startswith(prefix) #验证是否为符合难度的哈希值
bash
class BlockChain:
"""
区块链结构体
blocks: 包含的区块列表
"""
def __init__(self):
self.blocks = []
def add_block(self, block):
"""
添加区块
"""
self.blocks.append(block)
def print_list(self):
print("区块链包含区块个数: %d\n" % len(self.blocks))
for block in self.blocks:
print("上个区块哈希:%s" % block.prev_hash)
print("区块内容:%s" % block.transactions)
print("区块哈希:%s" % block.hash)
print("\n")
bash
def get_balance(user):
balance = 0
for block in blockchain.blocks:
for t in block.transactions:
if t.sender == user.address.decode():
balance -= t.amount
elif t.recipient == user.address.decode():
balance += t.amount
return balance
bash
# 初始化区块链
blockchain = BlockChain()
# 创建三个钱包,一个属于alice,一个属于tom,剩下一个属于bob
alice = Wallet()
tom = Wallet()
bob = Wallet()
# 打印当前钱包情况
print("alice: %d个加密货币" % (get_balance(alice)))
print("tom: %d个加密货币" % (get_balance(tom)))
print("bob: %d个加密货币" % (get_balance(bob)))
bash
# alice生成创世区块,并添加到区块链中
new_block1 = Block(transactions=[], prev_hash="")
w1 = ProofOfWork(new_block1, alice)
genesis_block = w1.mine()
blockchain.add_block(genesis_block)
bash
# 显示alice当前余额
print("alice: %d个加密货币" % (get_balance(alice)))
bash
# alice 转账给 tom 0.3个加密货币
transactions = []
new_transaction = Transaction(
sender=alice.address,
recipient=tom.address,
amount=0.3
)
sig = tom.sign(str(new_transaction)) #私钥签名
new_transaction.set_sign(sig, tom.pubkey) #发送签名和公钥
bash
# bob 在网络上接收到这笔交易,进行验证没问题后生成一个新的区块并添加到区块链中
if verify_sign(new_transaction.pubkey,
str(new_transaction),
new_transaction.signature): #验证者验证
# 验证交易签名没问题,生成一个新的区块
print("验证交易成功")
new_block2 = Block(transactions=[new_transaction], prev_hash="")
print("生成新的区块...")
w2 = ProofOfWork(new_block2, bob)
block = w2.mine() #bob挖矿,找到新的区块将其写入区块链
print("将新区块添加到区块链中")
blockchain.add_block(block)
else:
print("交易验证失败!")
# 打印当前钱包情况 print("alice: %.1f个加密货币" % (get_balance(alice))) print("tom: %.1f个加密货币" % (get_balance(tom))) print("bob: %d个加密货币" % (get_balance(bob)))