Как я могу просто подписать транзакцию Ethereum?

Я хочу использовать blockcypher для работы с сетью Ethereum.

В документации приведен пример инструмента для подписания, написанного на Go, но я использую Python.

Как проще всего подписать транзакцию?

Я пытался использовать web3.py , но столкнулся с некоторыми трудностями.

Здесь они приводят следующий пример:

transaction = {
       'to': '0xF0109fC8DF283027b6285cc889F5aA624EaC1F55',
       'value': 1000000000,
       'gas': 2000000,
       'gasPrice': 234567897654321,
       'nonce': 0,
       'chainId': 1
}
key = '0x4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318'
signed = w3.eth.account.signTransaction(transaction, key)
signed.rawTransaction
HexBytes('0xf86a8086d55698372431831e848094f0109fc8df283027b6285cc889f5aa624eac1f55843b9aca008025a009ebb6ca057a0535d6186462bc0b465b561c94a295bdb0621fc19208ab149a9ca0440ffd775ce91a833ab410777204d5341a6f9fa91216a6f3ee2c051fea6a0428')
signed.hash
HexBytes('0xd8f64a42b57be0d565f385378db2f6bf324ce14a594afc05de90436e9ce01f60')
signed.r
4487286261793418179817841024889747115779324305375823110249149479905075174044
signed.s
30785525769477805655994251009256770582792548537338581640010273753578382951464
signed.v
37

Но я не понимаю некоторые значения, которые нужно передать в transaction.

Что такое nonce, chainId?

Используя такие данные:

transaction = {
    'to': '0xe980e77404ae62ab0f2d6b8510bd951e25185414',
    'value': value,
    'gas': 2000000,
    'gasPrice': 1000000000,,
    'nonce': 0,
    'chainId': 1
}

Я получаю эту ошибку:

TypeError: Transaction had invalid fields: {'to': '0xe980e77404ae62ab0f2d6b8510bd951e25185414'}

Далее я попытался использовать ecdsa

Но я не смог найти простой пример. Я вообще ничего не понимаю в криптографии, и мне нужен самый простой способ отправить транзакцию в сеть, не вникая в детали.

ОБНОВЛЯТЬ

Я старался не использовать w3, так как мне нужно только подписать транзакцию.

Я смог сделать это, чтобы создать подпись:

импортировать hashlib импортировать binascii

импорт ecdsa

def sign(privkey, message):
    sk = ecdsa.SigningKey.from_string(
        binascii.unhexlify(privkey),
        curve=ecdsa.SECP256k1,
        hashfunc=hashlib.sha256
    )
    signature = binascii.hexlify(
        sk.sign(
            binascii.unhexlify(message),
            hashfunc=hashlib.sha256
        )
    )
    return signature

И функция работает нормально, я возвращаю строку байтов следующим образом:

b'4ace74a83082b5fc6d356083932b493e9fafbe0fabca19be3e77ccda188d08c6352f1fccb144e18b95a3f7e18f71fe95d79a9dd8ad9ecaa7490315f06a00177f'

Но длина этой строки 128 символов, а в примере с блочным шифром строка из 148 символов.

После попытки отправить подписанную транзакцию в сеть получаю такой ответ:

{'error': 'Could not compute an address from provided signature: invalid transaction v, r, s values.'}

Скорее всего, я создаю неправильную подпись, но как сделать правильную?

Кажется, я почти у цели, но все равно не получается.

Ответы (2)

Версия 4.x web3.py требует, чтобы все адреса использовали правильную контрольную сумму EIP 55 . В моем тестировании я получаю ту же ошибку, что и вы, пока не преобразую адрес в правильную форму контрольной суммы (обратите внимание на заглавные буквы):

0xe980E77404ae62aB0F2d6b8510BD951e25185414

(Обратите внимание, что у вас также есть дополнительная запятая, которая делает ваш код синтаксически недействительным, но я предполагаю, что это просто ошибка копирования/вставки.)

Адрес, отображаемый на etherscan, вводит в заблуждение, так как они показывали его строчными буквами, что не соответствует EIP 55.

Спасибо @smarx за подсказку.

Однако мне удалось найти другое решение:

from bitcoin import ecdsa_raw_sign
from bitcoin import der_encode_sig

def signing(transaction, privkey):
    signature = der_encode_sig(*ecdsa_raw_sign(transaction, privkey))
    return signature