Develop a complete blockchain system based on Java (with complete source code)

foreword

In recent years, the concept of blockchain has become more and more popular, especially after the blockchain technology has been included in the national infrastructure construction list, major companies have also begun to recruit people to conduct research on blockchain technology, from the blocks of major recruitment websites. In terms of chain positions, the salaries are very good, with monthly salaries ranging from 30K to 80K. This is also an opportunity for our programmers, indicating that it is imperative to learn blockchain technology.

The code of this blockchain system is very concise and clear, and it is very easy to understand for novices. It aims to tell everyone that blockchain technology is not so advanced and complicated. Except for the springboot framework, the rest of the system is basically pure native development, and even the P2P network is implemented with java socket.

1. Theoretical basis of blockchain technology

1. Basic Concepts

(1) Blockchain

From a technical point of view, a blockchain is a data structure in which blocks containing transaction information are sequentially linked from back to front in chronological order.

From the application level, the blockchain is a distributed shared ledger and database, which has the characteristics of decentralization, non-tampering, full trace, collective maintenance, openness and transparency. Based on these characteristics, blockchain technology can develop a system with its own characteristics of trust system to realize cooperative trust and concerted action among multiple subjects.

A block is the smallest unit in the blockchain. It is mainly composed of a block header containing metadata and a block body that stores one or more transaction information. Each block records the hash and value of the current block. The hash of the previous block, through the association of two hash values, makes all the blocks strung together in a chain structure to form a complete blockchain.

The first block in the blockchain is called the genesis block and does not need to be associated with the previous block. Taking the BTC network as an example, each block mainly contains the following information fields:

  • block size: the size of the block data in bytes
  • Block header: The block header consists of the following fields:
    1. Hash value of block header 2. Hash value of parent block header 3. Timestamp: approximate time of block generation 4. Merkle root: Merkle tree of transactions in this block Hash of the root 5. Difficulty target: The difficulty target of the proof-of-work algorithm for this block 6. Nonce: The counter used for the proof-of-work algorithm
  • Transaction Counter: The number of transactions
  • Transaction: transaction information recorded in the block

A simple model of the blockchain structure, as shown in the following figure:


The transaction set in the block records some specific information. In the BTC network, the main record is transaction information. In other blockchain networks, the corresponding business data can be stored according to business logic, such as audit information, copyright information, Bill information, etc., which is why the blockchain is often used as a shared ledger.

For example, the blockchain can be regarded as a notebook for bookkeeping. A block is equivalent to a page of paper, which records all the accounting information in a certain period of time, from the first page to the last page. , arranged in the order of page numbers is a complete ledger.

(2) Blockchain network

The actual blockchain system consists of multiple blockchain nodes, each node runs a copy of the same set of blockchain backbone network, and each node interacts through the P2P network, and finally forms a complete block chain network system.

The P2P network has reliability, decentralization, and openness. Each node operates interactively and cooperates with each other. While providing services to the outside world, each node also uses the services provided by other nodes in the network. When a blockchain node generates a new block, it will broadcast to other nodes. When other nodes receive the block information through the network, they will verify the block information. When there are a certain number of nodes After all verifications are passed, each node will update the block to their existing blockchain, and finally make the information of each node in the entire blockchain network consistent, which is also the decentralized and trustworthy feature of the blockchain. manifestation.

A simple model of the blockchain network, as shown in the following figure:

2. Blockchain classification

(1) Public chain

Public block chain (Public Block Chains) refers to: any individual or group in the world can send transactions, and the transaction can obtain the effective confirmation of the block chain, anyone can participate in the use and maintenance of the block chain, and the information is open transparent. The public blockchain is the earliest blockchain. Virtual digital currencies such as BTC and Ethereum are all based on the public blockchain. However, the actual application value of the public chain is not very large at present, and there is no particularly suitable application scenario.

(2) Alliance chain

Industry blockchain (Consortium Block Chains): multiple pre-selected nodes are designated as bookkeepers within a group, and the generation of each block is jointly determined by all pre-selected nodes (pre-selected nodes participate in the consensus process), other access nodes You can participate in transactions, but there are restrictions on permissions and information is protected, such as the UnionPay organization. At present, the alliance chain is the main research object of various blockchain technology teams. Because the alliance chain has most of the characteristics of blockchain technology, and has more advantages in rights management, data security, and supervision, it is the blockchain that enterprises give priority to. Technical solutions.

There are also some mainstream consortium chain technology frameworks on the market, making it easier to develop and maintain consortium chains. Some large software manufacturers in China also have their own enterprise blockchain technology solutions, such as Ant Financial's blockchain platform, Tencent's TrustSQL platform, Neusoft's SaCa EchoTrust blockchain application platform and JD's blockchain anti-counterfeiting and traceability platform and many more.

(3) Private chain

Private Block Chains: Only use the general ledger technology of the block chain for bookkeeping, which can be a company or an individual, and has exclusive access to the block chain. Features, using the blockchain as a ledger database.

3. Key technologies and features

(1) Consensus mechanism

The consensus mechanism is called the soul of the blockchain system and the foundation of the trust system of the blockchain system. The blockchain system is a multi-node distributed ledger system. When new information needs to be recorded, which node is responsible for bookkeeping, to which node the bookkeeping reward is issued, which nodes are responsible for verifying the bookkeeping results, and how to make each node Reaching a final consensus and copying and recording the accounting results by all nodes in the network in the same order is what the consensus mechanism needs to do.

And according to Wikipedia:

The so-called "consensus mechanism" is to complete the verification and confirmation of the transaction in a very short period of time through the voting of special nodes. For a transaction, if several nodes with irrelevant interests can reach a consensus, we can think that the entire network is correct. A consensus can also be reached on this. To put it more simply, if a Weibo big V in China, a virtual currency player in the United States, an African student and a European traveler do not know each other, but they all agree that you are a good person, then basically you can conclude You are not bad.

At present, the more mainstream consensus algorithms are PoW, PoS, DPoS, PBFT, etc. In actual use, each algorithm has its own advantages and disadvantages. When applied to different scenarios, blockchain projects will adopt different consensus mechanisms and algorithms.

(2) Decentralization

Decentralization is the form of social relations and content generation formed during the development of the Internet, and is a new type of network content production process relative to "centralization". In a blockchain system with many nodes distributed, each node is characterized by a high degree of autonomy. Any node may become a phased center, but it does not have a mandatory center control function. The influence between nodes will form an association relationship through the network. We call this open, flat, and egalitarian system phenomenon or structure decentralization.

The decentralized system has the characteristics of high fault tolerance and strong attack resistance. In a centralized system, once there is a problem with the center, the entire system will collapse, but if any node in the blockchain system fails, it will not have much impact on the entire blockchain network.

In addition, disintermediation does not mean not accepting supervision. "Decentralization" goes to the central controller and the intermediary, not the regulator. Supervisory nodes can easily access any blockchain network. And because of the open and transparent nature of the blockchain, regulators can more easily monitor the transaction data of the entire system.

