
Чтобы создать биткоин транзакцию в наше время не нужно прилагать много усилий. Есть специальные доверенные онлайн сервисы, которые отправят вашу транзакцию в сеть бесплатно (без учета комиссии сети) и безопасно. Вам даже не нужно устанавливать ноду биткоина локально и выкачивать весь блокчейн. Еще лучше то, что под Python есть супер-удобные библиотеки, чтобы пользоваться этими сервисами.
Давайте поставим библиотеку bit:
pip install bit
Ключи
Ключ – центральное понятие в мире Биткоина. Приватный ключ – это ваш кошелек. Вы храните его в секрете от всех. Публичный ключ получается из приватного. А адрес кошелька, получается из публичного ключа. Это преобразование одностороннее: нужно затратить колоссальный объем вычислительной мощности и миллиарды лет времени, чтобы к адресу подобрать приватный ключ и получить контроль над средствами. Я уже рассказывал о генерации ключей биткоин вручную. Но библиотека bit прекрасно делает это за вас.
У биткоина две сети – главная и тестовая. В каждой свои ключи и свои виды адресов. Генерация нового ключа для основной сети, где адреса обычно начинаются с цифры:
from bit import Key key = Key() print(k.address) # 1C8REeQUnXE3HtLCYXVG21AryDxRXnnyar
Класс Key
– псевдоним для PrivateKey
:
from bit import Key, PrivateKey print(PrivateKey is Key) # true
Для демонстрационных целей, я буду использовать тестовую сеть. В ней монеты ничего не стоят и их легко получить. Адреса тестовой сети обычно начинаются с буквы m
или n
! Ключ тестовой сети описан классом PrivateKeyTestnet
:
from bit import PrivateKeyTestnet k = PrivateKeyTestnet() print(k.address) # mrzdZkt4GfGMBDpZnyaX3yXqG2UePQJxpM
Если мы в конструкторе класса ключа не указали параметров, то каждый раз создается новый (почти наверняка пустой – без баланса) адрес. Генерация происходит локально (без обращения к онлайн сервисам) и очень быстро. Но, если приватный ключ не сохранен, то после завершения программы доступ будет утерян. Поэтому сгенерируем приватный ключ и запишем его в блокноте. Адрес получается по свойству k.address
, а приватный ключ можно получить в разных форматах, самый удобный из них – WIF (Wallet Export Format) – получаем строку методом k.to_wif()
:
from bit import PrivateKeyTestnet as Key k = Key() print('Private key:', k.to_wif()) print('Public address:', k.address) # Private key: cQqh9xFys2KJyWhHMaBwG2kFLCNBCmTgxVqnPTXK6Vng4vU6igoV # Public address: mhnmzFN5gr6gvmEr1t8UcRh6rdTh6JxuDe
Также по приватному ключу можно получить еще SegWit адрес. Если очень кратко, то этот адрес будет работать быстрее, чем традиционный.
print(k.segwit_address) # 2MsWNuzx8EfgEeGLesLmkMM6q3kajEjVnVh
Воспользуемся биткоин краном, чтобы получить немного тестовых монет бесплатно:

