>  기사  >  백엔드 개발  >  PHP와 Ethereum 클라이언트 간의 상호 작용에 대한 자세한 설명

PHP와 Ethereum 클라이언트 간의 상호 작용에 대한 자세한 설명

不言
不言원래의
2018-04-28 10:28:312094검색

이 기사는 PHP와 Ethereum 클라이언트 간의 상호 작용에 대한 관련 지식 포인트를 알려주며 도움이 필요한 친구들이 따라하고 배울 수 있습니다.

php는 이더리움 rpc 서버와 통신합니다

1. Json RPC

Json RPC는 json 기반의 원격 프로시저 호출입니다. 간단히 말하면 json 형식으로 데이터를 게시하고 rpc 서버에서 메서드를 호출하는 것입니다. 이 json 형식은 일반적으로 다음 항목이 있습니다.

{
  "method": "",
  "params": [],
  "id": idNumber
}

  • method: method name

  • params: 매개변수 목록

  • id: 프로시저 호출에 대한 고유 식별 번호

2. Json RPC 클라이언트 빌드

<?php

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 = &#39;&#39; : $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(&#39;Method name has no scalar value&#39;);
    }
    
    // check
    if (is_array($params)) {
      // no keys
      $params = $params[0];
    } else {
      throw new Exception(&#39;Params must be given as array&#39;);
    }
    
    // sets notification or request task
    if ($this->notification) {
      $currentId = NULL;
    } else {
      $currentId = $this->id;
    }
    
    // prepares the request
    $request = array(
            &#39;method&#39; => $method,
            &#39;params&#39; => $params,
            &#39;id&#39; => $currentId
            );
    $request = json_encode($request);
    $this->debug && $this->debug.=&#39;***** Request *****&#39;."\n".$request."\n".&#39;***** End Of request *****&#39;."\n\n";

    // performs the HTTP POST
    $opts = array (&#39;http&#39; => array (
              &#39;method&#39; => &#39;POST&#39;,
              &#39;header&#39; => &#39;Content-type: application/json&#39;,
              &#39;content&#39; => $request
              ));
    $context = stream_context_create($opts);
    if ($fp = fopen($this->url, &#39;r&#39;, false, $context)) {
      $response = &#39;&#39;;
      while($row = fgets($fp)) {
        $response.= trim($row)."\n";
      }
      $this->debug && $this->debug.=&#39;***** Server response *****&#39;."\n".$response.&#39;***** End of server response *****&#39;."\n";
      $response = json_decode($response,true);
    } else {
      throw new Exception(&#39;Unable to connect to &#39;.$this->url);
    }
    
    // debug output
    if ($this->debug) {
      echo nl2br($debug);
    }
    
    // final checks and return
    if (!$this->notification) {
      // check
      if ($response[&#39;id&#39;] != $currentId) {
        throw new Exception(&#39;Incorrect response id (request id: &#39;.$currentId.&#39;, response id: &#39;.$response[&#39;id&#39;].&#39;)&#39;);
      }
      if (!is_null($response[&#39;error&#39;])) {
        throw new Exception(&#39;Request error: &#39;. var_export($response[&#39;error&#39;], true));
      }
      
      return $response[&#39;result&#39;];
      
    } else {
      return true;
    }
  }
}
?>

비교적 간단한 코드, 게으른 경우 , take 과거에는 그냥 사용하세요. packagist.org에 가서 직접 rpc 클라이언트를 찾을 수도 있습니다.

3. RPC를 호출하는 두 가지 유형의 메소드

호출해야 하는 두 가지 유형의 메소드가 있습니다. 하나는 RPC 서버 고유의 메소드입니다. , 다른 하나는 계약 방법입니다.

RPC 서버 메서드는 json 형식을 호출합니다.

{
  "method": "eth_accounts",
  "params": [],
  "id": 1
}

RPC 서버에 내장된 메서드 목록

내장 메서드를 호출하는 방법은 비교적 간단합니다. 위 링크를 참조하세요. 대부분은 예시입니다.

계약 메서드는 json 형식을 호출합니다

계약 메서드를 호출하려면 내장 메서드에서 eth_call을 사용해야 합니다. 계약 메서드 이름과 계약 메서드 매개 변수 목록은 params를 사용하여 반영됩니다. 계약에서 BalanceOf 메소드를 호출하려면 json 데이터를 어떻게 구성해야 합니까?

우선 getBalanace의 함수 구현을 살펴보세요:

function balanceOf(address _owner) public view returns (uint256 balance)

함수 프로토타입 추출:

balanceOf(address)

geth 콘솔에서 명령을 실행하세요.

web3.sha3("balanceOf(address)").substring(0, 10)

Get the function hash "0x70a08231"

Assumption 쿼리할 주소는 address _owner = "0x38aabef4cd283ccd5091298dedc88d27입니다. c5ec5750", 앞에 있는 "0x"를 제거하세요. 왼쪽에 24개의 0을 추가하여(일반 주소 길이는 42비트이며 '0x'를 제거한 후 40비트임) 64비트 16진수 맞춤형 매개변수를 형성합니다.

최종 매개변수는 "0x70a082310000000000000000000000038aabef4cd283ccd5091298dedc88d입니다. 27c5ec5750"

가정하자 우리 계약 주소는 "0xaeab4084194B2a425096 fb583Fbcd67385210ac3"입니다.

그런 다음 최종 json 데이터는 다음과 같습니다.

{
  "method": "eth_call",
  "params": [{"from": "0x38aabef4cd283ccd5091298dedc88d27c5ec5750", "to": "0xaeab4084194B2a425096fb583Fbcd67385210ac3", "data": "0x70a0823100000000000000000000000038aabef4cd283ccd5091298dedc88d27c5ec5750"}, "latest"],
  "id": 1
}

위 json 데이터를 포스트 모드로 보냅니다. 서버에 계약 메서드 "balanceOf"를 호출하여 토큰을 쿼리할 수 있습니다.

계약의 다른 메소드를 호출하는 경우에도 위의 메소드를 따라야 합니다. 이체 메소드를 다시 분석하여 감상을 심화해 보겠습니다.

먼저 코드의 함수 구현을 살펴보세요.

function transfer(address _to, uint256 _value) public returns (bool)

Second로 기능 프로토 타입을 추출합니다. "0x38aabef4cd283ccd5091298dedc88d27c5ec5750", "0x"로 이동하여 64비트에 0을 추가합니다.

두 번째 매개변수는 uint256_value = 43776을 가정하고 16진수 시스템이 됩니다. "0xab00" 이후 "0x"로 이동하여 64에 0을 추가합니다.

함께 연결하세요

"0xa9059cbb000000000000000000000000038aabef4cd283ccd5091298dedc88d27c5ec5750000000000000 000000000000000000 0000000000000000000000000ab00"

json 데이터 빌드:

transfer(address,uint256) //注意逗号后面不能有空格


이체자 주소

to 계약 주소

data 위에서 얻은 숫자 Operation

위 단계를 코드로 변환합니다.

    Ethereum RPC 클라이언트 구축
  • web3.sha3("transfer(address,uint256)").substring(0, 10)
  • 코드는 비교적 간단합니다. 주의해야 할 몇 가지 사항이 있습니다. 포인트:

  • 의 값 단위
  • 전달 함수는 10^-18로 매우 작으므로 1000번을 전달하려면 실제로 10의 18승을 곱해야 합니다. 여기서 18은 소수입니다.

포인트 1로 인해, pow 함수 대신 bcpow를 사용해야 합니다.

PHP와 함께 제공되는 decex 함수는 사용할 수 없습니다. dechex에서는 정수 유형이 PHP_INT_MAX보다 클 수 없으며 이 숫자는 32비트 시스템에서 4294967295입니다. 1번 항목으로 인해 모든 숫자는 10의 18승을 곱해야 하므로 결과값은 PHP_INT_MAX보다 훨씬 큽니다. 구현 방법을 모르는 경우에는 10진수를 16진수로 직접 변환하는 것이 좋습니다. 위의 코드에.

이체 등 특정 계약 방법을 실행할 때는 먼저 사용자 잠금을 해제해야 합니다.

  • 트랜잭션을 보낸 후 서버 측에서 마이닝을 시작해야 트랜잭션이 실제로 블록에 기록됩니다. , 예를 들어 이체를 호출한 후 상대방이 계정을 받지 못한 것을 발견하면 아직 놀라지 말고 채굴을 시작하십시오. 자동 코드 마이닝을 활성화하려면 geth --rpc 끝에 --mine을 추가하세요... 테스트:

  • {
      "method": "eth_call",
      "params": [{"from": "0x38aabef4cd283ccd5091298dedc88d27c5ec5750", "to": "0xaeab4084194B2a425096fb583Fbcd67385210ac3", "data": "0xa9059cbb00000000000000000000000038aabef4cd283ccd5091298dedc88d27c5ec5750000000000000000000000000000000000000000000000000000000000000ab00"}, "latest"],
      "id": 1
    }

위 내용은 PHP와 Ethereum 클라이언트 간의 상호 작용에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.