(3) Smart contracts

From a technical point of view, a smart contract is a piece of program code deployed on the blockchain. When the conditions set by the program are met, it will run on the blockchain and get the corresponding results. This situation is somewhat similar to WeChat mini-programs. The blockchain provides virtual machines and scripting languages. Users develop programs with certain business logic according to the syntax of the scripting language and deploy them on the blockchain. When the execution conditions are met, Smart contracts are interpreted and run by the blockchain virtual machine.

A typical application is the smart contract of the Ethereum platform. In this platform, users can realize the contract they want through a few simple lines of code, realize the contract that does not require human supervision, cannot be tampered with, and can run automatically, and buy and sell houses. There is no need to find an intermediary, no need to find a notary for borrowing money... People can initiate a contract anytime and anywhere according to their own needs. Its execution does not depend on a person or organization, and all trust is completely based on the Ethereum blockchain platform itself.

(4) Immutability

Most people are accustomed to calling it irreversible modification, but from a technical point of view, I personally think it is more appropriate to call it irreversibility. Since it is a computer system, additions, deletions, modification and checking are basic functional attributes, but the blockchain system deletes It is a bit special with the modification operation.

The blockchain is a chain structure connected by the hash value of each block, and the hash value of the block = SHA256 ("the current block content + the hash value of the previous block"), any one Modification of the content of the block will cause the change of the hash value, and the change of the hash value will also cause the change of the hash value of the sub-block, which in turn causes the change of the entire blockchain.

Therefore, it is almost impossible for anyone to modify the data of the block, unless he re-modifies all the hash values ​​of the entire blockchain from the genesis block to the latest block, and after the modification, also It has to broadcast to tell all other nodes in the network to let all other nodes accept the modification.

However, according to the current computing power of the computer, it is very difficult to modify everything from the head to the tail of the blockchain in a short period of time, and even if the modification is completed, other nodes will not accept the modification, because it is by itself Power, there is no condition for all nodes to reach a consensus.

4. Popular blockchain frameworks and applications

(1) Public chain application: BTC network

Blockchain 1.0 products, for Bitcoin, Satoshi Nakamoto defines it as follows: It is an electronic cash system fully realized through peer-to-peer technology, which enables online payment to be directly initiated by one party and paid to the other party, without the need to go through the middle. any financial institution.

Unlike all currencies, Bitcoin is not issued by a specific currency institution. It is generated by a large number of calculations based on a specific algorithm. The Bitcoin economy uses a distributed database composed of many nodes in the entire P2P network to confirm and record all transactions. And use the design of cryptography to ensure the security of all aspects of currency circulation. After that, people sorted out the blockchain technology system based on the bitcoin network technology to solve the problem of trust, and the principle of the bitcoin network has also become a classic textbook for beginners in blockchain technology.

(2) Public chain application: Ethereum network

The representative of blockchain 2.0 products, Ethereum is an open-source blockchain platform for decentralized applications (Dapps). It has the characteristics of most blockchain technologies, but unlike other blockchains, Ethereum is programmable, and developers can use it to build different applications, providing a decentralized Ethereum Virtual Machine (EVM) to process peer-to-peer contracts through its dedicated cryptocurrency, Ether ("ETH" for short). just some script code). If you think of the Bitcoin network as a set of distributed databases, and Ethereum goes a step further, it can be seen as a distributed computer: the blockchain is the ROM of the computer, the contract is the program, and the Ethereum’s Miners are responsible for computing and play the role of CPU.


The concept of Ethereum was first proposed by programmer Vitalik Buterin in 2013-2014 after being inspired by Bitcoin, which means "the next generation of cryptocurrency and decentralized application platform". Although Ethereum as a platform can develop new applications on it, because the operation of Ethereum is the same as that of the BTC network, it adopts the Token mechanism, and the platform performance is insufficient, and network congestion often occurs. The platform is used for learning development and testing. Blockchain technology is OK, but it is not realistic to use it in actual production.

(3) Consortium chain development framework: Hyperledger Fabric

Hyperledger Fabric, also known as Hyperledger, is a commercial distributed ledger contributed by IBM to the Linux Foundation and is the world's largest distributed open source project for enterprise applications. Like other blockchain technologies, it also has a ledger and can use smart contracts. Fabric's smart contracts can have multiple architectures, and it can be programmed in mainstream languages ​​such as Go, Java, and Javascript, in addition to Solidity.

So far, Fabric has received support from Internet giants such as Alibaba, AWS, Azure, Baidu, Google, Huawei, IBM, Oracle, and Tencent. Many enterprise blockchain platforms use Fabric as the underlying framework, such as Oracle. However, because IBM's definition of blockchain emphasizes the distributed and immutable elements of blockchain, the consensus mechanism is weakened, and the "ordering service" of Kafka and zookeeper is used to achieve consensus, so some industry insiders also say that Hyperledger is a "pseudo-blockchain", but even so, it cannot resist the love of enterprises for Hyperledger. At present, the Fabric 2.0 version has been officially released.

(4) Summary

At present, there are not many business scenarios in the practical application of public chains. Most of them are games with the theme of mining or online pet feeding. Due to the anonymity of digital currency, some criminals take advantage of this feature. , the use of digital currency for money laundering, darknet trading and other illegal activities is the target of various countries, and my country's policies and regulations are also strictly prohibited. Therefore, for technical personnel, the public chain can be used as the object of research and study, and there is not much in other aspects for the time being. much practical significance.

At present, the research direction of most blockchain enterprises is mainly aimed at the alliance chain and private chain of enterprises, and the national level is also strongly supporting the development of blockchain technology, especially the research and development of the underlying core technology of blockchain, advocating the use of blockchain technology. As an important breakthrough for the independent innovation of core technologies, the chain clearly defines the main attack direction, increases investment, strives to overcome a number of key core technologies, and accelerates the development of blockchain technology and industrial innovation. However, most of the mainstream blockchain platforms on the market are still dominated by foreign companies. The development of the underlying core technology of domestic blockchains requires the redoubled efforts of technicians.

2. Java implementation of blockchain technology

1. Blockchain technology architecture


At present, the mainstream blockchain technology architecture is mainly divided into five layers. The data layer is the lowest technology, which mainly realizes modules such as data storage, account information, transaction information, etc. The data storage is mainly based on Merkle tree. The structure of the blockchain is realized, and the account and transaction are based on a variety of cryptographic algorithms and technologies such as digital signature, hash function and asymmetric encryption technology to ensure the security of data in the blockchain.

The network layer mainly realizes the connection and communication of network nodes, also known as point-to-point technology. Each blockchain node communicates through the network. The consensus layer uses the consensus algorithm to allow each node in the network to reach an agreement on the authenticity and correctness of all block data in the entire network, preventing Byzantine attacks, 51 attacks and other blockchain consensus algorithm attacks.

The incentive layer is mainly to realize the issuance and distribution mechanism of blockchain tokens, which is the category of the public chain, and we will not analyze it. The application layer generally regards the blockchain system as a platform, and implements some decentralized applications or smart contracts on the platform, and the platform provides virtual machines to run these applications.