Транзакция займет некоторое время (минут 10-20). Так что наберитесь терпения!
А пока она идет, создадим класс ключа уже из сохраненной секретной строки:
from bit import PrivateKeyTestnet as Key k = Key('cQqh9xFys2KJyWhHMaBwG2kFLCNBCmTgxVqnPTXK6Vng4vU6igoV') print(k.address) # mhnmzFN5gr6gvmEr1t8UcRh6rdTh6JxuDe ура тот же!
Приватный ключ может быть представлен, как число, байты, HEX-строка, в WIF, DER и PEM форматах:
from bit import PrivateKeyTestnet as Key k = Key('cQqh9xFys2KJyWhHMaBwG2kFLCNBCmTgxVqnPTXK6Vng4vU6igoV') print('Int:', k.to_int(), end='\n\n') print('Hex:', k.to_hex(), end='\n\n') print('Bytes:', k.to_bytes(), end='\n\n') print('WIF:', k.to_wif(), end='\n\n') print('DER:', k.to_der(), end='\n\n') print('PEM:', k.to_pem(), end='\n\n')
Вывод:
Int: 4397583691621789343100573085...453641742227689755261559235 Hex: 6139710fb66e82b7384b868bda1ce59a0bd216e89b8808ae503c5767e4d461c3 Bytes: b'a9q\x0f\xb6n\x82\xb78K\x86\x8b\xd...d4a\xc3' WIF: cQqh9xFys2KJyWhHMaBwG2kFLCNBCmTgxVqnPTXK6Vng4vU6igoV DER: b'0\x81\x84\x02\...xb3b\x8e\x1ar\xc6' PEM: b'-----BEGIN PRIVATE KEY-----\nMIGEA.....O\nrRnD/Ls2KOGnLG\n-----END PRIVATE KEY-----\n'
Также, удобно создавать класс ключа из WIF формата функцией wif_to_key
, она сама определит тип сети и создаст нужный класс:
from bit import wif_to_key k = wif_to_key('cQqh9xFys2KJyWhHMaBwG2kFLCNBCmTgxVqnPTXK6Vng4vU6igoV') print(k) # <PrivateKeyTestnet: mhnmzFN5gr6gvmEr1t8UcRh6rdTh6JxuDe>
Надеюсь монеты с крана вам уже дошли, и мы продолжим.
Баланс
Узнаем баланс нашего кошелька. Для этого внутри bit используются онлайн сервисы (https://insight.bitpay.com, https://blockchain.info, https://smartbit.com.au). Поэтому операция не моментальная.
from bit import PrivateKeyTestnet as Key k = Key('cQqh9xFys2KJyWhHMaBwG2kFLCNBCmTgxVqnPTXK6Vng4vU6igoV') print(k.get_balance()) # 1391025
Как видите, на тот момент на адресе лежало 1391025 сатоши. 1 сатоши = одна стомиллионная целого биткоина (10-8) – самая маленькая неделимая частичка. Библиотека bit удобна еще тем, что содержит встроенный конвертер валют, поэтому баланс можно получить в любой поддерживаемой валюте: хоть в милибиткоинах, хоть в долларах, хоть в рублях. Просто передайте название валюты аргументом:
print(k.get_balance('mbtc'), 'MBTC') # 13.91025 MBTC print(k.get_balance('usd'), 'USD') # 129.84 USD print(k.get_balance('rub'), 'RUB') # 8087.35 RUB
Как послать монеты?
Очень просто: методом send
. Создадим еще один ключ (dest_k
) и пошлем ему часть биткоинов от source_k
:
from bit import PrivateKeyTestnet as Key source_k = Key('cQqh9xFys2KJyWhHMaBwG2kFLCNBCmTgxVqnPTXK6Vng4vU6igoV') dest_k = Key('cP2Z27v1ZaBz3VQRRSTQRhgYt2x8BtcmAL9zi2JsKaDBHobxj5rx') print(f'Send from {source_k.address} to {dest_k.address}') r = source_k.send([ (dest_k.address, 0.0042, 'btc') ]) print(r) # ID транзакции
Как вы помните, у транзакции может быть много выходов, поэтому первый аргумент функции send
– список – кому и сколько мы посылаем (кортеж: адрес, количество, валюта). В данном случае адресат у нас один ‘n2R8xiqs6BqdgtqpXRDLKrN4BLo9VD171z’, а второй неявный выход – обратно наш же адрес, чтобы получить сдачу. Вот эта транзакция выглядит так:

Через 5 минут я уже получил первое подтверждение перевода! Проверим список транзакций:
transactions = source_k.get_transactions() print(transactions) # ['a101ad526e9fb131b90aac220b8b6e8bf11b9b9848ab8ea6d4384dc5b4ccece0', '0770f10a7b130852e38d9af44e050c9188664c12f2d31a56a62d6648a73e1264'] # Непотраченные входы: unspents = source_k.get_unspents() print(unspents) # [Unspent(amount=967861, confirmations=4, script='76a91418ee4d98c345db083114990baa17d02e988cfedb88ac', txid='a101ad526e9fb131b90aac220b8b6e8bf11b9b9848ab8ea6d4384dc5b4ccece0', txindex=1, segwit=False)]
Пример для нескольких адресатов (каждая валюта будет пересчитана по курсу в биткоин):
my_key.send([ ('1HB5XMLmzFVj8ALj6mfBsbifRoD4miY36v', 0.0035, 'btc'), ('1Archive1n2C579dMsAu3iC6tWzuQJz8dN', 190, 'jpy'), ('129TQVAroeehD9fZpzK51NdZGQT4TqifbG', 3, 'eur'), ('14Tr4HaKkKuC1Lmpr2YMAuYVZRWqAdRTcr', 2.5, 'cad') ])
Если вернуть сдачу не себе, а на другой адрес – аргумент leftover
:
key.send(..., leftover='адрес_для_сдачи')
Если нужно прикрепить к транзакции сообщение (до 40 байт в кодировке UTF-8) – аргумент message
:
key.send(..., message='За кофе и пончик')
Функция create_transaction
только создает транзакцию и подписывает ее ключом, но не посылает ее в сеть. Аргументы те же, что у send
.
Еще раз хочу подчеркнуть, что это безопасно, потому что вы отправляете уже подписанную транзакцию, перехват которой не даст злоумышленникам доступ к вашим средствам или прав на смену получателя.
В худшем случает транзакция не дойдет до сети и не исполнится.
Комиссии
Если комиссия не указана явно, то она рассчитывается по средним значениям с учетом длины транзакции. Средняя комиссия берется из онлайн-сервиса. Но можно указать комиссию самостоятельно:
# комиссия за байт (будет умножена на кол-во байт) source_k.create_transaction(..., fee=72) # комиссия за всю транзакцию целиком source_k.create_transaction(..., fee=200, absolute_fee=True)
Полезные константы комиссий:
from bit.network import fees fees.DEFAULT_FEE_FAST # 10 мин fees.DEFAULT_FEE_HOUR # 1 час
Советы
Иногда лучше пользоваться сервисом для комиссий, потому что из-за смены нагрузки на сеть комиссия для быстрого перевода может варьироваться в широком диапазоне.
Работа с внешними онлайн сервисами может тормозить. В принципе можно поменять их приоритет, но это тема отдельной статьи. Очень хорошо, если вам доступна своя нода биткоин, тогда вы можете подключиться к ней и выполнять все действия без лишних задержек и ограничений! Вот так:
from bit.network import NetworkAPI # тестовая нода NetworkAPI.connect_to_node(user='user', password='password', host='localhost', port='18443', use_https=False, testnet=True) # подключение к ноде главной сети NetworkAPI.connect_to_node(user='user', password='password', host='domain', port='8332', use_https=True, testnet=False) # на выбор или вместе
Храните надежно ваши приватные ключи!
Если вы брали тестовые монеты с крана, пожалуйте, верните обратно их на адрес, который вам предложат. Они могут быть полезны другим разработчикам!
Библиотека bit умеет еще работать с мульти-адресами, которые требует 2 и более подписей для выполнения транзакции.
Специально для канала @pyway. Подписывайтесь на мой канал в Телеграм @pyway 👈