Estoy tratando de trasladar la lógica de generación de TX a un idioma diferente (e impopular). Me he estado golpeando la cabeza contra esto demasiado tiempo y debería haberme ido, pero bueno, ya sabes, el cierre y la terquedad.
Aquí está mi código hasta ahora.
Blockchain.info, Electrum y Bitcoin Core descodifican mi intento de TX en algo de aspecto razonable, como:
{
"txid" : "49c210ae472c5b5e39447e1f6d9bc020cd0f0075cc03d919afb0857a964e1f41",
"version" : 1,
"locktime" : 0,
"vin" : [
{
"txid" : "b097384c42a3be2730db3e3720a1806c76172b6b62b2b5ee007c2c6fd295cadf",
"vout" : 1,
"scriptSig" : {
"asm" : "30460221009f478737296e39bbcff2ef7c6f013acc25bea75941acd8573bcea83ca910018b022100e9bff518297fec344d6e7e42cabc5ec793c4be507af68210bdde803a8a2958ed0104d8f39341451e2e66a00ef010c815f1284bc5e3a187476aab319b2d127b7e219c9b9e68bff311c63474242a9baab34f7ddec05de2c45bd140a74a64621ccb42cb",
"hex" : "4930460221009f478737296e39bbcff2ef7c6f013acc25bea75941acd8573bcea83ca910018b022100e9bff518297fec344d6e7e42cabc5ec793c4be507af68210bdde803a8a2958ed014104d8f39341451e2e66a00ef010c815f1284bc5e3a187476aab319b2d127b7e219c9b9e68bff311c63474242a9baab34f7ddec05de2c45bd140a74a64621ccb42cb"
},
"sequence" : 4294967295
}
],
"vout" : [
{
"value" : 0.00439999,
"n" : 0,
"scriptPubKey" : {
"asm" : "OP_DUP OP_HASH160 7847eb9e366653aeb8857d541236fe4fd90c57e7 OP_EQUALVERIFY OP_CHECKSIG",
"hex" : "76a9147847eb9e366653aeb8857d541236fe4fd90c57e788ac",
"reqSigs" : 1,
"type" : "pubkeyhash",
"addresses" : [
"1BxzF8rgXtuiPuSN8azdMJgryzQSWt4Uoj"
]
}
}
]
}
Al intentar enviar una transacción en Bitcoin Core, aparece el "error -25". Al leer otras publicaciones de StackExchange y buscar en Google, las posibles causas se enumeran como:
"Al leer el código fuente, se devuelve este error cuando falla AcceptToMemoryPool, pero no cuando falla porque la transacción no es válida. ¿Debug.log emite algo cuando esto sucede?"
"Obtienes ese oscuro error de RPC cuando tu tx está usando salidas de las que Bitcoin nunca ha oído hablar". No aparece nada en ~/.bitcoin/debug.log.
Al intentar enviarlo con el servicio slash pushtx de blockchain.info (oh, vamos, ¿en serio no hay una lista blanca para los sitios a los que puedo vincularme?), obtengo "El script resultó en una pila no verdadera: []", que implica que cometí un error en mi lógica de firma en alguna parte.
He caminado a través de estos:
http://procbits.com/2013/08/27/generando-una-direccion-de-bitcoin-con-javascript
http://www.righto.com/2014/02/bitcoins-hard-way-using-raw-bitcoin.html
Se requiere un ejemplo de canje de una transacción sin procesar paso a paso
Y otros, incluidas varias implementaciones de Ruby, Python, Java y JavaScript, pero necesito más de 10 reputación para publicar más de 2 enlaces. No puedo por mi vida averiguar dónde me estoy desviando.
Sé que partes de esos están desactualizados. La clave privada con la que estoy comenzando (de Electrum) no está marcada como comprimida (33 bytes después de DecodeBase58Check y el último es 0x01), por lo que la clave pública en la transacción de la que estoy tratando de extraer tampoco debería estar comprimida.
El TX que estoy tratando de gastar ( b097384c42a3be2730db3e3720a1806c76172b6b62b2b5ee007c2c6fd295cadf , segunda salida, también conocido como 1) con este TX tiene un script de salida que es Pay to Public Key Hash (d9495c762aed3dba15eec648beb3b55a1a4) según blockchain infobd. El scriptPubKey completo del prevout es:
OP_DUP OP_HASH160 d9495c762aed3dba15eec648beb55a8a43b8d1bd OP_EQUALVERIFY OP_CHECKSIG
Mi clave privada, decodificada de WIF y ejecutada a través de ecdsa::pub_from_priv(), ecdsa::pub_encode(), coincide con ese valor.
Parece que obtener el hash correcto antes de que el hash se firme en la firma sería la parte difícil. Estoy agregando 0x01 a la firma después de que sale de ecdsa::Sign(). Antes de firmar el TX, se le agrega 01000000. scriptSig (el script en la entrada para el TX que estoy construyendo) es "OP_DUP, OP_HASH160, PUSHDATA, dirección de Bitcoin (hash de clave pública), OP_EQUALVERIFY, OP_CHECKSIG" antes de que se firme, luego se convierte en un varstr del sig y el pubKey , y que se decodifica en un código de bytes de aspecto razonable:
guionSig:
0: OP_PUSHDATA 0x304602210094c538663c149f40929bb787d6174104a694181d063943a745e558b17d09e276022100b1812105ea6d7a8206c9019303a6459a9a2b2524b364debe69405b5d8b90c6c301
74: OP_PUSHDATA 0x04d8f39341451e2e66a00ef010c815f1284bc5e3a187476aab319b2d127b7e219c9b9e68bff311c63474242a9baab34f7ddec05de2c45bd140a74a64621ccb42cb
scriptPubKey:
0: OP_DUP
1: OP_HASH160
2: OP_PUSHDATA 0x7847eb9e366653aeb8857d541236fe4fd90c57e7
23: OP_EQUALVERIFY
24: OP_CHECKSIG
El uso de la antigua scriptPubKey como scriptSig se aproxima y supone un simple pago por firma en lugar de sacar la scriptPubKey exacta del TX que se está dibujando, pero en este caso simple, parecen coincidir.
Aquí está el TX sin procesar (¿incorrectamente?) firmado:
0100000001dfca95d26f2c7c00eeb5b2626b2b17766c80a120373edb3027bea3424c3897b0010000008b48304502202647239b48610693967a24c7c976f0df903891113c56f50b6e3368c3f73eefb0022100e372ab8bf76ab35cba1ce6c1890fb6b27bb4d6d54f080180b46a6ecc2ae09248014104d8f39341451e2e66a00ef010c815f1284bc5e3a187476aab319b2d127b7e219c9b9e68bff311c63474242a9baab34f7ddec05de2c45bd140a74a64621ccb42cbffffffff01c0b60600000000001976a9147847eb9e366653aeb8857d541236fe4fd90c57e788ac00000000
Aquí está el código:
https://gist.github.com/scrottie/15f2fca963d164306dcb
PrivateKey a pedido (hay $ 1 allí).
Si alguien puede volcar eso y descubrir dónde me equivoqué, estaría muy agradecido.
%&@!
Se solucionó con este cambio:
$privateKey = $privateKey->as_hex(); $privateKey =~ s{^0x}{} or die;
warn sprintf "doing: python sig.py '%s' '%s'\n", $privateKey, to_hex($s256);
open my $python, '-|', 'python', 'sig.py', $privateKey, to_hex($s256) or die $!;
my $sig = readline $python;
warn "python says for sig: $sig\n";
$sig =~ s{[^0-9a-fA-F]}{}g;
$sig = from_hex($sig);
Y agregando este archivo como sig.py:
import ecdsa
import ecdsa.der
import ecdsa.util
import sys
privateKey = sys.argv[1]
s256 = sys.argv[2]
# print("privateKey len: "); print(len(privateKey.decode('hex')))
# print(privateKey)
# print("s256 len: "); print(len(s256.decode('hex')))
# print(s256)
sk = ecdsa.SigningKey.from_string(privateKey.decode('hex'), curve=ecdsa.SECP256k1)
sig = sk.sign_digest(s256.decode('hex'), sigencode=ecdsa.util.sigencode_der) + '\01' # 01 is hashtype
print sig.encode('hex')
Soy nuevo aquí y aparentemente me estoy trolleando. No pude hacer funcionar los módulos en CPAN que interactúan con openssl, así que tenía una opción para la biblioteca EC, algo escrito en Perl puro. Eso aparentemente tiene problemas, a pesar de que pasa las pruebas unitarias. O lo estaba usando mal.
Eso resultó en una salida que hizo que https://blockchain.info/pushtx dijera "Transacción enviada". Y luego las monedas se movieron.
Gracias a todos los que se detuvieron para echarle un ojo a esto. Te debo una cerveza. Intentaré seguir adelante con muy, muy buenos comentarios y documentos.
Lo siento, no uso lenguaje perl y no tengo instalado el entorno perl para depurar su código
Echa un vistazo a ¿Cómo canjear un Tx básico?
No veo el paso n.º 13 en el que debe agregar 01000000 = SIGHASH_ALL a los datos que inicia en su método makeRawTransaction
amaclin
escocés
escocés
escocés
amaclin