Интерфейс для приёма Bitcoin платежей на Perl

7 Авг
2011

Основным отличием организации приёма Bitcoin денег при платежах пользователей является невозможность установить плательщика по осуществленной транзакции т.к. каждый покупатель анонимный и может иметь неограниченное количество кошельков и аккаунтов. Это значит, что при поступлении денег на наш кошелёк мы не можем идентифицировать покупателя чтобы выслать ему нужный товар или оказать купленную услугу. В качестве решения будем использовать генерацию уникального Bitcoin адреса для каждой транзакции. Для генерации адреса потребуется запущенный bitcoind, которому мы будем отправлять команды и получать ответ по JSON-RPC протоколу с использованием Perl модуля Finance::Bitcoin::API Bitcoind входит в состав дистрибутива скачиваемого с http://www.bitcoin.org. Скомпилированную версию возможно сразу запустить из каталога /bin/32(64). Перед запуском демона следует в конфигурационном файле ~/.bitcoin/bitcoin.conf указать логин и пароль для RPC подключения.
rpcuser=someuser
rpcpassword=password
После запуска демона подключение к нему из Perl на той же машине выглядит так:
 use Finance::Bitcoin::API;
 
# rpc_user, rpc_pswd, host, port
my $uri = 'http://someuser:password@localhost:8332/';
my $bitcoin_hndl = Finance::Bitcoin::API->new( endpoint => $uri );
 
my $balance = $bitcoin_hndl->call('getbalance');
 
die( $bitcoin_hndl->error ) if $bitcoin_hndl->error;
 
print "$balance\n";
 
...
Полный список поддерживаемых JSON RPC функций с их параметрами и возвращаемыми значениями можно найти тут. Новые адреса будем генерировать и помещать в БД для отслеживания статусов платежей. Таблица выглядит примерно так:
 id int, - Уникальный идентификатор транзакции, может быть просто autoincrement
date timestamp, - время создания транзакции
address varchar(64), - адрес, на который ожидаем поступления платежа от одного клиента по одной услуге
amount_expected float, - сколько денег клиент должен заплатить
amount_received float, - сколько денег пришло на текущий момент
trx_stat int - статус транзакции
Статусы транзакции — это некоторые величины, отображающие состояние операции платежа на текущий момент.
  • 0 = транзакция отменена
  • 1 = в процессе, деньги не приходили
  • 2 = в процессе, деньги пришли, но недостаточно заявленной сумме
  • 3 = транзакция завершена, деньги пришли в заявленной сумме
  • 4 = транзакция завершена, денег пришло больше, чем надо
  • 5 = транзакция закрыта, деньги переведены коллектору
Прежде всего, чтобы не запутаться, под транзакцией в данном случае я подразумеваю не Bitcoin транзакцию, а биллинговую транзакцию, т.е. осуществление платежа. Если клиент платит на предоставленный ему Bitcoin адрес с нескольких кошельков в несколько приёмов до достижения необходимой суммы — мы получим на одну биллинговую транзакцию несколько Bitcoin транзакций. С точки зрения организации платежного интерфейса Bitcoin транзакции нам не нужны. Когда клиент нажимает кнопку ‘оплатить 0.5 BTC’ на сайте — мы генерируем для оплаты адрес, предоставляем клиенту и помещаем информацию о сумме и адресе для приёма в БД под уникальным id. Тут стоит обратить внимание что мы явно указываем вторым аргументом метода call() аккаунт. Дело в том, что для одного Bitcoin кошелька может быть несколько аккаунтов и каждый аккаунт может иметь несколько адресов. Мы генерируем связку 1 аккаунт — 1 адрес, создавая аккаунт вместе с адресом и давая ему имя, аналогичное id транзакции. В дальнейшем это удобно для распределения денег при отправке коллектору, т.к. без явного указания аккаунта, деньги снимаются с любого, на котором имеется достаточная сумма для отправки.
 ...
my $pay_sum = 10; #BTC
my $transaction_id = $last_transaction + 1;
 
...
 
my $new_address = $bitcoin_hndl->call('getnewaddress', "$transaction_id");
 
...
 
my $sql = "INSERT INTO transactions
( id, address, amount_expected, amount_received, trx_stat )
VALUES
( $transaction_id, $new_address, $pay_sum, 1)";
Привязку кода товара/услуги к данной id транзакции и к покупателю осуществляем в другой таблице, это выходит за рамки описания платежного интерфейса. Далее периодически (по crontab или еще как-то) проверяем баланс на созданном адресе.
my $amount_received = $bitcoin_hndl->call('getbalance' , "$transaction_id");
Если баланс изменяется, то меняем статус транзакции и значение поля amount_received в БД. При достижении amount_received необходимой суммы, мы закрываем транзакцию, выставляя ей статус 5, а деньги переводим коллектору — т.е. на некий аккаунт и адрес, который собирает все поступившие платежи. … my $send_to_address_is_valid = $bitcoin_hndl->call(‘sendfrom’, «$transaction_id», $collector_address, $amount_received); Где-то в другой таблице отмечаем что товар/услуга успешно оплачены. В случае отмены транзакции, ей просто в базе выставляется статус 0 и она больше не обрабатывается. Я дал только основные наброски по организации приёма Bitcoin платежей. На самом деле это всё оформлено в большой модуль, предоставляющий некоторое API для внешних биллинговых функций.
По материалам Хабрахабр.



загрузка...

Комментарии:

Наверх