Next, we will develop a small blockchain system based on the Java language to realize some functions of the data layer, network layer, and consensus layer, and use simple codes to intuitively abstract concepts, so as to deepen the understanding of the above blockchain technology. theoretical understanding.

2. Java-based blockchain development practice

(1) Development environment

development tools

VSCode

Development language

Java

JDK version

JDK1.8 or OpenJDK11

Development Framework

SpringBoot2.2.1

Engineering Management

Maven3.6

test tools

Postman

(2) Construction of the basic model of blockchain

The block is the smallest unit of the blockchain system. The first step is to implement the simplest block structure and create a new Block.java class, which mainly contains the following fields:
Block.java

/**
 * 区块结构
 * 
 * @author Jared Jia
 *
 */
public class Block implements Serializable {


  private static final long serialVersionUID = 1L;
  /**
   * 区块索引号(区块高度)
   */
  private int index;
  /**
   * 当前区块的hash值,区块唯一标识
   */
  private String hash;
  /**
   * 前一个区块的hash值
   */
  private String previousHash;
  /**
   * 生成区块的时间戳
   */
  private long timestamp;
  /**
   * 工作量证明,计算正确hash值的次数
   */
  private int nonce;
  /**
   * 当前区块存储的业务数据集合(例如转账交易信息、票据信息、合同信息等)
   */
  private List<Transaction> transactions;
  
  /*** 省略get set方法****/
  }

The blockchain is a data structure in which blocks are connected in series in the order of block hashes. The hash value is the digital abstract information obtained by performing a second hash calculation on the block through a hash algorithm (if you don’t know the hash function, you can First Baidu to understand the SHA algorithm), which is used to ensure the information security of the block and the validity of the entire blockchain. Therefore, in the second step, we added a new method for calculating the hash value of the block, using the SHA256 algorithm and implementing it through java:
CryptoUtil.java

/**
 * 密码学工具类
 * 
 * @author Jared Jia
 *
 */
public class CryptoUtil {


  /**
   * SHA256散列函数
   * @param str
   * @return
   */
  public static String SHA256(String str) {
    MessageDigest messageDigest;
    String encodeStr = "";
    try {
      messageDigest = MessageDigest.getInstance("SHA-256");
      messageDigest.update(str.getBytes("UTF-8"));
      encodeStr = byte2Hex(messageDigest.digest());
    } catch (Exception e) {
      System.out.println("getSHA256 is error" + e.getMessage());
    }
    return encodeStr;
  }
  
  private static String byte2Hex(byte[] bytes) {
    StringBuilder builder = new StringBuilder();
    String temp;
    for (int i = 0; i < bytes.length; i++) {
      temp = Integer.toHexString(bytes[i] & 0xFF);
      if (temp.length() == 1) {
        builder.append("0");
      }
      builder.append(temp);
    }
    return builder.toString();
  }
}

The third step is to create a chain structure object, save the block objects in order, and form an orderly block chain list. Considering the thread safety issue, CopyOnWriteArrayList is used to implement it. For the convenience of testing, let’s put the blockchain The structure is stored in the local cache. The actual blockchain network will eventually realize the function of the persistence layer and save the blockchain data to the database. For example, the BTC core network uses the KV database LevelDB:
BlockCache.java

public class BlockCache {


  /**
   * 当前节点的区块链结构
   */
  private List<Block> blockChain = new CopyOnWriteArrayList<Block>();
  
  public List<Block> getBlockChain() {
    return blockChain;
  }


  public void setBlockChain(List<Block> blockChain) {
    this.blockChain = blockChain;
  }
 }

The fourth step, after having the blockchain structure, we need to add a new method of adding blocks to the blockchain. At the same time, every time we add a block, we need to verify the validity of the new block, such as whether the Hash value is correct. Whether the value of the hash attribute of the previous block in the new block is equal to the hash value of the previous block.

In addition, there must be a genesis block in the blockchain, which we implement directly by hardcoding:
BlockService.java

/**
 * 区块链核心服务
 * 
 * @author Jared Jia
 *
 */
@Service
public class BlockService {


  @Autowired
  BlockCache blockCache;
  
  /**
   * 创建创世区块
   * @return
   */
  public String createGenesisBlock() {
    Block genesisBlock = new Block();
    //设置创世区块高度为1
    genesisBlock.setIndex(1);
    genesisBlock.setTimestamp(System.currentTimeMillis());
    genesisBlock.setNonce(1);
    //封装业务数据
    List<Transaction> tsaList = new ArrayList<Transaction>();
    Transaction tsa = new Transaction();
    tsa.setId("1");
    tsa.setBusinessInfo("这是创世区块");
    tsaList.add(tsa);
    Transaction tsa2 = new Transaction();
    tsa2.setId("2");
    tsa2.setBusinessInfo("区块链高度为:1");
    tsaList.add(tsa2);    
    genesisBlock.setTransactions(tsaList);
    //设置创世区块的hash值
    genesisBlock.setHash(calculateHash("",tsaList,1));
    //添加到已打包保存的业务数据集合中
    blockCache.getPackedTransactions().addAll(tsaList);
    //添加到区块链中
    blockCache.getBlockChain().add(genesisBlock);
    return JSON.toJSONString(genesisBlock);
  }
  
  /**
   * 创建新区块
   * @param nonce
   * @param previousHash
   * @param hash
   * @param blockTxs
   * @return
   */
  public Block createNewBlock(int nonce, String previousHash, String hash, List<Transaction> blockTxs) {
    Block block = new Block();
    block.setIndex(blockCache.getBlockChain().size() + 1);
    //时间戳
    block.setTimestamp(System.currentTimeMillis());
    block.setTransactions(blockTxs);
    //工作量证明,计算正确hash值的次数
    block.setNonce(nonce);
    //上一区块的哈希
    block.setPreviousHash(previousHash);
    //当前区块的哈希
    block.setHash(hash);
    if (addBlock(block)) {
      return block;
    }
    return null;
  }


  /**
   * 添加新区块到当前节点的区块链中
   * 
   * @param newBlock
   */
  public boolean addBlock(Block newBlock) {
    //先对新区块的合法性进行校验
    if (isValidNewBlock(newBlock, blockCache.getLatestBlock())) {
      blockCache.getBlockChain().add(newBlock);
      // 新区块的业务数据需要加入到已打包的业务数据集合里去
      blockCache.getPackedTransactions().addAll(newBlock.getTransactions());
      return true;
    }
    return false;
  }
  
  /**
   * 验证新区块是否有效
   * 
   * @param newBlock
   * @param previousBlock
   * @return
   */
  public boolean isValidNewBlock(Block newBlock, Block previousBlock) {
    if (!previousBlock.getHash().equals(newBlock.getPreviousHash())) {
      System.out.println("新区块的前一个区块hash验证不通过");
      return false;
    } else {
      // 验证新区块hash值的正确性
      String hash = calculateHash(newBlock.getPreviousHash(), newBlock.getTransactions(), newBlock.getNonce());
      if (!hash.equals(newBlock.getHash())) {
        System.out.println("新区块的hash无效: " + hash + " " + newBlock.getHash());
        return false;
      }
      if (!isValidHash(newBlock.getHash())) {
        return false;
      }
    }


    return true;
  }
 }

