当前位置:首页 > 物联网 > 区块链
[导读] PBFT的数学证明 在实际的拜占庭容错中,如果N = 3F + 1,N个节点的系统可以容忍F个故障节点。 实际拜占庭容错系统中的每个决策都需要2F + 1批准,其中Fare是故障

PBFT的数学证明

在实际的拜占庭容错中,如果N = 3F + 1,N个节点的系统可以容忍F个故障节点。

实际拜占庭容错系统中的每个决策都需要2F + 1批准,其中Fare是故障节点。

我们现在将在数学上证明上述两个定义,它们是彼此的推论。以下计算是斯坦福大学笔记中数学的简化。

分布式系统的两个重要特性是活跃性和安全性。

活跃性

活跃性是系统继续运行时在分布式系统环境中使用的术语。这意味着即使出现一些错误,系统也不会停止运行。在区块链的情况下,活跃意味着系统将继续向链中添加新的区块,并且在任何时候系统都不会停止工作。

安全性

当系统收敛于单个决策时,安全性是分布式系统环境中使用的术语。在分布式系统中,节点可能会分成两个决策或进一步拆分,分布式系统的安全性确保了即使存在故障节点,网络也会在所有可靠节点上以单个决策结束。

证明

非拜占庭式故障

给定网络中的N个节点,具有f个故障节点,保证活跃性和安全性所需的仲裁大小Q是多少?

仲裁定义为网络正常运行和做出有效决策所需的最小节点数。仲裁由诚实的节点组成。

活跃度

为了避免网络停止,必须至少存在一个非故障节点。因此,为了活跃度:

Q 《= N - f

安全度

为了避免网络分裂成多个决策,大多数决策者应该在线。我们需要一个诚实的多数,仲裁大小应该大于节点总数的一半,以便我们做出有利于我们的决定。

因此,为了安全:

Q 》 N/2

2Q - N 》 0

通过梳理我们得到的两个条件,

N 《 2Q 《=2(N-f)

f 《 N/2

N 》 2f

因此,对于非拜占庭式故障

拜占庭式故障

假设网络中有n个节点,其中f个故障节点可能会遇到拜占庭式故障,那么要保证活跃性和安全性,需要多少仲裁大小Q?

遭受拜占庭式失败的节点可以投票给无效的区块或决策,导致决策中的分裂,并因此分叉。

活跃度

为了避免网络停止,必须存在至少一个非故障节点或仲裁。由于拜占庭节点可能无法回复。

因此,为了活跃度:

Q 《= N - f

安全性

为了避免网络分裂成多个决策,大多数决策者应该在线。然而,与非拜占庭式失败不同,拜占庭式失败中的节点也可以投票,因此我们需要在投票过程中考虑故障节点。

Q 》 N/2

2Q - N 》 0

此公式提供了网络中可能存在的最大失败节点数。

因此,为了安全起见,也可以将其写为:

2Q - N 》 f

其中f是可容忍故障节点的最大数量。

把这两个条件结合起来

N + f 《 2Q 《 2(N - f)

N + f 《 2N - 2f

3f 《 N

N 》 3f

if N = 3f + 1

then 2Q 》 4f + 1

or

Q 》 2f + 1/2

因此,对于拜占庭式的失败

Qmin = 3f + 1

node.js中实现PBFT

在本节中,我们将实现一个以PBFT为共识算法的区块链。值得注意的是,该区块链不会使用加密货币,但如果我们使用账户模型,则可以使用。此外,由于PBFT易受Sybil攻击,因此只能在许可的环境下运行,因此需要了解网络成员。

先决条件

· Node.js

· Postman

· VS code

架构与设计

为了实施PBFT,我们将开发以下组件:

1. 钱包类 - 用于公钥和签名数据。

2. 事务类 - 创建事务并验证它们。

3. 区块类 - 创建区块,验证块并验证区块的提议者。

4. 区块链类 - 创建链,添加区块,计算提议者,验证区块,更新区块。

5. P2p Server类 - 在对等体之间广播和接收数据。

6. 验证者 - 生成并验证验证者

7. 事务池,区块池,提交池,准备池和消息池 - 分别存储事务,区块,提交,准备和新轮消息。

8. App - 用于与区块链交互的Express API

9. 配置 - 存储全局变量

10. Chain UtiliTIes - 用于存储散列和验证签名等常用功能。

