Метка: криптовалюта

Отправить Bitcoin средствами Python

КДПВ

Чтобы создать биткоин транзакцию в наше время не нужно прилагать много усилий. Есть специальные доверенные онлайн сервисы, которые отправят вашу транзакцию в сеть бесплатно (без учета комиссии сети) и безопасно. Вам даже не нужно устанавливать ноду биткоина локально и выкачивать весь блокчейн. Еще лучше то, что под 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 👈 

Генерируем Bitcoin-адрес на Python

Тема криптовалют снова начинает будоражить интернет. Супер, что вам не надо идти в отделение банка с паспортом и выстаивать очередь, чтобы открыть счет. Сгенерировать кошелек Bitcoin — дело нескольких строк кода на Python.

Нам понадобятся библиотеки base58 и ecdsa. base58 – это кодирование бинарных данных 58-ю печатными символами (цифрами и латинскими буквами, кроме 0, O, I, l, которые похожи друг на друга). ecdsa – библиотека криптографии на эллиптических кривых.

pip install base58 ecdsa

Импортируем то, что нужно:

import hashlib
import ecdsa
from binascii import hexlify
from base58 import b58encode

Нам нужен приватный ключ, из него мы вычислим публичный ключ, а из него – адрес кошелька Bitcoin. (Обратная процедура не возможна без полного перебора до конца времен). Приватный ключ – это 32 байта данных, которые мы получим из криптографически-надежного источника случайных чисел. Вообще можно придумать свой приватный ключ самостоятельно, если так хочется. Для генерации случайного приватного ключа мы воспользуемся библиотекой ecdsa:

private_key = ecdsa.SigningKey.generate(curve=ecdsa.SECP256k1)

Вычислим этой же библиотекой публичный ключ и добавим спереди байт 0x4 (это признак «несжатого» публичного ключа; есть и другие форматы).

public_key = b'\04' + private_key.get_verifying_key().to_string()

Теперь нужно из публичного ключа сделать привычный число-буквенный адрес Bitcoin. Взглянем на схему:

Схема генерации адреса BTC из публичного ключа.

Для получения адреса из публичного ключа вычисляем сначала RIPEMD160(SHA256(public-key)):

ripemd160 = hashlib.new('ripemd160')
ripemd160.update(hashlib.sha256(public_key).digest())

Дополняем его префиксом 0x0 (главная сеть Bitcoin):

r = b'\0' + ripemd160.digest()

Вычисляем контрольную сумму (нужна, чтобы наши денюжки не пропадали, если мы ошибемся в каком-то символе адреса). Контрольная сумма это первые 4 байта от SHA256(SHA256(r)):

checksum = hashlib.sha256(hashlib.sha256(r).digest()).digest()[0:4]

Получаем адрес кошелька, закодировав в base58 сложенные r и checksum:

address = b58encode(r + checksum)

Выведем результат:

print(f'private key: {hexlify(private_key.to_string())}')
print(f'public key uncompressed: {hexlify(public_key)}')
print(f'btc address: {address}')

Генерация приватного ключа из своего источника случайностей, например, os.urandom:

def random_secret_exponent(curve_order):
    while True:
        bytes = os.urandom(32)
        random_hex = hexlify(bytes)
        random_int = int(random_hex, 16)
        if random_int >= 1 and random_int < curve_order:
            return random_int


def generate_private_key():
    curve = ecdsa.curves.SECP256k1
    se = random_secret_exponent(curve.order)
    from_secret_exponent = ecdsa.keys.SigningKey.from_secret_exponent
    return from_secret_exponent(se, curve, hashlib.sha256).to_string()

Важно для конфиденциальных данных, вроде приватного ключа, использовать криптографически безопасный источник случайности. Об этом я писал в одной из недавних статей!

Полный пример кода генерации кошельков.

Проверить ключи и адрес можно здесь. (Нажимаем Skip, дальше Enter my own…)

Подробнее по теме можно почитать здесь.

Специально для канала @pyway. Подписывайтесь на мой канал в Телеграм @pyway 👈 

NXT Coin

NXT server on my window
NXT server on my window

Решил поставить у себя сервер для новой криптовалюты. Ну не поставить, а повесить скорее 🙂 Небольшое описание:

Криптовалюта второго поколения Nxt (от «Next») запущена 24.11.2013 г.: основная веткапервоначальная ветка.
Это чисто PoS система, ~1 блок/минута, сложность пересчитывается каждый блок.
Всего эмитирован 1 млрд монет (пропорционально биткоинам, которые ранние адепты Nxt переводили автору), больше эмиссии не будет, майнинг происходит полностью за счёт транзакционных сборов (т.е. как это будет с Биткоином через 30 лет), минимальная комиссия — 1 Nxt.

Вообще-то это совсем не форк биткоина, т.к. софт (полностью на java) написан с нуля.
Чтобы Nxt не форкнули немедленно, автор намерен полностью опубликовать исходники не ранее 3-го января 2014 г., сейчас исходный код доступен частично.

Nxt — система по-настоящему децентрализованная, нет даже wallet.dat. Клиента как отдельного приложения тоже нет, весь функционал доступен через web-браузер. Счёт пользователи себе заводят через web-интерфейс(весёленький, нужно отменить) путём выбора длинной сложной фразы, примерно как в Brainwallet или Electrum. Войти в свой счёт можно с любого веб-браузера, лучше через IP адрес своего сервера, но можно и через любой другой сервер (если вы ему доверяете). В любом из этих случаев после открытия счёта монеты участвуют в PoS-майнинге, правда, свежекупленные монеты должны для этого вылежаться 1440 блоков, т.е. ~ 1 сутки.

(Источник: https://bitcointalk.org/index.php?topic=345882.0)

Небольшой FAQ (вопросы и ответы):

Вопрос. Зачем тебе это надо?

Ответ. Потому что могу. У меня оборудование, которое лежит без дела, и я хочу его пустить на благое дело – развитие новой финансовой системы. Bitcoin завоевал уже серьезную популярность и даже признание со стороны правительств. А NXT – только первая ласточка второго поколения криптовалюты. Хочу помочь проекту, тем более, что это мне ничего не стоит. Я потратил на это минимум денег и времени.

Вопрос. Тебя обманывают! (Это не вопрос). А вдруг оно взламывает пароли Пентагона?

Ответ. Я никому не плачу за это. Моя информация сохранна (так как все крутится на отдельной железке). Взламывает пароли? Вздор! Да, исходные коды еще полностью не открыты, но скоро будут открыты. Это обязательное условия признания валюты общественностью, мы будем наверняка знать, что делает эта программа. Даже если она взламывает чужие пароли, то мой девайс абсолютно в этом не эффективен. Это, наверное, самый медленный мой компьютер. Никому он вреда, кроме самого злоумышленника он не нанесет, а взломщику придется перекладывать задания с моего сервера на другой, так как мой с ним и не справится (грубо говоря). Обвинить меня в соучастии не получится, ведь я скачивал программу для совершенно других целей и только окажусь невинной жертвой мошенника. Также сложно вычислить отдельных людей, потому что в системе уже участвуют тысячи… В общем слишком много «но», чтобы эта бредовая идея была похожа на правду.

Вопрос. Ты не будешь успевать гнаться за нарастающими мощностями, требуемыми для майнинга монет. Потратишь кучу денег на ненужное оборудование и электроэнергию. 

Ответ. Иди читай статью. В NXT не нужны вычислительные мощности. Это все в прошлом. Все работает по-другому. Майнинга нет. Сервера нужны, чтобы поддерживать и подтверждать транзакции. Поэтому оконного сервера мне хватает за глаза. Я не скоро обновлю эту железку. А она потребляет максимум 2.5 Ватта (от обычного USB). Это в 400 раз меньше, чем утюг или чайник или даже мой стационарный компьютер (там БП аж на 1100 Ватт).

Вопрос. А что за железяка-то?

Ответ. PCduino (ARM), 1 Ghz, 1 Gb RAM, 4 Gb ROM, HDMI, GPIO (Arduino-like), Ubuntu. NXT сам на JAVA. Штукенция обошлась мне в 60 баксов, которые я взял из рекламных денег моей игры. Настройка и чтение отняли около двух часов времени.

Вопрос. Где ты узнал про NXT?

Из поста Артема в ВК.