After the above key code is implemented, we have built a very simple blockchain model, including a basic block model and a blockchain model, and can generate new blocks and add them to the blockchain. Next We test.

The fifth step, we write a Controller class to call:
BlockController.java

@Controller
public class BlockController {


  @Resource
  BlockService blockService;
  
  @Autowired
  BlockCache blockCache;
  
  /**
   * 查看当前节点区块链数据
   * @return
   */
  @GetMapping("/scan")
  @ResponseBody
  public String scanBlock() {
    return JSON.toJSONString(blockCache.getBlockChain());
  }
  
  /**
   * 创建创世区块
   * @return
   */
  @GetMapping("/create")
  @ResponseBody
  public String createFirstBlock() {
    blockService.createGenesisBlock();
    return JSON.toJSONString(blockCache.getBlockChain());
  }
 }

The sixth step, system test
First, after the system is started, first check the data in the blockchain, you can see that the blockchain in the current system is empty:


Then we call the method of creating the genesis block and check the return result:

After we add the generated genesis block to the local blockchain, convert it into a JSON string and return it, we can see that there is a block object stored in the current blockchain, so far we have implemented a simple block chain. The actual blockchain system model is much more complex, and the corresponding fields need to be expanded according to different business scenarios, but the basic features are the same.

(3) Implementation of consensus mechanism

In the previous chapter, we implemented a simple blockchain structure and were able to generate and add new blocks, but here comes the problem, the actual blockchain system is a multi-node, distributed, decentralized network , each node interacts through the network and stores the same entire blockchain data synchronously in real time, so how can the blocks we generate be recognized by other nodes and added to all other nodes synchronously? At this time, we need to A set of rules that allows all network node participants to reach a consensus, accept and save new blocks, which is the so-called "consensus mechanism".

As mentioned in the theoretical basis, there are many consensus mechanisms, each with its own advantages and disadvantages. Next, we will use java code to simulate and implement one of the mechanisms we are most familiar with: Proof of Work, as the name suggests. Proof of workload, in the blockchain network constructed based on the POW mechanism, nodes compete for accounting rights by calculating the value of random hashes, and the ability to obtain the correct value and generate blocks is the specific computing power of the node. The process of performance and calculation is generally called "mining" vividly.

To put it simply, the blockchain system sets a set of calculation rules or a set of calculation problems. Before a new block is generated, each node is invested in the calculation of this problem. Which node calculates the result first, and After being verified and recognized by other nodes, this node will obtain the bookkeeping right of the new block, and receive the corresponding rewards of the system, and the consensus ends.

A typical application of PoW consensus mechanism is the BTC network. In the BTC network, the goal of consensus calculation is to find a block Hash (hash value) that satisfies a specific requirement. This block hash value is a proof of the work result. The purpose of the calculation work is to find this proof value. In the previous chapter, we have seen this hash value during the test:

[
    {
        "hash": "25931395e736653212f0258824df4222ae739ec2d5897310258b0857d4d3870c",
        "index": 1,
        "nonce": 1,
        "timestamp": 1580970554734,
        "transactions": [
            {
                "businessInfo": "这是创世区块",
                "id": "1"
            }
        ]
    }
]

The Hashcash algorithm used by the BTC network PoW has the following general logic:

  1. Obtain some publicly known data (in the BTC network, it refers to the block header);
  2. Add a counter nonce, the initial value is set to 0;
  3. Calculate the hash value of the concatenated string of data and nonce;
  4. Check whether the hash value of the previous step meets a certain condition, stop the calculation if it is satisfied, add 1 to the nonce if it is not satisfied, and then repeat steps 3 and 4 until this specific condition is met.

Next, we use Java code to implement this algorithm, and set the specific conditions to be satisfied as if the first 4 digits of the Hash value are all 0, then the calculation is successful (the specific conditions in the actual blockchain network are more demanding, and the computing power of the calculation is required. It is also high, and the system dynamically adjusts the specific conditions met with the calculation difficulty to ensure the speed of block generation).

The first step, we create a new consensus mechanism service class, add a "mining" method, after the calculation is successful, obtain the accounting right, call the method of adding a block, and add the block to the blockchain:
PowService.java

/**
 * 共识机制
 * 采用POW即工作量证明实现共识
 * @author Administrator
 *
 */
@Service
public class PowService {


  @Autowired
  BlockCache blockCache;
  
  @Autowired
  BlockService blockService;
  
  /**
   * 通过“挖矿”进行工作量证明,实现节点间的共识
   * 
   * @return
   */
  public Block mine(){
    
    // 封装业务数据集合,记录区块产生的节点信息,临时硬编码实现
    List<Transaction> tsaList = new ArrayList<Transaction>();
    Transaction tsa1 = new Transaction();
    tsa1.setId("1");
    tsa1.setBusinessInfo("这是IP为:"+CommonUtil.getLocalIp()+",端口号为:"+blockCache.getP2pport()+"的节点挖矿生成的区块");
    tsaList.add(tsa1);
    Transaction tsa2 = new Transaction();
    tsa2.setId("2");
    tsa2.setBusinessInfo("区块链高度为:"+(blockCache.getLatestBlock().getIndex()+1));
    tsaList.add(tsa2);
    
    // 定义每次哈希函数的结果 
    String newBlockHash = "";
    int nonce = 0;
    long start = System.currentTimeMillis();
    System.out.println("开始挖矿");
    while (true) {
      // 计算新区块hash值
      newBlockHash = blockService.calculateHash(blockCache.getLatestBlock().getHash(), tsaList, nonce);
      // 校验hash值
      if (blockService.isValidHash(newBlockHash)) {
        System.out.println("挖矿完成,正确的hash值:" + newBlockHash);
        System.out.println("挖矿耗费时间:" + (System.currentTimeMillis() - start) + "ms");
        break;
      }
      System.out.println("第"+(nonce+1)+"次尝试计算的hash值:" + newBlockHash);
      nonce++;
    }
    // 创建新的区块
    Block block = blockService.createNewBlock(nonce, blockCache.getLatestBlock().getHash(), newBlockHash, tsaList);
    return block;
  }
  
  /**
   * 验证hash值是否满足系统条件
   * 暂定前4位是0则满足条件
   * @param hash
   * @return
   */
  public boolean isValidHash(String hash) {
    //System.out.println("难度系数:"+blockCache.getDifficulty());
    return hash.startsWith("0000");
  }
}

The second step is to write the Controller class method for testing the consensus mechanism service:
BlockController.java

/**
   * 工作量证明PoW
   * 挖矿生成新的区块 
   */
  @GetMapping("/mine")
  @ResponseBody
  public String createNewBlock() {
    powService.mine();
    return JSON.toJSONString(blockCache.getBlockChain());
  }

