币燕在开发数字货币交易所的过程中,有两大难点,一是高速撮合交易引擎,二是钱包对接,这是我们团队之前没有处理过的。本系列文章主要介绍数字货币交易所钱包对接的实现技术。首先要连接的是比特币BTCbtc t提币,因为BTC的提现过程比较简单。用户在交易所提交提现请求,由交易所审核后,系统或人工发币。
交易所如何连接到 比特币 钱包
交易所连接比特币钱包有两种方式:
1. 自建BTC节点
BTC节点支持通过RPC访问,所以自建节点可以快速查询区块和交易。但是由于BTC节点会同步所有的区块,所以到现在为止(2018/09/10)的区块高度已经达到了,所以这需要很大的硬盘存储空间,2016年至少160G。如果每各个币种自建节点,占用大量硬盘存储空间,还要承担维护节点的工作,创业团队对资金的合理使用要求比较高,所以我们放弃了这种方式,采用了第一种方法,两种方法。
2. 第三方API+区块链浏览器
通过第三方API可以对Bit钱包进行操作,如生成密钥对、玩币等。同时也可以通过区块链浏览器提供的开放接口进行交易查询。因此,我们的团队采用这种方式连接到 比特币 钱包。
比特币钱包知识点
1.比特币钱包密钥生成
这里需要了解的知识点是比特币钱包:首先比特币钱包可以离线生成,通过一系列的加密操作,不介意的话可以也可以自己实现,但是不需要重复创建;其次,比特币钱包的离线生成也可以保证不重复。你不必担心比特币地址用完,因为理论上比特币钱包可以生成的地址数量超过了宇宙中所有原子的总和,所以担心离线生成的钱包地址和其他人重复这个完全不用担心。
2.比特币网络中没有账户概念
如果你接触过以太坊,你就会知道以太坊有账户的概念。账户的概念更接近我们的现实生活。使用帐户,您可以查看余额。但是比特币没有这样的概念,有兴趣的可以研究一下比特币中的UTXO。比特币只有交易,所以你很好奇,如果你只有流水账,你怎么知道一个地址的余额?比特币 是通过计算您钱包地址的所有转入和所有转出之间的差额来计算的。你可能还想问,10比特币s 转账到某个地址的流程是什么?首先,比特币 网络会计算你当前的余额,看是否足够转账。如果足够了,那么 比特币 网络会把之前转账到你的地址的交易叫做input,也就是input,然后再把你的交易转账到你的地址。交易转移到其他地址作为输出,即。我们可以通过区块链浏览器提供的API查询如下结果:
{
"hash":"b6f6991d03df0e2e04dafffcd6bc418aac66049e2cd74b80f14ac86db1e3f0da",
"ver":1,
"vin_sz":1,
"vout_sz":2,
"lock_time":"Unavailable",
"size":258,
"relayed_by":"64.179.201.80",
"block_height, 12200,
"tx_index":"12563028",
"inputs":[
{
"prev_out":{
"hash":"a3e2bcc9a5f776112497a32b05f4b9e5b2405ed9",
"value":"100000000",
"tx_index":"12554260",
"n":"2"
},
"script":"76a914641ad5051edd97029a003fe9efb29359fcee409d88ac"
}
],
"out":[
{
"value":"98000000",
"hash":"29d6a3540acfa0a950bef2bfdc75cd51c24390fd",
"script":"76a914641ad5051edd97029a003fe9efb29359fcee409d88ac"
},
{
"value":"2000000",
"hash":"17b5038a413f5c5ee288caa64cfab35a0c01914e",
"script":"76a914641ad5051edd97029a003fe9efb29359fcee409d88ac"
}
]
}
查询链接:
以上是查询一个事务()的结果,可以看到int和out包含多个结果。
交易所充值逻辑设计
上图是交易所充值逻辑的设计图。以下是该过程的简要说明:
首先,我们通过比特币钱包API批量生成10000个比特币钱包地址。当用户在交易所获得自己的BTC充值地址时,我们从这10000个地址中给他分配一个(地址绑定UID)
然后,我们会提前运行一个监控任务程序。该程序负责从比特币区块链浏览器获取**的区块信息,然后解析交易中涉及的地址。当分配的地址出现在发现地址中时btc t提币,我们将 BTC 余额添加到与该地址绑定的用户资产表中。
**提醒用户充值。
实现方法代码演示(Java)
1. 通过第三方钱包 API 生成 比特币 地址:
这里我们使用开源代码,通过maven导入这个库,示例代码如下
import java.io.File;
import java.io.IOException;
import org.bitcoinj.core.ECKey;
import org.bitcoinj.core.NetworkParameters;
import org.bitcoinj.params.TestNetarams;
import org.bitcoinj.wallet.Wallet;
/**
* 演示生成/保存密钥对和钱包地址到文件
* @author bizzan.com
*
*/
public class GenerateKeyPair {
public static void main(String[] args) {
// 如在主网中生成钱包密钥对,需要改为MainNetParms
NetworkParameters params = TestNetarams.get();
Wallet wallet = null;
// 创建一个文件用于保存钱包文件
final File walletFile = new File("test.wallet");
wallet = new Wallet(params);
// 循环生成10个密钥对并添加到钱包
for(int i = 0; i < 10000; i++) {
ECKey key = new ECKey();
wallet.importKey(key);
}
try {
// 保存钱包文件
wallet.saveToFile(walletFile);
// 打印钱包内容信息
System.out.println(wallet.toString(true, true, true, null));
} catch (IOException e) {
e.printStackTrace();
}
}
}
使用此代码,您可以生成 10,000 个钱包地址,您可以将其保存在文件中。在实际应用中,您还需要在数据库中保存 10,000 个钱包地址,但不能将私钥保存在联网数据库中。
您保存到文件中的钱包内容可以通过以下代码读取:
import java.io.File;
import org.bitcoinj.core.ECKey;
import org.bitcoinj.core.NetworkParameters;
import org.bitcoinj.params.TestNetarams;
import org.bitcoinj.wallet.UnreadableWalletException;
import org.bitcoinj.wallet.Wallet;
/**
* 从文件导入钱包,注意需要先运行GenerateKeyPair生成钱包文件
* @author bizzan.com
*
*/
public class ImportWalletFromFile {
public static void main(String[] args) {
// 如在主网中生成钱包密钥对,需要改为MainNetParms
NetworkParameters params = TestNetarams.get();
Wallet wallet = null;
// 创建一个文件用于保存钱包文件
final File walletFile = new File("test.wallet");
try {
// 从文件加载钱包
wallet = Wallet.loadFromFile(walletFile);
// 打印钱包信息
System.out.println(wallet.toString(true, true, true, null));
// 获取钱包第一个密钥对
ECKey firstKey = wallet.getImportedKeys().get(0);
// 打印密钥对信息
System.out.println("The first key is: \n" + firstKey.toString());
// 打印密钥对中的私钥(HEX)
System.out.println("The first key Private Key(HEX) is: " + firstKey.getPrivateKeyAsHex());
// 打印密钥对中的私钥(WIF=Wallet Import Format)
System.out.println("The first key Private Key(WIF) is: " + firstKey.getPrivateKeyAsWiF(params));
// 打印密钥对中的公钥:
System.out.println("The first key Public Key is: " +firstKey.getPubKey());
// 打印密钥对中的公钥(HEX)
System.out.println("The first key Public Key(HEX) is: " + firstKey.getPublicKeyAsHex());
// 打印密钥对中的公钥(Hash)
System.out.println("The first key Public Key(Hash) is: " + firstKey.getPubKeyHash());
// 打印密钥对钱包地址
System.out.println("The first key Wallet Address is: " + firstKey.toAddress(params));
// 通过公钥查找密钥对:findKeyFromPubHash(byte[] pubkeyHash)
ECKey resultKey1 = wallet.findKeyFromPubHash(firstKey.getPubKeyHash());
System.out.println("Find Key From PubHash: " + resultKey1.toString());
// 判断公钥是否在钱包:isPubKeyHashMine(byte[] pubkeyHash)
System.out.println("Is PubKeyHash Mine: " + wallet.isPubKeyHashMine(firstKey.getPubKeyHash()));
// 通过公钥查找密钥对:findKeyFromPubKey(byte[] pubkey)
ECKey resultKey2 = wallet.findKeyFromPubKey(firstKey.getPubKey());
System.out.println("Find Key From PubKey: " + resultKey2.toString());
// 判断公钥是否在钱包:isPubKeyMine(byte[] pubkey)
System.out.println("Is PubKey Mine: " + wallet.isPubKeyMine(firstKey.getPubKey()));
} catch (UnreadableWalletException e) {
e.printStackTrace();
}
}
}
2. 通过区块链浏览器监控钱包地址:
通过轮询,比如每隔1小时查询区块链浏览器获取**的区块信息,然后解析其中的地址信息,示例代码如下:
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import org.apache.http.HttpEntity;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import com.alibaba.faston.ONArray;
import com.alibaba.faston.ONObject;
/**
* 演示通过Blockchain.info提供的ON Http获取比特币区块信息
* @author bizzan.com
*
*/
public class ApiApp {
private final static String requstHttpUrl = "https://blockchain.info/";
public static void main(String[] args) {
String param = "block-height/500000?format=on";
String result = sendGet(requstHttpUrl, param);
ONObject onObject = ONObject.parseObject(result);
ONArray arr = onObject.getONArray("blocks");
ONArray txList = arr.getONObject(0).getONArray("tx");
for(int i = 0; i < txList.size(); i++) {
ONObject txObj = txList.getONObject(i);
ONArray outs = txObj.getONArray("out");
for(int j = 0; j < outs.size(); j++) {
ONObject outObj = outs.getONObject(j);
// 这里已获取交易信息(包含收币地址信息),由此可将此地址与充值地址库对比,进行充值后续工作
System.out.println("tx_index:" + outObj.getIntValue("tx_index") + " - addr:" + outObj.getString("addr"));
}
}
}
public static String sendGet(String url, String param) {
CloseableHttpClient httpClient = null;
CloseableHttpResponse response = null;
String result = "";
try {
httpClient = HttpClients.createDefault();
HttpGet httpGet = new HttpGet(url + param);
RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(35000)
.setConnectionRequestTimeout(35000)
.setSocketTimeout(60000)
.build();
httpGet.setConfig(requestConfig);
response = httpClient.execute(httpGet);
HttpEntity entity = response.getEntity();
result = EntityUtils.toString(entity);
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} final {
if (null != response) {
try {
response.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (null != httpClient) {
try {
httpClient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return result;
}
}
上面的代码是获取高度为 的块信息,并解析其中的地址。
本站声明:网站内容来源于网络,如有侵权,请联系我们,我们将及时删除。
文章链接:https://www.btchangqing.cn/444732.html
更新时间:2023年01月20日
本站大部分内容均收集于网络,若内容若侵犯到您的权益,请联系我们,我们将第一时间处理。