BroadcastServer.php 7.6 KB

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