The third step is to start the system and test it.
First execute the
http://localhost:8080/create method to generate the creation block.
Next, call
the http://localhost:8080/mine method for proof of work calculation, generate a new block, and add it to the local blockchain:

Let's take a look at the background calculation process of the system. This calculation takes a total of 1048ms to calculate the Hash value that meets the conditions, and calculates a total of 4850 times:

So far, we have implemented a simple proof-of-work mechanism and run it on the current blockchain system node to complete the calculation of the correct result and generate a new block.

Next, we will develop a P2P network to realize the simultaneous operation of multiple nodes. When a node completes mining, it will broadcast to other nodes through the P2P network. After the other nodes pass the verification, they will add the newly generated blocks to themselves. on the blockchain, thereby ensuring the data consistency of all nodes in the entire blockchain network.

(4) P2P network development

Earlier, we have implemented a basic blockchain system and implemented the PoW workload proof consensus mechanism, which calculates the correct result through mining and generates a new block to add to the blockchain, but these are based on In the operation of a single node, the actual blockchain is a distributed network system with multiple nodes running at the same time. All nodes calculate and snatch the accounting right at the same time, and jointly maintain a complete blockchain.

Next, we implement a Peer-to-Peer network based on Java's WebSocket to achieve mutual communication between multiple nodes. Through this chapter, we will implement the following functions:

  - 创建一个基于java的p2p网络
  - 运行多个节点,且多个节点通过p2p网络自动同步区块信息
  - 一个节点挖矿生成新的区块后,自动广播给其他所有节点
  - 每个节点在接收到其他节点发送的区块内容后,进行验证,验证通过添加到本地区块链上
  - 在自我节点查看整个区块链内容

To develop and test the functions of this chapter, we'd better prepare two computers or virtual machines, or a Docker cluster environment, which is convenient for running tests on multiple nodes. If there is only one computer, the port number running on each node can be set to be different.

The first step is to organize the development ideas.
At present, we have realized the block generation of a single node, then we only need to realize the message synchronization of each node.

  • First, the server side and client side of the p2p network are implemented through java code, and each node is both a server side and a client side.
  • Then, when a node starts up, it will look for valid nodes on the blockchain network and establish socket connections (BTC network can obtain valid BTC nodes by using the "DNS" seed method, which provides the IP address list of Bitcoin nodes), We configure the node list directly into the application.yml file.
  • Next, get the latest block information from the connected node. If the current node runs for the first time, get the entire blockchain information and replace it locally.
  • After that, each node mines and calculates at the same time, whichever node completes the calculation first, broadcasts the generated new block to all other nodes (the actual blockchain network is always calculating, we manually trigger a node to mine for the convenience of testing. Generate blocks, and then broadcast to all other nodes on the entire network).
  • Finally, when a node receives the broadcast content, it verifies the new block received, and adds it to the local blockchain after the verification passes. The primary condition for verification is that the height of the new block must be higher than the local blockchain. .

The second step is to first implement the P2P network server side,
create a new P2PServer class, and add a method to initialize the server side:
P2PServer.java

/**
 * p2p服务端
 * 
 * @author Jared Jia
 *
 */
@Component
public class P2PServer {


  @Autowired
  P2PService p2pService;


  public void initP2PServer(int port) {
    WebSocketServer socketServer = new WebSocketServer(new InetSocketAddress(port)) {


      /**
       * 连接建立后触发
       */
      @Override
      public void onOpen(WebSocket webSocket, ClientHandshake clientHandshake) {
        p2pService.getSockets().add(webSocket);
      }


      /**
       * 连接关闭后触发
       */
      @Override
      public void onClose(WebSocket webSocket, int i, String s, boolean b) {
        p2pService.getSockets().remove(webSocket);
        System.out.println("connection closed to address:" + webSocket.getRemoteSocketAddress());
      }


      /**
       * 接收到客户端消息时触发
       */
      @Override
      public void onMessage(WebSocket webSocket, String msg) {
        //作为服务端,业务逻辑处理
        p2pService.handleMessage(webSocket, msg, p2pService.getSockets());
      }


      /**
       * 发生错误时触发
       */
      @Override
      public void onError(WebSocket webSocket, Exception e) {
        p2pService.getSockets().remove(webSocket);
        System.out.println("connection failed to address:" + webSocket.getRemoteSocketAddress());
      }


      @Override
      public void onStart() {


      }


    };
    socketServer.start();
    System.out.println("listening websocket p2p port on: " + port);
  }
}

The third step is to implement the P2P network client side
P2PClient.java

/**
 * p2p客户端
 * 
 * @author Jared Jia
 *
 */
@Component
public class P2PClient {
  
  @Autowired
  P2PService p2pService;


  public void connectToPeer(String addr) {
    try {
      final WebSocketClient socketClient = new WebSocketClient(new URI(addr)) {
        @Override
        public void onOpen(ServerHandshake serverHandshake) {
          //客户端发送请求,查询最新区块
          p2pService.write(this, p2pService.queryLatestBlockMsg());
          p2pService.getSockets().add(this);
        }


        /**
         * 接收到消息时触发
         * @param msg
         */
        @Override
        public void onMessage(String msg) {
          p2pService.handleMessage(this, msg, p2pService.getSockets());
        }


        @Override
        public void onClose(int i, String msg, boolean b) {
          p2pService.getSockets().remove(this);
          System.out.println("connection closed");
        }


        @Override
        public void onError(Exception e) {
          p2pService.getSockets().remove(this);
          System.out.println("connection failed");
        }
      };
      socketClient.connect();
    } catch (URISyntaxException e) {
      System.out.println("p2p connect is error:" + e.getMessage());
    }
  }
}

The fourth step is to define the message model of P2P network synchronization
. We define the message model of synchronization into four categories, namely:
BlockConstant.java

  // 查询最新的区块
  public final static int QUERY_LATEST_BLOCK = 1;


  // 返回最新的区块
  public final static int RESPONSE_LATEST_BLOCK = 2;


  // 查询整个区块链
  public final static int QUERY_BLOCKCHAIN = 3;


  // 返回整个区块链
  public final static int RESPONSE_BLOCKCHAIN = 4;

Define a message model passed between nodes:
Message.java

/**
 * p2p通讯消息
 *
 * @author Jared Jia
 * 
 */
public class Message implements Serializable {
  
    private static final long serialVersionUID = 1L;
    /**
     * 消息类型
     */
    private int type;
    /**
     * 消息内容
     */
    private String data;
    
    /****set get方法省略****/
    
  }

The fifth step is to implement the method of broadcasting to other nodes

Create a new p2p network service class to send out messages, or process requests sent by the current node to other nodes.
P2PService.java

/**
   * 全网广播消息
   * @param message
   */
  public void broatcast(String message) {
    List<WebSocket> socketsList = this.getSockets();
    if (CollectionUtils.isEmpty(socketsList)) {
      return;
    }
    System.out.println("======全网广播消息开始:");
    for (WebSocket socket : socketsList) {
      this.write(socket, message);
    }
    System.out.println("======全网广播消息结束");
  }

