White analog programming simple Bitcoin system, a wave of the hand and take you to write! (With code)

Author | VV smileヽ 

Zebian | Carol

Produced | block chain base camp (blockchain_camp)

Cover | CSDN pay to download the visual China

If there is a P2P D of emo, how can we apply them to block chain?

Together today to try to look at it!

First, we need to simulate a plurality of nodes in the network communicate with each other, we assume that the present situation is AB has two nodes throughout the process shown below:

Combing process

Let's sort out what the whole process, specifically in the P2P thing the network needs to be done.

  1. Start node A. A first create a block of Creation

  2. Create a wallet A1. A node is created API calls provided by a wallet, then the A1 Sphere currency is zero.

  3. A1 mining. A call to the node provided by mining API, to generate a new block, as well as the A1 coin purse with balls reward system.

  4. Starting a Node B. To A Node B synchronization information , the current block chain, currently trading pool, all current public purse.

  5. Create a wallet B1, A2, call the API Node A and B, to be broadcast (notify each node) to create a wallet out of (public) , there are only two nodes, so A need to tell B, A2 wallet. B need to tell A, B1 wallet.

  6. A1 transfers to B1. API A call to offer, while broadcast transaction .

  7. A2 mining accounting. API A call to offer, as well as broadcast a block of the new generation .

In summary, the node is added to the beginning of the block chain network, other nodes need to be synchronized

  • Block chain information

  • Wallet information

  • Trading Information

Has a node in the network, the need to notify other nodes in the network in the following cases

  • The new transaction

  • Create a new wallet

  • A new mining block

P2P general process for a few below, we will combine behind the realization of this process.

  1. client → server sends a message, typically request data;

  2. After the server receives a message, it sends a message to Client (call-Service, returns data processing);

  3. client received message processing data (call service, data processing).

The relevant code

In the implementation, since many types of message, encapsulates the message object used to transmit a message, the message type is encoded, unitary, the Message message object, implements Serializable interface, so that the object can be serialized:

public class Message implements Serializable {
/**
     * 消息内容,就是我们的区块链、交易池等所需要的信息,使用JSON.toString转化到的json字符串
     */
private String data;
/**
     * 消息类型
     */
private int type;
}

Related to the message type (Type) are:

/**
 * 查询最新的区块
 */
private final static int QUERY_LATEST_BLOCK = 0;
/**
 * 查询整个区块链
 */
private final static int QUERY_BLOCK_CHAIN = 1;
/**
 * 查询交易集合
 */
private final static int QUERY_TRANSACTION = 2;
/**
 * 查询已打包的交易集合
 */
private final static int QUERY_PACKED_TRANSACTION = 3;
/**
 * 查询钱包集合
 */
private final static int QUERY_WALLET = 4;
/**
 * 返回区块集合
 */
private final static int RESPONSE_BLOCK_CHAIN = 5;
/**
 * 返回交易集合
 */
private final static int RESPONSE_TRANSACTION = 6;
/**
 * 返回已打包交易集合
 */
private final static int RESPONSE_PACKED_TRANSACTION = 7;
/**
 * 返回钱包集合
 */
private final static int RESPONSE_WALLET = 8;

Because too many codes, not all stuck here, in order to synchronize other nodes wallet Client information, for example, in conjunction with the above P2P three-step network interactions, relevant realize introduce next.

1, client → server sends a message, the request data is typically

First created in the start node class Client Client object, call the Client internal methods, connection Server.

Main method starting class key code (Args disposed in the port parameters):

P2PClient p2PClient = new P2PClient();
String url = "ws://localhost:"+args[0]+"/test";       
p2PClient.connectToPeer(url);

P2PClientThe connectToPeermethod:

public void connectToPeer(String url) throws IOException, DeploymentException {
    WebSocketContainer container = ContainerProvider.getWebSocketContainer();
    URI uri = URI.create(url);
this.session = container.connectToServer(P2PClient.class, uri);
}

P2PClient, The WebSocketContainer.connectToServertime will callback onOpenfunction, we assume that only public information inquiry wallet, then the server will receive the corresponding request.

@OnOpen
public void onOpen(Session session) {
this.session = session;
    p2PService.sendMsg(session, p2PService.queryWalletMsg());
}

Note: I parse messages related operations package to a Service, a unified easy to use Server and Client. Gives the corresponding queryWalletMsgmethod:

public String queryWalletMsg() {
return JSON.toJSONString(new Message(QUERY_WALLET));
}

As well as the previously mentioned sendMsgmethods:

@Override
public void sendMsg(Session session, String msg) {
session.getAsyncRemote().sendText(msg);
}

2, S erver after receiving the message, sending a message to the Client ( call S ervice, returns processed data )

Server receives the message , enter P2PServerthe OnMessagemethod

/**
 * 收到客户端发来消息
 * @param msg  消息对象
 */
@OnMessage
public void onMessage(Session session, String msg) {
    p2PService.handleMessage(session, msg);
}

p2PService.handleMessageIt is the message (Msg) parsing the received, according to other methods of different types of calls (a giant Switch statement here introduce a small part), where we received the information code Client coming QUERY_WALLET.

