比特币开发原理浅析
2017-07-05 00:00
253 查看
随着勒索病毒的爆发,比特币更是近一步的被人们接触,机缘巧合之下,从大四开始接触比特币钱包的后台开发,我只做简单的介绍。
比特币终端是一个跨平台的软件,运行在windows ,linux ,移动设备上,本文以Windows平台为例。
服务器:windows 2012 server . Bitcoin Core . 由于同步钱包需要很多时间,并且现在同步容量应该在200G内(我最近一次是160g).
先上图
你的钱包只是在官网上下载的一个客户端,每个钱包可以生成N个钱包地址,从别的钱包转账可以转到这N个地址中的一个,你最先收到钱包转账的通知,也就是确认数为1,但是这个时候区块链还没有发出确认通知,当确认数>=2的时候可以认为转账成功了。
钱包服务器配置:
下面是一个简单的和钱包服务器进行rpc通讯的类
下面简述开发过程中经常用到的方法:
查询钱包状态
生成钱包地址
对外转账
收取转账信息
由于接触虚拟币开发比较多,因此对这个略有了解,虚拟币开发我几乎没找到什么文档,希望给广大的爱好者来一发!
rpc接口列表#
比特币终端是一个跨平台的软件,运行在windows ,linux ,移动设备上,本文以Windows平台为例。
服务器:windows 2012 server . Bitcoin Core . 由于同步钱包需要很多时间,并且现在同步容量应该在200G内(我最近一次是160g).
先上图
你的钱包只是在官网上下载的一个客户端,每个钱包可以生成N个钱包地址,从别的钱包转账可以转到这N个地址中的一个,你最先收到钱包转账的通知,也就是确认数为1,但是这个时候区块链还没有发出确认通知,当确认数>=2的时候可以认为转账成功了。
钱包服务器配置:
// 文件在家目录会有一个bitcoin文件夹 ,新建一个bitcoin.conf // 下面4个注释的是最重要的。 listen=1 server=1 daemon=1 rpcuser=user # rpc 通讯用户的账号 rpcpassword=password # rpc 密码 rpcallowip=127.0.0.1 # rpc 允许接受哪一个ip的消息 rpcport=8333 # rpc 端口 rpcallowip=122.114.20.103 addnode=122.114.20.103
下面是一个简单的和钱包服务器进行rpc通讯的类
<?php namespace App\Coin\Client; class CoinClient { // 钱包服务器ip private $url; // 连接超时时间 private $timeout; // 钱包服务器 用户名 private $username; // 钱包服务器密码 private $password; public $is_batch = false; public $batch = array(); public $debug = false; public $jsonformat = false; public $res = ''; private $headers = array('User-Agent: github.com Rpc', 'Content-Type: application/json', 'Accept: application/json', 'Connection: close'); public $ssl_verify_peer = true; public function __construct($username, $password, $ip, $port, $timeout = 3, $headers = array(), $jsonformat = false) { $this->url = 'http://' . $ip . ':' . $port; $this->username = $username; $this->password = $password; $this->timeout = $timeout; $this->headers = array_merge($this->headers, $headers); $this->jsonformat = $jsonformat; } /** * 这里通过魔术方法调用api * 比如 $client->getinfo() ; 可以直接获取到getinfo方法, * @param $method * @param array $params * @return string */ public function __call($method, array $params) { if ((count($params) === 1) && is_array($params[0])) { $params = $params[0]; } $res = $this->execute($method, $params); $this->debug(array('method' => $method, 'params' => $params, 'res' => $res)); return $res ? $res : $this->res; } /** * 构造参数 * @param $procedure * @param array $params * @return string */ public function execute($procedure, array $params = array()) { return $this->doRequest($this->prepareRequest($procedure, $params)); } /** * 构造 发送的内容 * @param $procedure * @param array $params * @return array */ public function prepareRequest($procedure, array $params = array()) { $payload = array('jsonrpc' => '2.0', 'method' => $procedure, 'id' => mt_rand()); if (!empty($params)) { $payload['params'] = $params; } return $payload; } /** * 执行 rpc 请求 * @param array $payload * @return string * @throws \Exception */ private function doRequest(array $payload) { $stream = @fopen(trim($this->url), 'r', false, $this->getContext($payload)); if (!is_resource($stream)) { throw new \Exception('钱包链接失败') ; } $metadata = stream_get_meta_data($stream); // 服务器响应内容 . $response = json_decode(stream_get_contents($stream), true); $header_1 = $metadata['wrapper_data'][0]; preg_match('/[\\d]{3}/i', $header_1, $code); $code = trim($code[0]); // 返回的状态值 . if ($code == '200') { // 这段就是服务器返回的信息 . return isset($response['result']) ? $response['result'] : 'nodata'; } else { if ($response['error'] && is_array($response['error'])) { $detail = 'code=' . $response['error']['code'] . ',message=' . $response['error']['message']; throw new \Exception($detail) ; } else { throw new \Exception($code) ; } } } /** * 获取上下文 * @param array $payload * @return resource */ private function getContext(array $payload) { $headers = $this->headers; // 用户名密码 认证过程 if (!empty($this->username) && !empty($this->password)) { $headers[] = 'Authorization: Basic ' . base64_encode($this->username . ':' . $this->password); } // 请求内容 $context = stream_context_create(array( 'http' => array('method' => 'POST', 'protocol_version' => 1.1000000000000001, 'timeout' => $this->timeout, 'max_redirects' => 2, 'header' => implode("\r\n", $headers), 'content' => json_encode($payload), 'ignore_errors' => true ), // ssl 证书 'ssl' => array('verify_peer' => $this->ssl_verify_peer, 'verify_peer_name' => $this->ssl_verify_peer) )); return $context ; } }
下面简述开发过程中经常用到的方法:
查询钱包状态
生成钱包地址
对外转账
收取转账信息
<?php class HandleClient{ // 客户端 private $client ; public function __construct() { $host = "127.0.0.1" ; // 钱包地址,本地开发通常是本机 本地开发可以用轻量级的山寨币钱包, $user = 'user'; $password = 'password'; $port = '6300'; $this->client = new Client($host ,$user ,$password ,$port ,30); } /** * 给站内用户生成一个 地址 ,表结构大致如下 * -------------------------------- * id | address | username * --------------------------------- * @param $label 用户->address 一对多的关系 * @return bool|mixed */ public function createAddress($label) { // 这步骤是获取这个标签的钱包地址,如果已经存在则返回, $address = $this->client->getaddressesbyaccount($label); if(!is_array($address)){ $address = $this->client->getnewaddress($label); if(!$address){ return false ; } }else{ $address = $address [0]; } return $address ; } /** * 将币转出,平台会有转出币钱包场景,在这之前需要判断是否是站内互转 * 在这之前需要判断是否是一个有效的钱包地址 * 该步骤通常以后台任务队列运行 */ public function turnout($address,$number) { // 判断是否是一个有效的钱包地址 $isAddr = $this->client->validateaddress($address); if(!$isAddr){ return false; } // 获取钱包的余额 $info = $this->client->getinfo(); if($info['balance'] < $number ){ return false ; } // 发送接口 return $this->client->sendtoaddress($address, $number ); } /** * 交易查询接口. */ public function trade() { // 该方法 有3个参数,第一个是指查询标签的意思* 查找所有用户 123456 ,查找123456的交易情况 $list = $this->client->listtransactions("*",100,0); foreach($list as $key => $val){ if($val ['category'] == 'receive'){ // 接受的交易 $this->handleReceive($val); }elseif($val ['category'] == 'send'){ // 发送的交易 $this->handleSend($val); } } } // 这里是系统用户向平台充币的处理, // 由于充币事先是不知道的,这里需要动态生成订单 // txid 是交易的唯一编号 注意启动事务 private function handleReceive($item) { $address = DB::table('address')->where(['address' => $item['address']])->get(); if(!$address){ return ; } $row = DB::table('trade')->where(['txid' => $item['txid'] , 'status' => 0 , 'type' => 'receive'])->get(); if($row){ // 如果有订单,判断确认次数 if($item['confirmations'] >= 2){ $row->save(['status' => 1 , 'confirmations' => $item['confirmations']]); // 给用户加钱 $user = $address->user()->increment('coin', $item['amount']); } }else{ $arr = [ 'confirmations' => $item['confirmations'], 'user_id' => $address->user->id , 'amount' => $item['amount'], 'txid' => $item['txid'], ]; if($item['confirmations'] >= 2){ $arr ['status'] = 1 ; $user = $address->user()->increment('coin', $item['amount']); }else{ $arr ['status'] = 0; } DB::table('trade')->create($arr); } } // 处理转出情况,转出是用户发起的,不需要动态插表 private function handleSend($item) { $row = DB::where(['address' => $item['address']])->get(); if(!$row){ return ; } if($item['confirmations'] >= 2){ $row->save(['status' => 1,'txid' => $item['txid'] , 'confirmations' => $item['confirmations']]); // 可能需要处理用户币的冻结情况, } } }
由于接触虚拟币开发比较多,因此对这个略有了解,虚拟币开发我几乎没找到什么文档,希望给广大的爱好者来一发!
rpc接口列表#
addmultisigaddress <nrequired> <'["key","key"]'> [account] addnode <node> <add|remove|onetry> backupwallet <destination> createmultisig <nrequired> <'["key","key"]'> createrawtransaction [{"txid":txid,"vout":n},...] {address:amount,...} decoderawtransaction <hex string> dumpprivkey <chinacoinaddress> encryptwallet <passphrase> getaccount <chinacoinaddress> getaccountaddress <account> getaddednodeinfo <dns> [node] getaddressesbyaccount <account> getbalance [account] [minconf=1] getbestblockhash getblock <hash> [verbose=true] getblockcount getblockhash <index> getblocktemplate [params] getconnectioncount getdifficulty getgenerate gethashespersec getinfo getmininginfo getnetworkhashps [blocks] [height] getnewaddress [account] getpeerinfo getrawmempool getrawtransaction <txid> [verbose=0] getreceivedbyaccount <account> [minconf=1] getreceivedbyaddress <chinacoinaddress> [minconf=1] gettransaction <txid> gettxout <txid> <n> [includemempool=true] gettxoutsetinfo getwork [data] getworkex [data, coinbase] help [command] importprivkey <chinacoinprivkey> [label] [rescan=true] keypoolrefill listaccounts [minconf=1] listaddressgroupings listlockunspent listreceivedbyaccount [minconf=1] [includeempty=false] listreceivedbyaddress [minconf=1] [includeempty=false] listsinceblock [blockhash] [target-confirmations] listtransactions [account] [count=10] [from=0] listunspent [minconf=1] [maxconf=9999999] ["address",...] lockunspent unlock? [array-of-Objects] move <fromaccount> <toaccount> <amount> [minconf=1] [comment] sendfrom <fromaccount> <tochinacoinaddress> <amount> [minconf=1] [comment] [comment-to] sendmany <fromaccount> {address:amount,...} [minconf=1] [comment] sendrawtransaction <hex string> sendtoaddress <chinacoinaddress> <amount> [comment] [comment-to] setaccount <chinacoinaddress> <account> setgenerate <generate> [genproclimit] setmininput <amount> settxfee <amount> signmessage <chinacoinaddress> <message> signrawtransaction <hex string> [{"txid":txid,"vout":n,"scriptPubKey":hex,"redeemScript":hex},...] [<privatekey1>,...] [sighashtype="ALL"] stop submitblock <hex data> [optional-params-obj] validateaddress <chinacoinaddress> verifychain [check level] [num blocks] verifymessage <chinacoinaddress> <signature> <message>
相关文章推荐
- PHPCMS2008源码浅析-模板原理分析 PHPCMS20008二次开发
- 浅析杀毒软件开发原理(之查毒引擎)
- PHPCMS2008源码浅析-模板原理分析 PHPCMS20008二次开发
- 浅析 微信公共平台消息 开发原理
- 比特币开发专题(挖矿的原理和发展方向)
- 【小松教你手游开发】【面试必读(编程基础)】.NET垃圾回收:原理浅析
- Unity手游开发札记——布料系统原理浅析和在Unity手游中的应用
- 浅析杀毒软件开发原理 转载
- 浅析杀毒软件开发原理
- 比特币深层技术原理浅析
- 【新手】浅析比特币、区块链原理。值钱 分布式 链式存储数据库 记账 以太坊
- 浅析杀毒软件开发原理
- Java开发Dubbo分布式框架使用及原理浅析
- PHPCMS2008源码浅析-Cache原理分析 PHPCMS20008二次开发
- 热门Web开发方式 REST实现原理浅析
- 【小松教你手游开发】【面试必读(编程基础)】.NET垃圾回收:原理浅析
- 比特币开发专题(数字货币原理理解及应用实例)
- CLR 中凭据(Evidence)相关信息获取原理浅析
- CLR 中类型字段的运行时内存布局 (Layout) 原理浅析 [1]
- ASP.NET 中 Session 实现原理浅析 [2] 状态管理器