The sixth step, develop message processing routes

In the fifth step, sending a message has been realized, and this step realizes receiving a message.
First, a message routing shared by the server and the client is designed to distribute messages to the corresponding processing units.
P2PService.java

/**
   * 客户端和服务端共用的消息处理方法
   * @param webSocket
   * @param msg
   * @param sockets
   */
  public void handleMessage(WebSocket webSocket, String msg, List<WebSocket> sockets) {
    try {
      Message message = JSON.parseObject(msg, Message.class);
      System.out.println("接收到IP地址为:" +webSocket.getRemoteSocketAddress().getAddress().toString()
          +",端口号为:"+ webSocket.getRemoteSocketAddress().getPort() + "的p2p消息:"
              + JSON.toJSONString(message));
      switch (message.getType()) {
      //客户端请求查询最新的区块:1
      case BlockConstant.QUERY_LATEST_BLOCK:
        write(webSocket, responseLatestBlockMsg());//服务端调用方法返回最新区块:2
        break;
      //接收到服务端返回的最新区块:2
      case BlockConstant.RESPONSE_LATEST_BLOCK:
        handleBlockResponse(message.getData(), sockets);
        break;
      //客户端请求查询整个区块链:3
      case BlockConstant.QUERY_BLOCKCHAIN:
        write(webSocket, responseBlockChainMsg());//服务端调用方法返回最新区块:4
        break;
      //直接接收到其他节点发送的整条区块链信息:4
      case BlockConstant.RESPONSE_BLOCKCHAIN:
        handleBlockChainResponse(message.getData(), sockets);
        break;
      }
    } catch (Exception e) {
      System.out.println("处理IP地址为:" +webSocket.getRemoteSocketAddress().getAddress().toString()
        +",端口号为:"+ webSocket.getRemoteSocketAddress().getPort() + "的p2p消息错误:" 
        + e.getMessage());
    }
  }

The seventh step, develop the message processing unit

After the message routing is in place, then write different processing units to process the block or blockchain information sent by other nodes. The general principle is: first verify the validity of the blocks or blockchains sent by other nodes, and then Judging that their height is higher than that of the current node's blockchain, if it is higher, replace the local blockchain, or add a new block to the local blockchain.
P2PService.java

/**
   * 处理其它节点发送过来的区块信息
   * @param blockData
   * @param sockets
   */
  public synchronized void handleBlockResponse(String blockData, List<WebSocket> sockets) {
    //反序列化得到其它节点的最新区块信息
    Block latestBlockReceived = JSON.parseObject(blockData, Block.class);
    //当前节点的最新区块
    Block latestBlock = blockCache.getLatestBlock();
    
    if (latestBlockReceived != null) {
      if(latestBlock != null) {
        //如果接收到的区块高度比本地区块高度大的多
        if(latestBlockReceived.getIndex() > latestBlock.getIndex() + 1) {
          broatcast(queryBlockChainMsg());
          System.out.println("重新查询所有节点上的整条区块链");
        }else if (latestBlockReceived.getIndex() > latestBlock.getIndex() && 
            latestBlock.getHash().equals(latestBlockReceived.getPreviousHash())) {
          if (blockService.addBlock(latestBlockReceived)) {
            broatcast(responseLatestBlockMsg());
          }
          System.out.println("将新接收到的区块加入到本地的区块链");
        }
      }else if(latestBlock == null) {
        broatcast(queryBlockChainMsg());
        System.out.println("重新查询所有节点上的整条区块链");
      }
    }
  }
  
  /**
   * 处理其它节点发送过来的区块链信息
   * @param blockData
   * @param sockets
   */
  public synchronized void handleBlockChainResponse(String blockData, List<WebSocket> sockets) {
    //反序列化得到其它节点的整条区块链信息
    List<Block> receiveBlockchain = JSON.parseArray(blockData, Block.class);
    if(!CollectionUtils.isEmpty(receiveBlockchain) && blockService.isValidChain(receiveBlockchain)) {
      //根据区块索引先对区块进行排序
      Collections.sort(receiveBlockchain, new Comparator<Block>() {
        public int compare(Block block1, Block block2) {
          return block1.getIndex() - block2.getIndex();
        }
      });
      
      //其它节点的最新区块
      Block latestBlockReceived = receiveBlockchain.get(receiveBlockchain.size() - 1);
      //当前节点的最新区块
      Block latestBlock = blockCache.getLatestBlock();
      
      if(latestBlock == null) {
        //替换本地的区块链
        blockService.replaceChain(receiveBlockchain);
      }else {
        //其它节点区块链如果比当前节点的长,则处理当前节点的区块链
        if (latestBlockReceived.getIndex() > latestBlock.getIndex()) {
          if (latestBlock.getHash().equals(latestBlockReceived.getPreviousHash())) {
            if (blockService.addBlock(latestBlockReceived)) {
              broatcast(responseLatestBlockMsg());
            }
            System.out.println("将新接收到的区块加入到本地的区块链");
          } else {
            // 用长链替换本地的短链
            blockService.replaceChain(receiveBlockchain);
          }
        }
      }
    }
  }

3. Complete system operation and testing

The first step is to package and generate an executable jar package for testing
Prepare two machines (either a virtual machine or a Docker cluster), and run two nodes at the same time. The node information is as follows:

Use the mvn package -Dmaven.test.skip=true command to package the project to generate a jar package that can be run directly. Configure the project before packaging. The configuration information is as follows:

Node Node1 package:

Node Node2 package:

After being packaged separately, the executable jar packages of the two nodes are generated, as follows:

Put the two jar packages on the windows machine of the corresponding IP, open the command line mode, enter the folder where the jar is located, and execute the following commands respectively to run the two nodes:
java -jar dce-blockchain-node1.jar
java -jar dce- blockchain-node2.jar

When starting node 2, you can see the background log, and node 1 has been connected, as shown in the following figure:

The second step is to test the two nodes

First, after the two nodes are started, use postman to execute
http://192.168.0.104:8080/scan and http://192.168.0.112:8090/scan requests respectively, you can see that the blockchain content of the two nodes is null.

Then, execute
http://192.168.0.104:8080/create and http://192.168.0.104:8080/mine requests on node 1 to generate the genesis block and generate the second block through mining , after execution, check the blockchain information of node 1 as follows:
Execute
http://192.168.0.104:8080/scan result:

[
    {
        "hash": "5303d2990c139992bdb5a22aa1dac4f2719755304e45bac03ca4a1f1688c909e",
        "index": 1,
        "nonce": 1,
        "timestamp": 1581064647736,
        "transactions": [
            {
                "businessInfo": "这是创世区块",
                "id": "1"
            },
            {
                "businessInfo": "区块链高度为:1",
                "id": "2"
            }
        ]
    },
    {
        "hash": "0000de5eea0c20c2e7d06220bc023886e88dd8784eaa2fd2d1d6c5e581061d85",
        "index": 2,
        "nonce": 4850,
        "previousHash": "5303d2990c139992bdb5a22aa1dac4f2719755304e45bac03ca4a1f1688c909e",
        "timestamp": 1581064655139,
        "transactions": [
            {
                "businessInfo": "这是IP为:192.168.0.104,端口号为:7001的节点挖矿生成的区块",
                "id": "1"
            },
            {
                "businessInfo": "区块链高度为:2",
                "id": "2"
            }
        ]
    }
]

