Using Stratum protocol in PHP is it possible? Is there any equivalent to Go's 'net.Dial'?

4

I wanted to use the Electrum servers, listed here , it uses a protocol called " Stratum, "which is documented here , but I do not even know it's the most up to date one.

I can "work" using the tls library and net (in case I do not use TLS) in Golang, as it is a test I did as follows:

config := &tls.Config{
    InsecureSkipVerify: true,
    // NOTA:
    // O Electrum permite servidores com certificados self-signed!
    // O melhor que posso fazer é um Public Key-Pinning baseado em Trust On First Use.
}

PKHashConfiavel := []byte{0x8c, 0x45, 0x01, 0x95, 0x91, 0xd5, 0x4a, 0x50, 0xc8, 0xf6, 0xac, 0x84, 0xa3, 0xf9, 0x70, 0xb1, 0xa7, 0x3b, 0x7e, 0x51, 0xc6, 0xb1, 0x18, 0x72, 0x64, 0x40, 0x00, 0x29, 0xfd, 0xaa, 0xa7, 0xed, 0xbc, 0x8c, 0xd4, 0x2a, 0xf8, 0xe5, 0xdb, 0x55, 0x5f, 0x09, 0x13, 0x56, 0x55, 0x2f, 0x95, 0x39}

// Se conecta com o servidor
conn, err := tls.Dial("tcp", "electrum.hsmiths.com:50002", config)
if err != nil {
    panic(err)
}

connState := conn.ConnectionState()
var isConfiavel bool = false

// Verifica a hash do certificado no qual me conectei
for _, cert := range connState.PeerCertificates {
    PKDer, _ := x509.MarshalPKIXPublicKey(cert.PublicKey)
    PKHash := blake2b.Sum384(PKDer)

    if hmac.Equal(PKHashConfiavel, PKHash[:]) {
        isConfiavel = true
    }
}

if isConfiavel {

    // Envia a requisição
    comando := "{\"id\": 1, \"method\": \"blockchain.address.get_history\", \"params\": [\"1DB8zJn99HSVUUwWRCgKxiZV33yPfBSVYr\"]}"
    comando += "\n"

    conn.Write([]byte(comando))

    // Obtêm resposta  
    resposta, _ := bufio.NewReader(conn).ReadString('\n')
    fmt.Print(resposta)

}

This works normally and returns:

{"jsonrpc": "2.0", "id": 1, "result": [{"tx_hash": "a7d790a2418fd0b17af37b2896327985d52941a1211de8705c6f16d868885412", "height": 483800}, {"tx_hash": "4ee9dcd51d1d80e6aa021e5503354ec3d4125cf8777894b68056cfef9bc9a818", "height": 483801}]}

I tried to do the same in PHP, with the native features, in this case the only solution I see would be cURL, but it does not work for nothing.

But I also tried in PHP, without using TLS, as follows:

$comando = '{"id": 1, "method": "blockchain.address.get_history", "params": ["1DB8zJn99HSVUUwWRCgKxiZV33yPfBSVYr"]}';

$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, 'electrum.hsmiths.com');
curl_setopt($curl, CURLOPT_PORT , '50001');
curl_setopt($curl, CURLOPT_HEADER, 1);

// Para testes desligamos a verificação de SSL:
// curl_setopt($curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);
// curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 1);
// curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);
// curl_setopt($curl, CURLOPT_PINNEDPUBLICKEY, 'sha256//' . base64_encode($PKHash))

// Testes fracassados:
//curl_setopt($curl, CURLOPT_HTTPHEADER, ['Content-Type: application/stratum']);

curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $comando);


$response = curl_exec($curl);

var_dump($response);

Answer:

string(134) "{"jsonrpc": "2.0", "id": null, "error": {"message": "cannot decode JSON: Expecting value: line 1 column 1 (char 0)", "code": -32700}}"

Apparently Stratum can not be used over HTTP and for this I need to create a TCP connection without cURL.

So, is there any equivalent of tls.Dial / net.Dial in PHP? Is there an alternative to cURL and which is natively embedded in PHP?

    
asked by anonymous 07.09.2017 / 00:36

1 answer

2

I was able to do this using socket_* , as follows:

$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
$conn = socket_connect($socket,  gethostbyname('electrum.hsmiths.com'), '50001');

$comando = '{"id": 1, "method": "blockchain.address.get_history", "params": ["1DB8zJn99HSVUUwWRCgKxiZV33yPfBSVYr"]}' . "\n";

socket_write($socket, $comando, strlen($comando));

$resposta = socket_read($socket, 1<<(10 * 2), PHP_NORMAL_READ);

echo $resposta;

Answer:

{"jsonrpc": "2.0", "id": 1, "result": [{"tx_hash": "a7d790a2418fd0b17af37b2896327985d52941a1211de8705c6f16d868885412", "height": 483800}, {"tx_hash": "4ee9dcd51d1d80e6aa021e5503354ec3d4125cf8777894b68056cfef9bc9a818", "height": 483801}]}

The documentation of socket_* is very precarious, several functions have no documentation and I do not know if this is the best way. But, it works.

However, supporting TLS / SSL is another matter, this is not supported by this feature set. If there is any way or some other resource I will edit this answer again.

    
07.09.2017 / 09:56