Facebook最新Libra币开发指南---接口服务器开发2

2024-02-02 12:32

本文主要是介绍Facebook最新Libra币开发指南---接口服务器开发2,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Facebook最新Libra币开发指南---接口服务器开发2

2019年06月24日 16:23:16 最老程序员闫涛 阅读数 1145

在上一篇博文中,我们已经使用Rust语言开发了一款简单的Web服务器,虽然以单线程方式工作,但是可以正确解析Libra Core的常见命令,完成了程序的基本框架,在这一篇文件中,我们将带领大家逐个实现这些命令,最后形成一个基本完整的程序,最后集成Libra Core的client工具中。这样我们就有一个Libra Core的Web接口,大家就可以将自己的应用系统第一时间移植到Libra Core,相信应该在绝对是Libra Core上的第一批应用,为明年Facebook推出的主网商用服务抢占有利的位置。

集成到命令行工具

我们首先需要将我们开发的Web服务器,集成到Libra Core Client中。首先打开libra/client/src/main.rs文件,将上一篇博文中的代码,除main函数外,全部拷贝到libra/client/src/main.rs文件中。
拷贝完成之后,我们首先编译运行一下Libra Core Client,以保证我们的程序没有编译错误,在libra目录下运行如下命令:

./scripts/cli/start_cli_testnet.sh
  • 1

在编译过程中会有一些警告信息,提示我们定义了一些函数而没有使用这些函数,因为我们定义的命令处理函数,确实没有调用过,所以我们可以暂时忽略这些警告信息。
接着我们在原来loop循环开始时调用启动我们服务器的方法,启动服务器,如下所示:

......let config = Config::builder().history_ignore_space(true).completion_type(CompletionType::List).auto_add_history(true).build();let mut rl = Editor::<()>::with_config(config);start_server(&mut client_proxy);/*loop {let readline = rl.readline("libra% ");match readline {Ok(line) => {......
*/
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

在上面的代码中,我们将client_proxy作为参数传入,实际上所有调用Libra Core功能的操作,均由此对象来实现。
重新编译运行客户端。我们应该可以看到Web服务器已经正常启动,在浏览器上输入http://127.0.0.1:7878/ls?cmd=query_balance&account_id=88 ,会显示如下所示的结果:
在这里插入图片描述
如果可以显示上述结果,就证明我们的Web服务器已经正常启动,并且可以正常接受和处理Libra Core的命令了。下面我们将在接收到客户端发送过来的命令之后,调用Libra Core相应接口,执行相应的逻辑,最后将调用结果返回给客户端。

改造启动方法和处理连接方法

由于我们要在Libra Core Client的模式下运行,我们的启动方法需要做出如下改动:

fn start_server(client_proxy: &mut ClientProxy) {println!("Libra Server v0.0.3 Starting up ...");let listener = TcpListener::bind("127.0.0.1:7878").unwrap();for stream in listener.incoming() {let stream = stream.unwrap();handle_connection(stream, client_proxy);}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

我们的连接处理方法需要做出如下改动:

fn handle_connection(mut stream: TcpStream, client_proxy: &mut ClientProxy) {let mut contents: String = String::from("Hello World!");let mut buffer = [0; 1024];// 获取请求信息stream.read(&mut buffer).unwrap();println!("Request: {}", String::from_utf8_lossy(&buffer[..]));let request = String::from_utf8_lossy(&buffer[..]);// 不处理请求网站图标请求if request.find("GET /favicon.ico HTTP/1.1") >= Some(0) {return ;}// 请出请求中的query stringlet query_string = &get_query_string(&request);println!("query_string:{}", query_string);let cmd = get_cmd_param(query_string.to_string());println!("接收到命令:cmd={}!", cmd);let params: Vec<_> = query_string.split("&").collect();if cmd.find("account_create")>=Some(0) {contents = handle_account_create(params, client_proxy);} else if cmd.find("account_list")>=Some(0) {contents = handle_account_list(params, client_proxy);} else if cmd.find("account_mint")>=Some(0) {contents = handle_account_mint(params, client_proxy);} else if cmd.find("query_balance")>=Some(0) {contents = handle_query_balance(params, client_proxy);} else if cmd.find("query_sequence")>=Some(0) {contents = handle_query_sequence(params, client_proxy);} else if cmd.find("transfer")>=Some(0) {contents = handle_transfer(params, client_proxy);} else if cmd.find("query_txn_acc_seq")>=Some(0) {contents = handle_query_txn_acc_seq(params, client_proxy);}let response = format!("HTTP/1.1 200 OK\r\n\r\n{}", contents);stream.write(response.as_bytes()).unwrap();stream.flush().unwrap();
}/**
* 获取请求中的Query String,规定参数以?cmd=开头
* @version v0.0.1 闫涛 2019.06.23
*/
fn get_query_string(request: &str) -> String {let pos = request.find("?cmd=");if pos <= Some(0) {return "Has no parameters in request".to_string();}let end_pos = request.find(" HTTP/1.1");return (&request[(pos.unwrap()+1)..end_pos.unwrap()]).to_string();
}/**
* 获取请求cmd参数值
* @version v0.0.1 闫涛 2019.06.23
*/
fn get_cmd_param(query_string: String) -> String {let params: Vec<_> = query_string.split("&").collect();for param in params.iter() {println!("item: {}!", param);if param.find("cmd=") >= Some(0) {let cmd = &param[4..];return cmd.to_string();}}return "".to_string();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65

与前一篇文章中的程序不同点在于,调用每个命令处理函数时,需将client_proxy作为参数传入。有了这些公共方法之后,我们就可以开始实现各个命令处理函数了。

账户生成

在命令行模式下,我们通过account create来创建账户,在我们的web服务器中我们通过http://127.0.0.1:7878/ls?cmd=account_create来创建账户,命令处理代码如下所示:

/**
* 生成账户命令处理函数
* @version v0.0.1 闫涛 2019.06.23
*/
fn handle_account_create(_params: Vec<&str>, client_proxy: &mut ClientProxy) -> String {println!("生成新账户!");let mut rst: String;match client_proxy.create_next_account() {Ok(account_data) => {rst = format!("{{\"account_id\": \"{}\", \"wallet_address\": \"{}\"}}", account_data.index, hex::encode(account_data.address));},Err(e) => rst = format!("Error creating account:{}", e),}return rst;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

在这个例子中使用了Rust的一种比较特别的语法,我们用match修饰调用client_proxy.create_next_account方法,该方法会返回Ok或Err两种情况,我们需要分别进行处理,大家可以将match 理解为其他语言中的switch语句。

查询所有账户列表

我们通过http://127.0.0.1:7878/ls?cmd=account_list请求来获取所有账户列表,命令处理函数如下所示:

/**
* 列出当前系统的所有账户
* @version v0.0.1 闫涛 2019.06.23
*/
fn handle_account_list(params: Vec<&str>, client_proxy: &ClientProxy) -> String {return client_proxy.get_all_accounts();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

我们在client/src/client_proxy.rs中添加一个新的函数,如下所示:

    /// Print index and address of all accounts.pub fn get_all_accounts(&self) -> String {let mut rst: String = String::new();rst.push_str("[");if !self.accounts.is_empty() {for (ref index, ref account) in self.accounts.iter().enumerate() {let mut item: String = String::new();item.push_str(&format!("{{\"account_id\":{}, \"wallet_address\":\"{}\", \"account_seq\":{}, \"account_status\":\"{:?}\"}},", index, hex::encode(&account.address), account.sequence_number, account.status));rst.push_str(&item);}}if let Some(faucet_account) = &self.faucet_account {println!("Faucet account address: {}, sequence_number: {}, status: {:?}",hex::encode(&faucet_account.address),faucet_account.sequence_number,faucet_account.status,);}rst.push_str("]");return rst;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

本来在官方程序中,有一个print_all_accounts方法,但是该方法只是将信息打印到屏幕上,这显然不是我们所需要的,所以我们重写了这个函数,将其返回值定义为Json字符串。

挖矿和发币

我们通过http://127.0.0.1:7878/ls?cmd=account_mint&account_id=1&num_coins=100来进行挖矿和发币,表明向编号为1的钱包发送100个Libra币,命令处理函数如下所示:

/**
* 挖指定数量的币发送给指定的账户
* @version v0.0.1 闫涛 2019.06.23
*/
fn handle_account_mint(params: Vec<&str>, client_proxy: &mut ClientProxy) -> String {let mut account_id: String = String::new();let mut num_coins: String = String::new();for param in params.iter() {if param.find("account_id=") >= Some(0) {account_id.push_str(&param[11..]);} else if param.find("num_coins=") >= Some(0) {num_coins.push_str(&param[10..]);}}println!("挖矿发币:account_id={}; num_coins={}!", account_id, num_coins);let cmd = format!("mint {} {}", account_id, num_coins);let params = ["mint", account_id.as_str(), num_coins.as_str()];match client_proxy.account_mint_coins(&params, false) {Ok(msg) => return msg,Err(_) => "{{\"status\": \"Error\"}}".to_string()}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

查询账户余额

我们通过http://127.0.0.1:7878/ls?cmd=query_balance&account_id=1来查询账户编号为1的账户的余额,命令处理函数如下所示:

/**
* 查询账户余额
* @version v0.0.1 闫涛 2019.06.23
*/
fn handle_query_balance(params: Vec<&str>, client_proxy: &mut ClientProxy) -> String {let mut account_id: String = String::new();for param in params.iter() {if param.find("account_id=") >= Some(0) {account_id.push_str(&param[11..]);} }println!("查询余额:account_id={};!", account_id);let params = ["balance", account_id.as_str()];match client_proxy.get_balance(&params) {Ok(num) => {let resp = format!("{{\"status\": \"Ok\", \"balance\": {} }}", num);return resp;},Err(_) => "{{\"status\": \"Error\"}}".to_string()}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

查询账户最新交易编号

我们通过http://127.0.0.1:7878/ls?cmd=query_sequence&account_id=1查询账户编号为1的账户的交易编号,注意这里只有资金转出时才产生交易,命令处理方法如下所示:

/**
* 查询指定账户的交易编号,即已经发生的交易数(指转出的笔数)
* @version v0.0.1 闫涛 2019.06.23
*/
fn handle_query_sequence(params: Vec<&str>, client_proxy: &mut ClientProxy) -> String {let mut account_id: String = String::new();for param in params.iter() {if param.find("account_id=") >= Some(0) {account_id.push_str(&param[11..]);}}println!("查询交易编号:account_id={};!", account_id);let params = ["sequence", account_id.as_str()];match client_proxy.get_sequence_number(&params) {Ok(seq) => {let resp = format!("{{\"status\": \"Ok\", \"sequence\": {} }}", seq);return resp;},Err(_) => "{{\"status\": \"Error\"}}".to_string()}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

转账

我们通过http://127.0.0.1:7878/ls?cmd=transfer&src_account_id=1&dest_account_id=2&amount=20来实现从账户1转20个Libra币给账户2,命令处理函数如下所示:

/**
* 账户之间转账
* @version v0.0.1 闫涛 2019.06.23
*/
fn handle_transfer(params: Vec<&str>, client_proxy: &mut ClientProxy) -> String {let mut src_account_id: String = String::new();let mut dest_account_id: String = String::new();let mut amount: String = String::new();for param in params.iter() {if param.find("src_account_id=") >= Some(0) {src_account_id.push_str(&param[15..]);} else if param.find("dest_account_id=") >= Some(0) {dest_account_id.push_str(&param[16..]);} else if param.find("amount=") >= Some(0) {amount.push_str(&param[7..]);}}println!("账户间转账交易:src_account_id={}; dest_account_id={}; amount={}!", src_account_id, dest_account_id, amount);let params = ["transfer", src_account_id.as_str(),dest_account_id.as_str(),amount.as_str()];match client_proxy.transfer_coins(&params, false) {Ok(ias) => {let resp = format!("{{\"status\": \"Ok\", \"account_index\": {}, \"account_number\": {} }}", ias.account_index, ias.sequence_number);return resp;},Err(_) => "{{\"status\": \"Error\"}}".to_string()}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

查询交易详细信息

我们通过http://127.0.0.1:7878/ls?cmd=query_txn_acc_seq&account_id=1&seq=1用来查询账户1的编号为1的交易的详情,命令处理函数如下所示:

/**
* 查询交易详情
* @version v0.0.1 闫涛 2019.06.23
*/
fn handle_query_txn_acc_seq(params: Vec<&str>, client_proxy: &mut ClientProxy) -> String {let mut account_id: String = String::new();let mut seq: String = String::new();for param in params.iter() {if param.find("account_id=") >= Some(0) {account_id.push_str(&param[11..]);} else if param.find("seq=") >= Some(0) {seq.push_str(&param[4..]);}}println!("查询交易详情:account_id={}; seq={}!", account_id, seq);let params = ["txn_acc_seq", account_id.as_str(), seq.as_str(), "false"];match client_proxy.get_committed_txn_by_acc_seq(&params) {Ok(rst) => {let mut resp = String::new(); //format!("{{\"status\": \"Ok\" }}");if let Some(obj) = rst {let trans = obj.0;resp.push_str(&trans.format_for_client(name_cb));}return resp;},Err(_) => "{{\"status\": \"Error\"}}".to_string()}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

这样,我们就拥有了一个与官方命令功能相等的Web API,虽然十分简陋,但是作为应用系统测试后台已经足够了,我们可以现在就开始构建基于Libra的应用系统,祝大家能抓住Libra的商机。

这篇关于Facebook最新Libra币开发指南---接口服务器开发2的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/670716

相关文章

服务器集群同步时间手记

1.时间服务器配置(必须root用户) (1)检查ntp是否安装 [root@node1 桌面]# rpm -qa|grep ntpntp-4.2.6p5-10.el6.centos.x86_64fontpackages-filesystem-1.41-1.1.el6.noarchntpdate-4.2.6p5-10.el6.centos.x86_64 (2)修改ntp配置文件 [r

这15个Vue指令,让你的项目开发爽到爆

1. V-Hotkey 仓库地址: github.com/Dafrok/v-ho… Demo: 戳这里 https://dafrok.github.io/v-hotkey 安装: npm install --save v-hotkey 这个指令可以给组件绑定一个或多个快捷键。你想要通过按下 Escape 键后隐藏某个组件,按住 Control 和回车键再显示它吗?小菜一碟: <template

Hadoop企业开发案例调优场景

需求 (1)需求:从1G数据中,统计每个单词出现次数。服务器3台,每台配置4G内存,4核CPU,4线程。 (2)需求分析: 1G / 128m = 8个MapTask;1个ReduceTask;1个mrAppMaster 平均每个节点运行10个 / 3台 ≈ 3个任务(4    3    3) HDFS参数调优 (1)修改:hadoop-env.sh export HDFS_NAMENOD

Andrej Karpathy最新采访:认知核心模型10亿参数就够了,AI会打破教育不公的僵局

夕小瑶科技说 原创  作者 | 海野 AI圈子的红人,AI大神Andrej Karpathy,曾是OpenAI联合创始人之一,特斯拉AI总监。上一次的动态是官宣创办一家名为 Eureka Labs 的人工智能+教育公司 ,宣布将长期致力于AI原生教育。 近日,Andrej Karpathy接受了No Priors(投资博客)的采访,与硅谷知名投资人 Sara Guo 和 Elad G

嵌入式QT开发:构建高效智能的嵌入式系统

摘要: 本文深入探讨了嵌入式 QT 相关的各个方面。从 QT 框架的基础架构和核心概念出发,详细阐述了其在嵌入式环境中的优势与特点。文中分析了嵌入式 QT 的开发环境搭建过程,包括交叉编译工具链的配置等关键步骤。进一步探讨了嵌入式 QT 的界面设计与开发,涵盖了从基本控件的使用到复杂界面布局的构建。同时也深入研究了信号与槽机制在嵌入式系统中的应用,以及嵌入式 QT 与硬件设备的交互,包括输入输出设

OpenHarmony鸿蒙开发( Beta5.0)无感配网详解

1、简介 无感配网是指在设备联网过程中无需输入热点相关账号信息,即可快速实现设备配网,是一种兼顾高效性、可靠性和安全性的配网方式。 2、配网原理 2.1 通信原理 手机和智能设备之间的信息传递,利用特有的NAN协议实现。利用手机和智能设备之间的WiFi 感知订阅、发布能力,实现了数字管家应用和设备之间的发现。在完成设备间的认证和响应后,即可发送相关配网数据。同时还支持与常规Sof

活用c4d官方开发文档查询代码

当你问AI助手比如豆包,如何用python禁止掉xpresso标签时候,它会提示到 这时候要用到两个东西。https://developers.maxon.net/论坛搜索和开发文档 比如这里我就在官方找到正确的id描述 然后我就把参数标签换过来

Retrieval-based-Voice-Conversion-WebUI模型构建指南

一、模型介绍 Retrieval-based-Voice-Conversion-WebUI(简称 RVC)模型是一个基于 VITS(Variational Inference with adversarial learning for end-to-end Text-to-Speech)的简单易用的语音转换框架。 具有以下特点 简单易用:RVC 模型通过简单易用的网页界面,使得用户无需深入了

秋招最新大模型算法面试,熬夜都要肝完它

💥大家在面试大模型LLM这个板块的时候,不知道面试完会不会复盘、总结,做笔记的习惯,这份大模型算法岗面试八股笔记也帮助不少人拿到过offer ✨对于面试大模型算法工程师会有一定的帮助,都附有完整答案,熬夜也要看完,祝大家一臂之力 这份《大模型算法工程师面试题》已经上传CSDN,还有完整版的大模型 AI 学习资料,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

Java 创建图形用户界面(GUI)入门指南(Swing库 JFrame 类)概述

概述 基本概念 Java Swing 的架构 Java Swing 是一个为 Java 设计的 GUI 工具包,是 JAVA 基础类的一部分,基于 Java AWT 构建,提供了一系列轻量级、可定制的图形用户界面(GUI)组件。 与 AWT 相比,Swing 提供了许多比 AWT 更好的屏幕显示元素,更加灵活和可定制,具有更好的跨平台性能。 组件和容器 Java Swing 提供了许多