引入钱包,账户地址,公私钥
# 导入椭圆曲线算法
from ecdsa import SigningKey, SECP256k1, VerifyingKey, BadSignatureError
import binascii
import base64
from hashlib import sha256class 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哈希加密后的哈希值并对其进行编码@propertydef 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())
# 新建一个钱包w = Wallet()
# 打印钱包地址
w.address
# 打印钱包公钥w.pubkey
# 测试数据data = "交易数据"
# 生成签名sig = w.sign(data)# 打印签名
print(sig)
# 验证签名verify_sign(w.pubkey, data, sig)
import jsonclass 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 sclass 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和哈希的初始值为Noneself.nonce = Noneself.hash = Nonedef __repr__(self):return "区块内容:%s\n哈希值: %s" % (json.dumps(self.transactions), self.hash)`
class ProofOfWork:"""工作量证明简化为一个挖矿者,只要挖矿就一定能挖到,只是时间问题"""def __init__(self, block, miner, difficult=5):self.block = block# 定义工作量难度,默认为5,表示有效的哈希值以5个“0”开头self.difficulty = difficultself.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 = iself.block.hash = digestreturn self.blocki += 1def 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.difficultyreturn digest.startswith(prefix) #验证是否为符合难度的哈希值
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")
def get_balance(user):balance = 0for block in blockchain.blocks:for t in block.transactions:if t.sender == user.address.decode():balance -= t.amountelif t.recipient == user.address.decode():balance += t.amountreturn balance
# 初始化区块链
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)))
# alice生成创世区块,并添加到区块链中new_block1 = Block(transactions=[], prev_hash="")
w1 = ProofOfWork(new_block1, alice)
genesis_block = w1.mine()
blockchain.add_block(genesis_block)
# 显示alice当前余额print("alice: %d个加密货币" % (get_balance(alice)))
# 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) #发送签名和公钥
# 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)))