主页 > imtoken钱包怎么下载 > 比特币开源代码公开编程小白模拟一个简单的比特币系统,带你写一波!

比特币开源代码公开编程小白模拟一个简单的比特币系统,带你写一波!

imtoken钱包怎么下载 2023-01-28 07:40:14

出品 | 区块链大本营()

封面 | 视觉中国CSDN付费下载

如果有p2p demo,我们如何将它应用到区块链上呢?

今天就来试试吧!

首先,我们需要模拟多个节点在网络中相互通信。 我们假设当前的情况是有两个节点AB。 整个过程如下图所示:

梳理工序

让我们看一下将比特币开源代码公开的整个过程,并阐明在 p2p 网络中需要做什么。

启动节点A。A首先创建一个创世块来创建钱包A1。 调用节点A提供的API创建钱包。 此时A1的球币为0。A1挖矿。 调用A节点提供的挖矿API生成新区块,同时系统奖励A1钱包中的球币。 启动节点B,节点B需要和A同步信息,当前区块链,当前交易池,当前所有钱包的公钥。 创建钱包B1和A2,调用节点A和B的API,广播(通知各节点)创建的钱包(公钥),目前只有两个节点,所以A需要告诉B,A2的钱包。 B需要告诉A,B1的钱包。 A1 转账给 B1。 调用A提供的API,同时广播交易。 A2 矿业会计。

综上所述,当一个节点刚加入区块链网络时,需要同步其他节点的数据。

已经在网络中的节点在以下情况下需要通知网络中的其他节点

P2P的大致流程如下,我们后续的实现会结合这个流程。

比特币开源代码公开_比特币开源代码查询_比特币开源代码怎么找

Client→Server发送消息,一般是请求数据。 服务端收到消息后,将消息发送给客户端(调用服务,处理后返回数据)。 客户端接收消息并处理数据(调用服务Bitcoin open source code is open, processing the data)

相关代码

在实现过程中,由于消息类型较多,封装了一个消息对象来传递消息,并对消息类型进行编码统一处理。 消息对象 Message 实现了使对象可序列化的接口:

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

涉及的消息类型有:

/**
 * 查询最新的区块
 */
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;

由于代码太多,这里就不一一贴出来了。 以客户端同步其他节点钱包信息为例,结合上述p2p网络交互的三个步骤,介绍相关实现。

1.client→server发送消息,一般是请求数据

在客户端节点的启动类中,首先创建客户端对象,调用客户端的内部方法,连接到服务器端。

比特币开源代码查询_比特币开源代码怎么找_比特币开源代码公开

启动类的main方法中的关键代码,(端口参数在args中配置):

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

中的方法

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

,onOpen函数就会在。假设我们只查询钱包公钥信息,服务器就会收到相应的请求。

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

注:我将解析消息相关的操作封装成一个服务,方便服务端和客户端统一使用。 给出相应的方法:

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

和前面提到的 sendMsg 方法:

比特币开源代码公开_比特币开源代码怎么找_比特币开源代码查询

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

2、服务端收到消息后,向客户端发送消息(调用服务,处理后返回数据)

服务端收到消息,进入方法

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

. 就是解析接收到的消息(msg),根据类型调用其他方法(庞大的switch语句,这里只介绍一小部分),这里我们接收客户端的信息代码。

@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;
            ......
    }

根据信息码,调用()方法获取数据。

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

这里,我也把区块链的相关操作封装成一个服务。 下面给出的具体实现其实就是遍历钱包集合,统计钱包公钥,并不难。

比特币开源代码查询_比特币开源代码怎么找_比特币开源代码公开

@Override
public String findAllWallets() {
    List 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);
}

拿到数据后返回给客户端:

因此,在我们的()方法中,在最后一句中新建了一个消息对象,并设置了信息编码为,并在其中调用了sendmsg方法返回给客户端。

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

3、客户端接收消息并处理数据(调用服务处理数据)

客户端收到请求的数据,输入法

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

同样输入我们上面提到的.method,此时收到的信息代码是,enter method

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

实现,解析接收到的钱包公钥信息模拟比特币,存储在客户端节点。

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

在具体实现中,由于注入服务的方式,在使用@注解向服务端(@)和客户端(@)注入bean时,由于Spring boot单例的特性,每次都会创建一个新的对象时间,所以使用服务,会导致空指针异常。 因此,我们创建了一个实用程序类。 每次我们需要一个服务时,我们从 Spring 容器中获取我们需要的 bean。 工具类代码如下。

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

因此,在测试之前,我们需要先进行设置。 下面给出启动类(为了简单测试,两个节点共用一个启动类,根据args分别处理)和相关节点的配置。

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();
        }
    }

使用时,我们需要手动获取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());}

你好节点,在测试时用作服务器

测试节点在测试期间用作客户端。

至此,我们就实现了p2p网络中server节点和client节点的交互过程。 我建议您尝试一下并在评论中与我们讨论!

挖矿网Ethos中文网拥有简单易用的挖矿系统,为挖矿行业提供教程软件和矿机评测及交易信息,对比计算各种数字货币在挖矿网的挖矿收益,以及介绍矿网挖矿工具,矿场最新动态等。

矿业网络,版权所有丨如未注明,均为原创丨本站采用BY-NC-SA协议授权

转载请注明原文链接:比特币开源代码开放编程小白模拟一个简单的比特币系统模拟比特币,带你写一波! (带代码) | 特色博客