BroadcastServer.php 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. <?php
  2. namespace App\Servers;
  3. use App\Models\Broadcast;
  4. use App\Servers\Icon\BanRPC;
  5. use App\Servers\Icon\Utils;
  6. use Web3p\EthereumTx\Transaction;
  7. /**
  8. * 广播接口
  9. */
  10. class BroadcastServer
  11. {
  12. public static $type_str=[
  13. ];
  14. static private $server = null;
  15. /**
  16. * 创建对象
  17. * @return BroadcastServer
  18. */
  19. static function creatServer()
  20. {
  21. if (empty(self::$server)) self::$server = new BroadcastServer();
  22. return self::$server;
  23. }
  24. /**
  25. * 创建广播信息
  26. * @param $coin_id
  27. * @param $money
  28. * @param $from
  29. * @param $from_key
  30. * @param $to
  31. * @param $member_id
  32. * @param int $order_id
  33. * @param int $status_type
  34. * @param int $status
  35. * @return mixed
  36. */
  37. public static function addBroadcast($coin_id, $money, $from, $from_key, $to, $member_id, $order_id = 0, $status_type = 0, $status = 1)
  38. {
  39. //保留数量
  40. $transaction = [
  41. 'depend' => 0,
  42. 'from' => $from,
  43. 'to' => $to,
  44. 'nonce' => '',
  45. 'coin_id' => $coin_id,
  46. 'value' => '0x0',
  47. 'data' => !empty($tx['data']) ? $tx['data'] : Utils::fixHex(bin2hex('NYT')),
  48. 'chain_id' => 0,
  49. 'gas_price' => '',
  50. 'gas_limit' => '',
  51. 'to_address' => $to,
  52. 'sign' => '',
  53. 'success' => '',
  54. 'hash' => $status == 5 ? '系统内部转账,直接成功,无需链上广播' : '',
  55. 'from_key' => $from_key,
  56. 'money' =>round($money,6),
  57. 'status' => $status,
  58. 'type' => $status_type,
  59. 'm_id' => $member_id,
  60. 'order_id' => $order_id,
  61. ];
  62. $transaction = Broadcast::create($transaction);
  63. return $transaction->{'id'};
  64. }
  65. /**
  66. * 广播查询
  67. */
  68. public function getBroadcast()
  69. {
  70. $list = Broadcast::where('status', '2')->select(['id', 'm_id', 'from', 'to', 'send_money', 'value', 'coin_id', 'type', 'sign', 'money', 'from_key', 'coin_id', 'hash', 'send_money', 'order_id'])->limit(100)->get();
  71. $ret_type=false;
  72. if (empty($list)) return $ret_type;
  73. $bnbServer=BanRPC::creatServer();
  74. foreach ($list as $value) {
  75. $receipt = $bnbServer->getTransactionReceipt($value['hash']);//交易查询
  76. if (empty($receipt)) {
  77. //交易正在广播中,下次继续查询
  78. continue;
  79. } else {
  80. //交易已完成 返回数据格式数据 ,将数据json保存
  81. if ($receipt['status'] != '0x1') {
  82. $update_info['error'] = '广播提交失败';
  83. $update_info['status'] = 3;
  84. } else {
  85. $update_info['status'] = 4;
  86. $update_info['end_time'] = time();
  87. }
  88. }
  89. }
  90. return $list->count();
  91. }
  92. /**
  93. * 交易广播
  94. */
  95. function sendBroadcast(){
  96. $list = Broadcast::where('status', '1')->where([['end_time','=',0,'or'],['end_time','<=',time()-60,'or']])->select(['id', 'm_id', 'from', 'to', 'nonce', 'value', 'data', 'gas_price', 'gas_limit', 'sign', 'money', 'from_key', 'coin_id', 'depend','type','contract_address','order_id'])->limit(100)->get();
  97. $bnbServer=BanRPC::creatServer();
  98. foreach ($list as $value){
  99. $bnbNum=$bnbServer->getBalance($value->{'from'});
  100. if(env('TEST_SERVE')){
  101. $value->{'money'}='0.00001';
  102. }
  103. if(empty($bnbNum) || $bnbNum<($value->{'money'}+0.0004)){
  104. $transaction['end_time'] = time();
  105. }else{
  106. //ETH广播
  107. $send_num = Broadcast::where('from', $value->{'from'})->where('status', '2')->count('id');
  108. if ($send_num > 0) {
  109. sleep(1);
  110. continue;
  111. }
  112. $transaction = $this->sendBnb($value);
  113. if (empty($transaction) || empty($transaction['hash'])) {
  114. $transaction = ['status' => 3, 'error' => '广播失败'];
  115. } else {
  116. $transaction['status'] = 2;
  117. }
  118. if ($transaction) {
  119. Broadcast::where('id', $value->{'id'})->update($transaction);
  120. }
  121. }
  122. }
  123. return $list->count();
  124. }
  125. function sendBnb($value){
  126. $bnbServer=BanRPC::creatServer();
  127. // try {
  128. $transaction['from'] = $value['from'];
  129. $transaction['to'] = $value['to'];
  130. $transaction['chain_id'] = $bnbServer->chainId;
  131. $transaction['value'] = Utils::dec2hex(Utils::fund2int($value['money'] )); // 转账金额
  132. $transaction['data'] = '0x0';
  133. $nonce = $bnbServer->getTransactionCount($value['from']);
  134. $transaction['nonce'] = $nonce;
  135. $gas_price = $bnbServer->getGasPrice();
  136. // $transaction['gas_price'] = Utils::dec2hex(Utils::toWei("26gwei") + Utils::hex2dec($gas_price));//燃料十六进制。由eth_estimateGas获取
  137. $transaction['gas_price'] =$gas_price;//燃料十六进制。由eth_estimateGas获取
  138. $gas_limit =$this->getEthGasLimit($transaction);
  139. $transaction['gas_limit'] = $gas_limit;
  140. if($value->{'type'}==3)$value->{'m_id'}=0;
  141. $sign = $this->ethSign($transaction, PassServer::creatServer()->getSecretKey($value->{'from_key'}, $value->{'m_id'})); //交易签名
  142. $transaction['sign'] = $sign;
  143. $error='';
  144. $hash = $bnbServer->sendRawTransaction($transaction['sign'], $error);//广播交易
  145. $transaction['hash'] = $hash;
  146. return $transaction;
  147. // } catch (\Exception $e) {
  148. // return false;
  149. // }
  150. }
  151. /**
  152. * @param $transaction
  153. * @return string
  154. */
  155. public function getEthGasLimit($transaction)
  156. {
  157. $bnbServer=BanRPC::creatServer();
  158. $tx = [
  159. 'from' => $transaction['from'],
  160. 'to' => $transaction['to'],
  161. 'nonce' => $transaction['nonce'],
  162. 'value' => $transaction['value'],
  163. 'data' => $transaction['data'],
  164. 'chainId' => $bnbServer->chainId,
  165. 'gasPrice' => $transaction['gas_price'],
  166. ];
  167. $gasLimit = $bnbServer->estimateGas($tx);
  168. if (!$gasLimit) {
  169. $gasLimit = 10 * 10000; // 预估失败, 最高10万
  170. }
  171. return $gasLimit;
  172. }
  173. protected function build($from, $to, $value, $data)
  174. {
  175. $tx = [];
  176. $tx['from'] = $from;
  177. $tx['to'] = $to;
  178. $tx['value'] = $value;
  179. $tx['data'] = $data;
  180. return $tx;
  181. }
  182. protected function ethSign($transaction, $key)
  183. {
  184. $bnbServer=BanRPC::creatServer();
  185. $tx = [
  186. 'from' => $transaction['from'],
  187. 'to' => $transaction['to'],
  188. 'nonce' => $transaction['nonce'],
  189. 'value' => $transaction['value'],
  190. 'data' => $transaction['data'],
  191. 'chainId' => $bnbServer->chainId,
  192. 'gasPrice' => $transaction['gas_price'],
  193. 'gasLimit' => $transaction['gas_limit'],
  194. ];
  195. // 数据签名
  196. $tr = new Transaction($tx);
  197. $tr->sign($key);
  198. return Utils::fixHex($tr->serialize());
  199. }
  200. }