PHP生成管理以太坊私钥并签名交易

本篇是介绍PHP如何生成管理以太坊私钥并签名交易。

之前的ETH以太坊钱包交互方式

  1. 一台Web服务器,一台钱包服务器运行Geth或Parity
  2. 一台钱包服务器存储keystore
  3. 需要交易时先解锁钱包再发送交易

优点

  1. Web服务器本身不用存储钱包,只用记住钱包密码即可

缺点

  1. 钱包服务器存储所有地址,并不能单独服务于某一个应用
  2. 钱包服务器如果挂了或者要迁移,比较麻烦。

目前要用的方式

  1. 一台钱包服务器供多个Web服务器使用,本身不存储keystore
  2. Web服务器自己生成并管理私钥,需要交易时自己签名并发送RAW交易

imToken及其它一众钱包就是类似这种方式,不同的是它们是客户端应用,但原理是一样的。

优点

  1. 不用管理多个钱包服务器,节省运维成本
  2. 方便迁移

缺点

  1. 私钥在Web服务器上,一旦被盗,资产全丢。所以私钥一定要妥善保管,可采取加密存储。

下面是关键的实现环节,主要是生成私钥、交易签名及广播。

首先安装依赖

# 这两个用来生成BTC/ETH/LTC等的助记词、种子、私钥和公钥
composer require bitwasp/bitcoin
composer require web3p/ethereum-util

# 这两个用来生成交易、签名并与钱包服务器交互
composer require web3p/ethereum-tx
composer require sc0vu/web3.php

生成私钥

use BitWasp\Bitcoin\Bitcoin;
use BitWasp\Bitcoin\Crypto\Random\Random;
use BitWasp\Bitcoin\Key\Factory\HierarchicalKeyFactory;
use BitWasp\Bitcoin\Mnemonic\Bip39\Bip39Mnemonic;
use BitWasp\Bitcoin\Mnemonic\Bip39\Bip39SeedGenerator;
use BitWasp\Bitcoin\Mnemonic\MnemonicFactory;
use Web3p\EthereumUtil\Util;

// Bip39
$random = new Random();
// 生成随机数(initial entropy)
$entropy = $random->bytes(Bip39Mnemonic::MIN_ENTROPY_BYTE_LEN);
$bip39 = MnemonicFactory::bip39();
// 通过随机数生成助记词
$mnemonic = $bip39->entropyToMnemonic($entropy);
echo "mnemonic: " . $mnemonic.PHP_EOL.PHP_EOL;// 助记词

$seedGenerator = new Bip39SeedGenerator();
// 通过助记词生成种子,传入可选加密串'hello'
$seed = $seedGenerator->getSeed($mnemonic);
echo "seed: " . $seed->getHex() . PHP_EOL;
$hdFactory = new HierarchicalKeyFactory();
$master = $hdFactory->fromEntropy($seed);

$util = new Util();
// 设置路径account
$hardened = $master->derivePath("44'/60'/0'/0/0");
echo " - m/44'/60'/0'/0/0 " .PHP_EOL;
echo " public key: " . $hardened->getPublicKey()->getHex().PHP_EOL;
echo " private key: " . $hardened->getPrivateKey()->getHex().PHP_EOL;// 可以导入到imtoken使用的私钥
echo " address: " . $util->publicKeyToAddress($util->privateKeyToPublicKey($hardened->getPrivateKey()->getHex())) . PHP_EOL;// 私钥导入imtoken后一样的地址

生成好了之后把地址、公钥、私钥保存到数据库中,留待备用。

交易签名并广播

use Web3\Providers\HttpProvider;
use Web3\RequestManagers\HttpRequestManager;
use Web3\Web3;
use Web3p\EthereumTx\Transaction;

//构造交易
$transaction = new Transaction([
            'nonce' => '0x1',
            'from' => 'address_from',
            'to' => 'address_to',
            'gas' => '0x76c0',
            'gasPrice' => '0x10',
            'value' => '0x1000',
            'chainId' => 1,
        ]);
//签名        
$signedTransaction = $transaction->sign("private_key");

var_dump($signedTransaction);

//使用web3发送交易
$web3 = new Web3(new HttpProvider(new HttpRequestManager('http://localhost:8545', 5)));
$eth = $web3->eth;
$eth->sendRawTransaction('0x' .$signedTransaction,function ($err, $tx) {
    if ($err !== null) {
        var_dump($err->getMessage());
    }else{
        echo 'TX: '. $tx . PHP_EOL;
    }
});

注意点:

  1. 交易参数中有两个参数需要注意下,一是 nonce,nonce必须严格递增,不能跳跃,不然会暂存到交易池中,直到nonce到达它所在的高度时才会被提交打包。可通过eth_getTransactionCount获取某个地址的交易量,第二个参数传pending,即包含未确认的交易,下一笔交易nonce就用此交易量即可(因为nonce从0开始);二是 chainId,主网是1,也是默认的,如果用测试网络,须指定chainId。

Leave a Comment

豫ICP备19001387号-1