创建一个根目录pbft并将其cd入其中。此项目中的所有文件都存在于根目录中。

mkdir pbft && cd pbft

ChainUTIl类

我们将从创建一个chain-uTIl.js文件开始,该文件将在此项目中多次使用。此文件将用于创建用于签名数据的密钥对,为事务生成ID,散列数据和验证签名。

我们需要三个模块来执行这些功能。因此我们需要安装它们。

npm i --save ellipTIc uuid crypto-js

创建一个ChainUtil类并将其导出。

// EDDSA allows us to create keypairs

// It is collection of cryptographic algorithms that are used to create keypairs

const EDDSA = require(“elliptic”).eddsa;

// ed25519 allows us to create key pair from secret

const eddsa = new EDDSA(“ed25519”);

// uuid/v1 creates timestamp dependent ids

const uuidV1 = require(“uuid/v1”);

// used for hashing data to 256 bits string

const SHA256 = require(“crypto-js/sha256”);

class ChainUtil {

// a static function to return keypair generated using a secret phrase

static genKeyPair(secret) {

return eddsa.keyFromSecret(secret);

}

// returns ids used in transactions

static id() {

return uuidV1();

}

// hashes any data using SHA256

static hash(data) {

return SHA256(JSON.stringify(data)).toString();

}

// verifies the signed hash by decrypting it with public key

// and matching it with the hash

static verifySignature(publicKey, signature, dataHash) {

return eddsa.keyFromPublic(publicKey).verify(dataHash, signature);

}

}

module.exports = ChainUtil;

pbft_chain_util.js

事务类

接下来,我们将创建一个事务类。在项目文件夹中创建文件transaction.js。此项目中的事务将包含以下属性:

· id - 用于识别

· from - 发件人的地址

· input - 一个进一步包含要存储的数据和时间戳的对象

· hash - 输入的SHA256

· signature - 发件人签名的哈希

在文件中创建一个类Transaction并将其导出。

// Import the ChainUtil class used for hashing and verification

const ChainUtil = require(“。/chain-util”);

class Transaction {

// the wallet instance will be passed as a parameter to the constructor

// along with the data to be stored.

constructor(data, wallet) {

this.id = ChainUtil.id();

this.from = wallet.publicKey;

this.input = { data: data, timestamp: Date.now() };

this.hash = ChainUtil.hash(this.input);

this.signature = wallet.sign(this.hash);

}

// this method verifies wether the transaction is valid

static verifyTransaction(transaction) {

return ChainUtil.verifySignature(

transaction.from,

transaction.signature,

ChainUtil.hash(transaction.input)

);

}

}

module.exports = Transaction;

pbft-transaction.js

钱包类

接下来是钱包。钱包持有公钥和密钥对。它还负责签署数据哈希并创建签名事务。

在项目目录中创建文件wallet.js。添加一个类Wallet并将其导出。

// Import the ChainUtil class used for hashing and verification

const ChainUtil = require(“。/chain-util”);

// Import transaction class used for creating transactions

const Transaction = require(“。/transaction”);

class Wallet {

// The secret phase is passed an argument when creating a wallet

// The keypair generated for a secret phrase is always the same

constructor(secret) {

this.keyPair = ChainUtil.genKeyPair(secret);

this.publicKey = this.keyPair.getPublic(“hex”);

}

// Used for prining the wallet details

toString() {

return `Wallet -

publicKey: ${this.publicKey.toString()}`;

}

// Used for signing data hashes

sign(dataHash) {

return this.keyPair.sign(dataHash).toHex();

}

// Creates and returns transactions

createTransaction(data) {

return new Transaction(data, this);

}

// Return public key

getPublicKey() {

return this.publicKey;

}

}

module.exports = Wallet;

pbft-wallet.js

验证者类

由于PBFT是一种许可的区块链一致性算法,我们需要存储每个节点系统中所有节点的地址。我们可以通过选择一个密钥,创建一个钱包,获取其公钥并将该密钥存储到一个文件中来手动执行此操作。当我们运行我们的项目时,它会读取此文件以获取密钥。

但是,不是手动执行此操作,我们可以通过创建类并添加可以返回N个节点的公钥列表的函数来自动执行此操作。

我们将创建一个Validator类,它将生成每个节点都知道的公钥列表。在这个项目中,我们使用了每个节点的密码短语

NODE1,NODE2,NODE3 。..。..

