$player_transaction_id, 'transaction_type' => $transaction_type, 'from' => $from, 'to' => $to, 'cmd' => $cmd, 'json' => $json, ]; // 记录交易,失败重试 return self::logTrans($log); } /** * 当前交易的块id * @var int */ static $last_json = ''; static $last_trx_id = 0; /** * 记录交易,并定时检查是否失效了 * @param $data [`transaction_id`, `player_transaction_id`, `transaction_type`, `from`, `to`, `cmd`, `transaction_state`, `json`, `retry_times`] * @return array */ static function logTrans($data) { self::$last_json = $data['json']; $objTrans = new TableHelper('transaction_log', 'dw_eos'); $ret = []; $flag = false; if (!$data['transaction_id']) { if (!$data['json']) { self::_fillId($data); $data['transaction_state'] = -1; } else { $ret = json_decode($data['json'], true); $data['transaction_id'] = $ret['transaction_id']; if ($data['transaction_id']) { $flag = true; $data['block_num'] = $ret['processed']['block_num']; } else { // 没有id,就需要填充 self::_fillId($data); $data['transaction_state'] = -1; } } } self::$last_trx_id = $data['transaction_id']; $data['console'] = $data['console'] ?: $ret['processed']['action_traces'][0]['console']; $data['create_time'] = date('Y-m-d H:i:s'); $objTrans->addObject($data); if ($flag) { // return $data['transaction_id']; return $data; } else { return null; } } private static function _fillId(&$data) { $objTrans = new TableHelper('transaction_log', 'dw_eos'); $count = $objTrans->getCount(); $rand = rand(1000, 9999); $data['transaction_id'] = "unknown:{$count}:{$rand}"; } /** * 获取真正的块id * @param $trxId * @param int $block_num * * @return mixed */ static function getRealBlockNum($trxId, $block_num = 0) { if ($block_num || ENV == ENV_DEV) { $ret = self::getTransaction2($trxId, $block_num); } else { $ret = self::getTrxBySpark($trxId); } return $ret['block_num']; } static function getTrxBySpark($transaction_id) { $api_key = '37400d93f3c7eb64428585f1cd355fe8'; $url = "https://api.eospark.com/api?module=transaction&action=get_transaction_detail_info&apikey={$api_key}&trx_id={$transaction_id}"; $objHttp = new dwHttp(); $data = null; for ($i = 1; $i <= 3; $i++) { $json = $objHttp->get2($url); $data = json_decode($json, true); if ($data['errno'] == 0) { return $data['data']; } else { sleep($i / 2); } } return $data; } /** * 获取交易详情 * @param string $transaction_id * @param int $block_num_hint * @return string */ static function getTransaction($transaction_id, $block_num_hint) { $api = $GLOBALS['eosUrl'] . 'v1/history/get_transaction'; $data = ["id" => $transaction_id]; $block_num_hint = (int)$block_num_hint; if ($block_num_hint) { $data['block_num_hint'] = $block_num_hint; } $json = null; for ($i = 0; $i < 4; $i++) { $post_json = json_encode($data); $json = (new dwHttp)->post2($api, $post_json, 3, 3); $trx = json_decode($json, true); if ($trx['id']) { return $json; } else { $data['block_num_hint']++; } } return $json; } /** * 获取账号信息 * @param $userName * * @return string */ static function getAccount($userName) { $cmd = "cleos -u {$GLOBALS['eosUrl']} get account {$userName} -j"; return self::execCmd($cmd, false); } /** * 获取余额 * @param $userName * @param $code * * @return float */ public static function getBalance($userName, $code = 'eosio.token') { $cmd = "cleos -u {$GLOBALS['eosUrl']} get currency balance {$code} {$userName}"; $result = self::execCmd($cmd); $balance = (float) $result; return $balance * 10000; } /** * 获取块信息 * @param $block_num * * @return array */ public static function getBlock($block_num) { $cmd = "cleos -u {$GLOBALS['eosUrl']} get block {$block_num}"; $json = self::execCmd($cmd); $json = str_replace("\n", '', $json); $info = json_decode($json, true); return $info; } /** * 获取块id * @param $block_num * * @return array */ public static function getBlockId($block_num) { $cmd = "cleos -u {$GLOBALS['eosUrl']} get block {$block_num}"; $json = self::execCmd($cmd); $json = str_replace("\n", '', $json); $info = json_decode($json, true); if ($info && $info['id']) { $block_id = $info['id']; } else { $hex = dechex($block_num); $hex = sprintf("%08s", $hex); preg_match("/\"({$hex}[0-9a-fA-F]{56})\"/", $json, $matches); $block_id = $matches[1]; } return $block_id; } static function execCmd($cmd, $writeLog = true) { self::$last_json = null; $startTime = microtime(true); if (strpos($cmd, ' 2>&1') === false) { $cmd = $cmd .' 2>&1'; } // 同时输出错误信息 $json = shell_exec($cmd); $msg = "{$cmd}, ret:" . substr($json, 0, 100); if ($writeLog) { CallLog::logModuleCall("Shell:", $msg, null, $json, $startTime); CallLog::flushLogs(); } self::$last_json = $json; return $json; } static function log($msg) { $date = date('Y-m-d H:i:s', time()); print_r("[{$date}], {$msg}\n"); } /** * 重试多次获取交易id * @param $transaction_id * @param int $block_num_hint * @param int $maxTimes * @param int $times * * @return mixed */ static function getTransaction2($transaction_id, $block_num_hint, $maxTimes = 3, $times = 0) { // 检验交易id是否是当前用户,当前gameid $json = self::getTransaction($transaction_id, $block_num_hint); $ret = json_decode($json, true); if ($ret['error']) { // 3040011 The transaction can not be found if ($ret['error']['code'] == 3040011) { if ($times < $maxTimes) { Tool::sleep($times); return self::getTransaction2($transaction_id, $block_num_hint, $maxTimes, $times + 1); } else { Response::error(CODE_PARAM_ERROR, "transaction id:{$transaction_id} is not found."); } } } return $ret; } static function getActions($account, $limit = 50, $p = 1, $ascendOrder = false){ $p = (int)$p ?: 1; $pos = $ascendOrder ? $limit * ($p - 1) : -1;//升序支持分页,降序不支持分页,仅能从最尾部开始 $offset = $limit - 1; $cmd = "cleos -u {$GLOBALS['eosUrl']} get actions -j {$account} {$pos} {$offset}"; $actions = []; for ($i = 0; $i < 5; $i ++) { $json = self::execCmd($cmd); @$data = json_decode($json, 1) ?: []; if (isset($data['actions']) && is_array($data['actions'])) { $actions = $data['actions']; if (is_array($actions) && count($actions) == $limit) { break;//由于节点的不稳定性,所以要求一定要拿到actions,并争取非尾页的条数等于期望条数 } } } return $actions; } }