Finally, let's verify whether node 2 has completed the network synchronization of the blockchain information generated by node 1. Postman executes the
http://192.168.0.112:8090/scan request to view the returned result:

It can be seen from the results that the blockchain network node 2 has received the blockchain information sent by node 1, and the system log is as follows:

In turn, we perform another mining operation on node 2, and we can see that on node 1, the newly mined block information of node 2 has been received and added to the blockchain of node 1:

So far, we have implemented a complete small blockchain network and realized the communication between each node, and multiple nodes jointly maintain the same blockchain information.

Conclusion:
The blockchain system is very large and involves various technologies. The code I demonstrated mainly interprets some concepts of the blockchain foundation. Interested students can continue to develop on this basis to achieve, for example, persistence Layer, message encryption and decryption, system account model, oracle machine, side chain technology, and smart contracts and other blockchain system functions.


Write to every blockchain technician:
Currently, the popular enterprise-level blockchain frameworks on the market, such as Hyperledger Fabric, are dominated by foreign personnel, and in addition to a few large factories in our country, many other blockchain companies basically They all take other people's things for secondary packaging, and then claim that their company has mastered the core technology of blockchain and provide services to enterprises, which is a bad phenomenon. You can think about how many of the development languages ​​and frameworks we are using are actually domestically produced. Let’s think about the fact that ZTE and Huawei were blocked by other core technologies some time ago, and we know that we have a lot of things to do, and we need to remove them. Impetuous, calm down and study the underlying core technology, so as to achieve a real "curve overtaking"!

Linked list high-frequency interview questions (including inversion, merging, intersection, division, ring length, etc.)
1.1 Question description

Reverse a singly linked list.

Example:

  • Input: 1->2->3->4->5->NULL
  • Output: 5->4->3->2->1->NULL

Advanced: You can reverse the linked list iteratively or recursively. Can you solve this problem in two ways?

1.2 Algorithm Implementation

1.2.1 Algorithm idea

Double pointer: one pointer pre points to the previous node of the current node of the original linked list, and the other pointer next temporarily stores the next node of the current node.

