| 副标题[/!--empirenews.page--] php与ethereum rpc server通信一、Json RPCJson RPC就是基于json的远程过程调用,这么解释比较抽象。简单来说,就是post一个json格式的数据调用rpc server中的方法. 而这个json格式是固定的,总的来说有这么几项: 
  method: 方法名params: 参数列表id: 对过程调用的唯一标识号 二、构建一个Json RPC客户端class jsonRPCClient {/** 
Debug state
@var boolean*/
 private $debug;
 /** 
The server URL
@var string*/
 private $url;
 /**
The request id
@var integer*/
 private $id;
 /**
If true,notifications are performed instead of requests
@var boolean*/
 private $notification = false;
 /** 
Takes the connection parameters
@param string $url@param boolean $debug*/
 public function __construct($url,$debug = false) {
 // server URL
 $this->url = $url;
 // proxy
 empty($proxy) ? $this->proxy = '' : $this->proxy = $proxy;
 // debug state
 empty($debug) ? $this->debug = false : $this->debug = true;
 // message id
 $this->id = 1;
 }
 /** 
Sets the notification state of the object. In this state,notifications are performed,instead of requests.
@param boolean $notification*/
 public function setRPCNotification($notification) {
 empty($notification) ?
 $this->notification = false
 :
 $this->notification = true;
 }
 /** 
Performs a jsonRCP request and gets the results as an array
@param string $method@param array $params@return array*/
 public function __call($method,$params) {
 // check
if (!is_scalar($method)) {
  throw new Exception('Method name has no scalar value');
}
// check
if (is_array($params)) {
  // no keys
  $params = $params[0];
} else {
  throw new Exception('Params must be given as array');
}
// sets notification or request task
if ($this->notification) {
  $currentId = NULL;
} else {
  $currentId = $this->id;
}
// prepares the request
$request = array(
        'method' => $method,'params' => $params,'id' => $currentId
        );
$request = json_encode($request);
$this->debug && $this->debug.='***** Request *****'."n".$request."n".'***** End Of request *****'."nn";
// performs the HTTP POST
$opts = array ('http' => array (
          'method' => 'POST','header' => 'Content-type: application/json','content' => $request
          ));
$context = stream_context_create($opts);
if ($fp = fopen($this->url,'r',false,$context)) {
  $response = '';
  while($row = fgets($fp)) {
    $response.= trim($row)."n";
  }
  $this->debug && $this->debug.='***** Server response *****'."n".$response.'***** End of server response *****'."n";
  $response = json_decode($response,true);
} else {
  throw new Exception('Unable to connect to '.$this->url);
}
// debug output
if ($this->debug) {
  echo nl2br($debug);
}
// final checks and return
if (!$this->notification) {
  // check
  if ($response['id'] != $currentId) {
    throw new Exception('Incorrect response id (request id: '.$currentId.',response id: '.$response['id'].')');
  }
  if (!is_null($response['error'])) {
    throw new Exception('Request error: '. var_export($response['error'],true));
  }
  return $response['result'];
} else {
  return true;
}
 }}
 ?>
 比较简单的代码,如果比较懒,拿过去用就行了。也可以上packagist.org自己找一个rpc client. 三、调用RPC的两类方法有两类方法需要调用. 一类是RPC server自带方法,另一类就是合约方法. RPC server方法调用json格式 RPC Server自带方法的列表 调用自带方法比较简单,参考上述链接,大部分都有示例. 合约方法调用json格式
 调用合约方法必须使用自带方法中的eth_call. 而合约方法名称和合约方法参数列表则使用params进行体现,比如: 我们要调用合约中的balanceOf方法,则json数据应该如何构造呢? 首先看看getBalanace的函数实现: 提炼出函数原型: 在geth控制台下运行命令: 
得到函数hash "0x70a08231" 假设待查询的地址 address _owner = "0x38aabef4cd283ccd5091298dedc88d27c5ec5750",则去掉前面的"0x",并在左边补24个零(一般地址长度为42位,去掉'0x'后为40位),构成64位十六进制参数. 最终得到的参数为 "0x70a0823100000000000000000000000038aabef4cd283ccd5091298dedc88d27c5ec5750" 假设我们的合约地址为 "0xaeab4084194B2a425096fb583Fbcd67385210ac3". 则得到最终的json数据为: 把以上json数据以post方式发送给服务器,就可以调用合约方法"balanceOf",查询给定的地址中的代币余额. 调用合约中的其他方法也要新遵循上面的方式,我们再分析一下transfer方法,加深印象: 首先,看看代码中的函数实现: 其次,提炼出函数原型: 再次,在控制台运行sha3函数: 
得到函数hash "0xa9059cbb" 第一个参数假设 address _to = "0x38aabef4cd283ccd5091298dedc88d27c5ec5750",则去"0x",补零到64位.
 第二个参数假设 uint256 _value = 43776,则化为十六进制"0xab00"后,去"0x",补零到64位. 连接起来 "0xa9059cbb00000000000000000000000038aabef4cd283ccd5091298dedc88d27c5ec5750000000000000000000000000000000000000000000000000000000000000ab00" 构建json数据: 
  from 转出者地址to 合约地址data 上述操作得到的十六进制数 把以上的步骤转化为代码. 构建一个以太坊RPC client 
require './jsonRPCClient.php';
 //php自带的dechex无法把大整型转换为十六进制function bc_dechex($decimal)
 {
 $result = [];
 while ($decimal != 0) {$mod = $decimal % 16;
 $decimal = floor($decimal / 16);
 array_push($result,dechex($mod));
 }
 return join(array_reverse($result));}
 class EthereumRPCClient{
 public static $client = null;
 //布署合约的账户地址const COINBASE = '0x38aabef4cd283ccd5091298dedc88d27c5ec5750';
 //合约地址const CONTRACT = '0xaeab4084194B2a425096fb583Fbcd67385210ac3';
 (编辑:宣城站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |