In my opinion, Bitcoin is the real-life V for Vendetta. Of course, the reality is a more cruel world government. This game concerns human civilization, politics, social attributes, economy and human rights. IBM Hyperledger is also called fabric. You can think of it as a super ledger maintained by the whole society. There is no central authority holding power. Every transaction you make is open and secure to the whole network, and the credit is witnessed by the whole society. Its relationship with Bitcoin is that you can use fabric to build an application called Bitcoin to help you change the world. The vision is so awesome, and it seems to be just what we want to change the world. However, we are always naive in front of the cruel reality and the world. Blockchain needs to build its grand blueprint step by step. At least there is no case of using it in industrial production and national economy. Fabric originated from IBM. The original intention was to serve industrial production. IBM made 44,000 lines of code open source, which is a great contribution. It gives us the opportunity to explore the principles of blockchain so closely. But after all, IBM is based on its own interests and the interests of its customers. It is not doing this public welfare without purpose. When we look at fabric, we must have a prudent mindset: blockchain does not have to be like this. What is the most essential non-technical difference between it and Bitcoin? Let's first take a general look at the key terms of fabric (because some words are more accurate in English, I will not translate them). 1. Terminology
2. ArchitectureThere are three core logics of the architecture: Membership, Blockchain and Chaincode. 2.1 Membership ServicesThis service is used to manage node identity, privacy, confidentiality and auditability. In a non-permissioned blockchain network, participants do not require authorization, and all nodes are treated the same and can submit a transaction and store these transactions in blocks. The Membership Service is to transform a non-permissioned blockchain network into a permissioned blockchain network, relying on Public Key Infrastructure (PKI), decentralization and consistency. 2.2 Blockchain ServicesBlockchain services use a P2P protocol built on HTTP/2 to manage distributed ledgers. Provide the most efficient hashing algorithm to maintain a copy of the world state. Take a pluggable approach to set consensus protocols according to specific needs, such as PBFT, Raft, PoW, PoS, etc. 2.3 Chaincode ServicesChaincode services will provide a safe and lightweight sandbox operation mode to execute chaincode logic on VP nodes. Here, a container environment is used, and the base images in it are all signature-verified secure images, including the OS layer and the language, runtime, and SDK layer for developing chaincode. Currently, Go, Jave, and Nodejs development languages are supported. 2.4 EventsIn the blockchain network, VP nodes and chaincodes will send events to trigger some monitoring actions. For example, chaincode is user code, which can generate user events. 2.5 API and CLIProvides REST APIs that allow registering users, querying the blockchain, and sending transactions. Some chaincode-specific APIs can be used to execute transactions and query transaction results. For developers, CLI can be used to quickly test chaincode or query transaction status. 3. Topology The topology of distributed networks is very worth studying. In this world, there are many participants, different roles, different interest groups, and various situations. The handling of various situations symbolizes the rules and laws in the distributed network. There is no order without rules. In the blockchain network, there are Membership services, VP nodes, NVP nodes, and one or more applications. They form a chain, and then there will be multiple chains, each of which has its own security requirements and operational requirements. 3.1 Single VP Node NetworkThe simplest network contains only one VP node, so the consensus part is omitted. 3.2 Multiple VP Node NetworksA network with multiple VPs and NVPs is valuable and meaningful. NVP nodes share the workload of VP nodes and handle API requests and events. As for VP nodes, a mesh network is formed between VP nodes to propagate information. An NVP node can be connected to a neighboring VP node if allowed. NVP nodes can be omitted if the application can communicate directly with the VP node. 3.3 MultichainThere will also be situations where there are multiple chains in a network, and the intentions of each chain are different. 4. ProtocolFabric uses gRPC for P2P communication, which is a two-way stream message transmission. Protocol Buffer is used to serialize the data structure to be transmitted. 4.1 MessageThere are four types of messages: Discovery, Transaction, Synchronization and Consensus. Each type of message contains more sub-messages, which are indicated by the payload. The payload is an opaque byte array that contains some objects, such as Transaction or Response. For example, if type is CHAIN_TRANSACTION, then the payload is a Transaction object. message Message { enum Type { UNDEFINED = 0; DISC_HELLO = 1; DISC_DISCONNECT = 2; DISC_GET_PEERS = 3; DISC_PEERS = 4; DISC_NEWMSG = 5; CHAIN_STATUS = 6; CHAIN_TRANSACTION = 7; CHAIN_GET_TRANSACTIONS = 8; CHAIN_QUERY = 9; SYNC_GET_BLOCKS = 11; SYNC_BLOCKS = 12; SYNC_BLOCK_ADDED = 13; SYNC_STATE_GET_SNAPSHOT = 14; SYNC_STATE_SNAPSHOT = 15; SYNC_STATE_GET_DELTAS = 16; SYNC_STATE_DELTAS = 17; RESPONSE = 20; CONSENSUS = 21; } Type type = 1; bytes payload = 2; google.protobuf.Timestamp timestamp = 3; } 4.1.1 Discovery MessagesA newly started node, if CORE_PEER_DISCOVERY_ROOTNODE (ROOTNODE refers to the IP of any other node in the network) is specified, it will start running the discovery protocol. ROOTNODE is the first discovery node, and then all nodes in the entire network are discovered through the ROOTNODE node. The discovery protocol message is DISC_HELLO, and its payload is a HelloMessage object, which also contains the information of the node sending the message: message HelloMessage { PeerEndpoint peerEndpoint = 1; uint64 blockNumber = 2; } message PeerEndpoint { PeerID ID = 1; string address = 2; enum Type { UNDEFINED = 0; VALIDATOR = 1; NON_VALIDATOR = 2; } Type type = 3; bytes pkiID = 4; } message PeerID { string name = 1; } If a node receives a DISC_HELLO message and finds that the block height in it is higher than its current block height, it will immediately send a synchronization protocol to synchronize its status with the entire network (mark: but this synchronization logic does not seem to be implemented at the source code level). After the newly joined node completes the DISC_HELLO message transmission, it will periodically send DISC_GET_PEERS to discover other nodes that have joined the network. In response to DISC_GET_PEERS, a node will send DISC_PEERS. 4.1.2 Synchronization Messages The Synchronization protocol starts with the discovery protocol mentioned above. When a node finds that the state of its block is inconsistent with other nodes, it will trigger synchronization. The node will broadcast three types of information: SYNC_GET_BLOCKS, SYNC_STATE_GET_SNAPSHOT or The consensus algorithm currently embedded in fabric is pbft. SYNC_GET_BLOCKS will request a series of consecutive blocks, and the payload in the data structure sent will be a SyncBlockRange object. message SyncBlockRange { uint64 correlationId = 1; uint64 start = 2; uint64 end = 3; } The receiving node will reply with SYNC_BLOCKS, whose payload is a SyncBlocks object: message SyncBlocks { SyncBlockRange range = 1; repeated Block blocks = 2; } start and end represent the starting and ending blocks. For example, start=3, end=5 represents block 3,4,5; start=5, end=3 represents block 5,4,3. SYNC_STATE_GET_SNAPSHOT requests a snapshot of the current world state. The payload of this information is a SyncStateSnapshotRequest object: message SyncStateSnapshotRequest { uint64 correlationId = 1; } The correlationId is used by the requesting peer to track the corresponding reply to the message. The peer that receives the message will reply with SYNC_STATE_SNAPSHOT, whose payload is a SyncStateSnapshot object: message SyncStateSnapshot { bytes delta = 1; uint64 sequence = 2; uint64 blockNumber = 3; SyncStateSnapshotRequest request = 4; }SYNC_STATE_GET_DELTAS By default, the Ledger will contain 500 transition deltas. delta(j) represents the state transition between block(i) and block(j) (i = j -1).
4.1.3 Consensus MessagesThe consensus framework will convert the received CHAIN_TRANSACTION into CONSENSUS and then broadcast it to all VP nodes. 4.1.4 Transaction MessagesThere are three types of transactions in fabric: Deploy, Invoke and Query. Deploy installs the specified chaincode to the chain, and Invoke and Query call the functions of the deployed chaincode. 4.2 LedgerLedger mainly consists of two parts: blockchain and world state. Blockchain is a series of connected blocks used to record historical transactions. World state is a key-value database. When the transaction is executed, the chaincode will store the state in it. 4.2.1 BlockchainA blockchain is a list of blocks, each containing the hash of the previous block. A block also contains a list of transactions and a hash of the world state after all these transactions are executed. message Block { version = 1; google.protobuf.Timestamp timestamp = 2; bytes transactionsHash = 3; bytes stateHash = 4; bytes previousBlockHash = 5; bytes consensusMetadata = 6; NonHashData nonHashData = 7; } message BlockTransactions { repeated transactions = 1; } How is the hash of the previous block calculated?
In the above data structure, there is a transactionHash, which is the root node of the transaction Merkle tree (using Merkle tree to describe these transactions). 4.2.2 World StateThe world state of a peer is the collection of states of all deployed chaincodes. The state of a chaincode is described by a collection of key-value pairs. We expect nodes in the network to have consistent world states, so we will compare them by calculating the crypto-hash of the world state, but this will consume expensive computing power. For this reason, we need to design an efficient calculation method. For example, we can introduce Bucket-tree to implement the organization of the world state. The key in the world state is represented as {chaincodeID, ckey}. We can describe the key as follows: key = chaincodeID+nil+cKey. The key-value of the world state will be stored in a hash table, which consists of a predefined number (numBuckets) of buckets. A hash function will define which bucket contains which key. These buckets will serve as leaf nodes of the merkle-tree, and the bucket with the smallest number will serve as the leftmost leaf node of the merkle-tree. The second-to-last layer is constructed by grouping together maxGroupingAtEachLevel (predefined number) leaf nodes from the left to form N groups. A node will be inserted into each group as the parent node of the leaf nodes it contains, thus forming the second-to-last layer. It should be noted that the parent node of the last layer (the inserted node just described) may have fewer than maxGroupingAtEachLevel child nodes. Continue to build higher layers in this way until the root node is built. For example, {numBuckets=10009 and maxGroupingAtEachLevel=10}, the number of nodes in the tree it forms each time is as follows:
4.3 Consensus FrameworkThe consensus framework consists of three packages: consensus, controller and helper.
There are currently two consensus plugins: pbft and noops. 5. Implementation and contributionImplement SYNC_BLOCK_ADDED handler One of my colleagues implemented a handler for the SYNC_BLOCK_ADDED message so that in noops consensus mode, when a block is added to the (mined/added) ledger, the NVP node can process the message and store the newly added block in its own ledger. The callback corresponding to the SYNC_BLOCK_ADDED message is beforeBlockAdded (core/peer/handler.go). The official code is as follows: func (d *Handler) beforeBlockAdded(e *fsm.Event) { peerLogger.Debugf("Received message: %s", e.Event) msg, ok := e.Args[0].(*pb.Message) if !ok { e.Cancel(fmt.Errorf("Received unexpected message type")) return } // Add the block and any delta state to the ledger _ = msg }There is no way to obtain and process the block information here, we need to add the following: + if ValidatorEnabled() { + e.Cancel(fmt.Errorf("VP shouldn't receive SYNC_BLOCK_ADDED")) + return + } // Add the block and any delta state to the ledger - _ = msg + blockState := &pb.BlockState{} + err := proto.Unmarshal(msg.Payload, blockState) + if err != nil { + e.Cancel(fmt.Errorf("Error unmarshalling BlockState: %s", err)) + return + } + coord := d.Coordinator + blockHeight := coord.GetBlockchainSize() + if blockHeight <= 0 { + e.Cancel(fmt.Errorf("No genesis block is made")) + return + } + curBlock, err := coord.GetBlockByNumber(blockHeight -1) + if err != nil { + e.Cancel(fmt.Errorf("Error fetching block #%d, %s", blockHeight -1, err)) + return + } + hash, err := curBlock.GetHash() + if err != nil { + e.Cancel(fmt.Errorf("Error hashing latest block")) + return + } + if bytes.Compare(hash, blockState.Block.PreviousBlockHash) != 0 { + e.Cancel(fmt.Errorf("PreviousBlockHash of received block doesnot match hash of current block")) + return + } + coord.PutBlock(blockHeight, blockState.Block) + delta := &statemgmt.StateDelta{} + if err := delta.Unmarshal(blockState.StateDelta); nil != err { + e.Cancel(fmt.Errorf("Received a corrupt state delta")) + return + } + coord.ApplyStateDelta(msg, delta) + if coord.CommitStateDelta(msg) != nil { + e.Cancel(fmt.Errorf("Played state forward, hashes matched, but failed to commit, invalidated state")) + return + } + peerLogger.Infof("Blockchain height grows into %d", coord.GetBlockchainSize()) Enable statetransfer for HELLO message We also found that when an NVP node just joins the network, it will send a DISC_HELLO message, and then receive a DISC_HELLO message containing the blockchain information of that node from other nodes, but the official code does not provide the implementation of NVP synchronizing its own status based on these returned information. When NVP is implementing its own status synchronization in the network, a new block is mined, but NVP cannot add this new block to its own chain. So now there is a tricky situation: when a new NVP node just joins the network, it obtains the blockchain information of other nodes through the HELLO message to start synchronizing its own status, which will definitely take some time to complete, but at the same time, transactions in the network are still continuing, and new blocks will be continuously mined. Although NVP can receive SYNC_BLOCK_ADDED and has a handler to process it, it cannot add the new block information to its own chain at this time because the hash does not match. After all, the NVP node has not completed the initial synchronization. |
<<: Blockchain Credit: The Second Law of Thermodynamics of Transactions
>>: Fintech startup Revolut raises €7.75 million to enable zero-fee overseas transactions
Some women can bring prosperity to the husband an...
According to Coindesk, Brian Nelson, the Treasury...
What are the special palm lines? 1. Termination l...
There are many lines on the hands, and it is thes...
Nowadays, Internet celebrities have become ubiqui...
1. What is the most blessed facial features for g...
In fact, God has already arranged our fortune in ...
Fan-eared people lose money Characteristics of fa...
US telecommunications giant Sprint is working on ...
Woman with phoenix eyes Women's phoenix eyes ...
Physiognomy: What kind of man is most likely to b...
R3 reviewed eight major areas of blockchain resea...
Is eyebrow fortune telling accurate? Eyebrows are...
Everyone hopes to grow old together with the pers...