headzoo / bitcoin-wallet-api
PHP library supporting communication with the Bitcoin wallet JSON-RPC API.
Requires
- php: >=5.4.0
- ext-simplexml: *
- headzoo/web-tools: dev-master
- psr/log: dev-master
This package is not auto-updated.
Last update: 2024-12-21 14:07:09 UTC
README
PHP library which facilitates communication with the Bitcoin JSON-RPC API. The rest of this documentation refers to the Bitcoin wallet, but this library works with any Bitcoin wallet descendant. Including wallets for Litecoin and Dogecoin.
- Overview
- Requirements
- Installing
- Wallet Configuration
- Quick Start
- Class Documentation
- Change Log
- TODO
- License
Overview
The goal of this project is to provide more than a thin PHP wrapper to the Bitcoin JSON-RPC API; there are plenty of PHP libraries for that purpose. This library is meant to be more powerful than other libraries by offering the following features:
- Concrete methods are defined for each API call, which means modern IDEs can provide auto-complete and argument documentation.
- Arguments for each API call are checked for correct type and format, which is useful during development and debugging.
- Abstracts away some of the Bitcoin API complications and inconsistencies, while tyring to stay close to the original.
- Better error handling and reporting.
- RPCPool management so that wallets may be clustered, with queries are evenly distributed to the cluster.
- Follows PSR standards.
- Designed from the ground up to be unit testable.
- Solid documentation for each API call, which is often taken directly from the Bitcoin source code.
See the Bitcoin API wiki for information on each method.
Requirements
- PHP 5.5 or greater.
- SimpleXML PHP extension.
- psr/log.
- A Bitcoin wallet which supports the JSON-API API.
Installing
Add the project to your composer.json as a dependency.
"require": {
"headzoo/bitcoin-wallet-api" : "dev-master"
}
And then run composer update
.
Wallet Configuration
You will need to configure you wallet to act as a server before using this library. This is done by adding a few
configuration values to the bitcoin.conf
file. Shut down your wallet if it's running, and find your Bitcoin data
directory. By default the data directory is located at /home/[user]/.bitcoin
on Linux systems,
and /Users/[user]/AppData/Roaming/Bitcoin
on Windows systems. Create the bitcoin.conf
file in the data directory
if it does not already exist.
Add the following lines:
rpcuser=testuser
rpcpassword=testpass
rpcallowip=127.0.0.1
rpcport=9335
server=1
You will of course want to choose a strong username and password combination. Non-Bitcoin wallets are configured in the
same way. For example the Litecoin data directory is located at /home/[user]/.litecoin
on Linux systems,
and /Users/[user]/AppData/Roaming/Litecoin
on Windows systems, and the configuration file is named litecoin.conf.
Note: You will also need to add txindex=1
to your configuration if you want to query the wallet for non-wallet
transactions. You may need to start your wallet with the -rescan
switch for the first time after adding this
configuration directive.
Quick Start
<?php use Headzoo\Bitcoin\Wallet\Api\JsonRPC; use Headzoo\Bitcoin\Wallet\Api\Wallet; use Headzoo\Bitcoin\Wallet\Api\RPCException; // These configuration settings must match those from the bitcoin.conf file. $conf = [ "user" => "testuser", "pass" => "testpass", "host" => "127.0.0.1", "port" => 9332 ]; // Begin by creating a Wallet instance, which needs an instance of JsonRPC passed to it's constructor. $wallet = new Wallet(new JsonRPC($conf)); try { // Get some basic information from the wallet. $info = $wallet->getInfo(); print_r($info); } catch (RPCException $e) { echo $e->getTraceAsString(); die(); } // Example output: // [ // "version" => 90000, // "protocolversion" => 70002, // "walletversion" => 60000, // "balance" => 6.02730425, // "blocks" => 292075, // "timeoffset" => -1, // "connections" => 65, // "proxy" => "", // "difficulty" => 4250217919.86953540, // "testnet" => false, // "keypoololdest" => 1387569300, // "keypoolsize" => 101, // "paytxfee" => 0, // "mininput" => 0.00100000, // "unlocked_until" => 0, // "errors" => "" // ] try { // Get information about a specific block from the block chain. $block = $wallet->getBlock("00000000000000005242ff2ddc9a407d67632ae7ee97f8c472358931b8bfc679"); print_r($block); } catch (RPCException $e) { echo $e->getTraceAsString(); die(); } // Example output: // [ // "hash" => "00000000000000005242ff2ddc9a407d67632ae7ee97f8c472358931b8bfc679", // "confirmations" => 6, // "size" => 76575, // "height" => 292068, // "version" => 2, // "merkleroot" => "2520dd58da8b7e8d9f416db0c2d6669e63eb722a6bc6c344abfcfe64ac0ab024", // "tx" => [ // "38c78866705c623615c502f13dff5da60cdfee74ec77025bbc0cd419b215bf5d", // "46f551c0ba5822410c2349c6114dfb668adab827180eb5489a289b940e996682" // ], // "time" => 1395587882, // "nonce" => 1796742204, // "bits" => "190102b1", // "difficulty" => 4250217919.86953540, // "chainwork" => "000000000000000000000000000000000000000000002c6e31ad55d7fe8c8665", // "previousblockhash" => "0000000000000000fa0424195c23ca1078d04011796f382778f211bde0a08ae5", // "nextblockhash" => "0000000000000000c965941f8821c858c882414f0819aeccf1593076f97cb150" // ] // Signing a message using an address from the wallet, and then verifying the signature. $address = "16sycWcsHDM1iedeLs11jDmryqHwsz8Bfd"; $message = "Mary had a little lamb."; try { // Encrypted wallets must be unlocked first. $wallet->unlock("asd3sd945DS3a8D"); $signature = $wallet->signMessage($address, $message); var_dump($signature); } catch (RPCException $e) { echo $e->getTraceAsString(); die(); } // Example output: // "IEE8F4Idkqt/q4qN4dXrMQBwrpetyrbAtPYptw+PM8As+XhSjo3qedsrlCccjaX7W+Gm9uXFz/MfLonwObgJkYw=" try { $is_valid = $wallet->isSignedMessageValid($address, $signature, $message); var_dump($is_valid); } catch (RPCException $e) { echo $e->getTraceAsString(); die(); } // Example output: // bool(true)
Class Documentation
The full class API documentation is available in the /docs directory.
Headzoo\Bitcoin\Wallet\Api\JsonRPC
Core class which directly communicates with Bitcoin wallets supporting the JSON-RPC API. This class provides a single
query($method, array $params = [])
method via the Headzoo\Bitcoin\Wallet\Api\JsonRPCInterface
interface. Although you may
use this class directly to query a wallet, it's best to use an instance of Headzoo\Bitcoin\Wallet\Api\Wallet
instead.
<?php use Headzoo\Bitcoin\Wallet\Api\JsonRPC; use Headzoo\Bitcoin\Wallet\Api\RPCException; $conf = [ "user" => "testuser", "pass" => "testpass", "host" => "127.0.0.1", "port" => 9332 ]; $rpc = new JsonRPC($conf); try { $info = $rpc->query("getinfo"); } catch (RPCException $e) { echo $e->getTraceAsString(); die(); }
Headzoo\Bitcoin\Wallet\Api\Wallet
Wraps an instance of Headzoo\Bitcoin\Wallet\Api\JsonRPCInterface
to provide a higher level interface to the wallet API. This
class has methods for every single API call, eg Headzoo\Bitcoin\Wallet\Api\Wallet::getInfo()
, Headzoo\Bitcoin\Wallet\Api\Wallet::backup($destination)
,
Headzoo\Bitcoin\Wallet\Api\Wallet::getAccount($account)
, etc. Using this class instead of directly using Headzoo\Bitcoin\Wallet\Api\JsonRPC
makes it easier to catch programming errors, and allows IDEs to provide auto-complete and type hinting.
<?php use Headzoo\Bitcoin\Wallet\Api\JsonRPC; use Headzoo\Bitcoin\Wallet\Api\Wallet; use Headzoo\Bitcoin\Wallet\Api\RPCException; $conf = [ "user" => "testnet", "pass" => "testnet", "host" => "localhost", "port" => 9332 ]; try { $wallet = new Wallet(JsonRPC($conf)); $info = $wallet->getInfo(); $account = $wallet->getAccount("personal"); $count = $wallet->getBlockCount(); } catch (RPCException $e) { echo $e->getTraceAsString(); die(); }
Headzoo\Bitcoin\Wallet\Api\RPCPool
Wallet servers may be clustered and queried randomly using the Headzoo\Bitcoin\Wallet\Api\RPCPool
class.
Both Headzoo\Bitcoin\Wallet\Api\JsonRPC
and Headzoo\Bitcoin\Wallet\Api\RPCPool
implement Headzoo\Bitcoin\Wallet\Api\JsonRPCInterface
, which
means either may be passed to the Headzoo\Bitcoin\Wallet\Api\Wallet
constructor.
<?php use Headzoo\Bitcoin\Wallet\Api\RPCPool; use Headzoo\Bitcoin\Wallet\Api\JsonRPC; use Headzoo\Bitcoin\Wallet\Api\RPCException; // Start by creating a new pool, adding JsonRPCInterface instances to it, and then pass the pool // to the Wallet constructor. $conf = [ "wallet1" => [ "user" => "testnet", "pass" => "testnet", "host" => "localhost", "port" => 9332 ], "wallet2" => [ "user" => "testnet", "pass" => "testnet", "host" => "localhost", "port" => 9333 ] ]; $pool = new RPCPool(); $pool->add(new JsonRPC($conf["wallet1"])); $pool->add(new JsonRPC($conf["wallet2"])); $wallet = new Wallet($pool); // A different server will be chosen by the pool for each method call. try { $info = $wallet->getInfo(); $balance = $wallet->getBalance(); $accounts = $wallet->getAccounts(); } catch (Headzoo\Bitcoin\Wallet\Api\RPCException $e) { echo $e->getTraceAsString(); die(); }
Change Log
v0.4.0 - 2014/03/23
- Increased minimum PHP version to 5.5.
- Renamed project to Bitcoin Wallet API.
- Renamed namespace
Headzoo\CoinTalk
toHeadzoo\Bitcoin\Wallet\Api
. - Refactored the unit tests to use more mocks.
- Using headzoo/web-tools for making HTTP requests.
v0.3.0 - 2014/03/23
- Renamed class
Headzoo\CoinTalk\Api
toHeadzoo\CoinTalk\Wallet
. - Renamed class
Headzoo\CoinTalk\Server
toHeadzoo\CoinTalk\JsonRPC
. - Renamed class
Headzoo\CoinTalk\IServer
toHeadzoo\CoinTalk\JsonRPCInterface
. - Renamed class
Headzoo\CoinTalk\Pool
toHeadzoo\CoinTalk\RPCPool
. - Renamed methods starting with
list
in theHeadzoo\CoinTalk\Wallet
class withget
, eglistAccounts()
was renamed togetAccounts()
. - Renamed the following methods to make the method names more consistent, and so they conform to my naming standards:
Headzoo\CoinTalk\Wallet::sendRawTransaction()
toHeadzoo\CoinTalk\Wallet::submitRawTransaction()
.Headzoo\CoinTalk\Wallet::submitBlock()
toHeadzoo\CoinTalk\Wallet::submitRawBlock()
.Headzoo\CoinTalk\Wallet::getRawMemPool()
toHeadzoo\CoinTalk\Wallet::getTransactionsFromMemoryPool()
.Headzoo\CoinTalk\Wallet::dumpPrivKey()
toHeadzoo\CoinTalk\Wallet::getPrivateKeyByAddress()
.Headzoo\CoinTalk\Wallet::importPrivKey()
toHeadzoo\CoinTalk\Wallet::addPrivateKey()
.Headzoo\CoinTalk\Wallet::lockUnspent()
toHeadzoo\CoinTalk\Wallet::setLockUnspent()
.Headzoo\CoinTalk\Wallet::sendToAddress()
toHeadzoo\CoinTalk\Wallet::send()
.Headzoo\CoinTalk\Wallet::sendFrom()
toHeadzoo\CoinTalk\Wallet::sendFromAccount()
.Headzoo\CoinTalk\Wallet::sendMany()
toHeadzoo\CoinTalk\Wallet::sendManyFromAccount()
.Headzoo\CoinTalk\Wallet::verifyMessage()
toHeadzoo\CoinTalk\Wallet::isSignedMessageValid()
.Headzoo\CoinTalk\Wallet::validateAddress()
toHeadzoo\CoinTalk\Wallet::getAddressInfo()
.Headzoo\CoinTalk\Wallet::encryptWallet()
toHeadzoo\CoinTalk\Wallet::encrypt()
.Headzoo\CoinTalk\Wallet::walletLock()
toHeadzoo\CoinTalk\Wallet::lock()
.Headzoo\CoinTalk\Wallet::walletPassPhrase()
toHeadzoo\CoinTalk\Wallet::unlock()
.Headzoo\CoinTalk\Wallet::walletPassPhraseChange()
toHeadzoo\CoinTalk\Wallet::changePassPhrase()
.Headzoo\CoinTalk\Wallet::keyPoolRefill()
toHeadzoo\CoinTalk\Wallet::fillKeyPool()
.Headzoo\CoinTalk\Wallet::stop()
toHeadzoo\CoinTalk\Wallet::stop()
.Headzoo\CoinTalk\Wallet::setTxFee()
toHeadzoo\CoinTalk\Wallet::setTransactionFee()
.Headzoo\CoinTalk\Wallet::getReceivedByAddress()
toHeadzoo\CoinTalk\Wallet::getBalanceByAddress()
.Headzoo\CoinTalk\Wallet::getAccount()
toHeadzoo\CoinTalk\Wallet::getAccountByAddress()
.Headzoo\CoinTalk\Wallet::getAccountAddress()
toHeadzoo\CoinTalk\Wallet::getAddressByAccount()
.Headzoo\CoinTalk\Wallet::createMultiSig()
toHeadzoo\CoinTalk\Wallet::getNewMultiSignatureAddress()
.Headzoo\CoinTalk\Wallet::addMultiSigAddress()
toHeadzoo\CoinTalk\Wallet::addMultiSignatureAddress()
.Headzoo\CoinTalk\Wallet::getTxOut()
toHeadzoo\CoinTalk\Wallet::getTransactionOut()
.Headzoo\CoinTalk\Wallet::getTxOutSetInfo()
toHeadzoo\CoinTalk\Wallet::getTransactionOutSet()
.Headzoo\CoinTalk\Wallet::getAddedNodeInfo()
toHeadzoo\CoinTalk\Wallet::getNodeInfo()
.
- Removed the following methods:
Headzoo\CoinTalk\Wallet::getReceivedByAccount()
.Headzoo\CoinTalk\Wallet::listReceivedByAccount()
.
v0.2.0 - 2013/12/31
- Minor tweaks.
v0.1.0 - 2013/12/18
- Genesis import!
TODO
- Ensure the wallet server version supports specific calls.
- Document which methods need an unlocked wallet.
- Create classes which represent:
- Blocks
- Keys (public/private)
- Transactions
- etc
License
This content is released under the MIT License. See the included LICENSE for more information.
I write code because I like writing code, and writing code is a reward in itself, but donations are always welcome.
Bitcoin: 1Headz2mYtpBRo6KFaaUEtcm5Kce6BZRJM
Litecoin: LheadzBgTNAitxYxUTUTTQ3RT7zR5jnkfq