@Override
public void handleMessage(Session session, String msg) {
    Message message = JSON.parseObject(msg, Message.class);
switch (message.getType()){
case QUERY_WALLET:
            sendMsg(session, responseWallets());
break;
case RESPONSE_WALLET:
            handleWalletResponse(message.getData());
break;
            ......
    }

The information code is a QUERY_WALLETcalling  responseWallets()method, to obtain data .

private String responseWallets() {
String wallets = blockService.findAllWallets();
return JSON.toJSONString(new Message(RESPONSE_WALLET, wallets));
}

Here I put the block chain of related operations also encapsulate a Service, the following are given findAllWalletsconcrete realization, in fact, traversing a collection of purses, wallets public statistics, there is no difficulty.

@Override
public String findAllWallets() {
    List<Wallet> wallets = new ArrayList<>();
    myWalletMap.forEach((address, wallet) ->{
        wallets.add(Wallet.builder().publicKey(wallet.getPublicKey()).build());
    });
    otherWalletMap.forEach((address, wallet) ->{
        wallets.add(wallet);
    });
return JSON.toJSONString(wallets);
}

After obtaining the data, and return to the Client:

So our  responseWallets()approach, the last sentence created a Message object and set the information code RESPONSE_WALLETin handleMessagethe called sendmsgmethod back to the Client.

case QUERY_WALLET:
        sendMsg(session, responseWallets());
        break;

. 3, C Lien T received message data (call Service, data processing)

Client requests received data obtained into P2PClientthe OnMessagemethod:

@OnMessage
public void onMessage(String msg) {
    p2PService.handleMessage(this.session, msg);
}

Also enter our above-mentioned p2PService.handleMessagemethod, this time received information code RESPONSE_WALLETinto the handleWalletResponsemethod:

case RESPONSE_WALLET:
        handleWalletResponse(message.getData());
        break;

handleWalletResponseImplementation, parsing the received information to the public key wallet, and storing the Client node blockServicein.

private void handleWalletResponse(String msg) {
    List<Wallet> wallets = "\"[]\"".equals(msg)?new ArrayList<>():JSON.parseArray(msg, Wallet.class);
    wallets.forEach(wallet -> {
        blockService.addOtherWallet(walletService.getWalletAddress(wallet.getPublicKey()),wallet );
    });
}

When the specific implementation, due to the way the use of injection services, use annotations to @Autowired Server (@ServerEndpoint) and Client (@ClientEndpoint) injected Bean, features Spring Boot singleton due.

And every time Websocket create a new object, so when using the service will result in a null pointer exception, therefore, we have created a tool like Spring til, every time in need of services are available from the Spring container to us desired Bean, tools class code is given below.

public class SpringUtil implements ApplicationContextAware {
public static ApplicationContext applicationContext;
    @Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
if (SpringUtil.applicationContext != null) {
            SpringUtil.applicationContext = applicationContext;
        }
    }
/**
     * 获取applicationContext
     */
public static ApplicationContext getApplicationContext() {
return applicationContext;
    }

/**
     * 通过name获取 Bean.
     */
public static Object getBean(String name) {
return getApplicationContext().getBean(name);
    }
/**
     * 通过class获取Bean.
     */
public static <T> T getBean(Class<T> clazz) {
return getApplicationContext().getBean(clazz);
    }

/**
     * 通过name,以及Clazz返回指定的Bean
     */
public static <T> T getBean(String name, Class<T> clazz) {
return getApplicationContext().getBean(name, clazz);
    }
}

So we need to set before the test SpringUtilis applicationContextgiven below class start (for a simple test, class two nodes share a boot, respectively, according to the processing of different Args) configuration and the relevant node.

public static void main(String[] args) {
    System.out.println("Hello world");
    SpringUtil.applicationContext  = SpringApplication.run(Hello.class, args);
if (args.length>0){
        P2PClient p2PClient = new P2PClient();
        String url = "ws://localhost:"+args[0]+"/test";
try {
            p2PClient.connectToPeer(url);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

In use, we need to manually get Bean :

//之前是这样//@Autowired//private P2PService p2PService;//改正后,去掉Autowired,每次使用都手动获取beanprivate P2PService p2PService;@OnOpenpublic void onOpen(Session session) {//如果不使用那些,在这里会报空指针异常,p2PService 为 null p2PService = SpringUtil.getBean(P2PService.class);//新增这句话从IVO容器中获取bean p2PService.sendMsg(session, p2PService.queryWalletMsg());}

Hello node, when tested as a Server:

Test node, when tested as a Client.

This, we realize the interaction P2P network node in Server and Client node. I suggest you can try, and then we discuss in the comments area and Oh!

Recommended Reading 

do not have a hair out! With Flutter + Dart quickly build a beautiful mobile App

Look what I found a good thing? Java Optional, definitely worth learning | Force program

Tencent combined ACNet mention fine-grained classification, the effect is up to the latest SOTA | CVPR 2020

My favorite cloud IDE recommendation!

advanced features Solidity written contract of intelligence

return E staff to return to work readme: back to work, Wuhan, Hefei fly first, then go back and pick chartered by the company

You look at every point, I seriously as a favorite

Released 1830 original articles · won praise 40000 + · Views 16,540,000 +

Guess you like

Origin blog.csdn.net/csdnnews/article/details/104890435