Traverse each node of the linked list in turn, each traversing a node will point it to the previous node (inverted), mainly divided into 4 steps:

  1. Back up the next node first (in case the next node cannot be found when moving the pointer): next = head.Next;
  2. Next of the next node points to the previous node: next.Next = pre;
  3. Move the previous node one position back to the current node: pre = head;
  4. The post node moves one position back to the next node: head = next, pay attention to this step (don't) is easy to ignore.

1.2.2 Code Implementation

type LikedList struct{
    Val int
    Next *LikedList
}

// 头插法,倒置单链表
func reverseLikedList(head *LikedList)*LikedList{
    if(head == nil || head.Next == nil){
        return head
    }
 var pre, next *LikedList 
 // head是当前节点,pre是当前节点的前一个几点,next是当前节点的后一个节点
    for head != nil {  // 当前节点不为空
        next = head.Next    // 备份head.Next(指向当前节点的下一个节点),防止移动节点时找不到后置节点
  head.Next = pre     // 更新head.Next,后一个节点指向前一个(翻转)
  pre = head          // 前一个节点后移
  head = next   // 当前节点后移
 }
    return pre              // 注意:当pre指向原链表的最后一个节点时,head已经指向最后一个节点的Next即空节点,所以这里应返回pre
}

2. Reverse the mth to nth nodes in the linked list

Topic source:

https://leetcode-cn.com/problems/reverse-linked-list-ii

2.1 Topic description

Reverse the linked list from position m to n. Please use one scan to complete the reversal.

illustrate:

1 ≤ m ≤ n ≤ linked list length.

Example:

  • Input: 1->2->3->4->5->NULL, m = 2, n = 4
  • Output: 1->4->3->2->5->NULL

2.2 Algorithm Implementation

2.2.1 Algorithm idea

There are four key positions to record: the mth node and its predecessors, the nth node and its successors.

  1. Traverse the entire linked list, move the head pointer of the linked list head back by m-1 nodes, which is the mth node, and record its predecessor node as pre;
  2. Starting from the mth node, reverse changLen = n-m+1 nodes, that is, reverse the mth to nth nodes in turn, and record the reversed head node reversedListHead and tail node reversedListTail;
  3. Connect the Next field of the reversed tail node reversedListTail with the successor node head of the nth node, and connect the Next field of the pre node with the reversedListHead.

2.2.2 Code Implementation

/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func reverseBetween(head *ListNode, m int, n int) *ListNode {
    changeLen := n - m + 1                      // 计算需要逆置的节点个数
    var pre *ListNode = nil                     // 初始化开始逆置的节点的前驱
    var result *ListNode = head                 // 最终转换后的链表的头结点,非特殊情况即为head
    move := m - 1                               // head向后移动m-1个位置指向第m个节点
    for(head != nil && move > 0){               // 将head后移m-1个位置,即
        pre = head                              // for循环后pre指向第m个节点的前驱节点
        head = head.Next                        // for循环后head指向第m个节点
        move--
    }

    var reversedListTail *ListNode = head       // 此时reversedListTail指向的是第m个节点,该节点即是链表片段反转后的尾节点
    var reversedListHead *ListNode = nil        // 记录链表片段反转后的头结点
    for(head != nil && changeLen > 0){          // 逆置changeLen个节点
        next := head.Next                       // 暂存当前节点的下一个节点
        head.Next = reversedListHead            // 当前节点的Next指针域指向新开辟的反转后的头结点
        reversedListHead = head                 // 反转后的链表的头结点后移一个位置
        head = next                             // 当前节点后移一个节点
        changeLen--                             // 每完成一个节点逆置,changLen--
    }

    reversedListTail.Next = head                // 连接逆置后的链表尾与逆置段的后一个节点,翻转后的尾节点指向第n个节点的下一个节点
    if(pre != nil){                             // 如果pre不为空,说明不是从第1个节点开始逆置的,即m > 1 
        pre.Next = reversedListHead             // 将逆置链表开始的节点前驱与逆置后的头结点连接起来
    }else{                                      // 如果pre为空,说明m=1,即从第1个节点开始逆置,结果即为逆置后的头结点
        result = reversedListHead
    }
    return result
}

3. Find the intersection between two linked lists

3.1 Topic description

Topic source:

https://leetcode-cn.com/problems/intersection-of-two-linked-lists

Write a program that finds the starting node where two singly linked lists intersect.

Such as the following two linked lists:

The intersection starts at node c1.

Example 1:

  • Input: intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
  • Output: Reference of the node with value = 8

Input Explanation: The intersection node has a value of 8 (note that it cannot be 0 if the two lists intersect). Counting from their respective headers, the linked list A is [4,1,8,4,5] and the linked list B is [5,0,1,8,4,5]. In A, there are 2 nodes before the intersecting node; in B, there are 3 nodes before the intersecting node.

Recommendation: Summary of 250 interview questions

Example 2:

  • Input: intersectVal = 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1
  • Output: Reference of the node with value = 2

Input Explanation: The intersection node has a value of 2 (note that it cannot be 0 if two lists intersect). Starting from their respective headers, the list A is [0,9,1,2,4], and the list B is [3,2,4]. In A, the intersection node is preceded by 3 nodes; in B, the intersection node is preceded by 1 node.

Example 3:

  • Input: intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2
  • output: null

Input explanation: Starting from the respective headers, the linked list A is [2,6,4], and the linked list B is [1,5]. Since the two linked lists do not intersect, intersectVal must be 0, while skipA and skipB can be arbitrary values. Explanation: The two linked lists do not intersect, so null is returned.

Notice:

  • Returns null if the two linked lists do not intersect.
  • After returning the result, the two linked lists must still maintain the original structure.
  • It can be assumed that there are no loops in the entire linked list structure.
  • The program tries to satisfy O(n) time complexity and only uses O(1) memory.

3.2 Algorithm Implementation

3.2.1 Algorithm idea

  1. Traverse the two linked lists ListNode1 and ListNode2 respectively, and calculate their lengths len1 and len2;
  2. The head pointer of the long linked list is moved back by abs(len1 - len2) nodes;
  3. When the linked list has not been traversed to the end, and the two linked lists point to the same node, the node is the intersection of the two linked lists. If they do not point to the same node, the pointers of the two head nodes continue to move backward; if they are not found after the traversal, it means that there is no intersection, and return nil.

3.2.2 Code Implementation

/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func getIntersectionNode(headA, headB *ListNode) *ListNode {
    var lenA, lenB int                                      // 分别记录链表headA和链表headB的长度    
    lenA = getListLength(headA)
    lenB = getListLength(headB)

    if lenA > lenB {
        headA = forwardDeltaLenNode(lenA, lenB, headA)      // headA链表的头结点指向移动多出的节点个位置后
    }else{
        headB = forwardDeltaLenNode(lenB, lenA, headB)      // 如果链表headB长,移动其头结点到相应位置
    }
    for headA != nil && headB != nil {      // 没有到达链表末尾
        if(headA == headB){                 // 当前两个链表的节点相同,即指向同一个节点,说明找到的交点;否则,两链表同时后移
            return headA
        }
        headA = headA.Next                  
        headB = headB.Next
    }
    return nil                              // 遍历到链表末尾还没有找到同一个节点,说明两链表没有交点
}

// 逐个节点遍历,获取链表长度
func getListLength(head *ListNode)int{
    var lengthList int 
    for head != nil {
        lengthList++
        head = head.Next
    }
    return lengthList
}

// 较长链表移动 长链表长度-短链表长度 个节点后对应的头指针
// 参数longLen和shortLen分别表示长链表和短链表的长度,longList对应长链表
func forwardDeltaLenNode(longLen, shortLen int, longList *ListNode)*ListNode{
    deltaLen := longLen - shortLen
    for longList != nil && deltaLen != 0{
        longList = longList.Next
        deltaLen--
    }
    return longList             // 如果longList为nil或者deltaLen=0直接返回此时的头结点longList
}

4. Determine whether the linked list has a ring; if there is a ring, give the starting node where the ring is located and the length of the ring.

4.1 Determine whether the linked list has a cycle

4.2 Give the starting node and length of the ring of a linked list with a ring

5. Divide the linked list into two parts bounded by a certain value x

The linked list is divided according to: the front part of the linked list is less than x, the latter part is greater than or equal to x, and the relative order of the original nodes remains unchanged. For example: divide 1->3-7->2->5->3->6-9-2 into two parts with 5 as the boundary: 1->3->2->3->2 - >7->5->6->9

5.1 Problem description

Given a linked list and a particular value x, partition the linked list such that all nodes less than x come before nodes greater than or equal to x.

You should keep the initial relative position of each node in both partitions.

Example:

  • Input: head = 1->4->3->2->5->2, x = 3
  • Output: 1->2->2->4->3->5

Link:

https://leetcode-cn.com/problems/partition-list

5.2 Algorithm Implementation

5.2.1 Algorithm idea

The linked list is divided into two parts, front and back. You can traverse the linked list in turn, insert nodes smaller than x into the first half of the linked list pointed to by preHead in turn, and connect nodes greater than or equal to x to another linked list corresponding to postHead; The Next field of the tail node of preHead points to the next node of the postHead node, and the Next field of the tail node of postHead is set to empty, that is, the connection between the two linked lists is realized.

In order to connect the two linked lists of preHead and postHead, it is necessary to know the tails of the two linked lists respectively. Here, the prePtr and postPtr pointers are used to traverse preHead and postHead respectively to know the tail nodes of the two linked lists.

  • The previous linked list: preHead->1->2->2
  • The latter linked list: postHead->4->3->5

5.2.2 Code Implementation

/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func partition(head *ListNode, x int) *ListNode {
    //var preHead, postHead *ListNode     // 前后两部分链表的头结点,不能这么声明,这样声明的话两者都为&ListNode{0, nil}其中Next域为nil,当运行到prePtr.Next = head时会报panic: runtime error:invalid memory address or nil pointer deference错误
    preHead := &ListNode{0, nil}        // 生成一个preHead链表的头结点,该节点固定一直不对其移动,改头节点的Val为多少都不影响结果,因为使用的是头结点的Next节点
    postHead := &ListNode{0, nil}       // 生成一个postHead链表的头结点,该节点固定不动
    prePtr := preHead                   // prePtr指针对preHead链表进行遍历,注意:开始时其指向preHead
    postPtr := postHead
    for head != nil {                   // 遍历原链表
        if(head.Val < x ){              // 小于x的节点尾插到preHead链表后面
            prePtr.Next = head          // prePtr的Next域指向当前节点,即将当前节点从preHead链表尾部prePtr依次插入
            prePtr = head               // prePtr指针后移一位,指向当前节点
        }else{                          // 大于等于x的节点放在postHead链表的后面
            postPtr.Next = head         // 将当前节点插入到postHead链表尾节点postPtr后面
            postPtr = head              // postHead链表的尾节点后移一位
        }
        head = head.Next                // 当前指针后移一位
    }
    // 对head链表遍历结束分为preHead和postHead两个子链表
    prePtr.Next = postHead.Next         // 注意:这里是将preHead链表的尾节点prePtr的Next域指向postHead链表头结点的下一个节点
    postPtr.Next = nil                  // postPtr的尾节点的Next域指向空
    return preHead.Next                 // 返回preHead链表的Next之后的链表

Guess you like

Origin blog.csdn.net/m0_61926454/article/details/124413808