这样,我们就可以更容易地创建公钥列表,并使用相同的公钥从命令行创建节点。

// Import the wallet class

const Wallet = require(“。/wallet”);

class Validators {

// constructor will take an argument which is the number of nodes in the network

constructor(numberOfValidators) {

this.list = this.generateAddresses(numberOfValidators);

}

// This function generates wallets and their public key

// The secret key has been known for demonstration purposes

// Secret will be passed from command line to generate the same wallet again

// As a result the same public key will be generatedd

generateAddresses(numberOfValidators) {

let list = [];

for (let i = 0; i 《 numberOfValidators; i++) {

list.push(new Wallet(“NODE” + i).getPublicKey());

}

return list;

}

// This function verfies if the passed public key is a known validator or not

isValidValidator(validator) {

return this.list.includes(validator);

}

}

module.exports = Validators;

注意:密钥不应该公开。只有在演示中我们才使用这样的密钥。在实际项目中,发送注册请求以使节点成为验证者。如果整个网络批准此请求,则该节点将成为验证者,并将公钥添加到列表中。

Config.js文件

网络中的验证者数量可以通过命令行传递,但更容易将其存储在文件中并在需要的地方导入。

创建一个文件config.js并创建三个变量NUMBER_OF_NODES,MIN_APPROVALS和TRANSACTION_THRESHOLD

// Maximum number of transactions that can be present in a block and transaction pool

const TRANSACTION_THRESHOLD = 5;

// total number of nodes in the network

const NUMBER_OF_NODES = 3;

// Minmu number of positive votes required for the message/block to be valid

const MIN_APPROVALS = 2 * (NUMBER_OF_NODES / 3) + 1;

module.exports = {

TRANSACTION_THRESHOLD,

NUMBER_OF_NODES,

MIN_APPROVALS

};

PBFT-config.js

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: 驱动电源

在工业自动化蓬勃发展的当下,工业电机作为核心动力设备,其驱动电源的性能直接关系到整个系统的稳定性和可靠性。其中,反电动势抑制与过流保护是驱动电源设计中至关重要的两个环节,集成化方案的设计成为提升电机驱动性能的关键。

关键字: 工业电机 驱动电源

LED 驱动电源作为 LED 照明系统的 “心脏”,其稳定性直接决定了整个照明设备的使用寿命。然而,在实际应用中,LED 驱动电源易损坏的问题却十分常见,不仅增加了维护成本,还影响了用户体验。要解决这一问题,需从设计、生...

关键字: 驱动电源 照明系统 散热

根据LED驱动电源的公式,电感内电流波动大小和电感值成反比,输出纹波和输出电容值成反比。所以加大电感值和输出电容值可以减小纹波。

关键字: LED 设计 驱动电源

电动汽车(EV)作为新能源汽车的重要代表,正逐渐成为全球汽车产业的重要发展方向。电动汽车的核心技术之一是电机驱动控制系统,而绝缘栅双极型晶体管(IGBT)作为电机驱动系统中的关键元件,其性能直接影响到电动汽车的动力性能和...

关键字: 电动汽车 新能源 驱动电源

在现代城市建设中,街道及停车场照明作为基础设施的重要组成部分,其质量和效率直接关系到城市的公共安全、居民生活质量和能源利用效率。随着科技的进步,高亮度白光发光二极管(LED)因其独特的优势逐渐取代传统光源,成为大功率区域...

关键字: 发光二极管 驱动电源 LED

LED通用照明设计工程师会遇到许多挑战,如功率密度、功率因数校正(PFC)、空间受限和可靠性等。

关键字: LED 驱动电源 功率因数校正

在LED照明技术日益普及的今天,LED驱动电源的电磁干扰(EMI)问题成为了一个不可忽视的挑战。电磁干扰不仅会影响LED灯具的正常工作,还可能对周围电子设备造成不利影响,甚至引发系统故障。因此,采取有效的硬件措施来解决L...

关键字: LED照明技术 电磁干扰 驱动电源

开关电源具有效率高的特性,而且开关电源的变压器体积比串联稳压型电源的要小得多,电源电路比较整洁,整机重量也有所下降,所以,现在的LED驱动电源

关键字: LED 驱动电源 开关电源

LED驱动电源是把电源供应转换为特定的电压电流以驱动LED发光的电压转换器,通常情况下:LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: LED 隧道灯 驱动电源
关闭