mirror of
https://github.com/ChristopherA/Learning-Bitcoin-from-the-Command-Line.git
synced 2025-06-05 23:16:12 +00:00
Merge pull request #551 from BlockchainCommons/spanish-translation
Spanish translation
This commit is contained in:
commit
63604d2e35
@ -105,7 +105,7 @@ Each transaction has a fee associated with. It's _implicit_ when you send a raw
|
||||
|
||||
> :book: ***How much should you spend on transaction fees?*** [Bitcoin Fees](https://bitcoinfees.21.co/) has a nice live assessment. It says that the "fastest and cheapest transaction fee is currently 42 satoshis/byte" and that "For the median transaction size of 224 bytes, this results in a fee of 9,408 satoshis".
|
||||
|
||||
Currently Bitcoin Fees suggests a transaction fee of about 10,000 satoshis, which is the same as .0001 BC. Yes, that's for the mainnet, not the testnet, but we want to test out things realistically, so that's what we're going to use.
|
||||
Currently Bitcoin Fees suggests a transaction fee of about 10,000 satoshis, which is the same as .0001 BTC. Yes, that's for the mainnet, not the testnet, but we want to test out things realistically, so that's what we're going to use.
|
||||
|
||||
In this case, that means taking the .0005 BTC in the UTXO we're selected, reducing it by .0001 BTC for the transaction fee, and sending the remaining .0004 BTC. (And this is an example of why micropayments don't work on the Bitcoin network, because a $1 or so transaction fee is pretty expensive when you're sending $4, let alone if you were trying to make a micropayment of $0.50. But that's always why we have Lightning.)
|
||||
|
||||
|
63
es/01_0_Introduccion.md
Normal file
63
es/01_0_Introduccion.md
Normal file
@ -0,0 +1,63 @@
|
||||
# Capítulo uno: Introducción al aprendizaje de Bitcoin Core (y Lightning) desde la línea de comandos
|
||||
|
||||
## Introducción
|
||||
|
||||
La forma en que realizamos pagos por bienes y servicios ha cambiado drásticamente en las últimas décadas. Donde antes todas las transacciones se realizaban a través de efectivo o cheques, ahora distintos métodos de pago electrónico son la norma. Sin embargo, la mayoría de estos pagos electrónicos aún se realizan a través de sistemas centralizados, donde las compañías de tarjetas de crédito, los bancos o incluso las instituciones financieras basadas en Internet como Paypal mantienen listas de transacciones largas e individualmente correlacionadas lo que les da el poder de censurar las transacciones que no les gustan.
|
||||
|
||||
Estos riesgos de centralización fueron algunos de los principales catalizadores detrás de la creación de las criptomonedas, el primero y más exitoso proyecto es Bitcoin. Bitcoin ofrece seudoanonimato; dificulta la correlación de transacciones y hace que la censura por parte de entidades individuales sea casi imposible. Estas ventajas la han convertido en una de las monedas de más rápido crecimiento en el mundo. Ese crecimiento, a su vez, ha convertido a Bitcoin en una empresa en marcha entre empresarios y desarrolladores, ansiosos por crear nuevos servicios para la comunidad de Bitcoin.
|
||||
|
||||
Si eres uno de esos emprendedores o desarrolladores, este curso es para ti, porque se trata de aprender a programar Bitcoin. Es un curso introductorio que explica todos los matices y características de Bitcoin a medida que avanza. También toma un rumbo muy específico, al ofrecer lecciones sobre cómo trabajar directamente con Bitcoin Core y con el servidor c-lightning usando sus interfaces RPC.
|
||||
|
||||
¿Por qué no utilizar algunas de las bibliotecas más completas que se encuentran en varios lenguajes de programación? ¿Por qué no crear el tuyo propio desde cero? Porque empezar a trabajar con criptomonedas puede ser peligroso. No hay redes de seguridad. Si accidentalmente paga de más en sus tarifas o pierde una llave de firma o crea una transacción no válida o comete una cantidad de errores potenciales, entonces sus monedas desaparecerán para siempre. Gran parte de esa responsabilidad, por supuesto, recaerá en usted como programador de criptomonedas, aunque puede minimizarse el riesgo trabajando con las interfaces de criptomonedas más sólidas, seguras y probadas, las creadas por los propios equipos de programación de criptomonedas: bitcoind y lightningd.
|
||||
|
||||
Por lo tanto, gran parte de este libro analiza cómo crear un script de Bitcoin (y Lightning) directamente desde la línea de comandos. Algunos capítulos posteriores tratan sobre lenguajes de programación más sofisticados, pero nuevamente continúan interactuando directamente con los demonios bitcoind y lightningd usando RPC o interactuando con los archivos que crean. Esto le permite pararse sobre los hombros de gigantes y utilizar la tecnología de forma confiable para aprender a crear sus propios sistemas confiables.
|
||||
|
||||
# Nivel de habilidad requerido
|
||||
|
||||
No es necesario ser técnico para avanzar en la mayor parte de este curso. Todo lo que necesita es la confianza para ejecutar comandos básicos en la línea de comandos de UNIX. Si está familiarizado con cosas como ssh, cd y ls, el curso le proporcionará el resto.
|
||||
|
||||
Una parte menor de este curso requiere conocimientos de programación, y debe omitir esas secciones si es necesario como se explica en la siguiente sección.
|
||||
|
||||
## Resumen de temas
|
||||
|
||||
Este libro se divide a grandes rasgos en las siguientes secciones:
|
||||
|
||||
| Parte | Descripción | Habilidades |
|
||||
|-------|---------|---------|
|
||||
| **Primera parte: Primera parte: prepararse para Bitcoin** | Comprender los conceptos básicos de Bitcoin y configurar un servidor para su uso. | Línea de comandos |
|
||||
| **Segunda parte: Uso de Bitcoin-CLI** | Usando el Bitcoin-CLI para crear transacciones. | Línea de comandos |
|
||||
| **Tercera parte: Secuencias de comandos de Bitcoin** | Ampliando su trabajo de Bitcoin con scripts | Conceptos de programación |
|
||||
| **Parte Cuatro: Uso de Tor** | Mejorando la seguridad de su nodo con Tor | Línea de comandos |
|
||||
| **Parte Cinco: Programación con RPC** | Accediendo a RPC desde C y otros lenguajes | Programación en lenguaje C |
|
||||
| **Parte Seis: Uso de Lightning-CLI** | Uso de Lightning-CLI para crear transacciones. | Línea de comandos |
|
||||
| **Apendices** | Utilizando configuraciones de Bitcoin menos comunes | Linea de comandos |
|
||||
|
||||
# Cómo utilizar este curso
|
||||
|
||||
Así que ¿Por dónde se empieza? Este libro está destinado principalmente para leerse de forma secuencial. Simplemente se debe seguir el enlace llamado "¿Qué sigue?" al final de cada sección y / o hacer clic en los enlaces de las secciones individuales en cada página de capítulo. Obtendrá una mejor comprensión de este curso si realmente configura un servidor Bitcoin (siguiendo el Capítulo 2) y luego repasa todos los ejemplos a lo largo del libro: probar ejemplos es una excelente metodología de aprendizaje.
|
||||
|
||||
Si tiene diferentes niveles de habilidad o desea aprender cosas diferentes, puede pasar directamente a diferentes partes del libro:
|
||||
|
||||
* Si ya tiene un entorno de Bitcoin listo para ser utilizado, vaya al [Capítulo Tres: Comprensión de la configuración de Bitcoin.](03_2_Conociendo_Su_Configuracion_Bitcoin.md)
|
||||
* Si solo le interesan las secuencias de comandos de Bitcoin, vaya al [Capítulo nueve: Introducción a las secuencias de comandos de Bitcoin.](09_0_Introduciendo_Bitcoin_Scripts.md)
|
||||
* Si solo desea leer sobre el uso de lenguajes de programación, vaya al [Capítulo dieciséis: Comunicarse con el servidor Bitcoin.](16_0_Hablando_a_Bitcoind_con_C.md)
|
||||
* Si, por el contrario, no quiere hacer nada relativo a programación, definitivamente omita los capítulos 15-17 mientras lee, y tal vez omita los capítulos 9-13. El resto del curso aún debería tener sentido sin ellos.
|
||||
* Si solo está interesado en Lightning, pase al [Capítulo diecinueve: Comprensión de la configuración de Lightning.](19_0_Entendiendo_Su_Configuracion_Lightning.md)
|
||||
* Si desea leer el contenido nuevo más importante agregado para la versión 2 del curso (2020), a continuación de la versión 1 (2017), lea [§3.5: Comprensión de los descriptores](03_5_Entendiendo_El_Descriptor.md), [§4.6: Creación de una transacción SegWit](04_6_Creando_una_Transaccion_Segwit.md), [Capítulo 7: Expansión de Bitcoin con PSBT](07_0_Expandiendo_las_Transacciones_Bitcoin_con_PSBTs.md), [§9.5: Scripting con P2WPKH](09_5_Codificando_una_P2WPKH.md), [§10.5: Scripting con SegWit Script](10_5_Codificando_un_Script_Segwit.md), [Capítulo 14: Usando Tor](14_0_Usando_Tor.md), [Capítulo 15: Usando i2p](15_0_Usando_i2p.md), [Capítulo 16: Interactuando con Bitcoind con C](16_0_Hablando_a_Bitcoind_con_C.md), [Capítulo 17: Programando con Libwally](17_0_Programando_Bitcoin_con_Libwally.md), [Capítulo Dieciocho: Interactuando con Bitcoind con otros lenguajes](17_0_Programando_Bitcoin_con_Libwally.md), [Capítulo diecinueve: Comprensión su configuración de Lightning Network](19_0_Entendiendo_Su_Configuracion_Lightning.md) y [Capítulo Veinte: Uso de Lightning.](20_0_Usando_Lightning.md)
|
||||
|
||||
# Por qué utilizar este curso
|
||||
|
||||
Obviamente está trabajando en este curso porque está interesado en Bitcoin. Además de impartir conocimientos básicos, este curso también ha ayudado a los lectores a unirse (o crear) proyectos de código abierto y a obtener trabajos a nivel inicial en la programación de Bitcoin. Varios pasantes de Blockchain Commons aprendieron sobre Bitcoin en este curso, al igual que algunos miembros de nuestro equipo de programación.
|
||||
|
||||
# Cómo apoyar este curso
|
||||
|
||||
* Utilice la sección de [Problemas](https://github.com/BlockchainCommons/Learning-Bitcoin-from-the-Command-Line/issues) para cualquier pregunta. Blockchain Commons no tiene un equipo de soporte activo, por lo que no podemos abordar problemas o consultas individuales, pero los revisaremos a tiempo y los usaremos para mejorar las iteraciones futuras del curso.
|
||||
* Utilice la sección de [PR's](https://github.com/BlockchainCommons/Learning-Bitcoin-from-the-Command-Line/pulls) para corregir errores tipográficos o comandos incorrectos (o modificados). Para cambios técnicos o de línea de comandos, es muy útil si también usa los comentarios en los PR's para explicar las razones por las cuales hizo sus cambios y facilitar o evitar la investigación.
|
||||
* Utilice el [área de discusión](https://github.com/BlockchainCommons/Community/discussions) de nuestra comunidad para hablar sobre carreras y habilidades. Blockchain Commons ocasionalmente ofrece pasantías, como se explica en nuestro repositorio de la comunidad.
|
||||
* Conviértase en un [patrocinador](https://github.com/sponsors/BlockchainCommons) si encuentra útil este curso o si desea ayudar a educar a la próxima generación de programadores de blockchain.
|
||||
|
||||
# ¿Que Sigue?
|
||||
|
||||
Si desea una introducción básica a Bitcoin, criptografía de clave pública, ECC, blockchains y Lightning, lea el interludio [Introduciendo Bitcoin.](01_1_Introduciendo_Bitcoin.md)
|
||||
|
||||
De lo contrario, si está listo para sumergirse en el curso, vaya a [Configuración de un Servidor privado Virtual de Bitcoin-Core.](02_0_Configurando_un_Bitcoin-Core_VPS.md)
|
148
es/01_1_Introduciendo_Bitcoin.md
Normal file
148
es/01_1_Introduciendo_Bitcoin.md
Normal file
@ -0,0 +1,148 @@
|
||||
# Interludio: Presentación de Bitcoin
|
||||
|
||||
Antes de que pueda comenzar a programar sobre Bitcoin (y Lightning), debe tener una comprensión básica de qué son y cómo funcionan. Esta sección proporciona una descripción general. Aparecerán muchas más definiciones dentro del mismo documento con la única intención de sentar las bases.
|
||||
|
||||
## Acerca de Bitcoin
|
||||
|
||||
Bitcoin es un sistema programático que permite la transferencia de la moneda bitcoin. Está habilitado por un sistema de nodos descentralizado de igual a igual, que incluye nodos completos, billeteras y mineros. De forma conjunta se aseguran de que las transacciones de bitcoin sean rápidas y no repudiadas. Gracias a la naturaleza descentralizada del sistema, estas transacciones también son resistentes a la censura y pueden proporcionar otras ventajas como el uso de seudónimos y la no correlación siempre y cuando se utilicen bien.
|
||||
|
||||
Obviamente, Bitcoin es el corazón de este libro, pero también es el creador de muchos otros sistemas, incluidas otras blockchains y Lightning, que se detallan en este tutorial al igual que muchas otras criptomonedas como Ethereum y Litecoin que no son mencionadas.
|
||||
|
||||
**_Cómo se transfieren las monedas?_** La moneda Bitcoin no son monedas físicas. En cambio, son una serie interminable de reasignaciones de propiedad. Cuando una persona envía monedas a otra, esa transferencia se almacena como una transacción. Es la transacción la que realmente registra la propiedad del dinero y no un token local en la billetera del propietario o en su máquina.
|
||||
|
||||
**_A quién puede enviarle monedas?_** La gran mayoría de las transacciones de bitcoin implican el envío de monedas a personas individuales (o al menos a direcciones de bitcoin individuales). Sin embargo, se pueden utilizar metodologías más complejas para enviar monedas a grupos de personas o scripts. Estas diversas metodologías tienen nombres como P2PKH, multisig y P2SH.
|
||||
|
||||
**_Cómo se almacenan las transacciones?_** Las transacciones se combinan en bloques de datos más grandes, que luego se escriben en el libro mayor de la cadena de bloques. Un bloque se construye de tal manera que no se puede reemplazar o reescribir una vez que se han construido varios bloques sobre él (después). Esto es lo que hace que la moneda bitcoin sean irreprochable: el libro de contabilidad global descentralizado donde todo se registra es efectivamente una base de datos permanente e inmutable.
|
||||
|
||||
Sin embargo, el proceso de construcción de estos bloques es estocástico: es algo aleatorio, por lo que nunca puede estar seguro de que una transacción se colocará en un bloque específico. También puede haber cambios en los bloques si son muy recientes, pero solo si son muy recientes. Por lo tanto las cosas se vuelven realmente irreprochables (así como permanentes e inmutables) después de un poco de tiempo.
|
||||
|
||||
**_Cómo se protegen las transacciones?_** Los fondos contenidos en una transacción de Bitcoin están bloqueados con un rompecabezas criptográfico. Estos acertijos están diseñados para que los pueda resolver fácilmente la persona a la que se enviaron los fondos. Esto se hace utilizando el poder de la criptografía de clave pública. Técnicamente, una transacción está protegida por una firma que demuestra que usted es el propietario de la clave pública a la que se envió una transacción: esta prueba de propiedad es el rompecabezas que se está resolviendo.
|
||||
|
||||
Los fondos están aún más protegidos mediante el uso de hashes. Las claves públicas no se almacenan realmente en la cadena de bloques hasta que se gastan los fondos: son los hashes de clave pública los que se guardan. Esto significa que incluso si apareciera la computadora cuántica, las transacciones de Bitcoin permanecerían protegidas por este segundo nivel de criptografía.
|
||||
|
||||
**_Cómo se crean las transacciones?_** El corazón de cada transacción de Bitcoin es un lenguaje de secuencias de comandos similar a FORTH que se utiliza para bloquear la transacción. Para volver a gastar el dinero, el destinatario debe proporcionar información específica al guión que demuestra que es el destinatario previsto.
|
||||
|
||||
Sin embargo, estos scripts de Bitcoin son el nivel más bajo de funcionalidad de Bitcoin. Gran parte del trabajo de Bitcoin se realiza a través del demonio de Bitcoin llamado `bitcoind`, que es controlado mediante el uso de comandos RPC. Mucha gente envía esos comandos RPC a través del programa `bitcoin-cli`, que proporciona una interfaz aún más simple. Los no programadores ni siquiera se preocupan por estas minucias, sino que utilizan carteras programadas con interfaces más simples.
|
||||
|
||||
## Bitcoin - En resumen
|
||||
|
||||
Una forma de pensar en Bitcoin es como una secuencia de transacciones atómicas. Cada transacción es autenticada por un remitente con la solución a un rompecabezas criptográfico anterior que se almacenó como un script. La nueva transacción está bloqueada para el destinatario con un nuevo rompecabezas criptográfico que también se almacena como un script. Cada transacción se registra en un libro mayor global inmutable.
|
||||
|
||||
## Acerca de la criptografía de clave pública
|
||||
|
||||
La criptografía de clave pública es un sistema matemático para proteger los datos y demostrar la propiedad a través de un par asimétrico de claves vinculadas: la clave pública y la clave privada.
|
||||
|
||||
Es importante para Bitcoin (y para la mayoría de los sistemas blockchain) porque es la base de gran parte de la criptografía que protege los fondos de criptomonedas. Una transacción de Bitcoin generalmente se envía a una dirección que es hash de una clave pública. Luego, el destinatario puede recuperar el dinero revelando tanto la clave pública como la clave privada.
|
||||
|
||||
**_Qué es una clave pública?_** Una clave pública es la clave que se entrega a otras personas. En un sistema típico de clave pública, un usuario genera una clave pública y una clave privada, luego le da la clave pública a todos y cada uno. Esos destinatarios podrán cifrar información con la clave pública, pero no podrán descifrar con la misma clave pública debido a la asimetría del par de claves.
|
||||
|
||||
**_Qué es una clave privada?_** Una clave privada está vinculada a una clave pública en un par de claves. En un sistema típico de clave pública, un usuario mantiene segura su clave privada y la usa para descifrar los mensajes que fueron encriptados con su clave pública antes de enviárselos.
|
||||
|
||||
**_Qué es una firma?_** Un mensaje (o más comúnmente, un hash de un mensaje) se puede firmar con una clave privada, creando una firma. Cualquiera que tenga la clave pública correspondiente puede validar la firma, lo que verifica que el firmante sea el propietario de la clave privada asociada con la clave pública en cuestión. SegWit es un formato específico para almacenar una firma en la red Bitcoin que encontraremos más adelante.
|
||||
|
||||
**_Qué es una función hash?_** Una función hash es un algoritmo que se utiliza con frecuencia en conjunto con la criptografía. Es una forma de asignar una gran cantidad arbitraria de datos a una pequeña cantidad fija de datos. Las funciones hash que se utilizan en criptografía son unidireccionales y resistentes a colisiones, lo que significa que un hash se puede vincular de manera confiable a los datos originales, pero los datos originales no se pueden regenerar a partir del hash. Por tanto, los hashes permiten la transmisión de pequeñas cantidades de datos para representar grandes cantidades de datos, que pueden ser importantes para la eficiencia y los requisitos de almacenamiento.
|
||||
|
||||
Bitcoin aprovecha la capacidad de un hash para disfrazar los datos originales, lo que permite ocultar la clave pública real de un usuario, lo que hace que las transacciones sean resistentes a la computación cuántica.
|
||||
|
||||
## Criptografía de clave pública: en resumen
|
||||
|
||||
Una forma de entender la criptografía de clave pública es: una forma para que cualquier persona proteja los datos de manera que solo una persona autorizada pueda acceder a ellos y de manera que la persona autorizada pueda demostrar que tendrá ese acceso.
|
||||
|
||||
## Sobre ECC
|
||||
|
||||
ECC significa Criptografía de Curva Elíptica. Es una rama específica de la criptografía de clave pública que depende de cálculos matemáticos realizados utilizando curvas elípticas definidas sobre campos finitos. Es más complejo y más difícil de explicar que la criptografía de clave pública clásica (que utiliza números primos), pero tiene algunas ventajas interesantes.
|
||||
|
||||
ECC no recibe mucha atención en este tutorial. Esto se debe a que este tutorial trata sobre la integración con los servidores Bitcoin Core y Lightning, que ya se han ocupado de la criptografía por el lector. De hecho, la intención de este tutorial es que no tenga que preocuparse en absoluto por la criptografía, porque eso es algo de lo que realmente quiere que se ocupen los expertos.
|
||||
|
||||
**_Qué es una curva elíptica?_** Una curva elíptica es una curva geométrica que toma la forma `y`<sup>`2`</sup> = `x`<sup>`3`</sup>` + ax + b`. Se elige una curva elíptica específica seleccionando valores específicos de `a` y `b`. Luego, la curva debe examinarse cuidadosamente para determinar si funciona bien para la criptografía. Por ejemplo, la curva secp256k1 utilizada por Bitcoin se define como `a=0` y `b=7`.
|
||||
|
||||
Cualquier línea que cruce una curva elíptica lo hará en 1 o 3 puntos ... y esa es la base de la criptografía de curva elíptica.
|
||||
|
||||
**_Qué son los campos finitos?_** Un campo finito es un conjunto finito de números, donde toda suma, resta, multiplicación y división se define de modo que da como resultado otros números también en el mismo campo finito. Una forma sencilla de crear un campo finito es mediante el uso de una función de módulo.
|
||||
|
||||
**_Cómo se define una curva elíptica sobre un campo finito?_** Una curva elíptica definida sobre un campo finito tiene todos los puntos de su curva extraídos de un campo finito específico. Esto toma la forma: `y`<sup>`2`</sup> `% field-size = (x`<sup>`3`</sup>` + ax + b) % field-size` El campo finito usado para secp256k1 es `2`<sup>`256`</sup>` - 2`<sup>`32`</sup>` - 2`<sup>`9`</sup>` - 2`<sup>`8`</sup>` - 2`<sup>`7`</sup>` - 2`<sup>`6`</sup>` - 2`<sup>`4`</sup>` - 1`.
|
||||
|
||||
**_Cómo se utilizan las curvas elípticas en criptografía?_** En la criptografía de curva elíptica, un usuario selecciona un número muy grande (256 bits) como clave privada. Luego agrega un punto base establecido en la curva a sí misma tantas veces. (En secp256k1, el punto base es `G = 04 79BE667E F9DCBBAC 55A06295 CE870B07 029BFCDB 2DCE28D9 59F2815B 16F81798 483ADA77 26A3C465 5DA4FBFC 0E1108A8 FD17B448 A6855419 9C47D08F FB10D4B8`, que antepone las dos partes de la tupla con un `04` para decir que el punto de datos está en forma descomprimida. Si prefiere una definición geométrica recta, es el punto "0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798,0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199") El número resultante es la clave pública. Luego, se pueden usar varias fórmulas matemáticas para demostrar la propiedad de la clave pública, dada la clave privada. Al igual que con cualquier función criptográfica, esta es una trampilla: es fácil pasar de la clave privada a la clave pública y general es imposible pasar de la clave pública a la clave privada.
|
||||
|
||||
Esta metodología en particular también explica por qué se utilizan campos finitos en curvas elípticas: asegura que la clave privada no crecerá demasiado. Tenga en cuenta que el campo finito para secp256k1 es un poco más pequeño que 256 bits, lo que significa que todas las claves públicas tendrán 256 bits de longitud, al igual que las claves privadas.
|
||||
|
||||
**_Cuáles son las ventajas de ECC?_** La principal ventaja de ECC es que permite la misma seguridad que la criptografía clásica de clave pública con una clave mucho más pequeña. Una clave pública de curva elíptica de 256 bits corresponde a una clave pública tradicional (RSA) de 3072 bits.
|
||||
|
||||
### ECC - En resumen
|
||||
|
||||
Una forma de pensar en ECC es: una forma de habilitar la criptografía de clave pública que utiliza claves muy pequeñas y matemáticas muy poco conocidas.
|
||||
|
||||
### Sobre Cadenas de bloques (Blockchains)
|
||||
|
||||
Blockchain es la generalización de la metodología utilizada por Bitcoin para crear un libro mayor distribuido de forma global. Bitcoin es una cadena de bloques al igual que cualquier cantidad de monedas alternativas, cada una de las cuales vive en su propia red y escribe en su propia cadena. Las cadenas laterales como Liquid también son cadenas de bloques. Las cadenas de bloques ni siquiera necesitan tener nada que ver con las finanzas. Por ejemplo, ha habido muchas discusiones sobre el uso de blockchains para proteger identidades soberanas.
|
||||
|
||||
Aunque debe comprender los conceptos básicos de cómo funciona una cadena de bloques para comprender cómo funcionan las transacciones en Bitcoin, no necesitará ir más allá. Debido a que las cadenas de bloques se han convertido en una amplia categoría de tecnología, es probable que esos conceptos básicos sean aplicables a muchos otros proyectos en este creciente sector tecnológico. Sin embargo, los comandos de programación específicos aprendidos en este libro no lo serán, ya que son bastante específicos de Bitcoin (y Lightning).
|
||||
|
||||
**_Por qué se llama cadena?_** Cada bloque de la cadena de bloques almacena un hash del bloque anterior. Esto une el último bloque actual hasta el "bloque génesis" original a través de una cadena ininterrumpida. Es una forma de crear un orden absoluto entre datos posiblemente conflictivos. Esto también proporciona la seguridad de la cadena de bloques, porque cada bloque se apila sobre uno antiguo, lo que dificulta la recreación del bloque antiguo debido a los algoritmos de prueba de trabajo utilizados en la creación de bloques. Una vez que se han construido varios bloques sobre un bloque de la cadena, es esencialmente irreversible.
|
||||
|
||||
**_Qué es una bifurcación (fork)?_** De forma ocasional se crean dos bloques aproximadamente al mismo tiempo. Esto crea temporalmente una bifurcación de un bloque, donde cualquiera de los bloques actuales podría ser el "real". De vez en cuando, una bifurcación puede expandirse para convertirse en dos bloques, tres bloques o incluso cuatro bloques de largo, pero rápidamente se determina que un lado de la bifurcación es el real y el otro queda "huérfano". Esto es parte del proceso estocástico de creación de bloques y demuestra por qué se deben construir varios bloques encima de un bloque antes de que pueda considerarse verdaderamente confiable y no repudiable.
|
||||
|
||||
### Blockchain - En resumen
|
||||
|
||||
Una forma de pensar en blockchain es: una serie enlazada de bloques de datos inmutables que se remontan al pasado. Otra forma es: una serie enlazada de bloques para ordenar datos de forma absoluta que podrían estar en conflicto.
|
||||
|
||||
## Blockchain es adecuado para mí?
|
||||
|
||||
Si desea realizar transacciones con bitcoins, obviamente Bitcoin es adecuado para usted. Sin embargo, de manera más generalizada, blockchain se ha convertido en una palabra de moda popular a pesar de que no es una fórmula mágica para todos los problemas técnicos. Dicho esto, hay muchas situaciones específicas en las que blockchain es una tecnología superior.
|
||||
|
||||
Las cadenas de bloques probablemente serán útiles si:
|
||||
|
||||
* Los usuarios no confían entre sí.
|
||||
* Los usuarios existen a través de varias fronteras.
|
||||
* Los usuarios no confían en las autoridades centrales.
|
||||
* Los usuarios quieren controlar sus propios destinos.
|
||||
* Los usuarios quieren tecnología transparente.
|
||||
* Los usuarios quieren compartir algo.
|
||||
* Y: los usuarios quieren que lo que se comparte se registre de forma permanente.
|
||||
* Los usuarios quieren una finalidad de transacción rápida.
|
||||
* Pero: los usuarios no necesitan la finalidad instantánea de las transacciones.
|
||||
|
||||
Las cadenas de bloques probablemente no serán útiles si:
|
||||
|
||||
* Los usuarios son de confianza:
|
||||
* por ejemplo: las transacciones ocurren dentro de una empresa u organización.
|
||||
* por ejemplo: las transacciones son supervisadas por una autoridad central.
|
||||
* Se requiere secreto:
|
||||
* por ejemplo: la información debe ser secreta.
|
||||
* por ejemplo: las transacciones deben ser secretas.
|
||||
* por ejemplo: los Transactores deben ser secretos.
|
||||
* A menos que: Se considere, analice y pruebe cuidadosamente una metodología para el secreto criptográfico.
|
||||
* Los usuarios necesitan la finalidad instantánea de la transacción.
|
||||
* por ejemplo: en menos de 10 minutos en una red similar a Bitcoin, en menos de 2.5 minutos en una red similar a Litecoin, en menos de 15 segundos en una red similar a Ethereum
|
||||
|
||||
Tenga en cuenta que todavía puede haber soluciones para algunas de estas situaciones dentro del ecosistema de Bitcoin. Por ejemplo, los canales de pago están abordando rápidamente cuestiones de liquidez y finalidad del pago.
|
||||
|
||||
## Sobre Lightning
|
||||
|
||||
Lightning es un protocolo de capa 2 que interactúa con Bitcoin para permitir a los usuarios intercambiar sus bitcoins "fuera de la cadena". Tiene ventajas y desventajas sobre el uso de Bitcoin por sí solo.
|
||||
|
||||
Lightning Network también es el enfoque secundario de este tutorial. Aunque se trata principalmente de interactuar directamente con Bitcoin (y el `bitcoind`), presta algo de atención a Lightning porque es una tecnología de próxima aparición que probablemente se convierta en una alternativa popular a Bitcoin en un futuro próximo. Este libro adopta el mismo enfoque para Lightning que para Bitcoin: enseña cómo interactuar directamente con un demonio Lightning confiable desde la línea de comandos.
|
||||
|
||||
A diferencia de Bitcoin, en realidad existen varias variantes de Lightning. Este tutorial utiliza la implementación de [c-lightning](https://github.com/ElementsProject/lightning) compatible con el estándar como su servidor Lightning de confianza.
|
||||
|
||||
**_Qué es un protocolo de capa 2?_** Un protocolo de Bitcoin de capa 2 funciona sobre Bitcoin. En este caso, Lightning funciona sobre Bitcoin, interactuando con este a través de contratos inteligentes.
|
||||
|
||||
**_Qué es un canal Lightning?_** Un canal Lightning es una conexión entre dos usuarios de Lightning. Cada uno de los usuarios bloquea una cierta cantidad de bitcoins en la cadena de bloques de Bitcoin utilizando una transacción multi-firma por ambos. Los dos usuarios pueden intercambiar bitcoins a través de su canal Lightning sin tener que escribir en la cadena de bloques de Bitcoin. Solo cuando quieren cerrar su canal liquidan sus bitcoins, según la división final de monedas.
|
||||
|
||||
**_Qué es la red Lightning?_** Al juntar varios canales se crea la red Lightning. Esto permite que dos usuarios que no han creado un canal entre ellos intercambien bitcoins usando Lightning: el protocolo forma una cadena de Canales entre los dos usuarios, luego intercambia las monedas a través de la cadena mediante transacciones de tiempo bloqueado.
|
||||
|
||||
**_Cuáles son las ventajas de Lightning?_** Lightning permite transacciones más rápidas con tarifas más bajas. Esto crea la posibilidad real de micropagos financiados con bitcoins. También ofrece una mejor privacidad, ya que está fuera de la cadena y solo se escribe el primer y último estado de la transacción en el libro de contabilidad inmutable de Bitcoin.
|
||||
|
||||
**_Cuáles son las desventajas de la red Lightning?_** Lightning sigue siendo una tecnología muy nueva y no se ha probado tan a fondo como Bitcoin. No se trata solo de la implementación tecnológica, sino también el diseño en sí mismo se puede actuar de alguna manera inesperada.
|
||||
|
||||
### Lightning - en resumen
|
||||
|
||||
Una forma de pensar en Lightning es: una forma de realizar transacciones con bitcoins utilizando canales fuera de la cadena entre pares de personas, de modo que solo se tenga que escribir un primer y último estado en la cadena de bloques.
|
||||
|
||||
## Resumen - Introduciendo Bitcoin
|
||||
|
||||
Bitcoin es un sistema peer-to-peer que permite la transferencia de fondos a través de transacciones bloqueadas con acertijos. Estos acertijos dependen de la criptografía de curva elíptica de clave pública. Cuando generalizas las ideas detrás de Bitcoin, surge la cadena de bloques, una tecnología que actualmente está creciendo e innovando. Cuando expande las ideas detrás de Bitcoin, obtiene protocolos de capa 2 como Lightning, que expanden el potencial de la moneda.
|
||||
|
||||
## Que Sigue?
|
||||
|
||||
Continúe a través de la "Preparación para Bitcoin" con el [Capítulo dos: Configuración de un VPS Bitcoin-Core](02_0_Configurando_un_Bitcoin-Core_VPS.md)
|
28
es/02_0_Configurando_un_Bitcoin-Core_VPS.md
Normal file
28
es/02_0_Configurando_un_Bitcoin-Core_VPS.md
Normal file
@ -0,0 +1,28 @@
|
||||
|
||||
# Capítulo dos: Creando un Servidor Privado Virtual de Bitcoin-Core
|
||||
|
||||
Para iniciar con Bitcoin, se debe configurar una maquina ejecutando el software de Bitcoin. Los artículos en este capítulo describen como hacerlo, principalmente mediante el uso de un VPS (servidor privado virtual).
|
||||
|
||||
|
||||
## Objetivos de este capítulo
|
||||
|
||||
Después de trabajar en este capítulo, un desarrollador podrá:
|
||||
|
||||
* Decidir entre los cinco tipos principales de nodos de Bitcoin
|
||||
* Cree un nodo de Bitcoin para desarrollo.
|
||||
* Cree una instancia local de la Blockchain de Bitcoin
|
||||
|
||||
Los objetivos de apoyo incluyen la capacidad de:
|
||||
|
||||
* Comprender la configuración de red básica del VPS.
|
||||
* Decidir qué prioridades de seguridad implementar.
|
||||
* Comprender la diferencia entre nodos podados y no podados.
|
||||
* Comprender la diferencia entre los nodos Mainnet, Testnet y Regtest.
|
||||
* Interpretar los conceptos básicos del archivo de configuración de Bitcoin.
|
||||
|
||||
## Tabla de contenido
|
||||
|
||||
En realidad, no es necesario leer este capítulo completo. Decida si desea ejecutar un StackScript para configurar un nodo en un VPS Linode (§2.2); o desea configurarlo en un entorno diferente, como en una máquina AWS o Mac (§2.3). Luego puede ir a la sección correspondiente. Información adicional sobre nuestras configuraciones sugeridas también se puede encontrar en el Apéndice I.
|
||||
|
||||
* [Sección uno: Configurando un VPS Bitcoin-Core con Bitcoin Standup](02_1_Configurando_un_Bitcoin-Core_VPS_con_StackScript.md)
|
||||
* [Sección dos: Configurando una máquina Bitcoin-Core por otros medios](02_2_Configurando_Bitcoin_Core_Otros.md)
|
266
es/02_1_Configurando_un_Bitcoin-Core_VPS_con_StackScript.md
Normal file
266
es/02_1_Configurando_un_Bitcoin-Core_VPS_con_StackScript.md
Normal file
@ -0,0 +1,266 @@
|
||||
# 2.1: Configuración de un VPS Bitcoin-Core con Bitcoin Standup
|
||||
|
||||
Este documento explica cómo configurar un VPS (Virtual Private Sever) para ejecutar un nodo Bitcoin en Linode.com, instalado usando un StackScript automatizado del [proyecto Bitcoin Standup.](https://github.com/BlockchainCommons/Bitcoin-Standup-Scripts). Solo necesita ingresar algunos comandos e iniciar su VPS. Casi inmediatamente después de arrancar, encontrará su nuevo nodo Bitcoin descargando bloques felizmente.
|
||||
|
||||
> :warning: **ADVERTENCIA:** : No use un VPS para una billetera bitcoin con fondos reales significativos; ver [http://blog.thestateofme.com/2012/03/03/lessons-to-be-learned-from-the-linode-bitcoin-incident](http://blog.thestateofme.com/2012/03/03/lessons-to-be-learned-from-the-linode-bitcoin-incident). Es genial poder experimentar con transacciones reales de bitcoins en un nodo en vivo sin tener que conectar un servidor autohospedado en una red local. También es útil poder usar un iPhone o iPad para comunicarse a través de SSH con su VPS para realizar algunas tareas simples de bitcoin. Pero se requiere un mayor nivel de seguridad para fondos importantes.
|
||||
|
||||
* Si desea comprender lo que hace esta configuración, lea el [Apéndice I: Entendiendo Bitcoin Standup](A1_0_Entendiendo_Bitcoin_Standup.md) mientras realiza la instalación.
|
||||
* Si, en cambio, desea configurar en una máquina que no sea un VPS Linode, como una máquina AWS o una Mac, puede ir a [2.2: Configuración de una máquina Bitcoin-Core a través de otros medios](02_2_Configurando_Bitcoin_Core_Otros.md)
|
||||
* Si ya tiene un nodo de Bitcoin en ejecución, vaya al [Capítulo tres: Entendiendo la configuración de Bitcoin](03_0_Entendiendo_Su_Configuracion_Bitcoin.md).
|
||||
|
||||
## Introducción a Linode
|
||||
|
||||
Linode es un servicio de alojamiento en la nube que ofrece servidores Linux rápidos y económicos con almacenamiento SSD. Los usamos para este tutorial principalmente porque sus StackScripts basados en BASH ofrecen una manera fácil de configurar automáticamente un nodo de Bitcoin sin problemas y sin complicaciones.
|
||||
|
||||
### Configurar una cuenta de Linode
|
||||
|
||||
Puede crear una cuenta de Linode yendo aquí:
|
||||
|
||||
```
|
||||
https://www.linode.com
|
||||
```
|
||||
|
||||
Si lo prefiere, el siguiente código de referencia le dará aproximadamente un mes de uso gratuito, ideal para aprender Bitcoin:
|
||||
|
||||
```
|
||||
https://www.linode.com/?r=23211828bc517e2cb36e0ca81b91cc8c0e1b2d96
|
||||
```
|
||||
|
||||
Deberá proporcionar una dirección de correo electrónico y luego precargar dinero de una tarjeta de crédito o PayPal para costos futuros.
|
||||
|
||||
Cuando haya terminado, debe aterrizar en [https://cloud.linode.com/dashboard](https://cloud.linode.com/dashboard).
|
||||
|
||||
### Considere la autenticación de dos factores
|
||||
|
||||
La seguridad de su servidor no estará completa si las personas pueden ingresar a su cuenta de Linode, así que considere configurar la autenticación de dos factores para ello. Puede encontrar esta configuración en su página [Mi perfil: contraseña y autenticación](https://manager.linode.com/profile/auth). Si no hace esto ahora, cree un elemento TODO para volver y hacerlo más tarde.
|
||||
|
||||
## Creando la imagen de Linode usando un StackScript
|
||||
|
||||
### Cargar el StackScript
|
||||
|
||||
Descargue el [Script Linode Standup](https://github.com/BlockchainCommons/Bitcoin-Standup-Scripts/blob/master/Scripts/LinodeStandUp.sh) del repositorio de [Scripts de Bitcoin Standup](https://github.com/BlockchainCommons/Bitcoin-Standup-Scripts). Este script básicamente automatiza todas las instrucciones de configuración para un servidor VPS de Bitcoin. Si prefiere ser particularmente prudente, léelo con atención. Si está satisfecho, puede copiar ese StackScript en su propia cuenta dirigíendose a la [página de Stackscripts](https://cloud.linode.com/stackscripts?type=account) en su cuenta de Linode y seleccionando [Crear nuevo Stackscript](https://cloud.linode.com/stackscripts/create). Dale un buen nombre (usamos `Bitcoin Standup`), luego copia y pega el script. Elija Debian 10 para su imagen de destino y "Guárdelo".
|
||||
|
||||
### Realizar la configuración inicial
|
||||
|
||||
Ahora está listo para crear un nodo basado en Stackscript.
|
||||
|
||||
1. En la página [Stackscripts page](https://cloud.linode.com/stackscripts?type=account), haga clic en "..." a la derecha de su nuevo script y seleccione "Implementar nuevo Linode".
|
||||
2. Complete un nombre de host breve y completo.
|
||||
* **Nombre de host corto.** Elija un nombre para su VPS. Por ejemplo, "mybtctest".
|
||||
* **Nombre de host completamente calificado.** Si va a incluir este VPS como parte de una red con registros DNS completos, escriba el nombre de host con su dominio. Por ejemplo, "mybtctest.mydomain.com". De lo contrario, repita el nombre de host corto y agregue ".local", por ejemplo "mybtctest.local".
|
||||
3. Ingrese la contraseña para el usuario "standup".
|
||||
4. Elija un tipo de instalación en las opciones avanzadas.
|
||||
* **Tipo de instalación.** Probablemente sea "Mainnet" o "Pruned Mainnet" si está configurando un nodo para su uso y "Testnet" o "Pruned Testnet" si solo está probando. La mayor parte de este tutorial asumirá que eligió "Testnet podado", pero aún debería poder seguir con otros tipos. Consulte la [Synopsis](#synopsis-bitcoin-installation-types) para obtener más información sobre estas opciones. (Tenga en cuenta que si planea probar los capítulos Lightning, probablemente querrá usar un nodo sin podar, ya que trabajar con nodos podados en Lightning es dudoso. Consulte [§19.1](19_1_Verificando_Su_Configuracion_Lightning.md#compiling-the-source-code) para conocer los detalles).
|
||||
5. Complete cualquier otra opción avanzada apropiada.
|
||||
* **X25519 Clave pública.** Esta es una clave pública para agregar a la lista de clientes autorizados de Tor. Si no lo usa, cualquiera que obtenga el código QR de su nodo puede acceder a él. Obtendrá esta clave pública de cualquier cliente que esté utilizando para conectarse a su nodo. Por ejemplo, si usa [FullyNoded 2](https://github.com/BlockchainCommons/FullyNoded-2), puede ir a su configuración y "Exportar clave pública de autenticación Tor V3" para usar aquí.
|
||||
* **Clave SSH.** Copie aquí la clave SSH de su computadora local; esto le permite iniciar sesión automáticamente a través de SSH en la cuenta standup. Si aún no ha configurado una clave SSH en su computadora local, hay buenas instrucciones para ello en [Github](https://help.github.com/articles/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent/). Es posible que también desee agregar su clave SSH en su Linode LISH (Linode Interactive Shell) yendo a su "Página de inicio de Linode / Mis preferencias / Configuración de LISH / Teclas de LISH". El uso de una clave SSH le brindará una forma más sencilla y segura de iniciar sesión en su servidor.
|
||||
* **IP's permitidas por SSH** Esta es una lista de direcciones IP separadas por comas que se permitirán SSH en el VPS. Por ejemplo, "192.168.1.15,192.168.1.16". Si no ingresa ninguna IP, _su VPS no será muy seguro_. Será bombardeado constantemente por atacantes que intentan encontrar un puerta de entrada y es muy posible que lo logren.
|
||||
4. Seleccione una imagen
|
||||
* **Imagen de destino.** Si siguió las instrucciones, esto solo le permitirá seleccionar "Debian 10" (aunque "Debian 9" también funcionó con versiones anteriores de este Stackscript y aún podría hacerlo).
|
||||
5. Elija una región donde se ubicará el Linode.
|
||||
|
||||
*Las preguntas restantes tienen que ver con la mecánica de la implementación del VPS y deben dejarse como están con una excepción: aumente el disco de intercambio de 256 MB a 512 MB, para asegurarse de que tiene suficiente memoria para descargar la cadena de bloques.
|
||||
|
||||
Finalmente, deberá completar una contraseña de root, que será la contraseña utilizada para la cuenta de root.
|
||||
|
||||
### Elija otras opciones de standup
|
||||
|
||||
Blockchain Commons se encuentra actualmente en el proceso de expandir sus scripts de Bitcoin Standup con opciones para instalar Lightning y otras aplicaciones de Bitcoin importantes. Eche un vistazo a las opciones adicionales y vea si son cosas con las que le gustaría jugar. En particular, si Lightning es una opción, sugerimos instalarlo, porque hará que el [Capítulo 19](19_0_Entendiendo_Su_Configuracion_Lightning.md) y el [Capítulo 20](20_0_Usando_Lightning.md) sean mucho más fáciles.
|
||||
|
||||
### Elija un plan Linode
|
||||
|
||||
A continuación, elegirás un plan Linode.
|
||||
|
||||
Un Linode 4GB será suficiente para la mayoría de las configuraciones, incluidas: Mainnet podada, Testnet podada e incluso Testnet no podada. Todos usan menos de 50G de almacenamiento y 4GB es una cantidad cómoda de memoria. Esta es la configuración que sugerimos. Tiene un costo de $ 20 por mes.
|
||||
|
||||
Si, en cambio, desea tener una Mainnet no podada en un VPS, deberá instalar un Linode con un disco de más de 280G (!), Que actualmente es el Linode de 16GB, que tiene 320G de almacenamiento y 16G de memoria. y cuesta aproximadamente $ 80 por mes. Nosotros no recomendamos esto.
|
||||
|
||||
El siguiente cuadro muestra los requisitos mínimos
|
||||
|
||||
| Configuración | Memoria | Almacenamiento | Linode |
|
||||
|-------|--------|---------|---------|
|
||||
| Mainnet | 2G | 280G | Linode 16GB |
|
||||
| Mainnet podada | 2G | ~5G | Linode 4GB |
|
||||
| Testnet | 2G | ~15G | Linode 4GB |
|
||||
| Testnet podada | 2G | ~5G | Linode 4GB |
|
||||
| Regtest | 2G | ~ | Linode 4GB |
|
||||
|
||||
Tenga en cuenta que puede haber formas de reducir ambos costos.
|
||||
|
||||
* Para las máquinas que sugerimos como **Linode 4GB**, es posible que pueda reducirlo a un Linode 2GB. Algunas versiones de Bitcoin Core han funcionado bien con ese tamaño, algunas ocasionalmente se han quedado sin memoria y luego se han recuperado, y algunas se han quedado sin memoria continuamente. Recuerde aumentar ese espacio de intercambio para maximizar las probabilidades de que esto funcione. Úselo bajo su propio riesgo.
|
||||
* Para la red Mainnet sin podar, que sugerimos como **Linode 16GB**, probablemente pueda arreglárselas con un Linode 4GB, pero agregue [Block Storage](https://cloud.linode.com/volumes) suficiente para almacenar la cadena de bloques. Esta es sin duda una mejor solución a largo plazo, ya que los requisitos de almacenamiento de la cadena de bloques de Bitcoin aumentan continuamente si no se poda, mientras que los requisitos de la CPU no lo hacen (o no en el mismo grado). Un almacenamiento de 320 GibiByte costaría $ 32 al mes, que combinado con un Linode 4GB cuesta $ 52 al mes, en lugar de $ 80, y lo que es más importante, puede seguir creciendo. No documentamos completamente esta configuración por dos razones (1) no sugerimos la configuración de la red principal sin podar, por lo que sospechamos que es una configuración mucho menos común y (2) no hemos probado cómo se comparan los volúmenes de Linodes con sus SSD intrínsecos en cuanto a rendimiento y uso. Pero hay documentación completa en la página de almacenamiento de bloques. Debería configurar el nodo Linode, ejecutar su stackscript, pero luego interrumpirlo para mover el almacenamiento de la cadena de bloques en exceso a un volumen recién añadido antes de continuar.
|
||||
|
||||
### Hacer la configuración final
|
||||
|
||||
Lo último que debe hacer es ingresar una contraseña de root. (¡Si se perdiste algo, se lo dirán ahora!)
|
||||
|
||||
Haga clic en "Implementar" para inicializar sus discos y preparar su VPS. Toda la cola debería ejecutarse en menos de un minuto. Cuando haya terminado, debería ver en la "Cola de trabajos del host", y unos botones verdes de "Éxito" que indican "Crear disco desde StackScript - Configuración de contraseña para root" y "Crear sistema de archivos - Imagen de intercambio de 256 MB" que se ha terminado.
|
||||
|
||||
Es posible que ahora desee cambiar el nombre de su VPS Linode del predeterminado `linodexxxxxxxx`. Vaya a la pestaña Configuración y cambie la etiqueta para que sea más útil, como el nombre de host corto de su VPS. Por ejemplo, puede llamarlo `bitcoin-testnet-pruned` para diferenciarlo de otros VPS en su cuenta.
|
||||
|
||||
### Inicie sesión en su VPS
|
||||
|
||||
Si observa su panel de control Linode, debería ver que la nueva computadora gira. Cuando el trabajo haya alcanzado el 100%, podrá iniciar sesión.
|
||||
|
||||
Primero, necesitará la dirección IP. Haga clic en la pestaña "Linodes" y debería ver una lista de sus VPS, el hecho de que se está ejecutando, su "plan", su dirección IP y alguna otra información.
|
||||
|
||||
Vaya a su consola local e inicie sesión en la cuenta `standup` usando esa dirección:
|
||||
|
||||
```
|
||||
ssh standup@[IP-ADDRESS]
|
||||
```
|
||||
|
||||
Por ejemplo:
|
||||
|
||||
```
|
||||
ssh standup@192.168.33.11
|
||||
```
|
||||
|
||||
Si configuró su VPS para usar una clave SSH, el inicio de sesión debe ser automático (posiblemente requiera su contraseña SSH para desbloquear su clave). Si no configuró una clave SSH, deberá ingresar la contraseña de user.
|
||||
|
||||
|
||||
### Espere unos minutos
|
||||
|
||||
Aquí hay un pequeño truco: _su StackScript se está ejecutando en este momento_. El script BASH se ejecuta la primera vez que se inicia el VPS. Eso significa que su VPS aún no está listo.
|
||||
|
||||
El tiempo total de ejecución es de unos 10 minutos. Por lo tanto, tome un descanso, tome un espresso o relájese durante unos minutos. Hay dos partes del script que toman un tiempo: la actualización de todos los paquetes Debian; y la descarga del código Bitcoin. No deberían tomar más de 5 minutos cada uno, lo que significa que si regresa en 10 minutos, probablemente estará listo para comenzar.
|
||||
|
||||
Si está impaciente, puede saltar y `sudo tail -f /standup.log`, que mostrará el progreso actual de la instalación, como se describe en la siguiente sección.
|
||||
|
||||
## Verifique su instalación
|
||||
|
||||
Sabrá que stackscrpit está listo cuando la salida del comando `tail` del` standup.log` muestre algo como lo siguiente:
|
||||
|
||||
`/root/StackScript - Bitcoin is setup as a service and will automatically start if your VPS reboots and so is Tor
|
||||
/root/StackScript - You can manually stop Bitcoin with: sudo systemctl stop bitcoind.service
|
||||
/root/StackScript - You can manually start Bitcoin with: sudo systemctl start bitcoind.service`
|
||||
|
||||
En ese momento, su directorio de inicio debería verse así:
|
||||
|
||||
```
|
||||
$ ls
|
||||
bitcoin-0.20.0-x86_64-linux-gnu.tar.gz laanwj-releases.asc SHA256SUMS.asc
|
||||
```
|
||||
|
||||
Estos son los diversos archivos que se utilizaron para instalar Bitcoin en su VPS. Ninguno es necesario. Los dejamos en caso de que desee realizar una verificación adicional. De lo contrario, puede eliminarlos:
|
||||
|
||||
```
|
||||
$ rm *
|
||||
```
|
||||
|
||||
### Verificar la configuración de Bitcoin
|
||||
|
||||
Para garantizar que la versión de Bitcoin descargada sea válida, StackScript verifica tanto la firma como la suma de comprobación SHA. Debe verificar que ambas pruebas hayan salido bien:
|
||||
|
||||
```
|
||||
$ sudo grep VERIFICATION /standup.log
|
||||
```
|
||||
|
||||
Si ve algo como lo siguiente, todo debería estar bien:
|
||||
|
||||
```
|
||||
/root/StackScript - VERIFICATION SUCCESS / SIG: gpg: Good signature from "Wladimir J. van der Laan (Bitcoin Core binary release signing key) <laanwj@gmail.com>" [unknown]
|
||||
/root/StackScript - VERIFICATION SUCCESS / SHA: 35ec10f87b6bc1e44fd9cd1157e5dfa4```
|
||||
```
|
||||
|
||||
Sin embargo, si en alguna de esas dos comprobaciones se lee "ERROR DE VERIFICACIÓN", entonces hay un problema. Dado que todo esto está programado, es posible que solo haya habido un cambio menor que haya causado que las comprobaciones del script no funcionen correctamente. (Esto ha sucedido varias veces debido a la existencia del script que se convirtió en Standup). Pero también es posible que alguien esté tratando de persuadirlo a ejecutar una copia falsa del demonio de Bitcoin. Entonces, _¡asegúrese de saber lo que sucedió antes de usar Bitcoin!_
|
||||
|
||||
### Leer los registros
|
||||
|
||||
También es posible que desee leer todos los archivos de registro de instalación para asegurarse de que no haya ocurrido nada inesperado durante la instalación.
|
||||
|
||||
Es mejor revisar el archivo de registro estándar de StackScript, que tiene todos los resultados, incluidos los errores:
|
||||
|
||||
`$ sudo more /standup.log`
|
||||
|
||||
Tenga en cuenta que es totalmente normal ver _algunos_ errores, particularmente cuando se ejecuta el ruidoso software pgp y cuando varias cosas intentan acceder al dispositivo inexistente `/dev/tty`.
|
||||
|
||||
Si, en cambio desea ver un conjunto de información más pequeño, todos los errores deben estar en:
|
||||
|
||||
`$ sudo more /standup.err`
|
||||
|
||||
Todavía tiene una buena cantidad de información que no son errores, pero es una lectura más rápida.
|
||||
|
||||
Si todo se ve bien, felicitaciones, ¡tiene un nodo Bitcoin en funcionamiento usando Linode!
|
||||
|
||||
## Lo que hemos hecho
|
||||
|
||||
Aunque la imagen predeterminada de Debian 10 que estamos usando para su VPS ha sido modificada por Linode para que sea relativamente segura, su nodo Bitcoin instalado a través de Linode StackScript está configurado con un nivel de seguridad aún mayor. Es posible que encuentre esto limitante o que no pueda hacer las cosas que espera. Aquí hay algunas notas al respecto:
|
||||
|
||||
### Servicios protegidos
|
||||
|
||||
Su instalación de Bitcoin VPS es mínima y casi no permite ninguna comunicación. Esto se hace a través del sencillo firewall (`ufw`), que bloquea todo excepto las conexiones SSH. También es posible una seguridad adicional para sus puertos RPC, gracias a los servicios ocultos instalados por Tor.
|
||||
|
||||
**Ajustando UFW.** ¡Probablemente debería dejar UFW en su etapa superprotegida! No debería utilizar una máquina Bitcoin para otros servicios, ¡porque todos aumentan su vulnerabilidad! Si decide lo contrario, hay varias [guías de UFW](https://www.digitalocean.com/community/tutorials/ufw-essentials-common-firewall-rules-and-commands) que le permitirán agregar servicios. Como se anuncia, no es complicado. Por ejemplo, agregar servicios de correo solo requeriría abrir el puerto de correo: `sudo ufw allow 25`. Pero en general no debería eso.
|
||||
|
||||
**Ajuste de Tor.** Es posible que desee proteger mejor servicios tales como SSH. Consulte el [Capítulo 14: Usando Tor](14_0_Usando_Tor.md) para obtener más información sobre Tor.
|
||||
|
||||
### Consolas de comando protegidas
|
||||
|
||||
Si definió "IP permitidas por SSH", el acceso SSH (y SCP) al servidor está severamente restringido. `/etc/hosts.deny` no permite que nadie inicie sesión. _No sugerimos cambiar esto_. `/etc/hosts.allow` entonces permite direcciones IP específicas. Simplemente agregue más direcciones IP en una lista separada por comas si necesita ofrecer más acceso.
|
||||
|
||||
Por ejemplo:
|
||||
|
||||
```
|
||||
sshd: 127.0.0.1, 192.128.23.1
|
||||
```
|
||||
|
||||
### Actualizaciones automatizadas
|
||||
|
||||
Debian también está configurado para actualizarse automáticamente, para asegurarse de estar al día con los parches de seguridad más recientes.
|
||||
|
||||
|
||||
Si por alguna razón quisiera cambiar esto (_no lo sugerimos_), puede hacer esto:
|
||||
|
||||
```
|
||||
echo "unattended-upgrades unattended-upgrades/enable_auto_updates boolean false" | debconf-set-selections
|
||||
```
|
||||
|
||||
_Si desea saber más sobre lo que hace el stackscript de Bitcoin Standup, consulte el [Apéndice I: Entendiendo Bitcoin Standup] (A1_0_Entendiendo_la_Configuracion_Inicial_de_Bitcoin.md) ._
|
||||
|
||||
## Jugando con Bitcoin
|
||||
|
||||
¡Así que ahora probablemente quiera jugar con Bitcoin!
|
||||
|
||||
Pero espere, su demonio de Bitcoin probablemente todavía esté descargando bloques. El comando `bitcoin-cli getblockcount` le dirá cómo se encuentra actualmente:
|
||||
|
||||
```
|
||||
$ bitcoin-cli getblockcount
|
||||
1771352
|
||||
```
|
||||
|
||||
Si es diferente cada vez que escribe el comando, debe esperar antes de trabajar con Bitcoin. Esto toma de 1 a 6 horas actualmente para una configuración podada, dependiendo de su máquina.
|
||||
|
||||
Pero, una vez que se establezca en un número, ¡estará listo para continuar!
|
||||
|
||||
Aún así, podría ser hora de algunos expresos más. Pero muy pronto, su sistema estará listo para funcionar y estará leyendo para empezar a experimentar.
|
||||
|
||||
## Resumen: Configuración de un VPS de Bitcoin-Core a mano
|
||||
|
||||
La creación de un VPS de Bitcoin-Core con los scripts Standup hizo que todo el proceso fuera rápido, simple y (con suerte) sin contratiempos.
|
||||
|
||||
|
||||
## ¿Que sigue?
|
||||
|
||||
Tiene algunas opciones para lo que sigue:
|
||||
|
||||
* Lea [StackScript](https://github.com/BlockchainCommons/Bitcoin-Standup-Scripts/blob/master/Scripts/LinodeStandUp.sh) para comprender su configuración.
|
||||
|
||||
* Lea lo que hace StackScript en el [Apéndice I](A1_0_Entendiendo_Bitcoin_Standup.md).
|
||||
|
||||
* Elija una metodología completamente alternativa en [§2.2: Configuración de una máquina Bitcoin-Core a través de otros medios](02_2_Configurando_Bitcoin_Core_Otros.md).
|
||||
|
||||
* Pase a "bitcoin-cli" con el [Capítulo tres: Entendiendo la configuración de Bitcoin](03_0_Entendiendo_Su_Configuracion_Bitcoin.md).
|
||||
|
||||
|
||||
## Sinopsis: Tipos de instalación de Bitcoin
|
||||
|
||||
**Mainnet.** Esto descargará la totalidad de la cadena de bloques de Bitcoin. Esto es alrededor de 380G de datos (y cada día se aumenta más).
|
||||
|
||||
**Mainnet podado.** Esto reducirá la cadena de bloques que está almacenando a solo los últimos 550 bloques. Si no está minando o ejecutando algún otro servicio de Bitcoin, esto debería ser suficiente para la validación.
|
||||
|
||||
**Testnet.** Esto le da acceso a una cadena de bloques de Bitcoin alternativa donde los Bitcoins en realidad no tienen valor. Está destinado a la experimentación y las pruebas.
|
||||
|
||||
**Testnet podado.** Estos son solo los últimos 550 bloques de Testnet ... porque la cadena de bloques de Testnet también es bastante grande ahora.
|
||||
|
||||
**Private Regtest.** Este es el modo de prueba de regresión, que le permite ejecutar un servidor Bitcoin totalmente local. Permite pruebas aún más profundas. No es necesario podar aquí, porque comenzará desde cero. Esta es una configuración muy diferente, por lo que se trata en el [Apéndice 3](A3_0_Usando_Bitcoin_Regtest.md).
|
24
es/02_2_Configurando_Bitcoin_Core_Otros.md
Normal file
24
es/02_2_Configurando_Bitcoin_Core_Otros.md
Normal file
@ -0,0 +1,24 @@
|
||||
# 2.2: Configuración de una máquina Bitcoin-Core a través de otros medios
|
||||
|
||||
La sección anterior, [§2.1: Configuración de un VPS Bitcoin-Core con Bitcoin Standup](02_1_Configurando_un_Bitcoin-Core_VPS_con_StackScript.md), presumía que
|
||||
estaría creando un nodo completo en un VPS usando un Linode Stackscript. Sin embargo, puede crear una instancia de Bitcoin-Core a través de cualquier metodología de
|
||||
su elección y seguir los pasos posteriores de este tutorial.
|
||||
|
||||
A continuación, se muestran otras metodologías de configuración que conocemos:
|
||||
|
||||
* *[Compilación desde la fuente](A2_0_Compilando_Bitcoin_desde_la_Fuente.md).* Si prefiere compilar Bitcoin Core a mano, eso se trata en el Apéndice 2.
|
||||
* *[Usando GordianNode-macOS](https://github.com/BlockchainCommons/GordianNode-macOS).* Si tiene una Mac moderna, puede usar la aplicación *GordianNode* de
|
||||
Blockchain Commons, con tecnología *BitcoinStandup*, para instalar un nodo completo en su Mac.
|
||||
* *[Uso de otros scripts de Bitcoin Standup](https://github.com/BlockchainCommons/Bitcoin-Standup-Scripts).* Blockchain Commons también ofrece una versión del
|
||||
script de Linode que se uso anteriormente y que se puede ejecutar desde la línea de comandos en cualquier máquina Debian o Ubuntu. Este tiende a ser un script
|
||||
de vanguardia, lo que significa que es más probable que presente nuevas funciones, como la instalación de Lightning.
|
||||
* *[Configuración de un nodo Bitcoin en AWS](https://wolfmcnally.com/115/developer-notes-setting-up-a-bitcoin-node-on-aws/).* @wolfmcnally ha escrito un tutorial
|
||||
paso a paso para configurar Bitcoin-Core con Amazon Web Services (AWS).
|
||||
* *[Configuración de un nodo Bitcoin en una Raspberry Pi 3](https://medium.com/@meeDamian/bitcoin-full-node-on-rbp3-revised-88bb7c8ef1d1).* Damian Mee explica
|
||||
cómo configurar una Nodo completo de forma sencilla en una Raspberry Pi 3.
|
||||
|
||||
## ¿Que sigue?
|
||||
|
||||
A menos que desee volver a una de las otras metodologías para crear un nodo Bitcoin-Core, debe:
|
||||
|
||||
* Continúe con "bitcoin-cli" con el [Capítulo tres: Entendiendo su configuración de Bitcoin](03_0_Entendiendo_Su_Configuracion_Bitcoin.md).
|
31
es/03_0_Entendiendo_Su_Configuracion_Bitcoin.md
Normal file
31
es/03_0_Entendiendo_Su_Configuracion_Bitcoin.md
Normal file
@ -0,0 +1,31 @@
|
||||
# Capítulo Tres: Entendiendo Su Configuración Bitcoin
|
||||
|
||||
Ahora está listo para comenzar a trabajar con la interfaz de línea de comandos `bitcoin-cli`. Pero eso primero requiere que comprenda la configuración de Bitcoin y las características de su billetera, que es lo que se explicará en este capítulo.
|
||||
|
||||
Para este y futuros capítulos, suponemos que tiene un VPS con Bitcoin instalado, ejecutando `bitcoind`. También suponemos que está conectado a testnet, lo que le permite acceder a bitcoins sin utilizar fondos reales. Puede hacerlo con Bitcoin Standup en Linode.com, según [§2.1: Configuración de un Servidor Privado Virtual de Bitcoin-Core con Bitcoin Standup](02_1_Configurando_un_Bitcoin-Core_VPS_con_StackScript.md), o por otros medios, según [§2.2: Configuración de una Maquina Bitcoin-Core por Otros Medios](02_2_Configurando_Bitcoin_Core_Otros.md).
|
||||
|
||||
## Objetivos de este capítulo
|
||||
|
||||
Después de trabajar en este capítulo, un desarrollador podrá:
|
||||
|
||||
* Demostrar que su nodo Bitcoin está instalado y actualizado
|
||||
* Crear una dirección para recibir fondos de Bitcoin
|
||||
* Usar comandos básicos de billetera
|
||||
* Crear una dirección a partir de un descriptor
|
||||
|
||||
Los objetivos de apoyo incluyen la capacidad de:
|
||||
|
||||
* Comprender el diseño básico de archivos de Bitcoin
|
||||
* Usar comandos informativos básicos
|
||||
* Comprenda qué es una dirección de Bitcoin
|
||||
* Comprender qué es una billetera
|
||||
* Comprender cómo importar direcciones
|
||||
|
||||
## Tabla de contenido
|
||||
|
||||
* [Sección Uno: Verificando Su Configuración Bitcoin](03_1_Verificando_Su_Configuracion_Bitcoin.md)
|
||||
* [Sección Dos: Conociendo Su Configuración Bitcoin](03_2_Conociendo_Su_Configuracion_Bitcoin.md)
|
||||
* [Sección Tres: Configurando Su Billetera](03_3_Configurando_Su_Billetera.md)
|
||||
* [Interludio: Usando Variables de la Linea de Comandos](03_3_Interludio_Usando_Variables_Linea_Comando.md)
|
||||
* [Sección Cuatro: Recibiendo una Transacción](03_4_Recibiendo_una_Transaccion.md)
|
||||
* [Sección Cinco: Entendiendo El Descriptor](03_5_Entendiendo_El_Descriptor.md)
|
115
es/03_1_Verificando_Su_Configuracion_Bitcoin.md
Normal file
115
es/03_1_Verificando_Su_Configuracion_Bitcoin.md
Normal file
@ -0,0 +1,115 @@
|
||||
# 3.1: Verificando su configuración Bitcoin
|
||||
|
||||
Antes de comenzar a jugar con Bitcoin, debe asegurarse de que todo esté configurado correctamente.
|
||||
|
||||
## Cree sus Alias
|
||||
|
||||
Sugerimos crear algunos alias para facilitar el uso de Bitcoin.
|
||||
|
||||
Puede hacerlo colocándolos en sus archivos `.bash_profile`, `.bashrc` o `.profile`.
|
||||
```
|
||||
cat >> ~/.bash_profile <<EOF
|
||||
alias btcdir="cd ~/.bitcoin/" #linux default bitcoind path
|
||||
alias bc="bitcoin-cli"
|
||||
alias bd="bitcoind"
|
||||
alias btcinfo='bitcoin-cli getwalletinfo | egrep "\"balance\""; bitcoin-cli getnetworkinfo | egrep "\"version\"|connections"; bitcoin-cli getmininginfo | egrep "\"blocks\"|errors"'
|
||||
EOF
|
||||
```
|
||||
Después de ingresar estos alias, puede ejecutar `source .bash_profile` para cargarlos o cerrar sesion e iniciar sesion de nuevo.
|
||||
|
||||
Tenga en cuenta que estos alias incluyen atajos para ejecutar `bitcoin-cli`, para ejecutar `bitcoind` y para posicionarse en el directorio de Bitcoin.
|
||||
Estos alias están destinados principalmente a facilitarle la vida. Le sugerimos que cree otros alias para facilitar el uso de comandos frecuentes
|
||||
(y argumentos) y minimizar los errores. Los alias de este tipo pueden ser aún más útiles si tiene una configuración compleja en la que ejecuta
|
||||
regularmente comandos asociados con Mainnet, con Testnet _y_ con Regtest, como se explica más adelante.
|
||||
|
||||
Dicho esto, el uso de estos alias en este documento podría oscurecer accidentalmente las lecciones principales que se enseñan sobre Bitcoin,
|
||||
por lo que el único alias que se usa directamente aquí es `btcinfo` porque encapsula un comando mucho más largo y complejo. De lo contrario, mostramos
|
||||
los comandos completos; ajuste para su propio uso según corresponda.
|
||||
|
||||
## Ejecutar Bitcoind
|
||||
|
||||
Comenzará su exploración de la red Bitcoin con el comando `bitcoin-cli`. Sin embargo, bitcoind _debe_ estar ejecutándose para usar bitcoin-cli,
|
||||
ya que bitcoin-cli envía comandos JSON-RPC al bitcoind. Si usó nuestra configuración estándar, bitcoind ya debería estar en funcionamiento.
|
||||
Puede verificar dos veces mirando la tabla de procesos.
|
||||
|
||||
```
|
||||
$ ps auxww | grep bitcoind
|
||||
standup 455 1.3 34.4 3387536 1392904 ? SLsl Jun16 59:30 /usr/local/bin/bitcoind -conf=/home/standup/.bitcoin/bitcoin.conf
|
||||
```
|
||||
Si no se está ejecutando, querrá ejecutarlo `/usr/local/bin/bitcoind -daemon` manualmente y también colocarlo en su crontab.
|
||||
|
||||
## Verifique sus bloques
|
||||
|
||||
Debería tener toda la cadena de bloques descargada antes de comenzar a jugar. Simplemente ejecute el alias `bitcoin-cli getblockcount` para ver si está todo cargado.
|
||||
|
||||
```
|
||||
$ bitcoin-cli getblockcount
|
||||
1772384
|
||||
```
|
||||
Eso le indica lo que está descargado; luego deberá verificarlo con un servicio en línea que le indique la altura actual del bloque.
|
||||
|
||||
> :book: ***¿Qué es la altura del bloque?*** La altura del bloque es la distancia a la que se retira un bloque particular del bloque génesis. La altura del bloque actual es la altura del bloque más nuevo agregado a una cadena de bloques.
|
||||
|
||||
Puede hacer esto mirando un explorador de blocknet, tal como [Blockcypher Testnet explorer](https://live.blockcypher.com/btc-testnet/). Su número más reciente coincide con la salida del `getblockcount`? Si es así, está actualizado.
|
||||
|
||||
Si desea un alias para ver todo a la vez, lo siguiente funciona actualmente para Testnet, pero puede desaparecer en algún momento en el futuro:
|
||||
|
||||
```
|
||||
$ cat >> ~/.bash_profile << EOF
|
||||
alias btcblock="echo \\\`bitcoin-cli getblockcount 2>&1\\\`/\\\`wget -O - https://blockstream.info/testnet/api/blocks/tip/height 2> /dev/null | cut -d : -f2 | rev | cut -c 1- | rev\\\`"
|
||||
EOF
|
||||
$ source .bash_profile
|
||||
$ btcblock
|
||||
1804372/1804372
|
||||
```
|
||||
|
||||
> :link: **TESTNET vs MAINNET:** Recuerde que este tutorial generalmente asume que está usando testnet. Si en cambio está utilizando la red mainnet, se puede recuperar la altura del bloque actual con: `wget -O - http://blockchain.info/q/getblockcount 2>/dev/null`. Puede reemplazar la segunda mitad del alias `btblock` (después de `/`) con eso.
|
||||
|
||||
Si no está actualizado, pero la salida de su `getblockcount` está aumentando, no hay problema. El tiempo total de descarga puede llevar desde una hora hasta varias horas, según su configuración.
|
||||
|
||||
## Opcional: conozca los tipos de servidor
|
||||
|
||||
> **TESTNET vs MAINNET:** Cuando configura su nodo, usted puede elegir crearlo como un nodo Mainnet, Testnet o Regtest. Aunque este documento presupone una configuración de testnet, vale la pena comprender cómo puede acceder y utilizar los otros tipos de configuración, ¡incluso todos en la misma máquina! Pero, si es un usuario nuevo, omita esto, ya que no es necesario para una configuración básica.
|
||||
|
||||
El tipo de configuración se controla principalmente a través del archivo ~/.bitcoin/bitcoin.conf. Si está ejecutando testnet, probablemente contenga esta línea:
|
||||
```
|
||||
testnet=1
|
||||
```
|
||||
Si está ejecutando regtest, probablemente contenga esta línea:
|
||||
```
|
||||
regtest=1
|
||||
```
|
||||
|
||||
Sin embargo, si desea ejecutar varios tipos diferentes de nodos simultáneamente, debe dejar la marca testnet (o regtest) fuera de su archivo de configuración. Luego puede elegir si está utilizando la red principal, la red de prueba o su registro cada vez que ejecuta bitcoind o bitcoin-cli.
|
||||
|
||||
Aquí hay un conjunto de alias que lo facilitarían al crear un alias específico para iniciar y detener el bitcoind, para ir al directorio de bitcoin y para ejecutar bitcoin-cli, para cada una de las redes principales; mainnet (que no tiene indicadores adicionales), testnet (que es -testnet), o regtest (que es -regtest).
|
||||
|
||||
```
|
||||
cat >> ~/.bash_profile <<EOF
|
||||
alias bcstart="bitcoind -daemon"
|
||||
alias btstart="bitcoind -testnet -daemon"
|
||||
alias brstart="bitcoind -regtest -daemon"
|
||||
|
||||
alias bcstop="bitcoin-cli stop"
|
||||
alias btstop="bitcoin-cli -testnet stop"
|
||||
alias brstop="bitcoin-cli -regtest stop"
|
||||
|
||||
alias bcdir="cd ~/.bitcoin/" #linux default bitcoin path
|
||||
alias btdir="cd ~/.bitcoin/testnet" #linux default bitcoin testnet path
|
||||
alias brdir="cd ~/.bitcoin/regtest" #linux default bitcoin regtest path
|
||||
|
||||
alias bc="bitcoin-cli"
|
||||
alias bt="bitcoin-cli -testnet"
|
||||
alias br="bitcoin-cli -regtest"
|
||||
EOF
|
||||
```
|
||||
|
||||
Para una mayor complejidad, puede hacer que cada uno de sus alias de 'inicio' use el indicador -conf para cargar la configuración desde un archivo diferente. Esto va mucho más allá del alcance de este tutorial, pero lo ofrecemos como punto de partida para cuando sus exploraciones de Bitcoin alcancen el siguiente nivel.
|
||||
|
||||
## Resumen: verificación de la configuración de Bitcoin
|
||||
|
||||
Antes de comenzar a jugar con bitcoin, debe asegurarse de que sus alias estén configurados, su bitcoind se esté ejecutando y sus bloques estén descargados. Es posible que también desee configurar algún acceso a configuraciones alternativas de Bitcoin, si es un usuario avanzado.
|
||||
|
||||
## ¿Que sigue?
|
||||
|
||||
Continue "Conociendo su configuración Bitcoin" en [§3.2: Entendiendo su configuración Bitcoin](03_2_Conociendo_Su_Configuracion_Bitcoin.md).
|
315
es/03_2_Conociendo_Su_Configuracion_Bitcoin.md
Normal file
315
es/03_2_Conociendo_Su_Configuracion_Bitcoin.md
Normal file
@ -0,0 +1,315 @@
|
||||
# 3.2: Conociendo su configuración Bitcoin
|
||||
|
||||
Antes de comenzar a jugar con Bitcoin, es posible que siempre quiera llegar a una mejor comprension.
|
||||
|
||||
## Conozca su directorio de Bitcoin
|
||||
|
||||
Para empezar, debe comprender dónde se guarda todo: el directorio `~/.bitcoin`.
|
||||
|
||||
El directorio principal solo contiene su archivo de configuración y el directorio testnet:
|
||||
```
|
||||
$ ls ~/.bitcoin
|
||||
bitcoin.conf testnet3
|
||||
```
|
||||
Las guías de configuración del [Capítulo dos: Creación de un VPS de Bitcoin-Core](02_0_Configurando_un_Bitcoin-Core_VPS.md) presentaron un archivo de configuración estandarizado. [3.1: Verificando Su Configuración Bitcoin](03_1_Verificando_Su_Configuracion_Bitcoin.md) sugirió cómo cambiarla para admitir configuraciones más avanzadas. Si está interesado en aprender aún más sobre el archivo de configuración, puede consultar el Generador de configuración de [Bitcoin Core de Jameson Lopp](https://jlopp.github.io/bitcoin-core-config-generator/).
|
||||
|
||||
Volviendo a su directorio ~ / .bitcoin, encontrará que el directorio testnet3 contiene todas las vísceras:
|
||||
```
|
||||
$ ls ~/.bitcoin/testnet3
|
||||
banlist.dat blocks debug.log mempool.dat peers.dat
|
||||
bitcoind.pid chainstate fee_estimates.dat onion_private_key wallets
|
||||
```
|
||||
No debería interactuar con la mayoría de estos archivos y directorios, particularmente con los directorios `blocks` y `chainstate`, que contienen todos los datos de la cadena de bloques, y la información en su directorio `wallets`, que contiene su billetera personal. Sin embargo, tome nota del archvo `debug.log`, al que debe consultar si alguna vez tiene problemas con la configuración.
|
||||
|
||||
> :link: **TESTNET vs MAINNET:** Si está utilizando mainnet, entonces _todo_ se colocará en el directorio principal `~/.bitcoin`. Estas diversas configuraciones se apilan elegantemente, por lo que si usted está usando mainnet, testnet y regtest, usted encontrará que `~/.bitcoin` contiene el archivo de configuración y sus datos MainNet, el directorio `~/.bitcoin/testnet3` contiene los datos Testnet, y el directorio `~/.bitcoin/regtest` los datos Regtest.
|
||||
|
||||
## Conozca sus comandos Bitcoin-cli
|
||||
|
||||
La mayor parte de su trabajo inicial se realizará con el comando `bitcoin-cli`, que ofrece una interfaz sencilla para `bitcoind`. Si alguna vez desea obtener más información sobre su uso, simplemente ejecútelo con el argumento `help`. Sin ningún otro argumento, le muestra todos los comandos posibles:
|
||||
|
||||
```
|
||||
$ bitcoin-cli help
|
||||
== Blockchain ==
|
||||
getbestblockhash
|
||||
getblock "blockhash" ( verbosity )
|
||||
getblockchaininfo
|
||||
getblockcount
|
||||
getblockfilter "blockhash" ( "filtertype" )
|
||||
getblockhash height
|
||||
getblockheader "blockhash" ( verbose )
|
||||
getblockstats hash_or_height ( stats )
|
||||
getchaintips
|
||||
getchaintxstats ( nblocks "blockhash" )
|
||||
getdifficulty
|
||||
getmempoolancestors "txid" ( verbose )
|
||||
getmempooldescendants "txid" ( verbose )
|
||||
getmempoolentry "txid"
|
||||
getmempoolinfo
|
||||
getrawmempool ( verbose )
|
||||
gettxout "txid" n ( include_mempool )
|
||||
gettxoutproof ["txid",...] ( "blockhash" )
|
||||
gettxoutsetinfo
|
||||
preciousblock "blockhash"
|
||||
pruneblockchain height
|
||||
savemempool
|
||||
scantxoutset "action" ( [scanobjects,...] )
|
||||
verifychain ( checklevel nblocks )
|
||||
verifytxoutproof "proof"
|
||||
|
||||
== Control ==
|
||||
getmemoryinfo ( "mode" )
|
||||
getrpcinfo
|
||||
help ( "command" )
|
||||
logging ( ["include_category",...] ["exclude_category",...] )
|
||||
stop
|
||||
uptime
|
||||
|
||||
== Generating ==
|
||||
generatetoaddress nblocks "address" ( maxtries )
|
||||
generatetodescriptor num_blocks "descriptor" ( maxtries )
|
||||
|
||||
== Mining ==
|
||||
getblocktemplate ( "template_request" )
|
||||
getmininginfo
|
||||
getnetworkhashps ( nblocks height )
|
||||
prioritisetransaction "txid" ( dummy ) fee_delta
|
||||
submitblock "hexdata" ( "dummy" )
|
||||
submitheader "hexdata"
|
||||
|
||||
== Network ==
|
||||
addnode "node" "command"
|
||||
clearbanned
|
||||
disconnectnode ( "address" nodeid )
|
||||
getaddednodeinfo ( "node" )
|
||||
getconnectioncount
|
||||
getnettotals
|
||||
getnetworkinfo
|
||||
getnodeaddresses ( count )
|
||||
getpeerinfo
|
||||
listbanned
|
||||
ping
|
||||
setban "subnet" "command" ( bantime absolute )
|
||||
setnetworkactive state
|
||||
|
||||
== Rawtransactions ==
|
||||
analyzepsbt "psbt"
|
||||
combinepsbt ["psbt",...]
|
||||
combinerawtransaction ["hexstring",...]
|
||||
converttopsbt "hexstring" ( permitsigdata iswitness )
|
||||
createpsbt [{"txid":"hex","vout":n,"sequence":n},...] [{"address":amount},{"data":"hex"},...] ( locktime replaceable )
|
||||
createrawtransaction [{"txid":"hex","vout":n,"sequence":n},...] [{"address":amount},{"data":"hex"},...] ( locktime replaceable )
|
||||
decodepsbt "psbt"
|
||||
decoderawtransaction "hexstring" ( iswitness )
|
||||
decodescript "hexstring"
|
||||
finalizepsbt "psbt" ( extract )
|
||||
fundrawtransaction "hexstring" ( options iswitness )
|
||||
getrawtransaction "txid" ( verbose "blockhash" )
|
||||
joinpsbts ["psbt",...]
|
||||
sendrawtransaction "hexstring" ( maxfeerate )
|
||||
signrawtransactionwithkey "hexstring" ["privatekey",...] ( [{"txid":"hex","vout":n,"scriptPubKey":"hex","redeemScript":"hex","witnessScript":"hex","amount":amount},...] "sighashtype" )
|
||||
testmempoolaccept ["rawtx",...] ( maxfeerate )
|
||||
utxoupdatepsbt "psbt" ( ["",{"desc":"str","range":n or [n,n]},...] )
|
||||
|
||||
== Util ==
|
||||
createmultisig nrequired ["key",...] ( "address_type" )
|
||||
deriveaddresses "descriptor" ( range )
|
||||
estimatesmartfee conf_target ( "estimate_mode" )
|
||||
getdescriptorinfo "descriptor"
|
||||
signmessagewithprivkey "privkey" "message"
|
||||
validateaddress "address"
|
||||
verifymessage "address" "signature" "message"
|
||||
|
||||
== Wallet ==
|
||||
abandontransaction "txid"
|
||||
abortrescan
|
||||
addmultisigaddress nrequired ["key",...] ( "label" "address_type" )
|
||||
backupwallet "destination"
|
||||
bumpfee "txid" ( options )
|
||||
createwallet "wallet_name" ( disable_private_keys blank "passphrase" avoid_reuse )
|
||||
dumpprivkey "address"
|
||||
dumpwallet "filename"
|
||||
encryptwallet "passphrase"
|
||||
getaddressesbylabel "label"
|
||||
getaddressinfo "address"
|
||||
getbalance ( "dummy" minconf include_watchonly avoid_reuse )
|
||||
getbalances
|
||||
getnewaddress ( "label" "address_type" )
|
||||
getrawchangeaddress ( "address_type" )
|
||||
getreceivedbyaddress "address" ( minconf )
|
||||
getreceivedbylabel "label" ( minconf )
|
||||
gettransaction "txid" ( include_watchonly verbose )
|
||||
getunconfirmedbalance
|
||||
getwalletinfo
|
||||
importaddress "address" ( "label" rescan p2sh )
|
||||
importmulti "requests" ( "options" )
|
||||
importprivkey "privkey" ( "label" rescan )
|
||||
importprunedfunds "rawtransaction" "txoutproof"
|
||||
importpubkey "pubkey" ( "label" rescan )
|
||||
importwallet "filename"
|
||||
keypoolrefill ( newsize )
|
||||
listaddressgroupings
|
||||
listlabels ( "purpose" )
|
||||
listlockunspent
|
||||
listreceivedbyaddress ( minconf include_empty include_watchonly "address_filter" )
|
||||
listreceivedbylabel ( minconf include_empty include_watchonly )
|
||||
listsinceblock ( "blockhash" target_confirmations include_watchonly include_removed )
|
||||
listtransactions ( "label" count skip include_watchonly )
|
||||
listunspent ( minconf maxconf ["address",...] include_unsafe query_options )
|
||||
listwalletdir
|
||||
listwallets
|
||||
loadwallet "filename"
|
||||
lockunspent unlock ( [{"txid":"hex","vout":n},...] )
|
||||
removeprunedfunds "txid"
|
||||
rescanblockchain ( start_height stop_height )
|
||||
sendmany "" {"address":amount} ( minconf "comment" ["address",...] replaceable conf_target "estimate_mode" )
|
||||
sendtoaddress "address" amount ( "comment" "comment_to" subtractfeefromamount replaceable conf_target "estimate_mode" avoid_reuse )
|
||||
sethdseed ( newkeypool "seed" )
|
||||
setlabel "address" "label"
|
||||
settxfee amount
|
||||
setwalletflag "flag" ( value )
|
||||
signmessage "address" "message"
|
||||
signrawtransactionwithwallet "hexstring" ( [{"txid":"hex","vout":n,"scriptPubKey":"hex","redeemScript":"hex","witnessScript":"hex","amount":amount},...] "sighashtype" )
|
||||
unloadwallet ( "wallet_name" )
|
||||
walletcreatefundedpsbt [{"txid":"hex","vout":n,"sequence":n},...] [{"address":amount},{"data":"hex"},...] ( locktime options bip32derivs )
|
||||
walletlock
|
||||
walletpassphrase "passphrase" timeout
|
||||
walletpassphrasechange "oldpassphrase" "newpassphrase"
|
||||
walletprocesspsbt "psbt" ( sign "sighashtype" bip32derivs )
|
||||
|
||||
== Zmq ==
|
||||
getzmqnotifications
|
||||
```
|
||||
También puede escribir `bitcoin-cli help [command]` para obtener información aún más extensa sobre ese comando. Por ejemplo:
|
||||
```
|
||||
$ bitcoin-cli help getmininginfo
|
||||
...
|
||||
Returns a json object containing mining-related information.
|
||||
Result:
|
||||
{ (json object)
|
||||
"blocks" : n, (numeric) The current block
|
||||
"currentblockweight" : n, (numeric, optional) The block weight of the last assembled block (only present if a block was ever assembled)
|
||||
"currentblocktx" : n, (numeric, optional) The number of block transactions of the last assembled block (only present if a block was ever assembled)
|
||||
"difficulty" : n, (numeric) The current difficulty
|
||||
"networkhashps" : n, (numeric) The network hashes per second
|
||||
"pooledtx" : n, (numeric) The size of the mempool
|
||||
"chain" : "str", (string) current network name (main, test, regtest)
|
||||
"warnings" : "str" (string) any network and blockchain warnings
|
||||
}
|
||||
|
||||
Examples:
|
||||
> bitcoin-cli getmininginfo
|
||||
> curl --user myusername --data-binary '{"jsonrpc": "1.0", "id": "curltest", "method": "getmininginfo", "params": []}' -H 'content-type: text/plain;' http://127.0.0.1:8332/
|
||||
```
|
||||
> :book: ***¿Qué es RPC?*** `bitcoin-cli` es solo una interfaz práctica que le permite enviar comandos al `bitcoind`. Más específicamente, es una interfaz que le permite enviar comandos RPC (o protocolo de procedimiento remoto) al `bitcoind`. A menudo, el comando `bitcoin-cli` y el comando RPC tienen nombres e interfaces idénticos, pero algunos comandos `bitcoin-cli` proporcionan atajos para solicitudes RPC más complejas. Generalmente, la interfaz `bitcoin-cli` es mucho más limpia y simple que intentar enviar comandos RPC a mano, usando `curl` o algún otro método. Sin embargo, también tiene limitaciones en cuanto a lo que puede hacer en última instancia.
|
||||
|
||||
## Opcional: conozca su información de Bitcoin
|
||||
|
||||
Una variedad de comandos bitcoin-cli pueden brindarle información adicional sobre sus datos bitcoin. Los más generales son:
|
||||
|
||||
`bitcoin-cli -getinfo` devuelve información de diferentes RPC (fácil de usar)
|
||||
|
||||
```diff
|
||||
$ bitcoin-cli -getinfo
|
||||
|
||||
! Chain: test
|
||||
Blocks: 1977694
|
||||
Headers: 1977694
|
||||
Verification progress: 0.9999993275374796
|
||||
Difficulty: 1
|
||||
|
||||
+ Network: in 0, out 8, total 8
|
||||
Version: 219900
|
||||
Time offset (s): 0
|
||||
Proxy: N/A
|
||||
Min tx relay fee rate (BTC/kvB): 0.00001000
|
||||
|
||||
@@ Wallet: ""@@
|
||||
Keypool size: 1000
|
||||
Unlocked until: 0
|
||||
Transaction fee rate (-paytxfee) (BTC/kvB): 0.00000000
|
||||
|
||||
# Balance: 0.02853102
|
||||
|
||||
- Warnings: unknown new rules activated (versionbit 28)
|
||||
|
||||
```
|
||||
|
||||
Otros comandos para obtener información sobre blockchain, minería, red, billetera, etc.
|
||||
|
||||
```
|
||||
$ bitcoin-cli getblockchaininfo
|
||||
$ bitcoin-cli getmininginfo
|
||||
$ bitcoin-cli getnetworkinfo
|
||||
$ bitcoin-cli getnettotals
|
||||
$ bitcoin-cli getwalletinfo
|
||||
```
|
||||
Por ejemplo, `bitcoin-cli getnetworkinfo` le brinda una variedad de información sobre su configuración y su acceso a varias redes:
|
||||
```
|
||||
$ bitcoin-cli getnetworkinfo
|
||||
{
|
||||
"version": 200000,
|
||||
"subversion": "/Satoshi:0.20.0/",
|
||||
"protocolversion": 70015,
|
||||
"localservices": "0000000000000408",
|
||||
"localservicesnames": [
|
||||
"WITNESS",
|
||||
"NETWORK_LIMITED"
|
||||
],
|
||||
"localrelay": true,
|
||||
"timeoffset": 0,
|
||||
"networkactive": true,
|
||||
"connections": 10,
|
||||
"networks": [
|
||||
{
|
||||
"name": "ipv4",
|
||||
"limited": false,
|
||||
"reachable": true,
|
||||
"proxy": "",
|
||||
"proxy_randomize_credentials": false
|
||||
},
|
||||
{
|
||||
"name": "ipv6",
|
||||
"limited": false,
|
||||
"reachable": true,
|
||||
"proxy": "",
|
||||
"proxy_randomize_credentials": false
|
||||
},
|
||||
{
|
||||
"name": "onion",
|
||||
"limited": false,
|
||||
"reachable": true,
|
||||
"proxy": "127.0.0.1:9050",
|
||||
"proxy_randomize_credentials": true
|
||||
}
|
||||
],
|
||||
"relayfee": 0.00001000,
|
||||
"incrementalfee": 0.00001000,
|
||||
"localaddresses": [
|
||||
{
|
||||
"address": "45.79.111.171",
|
||||
"port": 18333,
|
||||
"score": 1
|
||||
},
|
||||
{
|
||||
"address": "2600:3c01::f03c:92ff:fecc:fdb7",
|
||||
"port": 18333,
|
||||
"score": 1
|
||||
},
|
||||
{
|
||||
"address": "4wrr3ktm6gl4sojx.onion",
|
||||
"port": 18333,
|
||||
"score": 4
|
||||
}
|
||||
],
|
||||
"warnings": "Warning: unknown new rules activated (versionbit 28)"
|
||||
}
|
||||
```
|
||||
No dude en hacer referencia a cualquiera de estos y utilizar el comando "bitcoin-cli help" si desea obtener más información sobre lo que hacen.
|
||||
|
||||
## Resumen: conociendo la configuración de Bitcoin
|
||||
|
||||
El directorio `~/.bitcoin` contiene todos sus archivos, mientras que `bitcoin-cli help` se puede usar con una variedad de comandos informativos para obtener más información sobre cómo funcionan su configuración y Bitcoin.
|
||||
|
||||
## ¿Que sigue?
|
||||
|
||||
Continúe "Entendiendo su configuracion de Bitcoin" en [§3.3: Configurando su billetera](03_3_Configurando_Su_Billetera.md).
|
174
es/03_3_Configurando_Su_Billetera.md
Normal file
174
es/03_3_Configurando_Su_Billetera.md
Normal file
@ -0,0 +1,174 @@
|
||||
# 3.3: Configurando su billetera
|
||||
|
||||
Ahora está listo para comenzar a trabajar con Bitcoin. Para empezar, deberá crear una billetera para recibir fondos.
|
||||
|
||||
## Crear una billetera
|
||||
|
||||
> :warning: **VERSION WARNING:** Las versiones más recientes de Bitcoin Core, a partir de la v0.21.0, ya no crearán automáticamente una billetera predeterminada al inicio. Por lo tanto, deberá crear uno manualmente. Pero si está ejecutando una versión anterior de Bitcoin Core, ya se ha creado una nueva billetera para usted, en cuyo caso puede pasar a [Crear una dirección] (#crear-una-dirección).
|
||||
|
||||
Lo primero que debe hacer es crear una nueva billetera, lo que se puede hacer con el comando `bitcoin-cli createwallet`. Al crear una nueva billetera, creará su par de claves pública-privada. Su clave pública es la fuente a partir de la cual se crearán sus direcciones, y su clave privada es la que le permitirá gastar los fondos que reciba en sus direcciones. Bitcoin Core guardará automáticamente esa información en un archivo `wallet.dat` en su directorio `~/.bitcoin/testnet3/wallets`.
|
||||
|
||||
Si revisa su directorio `wallets`, verá que actualmente está vacío.
|
||||
```
|
||||
$ ls ~/.bitcoin/testnet3/wallets
|
||||
$
|
||||
```
|
||||
|
||||
Aunque Bitcoin Core no creará una nueva billetera para usted, todavía cargará una billetera sin nombre de nivel superior ("") al inicio de forma predeterminada. Puede aprovechar esto creando una nueva billetera sin nombre.
|
||||
```
|
||||
$ bitcoin-cli createwallet ""
|
||||
{
|
||||
"name": "",
|
||||
"warning": ""
|
||||
}
|
||||
```
|
||||
|
||||
Ahora, su directorio `wallets` debería estar poblado.
|
||||
```
|
||||
$ ls ~/.bitcoin/testnet3/wallets
|
||||
database db.log wallet.dat
|
||||
```
|
||||
|
||||
> :book: ***What is a Bitcoin wallet?*** Una billetera Bitcoin es el equivalente digital de una billetera física en la red Bitcoin. Almacena información sobre la cantidad de bitcoins que tiene y dónde se encuentra (direcciones), así como las formas en que puede utilizar para gastarlos. Gastar dinero físico es intuitivo, pero para gastar bitcoins, los usuarios deben proporcionar la _clave privada_ correcta. Explicaremos esto con más detalle a lo largo del curso, pero lo que debe saber por ahora es que esta dinámica de clave pública-privada es parte de lo que hace que Bitcoin sea seguro y sin confianza. La información de su par de claves se guarda en el archivo `wallet.dat`, además de los datos sobre preferencias y transacciones. En su mayor parte, no tendrá que preocuparse por esa clave privada: `bitcoind` la usará cuando sea necesario. Sin embargo, esto hace que el archivo `wallet.dat` sea extremadamente importante: si lo pierde, pierde sus claves privadas, y si pierde sus claves privadas, ¡pierde sus fondos!
|
||||
|
||||
Genial, ahora tiene una billetera Bitcoin. Pero una billetera será de poca utilidad para recibir bitcoins si no crea una dirección primero.
|
||||
|
||||
## Crear una dirección.
|
||||
|
||||
Lo siguiente que debe hacer es crear una dirección para recibir pagos. Esto se hace con el comando `bitcoin-cli getnewaddress`.
|
||||
Recuerde que si quiere más información sobre este comando, debe escribir `bitcoin-cli help getnewaddress`.
|
||||
Actualmente, hay tres tipos de direcciones: legacy y los dos tipos de direcciones SegWit `p2sh-segwit` y `bech32`.
|
||||
Si no especifica lo contrario, obtendrá el valor predeterminado, que es actualmente bech32.
|
||||
|
||||
Sin embargo, en las próximas secciones usaremos direcciones `legacy`, tanto porque `bitcoin-cli` tuvó algunos problemas iniciales con sus primeras versiones
|
||||
de direcciones SegWit como porque otras personas podrían no ser capaces de enviar a direcciones `bech32`. Es poco probable que todo esto sea un problema para
|
||||
usted ahora, pero por el momento queremos comenzar con ejemplos de transacciones que está (en su mayoría) garantizado que funcionan.
|
||||
|
||||
Primero, reinicie `bitcoind` por lo que su nueva billetera sin nombre se establece como predeterminada y se carga automáticamente.
|
||||
```
|
||||
$ bitcoin-cli stop
|
||||
Bitcoin Core stopping # wait a minute so it stops completely
|
||||
$ bitcoind -daemon
|
||||
Bitcoin Core starting # wait a minute so it starts completely
|
||||
```
|
||||
|
||||
Ahora puede crear una dirección. Puede requerir la dirección `legacy` ya sea con el segundo argumento de` getnewaddress` o con el argumento llamado `addresstype`.
|
||||
|
||||
```
|
||||
$ bitcoin-cli getnewaddress -addresstype legacy
|
||||
moKVV6XEhfrBCE3QCYq6ppT7AaMF8KsZ1B
|
||||
```
|
||||
Tenga en cuenta que esta dirección comienza con una "m" (o, a veces, una "n") para indicar una dirección heredada de testnet.
|
||||
Sería un "2" para una dirección P2SH o un "tb1" para una dirección Bech32.
|
||||
|
||||
> :link: **TESTNET vs MAINNET:** La dirección de mainnet equivalente comenzaría con un "1" (para Legacy), "3" (para P2SH) o "bc1" (para Bech32).
|
||||
|
||||
Toma nota de la dirección. Deberá entregárselo a quien le envíe los fondos.
|
||||
|
||||
> :book: ***¿Qué es una dirección Bitcoin?*** Una dirección de Bitcoin es, literalmente, donde recibe dinero. Es como una dirección de correo electrónico, pero para fondos. Técnicamente, es una clave pública, aunque diferentes esquemas de direcciones lo ajustan de diferentes maneras. Sin embargo, a diferencia de una dirección de correo electrónico, una dirección de Bitcoin debe considerarse de un solo uso: úsela para recibir fondos solo una vez . Cuando desee recibir fondos de otra persona o en otro momento, genere una nueva dirección. Esto se sugiere en gran parte para mejorar su privacidad. Toda la cadena de bloques es inmutable, lo que significa que los exploradores pueden observar largas cadenas de transacciones a lo largo del tiempo, lo que hace posible determinar estadísticamente quiénes son usted y sus contactos, sin importar cuán cuidadoso sea. Sin embargo, si sigue reutilizando la misma dirección, esto se vuelve aún más fácil.
|
||||
|
||||
Con una sola dirección en la mano, puede pasar directamente a la siguiente sección y comenzar a recibir fondos. Sin embargo, antes de llegar allí, discutiremos brevemente los otros tipos de direcciones que encontrará en el futuro y hablaremos sobre algunos otros comandos de billetera que quizás desee usar en el futuro.
|
||||
|
||||
### Conociendo sus direcciones de Bitcoin
|
||||
|
||||
Hay tres tipos de direcciones de Bitcoin que puede crear con el comando RPC `getnewaddress`. Utilizará una dirección `legacy` (P2PKH) aquí, mientras que se moverá a una dirección SegWit (P2SH-SegWit) o a una dirección Bech32 en [§4.6: Creando una Transacción Segwit](04_6_Creando_una_Transaccion_Segwit.md)
|
||||
|
||||
Como se señaló anteriormente, la base de una dirección de Bitcoin es una clave pública: alguien envía fondos a su clave pública y luego usa su clave privada para canjearla.
|
||||
¿Fácil? Excepto que poner su clave pública allí no es del todo seguro. Por el momento, si alguien tiene su clave pública, entonces no puede recuperar su clave privada (y por lo tanto sus fondos); esa es la base de la criptografía, que utiliza una función de trampilla para garantizar que solo pueda pasar de la clave privada a la pública, y no al revés.
|
||||
Pero el problema es que no sabemos lo que deparará el futuro. Excepto que sabemos que los sistemas de criptografía eventualmente se rompen por el avance incesante de la tecnología, por lo que es mejor no poner claves públicas en crudo en la red, para asegurar sus transacciones en el futuro.
|
||||
|
||||
Las transacciones clásicas de Bitcoin crearon direcciones P2PKH que agregan un paso criptográfico adicional para proteger las claves públicas.
|
||||
|
||||
> :book: ***¿Qué es una dirección heredada (P2PKH)?*** Esta es una direccion de tipo Legacy, del tipo de aquellas usadas en los origenes de la red Bitcoin. Lo usaremos en ejemplos para las próximas secciones. Se llama dirección Pay to PubKey Hash (o P2PKH) porque la dirección es un hash de 160 bits de una clave pública. El uso de un hash de su clave pública como su dirección crea un proceso de dos pasos en el que para gastar los fondos necesita revelar tanto la clave privada como la clave pública, y aumenta la seguridad futura en consecuencia. Este tipo de dirección sigue siendo importante para recibir fondos de personas con software de billetera desactualizado.
|
||||
|
||||
Como se describe con más detalle en [4.6: Creando una Transacción Segwit](04_6_Creando_una_Transaccion_Segwit.md), Las guerras de tamaño de bloque de finales del año 2010 dieron como resultado un nuevo tipo de dirección: SegWit. Este es el tipo de dirección preferido actualmente y debería estar completamente integrado en Bitcoin-Core en este punto, pero no obstante lo estamos guardando para §4.6.
|
||||
|
||||
SegWit simplemente significa "testigo segregado" y es una forma de separar las firmas de transacciones del resto de la transacción para reducir el tamaño de la transacción. Algunas direcciones de SegWit se filtrarán en algunos de nuestros ejemplos antes de §4.6 como direcciones de cambio, que verá como direcciones que comienzan con "tb". Esto está bien porque `bitcoin-cli` es totalmente compatible con su uso. Pero no los usaremos de otra manera.
|
||||
|
||||
Hay dos direcciones de este tipo:
|
||||
|
||||
> :book: ***¿Qué es una dirección P2SH-SegWit?*** (también conocida como SegWit anidado)? Esta es la primera generación de SegWit. Envuelve la dirección de SegWit en un hash de script para garantizar la compatibilidad con versiones anteriores. El resultado crea transacciones que son aproximadamente un 25% más pequeñas (con las correspondientes reducciones en las tarifas de transacción).
|
||||
|
||||
> :book: ***¿Qué es una dirección Bech32?*** (también conocida como Native SegWit, también conocida como P2WPKH)? Esta es la segunda generación de SegWit. Está completamente descrito en [BIP 173](https://en.bitcoin.it/wiki/BIP_0173). Crea transacciones que son incluso más pequeñas, pero más notablemente también tiene algunas ventajas en la creación de direcciones que son menos propensas a errores humanos y tienen alguna corrección de errores implícita más allá de eso. No es compatible con versiones anteriores como lo era P2SH-SegWit, y es posible que algunas personas pueden no ser capaces de enviar a la misma.
|
||||
|
||||
Hay otros tipos de direcciones de Bitcoin, como P2PK (que paga a una clave pública y está en desuso debido a su futura inseguridad) y P2SH (que paga a un Script Hash, y que es utilizada por el SegWit anidado de primera generación direcciones; lo veremos con más detalle en unos pocos capítulos).
|
||||
|
||||
## Opcional: Firme un mensaje
|
||||
|
||||
A veces, deberá demostrar que controla una dirección de Bitcoin (o más bien, que controla su clave privada). Esto es importante porque le permite a las personas saber que están enviando fondos a la persona adecuada. Esto se puede hacer creando una firma con el comando `bitcoin-cli signmessage` en la forma de `bitcoin-cli signmessage [address] [message]`. Por ejemplo:
|
||||
```
|
||||
$ bitcoin-cli signmessage "moKVV6XEhfrBCE3QCYq6ppT7AaMF8KsZ1B" "Hello, World"
|
||||
HyIP0nzdcH12aNbQ2s2rUxLwzG832HxiO1vt8S/jw+W4Ia29lw6hyyaqYOsliYdxne70C6SZ5Utma6QY/trHZBI=
|
||||
```
|
||||
Recibirás la firma como devolución.
|
||||
|
||||
> :book: ***¿Qué es una firma?*** Una firma digital es una combinación de un mensaje y una clave privada que luego se puede desbloquear con una clave pública. Dado que existe una correspondencia uno a uno entre los elementos de un par de claves, el desbloqueo con una clave pública demuestra que el firmante controlaba la clave privada correspondiente.
|
||||
|
||||
Luego, otra persona puede usar el comando `bitcoin-cli verifymessage` para verificar la firma. Ingresa la dirección en cuestión, la firma y el mensaje:
|
||||
```
|
||||
$ bitcoin-cli verifymessage "moKVV6XEhfrBCE3QCYq6ppT7AaMF8KsZ1B" "HyIP0nzdcH12aNbQ2s2rUxLwzG832HxiO1vt8S/jw+W4Ia29lw6hyyaqYOsliYdxne70C6SZ5Utma6QY/trHZBI=" "Hello, World"
|
||||
true
|
||||
```
|
||||
Si todos coinciden, entonces la otra persona sabe que puede transferir fondos de manera segura a la persona que firmó el mensaje enviándolo a la dirección.
|
||||
|
||||
Si algún hacker "sombrero negro" estuviera inventando firmas, esto produciría un resultado negativo:
|
||||
```
|
||||
$ bitcoin-cli verifymessage "FAKEV6XEhfrBCE3QCYq6ppT7AaMF8KsZ1B" "HyIP0nzdcH12aNbQ2s2rUxLwzG832HxiO1vt8S/jw+W4Ia29lw6hyyaqYOsliYdxne70C6SZ5Utma6QY/trHZBI=" "Hello, World"
|
||||
error code: -3
|
||||
error message:
|
||||
Invalid address
|
||||
```
|
||||
|
||||
## Opcional: volcar su billetera
|
||||
|
||||
Puede parecer peligroso tener todas sus claves privadas irremplazables en un solo archivo. Para eso ejecute `bitcoin-cli dumpwallet`. Le permite hacer una copia de su wallet.dat:
|
||||
```
|
||||
$ bitcoin-cli dumpwallet ~/mywallet.txt
|
||||
```
|
||||
El archivo `mywallet.txt` en su directorio personal tendrá una larga lista de claves privadas, direcciones y otra información. Eso sí, ¡nunca querrá poner estos datos en un archivo de texto sin formato en una configuración de Bitcoin con fondos reales!
|
||||
|
||||
Luego puede recuperarlo con `bitcoin-cli importwallet`.
|
||||
```
|
||||
$ bitcoin-cli importwallet ~/mywallet.txt
|
||||
```
|
||||
¡Pero tenga en cuenta que esto requiere un nodo sin podar!
|
||||
```
|
||||
$ bitcoin-cli importwallet ~/mywallet.txt
|
||||
error code: -4
|
||||
error message:
|
||||
Importing wallets is disabled when blocks are pruned
|
||||
```
|
||||
|
||||
## Opcional: vea sus claves privadas
|
||||
|
||||
A veces, es posible que desee ver las claves privadas asociadas con sus direcciones de Bitcoin. Quizás quiera poder firmar un mensaje o gastar bitcoins desde una máquina diferente. Quizás solo desee hacer una copia de seguridad de ciertas claves privadas importantes. También puede hacer esto con su archivo de volcado, ya que es legible por humanos.
|
||||
```
|
||||
$ bitcoin-cli dumpwallet ~/mywallet.txt
|
||||
{
|
||||
"filename": "/home/standup/mywallet.txt"
|
||||
}
|
||||
```
|
||||
Lo más probable es que solo desee ver la clave privada asociada con una dirección específica. Esto se puede hacer con el comando `bitcoin-cli dumpprivkey`.
|
||||
```
|
||||
$ bitcoin-cli dumpprivkey "moKVV6XEhfrBCE3QCYq6ppT7AaMF8KsZ1B"
|
||||
cTv75T4B3NsG92tdSxSfzhuaGrzrmc1rJjLKscoQZXqNRs5tpYhH
|
||||
```
|
||||
Luego, puede guardar esa clave en un lugar seguro, preferiblemente en un lugar que no esté conectado a Internet.
|
||||
|
||||
También puede importar cualquier clave privada, desde un volcado de billetera o un volcado de clave individual, de la siguiente manera:
|
||||
```
|
||||
$ bitcoin-cli importprivkey cW4s4MdW7BkUmqiKgYzSJdmvnzq8QDrf6gszPMC7eLmfcdoRHtHh
|
||||
```
|
||||
Nuevamente, espere que esto requiera un nodo sin podar. Espere que esto tome un tiempo, ya que `bitcoind` debe volver a leer todas las transacciones pasadas, para ver si hay algunas nuevas a las que debería prestar atención.
|
||||
|
||||
> :information_source: **NOTA:** Muchas carteras modernas prefieren [códigos mnemónicos](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki) para generar las semillas necesarias para crear las claves privadas. Esta metodología no se utiliza en `bitcoin-cli`, por lo que no podrá generar listas de palabras útiles para recordar sus claves privadas.
|
||||
|
||||
_Ha estado escribiendo esa dirección Bitcoin que generó muchas veces, mientras estaba firmando mensajes y ahora exportando llaves. Si cree que es una molestia, estamos de acuerdo. También es propenso a errores, un tema que abordaremos en la siguiente sección._
|
||||
|
||||
## Resumen: configuración de su billetera
|
||||
|
||||
Necesita crear una dirección para recibir fondos. Su dirección se almacena en una billetera, de la que puede hacer una copia de seguridad. También puede hacer mucho más con una dirección, como descargar su clave privada o usarla para firmar mensajes. Pero realmente, crear esa dirección es _todo_ lo que necesita hacer para recibir fondos de Bitcoin.
|
||||
|
||||
## ¿Que sigue?
|
||||
|
||||
Aléjese de "Comprendiendo la configuración de Bitcoin" con [Interludio: Usando variables de la linea de comandos](03_3_Interludio_Usando_Variables_Linea_Comando.md)
|
46
es/03_3_Interludio_Usando_Variables_Linea_Comando.md
Normal file
46
es/03_3_Interludio_Usando_Variables_Linea_Comando.md
Normal file
@ -0,0 +1,46 @@
|
||||
# Interludio: Usando variables de la línea de comandos
|
||||
|
||||
La sección anterior demostró una serie de comandos de línea de comandos que se utilizan sin ofuscación ni interferencia.
|
||||
Sin embargo, a menudo esa no es la mejor manera de ejecutar Bitcoin desde la línea de comandos.
|
||||
Debido a que está tratando con variables largas, complejas e ilegibles, es fácil cometer un error si está copiando esas variables (o perder satoshis, si las está escribiendo a mano).
|
||||
Debido a que esas variables pueden significar la diferencia entre recibir y perder dinero real, no querrá cometer errores.
|
||||
Por estas razones, recomendamos encarecidamente utilizar variables de línea de comandos para guardar direcciones, firmas u otras cadenas largas de información siempre que sea razonable hacerlo.
|
||||
|
||||
Si está utilizando `bash`, puede guardar la información en una variable como esta:
|
||||
```
|
||||
$ VARIABLE=$(command)
|
||||
```
|
||||
Esa es una simple sustitución de comando, el equivalente a ``VARIABLE=`command` ``. El comando entre paréntesis se ejecuta y luego se asigna a la VARIABLE.
|
||||
|
||||
Para crear una nueva dirección se vería así:
|
||||
```
|
||||
$ unset NEW_ADDRESS_1
|
||||
$ NEW_ADDRESS_1=$(bitcoin-cli getnewaddress "" legacy)
|
||||
```
|
||||
|
||||
Estos comandos borran la variable NEW_ADDRESS_1, solo para estar seguros, luego la llenan con los resultados del comando `bitcoin-cli getnewaddress`.
|
||||
|
||||
Luego puede usar el comando `echo` de su shell para ver su dirección (nueva):
|
||||
```
|
||||
$ echo $NEW_ADDRESS_1
|
||||
mi25UrzHnvn3bpEfFCNqJhPWJn5b77a5NE
|
||||
```
|
||||
Debido a que tiene su dirección en una variable, ahora puede firmar fácilmente un mensaje para esa dirección, sin preocuparse por escribir mal la dirección. ¡Por supuesto, también guardará esa firma en una variable!
|
||||
|
||||
```
|
||||
$ NEW_SIG_1=$(bitcoin-cli signmessage $NEW_ADDRESS_1 "Hello, World")
|
||||
$ echo $NEW_SIG_1
|
||||
IPYIzgj+Rg4bxDwCyoPiFiNNcxWHYxgVcklhmN8aB2XRRJqV731Xu9XkfZ6oxj+QGCRmTe80X81EpXtmGUpXOM4=
|
||||
```
|
||||
El resto de este tutorial utilizará este estilo de guardar información en variables cuando sea práctico.
|
||||
|
||||
|
||||
> :book: ***¿Cuándo no es práctico utilizar variables de línea de comandos?*** Las variables de la línea de comandos no son prácticas si necesita usar la información en otro lugar que no sea la línea de comandos. Por ejemplo, es posible que guardar su firma no sea realmente útil si solo va a tener que enviársela a otra persona en un correo electrónico. Además, algunos comandos futuros generarán objetos JSON en lugar de información simple, y las variables no se pueden usar para capturar esa información ... al menos no sin un poco más de trabajo
|
||||
|
||||
## Resumen: Usando variables de la línea de comandos
|
||||
|
||||
Las variables de la línea de comandos se pueden usar para contener cadenas largas de Bitcoin, lo que minimiza las posibilidades de errores.
|
||||
|
||||
## ¿Que sigue?
|
||||
|
||||
Continúe "Comprendiendo la configuración de Bitcoin" en [§3.4: Recibiendo una transacción](03_4_Recibiendo_una_Transaccion.md).
|
333
es/03_4_Recibiendo_una_Transaccion.md
Normal file
333
es/03_4_Recibiendo_una_Transaccion.md
Normal file
@ -0,0 +1,333 @@
|
||||
# 3.4: Recibiendo una transaccion
|
||||
|
||||
Ahora está listo para recibir algo de dinero en la nueva dirección que configuró.
|
||||
|
||||
## Consiga algo de dinero
|
||||
|
||||
Para hacer algo más, necesita obtener algo de dinero. En testnet, esto se hace a través de faucets. Dado que el dinero es fingido, simplemente vaya a un grifo, solicite algo de dinero y se lo enviará. Sugerimos usar el faucet en https://testnet-faucet.mempool.co/, https://bitcoinfaucet.uo1.net/ o https://testnet.coinfaucet.eu/en/. Si no están disponibles por alguna razón, busque "bitcoin testnet faucet" y debería encontrar otros.
|
||||
|
||||
Para usar un faucet, generalmente deberá ir a una URL y copiar y pegar su dirección. Tenga en cuenta que este es uno de esos casos en los que, lamentablemente, no podrá utilizar variables de la línea de comandos. Posteriormente, se creará una transacción que le enviará dinero desde el grifo.
|
||||
|
||||
> :book: ***¿Qué es una transacción?*** Una transacción es un intercambio de bitcoins. El propietario de algunos bitcoins usa su clave privada para acceder a esas monedas, luego bloquea la transacción usando la clave pública del destinatario.
|
||||
|
||||
> :link: ** TESTNET vs MAINNET: ** Lamentablemente, no hay grifos en la vida real. Si estuviera jugando en la red principal, debería ir y comprar bitcoins en un intercambio de bitcoins o en un cajero automático, o necesitaría que alguien se los envíe. La vida de Testnet es mucho más fácil.
|
||||
|
||||
## Verifique su dinero
|
||||
|
||||
Una vez que haya solicitado su dinero, debería poder verificarlo con el comando `bitcoin-cli getbalance`:
|
||||
|
||||
```
|
||||
$ bitcoin-cli getbalance
|
||||
0.00000000
|
||||
```
|
||||
|
||||
Pero espere, ¿¡todavía no hay saldo!?
|
||||
|
||||
Bienvenido al mundo de la latencia de Bitcoin. ¡El problema es que su transacción aún no se ha registrado en un bloque!
|
||||
|
||||
> :book: ***¿Qué es un bloque?*** Las transacciones se transmiten a través de la red y los mineros las reúnen en bloques. Estos bloques están asegurados con una prueba matemática de trabajo, que demuestra que se ha gastado potencia de cálculo como parte de la creación del bloque. Es esa prueba de trabajo (multiplicada en muchos bloques, cada uno construido sobre el último) lo que, en última instancia, mantiene a Bitcoin seguro.
|
||||
|
||||
> :book: ***¿Qué es un minero?*** Un minero es un participante de la red Bitcoin que trabaja para crear bloques. Es un trabajo remunerado: cuando un minero crea con éxito un bloque, se le paga una recompensa única más las tarifas por las transacciones en su bloque. La minería es un gran negocio. Los mineros tienden a funcionar con hardware especial, acelerado de manera que es más probable que puedan crear bloques. También tienden a ser parte de grupos de minería, donde todos los mineros acuerdan compartir las recompensas cuando uno de ellos crea un bloque con éxito.
|
||||
|
||||
Afortunadamente, `bitcoin-cli getunconfirmedbalance` aún debería mostrar su saldo actualizado siempre que se haya creado la transacción inicial:
|
||||
|
||||
```
|
||||
$ bitcoin-cli getunconfirmedbalance
|
||||
0.01010000
|
||||
```
|
||||
|
||||
Si todavía muestra un cero, probablemente se esté moviendo a través de este tutorial demasiado rápido. Espere un segundo. Las monedas deben aparecer sin confirmar, luego pasar rápidamente a confirmadas. Tenga en cuenta que una moneda puede pasar de un saldo no confirmado a un saldo confirmado casi de inmediato, así que asegúrese de verificar ambos. Sin embargo, si su `getbalance` y su `getunconfirmedbalance` siguen mostrando cero en diez minutos, entonces probablemente haya algo mal con el grifo y tendrá que elegir otro.
|
||||
|
||||
### Gane confianza en su dinero
|
||||
|
||||
Puede usar `bitcoin-cli getbalance "*"[n]`, donde reemplaza `[n]` con un número entero, para ver si un saldo confirmado esta a 'n' bloques de profundidad.
|
||||
|
||||
> :book: ***¿Qué es la profundidad del bloque?*** Después de que se construye y se confirma un bloque, se construye otro bloque encima y otro ... Debido a que se trata de un proceso estocástico, existe alguna posibilidad de reversión cuando un bloque aún es nuevo. Por lo tanto, un bloque debe estar enterrado a varios bloques de profundidad en una cadena antes de que pueda sentirse totalmente seguro de sus fondos. Cada uno de esos bloques tiende a construirse en un promedio de 10 minutos ... por lo que generalmente toma alrededor de una hora para que una transacción confirmada reciba seis bloques de profundidad, que es la medida de plena confianza en Bitcoin.
|
||||
|
||||
A continuación se muestra que nuestras transacciones se han confirmado una vez, pero no dos veces:
|
||||
|
||||
```
|
||||
$ bitcoin-cli getbalance "*" 1
|
||||
0.01010000
|
||||
$ bitcoin-cli getbalance "*" 2
|
||||
0.00000000
|
||||
```
|
||||
|
||||
Obviamente, cada diez minutos más o menos esta profundidad aumentará.
|
||||
|
||||
Por supuesto, en la red de prueba, nadie está tan preocupado por la confiabilidad de sus fondos. Podrás gastar tu dinero tan pronto como se confirme.
|
||||
|
||||
## Verifique su billetera
|
||||
|
||||
El comando `bitcoin-cli getwalletinfo` le brinda más información sobre el saldo de su billetera:
|
||||
|
||||
```
|
||||
$ bitcoin-cli getwalletinfo
|
||||
{
|
||||
"walletname": "",
|
||||
"walletversion": 169900,
|
||||
"balance": 0.01010000,
|
||||
"unconfirmed_balance": 0.00000000,
|
||||
"immature_balance": 0.00000000,
|
||||
"txcount": 2,
|
||||
"keypoololdest": 1592335137,
|
||||
"keypoolsize": 999,
|
||||
"hdseedid": "fdea8e2630f00d29a9d6ff2af7bf5b358d061078",
|
||||
"keypoolsize_hd_internal": 1000,
|
||||
"paytxfee": 0.00000000,
|
||||
"private_keys_enabled": true,
|
||||
"avoid_reuse": false,
|
||||
"scanning": false
|
||||
}
|
||||
```
|
||||
|
||||
## Descubra su ID de transacción
|
||||
|
||||
Su dinero llegó a su billetera a través de una transacción. Puede descubrir ese transactionid (txid) con el comando `bitcoin-cli listtransactions` :
|
||||
|
||||
```
|
||||
$ bitcoin-cli listtransactions
|
||||
[
|
||||
{
|
||||
"address": "mi25UrzHnvn3bpEfFCNqJhPWJn5b77a5NE",
|
||||
"category": "receive",
|
||||
"amount": 0.01000000,
|
||||
"label": "",
|
||||
"vout": 1,
|
||||
"confirmations": 1,
|
||||
"blockhash": "00000000000001753b24411d0e4726212f6a53aeda481ceff058ffb49e1cd969",
|
||||
"blockheight": 1772396,
|
||||
"blockindex": 73,
|
||||
"blocktime": 1592600085,
|
||||
"txid": "8e2ab10cabe9ec04ed438086a80b1ac72558cc05bb206e48fc9a18b01b9282e9",
|
||||
"walletconflicts": [
|
||||
],
|
||||
"time": 1592599884,
|
||||
"timereceived": 1592599884,
|
||||
"bip125-replaceable": "no"
|
||||
},
|
||||
{
|
||||
"address": "mi25UrzHnvn3bpEfFCNqJhPWJn5b77a5NE",
|
||||
"category": "receive",
|
||||
"amount": 0.00010000,
|
||||
"label": "",
|
||||
"vout": 0,
|
||||
"confirmations": 1,
|
||||
"blockhash": "00000000000001753b24411d0e4726212f6a53aeda481ceff058ffb49e1cd969",
|
||||
"blockheight": 1772396,
|
||||
"blockindex": 72,
|
||||
"blocktime": 1592600085,
|
||||
"txid": "ca4898d8f950df03d6bfaa00578bd0305d041d24788b630d0c4a32debcac9f36",
|
||||
"walletconflicts": [
|
||||
],
|
||||
"time": 1592599938,
|
||||
"timereceived": 1592599938,
|
||||
"bip125-replaceable": "no"
|
||||
}
|
||||
]
|
||||
|
||||
```
|
||||
|
||||
Aquí se muestran dos transacciones (`8e2ab10cabe9ec04ed438086a80b1ac72558cc05bb206e48fc9a18b01b9282e9`) y (`ca4898d8f950df03d6bfaa00578bd0305d041d24788b630d0c4a32debcac9f36`) para una cantidad específica ( `0.01000000` y` 0.00010000`), las cuales fueron recibidas ( `receive`) por la misma dirección en nuestra billetera (`mi25UrzHnvn3bpEfFCNqJhPWJn5b77a5NE`). Eso es una mala higiene de claves, por cierto: debe usar una nueva dirección para cada Bitcoin que reciba. En este caso, nos impacientamos porque el primer grifo no parecía funcionar.
|
||||
|
||||
Puede acceder a información similar con el comando `bitcoin-cli listunspent`, pero solo muestra las transacciones por el dinero que no ha gastado. Estos se denominan UTXO y serán de vital importancia cuando envíe dinero al mundo de Bitcoin:
|
||||
|
||||
```
|
||||
$ bitcoin-cli listunspent
|
||||
[
|
||||
{
|
||||
"txid": "ca4898d8f950df03d6bfaa00578bd0305d041d24788b630d0c4a32debcac9f36",
|
||||
"vout": 0,
|
||||
"address": "mi25UrzHnvn3bpEfFCNqJhPWJn5b77a5NE",
|
||||
"label": "",
|
||||
"scriptPubKey": "76a9141b72503639a13f190bf79acf6d76255d772360b788ac",
|
||||
"amount": 0.00010000,
|
||||
"confirmations": 1,
|
||||
"spendable": true,
|
||||
"solvable": true,
|
||||
"desc": "pkh([d6043800/0'/0'/1']02fd5740996d853ea51a6904cf03257fc11204b0179f344c49739ec5b20b39c9ba)#62rud39c",
|
||||
"safe": true
|
||||
},
|
||||
{
|
||||
"txid": "8e2ab10cabe9ec04ed438086a80b1ac72558cc05bb206e48fc9a18b01b9282e9",
|
||||
"vout": 1,
|
||||
"address": "mi25UrzHnvn3bpEfFCNqJhPWJn5b77a5NE",
|
||||
"label": "",
|
||||
"scriptPubKey": "76a9141b72503639a13f190bf79acf6d76255d772360b788ac",
|
||||
"amount": 0.01000000,
|
||||
"confirmations": 1,
|
||||
"spendable": true,
|
||||
"solvable": true,
|
||||
"desc": "pkh([d6043800/0'/0'/1']02fd5740996d853ea51a6904cf03257fc11204b0179f344c49739ec5b20b39c9ba)#62rud39c",
|
||||
"safe": true
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
Tenga en cuenta que los bitcoins no son solo un lío homogéneo de dinero en efectivo atascado en su bolsillo. Cada transacción individual que recibe o envía se coloca en el libro mayor inmutable de blockchain, en un bloque. Puede ver estas transacciones individuales cuando mira su dinero no gastado. Esto significa que el gasto en bitcoins no es tan anónimo como parece. Aunque las direcciones son bastante privadas, las transacciones se pueden examinar a medida que entran y salen de las direcciones. Esto hace que la privacidad sea vulnerable al análisis estadístico. También introduce cierta no fungibilidad potencial para bitcoins, ya que puede rastrear una serie de transacciones, incluso si no puede rastrear un "bitcoin" específico.
|
||||
|
||||
> :book: ***¿Por qué todas estas cantidades de bitcoins están en fracciones?*** Los bitcoins se producen lentamente, por lo que hay relativamente pocos en circulación. Como resultado, cada bitcoin en la red principal vale bastante (~ $ 9,000 en el momento de escribir este artículo). Esto significa que la gente suele trabajar en fracciones. De hecho, el .0101 en monedas de Testnet valdría alrededor de $ 100 si estuvieran en la red principal. Por esta razón, han aparecido nombres para cantidades más pequeñas de bitcoins, incluidos milibitcoins o mBTC (una milésima parte de un bitcoin), microbitcoins o bits o μBTC (una millonésima parte de un bitcoin) y satoshis (una cien millonésima de un bitcoin).
|
||||
|
||||
## Examine su transacción
|
||||
|
||||
Puede obtener más información sobre una transacción con el comando `bitcoin-cli gettransaction`:
|
||||
|
||||
```
|
||||
$ bitcoin-cli gettransaction "8e2ab10cabe9ec04ed438086a80b1ac72558cc05bb206e48fc9a18b01b9282e9"
|
||||
{
|
||||
"amount": 0.01000000,
|
||||
"confirmations": 1,
|
||||
"blockhash": "00000000000001753b24411d0e4726212f6a53aeda481ceff058ffb49e1cd969",
|
||||
"blockheight": 1772396,
|
||||
"blockindex": 73,
|
||||
"blocktime": 1592600085,
|
||||
"txid": "8e2ab10cabe9ec04ed438086a80b1ac72558cc05bb206e48fc9a18b01b9282e9",
|
||||
"walletconflicts": [
|
||||
],
|
||||
"time": 1592599884,
|
||||
"timereceived": 1592599884,
|
||||
"bip125-replaceable": "no",
|
||||
"details": [
|
||||
{
|
||||
"address": "mi25UrzHnvn3bpEfFCNqJhPWJn5b77a5NE",
|
||||
"category": "receive",
|
||||
"amount": 0.01000000,
|
||||
"label": "",
|
||||
"vout": 1
|
||||
}
|
||||
],
|
||||
"hex": "0200000000010114d04977d1b0137adbf51dd5d79944b9465a2619f3fa7287eb69a779977bf5800100000017160014e85ba02862dbadabd6d204fcc8bb5d54658c7d4ffeffffff02df690f000000000017a9145c3bfb36b03f279967977ca9d1e35185e39917788740420f00000000001976a9141b72503639a13f190bf79acf6d76255d772360b788ac0247304402201e74bdfc330fc2e093a8eabe95b6c5633c8d6767249fa25baf62541a129359c202204d462bd932ee5c15c7f082ad7a6b5a41c68addc473786a0a9a232093fde8e1330121022897dfbf085ecc6ad7e22fc91593414a845659429a7bbb44e2e536258d2cbc0c270b1b00"
|
||||
}
|
||||
```
|
||||
|
||||
El comando `gettransaction` detallará las transacciones que están en su billetera, como esta, que nos fue enviada.
|
||||
|
||||
Tenga en cuenta que `gettransaction` tiene dos argumentos opcionales:
|
||||
|
||||
```
|
||||
$ bitcoin-cli help gettransaction
|
||||
gettransaction "txid" ( include_watchonly verbose )
|
||||
|
||||
Get detailed information about in-wallet transaction <txid>
|
||||
|
||||
Arguments:
|
||||
1. txid (string, required) The transaction id
|
||||
2. include_watchonly (boolean, optional, default=true for watch-only wallets, otherwise false) Whether to include watch-only addresses in balance calculation and details[]
|
||||
3. verbose (boolean, optional, default=false) Whether to include a `decoded` field containing the decoded transaction (equivalent to RPC decoderawtransaction)
|
||||
```
|
||||
|
||||
Al establecer estos dos como verdaderos o falsos, podemos elegir incluir direcciones de solo observación en la salida (lo que no nos importa) o mirar una salida más detallada (lo que hacemos).
|
||||
|
||||
En su lugar, esto es lo que estos datos miran cuando establecemos `include_watchonly` en` false` y `verbose` en` true`.
|
||||
|
||||
```
|
||||
$ bitcoin-cli gettransaction "8e2ab10cabe9ec04ed438086a80b1ac72558cc05bb206e48fc9a18b01b9282e9" false true
|
||||
{
|
||||
"amount": 0.01000000,
|
||||
"confirmations": 3,
|
||||
"blockhash": "00000000000001753b24411d0e4726212f6a53aeda481ceff058ffb49e1cd969",
|
||||
"blockheight": 1772396,
|
||||
"blockindex": 73,
|
||||
"blocktime": 1592600085,
|
||||
"txid": "8e2ab10cabe9ec04ed438086a80b1ac72558cc05bb206e48fc9a18b01b9282e9",
|
||||
"walletconflicts": [
|
||||
],
|
||||
"time": 1592599884,
|
||||
"timereceived": 1592599884,
|
||||
"bip125-replaceable": "no",
|
||||
"details": [
|
||||
{
|
||||
"address": "mi25UrzHnvn3bpEfFCNqJhPWJn5b77a5NE",
|
||||
"category": "receive",
|
||||
"amount": 0.01000000,
|
||||
"label": "",
|
||||
"vout": 1
|
||||
}
|
||||
],
|
||||
"hex": "0200000000010114d04977d1b0137adbf51dd5d79944b9465a2619f3fa7287eb69a779977bf5800100000017160014e85ba02862dbadabd6d204fcc8bb5d54658c7d4ffeffffff02df690f000000000017a9145c3bfb36b03f279967977ca9d1e35185e39917788740420f00000000001976a9141b72503639a13f190bf79acf6d76255d772360b788ac0247304402201e74bdfc330fc2e093a8eabe95b6c5633c8d6767249fa25baf62541a129359c202204d462bd932ee5c15c7f082ad7a6b5a41c68addc473786a0a9a232093fde8e1330121022897dfbf085ecc6ad7e22fc91593414a845659429a7bbb44e2e536258d2cbc0c270b1b00",
|
||||
"decoded": {
|
||||
"txid": "8e2ab10cabe9ec04ed438086a80b1ac72558cc05bb206e48fc9a18b01b9282e9",
|
||||
"hash": "d4ae2b009c43bfe9eba96dcd16e136ceba2842df3d76a67d689fae5975ce49cb",
|
||||
"version": 2,
|
||||
"size": 249,
|
||||
"vsize": 168,
|
||||
"weight": 669,
|
||||
"locktime": 1772327,
|
||||
"vin": [
|
||||
{
|
||||
"txid": "80f57b9779a769eb8772faf319265a46b94499d7d51df5db7a13b0d17749d014",
|
||||
"vout": 1,
|
||||
"scriptSig": {
|
||||
"asm": "0014e85ba02862dbadabd6d204fcc8bb5d54658c7d4f",
|
||||
"hex": "160014e85ba02862dbadabd6d204fcc8bb5d54658c7d4f"
|
||||
},
|
||||
"txinwitness": [
|
||||
"304402201e74bdfc330fc2e093a8eabe95b6c5633c8d6767249fa25baf62541a129359c202204d462bd932ee5c15c7f082ad7a6b5a41c68addc473786a0a9a232093fde8e13301",
|
||||
"022897dfbf085ecc6ad7e22fc91593414a845659429a7bbb44e2e536258d2cbc0c"
|
||||
],
|
||||
"sequence": 4294967294
|
||||
}
|
||||
],
|
||||
"vout": [
|
||||
{
|
||||
"value": 0.01010143,
|
||||
"n": 0,
|
||||
"scriptPubKey": {
|
||||
"asm": "OP_HASH160 5c3bfb36b03f279967977ca9d1e35185e3991778 OP_EQUAL",
|
||||
"hex": "a9145c3bfb36b03f279967977ca9d1e35185e399177887",
|
||||
"reqSigs": 1,
|
||||
"type": "scripthash",
|
||||
"addresses": [
|
||||
"2N1ev1WKevSsdmAvRqZf7JjvDg223tPrVCm"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"value": 0.01000000,
|
||||
"n": 1,
|
||||
"scriptPubKey": {
|
||||
"asm": "OP_DUP OP_HASH160 1b72503639a13f190bf79acf6d76255d772360b7 OP_EQUALVERIFY OP_CHECKSIG",
|
||||
"hex": "76a9141b72503639a13f190bf79acf6d76255d772360b788ac",
|
||||
"reqSigs": 1,
|
||||
"type": "pubkeyhash",
|
||||
"addresses": [
|
||||
"mi25UrzHnvn3bpEfFCNqJhPWJn5b77a5NE"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Ahora puede ver la información completa sobre la transacción, incluidas todas las entradas ("vin") y todas las salidas ("vout). Una de las cosas interesantes a tener en cuenta es que, aunque recibimos .01 BTC en la transacción, otra .01010143 se envió a otra dirección. Probablemente se trataba de una dirección de cambio, un concepto que se explora en la siguiente sección. Es bastante típico que una transacción tenga múltiples entradas y/o múltiples salidas.
|
||||
|
||||
Hay otro comando, `getrawtransaction`, que le permite ver las transacciones que no están en su billetera. Sin embargo, requiere que tenga un nodo sin podar y `txindex=1` en su archivo` bitcoin.conf`. A menos que tenga una necesidad seria de información que no esté en su billetera, probablemente sea mejor usar un explorador de Bitcoin para este tipo de cosas ...
|
||||
|
||||
## Opcional: Usar un explorador de bloques
|
||||
|
||||
Incluso mirar la información detallada de una transacción puede resultar un poco intimidante. El objetivo principal de este tutorial es enseñar cómo lidiar con transacciones sin procesar desde la línea de comandos, pero nos complace hablar sobre otras herramientas cuando sean aplicables. Una de esas herramientas es un explorador de bloques, que puede utilizar para ver las transacciones desde un navegador web en un formato mucho más amigable.
|
||||
|
||||
Actualmente, nuestro explorador de bloques preferido es [https://live.blockcypher.com/](https://live.blockcypher.com/).
|
||||
|
||||
Puede usarlo para buscar transacciones para una dirección:
|
||||
|
||||
[https://live.blockcypher.com/btc-testnet/address/mi25UrzHnvn3bpEfFCNqJhPWJn5b77a5NE/](https://live.blockcypher.com/btc-testnet/address/mi25UrzHnvn3bpEfFCNqJhPWJn5b77a5NE/)
|
||||
|
||||
También puede usarlo para ver transacciones individuales:
|
||||
|
||||
[https://live.blockcypher.com/btc-testnet/tx/8e2ab10cabe9ec04ed438086a80b1ac72558cc05bb206e48fc9a18b01b9282e9/](https://live.blockcypher.com/btc-testnet/tx/8e2ab10cabe9ec04ed438086a80b1ac72558cc05bb206e48fc9a18b01b9282e9/)
|
||||
|
||||
|
||||
Un explorador de bloques generalmente no proporciona más información que una mirada de línea de comandos a una transacción sin procesar; simplemente hace un buen trabajo al resaltar la información importante y armar las piezas del rompecabezas, incluidas las tarifas de transacción detrás de una transacción, otro concepto que cubriremos en secciones futuras.
|
||||
|
||||
## Resumen: Recibiendo una transacción
|
||||
|
||||
Los grifos le darán dinero en la red de prueba. Vienen como transacciones sin procesar, que se pueden examinar con `gettransaction` o un explorador de bloques. Una vez que haya recibido una transacción, podrá verla en su saldo y en su billetera.
|
||||
|
||||
## ¿Que sigue?
|
||||
|
||||
Para profundizar en cómo se describen las direcciones, de modo que se puedan transferir o convertir en partes de una firma múltiple, consulte [3.5: Entendiendo el descriptor](03_5_Entendiendo_El_Descriptor.md).
|
||||
|
||||
Pero si eso es demasiado profundo, continúe con el [Capitulo cuatro: Enviando transacciones Bitcoin](04_0_Enviando_Transacciones_Bitcoin.md).
|
157
es/03_5_Entendiendo_El_Descriptor.md
Normal file
157
es/03_5_Entendiendo_El_Descriptor.md
Normal file
@ -0,0 +1,157 @@
|
||||
# 3.5: Comprensión del descriptor
|
||||
|
||||
> :information_source: **NOTA:** Esta sección se ha agregado recientemente al curso y es un borrador inicial que aún puede estar pendiente de revisión. Lectura con precaución.
|
||||
|
||||
Es posible que haya notado un extraño campo `desc:` en el comando `listunspent` de la sección anterior. Esto es de qué se trata (y cómo se puede usar para transferir direcciones).
|
||||
|
||||
> :advertencia: **ADVERTENCIA DE VERSIÓN:** Esta es una innovación de Bitcoin Core v 0.17.0 que ha continuado expandiéndose a través de Bitcoin Core 0.20.0. La mayoría de los comandos de esta sección son de 0.17.0, pero el `importmulti` actualizado que admite descriptores es de 0.18.0.
|
||||
|
||||
## Conozca sobre transferencia de direcciones
|
||||
|
||||
La mayor parte de este curso supone que está trabajando completamente desde un solo nodo donde administra su propia billetera, enviando y recibiendo pagos con las direcciones creadas por esa billetera. Sin embargo, no es necesariamente así como funciona el ecosistema de Bitcoin más grande. Allí, es más probable que mueva direcciones entre billeteras e incluso configure billeteras para vigilar los fondos controlados por diferentes billeteras.
|
||||
|
||||
Ahí es donde entran los descriptores. Son más útiles si está interactuando con _otro_ software distinto a Bitcoin Core, y realmente necesita apoyarse en este tipo de función de compatibilidad: consulte [§6.1](06_1_Enviando_una_Transaccion_a_una_Direccion_Multifirma.md) para ver un ejemplo del mundo real de cómo tener la capacidad de los descriptores es fundamental.
|
||||
|
||||
El movimiento de direcciones entre carteras se solía centrar en `xpub` y` xprv`, y todavía se admiten.
|
||||
|
||||
> :book: ***¿Qué es xprv?*** Una clave privada extendida. Esta es la combinación de una clave privada y un código de cadena. Es una clave privada de la que se puede derivar una secuencia completa de claves privadas secundarias.
|
||||
|
||||
> :book: ***¿Qué es xpub?*** Una clave pública extendida. Esta es la combinación de una clave pública y un código de cadena. Es una clave pública de la que se puede derivar una secuencia completa de claves públicas secundarias.
|
||||
|
||||
El hecho de que pueda tener una "secuencia completa de claves secundarias ..." revela el hecho de que "xpub" y "xprv" no son claves estándar como hemos estado hablando hasta ahora. En cambio, son claves jerárquicas que se pueden usar para crear familias completas de claves, basadas en la idea de HD Wallets.
|
||||
|
||||
> :libro: ***¿Qué es una billetera HD?*** La mayoría de las billeteras modernas se basan en [BIP32: billeteras deterministas jerárquicas](https://github.com/bitcoin/bips/blob/master/bip-0032. mediawiki). Se trata de un diseño jerárquico en el que se puede utilizar una única semilla para generar una secuencia completa de claves. La billetera completa se puede restaurar a partir de esa semilla, en lugar de requerir la restauración de cada clave privada.
|
||||
|
||||
> :book: ***¿Qué es una ruta de derivación?*** Cuando tiene claves jerárquicas, necesita poder definir claves individuales como descendientes de una semilla. Por ejemplo, `[0]` es la clave 0, `[0/1]` es el primer hijo de la clave 0, `[1/0/1]` es el primer nieto del hijo cero de la primera clave. Algunas claves también contienen un `'` después del número, para mostrar que están endurecidas, lo que las protege de un ataque específico que se puede usar para derivar un `xprv` de un`xpub`. No necesita preocuparse por los detalles, aparte del hecho de que esos `'` s le causarán problemas de formato cuando trabaje desde la línea de comandos.
|
||||
|
||||
`xpubs` y` xprvs` resultaron ser insuficientes cuando los tipos de claves públicas se multiplicaron bajo la [expansión SegWit](04_6_Creando_una_Transaccion_Segwit.md), de ahí la necesidad de los "descriptores de salida".
|
||||
|
||||
> :book: ***¿Qué es un descriptor de salida?*** Una descripción precisa de cómo derivar una dirección de Bitcoin a partir de una combinación de una función y una o más entradas a esa función.
|
||||
|
||||
La introducción de funciones en los descriptores es lo que los hace poderosos, porque se pueden usar para transferir todo tipo de direcciones, desde las direcciones heredadas con las que estamos trabajando ahora hasta las direcciones Segwit y multifirma que encontraremos más adelante. Una función individual coincide con un tipo particular de dirección y se correlaciona con reglas específicas para generar esa dirección.
|
||||
|
||||
## Capture un descriptor
|
||||
|
||||
Los descriptores son visibles en varios comandos como `listunspent` y`getaddressinfo`:
|
||||
|
||||
```
|
||||
$ bitcoin-cli getaddressinfo ms7ruzvL4atCu77n47dStMb3of6iScS8kZ
|
||||
{
|
||||
"address": "ms7ruzvL4atCu77n47dStMb3of6iScS8kZ",
|
||||
"scriptPubKey": "76a9147f437379bcc66c40745edc1891ea6b3830e1975d88ac",
|
||||
"ismine": true,
|
||||
"solvable": true,
|
||||
"desc": "pkh([d6043800/0'/0'/18']03efdee34c0009fd175f3b20b5e5a5517fd5d16746f2e635b44617adafeaebc388)#4ahsl9pk",
|
||||
"iswatchonly": false,
|
||||
"isscript": false,
|
||||
"iswitness": false,
|
||||
"pubkey": "03efdee34c0009fd175f3b20b5e5a5517fd5d16746f2e635b44617adafeaebc388",
|
||||
"iscompressed": true,
|
||||
"ischange": false,
|
||||
"timestamp": 1592335136,
|
||||
"hdkeypath": "m/0'/0'/18'",
|
||||
"hdseedid": "fdea8e2630f00d29a9d6ff2af7bf5b358d061078",
|
||||
"hdmasterfingerprint": "d6043800",
|
||||
"labels": [
|
||||
""
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Aquí el descriptor es `pkh ([d6043800 / 0 '/ 0' / 18 '] 03efdee34c0009fd175f3b20b5e5a5517fd5d16746f2e635b44617adafeaebc388) # 4ahsl9pk`.
|
||||
|
||||
## Entienda un descriptor
|
||||
|
||||
Un descriptor se divide en varias partes:
|
||||
|
||||
```
|
||||
function([derivation-path]key)#checksum
|
||||
```
|
||||
|
||||
Esto es lo que todo eso significa:
|
||||
* **Función.** La función que se utiliza para crear una dirección a partir de esa tecla. En estos casos, es `pkh`, que es la dirección heredada P2PKH estándar que conoció en [§3.3: Configuración de su billetera](03_3_Configurando_Su_Billetera.md). De manera similar, una dirección P2WSH SegWit usaría `wsh` y una dirección P2WPKH usaría` wpkh`.
|
||||
* **Ruta de derivación.** Esto describe qué parte de una billetera HD se está exportando. En este caso, es una semilla con la huella digital `d6043800` y luego el hijo 18 del hijo 0 del hijo 0 (` 0'/ 0'/18'`) de esa semilla. También puede haber una derivación adicional después de la clave: `función ([ruta de derivación] clave / más-derivación) # suma de comprobación`
|
||||
* Vale la pena señalar aquí que si alguna vez obtiene una ruta de derivación sin una huella digital, puede inventarla. Es solo que si hay uno existente, debe coincidir, porque si alguna vez regresa al dispositivo que creó la huella digital, deberá tener el mismo.
|
||||
* **Clave**. La clave o claves que se están transfiriendo. Esto podría ser algo tradicional como un `xpub` o` xprv`, podría ser simplemente una clave pública para una dirección, como en este caso, podría ser un conjunto de direcciones para una firma múltiple, o podría ser otra cosa. Estos son los datos centrales: la función explica qué hacer con ellos.
|
||||
* **Suma de comprobación**. Los descriptores están destinados a ser transferibles por humanos. Esta suma de comprobación asegura que lo haga bien.
|
||||
|
||||
Consulte [Información de Bitcoin Core sobre la compatibilidad con descriptores](https://github.com/bitcoin/bitcoin/blob/master/doc/descriptors.md) para obtener más información.
|
||||
|
||||
## Examine un Descriptor
|
||||
|
||||
Usted puede examinar el descriptor con el comando RPC `getdescriptorinfo`:
|
||||
```
|
||||
$ bitcoin-cli getdescriptorinfo "pkh([d6043800/0'/0'/18']03efdee34c0009fd175f3b20b5e5a5517fd5d16746f2e635b44617adafeaebc388)#4ahsl9pk"
|
||||
{
|
||||
"descriptor": "pkh([d6043800/0'/0'/18']03efdee34c0009fd175f3b20b5e5a5517fd5d16746f2e635b44617adafeaebc388)#4ahsl9pk",
|
||||
"checksum": "4ahsl9pk",
|
||||
"isrange": false,
|
||||
"issolvable": true,
|
||||
"hasprivatekeys": false
|
||||
}
|
||||
```
|
||||
Tenga en cuenta que devuelve una suma de comprobación. Si alguna vez le dan un descriptor sin una suma de verificación, puede aprenderlo con este comando:
|
||||
```
|
||||
$ bitcoin-cli getdescriptorinfo "pkh([d6043800/0'/0'/18']03efdee34c0009fd175f3b20b5e5a5517fd5d16746f2e635b44617adafeaebc388)"
|
||||
{
|
||||
"descriptor": "pkh([d6043800/0'/0'/18']03efdee34c0009fd175f3b20b5e5a5517fd5d16746f2e635b44617adafeaebc388)#4ahsl9pk",
|
||||
"checksum": "4ahsl9pk",
|
||||
"isrange": false,
|
||||
"issolvable": true,
|
||||
"hasprivatekeys": false
|
||||
}
|
||||
```
|
||||
|
||||
Además de darle la suma de verificación, este comando también verifica la validez del descriptor y proporciona información útil como comprobar si un descriptor contiene claves privadas.
|
||||
|
||||
Uno de los poderes de un descriptor es poder derivar una dirección de forma regular. Esto se hace con el RPC `deriveaddresses`.
|
||||
|
||||
```
|
||||
$ bitcoin-cli deriveaddresses "pkh([d6043800/0'/0'/18']03efdee34c0009fd175f3b20b5e5a5517fd5d16746f2e635b44617adafeaebc388)#4ahsl9pk"
|
||||
[
|
||||
"ms7ruzvL4atCu77n47dStMb3of6iScS8kZ"
|
||||
]
|
||||
```
|
||||
|
||||
Notará que regresa a la dirección con la que comenzamos (como debería).
|
||||
|
||||
## Importar un descriptor
|
||||
|
||||
Pero lo realmente importante de un descriptor es que puede llevarlo a otra máquina (remota) e importarlo. Esto se hace con el RPC `importmulti` usando la opción`desc`:
|
||||
|
||||
```
|
||||
remote$ bitcoin-cli importmulti '[{"desc": "pkh([d6043800/0'"'"'/0'"'"'/18'"'"']03efdee34c0009fd175f3b20b5e5a5517fd5d16746f2e635b44617adafeaebc388)#4ahsl9pk", "timestamp": "now", "watchonly": true}]'
|
||||
[
|
||||
{
|
||||
"success": true
|
||||
}
|
||||
]
|
||||
```
|
||||
Primero, notará nuestro primer uso realmente desagradable de las comillas. Cada `'` en la ruta de derivación tuvo que ser reemplazado por `'"'"'`. Solo espere tener que hacer eso si está manipulando un descriptor que contiene una ruta de derivación. (La otra opción es intercambiar el `'` con una `h` por el endurecido, pero eso cambiará su suma de verificación, por lo que si lo prefiere por su facilidad de uso, deberá obtener una nueva suma de verificación con `getdescriptorinfo` .)
|
||||
|
||||
En segundo lugar, observará que marcamos esto como `solo vigilancia` o `watchonly`. Eso es porque sabemos que es una clave pública, por lo que no podemos gastar con ella. Si no hubiésemos ingresado esta indicador, `importmulti` nos habría ayudado a decirnos algo como: `Faltan algunas claves privadas, las salidas se considerarán solo de observación. Si es intencional, especifique la bandera de solo vigilancia`.
|
||||
|
||||
> :book: ***¿Qué es una dirección de solo observación?*** Una dirección de solo observación le permite ver las transacciones relacionadas con una dirección (o con toda una familia de direcciones si usó un `xpub`), pero no gastar fondos en esas direcciones.
|
||||
|
||||
Usando `getaddressesbylabel`, ¡ahora podemos ver que nuestra dirección ha sido importada correctamente a nuestra máquina remota!
|
||||
|
||||
```
|
||||
remote$ bitcoin-cli getaddressesbylabel ""
|
||||
{
|
||||
"ms7ruzvL4atCu77n47dStMb3of6iScS8kZ": {
|
||||
"purpose": "receive"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Resumen: comprendiendo del descriptor
|
||||
|
||||
Los descriptores le permiten pasar claves públicas y claves privadas entre billeteras, pero más que eso, le permiten definir direcciones de manera precisa y correcta y derivar direcciones de muchos tipos diferentes a partir de un formato de descripción estandarizado.
|
||||
|
||||
> :fire: ***¿Cuál es el poder de los descriptores?*** Los descriptores le permiten importar y exportar semillas y claves. Eso es genial si quiere moverse entre diferentes carteras. Como desarrollador, también le permiten crear el tipo preciso de direcciones que le interesa crear. Por ejemplo, lo usamos en [FullyNoded 2](https://github.com/BlockchainCommons/FullyNoded-2/blob/master/Docs/How-it-works.md) para generar un multifirma a partir de tres semillas.
|
||||
|
||||
Haremos un uso real de los descriptores en [§7.3](07_3_Integrando_con_Hardware_Wallets.md), cuando estemos importando direcciones desde una billetera de hardware.
|
||||
|
||||
## ¿Que sigue?
|
||||
|
||||
Avance a través de "bitcoin-cli" con el [Capítulo cuatro: Enviando Transacciones Bitcoin](04_0_Enviando_Transacciones_Bitcoin.md).
|
31
es/04_0_Enviando_Transacciones_Bitcoin.md
Normal file
31
es/04_0_Enviando_Transacciones_Bitcoin.md
Normal file
@ -0,0 +1,31 @@
|
||||
# Capítulo Cuatro: Enviando Transacciones en Bitcoin
|
||||
|
||||
Este capítulo describe tres metodos diferentes para enviar bitcoins a direcciones tipicas P2PKH desde la línea de comandos, usando unicamente la interfaz de bitcoin-cli.
|
||||
|
||||
## Objetivos de este Capítulo
|
||||
|
||||
Después de trabajar en este capítulo, un desarrollador podrá:
|
||||
|
||||
* Decidir cómo enviar dinero a través de Bitcoin
|
||||
* Crear una transacción en crudo
|
||||
* Utilizar la aritmética para calcular las tarifas
|
||||
|
||||
Con los objetivos complementarios se tendrá la habilidad de:
|
||||
|
||||
* Entender las transacciones y sus comisiones
|
||||
* Entender las transacciones de tipo Legacy & SegWit
|
||||
* Usar métodos básicos para enviar dinero
|
||||
* Usar métodos automaticos para calcular comisiones para enviar dinero
|
||||
* Entender el peligro de las transacciones sin procesar
|
||||
|
||||
## Tabla de contenido
|
||||
|
||||
* [Sección Uno: Enviando Monedas de la Forma Fácil](04_1_Enviando_Monedas_de_la_Forma_Facil.md)
|
||||
* [Sección Dos: Creando una Transacción Cruda](04_2_Creando_una_Transaccion_Cruda.md)
|
||||
* [Interludio: Usando JQ](04_2_Interludio_Usando_JQ.md)
|
||||
* [Sección Tres: Creando una Transacción Cruda con Argumentos Ingresados con Nombre](04_3_Creando_una_Transaccion_Cruda_con_Argumentos_Ingresados_con_Nombre.md)
|
||||
* [Sección Cuatro: Enviando Monedas con una Transacción Cruda](04_4_Enviando_Monedas_con_una_Transaccion_Cruda.md)
|
||||
* [Interludio: Usando Curl](04_4_Interludio_Usando_Curl.md)
|
||||
* [Sección Cinco: Enviando Monedas con Transacciones Crudas Automatizadas](04_5_Enviando_Monedas_con_Transacciones_Crudas_Automatizadas.md)
|
||||
* [Sección Seis: Creando una Transacción Segwit](04_6_Creando_una_Transaccion_Segwit.md)
|
||||
|
106
es/04_1_Enviando_Monedas_de_la_Forma_Facil.md
Normal file
106
es/04_1_Enviando_Monedas_de_la_Forma_Facil.md
Normal file
@ -0,0 +1,106 @@
|
||||
# 4.1: Enviando Monedas de Forma Facil
|
||||
|
||||
El comando `bitcoin-cli` ofrece tres formas principales de enviar monedas: como un simple comando; como una transacción en crudo; y como una transacción en crudo con cálculo. Cada una tiene sus propias ventajas y desventajas. El primer método para enviar monedas es también el más sencillo.
|
||||
|
||||
## Indicar la Comisión de la Transacción
|
||||
|
||||
Antes de enviar dinero en la red Bitcoin, debe pensar en las comisiones por transacción que va a pagar.
|
||||
|
||||
> 📖 ***¿Qué es una comisión por transacción?*** No existe el almuerzo gratis. Los mineros incorporan las transacciones a los bloques porque se les paga para ello. No sólo obtienen el pago de la red por crear el bloque, sino que también les pagan los usuarios por incluir sus transacciones en el. Si no paga una comisión, su transacción puede quedarse atascada... para siempre (o, hasta que se haga con alguno de los trucos del [Capítulo Cinco](05_0_Controlando_Transacciones_Bitcoin.md)).
|
||||
|
||||
Cuando se utilizan los métodos simples y automatizados para crear transacciones, como se indica aquí y en [§4.5: Enviando Monedas con Transacciones Automatizadas en Crudo](04_5_Enviando_Monedas_con_Transacciones_Crudas_Automatizadas.md), Bitcoin calculará las tasas de transacción por usted. Esto se hace utilizando tasas flotantes, donde `bitcoind` observa el tiempo que tardan las transacciones en confirmarse y calcula automáticamente lo que se debe gastar.
|
||||
|
||||
Puede controlar esto colocando valores racionales en su fichero `~/.bitcoin/bitcoin.conf`. Los siguientes valores de bajos costes se asegurarían que haya una tasa mínima de 10,000 satoshis de comisión por kByte de data en su trasacción y solicitarían que las tasas flotantes se calcularan con una cantidad atractiva para que la transacción sea procesada en los siguientes seis bloques.
|
||||
```
|
||||
mintxfee=0.0001
|
||||
txconfirmtarget=6
|
||||
```
|
||||
Sin embargo, bajo la teoría de que usted no va esperar mientras trabaja con este tutorial, hemos adoptado los siguientes valores más altos.
|
||||
```
|
||||
mintxfee=0.001
|
||||
txconfirmtarget=1
|
||||
```
|
||||
Deberá introducir esto en `~/.bitcoin/bitcoin.conf`, en la sección principal, en la parte superior del archivo o si quiere estar seguro de que nunca se usará en otra parte, bajo la sección `[test]`.
|
||||
|
||||
Para llevar a cabo este tutorial, estamos dispuestos a gastar 100,000 satoshis por kB en cada transacción (Unos $10 dólares) ¡Queremos que cada transacción llegue en el siguiente bloque! (Para ponerlo en perspectiva, una transacción típica se ocupa entre 0.25 kB y 1 kB, así que en realidad estará pagando $2.50 dólares en vez $10 dólares... si esto fuera dinero real).
|
||||
|
||||
Despues de que haya editado su archivo bitcoin.conf, deberá reiniciar forzosamente el servicio de bitcoind.
|
||||
```
|
||||
$ bitcoin-cli stop
|
||||
$ bitcoind -daemon
|
||||
```
|
||||
|
||||
## Obtener una dirección
|
||||
|
||||
Necesita un lugar al que enviar sus monedas. Normalmente, alguien le enviará una dirección y quizás le dé una firma para demostrar que es el propietario de esa dirección. También puede darle un código QR para que lo escanee y no se equivoque al escribir la dirección. En nuestro caso, vamos a enviar monedas a `n2eMqTT929pb1RDNuqEnxdaLau1rxy3efi`, que es una dirección de retorno de un antiguo grifo de Testnet.
|
||||
|
||||
> 📖 ***¿Qué es un código QR?*** Un código QR es sólo una codificación de una dirección Bitcoin. Muchas billeteras generarán códigos QR para usted, mientras que algunos sitios convertirán de una dirección a un código QR. Obviamente, sólo debe aceptar un código QR de un sitio en el que confíe absolutamente. Un pagador puede utilizar un escáner de código de barras para leer el código QR y luego pagar con él.
|
||||
|
||||
## Enviar las monedas
|
||||
|
||||
Ahora está listo para enviar algunas monedas. Esto es bastante sencillo a través de la línea de comandos. Sólo tiene que utilizar `bitcoin-cli sendtoaddress [address] [amount]`. Así, para enviar un pocas monedas a la dirección `n2eMqTT929pb1RDNuqEnxdaLau1rxy3efi` sólo se requiere:
|
||||
```
|
||||
$ txid=$(bitcoin-cli sendtoaddress n2eMqTT929pb1RDNuqEnxdaLau1rxy3efi 0.001)
|
||||
$ echo $txid
|
||||
93250d0cacb0361b8e21030ac65bc4c2159a53de1075425d800b2d7a8ab13ba8
|
||||
```
|
||||
|
||||
> 🙏 Para ayudar a mantener vivos los grifos de testnet, intente utilizar la dirección de retorno del mismo grifo que utilizó en el capítulo anterior sobre la recepción de transacciones.
|
||||
|
||||
Asegurese de que la dirección que escribe es a donde quiere que vaya el dinero. Asegúrese _Doble_. Si se equivoca en Bitcoin, no hay vuelta atrás.
|
||||
|
||||
Recibirá un txid de vuelta cuando utilice este comando.
|
||||
|
||||
> ❕ Puede obtener un código de error si no tiene los suficientes fondos en su cartera para enviar la transacción. Dependiendo de su saldo actual `bitcoin-cli getbalance` es posible que tenga que ajustar el importe a enviar para tener en cuenta la cantidad que se envía junto a la comisión de la transacción. Si su saldo actual es de 0.001, entonces podría intentar enviar 0.0001. De mejor forma sería restar de su saldo actual la comisión prevista que aparece en el mensaje de error. Esta es una buena práctica, ya que muchos monederos esperan que calcule el monto + las comisiones a retirar, incluso entre las casas de cambio populares.
|
||||
|
||||
> ⚠️ **ADVERTENCIA:** El comando `bitcoin-cli` en realidad genera comandos JSON-RPC cuando se está comunicando con bitcoind. Pueden ser muy quisquillosos. Este es un ejemplo: si enumera la cantidad de bitcoin sin el cero inicial (es decir, ".1" en lugar de "0.1"), entonces bitcoin-cli fallará con un mensaje misterioso.
|
||||
|
||||
> ⚠️ **ADVERTENCIA:** Incluso si tiene cuidado con las entradas, podría ver "La estimación de la comisión falló. Fallbackfee está deshabilitado". Fundamentalmente, esto significa que su archivo `bitcoind` local no tiene suficiente información para estimar las comisiones. Realmente no debería ver este mensaje si ha esperado a que la blockchain se sincronice y se configure el sistema con Bitcoin Standup. Pero si no está completamente sincronizado, es posible que vea esto. También puede ser que no esté usando un `bitcoin.conf` estándar: la entrada `blocksonly=1` hará que su `bitcoind` no pueda estimar las comisiones.
|
||||
|
||||
## Examinando la Transacción
|
||||
|
||||
Puede ver la transacción utilizando el id de la transacción:
|
||||
```
|
||||
{
|
||||
"amount": -0.00100000,
|
||||
"fee": -0.00022200,
|
||||
"confirmations": 0,
|
||||
"trusted": true,
|
||||
"txid": "93250d0cacb0361b8e21030ac65bc4c2159a53de1075425d800b2d7a8ab13ba8",
|
||||
"walletconflicts": [
|
||||
],
|
||||
"time": 1592604194,
|
||||
"timereceived": 1592604194,
|
||||
"bip125-replaceable": "no",
|
||||
"details": [
|
||||
{
|
||||
"address": "n2eMqTT929pb1RDNuqEnxdaLau1rxy3efi",
|
||||
"category": "send",
|
||||
"amount": -0.00100000,
|
||||
"vout": 1,
|
||||
"fee": -0.00022200,
|
||||
"abandoned": false
|
||||
}
|
||||
],
|
||||
"hex": "0200000001e982921bb0189afc486e20bb05cc5825c71a0ba8868043ed04ece9ab0cb12a8e010000006a47304402200fc493a01c5c9d9574f7c321cee6880f7f1df847be71039e2d996f7f75c17b3d02203057f5baa48745ba7ab5f1d4eed11585bd8beab838b1ca03a4138516fe52b3b8012102fd5740996d853ea51a6904cf03257fc11204b0179f344c49739ec5b20b39c9bafeffffff02e8640d0000000000160014d37b6ae4a917bcc873f6395741155f565e2dc7c4a0860100000000001976a914e7c1345fc8f87c68170b3aa798a956c2fe6a9eff88ac780b1b00"
|
||||
}
|
||||
```
|
||||
Se puede ver no sólo la cantidad transferida (.001 BTC) sino también la comisión de la transacción (.000222 BTC), que es aproximadamente una cuarta parte de la comisión mínima de 0.001 BTC/kB que se estableció, lo que sugiere que la transacción tenía un tamaño de aproximadamente un cuarto de kB.
|
||||
|
||||
Mientras espera a que esta transacción se complete, notará que bitcoin-cli getbalance muestra que todo su dinero ha desaparecido (o, al menos, todo su dinero de una única transacción entrante). Del mismo modo, bitcoin-cli listunspent mostrará que toda la transacción ha desaparecido, incluso si era más de lo que quería enviar. Hay una razón para esto: cada vez que ingresa dinero, tendra que enviarlo todo junto, y si quiere conservar algo, tendra que hacer algunos malabares. Una vez más, sendtoaddress se encarga de todo esto por usted, lo que significa que no tiene que preocuparse de hacer el cambio hasta que envíe una transacción en crudo. En este caso, aparecerá una nueva transacción con el cambio cuando el gasto se incorpore a un bloque.
|
||||
|
||||
|
||||
|
||||
## Resumen: Enviando Monedas de Forma Sencilla
|
||||
|
||||
Para enviar monedas de forma fácil, asegúrese de que los valores predeterminados de la transacción son racionales, consiga una dirección y envíe monedas allí. ¡Por eso lo llaman fácil!
|
||||
|
||||
> 🔥 ***¿Cuál es el poder de enviar monedas de manera fácil?***
|
||||
|
||||
> _Las ventajas._ Es facil. No tiene que preocuparse de cosas arcaicas como los UTXOs. No tiene que calcular las comisiones a mano, por lo que no es probable que cometa errores que le cuesten grandes cantidades de dinero. Si su único objetivo es sentarse frente a su ordenador y enviar dinero, este es el camino a seguir.
|
||||
|
||||
> _Las desventajas._ Es de alto nivel. Usted tiene muy poco dominio sobre lo que ocurre, y no puede hacer nada del otro mundo. Si está planeando escribir software de Bitcoin más complejo o quiere una comprensión más profunda de cómo funciona Bitcoin, entonces la forma fácil es sólo una diversión aburrida antes de llegar a lo real.
|
||||
|
||||
## ¿Qué sigue?
|
||||
|
||||
Continúe "Enviando transacciones en Bitcoin" con [§4.2 Creando una Transacción en Crudo](04_2_Creando_una_Transaccion_Cruda.md).
|
275
es/04_2_Creando_una_Transaccion_Cruda.md
Normal file
275
es/04_2_Creando_una_Transaccion_Cruda.md
Normal file
@ -0,0 +1,275 @@
|
||||
# 4.2 Creación de una transacción en Crudo
|
||||
|
||||
Creación de una transacción sin procesar
|
||||
Ahora está listo para crear transacciones en crudo de Bitcoin. Esto le permite enviar dinero, pero elaborar las transacciones con la precisión que desee. Esta primera sección se centra en una simple transacción de una entrada y una salida. Este tipo de transacción _no_ es en realidad tan útil, porque rara vez va a querer enviar todo su dinero a una persona (a menos que lo esté reenviando, como por ejemplo si está moviendo cosas de un monedero a otro). Por lo tanto, no etiquetamos esta sección como una forma de enviar dinero. Es sólo un paso fundamental para _realmente_ enviar dinero con una transacción en bruto.
|
||||
|
||||
## Entender una transacción en Bitcoin
|
||||
|
||||
Antes de sumergirse en la creación de transacciones en crudo, debería asegurarse de que entiende cómo funciona una transacción en Bitcoin. Se trata de los UTXOs.
|
||||
|
||||
> :book: ***¿Qué es un UTXO?*** Cuando recibe dinero en efectivo en su monedero Bitcoin, aparece como una transacción individual. Cada una de estas transacciones se denomina Unspent Transaction Output (UTXO), o salida de transacción no gastada. No importa si se hicieron varios pagos a la misma dirección o a múltiples direcciones: cada transacción entrante permanece distinta en su monedero como un UTXO.
|
||||
|
||||
Cuando crea una nueva transacción saliente, reúne uno o más UTXOs, cada uno de los cuales representa una porción de dinero que ha recibido. Los utiliza como entradas para una nueva transacción. Su importe conjunto debe ser igual a lo que quieres gastar _o más_. Luego, genera una o más salidas, que dan el dinero representado por las entradas a una o más personas. Esto crea nuevos UTXOs para los receptores, que luego pueden usar _esos_ para financiar futuras transacciones.
|
||||
|
||||
Este es el truco: ¡Todos de los UTXOs que reúna se gastan en su totalidad! Esto significa que, si quiere enviar sólo una parte del dinero de un UTXO a otra persona, ¡También tiene que generar una salida adicional que te devuelva el resto! Por ahora, no nos preocuparemos por eso, pero el uso de una dirección de cambio será vital cuando pasemos de la teoría de este capítulo a transacciones más prácticas.
|
||||
|
||||
## Listar transacciones no gastadas
|
||||
|
||||
Para crear una nueva transacción en crudo, debe saber qué UTXOs tiene a mano para gastar. Puede determinar esta información con el comando `bitcoin-cli listunspent`:
|
||||
```
|
||||
$ bitcoin-cli listunspent
|
||||
[
|
||||
{
|
||||
"txid": "ca4898d8f950df03d6bfaa00578bd0305d041d24788b630d0c4a32debcac9f36",
|
||||
"vout": 0,
|
||||
"address": "mi25UrzHnvn3bpEfFCNqJhPWJn5b77a5NE",
|
||||
"label": "",
|
||||
"scriptPubKey": "76a9141b72503639a13f190bf79acf6d76255d772360b788ac",
|
||||
"amount": 0.00010000,
|
||||
"confirmations": 20,
|
||||
"spendable": true,
|
||||
"solvable": true,
|
||||
"desc": "pkh([d6043800/0'/0'/1']02fd5740996d853ea51a6904cf03257fc11204b0179f344c49739ec5b20b39c9ba)#62rud39c",
|
||||
"safe": true
|
||||
},
|
||||
{
|
||||
"txid": "61f3b7016bf1ecc3987b8805207e79362e4de8026682e149107999b779426e3a",
|
||||
"vout": 1,
|
||||
"address": "mjehC2KHzXcBDcwTd4LhZ2GzyzrZ3Kd3ff",
|
||||
"label": "",
|
||||
"scriptPubKey": "76a9142d573900aa357a38afd741fbf24b075d263ea6e088ac",
|
||||
"amount": 0.00050000,
|
||||
"confirmations": 3,
|
||||
"spendable": true,
|
||||
"solvable": true,
|
||||
"desc": "pkh([d6043800/0'/0'/3']0278608b54b8fb0d8379d3823d31f03a7c6ab0adffb07dd3811819fdfc34f8c132)#nhjc3f8y",
|
||||
"safe": true
|
||||
},
|
||||
{
|
||||
"txid": "91261eafae15ea53dedbea7c1db748c52bbc04a85859ffd0d839bda1421fda4c",
|
||||
"vout": 0,
|
||||
"address": "mjehC2KHzXcBDcwTd4LhZ2GzyzrZ3Kd3ff",
|
||||
"label": "",
|
||||
"scriptPubKey": "76a9142d573900aa357a38afd741fbf24b075d263ea6e088ac",
|
||||
"amount": 0.00022000,
|
||||
"confirmations": 3,
|
||||
"spendable": true,
|
||||
"solvable": true,
|
||||
"desc": "pkh([d6043800/0'/0'/3']0278608b54b8fb0d8379d3823d31f03a7c6ab0adffb07dd3811819fdfc34f8c132)#nhjc3f8y",
|
||||
"safe": true
|
||||
}
|
||||
]
|
||||
|
||||
```
|
||||
Este listado muestra tres UTXOs diferentes, con un valor de .0001, .0005 y .00022 BTC. Nótese que cada uno tiene su propio txid distinto y permanece distinto en el monedero, incluso los dos últimos, que fueron enviados a la misma dirección.
|
||||
|
||||
Cuando quiera gastar un UTXO, no es suficiente con saber el id de la transacción. ¡Eso es porque cada transacción puede tener múltiples salidas! ¿Recuerda el primer trozo de dinero que nos envió el grifo? En la transacción, una parte del dinero fue para nosotros y otra para otra persona. El `txid` se refiere a la transacción global, mientras que el `vout` dice cuál de las múltiples salidas ha recibido. En esta lista, cada una de estas transacciones es la 0ª `salida` de una transacción anterior, pero _no tiene por qué ser así_.
|
||||
|
||||
Así, txid+vout=UTXO. Esta será la base de cualquier transacción en crudo.
|
||||
|
||||
## Escribir una transacción en crudo con una salida
|
||||
|
||||
Ahora está listo para escribir una simple transacción cruda de ejemplo que muestra cómo enviar la totalidad de un UTXO a otra parte. Como se ha señalado, este no es necesariamente un caso muy frecuente en el mundo real.
|
||||
|
||||
> :warning: **ADVERTENCIA:** Es muy fácil perder dinero con una transacción en crudo. Considera que todas las instrucciones sobre el envío de bitcoins a través de transacciones en bruto son _muy_, _muy_ peligrosas. Siempre que vaya a enviar dinero real a otras personas, deberá utilizar uno de los otros métodos explicados en este capítulo. Crear transacciones en crudo es extremadamente útil si estás escribiendo programas de bitcoin, pero _sólo_ cuando estás escribiendo programas de bitcoin. (Por ejemplo: al escribir este ejemplo para una versión de este tutorial, accidentalmente gastamos la transacción equivocada, aunque tenía cerca de 10 veces más valor. Casi todo eso se perdió en los mineros).
|
||||
|
||||
### Preparar la transacción en crudo
|
||||
|
||||
Para las mejores prácticas, comenzaremos cada transacción registrando cuidadosamente los txids y vouts que vamos a gastar.
|
||||
|
||||
En este caso, vamos a gastar el que vale .00050000 BTC porque es el único con un valor decente.
|
||||
```
|
||||
$ utxo_txid="61f3b7016bf1ecc3987b8805207e79362e4de8026682e149107999b779426e3a"
|
||||
$ utxo_vout="1"
|
||||
```
|
||||
|
||||
De la misma manera, deberá anotar la dirección del destinatario, para asegurarse de tenerla bien. Volvemos a enviar algo de dinero al grifo de TP:
|
||||
```
|
||||
$ recipient="n2eMqTT929pb1RDNuqEnxdaLau1rxy3efi"
|
||||
```
|
||||
Como siempre, comprueba sus variables con cuidado, para asegurarse de que son las que espera.
|
||||
```
|
||||
$ echo $utxo_txid
|
||||
61f3b7016bf1ecc3987b8805207e79362e4de8026682e149107999b779426e3a
|
||||
$ echo $utxo_vout
|
||||
1
|
||||
$ echo $recipient
|
||||
n2eMqTT929pb1RDNuqEnxdaLau1rxy3efi
|
||||
```
|
||||
Este destinatario es especialmente importante, porque si se equivoca, ¡Su dinero está _perdido_! (Y, como ya hemos visto, elegir la transacción equivocada puede suponer la pérdida de dinero). Así que compruébelo todo tres veces.
|
||||
|
||||
### Comprender la comisión por transacción
|
||||
|
||||
Cada transacción tiene una tasa asociada. Es _implícito_ cuando envía una transacción en crudo: la cantidad que pagará como tarifa es siempre igual a la cantidad de su entrada menos la cantidad de su salida. Por lo tanto, tiene que disminuir su salida un poco de su entrada para asegurarse de que su transacción salga.
|
||||
|
||||
> :warning: **AVISO:** ¡Esta es la parte más peligrosa de las transacciones en crudo! Debido a que automáticamente gasta toda la cantidad en los UTXOs que utiliza, es de vital importancia que se asegure de saber (1) exactamente qué UTXOs está usando; (2) exactamente cuánto dinero contienen; (3) exactamente cuánto dinero está enviando; y (4) cuál es la diferencia. Si se equivoca y utiliza el UTXO equivocado (con más dinero del que pensabas) o si envías muy poco dinero, el exceso se pierde. Para siempre. ¡No cometa ese error! Conozca sus entradas y salidas _precisamente_. O mejor, no utilice las transacciones en crudo salvo como parte de un programa cuidadosamente estudiado y triplemente comprobado.
|
||||
|
||||
> :book: ***¿Cuánto deberá gastar en tasas de transacción?*** [Bitcoin Fees](https://bitcoinfees.21.co/) tiene una buena evaluación en vivo. Dice que "la tarifa de transacción más rápida y barata es actualmente de 42 satoshis/byte" y que "para el tamaño medio de transacción de 224 bytes, esto resulta en una tarifa de 9.408 satoshis".
|
||||
|
||||
Actualmente Bitcoin Fees sugiere una tarifa de transacción de unos 10.000 satoshis, que es lo mismo que 0,0001 BC. Sí, eso es para la red principal, no para la red de pruebas, pero queremos probar las cosas de forma realista, así que eso es lo que vamos a utilizar.
|
||||
|
||||
En este caso, eso significa tomar los 0,0005 BTC en el UTXO que hemos seleccionado, reduciéndolos en 0,0001 BTC para la tasa de transacción, y enviando los 0,0004 BTC restantes. (Y este es un ejemplo de por qué los micropagos no funcionan en la red Bitcoin, porque una tarifa de transacción de 1$ más o menos es bastante cara cuando se está enviando 4$, y no digamos si estuviera intentando hacer un micropago de 0,50$. Pero siempre es por eso que tenemos Lightning).
|
||||
|
||||
> :warning: **ADVERTENCIA:** Cuanto más baja sea la tarifa de la transacción, más tiempo pasará antes de que su transacción se incorpore a un bloque. El sitio de tarifas de Bitcoin enumera los tiempos esperados, desde un esperado 0 bloques, hasta 22. Dado que los bloques se construyen de media cada 10 minutos, ¡esa es la diferencia entre unos minutos y unas horas! Por lo tanto, elija una tarifa de transacción que sea apropiada para lo que está enviando. Tenga en cuenta que nunca debe bajar de la tarifa mínima de retransmisión, que es de 0,0001 BTC.
|
||||
|
||||
### Escribir la transacción en crudo
|
||||
|
||||
Ahora está listo para crear la transacción en crudo. Esto utiliza el comando `createrawtransaction`, que puede parecer un poco intimidante. Eso es porque el comando `createrawtransaction` no le protege completamente del RPC JSON que utiliza bitcoin-cli. En su lugar, va a introducir un arreglo JSON para listar los UTXOs que está gastando y un objeto JSON para listar las salidas.
|
||||
|
||||
Este es el formato estándar:
|
||||
```
|
||||
$ bitcoin-cli createrawtransaction
|
||||
'''[
|
||||
{
|
||||
"txid": "'$your_txid'",
|
||||
"vout": '$your_vout'
|
||||
}
|
||||
]'''
|
||||
'''{
|
||||
"'$your_recipient'": bitcoin_amount
|
||||
}'''
|
||||
```
|
||||
Sí, hay todo tipo de comillas locas ahí, pero confíe en que harán lo correcto. Use `'''` para marcar el inicio y el final del array JSON y del objeto JSON. Protege las palabras normales como `"this"`, pero no necesita proteger los números normales: `0`. Si son variables, inserta comillas simples, como `"'$this_word'"` y `'$this_num'`. (Ya se acostumbrá).
|
||||
|
||||
Aquí hay un comando que crea una transacción en crudo para enviar su $utxo a su $recipient
|
||||
```
|
||||
$ rawtxhex=$(bitcoin-cli createrawtransaction '''[ { "txid": "'$utxo_txid'", "vout": '$utxo_vout' } ]''' '''{ "'$recipient'": 0.0004 }''')
|
||||
$ echo $rawtxhex
|
||||
02000000013a6e4279b799791049e1826602e84d2e36797e2005887b98c3ecf16b01b7f3610100000000ffffffff01409c0000000000001976a914e7c1345fc8f87c68170b3aa798a956c2fe6a9eff88ac00000000
|
||||
```
|
||||
|
||||
### Verifique su transacción en crudo
|
||||
|
||||
A continuación debe verificar su rawtransaction con `decoderawtransaction` para asegurarse de que hará lo correcto.
|
||||
```
|
||||
$ bitcoin-cli decoderawtransaction $rawtxhex
|
||||
{
|
||||
"txid": "dcd2d8f0ec5581b806a1fbe00325e1680c4da67033761b478a26895380cc1298",
|
||||
"hash": "dcd2d8f0ec5581b806a1fbe00325e1680c4da67033761b478a26895380cc1298",
|
||||
"version": 2,
|
||||
"size": 85,
|
||||
"vsize": 85,
|
||||
"weight": 340,
|
||||
"locktime": 0,
|
||||
"vin": [
|
||||
{
|
||||
"txid": "61f3b7016bf1ecc3987b8805207e79362e4de8026682e149107999b779426e3a",
|
||||
"vout": 1,
|
||||
"scriptSig": {
|
||||
"asm": "",
|
||||
"hex": ""
|
||||
},
|
||||
"sequence": 4294967295
|
||||
}
|
||||
],
|
||||
"vout": [
|
||||
{
|
||||
"value": 0.00040000,
|
||||
"n": 0,
|
||||
"scriptPubKey": {
|
||||
"asm": "OP_DUP OP_HASH160 e7c1345fc8f87c68170b3aa798a956c2fe6a9eff OP_EQUALVERIFY OP_CHECKSIG",
|
||||
"hex": "76a914e7c1345fc8f87c68170b3aa798a956c2fe6a9eff88ac",
|
||||
"reqSigs": 1,
|
||||
"type": "pubkeyhash",
|
||||
"addresses": [
|
||||
"n2eMqTT929pb1RDNuqEnxdaLau1rxy3efi"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Compruebe el `vin`. ¿Está gastando la transacción correcta? ¿Contiene la cantidad de dinero esperada? (Compruébelo con `bitcoin-cli gettransaction` y asegúrese de mirar el `vout` correcto). Compruebe su `vout`. ¿Está enviando la cantidad correcta? ¿Va a la dirección correcta? Por último, haga los cálculos para asegurarse de que el dinero cuadra. ¿El valor del UTXO menos la cantidad que se está gastando es igual a la tasa de transacción prevista?
|
||||
|
||||
> :information_source: **NOTA - SECUENCIA:** Puede notar que cada entrada tiene un número de secuencia, establecido aquí en 4294967295, que es 0xFFFFFFFF. Esta es la última frontera de las transacciones de Bitcoin, porque es un campo estándar en las transacciones que originalmente estaba destinado a un propósito específico, pero nunca fue implementado completamente. Así que ahora hay este número entero en las transacciones que podría ser reutilizado para otros usos. Y, de hecho, lo ha sido. En el momento de escribir este artículo hay tres usos diferentes para la variable que se llama `nSequence` en el código de Bitcoin Core: permite RBF, `nLockTime`, y timelocks relativos. Si no hay nada raro, `nSequence` se establecerá en 4294967295. Establecer un valor más bajo indica que están ocurriendo cosas especiales.
|
||||
|
||||
### Firmar la transacción cruda
|
||||
|
||||
Hasta la fecha, su transacción cruda es sólo algo teórico: usted _podría_ enviarla, pero no se ha prometido nada. Tiene que hacer algunas cosas para que salga a la red.
|
||||
|
||||
En primer lugar, tiene que firmar su transacción en crudo:
|
||||
```
|
||||
|
||||
$ bitcoin-cli signrawtransactionwithwallet $rawtxhex
|
||||
{
|
||||
"hex": "02000000013a6e4279b799791049e1826602e84d2e36797e2005887b98c3ecf16b01b7f361010000006a4730440220335d15a2a2ca3ce6a302ce041686739d4a38eb0599a5ea08305de71965268d05022015f77a33cf7d613015b2aba5beb03088033625505ad5d4d0624defdbea22262b01210278608b54b8fb0d8379d3823d31f03a7c6ab0adffb07dd3811819fdfc34f8c132ffffffff01409c0000000000001976a914e7c1345fc8f87c68170b3aa798a956c2fe6a9eff88ac00000000",
|
||||
"complete": true
|
||||
}
|
||||
$ signedtx="02000000013a6e4279b799791049e1826602e84d2e36797e2005887b98c3ecf16b01b7f361010000006a4730440220335d15a2a2ca3ce6a302ce041686739d4a38eb0599a5ea08305de71965268d05022015f77a33cf7d613015b2aba5beb03088033625505ad5d4d0624defdbea22262b01210278608b54b8fb0d8379d3823d31f03a7c6ab0adffb07dd3811819fdfc34f8c132ffffffff01409c0000000000001976a914e7c1345fc8f87c68170b3aa798a956c2fe6a9eff88ac00000000"
|
||||
```
|
||||
Obsérvese que hemos capturado el hexágono firmado a mano, en lugar de intentar analizarlo a partir del objeto JSON. Un paquete de software llamado "JQ" podría hacerlo mejor, como explicaremos en un próximo interludio.
|
||||
|
||||
### Enviar la transacción cruda
|
||||
|
||||
Ahora tiene una transacción en crudo lista para funcionar, pero no cuenta hasta que la ponga en la red, lo que se hace con el comando `sendrawtransaction`. Recibirá de vuelta un txid:
|
||||
```
|
||||
$ bitcoin-cli sendrawtransaction $signedtx
|
||||
a1fd550d1de727eccde6108c90d4ffec11ed83691e96e119d842b3f390e2f19a
|
||||
```
|
||||
Inmediatamente verá que el UTXO y su dinero han sido eliminados de tu cartera:
|
||||
```
|
||||
$ bitcoin-cli listunspent
|
||||
[
|
||||
{
|
||||
"txid": "ca4898d8f950df03d6bfaa00578bd0305d041d24788b630d0c4a32debcac9f36",
|
||||
"vout": 0,
|
||||
"address": "mi25UrzHnvn3bpEfFCNqJhPWJn5b77a5NE",
|
||||
"label": "",
|
||||
"scriptPubKey": "76a9141b72503639a13f190bf79acf6d76255d772360b788ac",
|
||||
"amount": 0.00010000,
|
||||
"confirmations": 23,
|
||||
"spendable": true,
|
||||
"solvable": true,
|
||||
"desc": "pkh([d6043800/0'/0'/1']02fd5740996d853ea51a6904cf03257fc11204b0179f344c49739ec5b20b39c9ba)#62rud39c",
|
||||
"safe": true
|
||||
},
|
||||
{
|
||||
"txid": "91261eafae15ea53dedbea7c1db748c52bbc04a85859ffd0d839bda1421fda4c",
|
||||
"vout": 0,
|
||||
"address": "mjehC2KHzXcBDcwTd4LhZ2GzyzrZ3Kd3ff",
|
||||
"label": "",
|
||||
"scriptPubKey": "76a9142d573900aa357a38afd741fbf24b075d263ea6e088ac",
|
||||
"amount": 0.00022000,
|
||||
"confirmations": 6,
|
||||
"spendable": true,
|
||||
"solvable": true,
|
||||
"desc": "pkh([d6043800/0'/0'/3']0278608b54b8fb0d8379d3823d31f03a7c6ab0adffb07dd3811819fdfc34f8c132)#nhjc3f8y",
|
||||
"safe": true
|
||||
}
|
||||
]
|
||||
|
||||
$ bitcoin-cli getbalance
|
||||
0.00032000
|
||||
```
|
||||
Pronto `listtransactions` deberá mostrar una transacción confirmada de la categoría "enviar".
|
||||
```
|
||||
{
|
||||
"address": "n2eMqTT929pb1RDNuqEnxdaLau1rxy3efi",
|
||||
"category": "send",
|
||||
"amount": -0.00040000,
|
||||
"vout": 0,
|
||||
"fee": -0.00010000,
|
||||
"confirmations": 1,
|
||||
"trusted": true,
|
||||
"txid": "a1fd550d1de727eccde6108c90d4ffec11ed83691e96e119d842b3f390e2f19a",
|
||||
"walletconflicts": [
|
||||
],
|
||||
"time": 1592608574,
|
||||
"timereceived": 1592608574,
|
||||
"bip125-replaceable": "no",
|
||||
"abandoned": false
|
||||
}
|
||||
```
|
||||
Puede ver que coincide con el `txid` y la dirección del `receptor`. No sólo muestra el "importe" enviado, sino también la `comisión` de la transacción. Y, ya ha recibido una confirmación, porque ofrecimos una tarifa que haría que se incluyera en un bloque rápidamente.
|
||||
|
||||
¡Felicidades! ¡Ahora es unos cuantos satoshis más pobre!
|
||||
|
||||
|
||||
## Resumen: Creación de una transacción en crudo
|
||||
|
||||
Cuando el dinero entra en su monedero Bitcoin, permanece como cantidades distintas, llamadas UTXOs. Cuando usted crea una transacción cruda para enviar ese dinero de vuelta, utiliza uno o más UTXOs para financiarlo. Entonces puede crear una transacción en crudo, firmarla y enviarla en la red Bitcoin. Sin embargo, esto es sólo una base: ¡normalmente necesitará crear una transacción cruda con múltiples salidas para enviar realmente algo en la red bitcoin!
|
||||
|
||||
## ¿Qué sigue?
|
||||
|
||||
Retroceda con "Enviando Transacciones en Bitcoin" con [Interludio: Usando JQ](04_2_Interludio_Usando_JQ.md).
|
413
es/04_2_Interludio_Usando_JQ.md
Normal file
413
es/04_2_Interludio_Usando_JQ.md
Normal file
@ -0,0 +1,413 @@
|
||||
# Interludio: Usando JQ
|
||||
|
||||
La creación de una transacción en crudo reveló cómo los resultados más complejos de bitcoin-cli no pueden guardarse fácilmente en variables de línea de comandos. La respuesta es JQ, que permite extraer elementos individuales de JSON más complejos.
|
||||
|
||||
## Instalación de JQ
|
||||
|
||||
JQ esta disponible en [Github repository](https://stedolan.github.io/jq/). Descargar para Linux, OS X, or Windows, según corresponda.
|
||||
|
||||
Una vez que haya descargado el binario, puede instalarlo en su sistema. Si está trabajando en un VPS Debian como sugerimos, tu instalación se verá así:
|
||||
```
|
||||
$ mv jq-linux64 jq
|
||||
$ sudo /usr/bin/install -m 0755 -o root -g root -t /usr/local/bin jq
|
||||
```
|
||||
> :book: ***¿Qué es JQ?*** jq es como sed para datos JSON - puede usarlo para cortar y filtrar y mapear y transformar datos estructurados con la misma facilidad que sed, awk, grep y amigos se permiten jugar con el texto".
|
||||
|
||||
## Utilizar JQ para acceder al valor de un objeto JSON por clave
|
||||
|
||||
**Ejemplo de uso:** _Capturar el hex de una transacción cruda firmada._
|
||||
|
||||
En la sección anterior, el uso de `signrawtransaction` ofreció un ejemplo de no poder capturar fácilmente los datos en las variables debido al uso de JSON como salida:
|
||||
```
|
||||
$ bitcoin-cli signrawtransactionwithwallet $rawtxhex
|
||||
{
|
||||
"hex": "02000000013a6e4279b799791049e1826602e84d2e36797e2005887b98c3ecf16b01b7f361010000006a4730440220335d15a2a2ca3ce6a302ce041686739d4a38eb0599a5ea08305de71965268d05022015f77a33cf7d613015b2aba5beb03088033625505ad5d4d0624defdbea22262b01210278608b54b8fb0d8379d3823d31f03a7c6ab0adffb07dd3811819fdfc34f8c132ffffffff01409c0000000000001976a914e7c1345fc8f87c68170b3aa798a956c2fe6a9eff88ac00000000",
|
||||
"complete": true
|
||||
}
|
||||
```
|
||||
Afortunadamente, JQ puede capturar fácilmente este tipo de datos.
|
||||
|
||||
Para utilizar JQ, ejecute `jq` en el extremo posterior de una tubería, y utilice siempre la invocación estándar de `jq -r '.'`. El `-r` le dice a JQ que produzca una salida cruda, que funcionará para las variables de la línea de comandos, mientras que el `.` le dice a jq que salga. Protegemos ese argumento en `' ` porque necesitaremos esa protección más adelante cuando nuestras invocaciones de `jq` se vuelvan más complejas.
|
||||
|
||||
Para capturar un valor específico de un objeto JSON, basta con enumerar la clave después del `.`:
|
||||
```
|
||||
$ bitcoin-cli signrawtransactionwithwallet $rawtxhex | jq -r '.hex'
|
||||
02000000013a6e4279b799791049e1826602e84d2e36797e2005887b98c3ecf16b01b7f361010000006a4730440220335d15a2a2ca3ce6a302ce041686739d4a38eb0599a5ea08305de71965268d05022015f77a33cf7d613015b2aba5beb03088033625505ad5d4d0624defdbea22262b01210278608b54b8fb0d8379d3823d31f03a7c6ab0adffb07dd3811819fdfc34f8c132ffffffff01409c0000000000001976a914e7c1345fc8f87c68170b3aa798a956c2fe6a9eff88ac00000000
|
||||
```
|
||||
Con esa herramienta en la mano, puede capturar información de objetos JSON en variables de línea de comandos:
|
||||
```
|
||||
$ signedtx=$(bitcoin-cli signrawtransactionwithwallet $rawtxhex | jq -r '.hex')
|
||||
$ echo $signedtx
|
||||
02000000013a6e4279b799791049e1826602e84d2e36797e2005887b98c3ecf16b01b7f361010000006a4730440220335d15a2a2ca3ce6a302ce041686739d4a38eb0599a5ea08305de71965268d05022015f77a33cf7d613015b2aba5beb03088033625505ad5d4d0624defdbea22262b01210278608b54b8fb0d8379d3823d31f03a7c6ab0adffb07dd3811819fdfc34f8c132ffffffff01409c0000000000001976a914e7c1345fc8f87c68170b3aa798a956c2fe6a9eff88ac00000000
|
||||
```
|
||||
Así podrá utilizar esas variables fácilmente y sin errores:
|
||||
```
|
||||
$ bitcoin-cli sendrawtransaction $signedtx
|
||||
3f9ccb6e16663e66dc119de1866610cc4f7a83079bfec2abf0598ed3adf10a78
|
||||
```
|
||||
## Utilizar JQ para acceder a los valores de un objeto JSON en un arreglo por clave
|
||||
|
||||
**Ejemplo de uso:** _Capturar el txid y vout para un UTXO seleccionado._
|
||||
|
||||
Sacar datos de un objeto JSON es fácil, pero ¿Qué pasa si ese objeto JSON está en un arreglo JSON? El comando `listunspent` ofrece un gran ejemplo, porque normalmente contendrá un número de transacciones diferentes. ¿Y si quiere capturar información específica de _una_ de ellas?
|
||||
|
||||
Cuando se trabaja con un array JSON, lo primero que hay que hacer es decirle a JQ a qué índice debe acceder. Por ejemplo, puede que haya mirado sus transacciones en `listunspent` y que haya decidido que quiere trabajar con la segunda de ellas. Usas `'.[1]'` para acceder a ese segundo elemento. El `[]` dice que estamos haciendo referencia a un arreglo JSON y el `1` dice que queremos el índice 1.
|
||||
```
|
||||
$ bitcoin-cli listunspent | jq -r '.[1]'
|
||||
{
|
||||
"txid": "91261eafae15ea53dedbea7c1db748c52bbc04a85859ffd0d839bda1421fda4c",
|
||||
"vout": 0,
|
||||
"address": "mjehC2KHzXcBDcwTd4LhZ2GzyzrZ3Kd3ff",
|
||||
"label": "",
|
||||
"scriptPubKey": "76a9142d573900aa357a38afd741fbf24b075d263ea6e088ac",
|
||||
"amount": 0.00022,
|
||||
"confirmations": 9,
|
||||
"spendable": true,
|
||||
"solvable": true,
|
||||
"desc": "pkh([d6043800/0'/0'/3']0278608b54b8fb0d8379d3823d31f03a7c6ab0adffb07dd3811819fdfc34f8c132)#nhjc3f8y",
|
||||
"safe": true
|
||||
}
|
||||
```
|
||||
A continuación, puede capturar un valor individual de ese arreglo seleccionado (1) utilizando una tubería _dentro_ de los argumentos JQ; y luego (2) solicitando el valor específico después, como en el ejemplo anterior. Lo siguiente capturaría el `txid` del objeto JSON número 1 del arreglo JSON producido por `listunspent`:
|
||||
```
|
||||
$ bitcoin-cli listunspent | jq -r '.[1] | .txid'
|
||||
91261eafae15ea53dedbea7c1db748c52bbc04a85859ffd0d839bda1421fda4c
|
||||
```
|
||||
Observe cuidadosamente cómo las `' 's` van alrededor de toda la expresión JQ _incluyendo_ la tubería.
|
||||
|
||||
Este método se puede utilizar para rellenar las variables de un UTXO que se quiera utilizar:
|
||||
```
|
||||
$ newtxid=$(bitcoin-cli listunspent | jq -r '.[1] | .txid')
|
||||
$ newvout=$(bitcoin-cli listunspent | jq -r '.[1] | .vout')
|
||||
$ echo $newtxid
|
||||
91261eafae15ea53dedbea7c1db748c52bbc04a85859ffd0d839bda1421fda4c
|
||||
$ echo $newvout
|
||||
0
|
||||
```
|
||||
¡Voila! Ahora podemos crear una nueva transacción en crudo utilizando nuestro primer UTXO como entrada, ¡Sin tener que teclear ninguna información del UTXO a mano!
|
||||
|
||||
## Utilizar JQ para acceder a valores de objetos JSON coincidentes con un arreglo por clave
|
||||
|
||||
**Ejemplo de uso:** _Lista el valor de todos los UTXOs no gastados._
|
||||
|
||||
En lugar de acceder a un único valor específico en un objeto JSON específico, se puede acceder a todo un valor específico en todos los objetos JSON. Esto se hace con `.[]`, donde no se especifica ningún índice. Por ejemplo, esto listaría todos los fondos no gastados:
|
||||
```
|
||||
$ bitcoin-cli listunspent | jq -r '.[] | .amount'
|
||||
0.0001
|
||||
0.00022
|
||||
```
|
||||
|
||||
## Utilizar JQ para cálculos sencillos por clave
|
||||
|
||||
**Ejemplo de uso:** _Sumar el valor de todos los UTXOs no gastados._
|
||||
|
||||
En este punto, puede empezar a usar la salida de JQ para hacer cálculos sencillos. Por ejemplo, sumando los valores de esas transacciones no gastadas con un simple script `awk` le dara el equivalente a `getbalance`:
|
||||
```
|
||||
$ bitcoin-cli listunspent | jq -r '.[] | .amount' | awk '{s+=$1} END {print s}'
|
||||
0.00032
|
||||
$ bitcoin-cli getbalance
|
||||
0.00032000
|
||||
```
|
||||
|
||||
## Usar JQ para mostrar múltiples valores de objetos JSON en un arreglo de claves múltiples
|
||||
|
||||
**Ejemplo de uso:** _Lista de información de uso para todos los UTXOs._
|
||||
|
||||
JQ puede capturar fácilmente elementos individuales de objetos JSON y arreglos y colocar esos elementos en variables. Ese será su principal uso en futuras secciones. Sin embargo, también se puede utilizar para reducir las enormes cantidades de información emitidas por `bitcoin-cli` en cantidades razonables de información.
|
||||
|
||||
Por ejemplo, puede querer ver un listado de todos sus UTXOs (`.[]`) y obtener un listado de toda su información más importante (`.txid, .vout, .amount`):
|
||||
```
|
||||
$ bitcoin-cli listunspent | jq -r '.[] | .txid, .vout, .amount'
|
||||
ca4898d8f950df03d6bfaa00578bd0305d041d24788b630d0c4a32debcac9f36
|
||||
0
|
||||
0.0001
|
||||
91261eafae15ea53dedbea7c1db748c52bbc04a85859ffd0d839bda1421fda4c
|
||||
0
|
||||
0.00022
|
||||
```
|
||||
Esto hace que sea fácil decidir qué UTXOs gastar en una transacción en crudo, pero no es muy bonito.
|
||||
|
||||
Afortunadamente, JQ también le permite ser elegante. Puede usar `{}`s para crear nuevos objetos JSON (ya sea para un análisis adicional o para una salida bonita). También puede definir el nombre de la nueva clave para cada uno de sus valores. La salida resultante debería ser mucho más intuitiva y menos propensa a errores (aunque, obviamente, menos útil para volcar información directamente en las variables).
|
||||
|
||||
El siguiente ejemplo muestra exactamente el mismo análisis de `listunspent`, pero con cada objeto JSON antiguo reconstruido como un nuevo objeto JSON abreviado, con todos los nuevos valores nombrados con sus antiguas claves:
|
||||
```
|
||||
$ bitcoin-cli listunspent | jq -r '.[] | { txid: .txid, vout: .vout, amount: .amount }'
|
||||
{
|
||||
"txid": "ca4898d8f950df03d6bfaa00578bd0305d041d24788b630d0c4a32debcac9f36",
|
||||
"vout": 0,
|
||||
"amount": 0.0001
|
||||
}
|
||||
{
|
||||
"txid": "91261eafae15ea53dedbea7c1db748c52bbc04a85859ffd0d839bda1421fda4c",
|
||||
"vout": 0,
|
||||
"amount": 0.00022
|
||||
}
|
||||
```
|
||||
Por supuesto, puede cambiar el nombre de sus nuevas llaves como mejor se parezca. No hay nada mágico en los nombres originales.
|
||||
```
|
||||
$ bitcoin-cli listunspent | jq -r '.[] | { tx: .txid, output: .vout, bitcoins: .amount }'
|
||||
{
|
||||
"tx": "ca4898d8f950df03d6bfaa00578bd0305d041d24788b630d0c4a32debcac9f36",
|
||||
"output": 0,
|
||||
"bitcoins": 0.0001
|
||||
}
|
||||
{
|
||||
"tx": "91261eafae15ea53dedbea7c1db748c52bbc04a85859ffd0d839bda1421fda4c",
|
||||
"output": 0,
|
||||
"bitcoins": 0.00022
|
||||
}
|
||||
```
|
||||
## Utilizar JQ para acceder a objetos JSON por valor de búsqueda
|
||||
|
||||
**Ejemplo de uso:** _Buscar automáticamente los UTXOs que se utilizan en una transacción._
|
||||
|
||||
Hasta ahora, las búsquedas en JQ han sido bastante sencillas: se utiliza una clave para buscar uno o más valores en un objeto o arreglo JSON. ¿Pero qué pasa si quiere buscar un valor en un objeto JSON... por otro valor? Este tipo de búsqueda indirecta tiene una aplicación real cuando se trabaja con transacciones construidas sobre UTXOs existentes. Por ejemplo, puede permitirse calcular el valor de la suma de los UTXOs que se utilizan en una transacción, algo que es de vital importancia.
|
||||
|
||||
Este ejemplo utiliza la siguiente transacción en crudo. Tenga en cuenta que esta es una transacción cruda más compleja con dos entradas y dos salidas. Aprenderemos a hacerlas en próximas secciones; por ahora, es necesario para poder ofrecer ejemplos robustos. Observa que, a diferencia de nuestros ejemplos anteriores, éste tiene dos objetos en su matriz `vin` y dos en su matriz `vout`.
|
||||
```
|
||||
$ bitcoin-cli decoderawtransaction $rawtxhex
|
||||
{
|
||||
"txid": "6f83a0b78c598de01915554688592da1d7a3047eacacc8a9be39f5396bf0a07e",
|
||||
"hash": "6f83a0b78c598de01915554688592da1d7a3047eacacc8a9be39f5396bf0a07e",
|
||||
"size": 160,
|
||||
"vsize": 160,
|
||||
"version": 2,
|
||||
"locktime": 0,
|
||||
"vin": [
|
||||
{
|
||||
"txid": "d261b9494eb29084f668e1abd75d331fc2d6525dd206b2f5236753b5448ca12c",
|
||||
"vout": 1,
|
||||
"scriptSig": {
|
||||
"asm": "",
|
||||
"hex": ""
|
||||
},
|
||||
"sequence": 4294967295
|
||||
},
|
||||
{
|
||||
"txid": "c7c7f6371ec19330527325908a544bbf8401191645598301d24b54d37e209e7b",
|
||||
"vout": 1,
|
||||
"scriptSig": {
|
||||
"asm": "",
|
||||
"hex": ""
|
||||
},
|
||||
"sequence": 4294967295
|
||||
}
|
||||
],
|
||||
"vout": [
|
||||
{
|
||||
"value": 1.00000000,
|
||||
"n": 0,
|
||||
"scriptPubKey": {
|
||||
"asm": "OP_DUP OP_HASH160 cfc39be7ea3337c450a0c77a839ad0e160739058 OP_EQUALVERIFY OP_CHECKSIG",
|
||||
"hex": "76a914cfc39be7ea3337c450a0c77a839ad0e16073905888ac",
|
||||
"reqSigs": 1,
|
||||
"type": "pubkeyhash",
|
||||
"addresses": [
|
||||
"mzTWVv2QSgBNqXx7RC56zEhaQPve8C8VS9"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"value": 0.04500000,
|
||||
"n": 1,
|
||||
"scriptPubKey": {
|
||||
"asm": "OP_DUP OP_HASH160 166692bda9f25ced145267bb44286e8ee3963d26 OP_EQUALVERIFY OP_CHECKSIG",
|
||||
"hex": "76a914166692bda9f25ced145267bb44286e8ee3963d2688ac",
|
||||
"reqSigs": 1,
|
||||
"type": "pubkeyhash",
|
||||
"addresses": [
|
||||
"mhZQ3Bih6wi7jP1tpFZrCcyr4NsfCapiZP"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Recuperar el(los) valor(es)
|
||||
|
||||
Supongamos que sabemos exactamente cómo se construye esta transacción: sabemos que utiliza dos UTXOs como entrada. Para recuperar el txid de los dos UTXOs, podríamos usar `jq` para buscar el valor .vin de la transacción, luego referenciar el arreglo 0 del .vin, y luego el valor .txid de ese arreglo. Después, podríamos hacer lo mismo con el 1er arreglo, y luego lo mismo con los dos valores .vout del .vin. Fácil:
|
||||
```
|
||||
$ usedtxid1=$(bitcoin-cli decoderawtransaction $rawtxhex | jq -r '.vin | .[0] | .txid')
|
||||
$ echo $usedtxid1
|
||||
d261b9494eb29084f668e1abd75d331fc2d6525dd206b2f5236753b5448ca12c
|
||||
$ usedtxid2=$(bitcoin-cli decoderawtransaction $rawtxhex | jq -r '.vin | .[1] | .txid')
|
||||
$ echo $usedtxid2
|
||||
c7c7f6371ec19330527325908a544bbf8401191645598301d24b54d37e209e7b
|
||||
|
||||
$ usedvout1=$(bitcoin-cli decoderawtransaction $rawtxhex | jq -r '.vin | .[0] | .vout')
|
||||
$ echo $usedvout1
|
||||
1
|
||||
$ usedvout2=$(bitcoin-cli decoderawtransaction $rawtxhex | jq -r '.vin | .[1] | .vout')
|
||||
$ echo $usedvout2
|
||||
1
|
||||
```
|
||||
Sin embargo, sería mejor tener un caso general que _automáticamente_ guardara todos los txids de nuestros UTXOs.
|
||||
|
||||
Ya sabemos que podemos acceder a todos los `.txid`s utilizando un valor de matriz `.[]`. Podemos usar eso para construir una búsqueda general de .txid:
|
||||
```
|
||||
$ usedtxid=($(bitcoin-cli decoderawtransaction $rawtxhex | jq -r '.vin | .[] | .txid'))
|
||||
$ echo ${usedtxid[0]}
|
||||
d261b9494eb29084f668e1abd75d331fc2d6525dd206b2f5236753b5448ca12c
|
||||
$ echo ${usedtxid[1]}
|
||||
c7c7f6371ec19330527325908a544bbf8401191645598301d24b54d37e209e7b
|
||||
|
||||
$ usedvout=($(bitcoin-cli decoderawtransaction $rawtxhex | jq -r '.vin | .[] | .vout'))
|
||||
$ echo ${usedvout[0]}
|
||||
1
|
||||
$ echo ${usedvout[1]}
|
||||
1
|
||||
```
|
||||
El único truco real aquí es cómo guardamos la información usando el shell bash. En lugar de guardar en una variable con `$(comando)`, guardamos en una matriz con `($(comando))`. Entonces pudimos acceder a los elementos individuales de la matriz bash con una construcción `${variable[n]}`. En cambio, podíamos acceder a todo el arreglo con `${variable[@]}`. (Sí, nadie dijo nunca que bash fuera bonito).
|
||||
|
||||
> :warning: **ADVERTENCIA:** Recuerde siempre que un UTXO es una transacción _más_ un vout. La primera vez que escribimos este ejemplo de JQ se nos escapó el vout, y dejó de funcionar cuando acabamos con una situación en la que nos habían enviado dos `vouts` de la misma transacción.
|
||||
|
||||
### Recuperar los objetos relacionados
|
||||
|
||||
Ahora puede utilizar la información guardada de `txid` y `vout` para referenciar UTXOs en `listunspent`. Para encontrar la información sobre los UTXOs que están siendo utilizados por la transacción en crudo, es necesario buscar en todo el arreglo JSON (`[]`) de las transacciones no gastadas. A continuación, puede seleccionar (`select`) objetos JSON individuales que incluyan (`contains`) los txids. A continuación, seleccione (`select`) las transacciones que también contengan (`contain`) la salida correcta vout.
|
||||
|
||||
El uso de otro nivel de tuberías es la metodología estándar de JQ: se toma un conjunto de datos, luego se reduce a todas las transacciones relevantes, luego se reduce a los vouts que realmente se usaron de esas transacciones. Sin embargo, los argumentos `select` y `contains` son algo nuevo. Muestran algo de la complejidad de JSON que va más allá del alcance de este tutorial; por ahora, solo hay que saber que esta invocación particular funcionará para agarrar objetos que coincidan.
|
||||
|
||||
Para empezar de forma sencilla, esto escoge los dos UTXO de uno en uno:
|
||||
```
|
||||
$ bitcoin-cli listunspent | jq -r '.[] | select (.txid | contains("'${usedtxid[0]}'")) | select(.vout | contains('${usedvout[0]}'))'
|
||||
{
|
||||
"txid": "d261b9494eb29084f668e1abd75d331fc2d6525dd206b2f5236753b5448ca12c",
|
||||
"vout": 1,
|
||||
"address": "miSrC3FvkPPZgqqvCiQycq7io7wTSVsAFH",
|
||||
"scriptPubKey": "76a91420219e4f3c6bc0f6524d538009e980091b3613e888ac",
|
||||
"amount": 0.9,
|
||||
"confirmations": 6,
|
||||
"spendable": true,
|
||||
"solvable": true
|
||||
}
|
||||
$ bitcoin-cli listunspent | jq -r '.[] | select (.txid | contains("'${usedtxid[1]}'")) | select(.vout | contains('${usedvout[1]}'))'
|
||||
{
|
||||
"txid": "c7c7f6371ec19330527325908a544bbf8401191645598301d24b54d37e209e7b",
|
||||
"vout": 1,
|
||||
"address": "mzizSuAy8aL1ytFijds7pm4MuDPx5aYH5Q",
|
||||
"scriptPubKey": "76a914d2b12da30320e81f2dfa416c5d9499d08f778f9888ac",
|
||||
"amount": 0.4,
|
||||
"confirmations": 5,
|
||||
"spendable": true,
|
||||
"solvable": true
|
||||
}
|
||||
```
|
||||
Un simple bucle for-loop de bash podría, en cambio, traer _todos_ sus UTXOs:
|
||||
```
|
||||
$ for ((i=0; i<${#usedtxid[*]}; i++)); do txid=${usedtxid[i]}; vout=${usedvout[i]}; bitcoin-cli listunspent | jq -r '.[] | select (.txid | contains("'${txid}'")) | select(.vout | contains('$vout'))'; done;
|
||||
{
|
||||
"txid": "d261b9494eb29084f668e1abd75d331fc2d6525dd206b2f5236753b5448ca12c",
|
||||
"vout": 1,
|
||||
"address": "miSrC3FvkPPZgqqvCiQycq7io7wTSVsAFH",
|
||||
"scriptPubKey": "76a91420219e4f3c6bc0f6524d538009e980091b3613e888ac",
|
||||
"amount": 0.9,
|
||||
"confirmations": 7,
|
||||
"spendable": true,
|
||||
"solvable": true
|
||||
}
|
||||
{
|
||||
"txid": "c7c7f6371ec19330527325908a544bbf8401191645598301d24b54d37e209e7b",
|
||||
"vout": 1,
|
||||
"address": "mzizSuAy8aL1ytFijds7pm4MuDPx5aYH5Q",
|
||||
"scriptPubKey": "76a914d2b12da30320e81f2dfa416c5d9499d08f778f9888ac",
|
||||
"amount": 0.4,
|
||||
"confirmations": 6,
|
||||
"spendable": true,
|
||||
"solvable": true
|
||||
}
|
||||
|
||||
```
|
||||
Obsérvese que hemos utilizado otra parte de la fealdad de la arreglo `${#usedtxid[*]}` para determinar el tamaño del arreglo, y luego hemos accedido a cada valor en el arreglo `usedtxid` y a cada valor en el arreglo paralelo `usedvout`, colocándolos en variables más simples para un acceso menos feo.
|
||||
|
||||
## Utilizar JSON para el cálculo simple por valor
|
||||
|
||||
**Ejemplo de uso:** _Calcular automáticamente el valor de los UTXOs utilizados en una transacción._
|
||||
|
||||
Ahora puede ir un paso más allá, y solicitar el .amount (o cualquier otro valor-clave JSON) de los UTXOs que está recuperando.
|
||||
|
||||
Este ejemplo repite el uso de las arreglos `$usedtxid` y `$usedvout` que fueron establecidas de la siguiente manera:
|
||||
```
|
||||
$ usedtxid=($(bitcoin-cli decoderawtransaction $rawtxhex | jq -r '.vin | .[] | .txid'))
|
||||
$ usedvout=($(bitcoin-cli decoderawtransaction $rawtxhex | jq -r '.vin | .[] | .vout'))
|
||||
```
|
||||
El mismo script `for` se puede utilizar para recorrer esos arreglos, pero con una tubería añadida en el JQ da salida al valor `amount` para cada uno de los UTXOs seleccionados.
|
||||
```
|
||||
$ for ((i=0; i<${#usedtxid[*]}; i++)); do txid=${usedtxid[i]}; vout=${usedvout[i]}; bitcoin-cli listunspent | jq -r '.[] | select (.txid | contains("'${txid}'")) | select(.vout | contains('$vout')) | .amount'; done;
|
||||
0.9
|
||||
0.4
|
||||
```
|
||||
En este punto, también se pueden sumar las .cantidades con un script `awk`, para ver realmente cuánto dinero hay en los UTXOs que la transacción está gastando:
|
||||
```
|
||||
$ for ((i=0; i<${#usedtxid[*]}; i++)); do txid=${usedtxid[i]}; vout=${usedvout[i]}; bitcoin-cli listunspent | jq -r '.[] | select (.txid | contains("'${txid}'")) | select(.vout | contains('$vout')) | .amount'; done | awk '{s+=$1} END {print s}'
|
||||
1.3
|
||||
```
|
||||
¡Uf!
|
||||
|
||||
## Utilizar JQ para cálculos complejos
|
||||
|
||||
**Ejemplo de uso:** _Calcular la tasa de una transacción._
|
||||
|
||||
Para calcular la tarifa completa de la transacción en este punto sólo hace falta un poco más de matemáticas: determinar cuánto dinero pasa por el .vout. Este es un uso sencillo de JQ en el que simplemente se utiliza `awk` para sumar el `valor` de toda la información de `vout`:
|
||||
```
|
||||
$ bitcoin-cli decoderawtransaction $rawtxhex | jq -r '.vout [] | .value' | awk '{s+=$1} END {print s}'
|
||||
1.045
|
||||
```
|
||||
Para completar el cálculo de la tasa de transacción, se resta el importe de .vout (1.045) del importe de .vin (1.3).
|
||||
|
||||
Para ello, tendrá que instalar `bc`:
|
||||
```
|
||||
$ sudo apt-get intall bc
|
||||
```
|
||||
|
||||
Al juntar todo esto se crea una calculadora completa en sólo cinco líneas de script:
|
||||
```
|
||||
$ usedtxid=($(bitcoin-cli decoderawtransaction $rawtxhex | jq -r '.vin | .[] | .txid'))
|
||||
$ usedvout=($(bitcoin-cli decoderawtransaction $rawtxhex | jq -r '.vin | .[] | .vout'))
|
||||
$ btcin=$(for ((i=0; i<${#usedtxid[*]}; i++)); do txid=${usedtxid[i]}; vout=${usedvout[i]}; bitcoin-cli listunspent | jq -r '.[] | select (.txid | contains("'${txid}'")) | select(.vout | contains('$vout')) | .amount'; done | awk '{s+=$1} END {print s}')
|
||||
$ btcout=$(bitcoin-cli decoderawtransaction $rawtxhex | jq -r '.vout [] | .value' | awk '{s+=$1} END {print s}')
|
||||
$ echo "$btcin-$btcout"| /usr/bin/bc
|
||||
.255
|
||||
```
|
||||
Y este es también un buen ejemplo de por qué hay que comprobar dos veces las tarifas: teníamos la intención de enviar una tarifa de transacción de 5.000 satoshis, pero enviamos 255.000 satoshis en su lugar. ¡Ups!
|
||||
|
||||
> :warning: **ADVERTENCIA:** La primera vez que escribimos esta lección, realmente calculamos mal nuestra tarifa y no lo vimos hasta que ejecutamos nuestra calculadora de tarifas. Es *así de fácil*, luego su dinero se esfuma. (El ejemplo de arriba es en realidad de nuestra segunda iteración de la calculadora, y esa vez cometimos el error a propósito).
|
||||
|
||||
Para más magia de JSON (y si algo de esto no está claro), por favor lee el [Manual de JSON](https://stedolan.github.io/jq/manual/) y el [JSON Cookbook](https://github.com/stedolan/jq/wiki/Cookbook). Usaremos regularmente JQ en futuros ejemplos.
|
||||
|
||||
## Crear nuevos alias
|
||||
|
||||
El código JQ puede ser un poco difícil de manejar, así que debería considerar añadir algunas invocaciones más largas e interesantes a su ~/.bash_profile.
|
||||
|
||||
Cada vez que busque una gran cantidad de información en un objeto JSON emitido por un comando `bitcoin-cli`, considere escribir un alias para reducirlo a lo que quiere ver.
|
||||
```
|
||||
alias btcunspent="bitcoin-cli listunspent | jq -r '.[] | { txid: .txid, vout: .vout, amount: .amount }'"
|
||||
```
|
||||
|
||||
## Ejecutar el script comisión por transacción
|
||||
|
||||
El [script de cálculo de tasas](../src/04_2_i_txfee-calc.sh) está disponible en el directorio src-code. Puede descargarlo y guardarlo como `txfee-calc.sh`.
|
||||
|
||||
> :warning: **ADVERTENCIA:** Este script no ha sido verificado de forma robusta. Si va a utilizarlo para verificar las comisiones de las transacciones reales, sólo deberá hacerlo como triple comprobación después de haber hecho todos los cálculos usted mismo.
|
||||
|
||||
Asegúrese de que los permisos del script son correctos:
|
||||
```
|
||||
$ chmod 755 txfee-calc.sh
|
||||
```
|
||||
A continuación, puede ejecutar el script de la siguiente manera:
|
||||
```
|
||||
$ ./txfee-calc.sh $rawtxhex
|
||||
.255
|
||||
```
|
||||
También puede crear un alias:
|
||||
```
|
||||
alias btctxfee="~/txfee-calc.sh"
|
||||
```
|
||||
|
||||
## Resumen: Usando JQ
|
||||
|
||||
JQ facilita la extracción de información de arreglos y objetos JSON. También se puede utilizar en scripts de shell para realizar cálculos bastante complejos que le harán la vida más fácil.
|
||||
|
||||
## ¿Qué sigue?
|
||||
|
||||
Continue "Enviando Transacciones en Bitcoin" con [§4.3 Creando Transacciones en Cruda con Argumentos Ingresados con Nombre](04_3_Creando_una_Transaccion_Cruda_con_Argumentos_Ingresados_con_Nombre.md).
|
@ -0,0 +1,97 @@
|
||||
# 4.3 Creación de una transacción en cruda con argumentos ingresado con nombre
|
||||
|
||||
A veces puede ser desalentador averiguar el orden correcto de los argumentos de un comando bitcoin-cli. Afortunadamente, puede utilizar _argumentos con nombre_ como alternativa.
|
||||
|
||||
> ⚠️ **ADVERTENCIA DE VERSIÓN:** Esta es una innovación de Bitcoin Core v 0.14.0. Si ha utilizado nuestros scripts de instalación, es lo que debería tener, pero vuelva a comprobar su versión si tiene algún problema. También hay un error en el uso del comando `createrawtransaction` de los argumentos con nombre que presumiblemente será corregido en 0.14.1.
|
||||
|
||||
## Crear un Alias para el argumento con nombre
|
||||
|
||||
Para utilizar un argumento con nombre debe ejecutar `bitcoin-cli` con el argumento `-named`. Si planea hacer esto regularmente, probablemente querrá crear un alias:
|
||||
```
|
||||
alias bitcoin-cli="bitcoin-cli -named"
|
||||
```
|
||||
Como siempre, esto es para facilitar su uso, pero seguiremos usando los comandos completos para mantener la claridad.
|
||||
|
||||
## Probar un argumento con nombre
|
||||
|
||||
Para conocer los nombres de los argumentos de un comando, consulta la ayuda de `bitcoin-cli`. Enumerará los argumentos en su orden correcto, pero ahora también dará nombres para cada uno de ellos.
|
||||
|
||||
Por ejemplo, `bitcoin-cli help getbalance` lista estos argumentos:
|
||||
|
||||
1. dummy [used to be account]
|
||||
2. minconf
|
||||
3. include_watchonly
|
||||
4. avoid_reuse
|
||||
|
||||
A continuación se muestra un uso tradicional y poco intuitivo de `getbalance` utilizando el argumento de confirmación mínima:
|
||||
```
|
||||
$ bitcoin-cli getbalance "*" 1
|
||||
```
|
||||
Con los argumentos con nombre, puede aclarar lo que está haciendo, lo que también minimiza los errores:
|
||||
```
|
||||
$ bitcoin-cli -named getbalance minconf=1
|
||||
```
|
||||
|
||||
## Probar una transacción en crudo
|
||||
|
||||
A continuación se muestran los comandos para enviar una transacción en crudo con argumentos nombrados:
|
||||
```
|
||||
$ utxo_txid=$(bitcoin-cli listunspent | jq -r '.[0] | .txid')
|
||||
$ utxo_vout=$(bitcoin-cli listunspent | jq -r '.[0] | .vout')
|
||||
$ recipient="n2eMqTT929pb1RDNuqEnxdaLau1rxy3efi"
|
||||
|
||||
$ rawtxhex=$(bitcoin-cli -named createrawtransaction inputs='''[ { "txid": "'$utxo_txid'", "vout": '$utxo_vout' } ]''' outputs='''{ "'$recipient'": 0.00001 }''')
|
||||
$ bitcoin-cli -named decoderawtransaction hexstring=$rawtxhex
|
||||
{
|
||||
"txid": "2b59c31bc232c0399acee4c2a381b564b6fec295c21044fbcbb899ffa56c3da5",
|
||||
"hash": "2b59c31bc232c0399acee4c2a381b564b6fec295c21044fbcbb899ffa56c3da5",
|
||||
"version": 2,
|
||||
"size": 85,
|
||||
"vsize": 85,
|
||||
"weight": 340,
|
||||
"locktime": 0,
|
||||
"vin": [
|
||||
{
|
||||
"txid": "ca4898d8f950df03d6bfaa00578bd0305d041d24788b630d0c4a32debcac9f36",
|
||||
"vout": 0,
|
||||
"scriptSig": {
|
||||
"asm": "",
|
||||
"hex": ""
|
||||
},
|
||||
"sequence": 4294967295
|
||||
}
|
||||
],
|
||||
"vout": [
|
||||
{
|
||||
"value": 0.00001000,
|
||||
"n": 0,
|
||||
"scriptPubKey": {
|
||||
"asm": "OP_DUP OP_HASH160 e7c1345fc8f87c68170b3aa798a956c2fe6a9eff OP_EQUALVERIFY OP_CHECKSIG",
|
||||
"hex": "76a914e7c1345fc8f87c68170b3aa798a956c2fe6a9eff88ac",
|
||||
"reqSigs": 1,
|
||||
"type": "pubkeyhash",
|
||||
"addresses": [
|
||||
"n2eMqTT929pb1RDNuqEnxdaLau1rxy3efi"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
$ signedtx=$(bitcoin-cli -named signrawtransactionwithwallet hexstring=$rawtxhex | jq -r '.hex')
|
||||
$ bitcoin-cli -named sendrawtransaction hexstring=$signedtx
|
||||
e70dd2aa13422d12c222481c17ca21a57071f92ff86bdcffd7eaca71772ba172
|
||||
```
|
||||
¡Voilà! Ha enviado otra transacción en crudo, pero esta vez utilizando argumentos con nombre para mayor claridad y para reducir los errores.
|
||||
|
||||
> ⚠️ **ADVERTENCIA DE VERSIÓN:** Aquí es donde aparece el error en Bitcoin Core 0.14: el argumento 'inputs' para 'createrawtransaction' se llama erróneamente 'transactions'. Así que, si está en Bitcoin Core 0.14.0, sustituye el argumento 'inputs' por 'transactions' para este y futuros ejemplos. Sin embargo, a partir de Bitcoin Core 0.14.1, este código debería funcionar como se muestra.
|
||||
|
||||
## Resumen: Creación de una transacción en crudo con argumentos nombrados
|
||||
|
||||
Ejecutando `bitcoin-cli` con la bandera `-named`, puede utilizar argumentos con nombre en lugar de depender de argumentos ordenados. La ayuda de `bitcoin-cli` le mostrará siempre el nombre correcto de cada argumento. Esto puede resultar en un código más robusto, más fácil de leer y menos propenso a errores.
|
||||
|
||||
_Esta documentación utilizará argumentos con nombre para todos los ejemplos futuros, por claridad y para establecer las mejores prácticas. Sin embargo, también mostrará todos los argumentos en el orden correcto. Por lo tanto, si prefiere no utilizar argumentos con nombre, simplemente elimine la bandera '-named' y todos los "name="s y los ejemplos deberían seguir funcionando correctamente._
|
||||
|
||||
## ¿Qué sigue?
|
||||
|
||||
Continuar "Enviando transacciones de Bitcoin" con [§4.4: Enviando Monedas con una Transacción Cruda](04_4_Enviando_Monedas_con_una_Transaccion_Cruda.md).
|
191
es/04_4_Enviando_Monedas_con_una_Transaccion_Cruda.md
Normal file
191
es/04_4_Enviando_Monedas_con_una_Transaccion_Cruda.md
Normal file
@ -0,0 +1,191 @@
|
||||
# 4.4: Enviando Monedas con una Transacción Cruda
|
||||
|
||||
Como se indicó al principio de este capítulo, la interfaz `bitcoin-cli` ofrece tres formas principales de enviar monedas. En [§4.1](04_1_Enviando_Monedas_de_la_Forma_Facil.md) hablamos de enviarlas de la primera manera, usando el comando `sendtoaddress`. Desde entonces, hemos estado construyendo detalles sobre cómo enviar monedas de una segunda manera, con transacciones en crudo. El [§4.2](04_2_Creando_una_Transaccion_Cruda.md) enseñó cómo crear una transacción sin procesar, un [Interlude](04_2_Interludio_Usando_JQ.md) explicó JQ, y el [§4.3](04_3_Creando_una_Transaccion_Cruda_con_Argumentos_Ingresados_con_Nombre.md) demostró los argumentos con nombre.
|
||||
|
||||
Ahora podemos juntar todo esto y enviar fondos usando una transacción en crudo.
|
||||
|
||||
## Crear una dirección de cambio
|
||||
|
||||
Nuestro ejemplo de transacción cruda en la sección §4.2 era muy simplista: enviamos la totalidad de un UTXO a una nueva dirección. Más frecuentemente, querrá enviar a alguien una cantidad de dinero que no coincide con un UTXO. Pero, recordará que el exceso de dinero de un UTXO que no se envía a tu destinatario se convierte en una comisión de transacción. Entonces, ¿Cómo se puede enviar a alguien sólo una parte de un UTXO y quedarse con el resto?
|
||||
|
||||
La solución es _enviar_ el resto de los fondos a una segunda dirección, una dirección de cambio que has creado en su cartera específicamente para recibirlos:
|
||||
```
|
||||
$ changeaddress=$(bitcoin-cli getrawchangeaddress legacy)
|
||||
$ echo $changeaddress
|
||||
mk9ry5VVy8mrA8SygxSQQUDNSSXyGFot6h
|
||||
```
|
||||
Tenga en cuenta que esto utiliza una nueva función: `getrawchangeaddress`. Es en gran medida la misma que `getnewaddress` pero está optimizada para su uso como una dirección de cambio en una transacción cruda, por lo que no hace cosas como hacer entradas en su libreta de direcciones. De nuevo seleccionamos la dirección `legacy`, en lugar de ir con el valor por defecto de `bech32`, simplemente por consistencia. Esta es una situación en la que habría sido totalmente seguro generar una dirección Bech32 por defecto, simplemente usando `bitcoin-cli getrawchangeaddress`, porque sería enviada y recibida por usted en su nodo Bitcoin Core que lo soporta completamente. Pero, hobgoblins; cambiaremos esto a Bech32 también en [§4.6](04_6_Creando_una_Transaccion_Segwit.md).
|
||||
|
||||
Ahora tiene una dirección adicional dentro de tu monedero, ¡Para que pueda recibir cambio de un UTXO! Para usarlo, tendrá que crear una transacción en crudo con dos salidas.
|
||||
|
||||
## Escoger suficientes UTXOs
|
||||
|
||||
Nuestro ejemplo de transacción en crudo era simple en otro sentido: asumía que había suficiente dinero en un solo UTXO para cubrir la transacción. A menudo este será el caso, pero a veces querrá crear transacciones que gasten más dinero del que tiene en un solo UTXO. Para ello, debe crear una transacción cruda con dos (o más) entradas.
|
||||
|
||||
## Escribir una transacción en crudo real
|
||||
|
||||
Para resumir: crear una transacción real en crudo para enviar monedas a veces requerirá múltiples entradas y casi siempre requerirá múltiples salidas, una de las cuales es una dirección de cambio. Vamos a crear ese tipo de transacción más realista aquí, en un nuevo ejemplo que muestra un ejemplo real de envío de fondos a través de la segunda metodología de Bitcoin, las transacciones en bruto.
|
||||
|
||||
Vamos a utilizar nuestros UTXOs 0 y 2:
|
||||
```
|
||||
$ bitcoin-cli listunspent
|
||||
[
|
||||
[
|
||||
{
|
||||
"txid": "0619fecf6b2668fab1308fbd7b291ac210932602a6ac6b8cc11c7ae22c43701e",
|
||||
"vout": 1,
|
||||
"address": "mwJL7cRiW2bUnY81r1thSu3D4jtMmwyU6d",
|
||||
"label": "",
|
||||
"scriptPubKey": "76a914ad1ed1c5971b2308f89c1362d4705d020a40e8e788ac",
|
||||
"amount": 0.00899999,
|
||||
"confirmations": 1,
|
||||
"spendable": true,
|
||||
"solvable": true,
|
||||
"desc": "pkh([d6043800/0'/0'/4']03eae28c93035f95a620dd96e1822f2a96e0357263fa1f87606a5254d5b9e6698f)#wwnfx2sp",
|
||||
"safe": true
|
||||
},
|
||||
{
|
||||
"txid": "91261eafae15ea53dedbea7c1db748c52bbc04a85859ffd0d839bda1421fda4c",
|
||||
"vout": 0,
|
||||
"address": "mjehC2KHzXcBDcwTd4LhZ2GzyzrZ3Kd3ff",
|
||||
"label": "",
|
||||
"scriptPubKey": "76a9142d573900aa357a38afd741fbf24b075d263ea6e088ac",
|
||||
"amount": 0.00022000,
|
||||
"confirmations": 15,
|
||||
"spendable": true,
|
||||
"solvable": true,
|
||||
"desc": "pkh([d6043800/0'/0'/3']0278608b54b8fb0d8379d3823d31f03a7c6ab0adffb07dd3811819fdfc34f8c132)#nhjc3f8y",
|
||||
"safe": true
|
||||
},
|
||||
{
|
||||
"txid": "0df23a9dba49e822bbc558f15516f33021a64a5c2e48962cec541e0bcc79854d",
|
||||
"vout": 0,
|
||||
"address": "mwJL7cRiW2bUnY81r1thSu3D4jtMmwyU6d",
|
||||
"label": "",
|
||||
"scriptPubKey": "76a914ad1ed1c5971b2308f89c1362d4705d020a40e8e788ac",
|
||||
"amount": 0.00100000,
|
||||
"confirmations": 1,
|
||||
"spendable": true,
|
||||
"solvable": true,
|
||||
"desc": "pkh([d6043800/0'/0'/4']03eae28c93035f95a620dd96e1822f2a96e0357263fa1f87606a5254d5b9e6698f)#wwnfx2sp",
|
||||
"safe": true
|
||||
}
|
||||
]
|
||||
|
||||
```
|
||||
En nuestro ejemplo, vamos a enviar 0.009 BTC, que es (apenas) mayor que cualquiera de nuestros UTXOs. Esto requiere combinarlos, y luego usar nuestra dirección de cambio para recuperar los fondos no gastados.
|
||||
|
||||
### Configurar las variables
|
||||
|
||||
Ya tenemos las variables `$changeaddress` y `$recipient` de los ejemplos anteriores:
|
||||
```
|
||||
$ echo $changeaddress
|
||||
mk9ry5VVy8mrA8SygxSQQUDNSSXyGFot6h
|
||||
$ echo $recipient
|
||||
n2eMqTT929pb1RDNuqEnxdaLau1rxy3efi
|
||||
```
|
||||
También necesitamos registrar el txid y el vout para cada uno de nuestros dos UTXOs. Una vez identificados los UTXOs que queremos gastar, podemos utilizar nuestras técnicas JQ para asegurarnos de que el acceso a ellos está libre de errores:
|
||||
```
|
||||
$ utxo_txid_1=$(bitcoin-cli listunspent | jq -r '.[0] | .txid')
|
||||
$ utxo_vout_1=$(bitcoin-cli listunspent | jq -r '.[0] | .vout')
|
||||
$ utxo_txid_2=$(bitcoin-cli listunspent | jq -r '.[2] | .txid')
|
||||
$ utxo_vout_2=$(bitcoin-cli listunspent | jq -r '.[2] | .vout')
|
||||
```
|
||||
|
||||
### Escribir la transacción
|
||||
|
||||
Escribir la transacción en crudo es sorprendentemente sencillo. Todo lo que tiene que hacer es incluir un objeto JSON adicional, separado por comas, en la arreglo JSON de entradas y un par clave-valor adicional, separado por comas, en el objeto JSON de salidas.
|
||||
|
||||
Este es el ejemplo. Fíjese en las múltiples entradas después del argumento `inputs` y en las múltiples salidas después del argumento `outputs`.
|
||||
```
|
||||
$ rawtxhex2=$(bitcoin-cli -named createrawtransaction inputs='''[ { "txid": "'$utxo_txid_1'", "vout": '$utxo_vout_1' }, { "txid": "'$utxo_txid_2'", "vout": '$utxo_vout_2' } ]''' outputs='''{ "'$recipient'": 0.009, "'$changeaddress'": 0.0009 }''')
|
||||
```
|
||||
Fuimos _muy_ cuidadosos al calcular nuestro dinero. Estos dos UTXOs contienen 0.00999999 BTC. Después de enviar 0.009 BTC, nos quedarán .00099999 BTC. Elegimos .00009999 BTC como comisión de la transacción. Para acomodar esa tarifa, fijamos nuestro cambio en .0009 BTC. Si nos hubiéramos equivocado en las matemáticas y hubiéramos puesto el cambio a 0.00009 BTC, ¡Ese BTC adicional se perdería para los mineros! Si nos hubiéramos olvidado de hacer el cambio, todo el exceso habría desaparecido. Así que, de nuevo, _tenga cuidado_.
|
||||
|
||||
Afortunadamente, podemos hacer una triple comprobación con el alias `btctxfee` del Interludio JQ:
|
||||
```
|
||||
$ ./txfee-calc.sh $rawtxhex2
|
||||
.00009999
|
||||
```
|
||||
|
||||
### Finalizarlo
|
||||
|
||||
Ya puede firmar, sellar y entregar su transacción, y es suya (y del grifo):
|
||||
```
|
||||
$ signedtx2=$(bitcoin-cli -named signrawtransactionwithwallet hexstring=$rawtxhex2 | jq -r '.hex')
|
||||
$ bitcoin-cli -named sendrawtransaction hexstring=$signedtx2
|
||||
e7071092dee0b2ae584bf6c1ee3c22164304e3a17feea7a32c22db5603cd6a0d
|
||||
```
|
||||
|
||||
### Espera
|
||||
|
||||
Como es habitual, su dinero estará en el aire durante un tiempo: el cambio no estará disponible hasta que se confirme la transacción y se entregue un nuevo UTXO.
|
||||
|
||||
Pero, en 10 minutos o menos (probablemente), tendrá su dinero restante de vuelta y totalmente gastable de nuevo. Por ahora, seguimos esperando:
|
||||
```
|
||||
$ bitcoin-cli listunspent
|
||||
[
|
||||
{
|
||||
"txid": "91261eafae15ea53dedbea7c1db748c52bbc04a85859ffd0d839bda1421fda4c",
|
||||
"vout": 0,
|
||||
"address": "mjehC2KHzXcBDcwTd4LhZ2GzyzrZ3Kd3ff",
|
||||
"label": "",
|
||||
"scriptPubKey": "76a9142d573900aa357a38afd741fbf24b075d263ea6e088ac",
|
||||
"amount": 0.00022000,
|
||||
"confirmations": 15,
|
||||
"spendable": true,
|
||||
"solvable": true,
|
||||
"desc": "pkh([d6043800/0'/0'/3']0278608b54b8fb0d8379d3823d31f03a7c6ab0adffb07dd3811819fdfc34f8c132)#nhjc3f8y",
|
||||
"safe": true
|
||||
}
|
||||
]
|
||||
```
|
||||
Y el cambio llegará:
|
||||
```
|
||||
[
|
||||
{
|
||||
"txid": "e7071092dee0b2ae584bf6c1ee3c22164304e3a17feea7a32c22db5603cd6a0d",
|
||||
"vout": 1,
|
||||
"address": "mk9ry5VVy8mrA8SygxSQQUDNSSXyGFot6h",
|
||||
"scriptPubKey": "76a91432db726320e4ad170c9c1ee83cd4d8a243c3435988ac",
|
||||
"amount": 0.00090000,
|
||||
"confirmations": 1,
|
||||
"spendable": true,
|
||||
"solvable": true,
|
||||
"desc": "pkh([d6043800/0'/1'/2']02881697d252d8bf181d08c58de1f02aec088cd2d468fc5fd888c6e39909f7fabf)#p6k7dptk",
|
||||
"safe": true
|
||||
},
|
||||
{
|
||||
"txid": "91261eafae15ea53dedbea7c1db748c52bbc04a85859ffd0d839bda1421fda4c",
|
||||
"vout": 0,
|
||||
"address": "mjehC2KHzXcBDcwTd4LhZ2GzyzrZ3Kd3ff",
|
||||
"label": "",
|
||||
"scriptPubKey": "76a9142d573900aa357a38afd741fbf24b075d263ea6e088ac",
|
||||
"amount": 0.00022000,
|
||||
"confirmations": 16,
|
||||
"spendable": true,
|
||||
"solvable": true,
|
||||
"desc": "pkh([d6043800/0'/0'/3']0278608b54b8fb0d8379d3823d31f03a7c6ab0adffb07dd3811819fdfc34f8c132)#nhjc3f8y",
|
||||
"safe": true
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
Este también podría ser un buen momento para volver a ver un explorador de blockchain, para que pueda ver de forma más intuitiva cómo están dispuestas las entradas, salidas y la tasa de transacción: [e7071092dee0b2ae584bf6c1ee3c22164304e3a17feea7a32c22db5603cd6a0d](https://live.blockcypher.com/btc-testnet/tx/e7071092dee0b2ae584bf6c1ee3c22164304e3a17feea7a32c22db5603cd6a0d/).
|
||||
|
||||
## Resumen: Envío de monedas con transacciones crudas
|
||||
|
||||
Para enviar monedas con transacciones en crudo, necesita crear una transacción en crudo con una o más entradas (para tener fondos suficientes) y una o más salidas (para recuperar el cambio). Entonces, puede seguir el procedimiento normal de usar `createrawtransaction` con argumentos nombrados y JQ, como se ha expuesto en las secciones anteriores.
|
||||
|
||||
> 🔥 ___¿Cuál es el poder de enviar monedas con transacciones en crudo?___
|
||||
|
||||
> _Las ventajas._ Le otorga el mejor control. Si su objetivo es escribir un script o programa de Bitcoin más complejo, probablemente utilizará transacciones en crudo para saber exactamente lo que está pasando. Esta es también la situación _más segura_ para usar transacciones en crudo, porque puede asegurarse programáticamente de no cometer errores.
|
||||
|
||||
> _Las desventajas._ Es fácil perder dinero. No hay advertencias, no hay salvaguardias, y no hay respaldos programáticos a menos que usted los escriba. También es arcaico. El formato es odioso, incluso usando la interfaz `bitcoin-cli`, que es muy fácil de usar, y tiene que hacer muchas búsquedas y cálculos a mano.
|
||||
|
||||
## ¿Qué sigue?
|
||||
|
||||
Vea otra forma alternativa de introducir comandos con [Interludio: Usando Curl](04_4_Interludio_Usando_Curl.md).
|
||||
|
||||
O, si prefiere saltarse lo que es francamente una paréntesis, aprende una forma más de "Enviar Transacciones Bitcoin" con [§4.5: Enviando Monedas con Transacciones Crudas Automatizadas](04_5_Enviando_Monedas_con_Transacciones_Crudas_Automatizadas.md).
|
||||
|
315
es/04_4_Interludio_Usando_Curl.md
Normal file
315
es/04_4_Interludio_Usando_Curl.md
Normal file
@ -0,0 +1,315 @@
|
||||
# Interludio: Usando Curl
|
||||
|
||||
`bitcoin-cli` es, en última instancia, sólo una envoltura. Es una forma de interactuar con `bitcoind` desde la línea de comandos, proporcionando un acceso simplificado a sus muchos comandos RPC. Pero el RPC puede, por supuesto, ser accedido directamente. De eso trata este interludio: de conectar directamente con RPC con el comando `curl`.
|
||||
|
||||
No se usará mucho en los próximos capítulos, pero es un bloque importante que puede ver como un acceso alternativo a `bitcoind` si así lo prefiere.
|
||||
|
||||
## Conoce Curl
|
||||
|
||||
`curl`, abreviatura de "see URL", es una herramienta de línea de comandos que permite acceder directamente a las URLs de forma programática. Es una forma fácil de interactuar con servidores como `bitcoind` que escuchan puertos en Internet y que hablan una variedad de protocolos. Curl también está disponible como biblioteca para muchos lenguajes de programación, como C, Java, PHP y Python. Así que, una vez que sepa cómo trabajar con Curl, tendrá una base sólida para utilizar un montón de API diferentes.
|
||||
|
||||
Para usar `curl` con `bitcoind`, debe saber tres cosas: el formato estándar, el nombre de usuario y la contraseña, y el puerto correcto.
|
||||
|
||||
### Conocer el formato
|
||||
|
||||
Los comandos de `bitcoin-cli` están todos vinculados a comandos RPC en `bitcoind`. Esto hace que la transición de usar `bitcoin-cli` a usar `curl` sea muy sencilla. De hecho, si mira cualquiera de las páginas de ayuda de `bitcoin-cli`, verá que no sólo enumeran los comandos de `bitcoin-cli`, sino también los comandos paralelos de `curl`. Por ejemplo, aquí está `bitcoin-cli help getmininginfo`:
|
||||
```
|
||||
$ bitcoin-cli help getmininginfo
|
||||
getmininginfo
|
||||
|
||||
Returns a json object containing mining-related information.
|
||||
Result:
|
||||
{ (json object)
|
||||
"blocks" : n, (numeric) The current block
|
||||
"currentblockweight" : n, (numeric, optional) The block weight of the last assembled block (only present if a block was ever assembled)
|
||||
"currentblocktx" : n, (numeric, optional) The number of block transactions of the last assembled block (only present if a block was ever assembled)
|
||||
"difficulty" : n, (numeric) The current difficulty
|
||||
"networkhashps" : n, (numeric) The network hashes per second
|
||||
"pooledtx" : n, (numeric) The size of the mempool
|
||||
"chain" : "str", (string) current network name (main, test, regtest)
|
||||
"warnings" : "str" (string) any network and blockchain warnings
|
||||
}
|
||||
|
||||
Examples:
|
||||
> bitcoin-cli getmininginfo
|
||||
> curl --user myusername --data-binary '{"jsonrpc": "1.0", "id": "curltest", "method": "getmininginfo", "params": []}' -H 'content-type: text/plain;' http://127.0.0.1:8332/
|
||||
```
|
||||
Y ahí está el comando `curl`, al final de la pantalla de ayuda. Este comando algo largo tiene cuatro partes principales: (1) un listado con tu nombre de usuario; (2) una bandera `--data-binary`; (3) un objeto JSON que le dice a `bitcoind` lo que debe hacer, incluyendo una arreglo JSON de parámetros; y (4) una cabecera HTTP que incluye la URL de `bitcoind`.
|
||||
|
||||
Cuando trabaje con `curl`, la mayoría de estos argumentos para `curl` serán los mismos de un comando a otro; sólo las entradas `method` y `params` del array JSON cambiarán normalmente. Sin embargo, ¡Necesita saber cómo rellenar su nombre de usuario y su dirección URL para que funcione en primer lugar!
|
||||
|
||||
_Siempre que no esté seguro de cómo ejecutar un comando RPC, sólo tiene que mirar la ayuda de bitcoin-cli y partir de ahí._
|
||||
|
||||
### Conozca su Nombre de Usuario
|
||||
|
||||
Para hablar con el puerto `bitcoind`, necesita un nombre de usuario y una contraseña. Estos fueron creados como parte de su configuración inicial de Bitcoin, y se pueden encontrar en `~/.bitcoin/bitcoin.conf`.
|
||||
|
||||
Por ejemplo, esta es nuestra configuración actual:
|
||||
```
|
||||
$ cat ~/.bitcoin/bitcoin.conf
|
||||
server=1
|
||||
dbcache=1536
|
||||
par=1
|
||||
maxuploadtarget=137
|
||||
maxconnections=16
|
||||
rpcuser=StandUp
|
||||
rpcpassword=8eaf562eaf45c33c3328bc66008f2dd1
|
||||
rpcallowip=127.0.0.1
|
||||
debug=tor
|
||||
prune=550
|
||||
testnet=1
|
||||
mintxfee=0.001
|
||||
txconfirmtarget=1
|
||||
[test]
|
||||
rpcbind=127.0.0.1
|
||||
rpcport=18332
|
||||
[main]
|
||||
rpcbind=127.0.0.1
|
||||
rpcport=8332
|
||||
[regtest]
|
||||
rpcbind=127.0.0.1
|
||||
rpcport=18443
|
||||
```
|
||||
Nuestro nombre de usuario es `StandUp` y nuestra contraseña es `8eaf562eaf45c33c3328bc66008f2dd1`.
|
||||
|
||||
> **AVISO:** Claramente, no es muy seguro tener esta información en un archivo de texto plano. A partir de Bitcoin Core 0.12, puede omitir la `rpcpassword` de su archivo `bitcoin.conf`, y hacer que `bitcoind` genere una nueva cookie cada vez que se inicie. La desventaja de esto es que dificulta el uso de comandos RPC por parte de otras aplicaciones, como las que se detallan en este capítulo. Por lo tanto, vamos a quedarnos con la información simple de `rpcuser` y `rpcpassword` por ahora, pero para el software de producción, considera pasar a las cookies.
|
||||
|
||||
La forma segura de hacer RPC con `bitcoind` es la siguiente:
|
||||
```
|
||||
$ curl --user StandUp --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "getmininginfo", "params": [] }' -H 'content-type: text/plain;' http://127.0.0.1:18332/
|
||||
Enter host password for user 'bitcoinrpc':
|
||||
```
|
||||
Como se ha señalado, se le pedirá la contraseña.
|
||||
|
||||
> 🔗 **TESTNET vs MAINNET:** Testnet utiliza una URL con el puerto 18332 y mainnet utiliza una URL con el puerto 8332. Echa un vistazo a su `bitcoin.conf`, está todo dispuesto allí.
|
||||
|
||||
La forma insegura de hacerlo es la siguiente:
|
||||
```
|
||||
$ curl --user StandUp:8eaf562eaf45c33c3328bc66008f2dd1 --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "getmininginfo", "params": [] }' -H 'content-type: text/plain;' http://127.0.0.1:18332/
|
||||
```
|
||||
> **AVISO:** Introducir su contraseña en la línea de comandos puede poner su contraseña en la tabla de procesos y/o guardarla en un historial. Esto es aún menos recomendable que ponerla en un archivo, excepto para pruebas en testnet. Si quiere hacerlo en cualquier otro lugar, ¡Asegúrese de saber lo que está haciendo!
|
||||
|
||||
### Conociendo los Comandos y Parámetros
|
||||
|
||||
Con todo esto en la mano, está listo para enviar comandos RPC estándar con `curl` ... pero todavía necesita saber cómo incorporar los dos elementos que tienden a cambiar en el comando `curl`.
|
||||
|
||||
El primero es `method`, que es el método RPC que se utiliza. Por lo general, debería coincidir con los nombres de los comandos que has estado introduciendo en `bitcoin-cli` durante años.
|
||||
|
||||
El segundo es `params`, que es una arreglo JSON de parámetros. Estos son los mismos que los argumentos (o argumentos con nombre) que ha estado utilizando. También son la parte más confusa de `curl`, en gran parte porque son una arreglo estructurada en lugar de una simple lista.
|
||||
|
||||
Así es como se ven algunos arreglos de parámetros:
|
||||
|
||||
* `[]` — Un arreglo vacío
|
||||
* `["000b4430a7a2ba60891b01b718747eaf9665cb93fbc0c619c99419b5b5cf3ad2"]` — Un arreglo con datos
|
||||
* `["'$signedhex'"]` — Un arreglo con una varible
|
||||
* `[6, 9999999]` — Un arreglo con parametros
|
||||
* `{}` - Un objeto vacío
|
||||
* `[''[ { "txid": "'$utxo_txid'", "vout": '$utxo_vout' } ]'', ''{ "'$recipient'": 0.298, "'$changeaddress'": 1.0}'']` — Un arreglo con una arreglo que contiene un objeto y un objeto vacío
|
||||
|
||||
## Obtener información
|
||||
|
||||
Ahora puede enviar su primer comando `curl` accediendo al RPC `getmininginfo`:
|
||||
|
||||
```
|
||||
$ curl --user StandUp:8eaf562eaf45c33c3328bc66008f2dd1 --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "getmininginfo", "params": [] }' -H 'content-type: text/plain;' http://127.0.0.1:18332/
|
||||
{"result":{"blocks":1772428,"difficulty":10178811.40698772,"networkhashps":91963587385939.06,"pooledtx":61,"chain":"test","warnings":"Warning: unknown new rules activated (versionbit 28)"},"error":null,"id":"curltest"}
|
||||
```
|
||||
Tenga en cuenta que proporcionamos el método, `getmininginfo`, y el parámetro,`[]`, pero que todo lo demás era la línea de comando estándar` curl`.
|
||||
|
||||
> **AVISO:** Si obtiene un resultado como "Failed to connect to 127.0.0.1 port 8332: Connection refused", asegúrese de que una línea como `rpcallowip=127.0.0.1` está en su ~/.bitcoin/bitcoin.conf. Si las cosas siguen sin funcionar, asegúrese de que está permitiendo el acceso al puerto 18332 (o 8332) desde localhost. Nuestra configuración estándar del [2.0: Configuración de un Servidor Privado Virtual de Bitcoin-Core](02_0_Configurando_un_Bitcoin-Core_VPS.md) debería hacer todo esto.
|
||||
|
||||
El resultado es otro arreglo JSON, que desafortunadamente es feo de leer si está usando `curl` a mano. Afortunadamente, puede limpiarlo simplemente pasándolo por `jq`:
|
||||
```
|
||||
$ curl --user StandUp:8eaf562eaf45c33c3328bc66008f2dd1 --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "getmininginfo", "params": [] }' -H 'content-type: text/plain;' http://127.0.0.1:18332/ | jq -r '.'
|
||||
% Total % Received % Xferd Average Speed Time Time Time Current
|
||||
Dload Upload Total Spent Left Speed
|
||||
100 295 100 218 100 77 72666 25666 --:--:-- --:--:-- --:--:-- 98333
|
||||
{
|
||||
"result": {
|
||||
"blocks": 1772429,
|
||||
"difficulty": 10178811.40698772,
|
||||
"networkhashps": 90580030969896.44,
|
||||
"pooledtx": 4,
|
||||
"chain": "test",
|
||||
"warnings": "Warning: unknown new rules activated (versionbit 28)"
|
||||
},
|
||||
"error": null,
|
||||
"id": "curltest"
|
||||
}
|
||||
```
|
||||
Verá un poco de información de conectividad a medida que se descargan los datos, luego cuando esos datos lleguen a `jq`, todo saldrá en una forma correctamente indentada. (Omitiremos la información de descarga en futuros ejemplos).
|
||||
|
||||
## Manipular su monedero
|
||||
|
||||
Aunque esté accediendo directamente a `bitcoind`, seguirá teniendo acceso a la funcionalidad del monedero, ya que ésta se almacena en gran parte en el propio `bitcoind`.
|
||||
|
||||
### Buscar direcciones
|
||||
|
||||
Usa el RPC `getaddressesbylabel` para listar todas sus direcciones actuales:
|
||||
```
|
||||
$ curl --user StandUp:8eaf562eaf45c33c3328bc66008f2dd1 --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "getaddressesbylabel", "params": [""] }' -H 'content-type: text/plain;' http://127.0.0.1:18332/ | jq -r '.'
|
||||
{
|
||||
"result": {
|
||||
"mi25UrzHnvn3bpEfFCNqJhPWJn5b77a5NE": {
|
||||
"purpose": "receive"
|
||||
},
|
||||
"mjehC2KHzXcBDcwTd4LhZ2GzyzrZ3Kd3ff": {
|
||||
"purpose": "receive"
|
||||
},
|
||||
"moKVV6XEhfrBCE3QCYq6ppT7AaMF8KsZ1B": {
|
||||
"purpose": "receive"
|
||||
},
|
||||
"mwJL7cRiW2bUnY81r1thSu3D4jtMmwyU6d": {
|
||||
"purpose": "receive"
|
||||
},
|
||||
"tb1q5gnwrh7ss5mmqt0qfan85jdagmumnatcscwpk6": {
|
||||
"purpose": "receive"
|
||||
},
|
||||
"tb1qmtucvjtga68kgrvkl7q05x4t9lylxhku7kqdpr": {
|
||||
"purpose": "receive"
|
||||
}
|
||||
},
|
||||
"error": null,
|
||||
"id": "curltest"
|
||||
}
|
||||
```
|
||||
Este es nuestro primer ejemplo de un parámetro real, `""`. Este es el parámetro requerido `label` para `getaddressesbylabel`, pero todas nuestras direcciones están bajo la etiqueta por defecto, así que no se requiere nada especial aquí.
|
||||
|
||||
El resultado es una lista de todas las direcciones que han sido utilizadas por este monedero... algunas de las cuales presumiblemente contienen fondos.
|
||||
|
||||
### Buscar fondos
|
||||
|
||||
Utilice el RPC `listunspent` para listar los fondos que tiene disponibles:
|
||||
```
|
||||
$ curl --user StandUp:8eaf562eaf45c33c3328bc66008f2dd1 --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "listunspent", "params": [] }' -H 'content-type: text/plain;' http://127.0.0.1:18332/ | jq -r '.'
|
||||
{
|
||||
"result": [
|
||||
{
|
||||
"txid": "e7071092dee0b2ae584bf6c1ee3c22164304e3a17feea7a32c22db5603cd6a0d",
|
||||
"vout": 1,
|
||||
"address": "mk9ry5VVy8mrA8SygxSQQUDNSSXyGFot6h",
|
||||
"scriptPubKey": "76a91432db726320e4ad170c9c1ee83cd4d8a243c3435988ac",
|
||||
"amount": 0.0009,
|
||||
"confirmations": 4,
|
||||
"spendable": true,
|
||||
"solvable": true,
|
||||
"desc": "pkh([d6043800/0'/1'/2']02881697d252d8bf181d08c58de1f02aec088cd2d468fc5fd888c6e39909f7fabf)#p6k7dptk",
|
||||
"safe": true
|
||||
},
|
||||
{
|
||||
"txid": "91261eafae15ea53dedbea7c1db748c52bbc04a85859ffd0d839bda1421fda4c",
|
||||
"vout": 0,
|
||||
"address": "mjehC2KHzXcBDcwTd4LhZ2GzyzrZ3Kd3ff",
|
||||
"label": "",
|
||||
"scriptPubKey": "76a9142d573900aa357a38afd741fbf24b075d263ea6e088ac",
|
||||
"amount": 0.00022,
|
||||
"confirmations": 19,
|
||||
"spendable": true,
|
||||
"solvable": true,
|
||||
"desc": "pkh([d6043800/0'/0'/3']0278608b54b8fb0d8379d3823d31f03a7c6ab0adffb07dd3811819fdfc34f8c132)#nhjc3f8y",
|
||||
"safe": true
|
||||
}
|
||||
],
|
||||
"error": null,
|
||||
"id": "curltest"
|
||||
}
|
||||
```
|
||||
Esta es casi la misma salida que recibe cuando escribe `bitcoin-cli listunspent`, lo que demuestra lo estrechamente ligadas que están las dos interfaces. Si no se necesita ninguna limpieza o ayuda extra, entonces `bitcoin-cli` sólo muestra la RPC. ¡Fácil!
|
||||
|
||||
### Crear una dirección
|
||||
|
||||
Después de saber dónde están sus fondos, el siguiente paso en la elaboración de una transacción es conseguir una dirección de cambio. A estas alturas, probablemente ya se haya hecho a la idea, y sabe que para los comandos RPC simples, todo lo que necesita hacer es ajustar el `method` es el comando `curl`:
|
||||
|
||||
```
|
||||
$ curl --user StandUp:8eaf562eaf45c33c3328bc66008f2dd1 --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "getrawchangeaddress", "params": ["", "legacy"] }' -H 'content-type: text/plain;' http://127.0.0.1:18332/ | jq -r '.'
|
||||
{
|
||||
"result": "mrSqN37TPs89GcidSZTvXmMzjxoJZ6RKoz",
|
||||
"error": null,
|
||||
"id": "curltest"
|
||||
}
|
||||
```
|
||||
|
||||
En este punto, podemos incluso volver a nuestra práctica estándar de guardar los resultados en variables con la ayuda adicional de `jq`:
|
||||
```
|
||||
$ changeaddress=$(curl --user StandUp:8eaf562eaf45c33c3328bc66008f2dd1 --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "getrawchangeaddress", "params": ["", "legacy"] }' -H 'content-type: text/plain;' http://127.0.0.1:18332/ | jq -r '.result')
|
||||
$ echo $changeaddress
|
||||
mqdfnjgWr2r3sCCeuTDfe8fJ1CnycF2e6R
|
||||
```
|
||||
No hay que preocuparse por la información de la descarga. Irá a `STDERR` y se mostrará en su pantalla, mientras que los resultados van a `STDOUT` y se guardan en su variable.
|
||||
|
||||
## Crear una Transacción
|
||||
|
||||
Ahora está listo para crear una transacción con `curl`.
|
||||
|
||||
### Prepare sus variables
|
||||
|
||||
Al igual que con `bitcoin-cli`, para crear una transacción curlando comandos RPC, primero debe guardar sus variables. El único cambio aquí es que `curl` crea un objeto JSON que incluye un valor-clave `resultado`, por lo que siempre hay que pasar la etiqueta `.resultado` antes de hacer cualquier otra cosa.
|
||||
|
||||
Este ejemplo configura nuestras variables para utilzar los 1.2985 BTC en fondos que aparecen en la primera transacción no gastada anterior:
|
||||
```
|
||||
$ utxo_txid=$(curl --user StandUp:8eaf562eaf45c33c3328bc66008f2dd1 --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "listunspent", "params": [] }' -H 'content-type: text/plain;' http://127.0.0.1:18332/ | jq -r '.result | .[0] | .txid')
|
||||
$ utxo_vout=$(curl --user StandUp:8eaf562eaf45c33c3328bc66008f2dd1 --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "listunspent", "params": [] }' -H 'content-type: text/plain;' http://127.0.0.1:18332/ | jq -r '.result | .[0] | .vout')
|
||||
$ recipient=mwCwTceJvYV27KXBc3NJZys6CjsgsoeHmf
|
||||
$ changeaddress=$(curl --user StandUp:8eaf562eaf45c33c3328bc66008f2dd1 --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "getrawchangeaddress", "params": ["legacy"] }' -H 'content-type: text/plain;' http://127.0.0.1:18332/ | jq -r '.result')
|
||||
|
||||
$ echo $utxo_txid
|
||||
e7071092dee0b2ae584bf6c1ee3c22164304e3a17feea7a32c22db5603cd6a0d
|
||||
$ echo $utxo_vout
|
||||
1
|
||||
$ echo $recipient
|
||||
mwCwTceJvYV27KXBc3NJZys6CjsgsoeHmf
|
||||
$ echo $changeaddress
|
||||
n2jf3MzeFpFGa7wq8rXKVnVuv5FoNSJZ1N
|
||||
```
|
||||
|
||||
### Crear la transacción
|
||||
|
||||
La transacción creada con `curl` es muy similar a la transacción creada con `bitcoin-cli`, pero con algunas sutiles diferencias:
|
||||
```
|
||||
$ curl --user StandUp:8eaf562eaf45c33c3328bc66008f2dd1 --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "createrawtransaction", "params": [''[ { "txid": "'$utxo_txid'", "vout": '$utxo_vout' } ]'', ''{ "'$recipient'": 0.0003, "'$changeaddress'": 0.0005}'']}' -H 'content-type: text/plain;' http://127.0.0.1:18332/ | jq -r '.'
|
||||
{
|
||||
"result": "02000000010d6acd0356db222ca3a7ee7fa1e3044316223ceec1f64b58aeb2e0de921007e70100000000ffffffff0230750000000000001976a914ac19d3fd17710e6b9a331022fe92c693fdf6659588ac50c30000000000001976a9147021efec134057043386decfaa6a6aa4ee5f19eb88ac00000000",
|
||||
"error": null,
|
||||
"id": "curltest"
|
||||
}
|
||||
```
|
||||
El corazón de la transacción es, por supuesto, el arreglo JSON `params`, que estamos poniendo en uso por primera vez.
|
||||
|
||||
Observa que todo el `params` está alojado en `[]`s para marcar el arreglo de parámetros.
|
||||
|
||||
También hemos variado las citas de cómo funcionaban las cosas en `bitcoin-cli`, para empezar y terminar cada arreglo y objeto dentro del arreglo `params` con `''` en lugar de nuestro tradicional `'''`. Esto se debe a que todo el conjunto de argumentos JSON ya tiene un `'` alrededor. Como de costumbre, sólo hay que echar un vistazo a las extrañas citas del shell y acostumbrarse a ellas.
|
||||
|
||||
Sin embargo, hay una última cosa a tener en cuenta en este ejemplo, y puede ser _enfadante_ si se lo pierde. Cuando ejecutaba un comando `createrawtransaction` con `bitcoin-cli` el arreglo JSON de entradas y el objeto JSON de salidas eran cada uno parámetros distintos, por lo que estaban separados por un espacio. Ahora, como son parte de ese arreglo JSON `params`, están separados por una coma (`,`). Si no lo hace, obtendrá un "error de análisis" sin mucha información adicional.
|
||||
|
||||
> **AVISO:** ¿Alguna vez ha tenido problemas para depurar su `curl`? Añade el argumento `--trace-ascii /tmp/foo`. La información completa de lo que se envía al servidor se guardará en `/tmp/foo` (o cualquier nombre de archivo que proporcione).
|
||||
|
||||
Habiendo verificado que las cosas funcionan, probablemente quiera guardar el código hexadecimal en una variable:
|
||||
```
|
||||
$ hexcode=$(curl --user StandUp:8eaf562eaf45c33c3328bc66008f2dd1 --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "createrawtransaction", "params": [''[ { "txid": "'$utxo_txid'", "vout": '$utxo_vout' } ]'', ''{ "'$recipient'": 0.0003, "'$changeaddress'": 0.0005}'']}' -H 'content-type: text/plain;' http://127.0.0.1:18332/ | jq -r '.result')
|
||||
```
|
||||
|
||||
### Firmar y enviar
|
||||
|
||||
Firmar y enviar su transacción usando `curl` es un uso sencillo del RPC `signrawtransactionwithwallet` y `sendrawtransaction`:
|
||||
|
||||
```
|
||||
$ signedhex=$(curl --user StandUp:8eaf562eaf45c33c3328bc66008f2dd1 --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "signrawtransactionwithwallet", "params": ["'$hexcode'"] }' -H 'content-type: text/plain;' http://127.0.0.1:18332/ | jq -r '.result | .hex')
|
||||
|
||||
$ curl --user StandUp:8eaf562eaf45c33c3328bc66008f2dd1 --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "sendrawtransaction", "params": ["'$signedhex'"] }' -H 'content-type: text/plain;' http://127.0.0.1:18332/ | jq -r '.'
|
||||
{
|
||||
"result": "eb84c5008038d760805d4d9644ace67849542864220cb2685a1ea2c64176b82d",
|
||||
"error": null,
|
||||
"id": "curltest"
|
||||
}
|
||||
```
|
||||
## Resumen: Accediendo a Bitcoind con Curl
|
||||
|
||||
Una vez terminada esta sección, puede que sienta que acceder a `bitcoind` a través de `curl` es muy parecido a acceder a través de `bitcoin-cli` ... pero más engorroso. Y, tendría razón. `bitcoin-cli` tiene una funcionalidad RPC bastante completa, así que cualquier cosa que haga a través de `curl` probablemente pueda hacerla a través de `bitcoin-cli`. Por eso vamos a seguir concentrándonos en `bitcoin-cli` después de este paréntesis.
|
||||
|
||||
Pero todavía hay razones para usar `curl` en lugar de `bitcoin-cli`:
|
||||
|
||||
Lo más obvio es que `curl` elimina un nivel de indirección. En lugar de trabajar con `bitcoin-cli` que envía comandos RPC a `bitcoind`, está enviando esos comandos RPC directamente. Esto permite una programación más robusta, porque no tiene que preocuparse de las cosas inesperadas que pueda hacer `bitcoin-cli` o de cómo pueda cambiar con el tiempo. Sin embargo, también usted está dando sus primeros pasos hacia el uso de un lenguaje de programación más completo que las pobres opciones que ofrece un script de shell. Como verá en los últimos capítulos de esto, podría ver que las librerías curl son otras funciones para acceder a los comandos RPC en una variedad de lenguajes de programación: pero eso está todavía muy lejos.
|
||||
|
||||
## ¿Qué sigue?
|
||||
|
||||
Conozca una forma más de "Enviar Transacciones Bitcoin" con [§4.5: Enviando Monedas con Transacciones Crudas Automatizadas](04_5_Enviando_Monedas_con_Transacciones_Crudas_Automatizadas.md).
|
@ -0,0 +1,173 @@
|
||||
# 4.5: Enviando Monedas con Transacciones Crudas Automatizadas
|
||||
|
||||
Este capítulo expone tres formas de enviar fondos a través de la interfaz cli de Bitcoin. [§4.1](04_1_Enviando_Monedas_de_la_Forma_Facil.md) describe cómo hacerlo con un simple comando, y [§4.4](04_4_Enviando_Monedas_con_una_Transaccion_Cruda.md) detalla cómo usar una transacción en crudo más peligrosa. Esta sección final divide la diferencia mostrando cómo hacer que las transacciones crudas sean más simples y seguras.
|
||||
|
||||
## Deje que Bitcoin calcule por usted
|
||||
|
||||
La metodología para automatizar las transacciones en crudo es sencilla: usted crea una transacción en crudo, pero utiliza el comando `fundrawtransaction` para pedir a bitcoind que realice los cálculos por usted.
|
||||
|
||||
Para utilizar este comando, tendrá que asegurarse de que tu archivo ~/.bitcoin/bitcoin.conf contiene variables racionales para calcular las tasas de las transacciones. Por favor, consulta [§4.1: Enviando Monedas de la Forma Fácil](04_1_Enviando_Monedas_de_la_Forma_Facil.md) para más información al respecto.
|
||||
|
||||
Para números muy conservadores, sugerimos añadir lo siguiente al `bitcoin.conf`:
|
||||
```
|
||||
mintxfee=0.0001
|
||||
txconfirmtarget=6
|
||||
```
|
||||
Para que el tutorial siga avanzando (y, en general, para que el dinero se mueva con rapidez) sugerimos lo siguiente:
|
||||
```
|
||||
mintxfee=0.001
|
||||
txconfirmtarget=1
|
||||
```
|
||||
|
||||
## Crear una transacción básica en crudo
|
||||
|
||||
Para utilizar `fundrawtransaction`, primero debe crear una transacción básica que no contenga ninguna entrada ni ninguna dirección de cambio. Sólo debe indicar el destinatario y la cantidad que desea enviarle, en este caso "destinatario" y "0.0002" BTC.
|
||||
```
|
||||
$ recipient=n2eMqTT929pb1RDNuqEnxdaLau1rxy3efi
|
||||
$ unfinishedtx=$(bitcoin-cli -named createrawtransaction inputs='''[]''' outputs='''{ "'$recipient'": 0.0002 }''')
|
||||
```
|
||||
|
||||
## Financiar su transacción básica
|
||||
|
||||
A continuación, se le indica a `bitcoin-cli` que financie esa transacción básica:
|
||||
```
|
||||
$ bitcoin-cli -named fundrawtransaction hexstring=$unfinishedtx
|
||||
{
|
||||
"hex": "02000000012db87641c6a21e5a68b20c226428544978e6ac44964d5d8060d7388000c584eb0100000000feffffff02204e0000000000001976a914e7c1345fc8f87c68170b3aa798a956c2fe6a9eff88ac781e0000000000001600140cc9cdcf45d4ea17f5227a7ead52367aad10a88400000000",
|
||||
"fee": 0.00022200,
|
||||
"changepos": 1
|
||||
}
|
||||
```
|
||||
Esto proporciona mucha información útil, pero una vez que esté seguro de cómo funciona, querrá usar JQ para guardar su hex en una variable, como de costumbre:
|
||||
```
|
||||
$ rawtxhex3=$(bitcoin-cli -named fundrawtransaction hexstring=$unfinishedtx | jq -r '.hex')
|
||||
```
|
||||
## Verifique la transacción financiada
|
||||
|
||||
Parece magia, así que las primeras veces que use `fundrawtransaction`, probablemente querrá verificarla.
|
||||
|
||||
Ejecutar `decoderawtransaction` mostrará que la transacción en crudo está ahora dispuesta correctamente, utilizando uno o más de sus UTXOs y enviando los fondos sobrantes a una dirección de cambio:
|
||||
```
|
||||
$ bitcoin-cli -named decoderawtransaction hexstring=$rawtxhex3
|
||||
{
|
||||
"txid": "b3b4c2057dbfbef6690e975ede92fde805ddea13c730f58401939a52c9ac1b99",
|
||||
"hash": "b3b4c2057dbfbef6690e975ede92fde805ddea13c730f58401939a52c9ac1b99",
|
||||
"version": 2,
|
||||
"size": 116,
|
||||
"vsize": 116,
|
||||
"weight": 464,
|
||||
"locktime": 0,
|
||||
"vin": [
|
||||
{
|
||||
"txid": "eb84c5008038d760805d4d9644ace67849542864220cb2685a1ea2c64176b82d",
|
||||
"vout": 1,
|
||||
"scriptSig": {
|
||||
"asm": "",
|
||||
"hex": ""
|
||||
},
|
||||
"sequence": 4294967294
|
||||
}
|
||||
],
|
||||
"vout": [
|
||||
{
|
||||
"value": 0.00020000,
|
||||
"n": 0,
|
||||
"scriptPubKey": {
|
||||
"asm": "OP_DUP OP_HASH160 e7c1345fc8f87c68170b3aa798a956c2fe6a9eff OP_EQUALVERIFY OP_CHECKSIG",
|
||||
"hex": "76a914e7c1345fc8f87c68170b3aa798a956c2fe6a9eff88ac",
|
||||
"reqSigs": 1,
|
||||
"type": "pubkeyhash",
|
||||
"addresses": [
|
||||
"n2eMqTT929pb1RDNuqEnxdaLau1rxy3efi"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"value": 0.00007800,
|
||||
"n": 1,
|
||||
"scriptPubKey": {
|
||||
"asm": "0 a782f4c6e1e75a5b24f3d675d6f11b5ebf3b2142",
|
||||
"hex": "0014a782f4c6e1e75a5b24f3d675d6f11b5ebf3b2142",
|
||||
"reqSigs": 1,
|
||||
"type": "witness_v0_keyhash",
|
||||
"addresses": [
|
||||
"tb1q57p0f3hpuad9kf8n6e6adugmt6lnkg2zzr592r"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
Una cosa de interés aquí es la dirección de cambio, que es la segunda `vout`. Observe que es una dirección `tb1`, lo que significa que es Bech32; cuando le dimos a Bitcoin Core la capacidad total de gestionar nuestro cambio, lo hizo usando su tipo de dirección por defecto, Bech32, y funcionó bien. Por eso nuestro cambio a direcciones SegWit en [§4.6](04_6_Creando_una_Transaccion_Segwit.md) realmente no es gran cosa, pero hay algunos inconvenientes para un uso más amplio, de los que hablaremos allí.
|
||||
|
||||
Aunque vimos la tasa en la salida de `fundrawtransaction`, no es visible aquí. Sin embargo, puede verificarlo con el script JQ `txfee-calc.sh` creado en el [Interludio: Usando JQ](04_2_Interludio_Usando_JQ.md):
|
||||
```
|
||||
$ ~/txfee-calc.sh $rawtxhex3
|
||||
.000222
|
||||
```
|
||||
Por último, puede utilizar `getaddressinfo` para comprobar que la dirección de cambio generada le pertenece realmente:
|
||||
```
|
||||
$ bitcoin-cli -named getaddressinfo address=tb1q57p0f3hpuad9kf8n6e6adugmt6lnkg2zzr592r
|
||||
{
|
||||
"address": "tb1q57p0f3hpuad9kf8n6e6adugmt6lnkg2zzr592r",
|
||||
"scriptPubKey": "0014a782f4c6e1e75a5b24f3d675d6f11b5ebf3b2142",
|
||||
"ismine": true,
|
||||
"solvable": true,
|
||||
"desc": "wpkh([d6043800/0'/1'/10']038a2702938e548eaec28feb92c7e4722042cfd1ea16bec9fc274640dc5be05ec5)#zpv26nar",
|
||||
"iswatchonly": false,
|
||||
"isscript": false,
|
||||
"iswitness": true,
|
||||
"witness_version": 0,
|
||||
"witness_program": "a782f4c6e1e75a5b24f3d675d6f11b5ebf3b2142",
|
||||
"pubkey": "038a2702938e548eaec28feb92c7e4722042cfd1ea16bec9fc274640dc5be05ec5",
|
||||
"ischange": true,
|
||||
"timestamp": 1592335137,
|
||||
"hdkeypath": "m/0'/1'/10'",
|
||||
"hdseedid": "fdea8e2630f00d29a9d6ff2af7bf5b358d061078",
|
||||
"hdmasterfingerprint": "d6043800",
|
||||
"labels": [
|
||||
]
|
||||
}
|
||||
```
|
||||
Observe los resultados del `ismine`.
|
||||
|
||||
## Envíe la transacción financiada
|
||||
|
||||
En este punto puede firmar y enviar la transacción como de costumbre.
|
||||
```
|
||||
$ signedtx3=$(bitcoin-cli -named signrawtransactionwithwallet hexstring=$rawtxhex3 | jq -r '.hex')
|
||||
$ bitcoin-cli -named sendrawtransaction hexstring=$signedtx3
|
||||
8b9dd66c999966462a3d88d6ac9405d09e2aa409c0aa830bdd08dbcbd34a36fa
|
||||
```
|
||||
En varios minutos, tendrá su cambio de vuelta:
|
||||
```
|
||||
$ bitcoin-cli listunspent
|
||||
[
|
||||
{
|
||||
"txid": "8b9dd66c999966462a3d88d6ac9405d09e2aa409c0aa830bdd08dbcbd34a36fa",
|
||||
"vout": 1,
|
||||
"address": "tb1q57p0f3hpuad9kf8n6e6adugmt6lnkg2zzr592r",
|
||||
"scriptPubKey": "0014a782f4c6e1e75a5b24f3d675d6f11b5ebf3b2142",
|
||||
"amount": 0.00007800,
|
||||
"confirmations": 1,
|
||||
"spendable": true,
|
||||
"solvable": true,
|
||||
"desc": "wpkh([d6043800/0'/1'/10']038a2702938e548eaec28feb92c7e4722042cfd1ea16bec9fc274640dc5be05ec5)#zpv26nar",
|
||||
"safe": true
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
## Resumen: Envío de monedas con transacciones crudas automatizadas
|
||||
|
||||
Si tiene que enviar fondos con transacciones crudas, entonces `fundrawtransaction` le da una buena alternativa donde las comisiones, entradas y salidas se calculan por usted, para que no pierda accidentalmente un montón de dinero.
|
||||
|
||||
> :fire: ___¿Cuál es el poder de enviar monedas con transacciones crudas automatizadas?___
|
||||
|
||||
> _Las ventajas._ Proporciona un buen equilibrio. Si está enviando fondos a mano y `sendtoaddress` no ofrece suficiente control por cualquier razón, puede obtener algunas de las ventajas de las transacciones en crudo sin los peligros asociados. Esta metodología debería usarse siempre que sea posible si está enviando transacciones en crudo a mano.
|
||||
|
||||
> _Las desventajas._ Es una mezcolanza. Aunque hay algunas opciones adicionales para el comando `fundrawtransaction` que no se han mencionado aquí, el control sigue siendo limitado. Probablemente nunca querrá usar este método si estuviera escribiendo un programa donde el objetivo es saber exactamente lo que está pasando.
|
||||
|
||||
## ¿Qué sigue?
|
||||
|
||||
Complemente "Enviando transacciones de Bitcoin" con [§4.6: Creando una Transacción Segwit](04_6_Creando_una_Transaccion_Segwit.md).
|
290
es/04_6_Creando_una_Transaccion_Segwit.md
Normal file
290
es/04_6_Creando_una_Transaccion_Segwit.md
Normal file
@ -0,0 +1,290 @@
|
||||
# 4.6: Creando una Transacción Segwit
|
||||
|
||||
> :information_source: **NOTA:** Esta sección ha sido añadida recientemente al curso y es un primer borrador que puede estar aún pendiente de revisión. Advertencia al lector.
|
||||
|
||||
Érase una vez, los cielos de Bitcoin se agitaron con las guerras de tamaño de bloque. Las tarifas se disparaban y los usuarios estaban preocupados por el escalado. Los desarrolladores de Bitcoin Core eran reacios a aumentar simplemente el tamaño de los bloques, pero llegaron a un compromiso: SegWit, el Testigo Segregado. Testigo Segregado es una forma elegante de decir "Firma Separada". Crea nuevos tipos de transacciones que eliminan las firmas al final de la transacción. Combinando esto con un aumento del tamaño de los bloques que sólo son visibles para los nodos actualizados, SegWit resolvió los problemas de escalado de Bitcoin en ese momento (y también resolvió un desagradable error de maleabilidad que había hecho impracticable un escalado aún mejor con protocolos de capa 2 como Lightning).
|
||||
|
||||
¿El truco? SegWit utiliza diferentes direcciones, algunas de las cuales son compatibles con los nodos más antiguos, y otras no.
|
||||
|
||||
> :warning: **ADVERTENCIA DE VERSIÓN:** SegWit fue introducido en BitCoin 0.16.0 con lo que se describió en su momento como "soporte completo". Dicho esto, hubo algunos fallos en su integración con `bitcoin-cli` en ese momento que impidieron que la firma funcionara correctamente en las nuevas direcciones P2SH-SegWit. La dirección Bech32 no compatible con la versión anterior también se introdujo en Bitcoin 0.16.0 y se convirtió en el tipo de dirección por defecto en Bitcoin 0.19.0. Toda esta funcionalidad debería ahora funcionar completamente con respecto a las funciones `bitcoin-cli` (y por lo tanto este tutorial).
|
||||
|
||||
> El problema es la interacción con el resto del mundo. Todo el mundo debería ser capaz de enviar a una dirección P2SH-SegWit porque fue construido a propósito para soportar la compatibilidad hacia atrás envolviendo la funcionalidad SegWit en un Script de Bitcoin. No ocurre lo mismo con las direcciones Bech32: si alguien le dice que no puede enviar a su dirección Bech32, es por eso, y necesita generar una dirección `legacy` o P2SH-SegWit para su uso. (Muchos sitios, particularmente los intercambios, tampoco pueden generar o recibir en direcciones SegWit, particularmente en direcciones Bech32, pero eso es un tema totalmente diferente y no afecta a su uso).
|
||||
|
||||
## Entender una transacción SegWit
|
||||
|
||||
En las transacciones clásicas, la información de la firma (testigo) se almacenaba hacia la mitad de la transacción, mientras que en las transacciones SegWit, está en la parte inferior. Esto va de la mano con el aumento del tamaño de los bloques que se introdujo en la actualización de SegWit. El tamaño del bloque pasó de 1M a una cantidad variable basada en cuántas transacciones SegWit hay en un bloque, empezando por 1M (sin transacciones SegWit) y llegando hasta 4M (todas las transacciones SegWit). Este tamaño variable se creó para acomodar a los nodos clásicos, para que todo siga siendo compatible con el pasado. Si un nodo clásico ve una transacción SegWit, desecha la información del testigo (dando como resultado un bloque de menor tamaño, por debajo del antiguo límite de 1M), mientras que si un nodo nuevo ve una transacción SegWit, mantiene la información del testigo (dando como resultado un bloque de mayor tamaño, hasta el nuevo límite de 4M).
|
||||
|
||||
Así que ese es el qué y el cómo de las transacciones SegWit. No es que necesite saber nada de esto para usarlas. La mayoría de las transacciones en la red Bitcoin son ahora SegWit. Son las que se van a utilizar de forma nativa para más transacciones y recibos de dinero. Los detalles no son más relevantes en este momento que los detalles de cómo funciona la mayor parte de Bitcoin.
|
||||
|
||||
## Crear una dirección SegWit
|
||||
|
||||
Una dirección SegWit se crea de la misma manera que cualquier otra dirección, con los comandos `getnewaddress` y `getrawchangeaddress`.
|
||||
|
||||
Si necesita crear una dirección para alguien que no puede enviar a las nuevas direcciones Bech32, utiliza el tipo de dirección `p2sh-segwit`:
|
||||
```
|
||||
$ bitcoin-cli -named getnewaddress address_type=p2sh-segwit
|
||||
2N5h2r4karVqN7uFtpcn8xnA3t5cbpszgyN
|
||||
```
|
||||
Ver una dirección con el prefijo "2" significa que lo ha hecho bien.
|
||||
|
||||
> :link: **TESTNET vs MAINNET:** "3" para Mainnet.
|
||||
|
||||
Sin embargo, si la persona con la que está interactuando tiene un cliente completamente maduro, podrá enviar a una dirección Bech32, que crea usando los comandos de la manera predeterminada:
|
||||
```
|
||||
$ bitcoin-cli getnewaddress
|
||||
tb1q5gnwrh7ss5mmqt0qfan85jdagmumnatcscwpk6
|
||||
```
|
||||
Como ya hemos visto, las direcciones de cambio generadas desde `bitcoin-cli` interactúan bien con las direcciones de Bech32, por lo que tampoco tiene sentido usar la bandera `legacy` allí:
|
||||
```
|
||||
$ bitcoin-cli getrawchangeaddress
|
||||
tb1q05wx5tyadm8qe83exdqdyqvqqzjt3m38vfu8ff
|
||||
```
|
||||
|
||||
En este caso, hay que tener en cuenta que el prefijo único "tb1" denota Bech32.
|
||||
|
||||
> :link: **TESTNET vs MAINNET:** "bc1" para mainnet.
|
||||
|
||||
A Bitcoin-cli no le importa el tipo de dirección que esté usando. Puede ejecutar un comando como `listaddressgroupings` y mezclará libremente direcciones de los diferentes tipos:
|
||||
```
|
||||
$ bitcoin-cli listaddressgroupings
|
||||
[
|
||||
[
|
||||
[
|
||||
"mfsiRhxbQxcD7HLS4PiAim99oeGyb9QY7m",
|
||||
0.01000000,
|
||||
""
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
"mi25UrzHnvn3bpEfFCNqJhPWJn5b77a5NE",
|
||||
0.00000000,
|
||||
""
|
||||
],
|
||||
[
|
||||
"tb1q6dak4e9fz77vsulk89t5z92l2e0zm37yvre4gt",
|
||||
0.00000000
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
"mjehC2KHzXcBDcwTd4LhZ2GzyzrZ3Kd3ff",
|
||||
0.00022000,
|
||||
""
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
"mk9ry5VVy8mrA8SygxSQQUDNSSXyGFot6h",
|
||||
0.00000000
|
||||
],
|
||||
[
|
||||
"mqjrdY5raxKzXQf5t2VvVvzhvFAgersu9B",
|
||||
0.00000000
|
||||
],
|
||||
[
|
||||
"mwJL7cRiW2bUnY81r1thSu3D4jtMmwyU6d",
|
||||
0.00000000,
|
||||
""
|
||||
],
|
||||
[
|
||||
"tb1q57p0f3hpuad9kf8n6e6adugmt6lnkg2zzr592r",
|
||||
0.00007800
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
"mpVLL7iqPr4d7BJkEG54mcdm7WmrAhaW6q",
|
||||
0.01000000,
|
||||
""
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
"tb1q5gnwrh7ss5mmqt0qfan85jdagmumnatcscwpk6",
|
||||
0.01000000,
|
||||
""
|
||||
]
|
||||
]
|
||||
]
|
||||
```
|
||||
|
||||
## Enviar una transacción SegWit de forma sencilla
|
||||
|
||||
¿Cómo se envía una transacción Segwit? Exactamente igual que cualquier otra transacción. No importa si el UTXO es SegWit, la dirección es SegWit, o alguna combinación de ellos. Puede esperar que `bitcoin-cli` haga lo correcto. Aunque se pueden notar las diferencias a través de las direcciones, no importan para interactuar con cosas a nivel de `bitcoin-cli` o RPC. (Y esta es una de las ventajas de utilizar la línea de comandos y la interfaz RPC, como se sugiere en este tutorial: los expertos ya han hecho el trabajo duro por usted, incluyendo cosas como la forma de enviar tanto a direcciones heredadas como a Bech32. Usted sólo tiene que utilizar esa funcionalidad en su propio beneficio).
|
||||
|
||||
Aquí hay un ejemplo de envío a una dirección SegWit, de la manera más fácil:
|
||||
```
|
||||
$ bitcoin-cli sendtoaddress tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx 0.005
|
||||
854a833b667049ac811b4cf1cad40fa7f8dce8b0f4c1018a58b84559b6e05f42
|
||||
```
|
||||
Si mira su transacción, puede ver el uso de la dirección Bech32:
|
||||
```
|
||||
$ bitcoin-cli -named gettransaction txid="854a833b667049ac811b4cf1cad40fa7f8dce8b0f4c1018a58b84559b6e05f42" verbose=true
|
||||
{
|
||||
"amount": -0.00500000,
|
||||
"fee": -0.00036600,
|
||||
"confirmations": 0,
|
||||
"trusted": true,
|
||||
"txid": "854a833b667049ac811b4cf1cad40fa7f8dce8b0f4c1018a58b84559b6e05f42",
|
||||
"walletconflicts": [
|
||||
],
|
||||
"time": 1592948795,
|
||||
"timereceived": 1592948795,
|
||||
"bip125-replaceable": "no",
|
||||
"details": [
|
||||
{
|
||||
"address": "tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx",
|
||||
"category": "send",
|
||||
"amount": -0.00500000,
|
||||
"vout": 1,
|
||||
"fee": -0.00036600,
|
||||
"abandoned": false
|
||||
}
|
||||
],
|
||||
"hex": "0200000002114d5a4c3b847bc796b2dc166ca7120607b874aa6904d4a43dd5f9e0ea79d4ba010000006a47304402200a3cc08b9778e7b616340d4cf7841180321d2fa019e43f25e7f710d9a628b55c02200541fc200a07f2eb073ad8554357777d5f1364c5a96afe5e77c6185d66a40fa7012103ee18c598bafc5fbea72d345329803a40ebfcf34014d0e96aac4f504d54e7042dfeffffffa71321e81ef039af490251379143f7247ad91613c26c8f3e3404184218361733000000006a47304402200dd80206b57beb5fa38a3c3578f4b0e40d56d4079116fd2a6fe28e5b8ece72310220298a8c3a1193ea805b27608ff67a2d8b01e347e33a4222edfba499bb1b64a31601210339c001b00dd607eeafd4c117cfcf86be8efbb0ca0a33700cffc0ae0c6ee69d7efeffffff026854160000000000160014d591091b8074a2375ed9985a9c4b18efecfd416520a1070000000000160014751e76e8199196d454941c45d1b3a323f1433bd6c60e1b00",
|
||||
"decoded": {
|
||||
"txid": "854a833b667049ac811b4cf1cad40fa7f8dce8b0f4c1018a58b84559b6e05f42",
|
||||
"hash": "854a833b667049ac811b4cf1cad40fa7f8dce8b0f4c1018a58b84559b6e05f42",
|
||||
"version": 2,
|
||||
"size": 366,
|
||||
"vsize": 366,
|
||||
"weight": 1464,
|
||||
"locktime": 1773254,
|
||||
"vin": [
|
||||
{
|
||||
"txid": "bad479eae0f9d53da4d40469aa74b8070612a76c16dcb296c77b843b4c5a4d11",
|
||||
"vout": 1,
|
||||
"scriptSig": {
|
||||
"asm": "304402200a3cc08b9778e7b616340d4cf7841180321d2fa019e43f25e7f710d9a628b55c02200541fc200a07f2eb073ad8554357777d5f1364c5a96afe5e77c6185d66a40fa7[ALL] 03ee18c598bafc5fbea72d345329803a40ebfcf34014d0e96aac4f504d54e7042d",
|
||||
"hex": "47304402200a3cc08b9778e7b616340d4cf7841180321d2fa019e43f25e7f710d9a628b55c02200541fc200a07f2eb073ad8554357777d5f1364c5a96afe5e77c6185d66a40fa7012103ee18c598bafc5fbea72d345329803a40ebfcf34014d0e96aac4f504d54e7042d"
|
||||
},
|
||||
"sequence": 4294967294
|
||||
},
|
||||
{
|
||||
"txid": "33173618421804343e8f6cc21316d97a24f7439137510249af39f01ee82113a7",
|
||||
"vout": 0,
|
||||
"scriptSig": {
|
||||
"asm": "304402200dd80206b57beb5fa38a3c3578f4b0e40d56d4079116fd2a6fe28e5b8ece72310220298a8c3a1193ea805b27608ff67a2d8b01e347e33a4222edfba499bb1b64a316[ALL] 0339c001b00dd607eeafd4c117cfcf86be8efbb0ca0a33700cffc0ae0c6ee69d7e",
|
||||
"hex": "47304402200dd80206b57beb5fa38a3c3578f4b0e40d56d4079116fd2a6fe28e5b8ece72310220298a8c3a1193ea805b27608ff67a2d8b01e347e33a4222edfba499bb1b64a31601210339c001b00dd607eeafd4c117cfcf86be8efbb0ca0a33700cffc0ae0c6ee69d7e"
|
||||
},
|
||||
"sequence": 4294967294
|
||||
}
|
||||
],
|
||||
"vout": [
|
||||
{
|
||||
"value": 0.01463400,
|
||||
"n": 0,
|
||||
"scriptPubKey": {
|
||||
"asm": "0 d591091b8074a2375ed9985a9c4b18efecfd4165",
|
||||
"hex": "0014d591091b8074a2375ed9985a9c4b18efecfd4165",
|
||||
"reqSigs": 1,
|
||||
"type": "witness_v0_keyhash",
|
||||
"addresses": [
|
||||
"tb1q6kgsjxuqwj3rwhkenpdfcjccalk06st9z0k0kh"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"value": 0.00500000,
|
||||
"n": 1,
|
||||
"scriptPubKey": {
|
||||
"asm": "0 751e76e8199196d454941c45d1b3a323f1433bd6",
|
||||
"hex": "0014751e76e8199196d454941c45d1b3a323f1433bd6",
|
||||
"reqSigs": 1,
|
||||
"type": "witness_v0_keyhash",
|
||||
"addresses": [
|
||||
"tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
De hecho, ambos `vouts` utilizan direcciones Bech32: su destinatario y la dirección de cambio generada automáticamente.
|
||||
|
||||
Pero cuando retrocedemos en nuestro `vin`, descubrimos que proviene de una dirección heredada. Porque no importa:
|
||||
```
|
||||
$ bitcoin-cli -named gettransaction txid="33173618421804343e8f6cc21316d97a24f7439137510249af39f01ee82113a7"
|
||||
{
|
||||
"amount": 0.01000000,
|
||||
"confirmations": 43,
|
||||
"blockhash": "00000000000000e2365d2f814d1774b063d9a04356f482010cdfdd537b1a24bb",
|
||||
"blockheight": 1773212,
|
||||
"blockindex": 103,
|
||||
"blocktime": 1592937103,
|
||||
"txid": "33173618421804343e8f6cc21316d97a24f7439137510249af39f01ee82113a7",
|
||||
"walletconflicts": [
|
||||
],
|
||||
"time": 1592936845,
|
||||
"timereceived": 1592936845,
|
||||
"bip125-replaceable": "no",
|
||||
"details": [
|
||||
{
|
||||
"address": "mpVLL7iqPr4d7BJkEG54mcdm7WmrAhaW6q",
|
||||
"category": "receive",
|
||||
"amount": 0.01000000,
|
||||
"label": "",
|
||||
"vout": 0
|
||||
}
|
||||
],
|
||||
"hex": "020000000001016a66efa334f06e2c54963e48d049a35d7a1bda44633b7464621cae302f35174a0100000017160014f17b16c6404e85165af6f123173e0705ba31ec25feffffff0240420f00000000001976a914626ab1ca41d98f597d18d1ff8151e31a40d4967288acd2125d000000000017a914d5e76abfe5362704ff6bbb000db9cdfa43cd2881870247304402203b3ba83f51c1895b5f639e9bfc40124715e2495ef2c79d4e49c0f8f70fbf2feb02203d50710abe3cf37df4d2a73680dadf3cecbe4f2b5d0b276dbe7711d0c2fa971a012102e64f83ee1c6548bcf44cb965ffdb803f30224459bd2e57a5df97cb41ba476b119b0e1b00"
|
||||
}
|
||||
```
|
||||
|
||||
## Enviar una transacción SegWit de la manera más difícil
|
||||
|
||||
De forma similar, puede financiar una transacción con una dirección Bech32 sin que haya ninguna diferencia con las técnicas que has aprendido hasta ahora. Aquí hay un ejemplo de cómo hacerlo con una transacción completa en crudo:
|
||||
```
|
||||
$ changeaddress=$(bitcoin-cli getrawchangeaddress)
|
||||
$ echo $changeaddress
|
||||
tb1q4xje3mx9xn7f8khv7p69ekfn0q72kfs8x3ay4j
|
||||
$ bitcoin-cli listunspent
|
||||
[
|
||||
...
|
||||
{
|
||||
"txid": "003bfdca5578c0045a76768281f05d5e6f57774be399a76f387e2a0e99e4e452",
|
||||
"vout": 0,
|
||||
"address": "tb1q5gnwrh7ss5mmqt0qfan85jdagmumnatcscwpk6",
|
||||
"label": "",
|
||||
"scriptPubKey": "0014a226e1dfd08537b02de04f667a49bd46f9b9f578",
|
||||
"amount": 0.01000000,
|
||||
"confirmations": 5,
|
||||
"spendable": true,
|
||||
"solvable": true,
|
||||
"desc": "wpkh([d6043800/0'/0'/5']0327dbe2d58d9ed2dbeca28cd26e18f48aa94c127fa6fb4b60e4188f6360317640)#hd66hknp",
|
||||
"safe": true
|
||||
}
|
||||
]
|
||||
$ recipient=tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx
|
||||
$ utxo_txid=$(bitcoin-cli listunspent | jq -r '.[2] | .txid')
|
||||
$ utxo_vout=$(bitcoin-cli listunspent | jq -r '.[2] | .vout')
|
||||
$ echo $utxo_txid $utxo_vout
|
||||
003bfdca5578c0045a76768281f05d5e6f57774be399a76f387e2a0e99e4e452 0
|
||||
$ rawtxhex=$(bitcoin-cli -named createrawtransaction inputs='''[ { "txid": "'$utxo_txid'", "vout": '$utxo_vout' } ]''' outputs='''{ "'$recipient'": 0.002, "'$changeaddress'": 0.007 }''')
|
||||
$ signedtx=$(bitcoin-cli -named signrawtransactionwithwallet hexstring=$rawtxhex | jq -r '.hex')
|
||||
$ bitcoin-cli -named sendrawtransaction hexstring=$signedtx
|
||||
e02568b706b21bcb56fcf9c4bb7ba63fdbdec1cf2866168c4f50bc0ad693f26c
|
||||
```
|
||||
Todo funciona exactamente igual que otros tipos de transacciones.
|
||||
|
||||
### Reconocer el nuevo descriptor
|
||||
|
||||
Si mira el campo `desc`, notará que la dirección SegWit tiene un estilo de descriptor diferente a los encontrados en [§3.5: Entendiendo el Descriptor](03_5_Entendiendo_El_Descriptor.md). Un descriptor heredado descrito en esa sección tenía el siguiente aspecto `pkh([d6043800/0'/0'/18']03efdee34c0009fd175f3b20b5e5a5517fd5d16746f2e635b44617adafeaebc388)#4ahsl9pk`. En cambio, nuestro nuevo descriptor SegWit tiene el siguiente aspecto `wpkh([d6043800/0'/0'/5']0327dbe2d58d9ed2dbeca28cd26e18f48aa94c127fa6fb4b60e4188f6360317640)#hd66hknp"`.
|
||||
|
||||
Lo más importante es que la función ha cambiado. Antes era `pkh`, que es una dirección de clave pública con hash P2PKH estándar. La dirección SegWit es en cambio `wpkh`, lo que significa que es una dirección SegWit nativa de P2WPKH. Esto subraya :fire: ***el poder de los descriptores***. Describen cómo crear una dirección a partir de una clave u otra información, y las funciones definen sin ambigüedad cómo hacer la dirección en función de su tipo.
|
||||
|
||||
## Resumen: Creación de una transacción SegWit
|
||||
|
||||
Realmente no hay ninguna complejidad en la creación de transacciones SegWit. Internamente, están estructuradas de forma diferente a las transacciones heredadas, pero desde la línea de comandos no hay ninguna diferencia: simplemente se utiliza una dirección con un prefijo diferente. Lo único que hay que tener en cuenta es que algunas personas pueden no ser capaces de enviar a una dirección Bech32 si están utilizando un software obsoleto.
|
||||
|
||||
> 🔥 ___¿Qué ventajas tiene el envío de monedas con SegWit?___
|
||||
|
||||
> _Las ventajas._ Las transacciones con SegWit son más pequeñas, y por lo tanto serán más baratas de enviar que las transacciones heredadas debido a las menores comisiones. Bech32 duplica esta ventaja, y también crea direcciones que son más difíciles de estropear al transcribir - y eso es bastante importante, dado que el error del usuario es una de las formas más probables de perder sus bitcoins.
|
||||
|
||||
> _Las desventajas._ Las direcciones SegWit pueden no ser soportadas por el software obsoleto de Bitcoin. En particular, la gente puede no ser capaz de enviar a su dirección Bech32.
|
||||
|
||||
## ¿Qué sigue?
|
||||
|
||||
Avanzar a través de "bitcoin-cli" con [Capítulo 5: Controlando Transacciones Bitcoin](05_0_Controlando_Transacciones_Bitcoin.md).
|
23
es/05_0_Controlando_Transacciones_Bitcoin.md
Normal file
23
es/05_0_Controlando_Transacciones_Bitcoin.md
Normal file
@ -0,0 +1,23 @@
|
||||
# Capitulo Cinco: Controlar Las Transacciones de Bitcoin
|
||||
|
||||
Enviar una transacción no siempre es el final de la historia. Al usar los protocolos RBF (reemplazo por tarifa) y CPFP (el niño paga por el padre), un desarrollador puede continuar controlando la transacción después de que se haya enviado, para mejorar la eficiencia o recuperar transacciones que se atascan. Estos métodos comenzarán a destacar el verdadero poder de Bitcoin.
|
||||
|
||||
## Objetivos de Esta Sección:
|
||||
|
||||
Después de trabajar en este capítulo, un desarrollador podrá:
|
||||
|
||||
* Decida si RBF o CPFP pueden ayudar en una transacción
|
||||
* Crear transacción de reemplazo usando RBF
|
||||
* Crear nuevas transacciones con CPFP
|
||||
|
||||
Los objetivos de apoyo incluyen la capacidad de:
|
||||
|
||||
* Entender la mempool
|
||||
* Comprenda la diferencia entre RBF y CPFP
|
||||
* Planifique el poder de RBF
|
||||
|
||||
## Tabla de Contenido
|
||||
|
||||
* [Sección uno: Vigilando por Transacciones Estancadas](05_1_Vigilando_por_Transacciones_Estancadas.md)
|
||||
* [Sección dos: Reenviando una Transacción con RBF](05_2_Reenviando_a_Transaccion_con_RBF.md)
|
||||
* [Sección tres: Financiando una Transacción con CPFP](05_3_Financiando_una_Transaccion_con_CPFP.md)
|
59
es/05_1_Vigilando_por_Transacciones_Estancadas.md
Normal file
59
es/05_1_Vigilando_por_Transacciones_Estancadas.md
Normal file
@ -0,0 +1,59 @@
|
||||
# 5.1: Vigilancia de Transacciones Atascadas
|
||||
|
||||
A veces, una transacción de Bitcoin puede atascarse. Por lo general, se debe a que no hubo una tarifa de transacción suficiente, pero también puede deberse a una falla única en la red o el software.
|
||||
|
||||
## Mire Sus Transacciones
|
||||
|
||||
Debe _siempre_ vigilar para asegurarse de que sus transacciones se realicen. `bitcoin-cli listtransactions` mostrará todas sus transacciones entrantes y salientes, mientras que `bitcoin-cli gettransaction` con un txid mostrará una transacción especifica.
|
||||
|
||||
A continuación, se muestra una transacción que no se ha incuido en un bloque. Puede decir esto porque no tiene confirmaciones.
|
||||
```
|
||||
$ bitcoin-cli -named gettransaction txid=fa2ddf84a4a632586d435e10880a2921db6310dfbd6f0f8f583aa0feacb74c8e
|
||||
{
|
||||
"amount": -0.00020000,
|
||||
"fee": -0.00001000,
|
||||
"confirmations": 0,
|
||||
"trusted": true,
|
||||
"txid": "fa2ddf84a4a632586d435e10880a2921db6310dfbd6f0f8f583aa0feacb74c8e",
|
||||
"walletconflicts": [
|
||||
],
|
||||
"time": 1592953220,
|
||||
"timereceived": 1592953220,
|
||||
"bip125-replaceable": "no",
|
||||
"details": [
|
||||
{
|
||||
"address": "tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx",
|
||||
"category": "send",
|
||||
"amount": -0.00020000,
|
||||
"vout": 0,
|
||||
"fee": -0.00001000,
|
||||
"abandoned": false
|
||||
}
|
||||
],
|
||||
"hex": "02000000014cda1f42a1bd39d8d0ff5958a804bc2bc548b71d7ceadbde53ea15aeaf1e2691000000006a473044022016a7a9f045a0f6a52129f48adb7da35c2f54a0741d6614e9d55b8a3bc3e1490a0220391e9085a3697bc790e94bb924d5310e16f23489d9c600864a32674e871f523c01210278608b54b8fb0d8379d3823d31f03a7c6ab0adffb07dd3811819fdfc34f8c132ffffffff02204e000000000000160014751e76e8199196d454941c45d1b3a323f1433bd6e8030000000000001600146c45d3afa8762086c4bd76d8a71ac7c976e1919600000000"
|
||||
```
|
||||
Una transacción puede considerarse bloqueada si permanece en este estado durante un período de temipo prolongado. No hace muchos años, podía estar seguro do que todas las transacciones saldrían _eventualmente_. Pero, ese ya no es el caso debido al mayor uso de Bitcoin. Ahora, si una transacción se atasca demasiado tiempo, saldrá del mempool y luego se perderá de la red Bitcoin.
|
||||
|
||||
> :book: ***Que es mempool?*** Mempool (o Pool de Memoria) es un grupo de todas las transacciones no confirmadas en un nodo bitcoin. Estas son las transacciones que un nodo ha recibido de la red p2p que aún no están incluidas en un bloque. Cada nodo de bitcoin puede tener un conjunto de transacctiones ligeramente diferente en su mempool: diferentes transacciones pueden haberse propagado a un nodo específico. Esto depende de cuándo se inició el nodo por última vez y también de sus límites sobre cuánto está dispuesto a almacenar. Cuando un minero hace un bloqueo, usa transacciones de su mempool. Luego cuando se verifica un bloque, todos los mineros eliminan las transacciones que contiene de sus grupos. A partir de Bitcoin 0.12, las transacciones no confirmadas también pueden vencer de la mempool si tienen la antigüedad suficiente, por lo general, 72 horas, y a partir de la versión 0.14.0, el tiempo de desalojo se incrementó a 2 semanas. Los grupos de minería pueden tener sus propios mecanismos de gestión de mempool.
|
||||
|
||||
Es posible que esta lista de todos las [transacciones no confirmadas](https://blockchain.info/unconfirmed-transactions) no coincida con el mempool de ninguna máquina individual, pero debería (en su mayoría) ser un superconjunto de ellas.
|
||||
|
||||
## Decidir Que Hacer
|
||||
|
||||
Si su transacción se atasca más de lo que deseas, normalmente puede hacer una de estas cuatro cosas:
|
||||
|
||||
**1. Espere Hasta Que Se Aclare.** Se envió su transacción con una tarifa baja o media, eventualmente debería pasar. Como se muestra en [Mempool Space](https://mempool.space), aquellos con tarifas más bajas _se retrasarán_. (Eche un vistazo a la transacción más a la izquierda y vea cuánto tiempo ha estado esperando y cuánto pagó por su tarifa)
|
||||
|
||||
**2. Espere Hasta Que Expire.** Se envió accidentalmente sin tarifa de transacción, o si se cumplen otras condiciones, es posible que su transacción nunca se realice. Sin embargo, sus monedas no se pierden. Siempre que no tenga una billetera que reenvíe intencionalmente las transacciones no confirmadas, debería borrarse del mempool en aproximadamente tres días, y luego puede volver a intentarlo.
|
||||
|
||||
**3. Utilice RBF Como Remitente.** Si usted es el remitente de la transacción y se inscribió en RBF (Replace by fee / Reemplazar Por Tarifa), puede volver a intentarlo con una tarifa más alta. Consulte [§5.2: Reenviando una Transacción con RBF](05_2_Reenviando_a_Transaccion_con_RBF.md).
|
||||
|
||||
**4. Us CPFP Como La Receptora.** Alternativeamente, si usted es el receptor de la transacción, puede usar CPFP (Child-pays-for-parent / nino-paga-por-el-padre) para usar la transacción no confirmada como entrada para una nueva transacción. Consulte [§5.3: Financiando una Transacción con CPFP](05_3_Financiando_una_Transaccion_con_CPFP.md).
|
||||
|
||||
## Resumen: Observación de Transacciones Atascadas
|
||||
|
||||
Esta es una introducción al poder de las transacciónes de Bitcoin. Si lo sabe que una transacción está atascada, puede decidir liberarla con funciones como RBF o CPFP.
|
||||
|
||||
## Que Sigue?
|
||||
|
||||
Continúe "Controlando las Transacciones de Bitcoin" con [§5.2: Reenviando una Transacción con RBF](05_2_Reenviando_a_Transaccion_con_RBF.md).
|
215
es/05_2_Reenviando_a_Transaccion_con_RBF.md
Normal file
215
es/05_2_Reenviando_a_Transaccion_con_RBF.md
Normal file
@ -0,0 +1,215 @@
|
||||
# 5.2: Reenviando una Transacción con RBF
|
||||
|
||||
Si su transacción de Bitcoin está atascada y usted es el remitente, puede reenviarla usando RBF (replace by fee / reemplazor por tarifa). Sin embargo, eso no es todo lo que puede hacer RBF: generalmente es una característica poderosa y multipropósito que permite a los remitentes de Bitcoin recrear transacciones por una variedad de razones.
|
||||
|
||||
> :warning: **ADVERTENCIA DE VERSIÓN:** Esta es una innovación de Bitcoin Core v 0.12.0, que alcanzó la madurez completa en la billetera Bitcoin Core con Bitcoin Core v 0.14.0. Obviamente, la mayoría de la gente ya debería estar utilizándolo.
|
||||
|
||||
## Optar en RBF
|
||||
|
||||
RBF es una función de Bitcoin opcional. Las transacciones solo son elegibles para usar RBF si se han creado con una marca de RBF especial. Esto se hace configurando cualquiera de los números de secuencia UTXO de la transacción (que generalmente se configuran automáticamente), de modo que sea más de 0 y menos de 0xffffffff-1 (4294967294).
|
||||
|
||||
Esto se logra simplemente agregando una variable de `sequence` (sequencia) a sus entradas UTXO:
|
||||
```
|
||||
$ rawtxhex=$(bitcoin-cli -named createrawtransaction inputs='''[ { "txid": "'$utxo_txid'", "vout": '$utxo_vout', "sequence": 1 } ]''' outputs='''{ "'$recipient'": 0.00007658, "'$changeaddress'": 0.00000001 }''')
|
||||
```
|
||||
Por supuesto, debe firmar y enviar su transacción como de costumbre:
|
||||
```
|
||||
$ signedtx=$(bitcoin-cli -named signrawtransactionwithwallet hexstring=$rawtxhex | jq -r '.hex')
|
||||
$ bitcoin-cli -named sendrawtransaction hexstring=$signedtx
|
||||
5b953a0bdfae0d11d20d195ea43ab7c31a5471d2385c258394f3bb9bb3089375
|
||||
```
|
||||
Ahora, cuando mire a su transacción, debería ver algo nuevo: la línea `bip125-replaceable`, que siempre ha sido marcada como `no` antes, ahora está marcada como `yes` (sí):
|
||||
```
|
||||
$ bitcoin-cli -named gettransaction txid=5b953a0bdfae0d11d20d195ea43ab7c31a5471d2385c258394f3bb9bb3089375
|
||||
|
||||
{
|
||||
"amount": 0.00000000,
|
||||
"fee": -0.00000141,
|
||||
"confirmations": 0,
|
||||
"trusted": true,
|
||||
"txid": "5b953a0bdfae0d11d20d195ea43ab7c31a5471d2385c258394f3bb9bb3089375",
|
||||
"walletconflicts": [
|
||||
],
|
||||
"time": 1592954399,
|
||||
"timereceived": 1592954399,
|
||||
"bip125-replaceable": "yes",
|
||||
"details": [
|
||||
],
|
||||
"hex": "02000000000101fa364ad3cbdb08dd0b83aac009a42a9ed00594acd6883d2a466699996cd69d8b01000000000100000002ea1d000000000000160014d591091b8074a2375ed9985a9c4b18efecfd416501000000000000001600146c45d3afa8762086c4bd76d8a71ac7c976e1919602473044022077007dff4df9ce75430e3065c82321dca9f6bdcfd5812f8dc0daeb957d3dfd1602203a624d4e9720a06def613eeea67fbf13ce1fb6188d3b7e780ce6e40e859f275d0121038a2702938e548eaec28feb92c7e4722042cfd1ea16bec9fc274640dc5be05ec500000000"
|
||||
}
|
||||
```
|
||||
La bandera `bip125-replaceable` permanecerá `yes` hasta que la transacción reciba confirmaciones. En ese momento, ya no es reemplazable.
|
||||
|
||||
> :book: ***¿Debo confiar en transacciones sin confirmaciones?*** No, nunca. Esto era cierto antes de RBF y fue cierto después de RBF. Las transacciones deben recibir confirmaciones antes de que sean confiables. Esto es especialmente cierto si una transacción está marcada como `bip125-replaceable`, porque entonces puede ser ... reemplazada.
|
||||
|
||||
> :information_source: **NOTA — SECUENCIA:** Este es el primer uso del valor `nSequence` en Bitcoin. Puede configurarlo entre 1 y 0xffffffff-2 (4294967293) y habilitar RBF, pero si no tiene cuidado, puede enfrentarse al uso paralelo de `nSequence` para bloqueos temporales relativos. :t Sugerimos configurarlo siempre en "1", que es lo que hace Bitcoin Core, pero la otra opción es configurarlo en un valor entre 0xf0000000 (4026531840) y 0xffffffff-2 (4294967293). Establecerlo en "1" efectivamente hace que los bloqueos temporales relativos sean irrelevantes y establecerlo en 0xf0000000 o superior los desactiva. Todo esto se explica con más detalle en [§11.3: Usando CSV en Scripts](11_3_Usando_CSV_en_Scripts.md). Por ahora, simplemente elija uno de los valores no conflictivos para `nSequence`.
|
||||
|
||||
### Opcional: Optar Siempre por RBF
|
||||
|
||||
Si lo prefiere, puede _siempre_ optar por RBF. Hágalo ejecutando su `bitcoind` con el comando `-walletrbf`. Cuando ya hecho esto (y reiniciado su `bitcoind`), todos los UTXOs deberían tener un número de secuencia más bajo y la transacción debería estar marcada como `bip125-replaceable`.
|
||||
|
||||
> :warning: **ADVERTENCIA DE VERSIÓN:** La bandera walletrbf requiere Bitcoin Core v.0.14.0.
|
||||
|
||||
## Comprender Cómo Funciona RBF
|
||||
|
||||
La funcionalidad RBF se basa en [BIP 125](https://github.com/bitcoin/bips/blob/master/bip-0125.mediawiki), que enumera las siguientes reglas para usar RBF:
|
||||
|
||||
> 1. Las transacciones originales señalan la reemplazabilidad explícitamente o mediante herencia, como se describe en la sección Resumen anterior.
|
||||
|
||||
Esto significa que el número de secuencia debe establecerse en menos de 0xffffffff-1. (4294967294), o lo mismo ocurre con las transacciones matrices no confirmada.
|
||||
|
||||
> 2. La transacción de reemplazo paga una tarifa absolutamente más alta que la suma pagada por las transacciones originales.
|
||||
> 3. La transacción de reemplazo no contiene ninguna entrada nueva no confirmada que no apareciera previamente en el mempool. (Las entradas no confirmadas son entradas que gastan salidas de transacciones actualente no confirmadas.)
|
||||
> 4. La transacción de reemplazo debe pagar por su propio ancho de banda además del monto pagado por las transacciones originales a la tasa establecida por la configuración de tarifa de retransmisión mínima del nodo por encima de ella. Por ejemplo, si la tarifa mínima de retransmisión es 1 satoshi/byte y la transacción de reemplazo es de 500 bytes en total, entonces el reemplazo debe pagar una tarifa al menos 500 satoshis más alta que la suma de los originales.
|
||||
> 5. El número de transacciones originales a reemplazar y sus transacciones descendientes que serán desalojadas del mempool no debe exceder un total de 100 transacciones.
|
||||
|
||||
> :book: ***Que es un BIP?*** Un BIP es una Bitcoin Improvement Proposal, una propuesta de mejora de Bitcoin. Es una sugerencia en profundidad para un cambio en el código de Bitcoin Core. A menudo, cuando un BIP se ha discutido y actualizado lo suficiente se convertirá en una parte real del código de Bitcoin Core. Por ejemplo, BIP 125 se implementó en Bitcoin Core 0.12.0.
|
||||
|
||||
La otra cosa que hay que entender sobre RBF es que para usarlo, debe gastar dos veces, reutilizando uno o más UTXO iguales. Simplemente enviar otra transacción con un UTXO diferente al mismo destinatario no funcionará (y probablemente resultará en una pérdida de dinero). En su lugar, debe crear un conflicto a propósito, donde se usa el mismo UTXO en dos transacciones diferentes.
|
||||
|
||||
Ante este conflicto, los mineros sabrán usar el que tenga la tarifa más alta, y estarán incentivados a hacerlo por esa tarifa más alta.
|
||||
|
||||
> :book: ***¿Qué es un doble-gasto?*** Un doble-gasto ocurre cuando alguien envía los mismos fondos electrónicos a dos personas diferentes (o, a la misma persona dos veces, en dos transacciones diferentes). Este es un problema central para cualquier sistema de efectivo electrónico. Se resuelve en Bitcoin por el libro mayor inmutable: una vez que una transacción está suficientemente confirmada, ningún minero verificará transacciones que reutilicen el mismo UTXO. Sin embargo, es posible gastar dos veces _antes_ de que se confirme una transacción, por lo que siempre desea una o más confirmaciones antes de finalizar una transacción. En el caso de RBF, usted gasta el doble a propósito porque una transacción inicial se ha estancado y los mineros aceptan su doble gasto si cumple con los criterios específicos establecidos por BIP 125.
|
||||
|
||||
> :warning: **ADVERTENCIA:** Algunas discusiones tempranas de esta política sugirieron que el número de `nSequence` también se incrementara. De hecho, este fue el uso previsto de `nSequence` en su forma original. Esto _no_ forma parte de la política publicada en BIP 125. De hecho, aumentar su número de secuencia puede bloquear accidentalmente su transacción con un bloqueo temporal relativo, a menos que use números de secuencia en el rango de 0xf0000000 (4026531840) a 0xffffffff-2 (4294967293).
|
||||
|
||||
## Reemplazar una Transacción de la Manera Difícil: A Mano
|
||||
|
||||
Para crear una transacción RBF a mano, todo lo que tiene que hacer es crear una transacción sin procesar que: (1) reemplaza una transacción sin procesar anterior que optó por RBF y que no está confirmada; (2) reutiliza una o más de las mismas UTXOs; (3) aumenta las tarifas; y (4) paga el ancho de banda mínimo de ambas transacciones [que ya puede ser antendido por (3)].
|
||||
|
||||
El siguiente ejemplo solo reutiliza nuestras variables existentes, pero disminuye la cantidad enviada a la dirección de cambio, para aumentar la tarifa de los 0 BTC accidentales de la transacción original a 0.01 BTC excesivamente generosos en la nueva transacción:
|
||||
```
|
||||
$ rawtxhex=$(bitcoin-cli -named createrawtransaction inputs='''[ { "txid": "'$utxo_txid'", "vout": '$utxo_vout', "sequence": 1 } ]''' outputs='''{ "'$recipient'": 0.000075, "'$changeaddress'": 0.00000001 }''')
|
||||
```
|
||||
Por supuesto, debemos volver a firmarlo y reenviarlo:
|
||||
```
|
||||
$ signedtx=$(bitcoin-cli -named signrawtransactionwithwallet hexstring=$rawtxhex | jq -r '.hex')
|
||||
$ bitcoin-cli -named sendrawtransaction hexstring=$signedtx
|
||||
c6de60427b28d8ec8102e49771e5d0348fc3ef6a5bf02eb864ec745105a6951b
|
||||
```
|
||||
Ahora puede ver su transacción original y ver que tiene `walletconflicts`, o confilctos de billetera:
|
||||
```
|
||||
$ bitcoin-cli -named gettransaction txid=5b953a0bdfae0d11d20d195ea43ab7c31a5471d2385c258394f3bb9bb3089375
|
||||
{
|
||||
"amount": 0.00000000,
|
||||
"fee": -0.00000141,
|
||||
"confirmations": 0,
|
||||
"trusted": false,
|
||||
"txid": "5b953a0bdfae0d11d20d195ea43ab7c31a5471d2385c258394f3bb9bb3089375",
|
||||
"walletconflicts": [
|
||||
"c6de60427b28d8ec8102e49771e5d0348fc3ef6a5bf02eb864ec745105a6951b"
|
||||
],
|
||||
"time": 1592954399,
|
||||
"timereceived": 1592954399,
|
||||
"bip125-replaceable": "yes",
|
||||
"details": [
|
||||
],
|
||||
"hex": "02000000000101fa364ad3cbdb08dd0b83aac009a42a9ed00594acd6883d2a466699996cd69d8b01000000000100000002ea1d000000000000160014d591091b8074a2375ed9985a9c4b18efecfd416501000000000000001600146c45d3afa8762086c4bd76d8a71ac7c976e1919602473044022077007dff4df9ce75430e3065c82321dca9f6bdcfd5812f8dc0daeb957d3dfd1602203a624d4e9720a06def613eeea67fbf13ce1fb6188d3b7e780ce6e40e859f275d0121038a2702938e548eaec28feb92c7e4722042cfd1ea16bec9fc274640dc5be05ec500000000"
|
||||
}
|
||||
```
|
||||
Esto representa el hecho de que dos transacciones diferentes intentan utilizar el mismo UTXO.
|
||||
|
||||
Eventualmente, se debe aceptar la transacción con la tarifa más alta:
|
||||
```
|
||||
$ bitcoin-cli -named gettransaction txid=c6de60427b28d8ec8102e49771e5d0348fc3ef6a5bf02eb864ec745105a6951b
|
||||
{
|
||||
"amount": 0.00000000,
|
||||
"fee": -0.00000299,
|
||||
"confirmations": 2,
|
||||
"blockhash": "0000000000000055ac4b6578d7ffb83b0eccef383ca74500b00f59ddfaa1acab",
|
||||
"blockheight": 1773266,
|
||||
"blockindex": 9,
|
||||
"blocktime": 1592955002,
|
||||
"txid": "c6de60427b28d8ec8102e49771e5d0348fc3ef6a5bf02eb864ec745105a6951b",
|
||||
"walletconflicts": [
|
||||
"5b953a0bdfae0d11d20d195ea43ab7c31a5471d2385c258394f3bb9bb3089375"
|
||||
],
|
||||
"time": 1592954467,
|
||||
"timereceived": 1592954467,
|
||||
"bip125-replaceable": "no",
|
||||
"details": [
|
||||
],
|
||||
"hex": "02000000000101fa364ad3cbdb08dd0b83aac009a42a9ed00594acd6883d2a466699996cd69d8b010000000001000000024c1d000000000000160014d591091b8074a2375ed9985a9c4b18efecfd416501000000000000001600146c45d3afa8762086c4bd76d8a71ac7c976e1919602473044022077dcdd98d85f6247450185c2b918a0f434d9b2e647330d741944ecae60d6ff790220424f85628cebe0ffe9fa11029b8240d08bdbfcc0c11f799483e63b437841b1cd0121038a2702938e548eaec28feb92c7e4722042cfd1ea16bec9fc274640dc5be05ec500000000"
|
||||
}
|
||||
```
|
||||
Mientras tanto, la transacción original con la tarifa más baja comienza a recoger confirmaciones negativas, para mostrar su divergencia con respecto a la cadena de bloques:
|
||||
```
|
||||
$ bitcoin-cli -named gettransaction txid=5b953a0bdfae0d11d20d195ea43ab7c31a5471d2385c258394f3bb9bb3089375
|
||||
{
|
||||
"amount": 0.00000000,
|
||||
"fee": -0.00000141,
|
||||
"confirmations": -2,
|
||||
"trusted": false,
|
||||
"txid": "5b953a0bdfae0d11d20d195ea43ab7c31a5471d2385c258394f3bb9bb3089375",
|
||||
"walletconflicts": [
|
||||
"c6de60427b28d8ec8102e49771e5d0348fc3ef6a5bf02eb864ec745105a6951b"
|
||||
],
|
||||
"time": 1592954399,
|
||||
"timereceived": 1592954399,
|
||||
"bip125-replaceable": "yes",
|
||||
"details": [
|
||||
],
|
||||
"hex": "02000000000101fa364ad3cbdb08dd0b83aac009a42a9ed00594acd6883d2a466699996cd69d8b01000000000100000002ea1d000000000000160014d591091b8074a2375ed9985a9c4b18efecfd416501000000000000001600146c45d3afa8762086c4bd76d8a71ac7c976e1919602473044022077007dff4df9ce75430e3065c82321dca9f6bdcfd5812f8dc0daeb957d3dfd1602203a624d4e9720a06def613eeea67fbf13ce1fb6188d3b7e780ce6e40e859f275d0121038a2702938e548eaec28feb92c7e4722042cfd1ea16bec9fc274640dc5be05ec500000000"
|
||||
}
|
||||
```
|
||||
Nuestros destinatarios tienen su dinero, y la transacción fallida original eventualmente se saldrá del mempool.
|
||||
|
||||
## Reemplazar una Transacción de la Manera Mas Fácil: Por bumpfee
|
||||
|
||||
Las transacciones sin procesar son muy poderosas y puede hacer muchas cosas interesantes combinándolas con RBF. Sim embargo, a veces _todo_ lo que quiere hacer es liberar una transacción que ha estado suspendida. Ahora puede hacerlo con un simple comando, `bumpfee`.
|
||||
|
||||
Por ejemplo, para aumentar la tarifa de la transacción `4460175e8276d5a1935f6136e36868a0a3561532d44ddffb09b7cb878f76f927` ejecutaría:
|
||||
```
|
||||
$ bitcoin-cli -named bumpfee txid=4460175e8276d5a1935f6136e36868a0a3561532d44ddffb09b7cb878f76f927
|
||||
{
|
||||
"txid": "75208c5c8cbd83081a0085cd050fc7a4064d87c7d73176ad9a7e3aee5e70095f",
|
||||
"origfee": 0.00000000,
|
||||
"fee": 0.00022600,
|
||||
"errors": [
|
||||
]
|
||||
}
|
||||
```
|
||||
El resultado es la generación automática de una nueva transacción que tiene una tarifa determinada por su archivo bitcoin.conf:
|
||||
```
|
||||
$ bitcoin-cli -named gettransaction txid=75208c5c8cbd83081a0085cd050fc7a4064d87c7d73176ad9a7e3aee5e70095f
|
||||
{
|
||||
"amount": -0.10000000,
|
||||
"fee": -0.00022600,
|
||||
"confirmations": 0,
|
||||
"trusted": false,
|
||||
"txid": "75208c5c8cbd83081a0085cd050fc7a4064d87c7d73176ad9a7e3aee5e70095f",
|
||||
"walletconflicts": [
|
||||
"4460175e8276d5a1935f6136e36868a0a3561532d44ddffb09b7cb878f76f927"
|
||||
],
|
||||
"time": 1491605676,
|
||||
"timereceived": 1491605676,
|
||||
"bip125-replaceable": "yes",
|
||||
"replaces_txid": "4460175e8276d5a1935f6136e36868a0a3561532d44ddffb09b7cb878f76f927",
|
||||
"details": [
|
||||
{
|
||||
"account": "",
|
||||
"address": "n2eMqTT929pb1RDNuqEnxdaLau1rxy3efi",
|
||||
"category": "send",
|
||||
"amount": -0.10000000,
|
||||
"vout": 0,
|
||||
"fee": -0.00022600,
|
||||
"abandoned": false
|
||||
}
|
||||
],
|
||||
"hex": "02000000014e843e22cb8ee522fbf4d8a0967a733685d2ad92697e63f52ce41bec8f7c8ac0020000006b48304502210094e54afafce093008172768d205d99ee2e9681b498326c077f0b6a845d9bbef702206d90256d5a2edee3cab1017b9b1c30b302530b0dd568e4af6f2d35380bbfaa280121029f39b2a19943fadbceb6697dbc859d4a53fcd3f9a8d2c8d523df2037e7c32a71010000000280969800000000001976a914e7c1345fc8f87c68170b3aa798a956c2fe6a9eff88ac38f25c05000000001976a914c101d8c34de7b8d83b3f8d75416ffaea871d664988ac00000000"
|
||||
}
|
||||
```
|
||||
|
||||
> :warning: **ADVERTENCIA DE VERSIÓN:** El `bumpfee` por RPC requiere Bitcoin Core v.0.14.0.
|
||||
|
||||
## Resumen: Reenvío de una Transacción con RBF
|
||||
|
||||
Si una transacción está atascada y no desea esperar a que caduque por completo, si optó por RBF, puede gastarla dos veces con RBF para crear una transacción de reemplazo (o simplemente usar `bumpfee`).
|
||||
|
||||
> :fire: ***Cual es el poder de RBF?*** Obviamente, RBF es muy útil si creó una transacción con una tarifa demasiado baja y necesita pasar esos fondos. Sin embargo, la capacidad de reemplazar generalmente las transacciones no confirmadas con las actualizadas tiene más poder que solo eso (y es por eso que es posible que desee continuar usando RBF con transacciones sin procesar, incluso después de la llegada de `bumpfee`).
|
||||
|
||||
> Por ejemplo, puede enviar una transacción y luego, antes de que se confirme, combinarla con una segunda transacción. Esto le permite comprimir múltiples transacciones en una sola, disminuyendo las tarifas generales. También podría ofrecer beneficios a la privacidad. También hay otras razones para usar RBF, para contratos inteligentes o transacciones de corte, como se describe en el [Opt-in RBF FAQ](https://bitcoincore.org/en/faq/optin_rbf/).
|
||||
|
||||
## Que Sigue?
|
||||
|
||||
Continúe "Controlando las Transacciones de Bitcoin" con [§5.3: Financiando una Transacción con CPFP](05_3_Financiando_una_Transaccion_con_CPFP.md).
|
126
es/05_3_Financiando_una_Transaccion_con_CPFP.md
Normal file
126
es/05_3_Financiando_una_Transaccion_con_CPFP.md
Normal file
@ -0,0 +1,126 @@
|
||||
# 5.3: Financiación de una Transación con CPFP
|
||||
|
||||
Si su transacción de Bitocin está atascada y usted es el _receptor_, puede borrarla usando CPFP (child-pays-for-parent o el niño paga por el padre). Esta es una alternativa a la capacidad del _remitente_ para hacerlo con RBF.
|
||||
|
||||
> :warning: **ADVERTENCIA DE VERSIÓN:** Esta es una innovación de Bitcoin Core v 0.13.0, lo que nuevamente significa que la mayoría de la gente ya debería estar usándolo.
|
||||
|
||||
## Comprenda Cómo Funciona CPFP
|
||||
|
||||
RBF se trataba del remitente. Se equivocó y necesitaba aumentar la tarifa, o quería ser inteligente y combinar transacciones por una variedad de razones. Era una potente función orientada al remitente. De alguna manera, CPFP es lo opuesto a RBF, porque le da poder al destinatario que sabe que su dinero aún no ha llegado y quiere acelerarlo. Sin embargo, también es una característica mucho más simple, con una aplicabilidad menos amplia.
|
||||
|
||||
Básicamente, la idea de CPFP es que un destinatario tiene una transacción que no ha sido confirmada en un bloque que quiere gastar. Entonces, incluye esa transacción no confirmada en una nueva transacción y paga una tarifa lo suficientemente alta como para alentar a un minero a incluir tanto la transacción original (principal) como la nueva transacción (secundaria) en un bloque. Como resultado, las transacciones principales y secundarias se borran simultáneamnete.
|
||||
|
||||
Cabe señalar que CPFP no es una función de protocolo nueva como RBF. Es solo un nuevo esquema de incentivos que los mineros pueden usar para la selección de transacciones. Esto también significa que no es tan confiable como un cambio de protocolo como RBF: puede haber razones por las que la secundaria no sea seleccionado para ser colocado en un bloque, y eso evitará que el principal sea colocado en un bloque.
|
||||
|
||||
## Gastar UTXOs No Confirmadas
|
||||
Financiar una transacción con CPFP es un proceso muy simple que utiliza los métodos con los que ya está familiarizado:
|
||||
|
||||
1. Busque el `txid` y `vout` de la transacción no confirmada. Esta puede ser la parte más complicada, ya que `bitcoin-cli` generalmente intenta protegerlo de transaciones no confirmadas. Es posible que el remitente pueda enviarle esta información; incluso con solo el `txid`, debería poder averigular el `vout` en un explorador de blockchain.
|
||||
|
||||
Tiene otra opción: use `bitcoin-cli getrawmempool`, que se puede usar para enumerar el contenido de su mempool completo, donde se encontrarán las transacciones no confirmadas. Es posible que tenga que buscar en varios se el mempool está particularmente ocupado. A continuación, puede obtener más información sobre una transacción especifica con `bitcoin-cli getrawtransaction` con el indicador detallado en `true`:
|
||||
```
|
||||
$ bitcoin-cli getrawmempool
|
||||
[
|
||||
"95d51e813daeb9a861b2dcdddf1da8c198d06452bbbecfd827447881ff79e061"
|
||||
]
|
||||
|
||||
$ bitcoin-cli getrawtransaction 95d51e813daeb9a861b2dcdddf1da8c198d06452bbbecfd827447881ff79e061 true
|
||||
{
|
||||
"txid": "95d51e813daeb9a861b2dcdddf1da8c198d06452bbbecfd827447881ff79e061",
|
||||
"hash": "9729e47b8aee776112a82cec46df7638d112ca51856c53e238a9b1f7af3be4ce",
|
||||
"version": 2,
|
||||
"size": 247,
|
||||
"vsize": 166,
|
||||
"weight": 661,
|
||||
"locktime": 1773277,
|
||||
"vin": [
|
||||
{
|
||||
"txid": "7a0178472300247d423ac4a04ff9165fa5b944104f6d6f9ebc557c6d207e7524",
|
||||
"vout": 0,
|
||||
"scriptSig": {
|
||||
"asm": "0014334f3a112df0f22e743ad97eec8195a00faa59a0",
|
||||
"hex": "160014334f3a112df0f22e743ad97eec8195a00faa59a0"
|
||||
},
|
||||
"txinwitness": [
|
||||
"304402207966aa87db340841d76d3c3596d8b4858e02aed1c02d87098dcedbc60721d8940220218aac9d728c9a485820b074804a8c5936fa3145ce68e24dcf477024b19e88ae01",
|
||||
"03574b1328a5dc2d648498fc12523cdf708efd091c28722a422d122f8a0db8daa9"
|
||||
],
|
||||
"sequence": 4294967294
|
||||
}
|
||||
],
|
||||
"vout": [
|
||||
{
|
||||
"value": 0.01000000,
|
||||
"n": 0,
|
||||
"scriptPubKey": {
|
||||
"asm": "OP_HASH160 f079f77f2ef0ef1187093379d128ec28d0b4bf76 OP_EQUAL",
|
||||
"hex": "a914f079f77f2ef0ef1187093379d128ec28d0b4bf7687",
|
||||
"reqSigs": 1,
|
||||
"type": "scripthash",
|
||||
"addresses": [
|
||||
"2NFAkGiwnp8wvCodRBx3smJwxncuG3hndn5"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"value": 0.02598722,
|
||||
"n": 1,
|
||||
"scriptPubKey": {
|
||||
"asm": "OP_HASH160 8799be12fb9eae6644659d95b9602ddfbb4b2aff OP_EQUAL",
|
||||
"hex": "a9148799be12fb9eae6644659d95b9602ddfbb4b2aff87",
|
||||
"reqSigs": 1,
|
||||
"type": "scripthash",
|
||||
"addresses": [
|
||||
"2N5cDPPuCTtYq13oXw8RfpY9dHJW8sL64U2"
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"hex": "0200000000010124757e206d7c55bc9e6f6d4f1044b9a55f16f94fa0c43a427d2400234778017a0000000017160014334f3a112df0f22e743ad97eec8195a00faa59a0feffffff0240420f000000000017a914f079f77f2ef0ef1187093379d128ec28d0b4bf768742a727000000000017a9148799be12fb9eae6644659d95b9602ddfbb4b2aff870247304402207966aa87db340841d76d3c3596d8b4858e02aed1c02d87098dcedbc60721d8940220218aac9d728c9a485820b074804a8c5936fa3145ce68e24dcf477024b19e88ae012103574b1328a5dc2d648498fc12523cdf708efd091c28722a422d122f8a0db8daa9dd0e1b00"
|
||||
}
|
||||
```
|
||||
Busque a través de la matriz `vout`. Encuentra el objecto que coincida con su dirección. (Aqui, es el único.) El `n` valor es su `vout`. Ahora tiene todo lo que necesita para crear una nueva transacción de CPFP.
|
||||
```
|
||||
$ utxo_txid=2NFAkGiwnp8wvCodRBx3smJwxncuG3hndn5
|
||||
$ utxo_vout=0
|
||||
$ recipient2=$(bitcoin-cli getrawchangeaddress)
|
||||
```
|
||||
|
||||
2. Cree una transacción sin procesar utilizando su transacción no confirmada como entrada.
|
||||
3. Duplique las tarifas de transacción (o mas).
|
||||
|
||||
Cuando siga estos pasos, todo debería verse totalmente normal, a pesar de que está trabajando con una transacción no confirmada. Para verificar que todo estaba bien, incluso miramos los resultados de nuestra firma antes de guardar la información en una variable:
|
||||
```
|
||||
$ rawtxhex=$(bitcoin-cli -named createrawtransaction inputs='''[ { "txid": "'$utxo_txid'", "vout": '$utxo_vout' } ]''' outputs='''{ "'$recipient2'": 0.03597 }''')
|
||||
|
||||
$ bitcoin-cli -named signrawtransaction hexstring=$rawtxhex | jq -r '.hex'
|
||||
02000000012b137ef780666ba214842ff6ea2c3a0b36711bcaba839c3710f763e3d9687fed000000006a473044022003ca1f6797d781ef121ba7c2d1d41d763a815e9dad52aa8bc5ea61e4d521f68e022036b992e8e6bf2c44748219ca6e0056a88e8250f6fd0794dc69f79a2e8993671601210317b163ab8c8862e09c71767112b828abd3852e315441893fa0f535de4fa39b8dffffffff01905abd07000000001976a91450b1d90a130c4f3f1e5fbfa7320fd36b7265db0488ac00000000
|
||||
|
||||
$ signedtx=$(bitcoin-cli -named signrawtransaction hexstring=$rawtxhex | jq -r '.hex')
|
||||
$ bitcoin-cli -named sendrawtransaction hexstring=$signedtx
|
||||
6a184a2f07fa30189f4831d6f041d52653a103b3883d2bec2f79187331fd7f0e
|
||||
```
|
||||
|
||||
4. No es necesario cruzar los dedos. Ha verificado que sus datos son correctos. A partir de este momento, las cosas están fuera de sus manos.
|
||||
|
||||
Es posible que sus transacciones se realicen rápidamente. Puede que no. Todo depende de si los mineros que están generando aleatoriamente los bloques actuales tienen el parche CPFP o no. Pero le ha dado a sus transacciones la mejor oportunidad.
|
||||
|
||||
Eso es realmente todo lo que hay que hacer.
|
||||
|
||||
### Tenga Cuidado con los Matices
|
||||
|
||||
Aunque CPFP generalmente se describe como un destinatario que usa una nueva transacción para pagar una anterior que no ha sido confirmada, esto tiene sus matices.
|
||||
|
||||
Un _remitente_ podría usar CPFP para liberar una transacción si recibiera un cambio. Simplemente usaría ese cambio como su entrada, y el uso resultante de CPFP liberaría toda la transacción. Eso sí, sería mejor que usara RBF siempre que estuviera habilitado, ya que las tarifas totales serían más bajas.
|
||||
|
||||
Un _receptor_ podría usar CPFP uncluso si no planeaba gastar el dinero de inmediato, por ejemplo, si le preocupa que los fondos no se reenvíen si la transacción expira. En este caso, simplemente crea una transacción secundaria que envía todo el dinero (menos una tarifa de transacción) a una dirección de cambio. Eso es lo que hicimos en nuestro ejemplo arriba.
|
||||
|
||||
## Resumen: Financiación de una Transacción con CPFP
|
||||
|
||||
Puede aprovechar los incentivos de CPFP para liberar fondos que le han sido enviados pero que no han sido confirmados. Simplemente use la transacción no confirmada como UTXO y pague una tarifa de transacción superior al promedio.
|
||||
|
||||
> :fire: ***¿Cuál es el Poder de CPFP?*** Principalmente, CPFP es útil para que los fondos se despeguen cuando usted es el destinatario y el remitente no está siendo útil por cualquier motivo. No tiene las posibilidades más poderosas de RBF, pero es una forma alternativa de ejercer control sobre una transacción después de que se haya colocado en el mempool, pero antes de que se confirme en un bloque.
|
||||
|
||||
## Que Sigue?
|
||||
|
||||
Avance a través de "bitcoin-cli" con [Capitulo seis: Expandiendo las Transacciones Bitcoin con Multifirmas](06_0_Expandiendo_las_Transacciones_Bitcoin_con_Multifirmas.md).
|
@ -0,0 +1,21 @@
|
||||
# Capítulo Seis: Expandiendo Transacciones Bitcoin con Multifirmas
|
||||
|
||||
Transacciones básicas Bitcoin: (1) enviar fondos; (2) a un destinatario P2PKH simple o SegWit; (3) desde una máquina; (4) inmediatamente. Sin embargo, estas cuatro partes de esta definición pueden expandirse usando transacciones Bitcoin más complejas. Este primer capítulo de "Expansión" muestra cómo variar puntos (2) y (3) enviando dinero a una dirección que representa a múltiples destinatarios (o al menos, múltiples firmantes).
|
||||
|
||||
## Objectivos para Esta Sección
|
||||
|
||||
Luego de trabajar a lo largo de este capítulo, un desarrollador será capaz de:
|
||||
|
||||
* Crear Direcciones Bitcoin Multifirma Usando los Fundamentos de Bitcoin
|
||||
* Crear Direcciones Bitcoin Multifirma Usando Mecanismos más Sencillos
|
||||
|
||||
Los objetivos propuestos incluyen la habilidad de:
|
||||
|
||||
* Comprender Cómo Gastar Fondos Enviados a una Multifirma
|
||||
* Planificar el Poder de las Multifirmas
|
||||
|
||||
## Tabla de Contenidos
|
||||
|
||||
* [Sección Uno: Enviando una Transacción a una Dirección Multifirma](06_1_Enviando_una_Transaccion_a_una_Direccion_Multifirma.md)
|
||||
* [Sección Dos: Gastando una Transacción con una Dirección Multifirma](06_2_Gastando_una_Transaccion_con_una_Direccion_Multifirma.md)
|
||||
* [Sección Tres: Enviando y Gastando una Multifirma Automatizada](06_3_Enviando_una_Multifirma_Automatizada.md)
|
206
es/06_1_Enviando_una_Transaccion_a_una_Direccion_Multifirma.md
Normal file
206
es/06_1_Enviando_una_Transaccion_a_una_Direccion_Multifirma.md
Normal file
@ -0,0 +1,206 @@
|
||||
# 6.1: Enviando una Transacción con una Multifirma
|
||||
|
||||
La primera forma de variar cómo envía una transacción básica es utilizar multifirma. Esto da la habilidad de requerir que múltiples personas (o al menos múltiples claves privadas) autoricen el uso de los fondos.
|
||||
|
||||
## Entender Cómo Funciona una Multifirma
|
||||
|
||||
En una transacción típica P2PKH o SegWit, los bitcoins son enviados a una dirección basada en su clave pública, lo que significa que se requiere la clave privada relacionada para desbloquear la transacción, resolver el rompecabezas criptográfico y permitir la reutilización de los fondos. Pero, ¿qué pasaría si pudiera bloquear una transacción con _múltiples_ claves privadas? Esto haría que efectivamente los fondos puedan ser enviados a un grupo de personas, en la que todas esas personas tengan que acordar la reutilización de los fondos.
|
||||
|
||||
> :book: ***¿Qué es una multifirma?*** Una multifirma es una metodología que permite a más de una persona la creación conjunta de una firma digital. Es una técnica general para el uso criptográfico de claves que va más allá de Bitcoin.
|
||||
|
||||
Técnicamente, un rompecabezas criptográfico multifirma es creado por Bitcoin usando el comando OP_CHECKMULTISIG, y normalmente está encapsulado en una dirección P2SH. [§10.4: Codificando una Multifirma](10_4_Codificando_una_Multifirma.md) detallará con más precisión cómo funciona. Por ahora, todo lo que debe saber es que puede usar el comando `bitcoin-cli` para crear direcciones multifirma; los fondos pueden ser enviados a estas direcciones como a cualquier otra dirección P2PKH o Segwit, pero serán requeridas múltiples claves privadas para la redención de los fondos.
|
||||
|
||||
> :book: ***¿Qué es una transacción multifirma?*** Una transacción mutifirma es una transacción de Bitcoin que ha sido enviada a una dirección multifirma, requiriendo así la firma de ciertas personas del grupo multifirma para reutilizar los fondos.
|
||||
|
||||
Multifirmas simples requieren que todos en el grupo firmen el UTXO cuando sea gastado. Sin embargo, es posible una mayor complejidad. Las multifirmas son descriptas generalmente como "m de n". Esto significa que la transacción está bloqueada con un grupo de "n" claves, pero sólo "m" de ellas son requeridas para desbloquear la transacción.
|
||||
|
||||
> :book: ***¿Qué es una multifirma m-de-n?*** En una multifirma, "m" firmas de un grupo de "n" son requeridas para formar la firma, donde "m ≤ n".
|
||||
|
||||
## Crear una Dirección Multifirma
|
||||
|
||||
A fin de bloquear una UTXO con múltiples claves privadas, debe crear primero una dirección multifirma. Los ejemplos utilizados aquí muestran la creación (y el uso) de una multifirma 2-de-2.
|
||||
|
||||
### Crear las Direcciones
|
||||
|
||||
Para crear una dirección multifirma, primero debe preparar las direcciones que combinará la multifirma. Las mejores prácticas sugieren que siempre cree nuevas direcciones. Esto significa que cada uno de los participantes correrá el comando `getnewaddress` en su propia máquina:
|
||||
```
|
||||
machine1$ address1=$(bitcoin-cli getnewaddress)
|
||||
```
|
||||
Y:
|
||||
```
|
||||
machine2$ address2=$(bitcoin-cli getnewaddress)
|
||||
```
|
||||
Luego, uno de los destinatarios (o quizás algún tercero) necesitará combinar las direcciones.
|
||||
|
||||
#### Recoger las Claves Públicas
|
||||
|
||||
Sin embargo, no puede crear una multifirma con las direcciones, pues son los hashes de las claves públicas: en su lugar necesita las claves públicas en sí.
|
||||
|
||||
Esta información está ya disponible con el comando `getaddressinfo`.
|
||||
|
||||
En la máquina remota, que asumimos que aquí es `machine2`, puede sacar la información del listado.
|
||||
```
|
||||
machine2$ bitcoin-cli -named getaddressinfo address=$address2
|
||||
{
|
||||
"address": "tb1qr2tkjh8rs9xn5xaktf5phct0wxqufplawrfd9q",
|
||||
"scriptPubKey": "00141a97695ce3814d3a1bb65a681be16f7181c487fd",
|
||||
"ismine": true,
|
||||
"solvable": true,
|
||||
"desc": "wpkh([fe6f2292/0'/0'/1']02bfde48be4aa8f4bf76c570e98a8d287f9be5638412ab38dede8e78df82f33fa3)#zc64l8dw",
|
||||
"iswatchonly": false,
|
||||
"isscript": false,
|
||||
"iswitness": true,
|
||||
"witness_version": 0,
|
||||
"witness_program": "1a97695ce3814d3a1bb65a681be16f7181c487fd",
|
||||
"pubkey": "02bfde48be4aa8f4bf76c570e98a8d287f9be5638412ab38dede8e78df82f33fa3",
|
||||
"ischange": false,
|
||||
"timestamp": 1592957904,
|
||||
"hdkeypath": "m/0'/0'/1'",
|
||||
"hdseedid": "1dc70547f2b80e9bb5fde5f34fb3d85f8d8d1dab",
|
||||
"hdmasterfingerprint": "fe6f2292",
|
||||
"labels": [
|
||||
""
|
||||
]
|
||||
}
|
||||
```
|
||||
La dirección `pubkey` (`02bfde48be4aa8f4bf76c570e98a8d287f9be5638412ab38dede8e78df82f33fa3`) es lo que se requiere. Cópielo en su máquina local por cualquier medio que le resulte más eficiente y _menos propenso a errores_.
|
||||
|
||||
Este proceso necesita ser emprendido para _cada_ dirección desde una máquina diferente de la que se está construyendo la multifirma. Obviamente, si algún tercero está creando la dirección, deberá hacer esto para cada dirección.
|
||||
|
||||
> :warning: **AVISO:** El uso en Bitcoin de los hashes de las claves-públicas como direcciones, en lugar de las claves públicas, en realidad representa una capa adicional de seguridad. Por lo tanto, enviar una clave pública aumenta ligeramente la vulnerabilidad de la dirección asociada, por alguna posibilidad en el futuro lejano de un compromiso de la curva elíptica. No debe preocuparse por tener que enviar ocasionalmente una clave pública para un uso como este, pero debe tener en cuenta que los hashes de las claves públicas representan seguridad y, por lo tanto, las claves públicas reales no deben enviarse a la ligera.
|
||||
|
||||
Si una de las direcciones se creó en su máquina local, que asumimos que aquí es `machine1`, puede simplemente volcar la dirección `pubkey` a una nueva variable.
|
||||
```
|
||||
machine1$ pubkey1=$(bitcoin-cli -named getaddressinfo address=$address1 | jq -r '.pubkey')
|
||||
```
|
||||
|
||||
### Crear la dirección
|
||||
|
||||
Una multifirma puede crearse ahora con el comando `createmultisig`:
|
||||
```
|
||||
machine1$ bitcoin-cli -named createmultisig nrequired=2 keys='''["'$pubkey1'","02bfde48be4aa8f4bf76c570e98a8d287f9be5638412ab38dede8e78df82f33fa3"]'''
|
||||
{
|
||||
"address": "2N8MytPW2ih27LctLjn6LfLFZZb1PFSsqBr",
|
||||
"redeemScript": "522102da2f10746e9778dd57bd0276a4f84101c4e0a711f9cfd9f09cde55acbdd2d1912102bfde48be4aa8f4bf76c570e98a8d287f9be5638412ab38dede8e78df82f33fa352ae",
|
||||
"descriptor": "sh(multi(2,02da2f10746e9778dd57bd0276a4f84101c4e0a711f9cfd9f09cde55acbdd2d191,02bfde48be4aa8f4bf76c570e98a8d287f9be5638412ab38dede8e78df82f33fa3))#0pazcr4y"
|
||||
}
|
||||
```
|
||||
> :warning: **AVISO DE VERSION:** Algunas versiones de `createmultisig` han permitido el ingreso de claves públicas o direcciones, algunas han requerido sólo claves públicas. Actualmente, cualquiera de las dos parece estar permitida.
|
||||
|
||||
Al crear la dirección multifirma, liste cuántas firmas se requieren con el argumento `nrequired` (esto es "m" en una multifirma "m-de-n"), luego liste el conjunto total de posibles firmas con el argumento `keys` (que es "n"). Tenga en cuenta que las entradas de las `keys` probablemente provienen de diferentes lugares. En este caso, incluimos `$pubkey1` de la máquina local y `02bfde48be4aa8f4bf76c570e98a8d287f9be5638412ab38dede8e78df82f33fa3` de una máquina remota.
|
||||
|
||||
> :information_source: **NOTA — M-DE-N VS N-DE-N:** Este ejemplo muestra la creación de una simple multifirma 2-de-2. Si en cambio quiere crear una firma m-de-n donde "m < n", ajuste el campo `nrequired` y/o el número de firmas en el objeto JSON `keys`. Para una multifirma 1-de-2, debería configurar `nrequired=1` y también listar dos claves, mientras que para una multifirma 2-de-3, debería dejar `nrequired=2`, pero agregar una clave pública más a la lista `keys`.
|
||||
|
||||
Cuando es usado correctamente, `createmultisig` devuelve tres resultados, siendo todos de importancia crítica.
|
||||
|
||||
_address_ es lo que dará a la gente que desee enviar fondos. Verá que tiene un nuevo prefijo de `2`, exactamente como aquellas direcciones P2SH-SegWit. Eso es porque, como aquellas, `createmultisig` está creando un tipo totalmente nuevo de dirección llamada P2SH. Funciona exactamente igual que una direcciópn P2PKH estándar para enviar fondos, pero como esta se desarrolló para requerir direcciones múltiples, necesitará hacer algunas tareas más para gastarlas.
|
||||
|
||||
> :link: **TESTNET vs MAINNET:** En testnet, el prefijo para direcciones P2SH es `2`, mientras que en mainnet, es `3`.
|
||||
|
||||
El _redeemScript_ es lo que necesita para redimir los fondos (junto a las claves privadas para "m" de the "n" direcciones). Este script es otra característica especial de las direcciones P2SH y será explicada completamente en [§10.3: Ejecutando un script de Bitcoin con P2SH](10_3_Ejecutando_un_Script_Bitcoin_con_P2SH.md). Por ahora, sólo debe saber que es algo más de data lo que se requiere para obtener su dinero.
|
||||
|
||||
_descriptor_ es la descripción estandarizada de una dirección que conocimos en [§3.5: Entendiendo El Descriptor](03_5_Entendiendo_El_Descriptor.md). Provee una forma en la que podría importar esta dirección nuevamente a la otra máquina, usando el RPC `importmulti`.
|
||||
|
||||
> :book: ***¿Qué es una dirección P2SH?*** P2SH significa Pay-to-script-hash. Es un tipo diferente de destinatario que una dirección P2PKH estándar o incluso una Bech32, se usa para fondos cuya redención está basada en Scripts de Bitcoin más complejos. `bitcoin-cli` usa encapsulamiento P2SH para ayudar a estandarizar y simplificar sus multifirmas como "P2SH multisigs", igual que P2SH-SegWit usaba P2SH para estandarizar sus direcciones SegWit y hacerlas totalmente compatibles con versiones anteriores.
|
||||
|
||||
> :warning: **AVISO:** las direcciones multifirma P2SH, como las creadas por `bitcoin-cli`, tienen un límite de "m" y "n" en multifirmas basadas en el tamaño máximo del script de redención, que actualmente es de 520 bytes. Prácticamente, no llegará a menos que haga algo excesivo.
|
||||
|
||||
### Guardar su trabajo
|
||||
|
||||
Aquí hay una advertencia importante: nada acerca de su multifirma se guarda en su billetera usando estas técnicas básicas. A fin de redimir dinero luego enviado a esta dirección multifirma, necesitará retener dos piezas cruciales de información:
|
||||
|
||||
* Una lista de las direcciones de Bitcoin usadas en la multifirma.
|
||||
* La salida `redeemScript` del `createmultsig`.
|
||||
|
||||
Técnicamente, el `redeemScript` puede ser recreado corriendo nuevamente `createmultisig` con la lista completa de claves públicas _en el mismo orden_ y con la cuenta correcta de m-de-n. Pero, es mejor guardar su trabajo y evitar estrés y penas luego.
|
||||
|
||||
### Observar el Orden
|
||||
|
||||
Aquí hay una cosa de la que debe tener mucho cuidado: _el orden es importante_. El orden de las claves utilizadas para crear una multi-firma crea un hash único, es decir, si coloca las claves en un orden diferente, producirán una dirección diferente, como se muestra:
|
||||
```
|
||||
$ bitcoin-cli -named createmultisig nrequired=2 keys='''["'$pubkey1'","'$pubkey2'"]'''
|
||||
{
|
||||
"address": "2NFBQvz57UzKWDr2Vx5D667epVZifjGixkm",
|
||||
"redeemScript": "52210342b306e410283065ffed38c3139a9bb8805b9f9fa6c16386e7ea96b1ba54da0321039cd6842869c1bfec13cfdbb7d8285bc4c501d413e6633e3ff75d9f13424d99b352ae",
|
||||
"descriptor": "sh(multi(2,0342b306e410283065ffed38c3139a9bb8805b9f9fa6c16386e7ea96b1ba54da03,039cd6842869c1bfec13cfdbb7d8285bc4c501d413e6633e3ff75d9f13424d99b3))#8l6hvjsk"
|
||||
}
|
||||
standup@btctest20:~$ bitcoin-cli -named createmultisig nrequired=2 keys='''["'$pubkey2'","'$pubkey1'"]'''
|
||||
{
|
||||
"address": "2N5bC4Yc5Pqept1y8nPRqvWmFSejkVeRb1k",
|
||||
"redeemScript": "5221039cd6842869c1bfec13cfdbb7d8285bc4c501d413e6633e3ff75d9f13424d99b3210342b306e410283065ffed38c3139a9bb8805b9f9fa6c16386e7ea96b1ba54da0352ae",
|
||||
"descriptor": "sh(multi(2,039cd6842869c1bfec13cfdbb7d8285bc4c501d413e6633e3ff75d9f13424d99b3,0342b306e410283065ffed38c3139a9bb8805b9f9fa6c16386e7ea96b1ba54da03))#audl88kg"
|
||||
}
|
||||
```
|
||||
Más notablemente, cada ordenamiento crea un diferente _redeemScript_. Esto significa que si se utilizan estas técnicas básicas y no se guarda el redeemScript como se indicó, tendrá que recorrer un número cada vez mayor de variaciones para encontrar la correcta cuando intente gastar sus fondos!
|
||||
|
||||
[BIP67](https://github.com/bitcoin/bips/blob/master/bip-0067.mediawiki) sugiere una forma de ordenar claves lexicográficamente, de manera que siempre generen las mismas multifirmas. ColdCard y Electrum están entre las billeteras que ya soportan esto. Por supuesto, esto puede causar problemas por sí solo si no sabe si una dirección multifirma se creó con claves ordenadas o no ordenadas. Una vez más, [descriptors](03_5_Entendiendo_El_Descriptor.md) vienen al rescate. Si una multifirma es no ordenada, está construída con la función `multi` y si es ordenada está construída con la función `sortedmulti`.
|
||||
|
||||
Si observa el `descriptor` para la multifirma creada anteriormente, verá que Bitcoin Core no ordena actualmente sus multifirmas:
|
||||
```
|
||||
"descriptor": "sh(multi(2,02da2f10746e9778dd57bd0276a4f84101c4e0a711f9cfd9f09cde55acbdd2d191,02bfde48be4aa8f4bf76c570e98a8d287f9be5638412ab38dede8e78df82f33fa3))#0pazcr4y"
|
||||
```
|
||||
Sin embargo, si importa una dirección con el tipo `sortedmulti`, hará lo correcto, que es para lo que están los descriptores!
|
||||
|
||||
> :warning: **AVISO DE VERSION:** Bitcoin Core sólo entiende la función descriptor `sortedmulti` comenzando por la v 0.20.0. Intenta acceder al descriptor en una versión anterior de Bitcoin Core y obtendrá un error como `A function is needed within P2WSH` (Una función es necesaria dentro de PSWSH).
|
||||
|
||||
## Enviar a una dirección Multifirma
|
||||
|
||||
Si tiene una multifirma en un formato P2SH conveniente, como la generada por `bitcoin-cli`, puede ser enviada exactamente como una dirección normal.
|
||||
```
|
||||
$ utxo_txid=$(bitcoin-cli listunspent | jq -r '.[0] | .txid')
|
||||
$ utxo_vout=$(bitcoin-cli listunspent | jq -r '.[0] | .vout')
|
||||
$ recipient="2N8MytPW2ih27LctLjn6LfLFZZb1PFSsqBr"
|
||||
|
||||
$ rawtxhex=$(bitcoin-cli -named createrawtransaction inputs='''[ { "txid": "'$utxo_txid'", "vout": '$utxo_vout' } ]''' outputs='''{ "'$recipient'": 0.000065}''')
|
||||
$ bitcoin-cli -named decoderawtransaction hexstring=$rawtxhex
|
||||
{
|
||||
"txid": "b164388854f9701051809eed166d9f6cedba92327e4296bf8a265a5da94f6521",
|
||||
"hash": "b164388854f9701051809eed166d9f6cedba92327e4296bf8a265a5da94f6521",
|
||||
"version": 2,
|
||||
"size": 83,
|
||||
"vsize": 83,
|
||||
"weight": 332,
|
||||
"locktime": 0,
|
||||
"vin": [
|
||||
{
|
||||
"txid": "c6de60427b28d8ec8102e49771e5d0348fc3ef6a5bf02eb864ec745105a6951b",
|
||||
"vout": 0,
|
||||
"scriptSig": {
|
||||
"asm": "",
|
||||
"hex": ""
|
||||
},
|
||||
"sequence": 4294967295
|
||||
}
|
||||
],
|
||||
"vout": [
|
||||
{
|
||||
"value": 0.00006500,
|
||||
"n": 0,
|
||||
"scriptPubKey": {
|
||||
"asm": "OP_HASH160 a5d106eb8ee51b23cf60d8bd98bc285695f233f3 OP_EQUAL",
|
||||
"hex": "a914a5d106eb8ee51b23cf60d8bd98bc285695f233f387",
|
||||
"reqSigs": 1,
|
||||
"type": "scripthash",
|
||||
"addresses": [
|
||||
"2N8MytPW2ih27LctLjn6LfLFZZb1PFSsqBr"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
$ signedtx=$(bitcoin-cli -named signrawtransactionwithwallet hexstring=$rawtxhex | jq -r '.hex')
|
||||
$ bitcoin-cli -named sendrawtransaction hexstring=$signedtx
|
||||
b164388854f9701051809eed166d9f6cedba92327e4296bf8a265a5da94f6521
|
||||
```
|
||||
Como puede ver, no hubo nada inusual en la creación de la transacción, y se veía completamente normal, aunque con una dirección con un prefijo diferente al normal (`2N8MytPW2ih27LctLjn6LfLFZZb1PFSsqBr`). Sin sorpresas, como vimos de la misma forma en que enviamos a direcciones Bech32 por primera vez en [§4.6: Creando una Transacción Segwit](04_6_Creando_una_Transaccion_Segwit.md).
|
||||
|
||||
## Resumen: Enviando una Transacción a una Dirección Multifirma
|
||||
|
||||
Las direcciones Multifirmas bloquean fondos en varias claves privadas - requiriendo posiblemente todas esas claves privadas para la redención, y requiriendo posiblemente sólo algunas del conjunto. Son bastante fáciles de crear con `bitcoin-cli` y son enteramente normales para enviar. Esta facilidad es debido en gran parte al uso invisible de direcciones P2SH (pay-to-script-hash), un gran tema que ya hemos abordado dos veces, con direcciones P2SH-SegWit y multifirma, y que tendrá más cobertura en el futuro.
|
||||
|
||||
> :fire: ***¿Cuál es el poder de las multifirmas?*** Las multifirmas permiten el modelado de una variedad de acuerdos financieros, como corporaciones, sociedades, comites, y otros grupos. Una multifirma 1-de-2 puede ser una cuenta conjunta de una pareja casada, mientras que una Sociedad de Responsabilidad Limitada podría utilizar una multifirma 2 de 2 para grandes gastos. Las multifirmas también forman una de las bases de los Contratos Inteligentes. Por ejemplo, un acuerdo de bienes raíces podría cerrarse con una multifirma 2 de 3, donde las firmas son enviadas por el comprador, el vendedor y un agente de custodia. Una vez que el agente de custodia acepta que se han cumplido todas las condiciones, libera los fondos para el vendedor; o alternativamente, el comprador y el vendedor pueden liberar conjuntamente los fondos.
|
||||
|
||||
## ¿Qué sigue?
|
||||
|
||||
Continuar "Expandiendo Transacciones Bitcoin" con [§6.2: Gastando una Transacción con una Dirección Multifirma](06_2_Gastando_una_Transaccion_con_una_Direccion_Multifirma.md).
|
229
es/06_2_Gastando_una_Transaccion_con_una_Direccion_Multifirma.md
Normal file
229
es/06_2_Gastando_una_Transaccion_con_una_Direccion_Multifirma.md
Normal file
@ -0,0 +1,229 @@
|
||||
# 6.2: Gastando una Transacción con una Multifirma
|
||||
|
||||
La clásica, y compleja, forma de gastar fondos enviados a una dirección multifirma usando `bitcoin-cli` requiere mucho trabajo.
|
||||
|
||||
## Encontrar Sus Fondos
|
||||
|
||||
Para empezar, necesita encontrar sus fondos; su computadora no sabe buscarlos, porque no están asociados con ninguna dirección en su billetera. Puede alertar a `bitcoind` para hacerlo usando el comando `importaddress`:
|
||||
```
|
||||
$ bitcoin-cli -named importaddress address=2NAGfA4nW6nrZkD5je8tSiAcYB9xL2xYMCz
|
||||
```
|
||||
Si tiene un nodo podado (y probablemente lo tenga), tendrá que decirle que no vuelva a escanear:
|
||||
```
|
||||
$ bitcoin-cli -named importaddress address=2NAGfA4nW6nrZkD5je8tSiAcYB9xL2xYMCz rescan="false"
|
||||
```
|
||||
Si prefiere, puede importar la dirección usando su descriptor (y esta es generalmente la mejor, más estandarizada respuesta):
|
||||
```
|
||||
$ bitcoin-cli importmulti '[{"desc": "sh(multi(2,02da2f10746e9778dd57bd0276a4f84101c4e0a711f9cfd9f09cde55acbdd2d191,02bfde48be4aa8f4bf76c570e98a8d287f9be5638412ab38dede8e78df82f33fa3))#0pazcr4y", "timestamp": "now", "watchonly": true}]'
|
||||
[
|
||||
{
|
||||
"success": true
|
||||
}
|
||||
]
|
||||
```
|
||||
Posteriormente, los fondos deberían aparecer cuando haga `listunspent` ... pero aún así no son fáciles de gastar. (De hecho, su billetera puede afirmar que no se pueden gastar `spendable` en absoluto!)
|
||||
|
||||
Si por alguna razón no le es posible incorporar la dirección a su billetera, puede usar `gettransaction` para obtener la info (o mirar en un explorador de bloques).
|
||||
```
|
||||
$ bitcoin-cli -named gettransaction txid=b164388854f9701051809eed166d9f6cedba92327e4296bf8a265a5da94f6521 verbose=true
|
||||
{
|
||||
"amount": -0.00006500,
|
||||
"fee": -0.00001000,
|
||||
"confirmations": 3,
|
||||
"blockhash": "0000000000000165b5f602920088a7e36b11214161d6aaebf5229e3ed4f10adc",
|
||||
"blockheight": 1773282,
|
||||
"blockindex": 9,
|
||||
"blocktime": 1592959320,
|
||||
"txid": "b164388854f9701051809eed166d9f6cedba92327e4296bf8a265a5da94f6521",
|
||||
"walletconflicts": [
|
||||
],
|
||||
"time": 1592958753,
|
||||
"timereceived": 1592958753,
|
||||
"bip125-replaceable": "no",
|
||||
"details": [
|
||||
{
|
||||
"address": "2N8MytPW2ih27LctLjn6LfLFZZb1PFSsqBr",
|
||||
"category": "send",
|
||||
"amount": -0.00006500,
|
||||
"vout": 0,
|
||||
"fee": -0.00001000,
|
||||
"abandoned": false
|
||||
}
|
||||
],
|
||||
"hex": "020000000001011b95a6055174ec64b82ef05b6aefc38f34d0e57197e40281ecd8287b4260dec60000000000ffffffff01641900000000000017a914a5d106eb8ee51b23cf60d8bd98bc285695f233f38702473044022070275f81ac4129e1d167ef7e700739f2899ea4c7f1adef3a4da29436f14fb97e02207310d4ec449eba49f0fa404ae45b9c82431d883490c7a0ed882ad0b5d7a623d0012102883bb5463e37d55252d8b3d5c2141b007b37c8a7db6211f75c955acc5ea325eb00000000",
|
||||
"decoded": {
|
||||
"txid": "b164388854f9701051809eed166d9f6cedba92327e4296bf8a265a5da94f6521",
|
||||
"hash": "bdf4e3bc5d354a5dfa5528f172480976321d989d7e5806ac14f1fe9b0b1c093a",
|
||||
"version": 2,
|
||||
"size": 192,
|
||||
"vsize": 111,
|
||||
"weight": 441,
|
||||
"locktime": 0,
|
||||
"vin": [
|
||||
{
|
||||
"txid": "c6de60427b28d8ec8102e49771e5d0348fc3ef6a5bf02eb864ec745105a6951b",
|
||||
"vout": 0,
|
||||
"scriptSig": {
|
||||
"asm": "",
|
||||
"hex": ""
|
||||
},
|
||||
"txinwitness": [
|
||||
"3044022070275f81ac4129e1d167ef7e700739f2899ea4c7f1adef3a4da29436f14fb97e02207310d4ec449eba49f0fa404ae45b9c82431d883490c7a0ed882ad0b5d7a623d001",
|
||||
"02883bb5463e37d55252d8b3d5c2141b007b37c8a7db6211f75c955acc5ea325eb"
|
||||
],
|
||||
"sequence": 4294967295
|
||||
}
|
||||
],
|
||||
"vout": [
|
||||
{
|
||||
"value": 0.00006500,
|
||||
"n": 0,
|
||||
"scriptPubKey": {
|
||||
"asm": "OP_HASH160 a5d106eb8ee51b23cf60d8bd98bc285695f233f3 OP_EQUAL",
|
||||
"hex": "a914a5d106eb8ee51b23cf60d8bd98bc285695f233f387",
|
||||
"reqSigs": 1,
|
||||
"type": "scripthash",
|
||||
"addresses": [
|
||||
"2N8MytPW2ih27LctLjn6LfLFZZb1PFSsqBr"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Configurar Sus Variables
|
||||
|
||||
Cuando esté listo para gastar los fondos recibidos por una dirección de multifirma, necesitará recopilar _muchos_ datos: mucho más de lo que necesita cuando gasta un P2PKH normal o un UTXO SegWit. Esto se debe en parte a que la información de la dirección multifirma no está en su billetera, y en parte a que está gastando dinero que se envió a una dirección P2SH (pago a script-hash), y eso es mucho más exigente.
|
||||
|
||||
En total, necesitará recopilar tres cosas: información ampliada sobre el UTXO; el redeemScript; y todas las claves privadas involucradas. Por supuesto, también necesitará una nueva dirección de destinatario. Las claves privadas deben esperar el paso de firma, pero todo lo demás se puede hacer ahora.
|
||||
|
||||
### Acceder a la información del UTXO
|
||||
|
||||
Para empezar, tome la `txid` y la `vout` para la transacción que desea gastar, como es habitual. En este caso, se recuperó de la información de `gettransaction`, arriba:
|
||||
```
|
||||
$ utxo_txid=b164388854f9701051809eed166d9f6cedba92327e4296bf8a265a5da94f6521
|
||||
$ utxo_vout=0
|
||||
```
|
||||
Sin embargo, necesita acceder también a una tercera parte de la información acerca del UTXO, es `scriptPubKey`/`hex`, que es el script que bloqueó la transacción. Nuevamente, probablemente está haciendo esto mirando los detalles de la transacción:
|
||||
```
|
||||
$ utxo_spk=a914a5d106eb8ee51b23cf60d8bd98bc285695f233f387
|
||||
```
|
||||
|
||||
### Registrar el Script de Redención
|
||||
|
||||
Con suerte, ha guardado el `redeemScript`. Ahora debería registrarlo en una variable.
|
||||
|
||||
Esto se extrajo de nuestra creación de la dirección en la sección anterior.
|
||||
```
|
||||
redeem_script="522102da2f10746e9778dd57bd0276a4f84101c4e0a711f9cfd9f09cde55acbdd2d1912102bfde48be4aa8f4bf76c570e98a8d287f9be5638412ab38dede8e78df82f33fa352ae"
|
||||
```
|
||||
### Decidir Su Destinatario
|
||||
|
||||
Nos enviaremos el dinero a nosotros mismos. Esto es útil porque libera los fondos de la multifirma, convirtiéndolos en una transacción P2PKH normal que luego puede ser confirmada por una sola clave privada:
|
||||
```
|
||||
$ recipient=$(bitcoin-cli getrawchangeaddress)
|
||||
```
|
||||
## Crear Su Transacción
|
||||
|
||||
Ahora puede crear su transacción. Esto no es diferente de lo habitual.
|
||||
```
|
||||
$ rawtxhex=$(bitcoin-cli -named createrawtransaction inputs='''[ { "txid": "'$utxo_txid'", "vout": '$utxo_vout' } ]''' outputs='''{ "'$recipient'": 0.00005}''')
|
||||
$ echo $rawtxhex
|
||||
020000000121654fa95d5a268abf96427e3292baed6c9f6d16ed9e80511070f954883864b10000000000ffffffff0188130000000000001600142c48d3401f6abed74f52df3f795c644b4398844600000000
|
||||
```
|
||||
|
||||
## Firmar Su Transacción
|
||||
|
||||
Ahora está listo para firma su transacción. Este es un proceso de varios pasos porque deberá hacerlo en varias máquinas, cada una de las cuales contribuirá con sus propias claves privadas.
|
||||
|
||||
### Descargar Su Primera Clave Privada
|
||||
|
||||
Debido a que esta transacción no está haciendo un uso completo de su billetera, necesitará acceder directamente a sus claves privadas. Comience en `machine1`, donde debe recuperar cualquiera de las claves privadas de ese usuario que estuvieron involucradas en la multifirma:
|
||||
```
|
||||
machine1$ bitcoin-cli -named dumpprivkey address=$address1
|
||||
cNPhhGjatADfhLD5gLfrR2JZKDE99Mn26NCbERsvnr24B3PcSbtR
|
||||
```
|
||||
> :warning: **ATENCIÓN:** Acceder directamente a sus claves privadas desde el shell es un comportamiento muy peligroso y debe hacerse con sumo cuidado si está usando dinero real. Al menos, no guarde la información en una variable a la que se pueda acceder desde su máquina. Eliminar el historial de su shell es otro gran paso. A lo sumo, no lo haga.
|
||||
|
||||
### Hacer Su Primer Firma
|
||||
|
||||
Ahora puede hacer su primer firma con el comando `signrawtransactionwithkey`. Aquí es donde las cosas son diferentes: necesitará instruir al comando sobre cómo firmar. Puede hacer esto agregando la siguiente información nueva:
|
||||
|
||||
* Incluya un argumento `prevtxs` que incluya la `txid`, la `vout`, la `scriptPubKey`, y la `redeemScript` que registró, cada una de ellas un par key-value en el objeto JSON.
|
||||
* Incluya un argumento `privkeys` que liste las claves privadas que descargó en esta máquina.
|
||||
|
||||
```
|
||||
machine1$ bitcoin-cli -named signrawtransactionwithkey hexstring=$rawtxhex prevtxs='''[ { "txid": "'$utxo_txid'", "vout": '$utxo_vout', "scriptPubKey": "'$utxo_spk'", "redeemScript": "'$redeem_script'" } ]''' privkeys='["cNPhhGjatADfhLD5gLfrR2JZKDE99Mn26NCbERsvnr24B3PcSbtR"]'
|
||||
{
|
||||
"hex": "020000000121654fa95d5a268abf96427e3292baed6c9f6d16ed9e80511070f954883864b100000000920047304402201c97b48215f261055e41b765ab025e77a849b349698ed742b305f2c845c69b3f022013a5142ef61db1ff425fbdcdeb3ea370aaff5265eee0956cff9aa97ad9a357e3010047522102da2f10746e9778dd57bd0276a4f84101c4e0a711f9cfd9f09cde55acbdd2d1912102bfde48be4aa8f4bf76c570e98a8d287f9be5638412ab38dede8e78df82f33fa352aeffffffff0188130000000000001600142c48d3401f6abed74f52df3f795c644b4398844600000000",
|
||||
"complete": false,
|
||||
"errors": [
|
||||
{
|
||||
"txid": "b164388854f9701051809eed166d9f6cedba92327e4296bf8a265a5da94f6521",
|
||||
"vout": 0,
|
||||
"witness": [
|
||||
],
|
||||
"scriptSig": "0047304402201c97b48215f261055e41b765ab025e77a849b349698ed742b305f2c845c69b3f022013a5142ef61db1ff425fbdcdeb3ea370aaff5265eee0956cff9aa97ad9a357e3010047522102da2f10746e9778dd57bd0276a4f84101c4e0a711f9cfd9f09cde55acbdd2d1912102bfde48be4aa8f4bf76c570e98a8d287f9be5638412ab38dede8e78df82f33fa352ae",
|
||||
"sequence": 4294967295,
|
||||
"error": "CHECK(MULTI)SIG failing with non-zero signature (possibly need more signatures)"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
```
|
||||
Eso produce errores aterradores y dice que está `fallando`. Esto está bien. Puede ver que la firma se ha realizado parcialmente correcta porque el `hex` se ha alargado. Aunque la transacción se ha firmado parcialmente, no se realiza porque necesita más firmas.
|
||||
|
||||
### Repetir para Otros Firmantes
|
||||
|
||||
Ahora puede transferir la transacción, para que la vuelva a firmar cualquier otra persona requerida para la multifirma. Hacen esto corriendo el mismo comando de firma que hizo pero: (1) con el `hex` más largo que sacó de (`bitcoin-cli -named signrawtransactionwithkey hexstring=$rawtxhex prevtxs='''[ { "txid": "'$utxo_txid'", "vout": '$utxo_vout', "scriptPubKey": "'$utxo_spk'", "redeemScript": "'$redeem_script'" } ]''' privkeys='["cMgb3KM8hPATCtgMKarKMiFesLft6eEw3DY6BB8d97fkeXeqQagw"]' | jq -r '.hex'`); y (2) con su propia clave privada.
|
||||
|
||||
> :information_source: **NOTA — M-DE-N VS N-DE-N:** Obviamente, si tiene una firma n-de-n (como la multifirma 2-de-2 en este ejemplo), entonces todos deben firmar, pero si tiene una multifirma m-de-n donde "m < n", entonces la firma estará completa cuando sólo alguno ("m") de los firmantes haya firmado.
|
||||
|
||||
Para hacerlo primero acceden a sus claves privadas:
|
||||
```
|
||||
machine2$ bitcoin-cli -named dumpprivkey address=$address2
|
||||
cVhqpKhx2jgfLUWmyR22JnichoctJCHPtPERm11a2yxnVFKWEKyz
|
||||
```
|
||||
Segundo, firman el nuevo `hex` usando los mismos valores `prevtxs`:
|
||||
```
|
||||
machine1$ bitcoin-cli -named signrawtransactionwithkey hexstring=020000000121654fa95d5a268abf96427e3292baed6c9f6d16ed9e80511070f954883864b100000000920047304402201c97b48215f261055e41b765ab025e77a849b349698ed742b305f2c845c69b3f022013a5142ef61db1ff425fbdcdeb3ea370aaff5265eee0956cff9aa97ad9a357e3010047522102da2f10746e9778dd57bd0276a4f84101c4e0a711f9cfd9f09cde55acbdd2d1912102bfde48be4aa8f4bf76c570e98a8d287f9be5638412ab38dede8e78df82f33fa352aeffffffff0188130000000000001600142c48d3401f6abed74f52df3f795c644b4398844600000000 prevtxs='''[ { "txid": "'$utxo_txid'", "vout": '$utxo_vout', "scriptPubKey": "'$utxo_spk'", "redeemScript": "'$redeem_script'" } ]''' privkeys='["cVhqpKhx2jgfLUWmyR22JnichoctJCHPtPERm11a2yxnVFKWEKyz"]'
|
||||
{
|
||||
"hex": "020000000121654fa95d5a268abf96427e3292baed6c9f6d16ed9e80511070f954883864b100000000d90047304402201c97b48215f261055e41b765ab025e77a849b349698ed742b305f2c845c69b3f022013a5142ef61db1ff425fbdcdeb3ea370aaff5265eee0956cff9aa97ad9a357e301473044022000a402ec4549a65799688dd531d7b18b03c6379416cc8c29b92011987084e9f402205470e24781509c70e2410aaa6d827aa133d6df2c578e96a496b885584fb039200147522102da2f10746e9778dd57bd0276a4f84101c4e0a711f9cfd9f09cde55acbdd2d1912102bfde48be4aa8f4bf76c570e98a8d287f9be5638412ab38dede8e78df82f33fa352aeffffffff0188130000000000001600142c48d3401f6abed74f52df3f795c644b4398844600000000",
|
||||
"complete": true
|
||||
}
|
||||
```
|
||||
Tercero, puede que necesiten enviar en la aún más larga `hexstring` que producen para firmantes adicionales.
|
||||
|
||||
Pero en este caso, vemos ahora que la firma está `completa`!
|
||||
|
||||
## Enviar Su Transacción
|
||||
|
||||
Una vez terminado, debería volver a la metodología JQ estándar para guardar su `hexstring` y luego enviarla:
|
||||
```
|
||||
$ signedtx=$(bitcoin-cli -named signrawtransactionwithkey hexstring=020000000121654fa95d5a268abf96427e3292baed6c9f6d16ed9e80511070f954883864b100000000920047304402201c97b48215f261055e41b765ab025e77a849b349698ed742b305f2c845c69b3f022013a5142ef61db1ff425fbdcdeb3ea370aaff5265eee0956cff9aa97ad9a357e3010047522102da2f10746e9778dd57bd0276a4f84101c4e0a711f9cfd9f09cde55acbdd2d1912102bfde48be4aa8f4bf76c570e98a8d287f9be5638412ab38dede8e78df82f33fa352aeffffffff0188130000000000001600142c48d3401f6abed74f52df3f795c644b4398844600000000 prevtxs='''[ { "txid": "'$utxo_txid'", "vout": '$utxo_vout', "scriptPubKey": "'$utxo_spk'", "redeemScript": "'$redeem_script'" } ]''' privkeys='["cVhqpKhx2jgfLUWmyR22JnichoctJCHPtPERm11a2yxnVFKWEKyz"]' | jq -r .hex)
|
||||
$ bitcoin-cli -named sendrawtransaction hexstring=$signedtx
|
||||
99d2b5717fed8875a1ed3b2827dd60ae3089f9caa7c7c23d47635f6f5b397c04
|
||||
```
|
||||
|
||||
## Comprendiendo la Importancia de Esta Metodología de Firmado Expandida
|
||||
|
||||
Esto requirió algo de trabajo, y como aprenderá pronto, la tontería con las claves privadas, el script de redención y el scriptpubkey en realidad no es necesario para redimir desde direcciones de firmas múltiples utilizando versiones más nuevas de Bitcoin Core. ¿De qué se trata, entonces?
|
||||
|
||||
Esta metodología de redención muestra una forma estándar de firmar y reutilizar transacciones P2SH. En síntesis, para redimir fondos P2SH, una `signrawtransactionwithkey` necesita:
|
||||
|
||||
1. Incluir la `scriptPubKey`, lo que explica el rompecabezas criptográfico P2SH.
|
||||
2. Incluir el `redeemScript`, que resuelve el rompecabezas criptográfico P2SH, e introduce un nuevo rompecabezas propio.
|
||||
3. Ejecutarse en cada máquina que tenga las claves privadas requeridas.
|
||||
4. Incluir las firmas relevantes, que resuelve el rompecabezas redeemScript.
|
||||
|
||||
Aquí, vimos esta metodología utilizada para redimir fondos multifirma. En el futuro también puede usarlo para redimir fondos que estaban bloqueados con otros, scripts P2SH más complejos, como se explica a partir del Capítulo 9.
|
||||
|
||||
## Resumen: Gastando una Transacción con una Multifirma
|
||||
|
||||
Resulta que gastar dinero enviado a una dirección multifirma puede requerir bastante trabajo. Pero siempre que tenga sus direcciones originales y su redeemScript, puede hacerlo firmando una transacción sin procesar con cada dirección diferente y proporcionando más información en el camino.
|
||||
|
||||
## ¿Qué sigue?
|
||||
|
||||
Continuar "Expandiendo Transacciones Bitcoin" con [§6.3: Enviando & Gastando una Multifirma Automatizada](06_3_Enviando_una_Multifirma_Automatizada.md).
|
119
es/06_3_Enviando_una_Multifirma_Automatizada.md
Normal file
119
es/06_3_Enviando_una_Multifirma_Automatizada.md
Normal file
@ -0,0 +1,119 @@
|
||||
# 6.3: Enviando & Gastando una Multifirma Automatizada
|
||||
|
||||
La técnica estándar para crear direcciones de multifirma y para gastar sus fondos es compleja, pero es un ejercicio que vale la pena para comprender un poco más sobre cómo funcionan y cómo puede manipularlas a un nivel relativamente bajo. Sin embargo, Bitcoin Core ha facilitado un poco las multifirmas en los nuevos lanzamientos.
|
||||
|
||||
> :warning: **AVISO DE VERSION:** El comando `addmultisigaddress` está disponible en Bitcoin Core v 0.10 o superior.
|
||||
|
||||
## Crear una Dirección Multifirma en Su Billetera
|
||||
|
||||
Para que los fondos enviados a direcciones multifirma sean más fáciles de gastar, sólo necesita hacer algunos preparativos usando el comando `addmultisigaddress`. Probablemente no sea lo que le gustaría hacer si estuviera escribiendo programas de billetera multifirma, pero si sólo estuviera tratando de recibir algunos fondos a mano, podría ahorrarse algunos tirones de pelo.
|
||||
|
||||
### Recolectar las Claves
|
||||
Empieza creando direcciones P2PKH y recuperando claves públicas, como es habitual, para cada usuario que formará parte de la multifirma:
|
||||
```
|
||||
machine1$ address3=$(bitcoin-cli getnewaddress)
|
||||
machine1$ echo $address3
|
||||
tb1q4ep2vmakpkkj6mflu94x5f94q662m0u5ad0t4w
|
||||
machine1$ bitcoin-cli -named getaddressinfo address=$address3 | jq -r '.pubkey'
|
||||
0297e681bff16cd4600138449e2527db4b2f83955c691a1b84254ecffddb9bfbfc
|
||||
|
||||
machine2$ address4=$(bitcoin-cli getnewaddress)
|
||||
machine2$ echo $address4
|
||||
tb1qa9v5h6zkhq8wh0etnv3ae9cdurkh085xufl3de
|
||||
machine2$ bitcoin-cli -named getaddressinfo address=$address4 | jq -r '.pubkey'
|
||||
02a0d96e16458ff0c90db4826f86408f2cfa0e960514c0db547ff152d3e567738f
|
||||
```
|
||||
|
||||
### Crear la Dirección Multifirma en Cualquier Lugar
|
||||
|
||||
A continuación, crea la multifirma en _cada máquina que aporta firmas_ usando un nuevo comando, `addmultisigaddress`, en lugar de `createmultisig`. Este nuevo comando guarda parte de la información en su billetera, lo que hace que sea mucho más fácil gastar el dinero después.
|
||||
```
|
||||
machine1$ bitcoin-cli -named addmultisigaddress nrequired=2 keys='''["'$address3'","02a0d96e16458ff0c90db4826f86408f2cfa0e960514c0db547ff152d3e567738f"]'''
|
||||
{
|
||||
"address": "tb1q9as46kupwcxancdx82gw65365svlzdwmjal4uxs23t3zz3rgg3wqpqlhex",
|
||||
"redeemScript": "52210297e681bff16cd4600138449e2527db4b2f83955c691a1b84254ecffddb9bfbfc2102a0d96e16458ff0c90db4826f86408f2cfa0e960514c0db547ff152d3e567738f52ae",
|
||||
"descriptor": "wsh(multi(2,[d6043800/0'/0'/15']0297e681bff16cd4600138449e2527db4b2f83955c691a1b84254ecffddb9bfbfc,[e9594be8]02a0d96e16458ff0c90db4826f86408f2cfa0e960514c0db547ff152d3e567738f))#wxn4tdju"
|
||||
}
|
||||
|
||||
machine2$ bitcoin-cli -named addmultisigaddress nrequired=2 keys='''["0297e681bff16cd4600138449e2527db4b2f83955c691a1b84254ecffddb9bfbfc","'$address4'"]'''
|
||||
{
|
||||
"address": "tb1q9as46kupwcxancdx82gw65365svlzdwmjal4uxs23t3zz3rgg3wqpqlhex",
|
||||
"redeemScript": "52210297e681bff16cd4600138449e2527db4b2f83955c691a1b84254ecffddb9bfbfc2102a0d96e16458ff0c90db4826f86408f2cfa0e960514c0db547ff152d3e567738f52ae",
|
||||
"descriptor": "wsh(multi(2,[ae42a66f]0297e681bff16cd4600138449e2527db4b2f83955c691a1b84254ecffddb9bfbfc,[fe6f2292/0'/0'/2']02a0d96e16458ff0c90db4826f86408f2cfa0e960514c0db547ff152d3e567738f))#cc96c5n6"
|
||||
}
|
||||
```
|
||||
Como se señaló en la sección anterior, actualmente no importa si usa direcciones o claves públicas, por lo que mostramos el otro mecanismo aquí, mezclando los dos. Obtendrá la misma dirección multifirma de cualquier manera. Sin embargo, _debe utilizar el mismo orden_. Por lo tanto, es mejor que los miembros de la multifirma se comprueben entre ellos para asegurarse de que todos obtuvieron el mismo resultado.
|
||||
|
||||
### Estar Atento a los Fondos
|
||||
|
||||
Posteriormente, los miembros de la multifirma aún necesitarán ejecutar `importaddress` para estar atentos a los fondos recibidos en la dirección multifirma:
|
||||
```
|
||||
machine1$ bitcoin-cli -named importaddress address=2Mzw7WBvh9RAQ4ssKqxyNyP7L9NAojLqSW8 rescan="false"
|
||||
|
||||
machine2$ bitcoin-cli -named importaddress address=2Mzw7WBvh9RAQ4ssKqxyNyP7L9NAojLqSW8 rescan="false"
|
||||
```
|
||||
|
||||
## Volver a Gastar con una Transacción Automatizada
|
||||
|
||||
Posteriormente, podrá recibir fondos en la dirección multifirma como de costumbre. El uso de `addmultisigaddress` es simplemente una cuestión burocrática por parte de los destinatarios: un poco de contabilidad para facilitarles la vida cuando quieran gastar sus fondos.
|
||||
|
||||
Pero hace la vida mucho más fácil. Debido a que la información se guardó en la billetera, los firmantes podrán volver a gastar los fondos enviados a la dirección multifirma exactamente igual que cualquier otra dirección ... aparte de la necesidad de firmar en varias máquinas.
|
||||
|
||||
Comienza recolectando sus variables, pero ya no tiene que preocuparse por `scriptPubKey` o `redeemScript`.
|
||||
|
||||
Aquí hay una nueva transacción enviada a nuestra nueva dirección multifirma:
|
||||
```
|
||||
machine1$ utxo_txid=b9f3c4756ef8159d6a66414a4317f865882ee04beb57a0f8349dafcc98f5acbc
|
||||
machine1$ utxo_vout=0
|
||||
machine1$ recipient=$(bitcoin-cli getrawchangeaddress)
|
||||
```
|
||||
Crea una transacción sin procesar:
|
||||
```
|
||||
machine1$ rawtxhex=$(bitcoin-cli -named createrawtransaction inputs='''[ { "txid": "'$utxo_txid'", "vout": '$utxo_vout' } ]''' outputs='''{ "'$recipient'": 0.00005}''')
|
||||
```
|
||||
Luego la firma:
|
||||
```
|
||||
machine1$ bitcoin-cli -named signrawtransactionwithwallet hexstring=$rawtxhex
|
||||
{
|
||||
"hex": "02000000000101bcacf598ccaf9d34f8a057eb4be02e8865f817434a41666a9d15f86e75c4f3b90000000000ffffffff0188130000000000001600144f93c831ec739166ea425984170f4dc6bac75829040047304402205f84d40ba16ff49e60a7fc9228ef5917473aae1ab667dad01e113ca0fef3008b02201a50da2c65f38798aea94bcbd5bbf065bc1e38de44bacee69d525dcddcc11bba01004752210297e681bff16cd4600138449e2527db4b2f83955c691a1b84254ecffddb9bfbfc2102a0d96e16458ff0c90db4826f86408f2cfa0e960514c0db547ff152d3e567738f52ae00000000",
|
||||
"complete": false,
|
||||
"errors": [
|
||||
{
|
||||
"txid": "b9f3c4756ef8159d6a66414a4317f865882ee04beb57a0f8349dafcc98f5acbc",
|
||||
"vout": 0,
|
||||
"witness": [
|
||||
"",
|
||||
"304402205f84d40ba16ff49e60a7fc9228ef5917473aae1ab667dad01e113ca0fef3008b02201a50da2c65f38798aea94bcbd5bbf065bc1e38de44bacee69d525dcddcc11bba01",
|
||||
"",
|
||||
"52210297e681bff16cd4600138449e2527db4b2f83955c691a1b84254ecffddb9bfbfc2102a0d96e16458ff0c90db4826f86408f2cfa0e960514c0db547ff152d3e567738f52ae"
|
||||
],
|
||||
"scriptSig": "",
|
||||
"sequence": 4294967295,
|
||||
"error": "CHECK(MULTI)SIG failing with non-zero signature (possibly need more signatures)"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
```
|
||||
Tenga en cuenta que ya no tiene que darle ayuda extra a `signrawtransactionwithkey`, porque toda esa información adicional ya estaba en su billetera. Lo más importante es que no ha hecho vulnerables sus claves privadas manipulándolas directamente. En su lugar el proceso fue _exactamente_ el mismo que volver a gastar una UTXO normal, excepto que la transacción no fue firmada completamente al final.
|
||||
|
||||
### Fírmela en Otras Máquinas
|
||||
|
||||
El paso final es exportar el `hex` parcialmente firmado a cualquier otra máquina y volver a firmarlo:
|
||||
```
|
||||
machine2$ signedtx=$(bitcoin-cli -named signrawtransactionwithwallet hexstring=02000000014ecda61c45f488e35c613a7c4ae26335a8d7bfd0a942f026d0fb1050e744a67d000000009100473044022025decef887fe2e3eb1c4b3edaa155e5755102d1570716f1467bb0b518b777ddf022017e97f8853af8acab4853ccf502213b7ff4cc3bd9502941369905371545de28d0147522102e7356952f4bb1daf475c04b95a2f7e0d9a12cf5b5c48a25b2303783d91849ba421030186d2b55de166389aefe209f508ce1fbd79966d9ac417adef74b7c1b5e0777652aeffffffff0130e1be07000000001976a9148dfbf103e48df7d1993448aa387dc31a2ebd522d88ac00000000 | jq -r '.hex')
|
||||
```
|
||||
Cuando todos los que sean necesarios hayan firmado, se irá a las carreras:
|
||||
```
|
||||
machine2$ bitcoin-cli -named sendrawtransaction hexstring=$signedtx
|
||||
3ce88839ac6165aeadcfb188c490e1b850468eff571b4ca78fac64342751510d
|
||||
```
|
||||
Al igual que con el shortcut discutido en [§4.5: Enviando Monedas con Transacciones Crudas Automatizadas](04_5_Enviando_Monedas_con_Transacciones_Crudas_Automatizadas.md), el resultado es mucho más sencillo, pero pierde algo de control en el proceso.
|
||||
|
||||
## Resúmen: Enviando & Gastando una Multifirma Automatizada
|
||||
|
||||
Existe una manera más fácil de volver a gastar los fondos enviados a direcciones multifirma que simplemente requiere el uso del comando `addmultisigaddress` cuando crea su dirección. No demuestra las complejidades de volver a gastar de P2SH y no le brinda un control amplio, pero si solo desea obtener su dinero, este es el camino a seguir.
|
||||
|
||||
## ¿Qué sigue?
|
||||
|
||||
Aprende más acerca de "Expandiendo Transacciones Bitcoin" con [Capítulo Siete: Expandiendo las Transacciones Bitcoin con PSBTs](07_0_Expandiendo_las_Transacciones_Bitcoin_con_PSBTs.md).
|
25
es/07_0_Expandiendo_las_Transacciones_Bitcoin_con_PSBTs.md
Normal file
25
es/07_0_Expandiendo_las_Transacciones_Bitcoin_con_PSBTs.md
Normal file
@ -0,0 +1,25 @@
|
||||
# Expandiendo las Transacciones Bitcoin con PSBTs
|
||||
|
||||
En el capítulo anterior se discutió cómo usar las múltiples fnuciones para determinar de manera colaborativa el consentimiento entre múltiples partes. No es la única forma de colaborar en la creación de transacciones de Bitcoin. Los PSBT son una tecnología mucho más nueva que le permite colaborar en una variedad de etapas, incluida la creación, financión y autenticación de una transacción de Bitcoin.
|
||||
|
||||
## Objetivos de esta sección
|
||||
|
||||
Después de trabajar en este capítulo, un desarrollador podrá:
|
||||
|
||||
* Crear transacciones con PSBT
|
||||
* Utilizar herramientas de línea de comandos para completar PSBT
|
||||
* Usar HWI para interactuar con una billetera de hardware
|
||||
|
||||
Los objetivos de apoyo incluyen la capacidad de:
|
||||
|
||||
* Comprender en qué se diferencian los PSBT de las multifirmas
|
||||
* Comprender el flujo de trabajo completo de trabajar con PSBT
|
||||
* Planear para el poder de las PSBT
|
||||
* Comprender el uso de una billetera de hardware
|
||||
|
||||
## Tabla de contenidos
|
||||
|
||||
* [Sección Uno: Creando una Transacción Bitcoin Parcialmente Firmada](07_1_Creando_una_Transaccion_Bitcoin_Parcialmente_Firmada.md)
|
||||
* [Sección Dos: Usando una Transacción Bitcoin Parcialmente Firmada](07_2_Usando_una_Transaccion_Bitcoin_Parcialmente_Firmada.md)
|
||||
* [Sección Tres: Integrando con Hardware Wallets](07_3_Integrando_con_Hardware_Wallets.md)
|
||||
|
509
es/07_1_Creando_una_Transaccion_Bitcoin_Parcialmente_Firmada.md
Normal file
509
es/07_1_Creando_una_Transaccion_Bitcoin_Parcialmente_Firmada.md
Normal file
@ -0,0 +1,509 @@
|
||||
# 7.1: Creando una Transacción Bitcoin Parcialmente Firmada
|
||||
|
||||
> :information_source: **NOTA:** Esta sección se ha agregado recientemente al curso y es un borrador inicial que aún puede estar pendiente de revisión. Lectura con precaución.
|
||||
|
||||
Las transacciones de Bitcoin parcialmente firmadas (PSBT) son la forma más nueva de variar la creación de transacciones básicas de Bitcoin. Para ello, introducen la colaboración en cada paso del proceso, lo que permite a las personas (o programas) no solo autenticar las transacciones juntas (como con las multifirmas), sino también crear, financiar y transmitir fácilmente de manera colaborativa.
|
||||
|
||||
> :warning: **ADVERTENCIA DE VERSIÓN:** Esta es una innovación de Bitcoin Core v 0.17.0. Las versiones anteriores de Bitcoin Core no podrán funcionar con el PSBT mientras esté en progreso (aunque aún podrán reconocer la transacción final). Algunas actualizaciones y mejoras para PSBT han continuado hasta 0.20.0.
|
||||
|
||||
## Comprenda cómo funcionan los PSBT
|
||||
|
||||
Las multifirmas fueron excelentes para el caso muy específico de la tenencia conjunta de fondos y el establecimiento de reglas para quién, entre los firmantes conjuntos, podría autenticar el uso de esos fondos. Hay muchos casos de uso, como: una cuenta bancaria conjunta del cónyuge (una firma de 1 de 2); un requisito fiduciario para el control dual (una firma 2 de 2); y un depósito en garantía (una firma 2 de 3).
|
||||
|
||||
> :book: ***Que es una PSBT?*** Como sugiere el nombre, un PSBT es una transacción que no se ha firmado por completo. Eso es importante, porque una vez que se firma una transacción, su contenido se bloquea. [BIP174](https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki) definió una metodología abstracta para poner los PSBTs juntos que describe y estandariza los roles en su creación colaborativa. Un *Creador* propone una transacción; uno o más *Actualizadores* lo complementan; y uno o más *Firmantes* lo autentican; antes de que un *Finalizador* lo complete; y un *Extracter* lo convierte en una transacción para la red Bitcoin. También puede haber un *Combinador* que fusiona PSBT paralelos de diferentes usuarios.
|
||||
|
||||
Inicialmente, los PSBT pueden tener un aspecto similar a las multifirmas porque tienen un solo bit de funcionalidad superpuesto: la capacidad de firmar conjuntamente una transacción. Sin embargo, fueron creados para un caso de uso totalmente diferente. Los PSBT reconocen la necesidad de que varios programas creen conjuntamente una transacción por varias razones diferentes, y proporcionan un formato regularizado para hacerlo. Son especialmente útiles para casos de uso que involucran billeteras de hardware (para lo cual, consulte [§7.3](https://github.com/BlockchainCommons/Learning-Bitcoin-from-the-Command-Line/blob/master/07_3_Integrating_with_Hardware_Wallets.md)), que están protegidas del acceso total a Internet y tienden a tener un historial de transacciones mínimo.
|
||||
|
||||
En general, los PSBT proporcionan una serie de elementos funcionales que mejoran este caso de uso:
|
||||
|
||||
1. Proporcionan un _estándar_ para la creación colaborativa de transacciones, mientras que las metodologías anteriores (incluida la multifirma del capítulo anterior) dependían de la implementación.
|
||||
2. Admiten una _variedad más amplia de casos de uso_, incluida la financiación conjunta simple.
|
||||
3. Admiten _billeteras de hardware_ y otros casos en los que un nodo puede no tener un historial de transacciones completo.
|
||||
4. Opcionalmente, permiten la combinación de _transacciones no serializadas_, sin requerir que se pase un código hexadecimal cada vez más grande de usuario a usuario.
|
||||
|
||||
Los PSBT hacen su trabajo al complementar la información de las transacciones normales con un conjunto de entradas y salidas, cada una de las cuales define todo lo que necesita saber sobre esos UTXO, de modo que incluso una una billetera aislada pueda tomar una decisión informada sobre las firmas. Por lo tanto, una entrada enumera la cantidad de dinero en un UTXO y lo que se debe hacer para gastarlo, mientras que una salida hace lo mismo para los UTXO que está creando.
|
||||
|
||||
Esta primera sección describirá el proceso estándar de PSBT de: Creador, Actualizador, Firmante, Finalizador, Extractor. Lo hará desde una sola máquina, lo que hará que parezca una forma complicada de crear una transacción sin procesar. Pero, ten fe, ¡esto tiene un propósito! [§7.2](07_2_Usando_una_Transaccion_Bitcoin_Parcialmente_Firmada.md) y [§7.3](07_3_Integrando_con_Hardware_Wallets.md) mostrará algunos ejemplos de la vida real del uso de PSBT y convertirá este simple sistema en un proceso colaborativo compartido entre múltiples máquinas que tiene efectos reales y crea oportunidades reales.
|
||||
|
||||
## Cree un PSBT a la antigua
|
||||
#### Rol en la PSBT: Creador
|
||||
|
||||
La forma más fácil de crear un PSBT es tomar una transacción existente y usar `converttopsbt` para convertirla en un PSBT. Ciertamente, esta no es la mejor manera, ya que requiere que realice una transacción para un formato (una transacción sin procesar) y luego la convierta a otro (PSBT), pero si tiene un software antiguo que solo puede generar una transacción sin procesar, puede que necesite usarlo..
|
||||
|
||||
Solo crea su transacción sin procesar normalmente:
|
||||
|
||||
```
|
||||
$ utxo_txid_1=$(bitcoin-cli listunspent | jq -r '.[0] | .txid')
|
||||
$ utxo_vout_1=$(bitcoin-cli listunspent | jq -r '.[0] | .vout')
|
||||
$ utxo_txid_2=$(bitcoin-cli listunspent | jq -r '.[1] | .txid')
|
||||
$ utxo_vout_2=$(bitcoin-cli listunspent | jq -r '.[1] | .vout')
|
||||
$ echo $utxo_txid_1 $utxo_vout_1 $utxo_txid_2 $utxo_vout_2
|
||||
c6de60427b28d8ec8102e49771e5d0348fc3ef6a5bf02eb864ec745105a6951b 1 8748eff5f12ca886e3603d9e30227dcb3f0332e0706c4322fec96001f7c7f41c 0
|
||||
$ recipient=tb1qcaedd724gts3aug73m78c7nfsv9d8zs9q6h2kd
|
||||
$ rawtxhex=$(bitcoin-cli -named createrawtransaction inputs='''[ { "txid": "'$utxo_txid_1'", "vout": '$utxo_vout_1' }, { "txid": "'$utxo_txid_2'", "vout": '$utxo_vout_2' } ]''' outputs='''{ "'$recipient'": 0.0000065 }''')
|
||||
```
|
||||
Entonces conviértalo:
|
||||
```
|
||||
$ psbt=$(bitcoin-cli -named converttopsbt hexstring=$rawtxhex)
|
||||
$ echo $psbt
|
||||
cHNidP8BAHsCAAAAAhuVpgVRdOxkuC7wW2rvw4800OVxl+QCgezYKHtCYN7GAQAAAAD/////HPTH9wFgyf4iQ2xw4DIDP8t9IjCePWDjhqgs8fXvSIcAAAAAAP////8BigIAAAAAAAAWABTHctb5VULhHvEejvx8emmDCtOKBQAAAAAAAAAA
|
||||
```
|
||||
Tenga en cuenta que la codificación PSBT se ve muy diferente de la transacción hexadecimal.
|
||||
|
||||
Pero si puede, desea crear el PSBT directamente en su lugar...
|
||||
|
||||
## Cree un PSBT de la manera difícil
|
||||
#### Rol en la PSBT: Creador
|
||||
|
||||
La primera metodología para crear un PSBT sin pasar por otro formato es el equivalente en PSBT de `createrawtransaction`. Se llama `createpsbt` y le brinda el máximo control al costo de la máxima labor y la máxima oportunidad de error.
|
||||
|
||||
La CLI debería parecer bastante familiar, solo con un nuevo comando RPC:
|
||||
```
|
||||
$ psbt_1=$(bitcoin-cli -named createpsbt inputs='''[ { "txid": "'$utxo_txid_1'", "vout": '$utxo_vout_1' }, { "txid": "'$utxo_txid_2'", "vout": '$utxo_vout_2' } ]''' outputs='''{ "'$recipient'": 0.0000065 }''')
|
||||
```
|
||||
El equipo de Bitcoin Core se aseguró de que `createpsbt` funcionara de manera muy similar a` createrawtransaction`, por lo que no es necesario que aprenda un formato de creación diferente.
|
||||
|
||||
Puede verificar que el nuevo PSBT es el mismo que el creado por `converttopsbt`:
|
||||
```
|
||||
$ echo $psbt_1
|
||||
cHNidP8BAHsCAAAAAhuVpgVRdOxkuC7wW2rvw4800OVxl+QCgezYKHtCYN7GAQAAAAD/////HPTH9wFgyf4iQ2xw4DIDP8t9IjCePWDjhqgs8fXvSIcAAAAAAP////8BigIAAAAAAAAWABTHctb5VULhHvEejvx8emmDCtOKBQAAAAAAAAAA
|
||||
$ if [ "$psbt" == "$psbt_1" ]; then echo "PSBTs are equal"; else echo "PSBTs are not equal"; fi
|
||||
PSBTs are equal
|
||||
```
|
||||
|
||||
## Examine una PSBT
|
||||
#### Rol en la PSBT: Cualquiera
|
||||
|
||||
Entonces, ¿cómo se ve realmente tu PSBT? Puede ver eso con el comando `decodepsbt`:
|
||||
```
|
||||
$ bitcoin-cli -named decodepsbt psbt=$psbt
|
||||
{
|
||||
"tx": {
|
||||
"txid": "ea73a631b456d2b041ed73bf5767946408c6ff067716929a68ecda2e3e4de6d3",
|
||||
"hash": "ea73a631b456d2b041ed73bf5767946408c6ff067716929a68ecda2e3e4de6d3",
|
||||
"version": 2,
|
||||
"size": 123,
|
||||
"vsize": 123,
|
||||
"weight": 492,
|
||||
"locktime": 0,
|
||||
"vin": [
|
||||
{
|
||||
"txid": "c6de60427b28d8ec8102e49771e5d0348fc3ef6a5bf02eb864ec745105a6951b",
|
||||
"vout": 1,
|
||||
"scriptSig": {
|
||||
"asm": "",
|
||||
"hex": ""
|
||||
},
|
||||
"sequence": 4294967295
|
||||
},
|
||||
{
|
||||
"txid": "8748eff5f12ca886e3603d9e30227dcb3f0332e0706c4322fec96001f7c7f41c",
|
||||
"vout": 0,
|
||||
"scriptSig": {
|
||||
"asm": "",
|
||||
"hex": ""
|
||||
},
|
||||
"sequence": 4294967295
|
||||
}
|
||||
],
|
||||
"vout": [
|
||||
{
|
||||
"value": 0.00000650,
|
||||
"n": 0,
|
||||
"scriptPubKey": {
|
||||
"asm": "0 c772d6f95542e11ef11e8efc7c7a69830ad38a05",
|
||||
"hex": "0014c772d6f95542e11ef11e8efc7c7a69830ad38a05",
|
||||
"reqSigs": 1,
|
||||
"type": "witness_v0_keyhash",
|
||||
"addresses": [
|
||||
"tb1qcaedd724gts3aug73m78c7nfsv9d8zs9q6h2kd"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"unknown": {
|
||||
},
|
||||
"inputs": [
|
||||
{
|
||||
},
|
||||
{
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
Es importante tener en cuenta que, aunque hemos definido los fundamentos de la transacción: los `vins` de dónde viene el dinero y los `vouts` de a dónde va, aún no hemos definido las `inputs` (entradas) y las `outputs` (salidas) que son el corazón de un PSBT y que son necesarias para los usuarios fuera de línea para evaluarlos. Esto es esperado: el rol del Creador como se define en [BIP174](https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki) es delinear la transacción, mientras que el rol del Actualizador es comenzar a llenar en los datos específicos de PSBT. (Otros comandos combinan los roles de Creador y Actualizador, pero `createpsbt` no lo hace porque no tiene acceso a su billetera).
|
||||
|
||||
También puede usar el comando `analysepsbt` para ver su estado actual:
|
||||
```
|
||||
standup@btctest20:~$ bitcoin-cli -named analyzepsbt psbt=$psbt
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"has_utxo": false,
|
||||
"is_final": false,
|
||||
"next": "updater"
|
||||
},
|
||||
{
|
||||
"has_utxo": false,
|
||||
"is_final": false,
|
||||
"next": "updater"
|
||||
}
|
||||
],
|
||||
"next": "updater"
|
||||
}
|
||||
```
|
||||
Del mismo modo, `analysepsbt` nos muestra un PSBT que necesita mejorarse. Echamos un vistazo a cada una de las dos `inputs` (correspondientes a los dos `vins`), y ninguna tiene la información que necesita.
|
||||
|
||||
## Finalize una PSBT
|
||||
#### Rol en la PSBT: Actualizador, Firmante, Finalizador
|
||||
|
||||
Existe un comando `utxoupdatepsbt` que se puede usar para actualizar UTXOs, importando su información de descriptor a mano, pero no desea usarlo a menos que tenga un caso de uso en el que no tenga toda esa información en las billeteras de todos los que firmarán el PSBT.
|
||||
|
||||
> :information_source: **NOTA:** Si elige Actualizar el PSBT con `utxoupdatepsbt`, aún necesitará usar `walletprocesspsbt` para firmarlo: es el único comando de rol de firmante para PSBT que está disponible en `bitcoin-cli`.
|
||||
|
||||
En su lugar, debe usar `walletprocesspsbt`, que actualizará, firmará y finalizará:
|
||||
```
|
||||
$ bitcoin-cli walletprocesspsbt $psbt
|
||||
{
|
||||
"psbt": "cHNidP8BAHsCAAAAAhuVpgVRdOxkuC7wW2rvw4800OVxl+QCgezYKHtCYN7GAQAAAAD/////HPTH9wFgyf4iQ2xw4DIDP8t9IjCePWDjhqgs8fXvSIcAAAAAAP////8BigIAAAAAAAAWABTHctb5VULhHvEejvx8emmDCtOKBQAAAAAAAQEfAQAAAAAAAAAWABRsRdOvqHYghsS9dtinGsfJduGRlgEIawJHMEQCIAqJbxz6dBzNpfaDu4XZXb+DbDkM3UWnhezh9UdmeVghAiBRxMlW2o0wEtphtUZRWIiJOaGtXfsQbB4lovkvE4eRIgEhArrDpkX9egpTfGJ6039faVBYxY0ZzrADPpE/Gpl14A3uAAEBH0gDAAAAAAAAFgAU1ZEJG4B0ojde2ZhanEsY7+z9QWUBCGsCRzBEAiB+sNNCO4xiFQ+DoHVrqqk9yM0V4H9ZSyExx1PW7RbjsgIgUeWkQ3L7aAv1xIe7h+8PZb8ECsXg1UzbtPW8wd2qx0UBIQKIO7VGPjfVUlLYs9XCFBsAezfIp9tiEfdclVrMXqMl6wAA",
|
||||
"complete": true
|
||||
}
|
||||
```
|
||||
Obviamente, necesitará guardar esa información de `psbt` usando` jq`:
|
||||
```
|
||||
$ psbt_f=$(bitcoin-cli walletprocesspsbt $psbt | jq -r '.psbt')
|
||||
```
|
||||
Puede ver que las `inputs` ahora se han completado:
|
||||
```
|
||||
$ bitcoin-cli decodepsbt $psbt_f
|
||||
{
|
||||
"tx": {
|
||||
"txid": "ea73a631b456d2b041ed73bf5767946408c6ff067716929a68ecda2e3e4de6d3",
|
||||
"hash": "ea73a631b456d2b041ed73bf5767946408c6ff067716929a68ecda2e3e4de6d3",
|
||||
"version": 2,
|
||||
"size": 123,
|
||||
"vsize": 123,
|
||||
"weight": 492,
|
||||
"locktime": 0,
|
||||
"vin": [
|
||||
{
|
||||
"txid": "c6de60427b28d8ec8102e49771e5d0348fc3ef6a5bf02eb864ec745105a6951b",
|
||||
"vout": 1,
|
||||
"scriptSig": {
|
||||
"asm": "",
|
||||
"hex": ""
|
||||
},
|
||||
"sequence": 4294967295
|
||||
},
|
||||
{
|
||||
"txid": "8748eff5f12ca886e3603d9e30227dcb3f0332e0706c4322fec96001f7c7f41c",
|
||||
"vout": 0,
|
||||
"scriptSig": {
|
||||
"asm": "",
|
||||
"hex": ""
|
||||
},
|
||||
"sequence": 4294967295
|
||||
}
|
||||
],
|
||||
"vout": [
|
||||
{
|
||||
"value": 0.00000650,
|
||||
"n": 0,
|
||||
"scriptPubKey": {
|
||||
"asm": "0 c772d6f95542e11ef11e8efc7c7a69830ad38a05",
|
||||
"hex": "0014c772d6f95542e11ef11e8efc7c7a69830ad38a05",
|
||||
"reqSigs": 1,
|
||||
"type": "witness_v0_keyhash",
|
||||
"addresses": [
|
||||
"tb1qcaedd724gts3aug73m78c7nfsv9d8zs9q6h2kd"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"unknown": {
|
||||
},
|
||||
"inputs": [
|
||||
{
|
||||
"witness_utxo": {
|
||||
"amount": 0.00000001,
|
||||
"scriptPubKey": {
|
||||
"asm": "0 6c45d3afa8762086c4bd76d8a71ac7c976e19196",
|
||||
"hex": "00146c45d3afa8762086c4bd76d8a71ac7c976e19196",
|
||||
"type": "witness_v0_keyhash",
|
||||
"address": "tb1qd3za8tagwcsgd39awmv2wxk8e9mwryvktqmkkg"
|
||||
}
|
||||
},
|
||||
"final_scriptwitness": [
|
||||
"304402200a896f1cfa741ccda5f683bb85d95dbf836c390cdd45a785ece1f54766795821022051c4c956da8d3012da61b5465158888939a1ad5dfb106c1e25a2f92f1387912201",
|
||||
"02bac3a645fd7a0a537c627ad37f5f695058c58d19ceb0033e913f1a9975e00dee"
|
||||
]
|
||||
},
|
||||
{
|
||||
"witness_utxo": {
|
||||
"amount": 0.00000840,
|
||||
"scriptPubKey": {
|
||||
"asm": "0 d591091b8074a2375ed9985a9c4b18efecfd4165",
|
||||
"hex": "0014d591091b8074a2375ed9985a9c4b18efecfd4165",
|
||||
"type": "witness_v0_keyhash",
|
||||
"address": "tb1q6kgsjxuqwj3rwhkenpdfcjccalk06st9z0k0kh"
|
||||
}
|
||||
},
|
||||
"final_scriptwitness": [
|
||||
"304402207eb0d3423b8c62150f83a0756baaa93dc8cd15e07f594b2131c753d6ed16e3b2022051e5a44372fb680bf5c487bb87ef0f65bf040ac5e0d54cdbb4f5bcc1ddaac74501",
|
||||
"02883bb5463e37d55252d8b3d5c2141b007b37c8a7db6211f75c955acc5ea325eb"
|
||||
]
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
}
|
||||
],
|
||||
"fee": 0.00000191
|
||||
}
|
||||
```
|
||||
O para ser más precisos: (1) el PSBT se ha actualizado con la información de `witness_utxo`; (2) se ha firmado el PSBT; y (3) se ha finalizado el PSBT.
|
||||
|
||||
|
||||
## Cree un PSBT de la manera más fácil
|
||||
#### Rol en la PSBT: Creador, Actualizador
|
||||
|
||||
Si cree que debería haber un comando equivalente a `fundrawtransaction`, le complacerá saber que existe: `walletcreatefundedpsbt`. Podría usarlo de la misma manera que `createpsbt`:
|
||||
```
|
||||
$ bitcoin-cli -named walletcreatefundedpsbt inputs='''[ { "txid": "'$utxo_txid_1'", "vout": '$utxo_vout_1' }, { "txid": "'$utxo_txid_2'", "vout": '$utxo_vout_2' } ]''' outputs='''{ "'$recipient'": 0.0000065 }'''
|
||||
{
|
||||
"psbt": "cHNidP8BAOwCAAAABBuVpgVRdOxkuC7wW2rvw4800OVxl+QCgezYKHtCYN7GAQAAAAD/////HPTH9wFgyf4iQ2xw4DIDP8t9IjCePWDjhqgs8fXvSIcAAAAAAP/////uFwerANKjyVK6WaR7gzlX+lOf+ORsfjP5LYCSNIbhaAAAAAAA/v///4XjOeey0NyGpJYpszNWF8AFNiuFaWsjkOrk35Jp+9kKAAAAAAD+////AtYjEAAAAAAAFgAUMPsier2ey1eH48oGqrbbYGzNHgKKAgAAAAAAABYAFMdy1vlVQuEe8R6O/Hx6aYMK04oFAAAAAAABAR8BAAAAAAAAABYAFGxF06+odiCGxL122Kcax8l24ZGWIgYCusOmRf16ClN8YnrTf19pUFjFjRnOsAM+kT8amXXgDe4Q1gQ4AAAAAIABAACADgAAgAABAR9IAwAAAAAAABYAFNWRCRuAdKI3XtmYWpxLGO/s/UFlIgYCiDu1Rj431VJS2LPVwhQbAHs3yKfbYhH3XJVazF6jJesQ1gQ4AAAAAIABAACADAAAgAABAIwCAAAAAdVmsvkSBmfeHqNAe/wDCQ5lEp9F/587ftzCD1UL60nMAQAAABcWABRzFxRJfFPl8FJ6SxjAJzy3mCAMXf7///8CQEIPAAAAAAAZdqkUf0NzebzGbEB0XtwYkeprODDhl12IrMEwLQAAAAAAF6kU/d+kMX6XijmD+jWdUrLZlJUnH2iHPhQbACIGA+/e40wACf0XXzsgteWlUX/V0WdG8uY1tEYXra/q68OIENYEOAAAAACAAAAAgBIAAIAAAQEfE4YBAAAAAAAWABTVkQkbgHSiN17ZmFqcSxjv7P1BZSIGAog7tUY+N9VSUtiz1cIUGwB7N8in22IR91yVWsxeoyXrENYEOAAAAACAAQAAgAwAAIAAIgICKMavAB+71Adqsbf+XtC1g/OlmLEuTp3U0axyeu/LAI0Q1gQ4AAAAAIABAACAGgAAgAAA",
|
||||
"fee": 0.00042300,
|
||||
"changepos": 0
|
||||
}
|
||||
```
|
||||
Sin embargo, la gran ventaja es que puede usarlo para autofinanciarse omitiendo las `inputs`, al igual que `fundrawtransaction`.
|
||||
```
|
||||
$ psbt_new=$(bitcoin-cli -named walletcreatefundedpsbt inputs='''[]''' outputs='''{ "'$recipient'": 0.0000065 }''' | jq -r '.psbt')
|
||||
$ bitcoin-cli decodepsbt $psbt_new
|
||||
{
|
||||
"tx": {
|
||||
"txid": "9f2c6205ac797c1020f7f261e3ab71cd0699ff4b1a8934f68b273c71547e235f",
|
||||
"hash": "9f2c6205ac797c1020f7f261e3ab71cd0699ff4b1a8934f68b273c71547e235f",
|
||||
"version": 2,
|
||||
"size": 154,
|
||||
"vsize": 154,
|
||||
"weight": 616,
|
||||
"locktime": 0,
|
||||
"vin": [
|
||||
{
|
||||
"txid": "8748eff5f12ca886e3603d9e30227dcb3f0332e0706c4322fec96001f7c7f41c",
|
||||
"vout": 0,
|
||||
"scriptSig": {
|
||||
"asm": "",
|
||||
"hex": ""
|
||||
},
|
||||
"sequence": 4294967294
|
||||
},
|
||||
{
|
||||
"txid": "68e1863492802df9337e6ce4f89f53fa5739837ba459ba52c9a3d200ab0717ee",
|
||||
"vout": 0,
|
||||
"scriptSig": {
|
||||
"asm": "",
|
||||
"hex": ""
|
||||
},
|
||||
"sequence": 4294967294
|
||||
}
|
||||
],
|
||||
"vout": [
|
||||
{
|
||||
"value": 0.00971390,
|
||||
"n": 0,
|
||||
"scriptPubKey": {
|
||||
"asm": "0 09a74ef0bae4d68b0b2ec9a7c4557a2b5c85bd8b",
|
||||
"hex": "001409a74ef0bae4d68b0b2ec9a7c4557a2b5c85bd8b",
|
||||
"reqSigs": 1,
|
||||
"type": "witness_v0_keyhash",
|
||||
"addresses": [
|
||||
"tb1qpxn5au96untgkzewexnug4t69dwgt0vtfahcv6"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"value": 0.00000650,
|
||||
"n": 1,
|
||||
"scriptPubKey": {
|
||||
"asm": "0 c772d6f95542e11ef11e8efc7c7a69830ad38a05",
|
||||
"hex": "0014c772d6f95542e11ef11e8efc7c7a69830ad38a05",
|
||||
"reqSigs": 1,
|
||||
"type": "witness_v0_keyhash",
|
||||
"addresses": [
|
||||
"tb1qcaedd724gts3aug73m78c7nfsv9d8zs9q6h2kd"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"unknown": {
|
||||
},
|
||||
"inputs": [
|
||||
{
|
||||
"witness_utxo": {
|
||||
"amount": 0.00000840,
|
||||
"scriptPubKey": {
|
||||
"asm": "0 d591091b8074a2375ed9985a9c4b18efecfd4165",
|
||||
"hex": "0014d591091b8074a2375ed9985a9c4b18efecfd4165",
|
||||
"type": "witness_v0_keyhash",
|
||||
"address": "tb1q6kgsjxuqwj3rwhkenpdfcjccalk06st9z0k0kh"
|
||||
}
|
||||
},
|
||||
"bip32_derivs": [
|
||||
{
|
||||
"pubkey": "02883bb5463e37d55252d8b3d5c2141b007b37c8a7db6211f75c955acc5ea325eb",
|
||||
"master_fingerprint": "d6043800",
|
||||
"path": "m/0'/1'/12'"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"non_witness_utxo": {
|
||||
"txid": "68e1863492802df9337e6ce4f89f53fa5739837ba459ba52c9a3d200ab0717ee",
|
||||
"hash": "68e1863492802df9337e6ce4f89f53fa5739837ba459ba52c9a3d200ab0717ee",
|
||||
"version": 2,
|
||||
"size": 140,
|
||||
"vsize": 140,
|
||||
"weight": 560,
|
||||
"locktime": 1774654,
|
||||
"vin": [
|
||||
{
|
||||
"txid": "cc49eb0b550fc2dc7e3b9fff459f12650e0903fc7b40a31ede670612f9b266d5",
|
||||
"vout": 1,
|
||||
"scriptSig": {
|
||||
"asm": "0014731714497c53e5f0527a4b18c0273cb798200c5d",
|
||||
"hex": "160014731714497c53e5f0527a4b18c0273cb798200c5d"
|
||||
},
|
||||
"sequence": 4294967294
|
||||
}
|
||||
],
|
||||
"vout": [
|
||||
{
|
||||
"value": 0.01000000,
|
||||
"n": 0,
|
||||
"scriptPubKey": {
|
||||
"asm": "OP_DUP OP_HASH160 7f437379bcc66c40745edc1891ea6b3830e1975d OP_EQUALVERIFY OP_CHECKSIG",
|
||||
"hex": "76a9147f437379bcc66c40745edc1891ea6b3830e1975d88ac",
|
||||
"reqSigs": 1,
|
||||
"type": "pubkeyhash",
|
||||
"addresses": [
|
||||
"ms7ruzvL4atCu77n47dStMb3of6iScS8kZ"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"value": 0.02961601,
|
||||
"n": 1,
|
||||
"scriptPubKey": {
|
||||
"asm": "OP_HASH160 fddfa4317e978a3983fa359d52b2d99495271f68 OP_EQUAL",
|
||||
"hex": "a914fddfa4317e978a3983fa359d52b2d99495271f6887",
|
||||
"reqSigs": 1,
|
||||
"type": "scripthash",
|
||||
"addresses": [
|
||||
"2NGParh82hE2Zif5PVK3AfLpYhfwF5FyRGr"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"bip32_derivs": [
|
||||
{
|
||||
"pubkey": "03efdee34c0009fd175f3b20b5e5a5517fd5d16746f2e635b44617adafeaebc388",
|
||||
"master_fingerprint": "d6043800",
|
||||
"path": "m/0'/0'/18'"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"bip32_derivs": [
|
||||
{
|
||||
"pubkey": "029bb586a52657dd98852cecef78552a4e21d081a7a30e4008ce9b419840d4deac",
|
||||
"master_fingerprint": "d6043800",
|
||||
"path": "m/0'/1'/27'"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
}
|
||||
],
|
||||
"fee": 0.00028800
|
||||
}
|
||||
```
|
||||
Como puede ver, creó el PSBT y luego lo actualizó con toda la información que pudo encontrar localmente.
|
||||
|
||||
A partir de ahí, debe usar `walletprocesspsbt` para Finalizar, como de costumbre:
|
||||
```
|
||||
$ psbt_new_f=$(bitcoin-cli walletprocesspsbt $psbt_new | jq -r '.psbt')
|
||||
```
|
||||
Luego, un análisis mostrará que tambien está a punto de estar lista para ser enviada:
|
||||
```
|
||||
$ bitcoin-cli analyzepsbt $psbt_new_f
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"has_utxo": true,
|
||||
"is_final": true,
|
||||
"next": "extractor"
|
||||
},
|
||||
{
|
||||
"has_utxo": true,
|
||||
"is_final": true,
|
||||
"next": "extractor"
|
||||
}
|
||||
],
|
||||
"estimated_vsize": 288,
|
||||
"estimated_feerate": 0.00100000,
|
||||
"fee": 0.00028800,
|
||||
"next": "extractor"
|
||||
}
|
||||
```
|
||||
Ahora, ¿realmente querría usar `walletcreatefundedpsbt` si estuviera creando un programa `bitcoin-cli`? Probablemente no. Pero es el mismo análisis que si se debe usar `fundrawtransaction`. ¿Deja que Bitcoin Core haga el análisis, el cálculo y las decisiones, o lo toma usted mismo?
|
||||
|
||||
## Envíe una PSBT
|
||||
#### Rol en la PSBT: Extractor
|
||||
|
||||
Para finalizar el PSBT, use `finalizepsbt`, que convertirá su PSBT nuevamente en hexadecimal. (También asumirá el rol de finalizador, si eso no sucedió ya).
|
||||
```
|
||||
$ bitcoin-cli finalizepsbt $psbt_f
|
||||
{
|
||||
"hex": "020000000001021b95a6055174ec64b82ef05b6aefc38f34d0e57197e40281ecd8287b4260dec60100000000ffffffff1cf4c7f70160c9fe22436c70e032033fcb7d22309e3d60e386a82cf1f5ef48870000000000ffffffff018a02000000000000160014c772d6f95542e11ef11e8efc7c7a69830ad38a050247304402200a896f1cfa741ccda5f683bb85d95dbf836c390cdd45a785ece1f54766795821022051c4c956da8d3012da61b5465158888939a1ad5dfb106c1e25a2f92f13879122012102bac3a645fd7a0a537c627ad37f5f695058c58d19ceb0033e913f1a9975e00dee0247304402207eb0d3423b8c62150f83a0756baaa93dc8cd15e07f594b2131c753d6ed16e3b2022051e5a44372fb680bf5c487bb87ef0f65bf040ac5e0d54cdbb4f5bcc1ddaac745012102883bb5463e37d55252d8b3d5c2141b007b37c8a7db6211f75c955acc5ea325eb00000000",
|
||||
"complete": true
|
||||
}
|
||||
```
|
||||
Como de costumbre, querrá guardar eso y luego puede enviarlo
|
||||
```
|
||||
$ psbt_hex=$(bitcoin-cli finalizepsbt $psbt_f | jq -r '.hex')
|
||||
$ bitcoin-cli -named sendrawtransaction hexstring=$psbt_hex
|
||||
ea73a631b456d2b041ed73bf5767946408c6ff067716929a68ecda2e3e4de6d3
|
||||
```
|
||||
## Revise el flujo de trabajo
|
||||
|
||||
Al crear el software `bitcoin-cli`, lo más probable es que cumpla las cinco funciones principales de los PSBT con `createpsbt`, `walletprocesspsbt` y `finalizepsbt`. Esto es lo que parece ese flujo:
|
||||
|
||||

|
||||
|
||||
Si elige usar el atajo de `walletcreatefundedpsbt`, así es como se ve en su lugar:
|
||||
|
||||

|
||||
|
||||
Finalmente, si en cambio necesita más control y elige usar `utxoupdatepsbt` (que no está documentado en gran parte aquí), en su lugar tiene este flujo de trabajo:
|
||||
|
||||

|
||||
|
||||
## Resumen: creando una transacción de Bitcoin firmada parcialmente
|
||||
|
||||
La creación de un PSBT implica un flujo de trabajo algo complejo de creación, actualización, firma, finalización y extracción de un PSBT, después de lo cual se convierte nuevamente en una transacción sin procesar. ¿Por qué se tomaría tanto trabajo? Porque quiere colaborar entre múltiples usuarios o múltiples programas. Ahora que comprende este flujo de trabajo, la siguiente sección tiene algunos ejemplos reales de cómo hacerlo.
|
||||
|
||||
## ¿Que sigue?
|
||||
|
||||
Continúe "Expandiendo transacciones de Bitcoin con PSBT" con [§7.2: Usando una Transacción Bitcoin Parcialmente Firmada](07_2_Usando_una_Transaccion_Bitcoin_Parcialmente_Firmada.md).
|
595
es/07_2_Usando_una_Transaccion_Bitcoin_Parcialmente_Firmada.md
Normal file
595
es/07_2_Usando_una_Transaccion_Bitcoin_Parcialmente_Firmada.md
Normal file
@ -0,0 +1,595 @@
|
||||
# 7.2: Usando una Transacción Bitcoin Parcialmente Firmada
|
||||
|
||||
> :information_source: **NOTA:** Esta sección se ha agregado recientemente al curso y es un borrador inicial que aún puede estar pendiente de revisión. Lectura con advertencias.
|
||||
|
||||
Ahora que ha aprendido el flujo de trabajo básico para generar un PSBT, probablemente quiera hacer algo con él. ¿Qué pueden hacer las PSBT que las multifirmas (y las transacciones sin procesar normales) no pueden hacer? Para empezar, tiene la facilidad de uso de un formato estandarizado, lo que significa que puede usar sus transacciones `bitcoin-cli` y combinarlas con transacciones generadas por personas (o programas) en otras plataformas. Más allá de eso, puede hacer algunas cosas que no fueron fáciles usando otras mecánicas.
|
||||
|
||||
A continuación se muestran tres ejemplos del uso de PSBT para: multifirmas, agrupación de dinero y unión de monedas.
|
||||
|
||||
> :warning: **ADVERTENCIA DE VERSIÓN:** Esta es una innovación de Bitcoin Core v 0.17.0. Las versiones anteriores de Bitcoin Core no podrán funcionar con el PSBT mientras esté en progreso (aunque aún podrán reconocer la transacción final).
|
||||
## Utilice un PSBT para gastar fondos Multifirma
|
||||
|
||||
Suponga que ha creado una dirección de firma múltiple, tal como lo hizo en [§6.3](06_3_Enviando_una_Multifirma_Automatizada.md).
|
||||
```
|
||||
machine1$ bitcoin-cli -named addmultisigaddress nrequired=2 keys='''["'$pubkey1'","'$pubkey2'"]'''
|
||||
{
|
||||
"address": "tb1qyfxt2qa877p40xdecghwps78my7sjq6kuv88qq2u86al5526xp6qfqjud0",
|
||||
"redeemScript": "5221038d73adf2c7ea33f9dc34b77b62b59af433c1de9c763332da79e83e155f96030e2103789f543423670e169667ff7e1f2da2a97df1b0912272e142d582451acebd063652ae",
|
||||
"descriptor": "wsh(multi(2,[d6043800/0'/0'/26']038d73adf2c7ea33f9dc34b77b62b59af433c1de9c763332da79e83e155f96030e,[be686772]03789f543423670e169667ff7e1f2da2a97df1b0912272e142d582451acebd0636))#07zyayfk"
|
||||
}
|
||||
machine1$ bitcoin-cli -named importaddress address="tb1qyfxt2qa877p40xdecghwps78my7sjq6kuv88qq2u86al5526xp6qfqjud0" rescan=false
|
||||
machine2$ bitcoin-cli -named addmultisigaddress nrequired=2 keys='''["'$pubkey1'","'$pubkey2'"]'''
|
||||
{
|
||||
"address": "tb1qyfxt2qa877p40xdecghwps78my7sjq6kuv88qq2u86al5526xp6qfqjud0",
|
||||
"redeemScript": "5221038d73adf2c7ea33f9dc34b77b62b59af433c1de9c763332da79e83e155f96030e2103789f543423670e169667ff7e1f2da2a97df1b0912272e142d582451acebd063652ae",
|
||||
"descriptor": "wsh(multi(2,[d6043800/0'/0'/26']038d73adf2c7ea33f9dc34b77b62b59af433c1de9c763332da79e83e155f96030e,[be686772]03789f543423670e169667ff7e1f2da2a97df1b0912272e142d582451acebd0636))#07zyayfk"
|
||||
}
|
||||
machine2$ bitcoin-cli -named importaddress address="tb1qyfxt2qa877p40xdecghwps78my7sjq6kuv88qq2u86al5526xp6qfqjud0" rescan=false
|
||||
```
|
||||
Y tiene algo de dinero en ello:
|
||||
```
|
||||
$ bitcoin-cli listunspent
|
||||
[
|
||||
{
|
||||
"txid": "53ec62c5c2fe8b16ee2164e9699d16c7b8ac30ec53a696e55f09b79704b539b5",
|
||||
"vout": 0,
|
||||
"address": "tb1qyfxt2qa877p40xdecghwps78my7sjq6kuv88qq2u86al5526xp6qfqjud0",
|
||||
"label": "",
|
||||
"witnessScript": "5221038d73adf2c7ea33f9dc34b77b62b59af433c1de9c763332da79e83e155f96030e2103789f543423670e169667ff7e1f2da2a97df1b0912272e142d582451acebd063652ae",
|
||||
"scriptPubKey": "0020224cb503a7f7835799b9c22ee0c3c7d93d090356e30e70015c3ebbfa515a3074",
|
||||
"amount": 0.01999800,
|
||||
"confirmations": 2,
|
||||
"spendable": false,
|
||||
"solvable": true,
|
||||
"desc": "wsh(multi(2,[d6043800/0'/0'/26']038d73adf2c7ea33f9dc34b77b62b59af433c1de9c763332da79e83e155f96030e,[be686772]03789f543423670e169667ff7e1f2da2a97df1b0912272e142d582451acebd0636))#07zyayfk",
|
||||
"safe": true
|
||||
}
|
||||
]
|
||||
```
|
||||
_Podría_ gastar esto usando los mecanismos del [Capítulo 6](06_0_Expandiendo_las_Transacciones_Bitcoin_con_Multifirmas.md), donde firmó una transacción en serie, pero en su lugar vamos a mostrar la ventaja de los PSBT para multi-sigs: puede generar un solo PSBT, permitir que todos firmen eso en paralelo y luego combinen los resultados. Ya no es más laborioso pasar un maleficio en constante expansión de persona a persona, lo que acelera las cosas y reduce las posibilidades de errores.
|
||||
|
||||
Para demostrar esta metodología, vamos a sacar ese 0.02 BTC de la multifirma y dividirlo entre los dos firmantes, cada uno de los cuales generó una nueva dirección para ese propósito:
|
||||
```
|
||||
machine1$ bitcoin-cli getnewaddress
|
||||
tb1qem5l3q5g5h6fsqv352xh4cy07kzq2rd8gphqma
|
||||
machine2$ bitcoin-cli getnewaddress
|
||||
tb1q3krplahg4ncu523m8h2eephjazs2hf6ur8r6zp
|
||||
```
|
||||
Lo primero que hacemos es crear un PSBT en la máquina de nuestra elección. (No importa cuál). Necesitamos usar `createpsbt` de [§7.1](07_1_Creando_una_Transaccion_Bitcoin_Parcialmente_Firmada.md) para esto, no el más simple `walletcreatefundedpsbt`, porque necesitamos el control adicional de seleccionar el dinero protegido por la multifirma. (Este será el caso de los tres ejemplos de esta sección, lo que demuestra por qué normalmente necesita usar `createpsbt` para las cosas complejas).
|
||||
```
|
||||
machine1$ utxo_txid=53ec62c5c2fe8b16ee2164e9699d16c7b8ac30ec53a696e55f09b79704b539b5
|
||||
machine1$ utxo_vout=0
|
||||
machine1$ split1=tb1qem5l3q5g5h6fsqv352xh4cy07kzq2rd8gphqma
|
||||
machine1$ split2=tb1q3krplahg4ncu523m8h2eephjazs2hf6ur8r6zp
|
||||
machine1$ psbt=$(bitcoin-cli -named createpsbt inputs='''[ { "txid": "'$utxo_txid'", "vout": '$utxo_vout' } ]''' outputs='''{ "'$split1'": 0.009998,"'$split2'": 0.009998 }''')
|
||||
```
|
||||
Luego debe enviar ese $psbt a todos para que lo firmen:
|
||||
```
|
||||
machine1$ echo $psbt
|
||||
cHNidP8BAHECAAAAAbU5tQSXtwlf5ZamU+wwrLjHFp1p6WQh7haL/sLFYuxTAAAAAAD/////AnhBDwAAAAAAFgAUzun4goil9JgBkaKNeuCP9YQFDad4QQ8AAAAAABYAFI2GH/borPHKKjs91ZyG8uigq6dcAAAAAAAAAAA=
|
||||
```
|
||||
¡Pero solo tiene que enviarlo una vez! Y lo haces de forma simultánea.
|
||||
|
||||
Aquí está el resultado en la primera máquina, donde generamos el PSBT:
|
||||
```
|
||||
machine1$ psbt_p1=$(bitcoin-cli walletprocesspsbt $psbt | jq -r '.psbt')
|
||||
machine1$ bitcoin-cli decodepsbt $psbt_p1
|
||||
{
|
||||
"tx": {
|
||||
"txid": "1687e89fcb9dd3067f75495b4884dc1d4d1cf05a6c272b783cfe29eb5d22e985",
|
||||
"hash": "1687e89fcb9dd3067f75495b4884dc1d4d1cf05a6c272b783cfe29eb5d22e985",
|
||||
"version": 2,
|
||||
"size": 113,
|
||||
"vsize": 113,
|
||||
"weight": 452,
|
||||
"locktime": 0,
|
||||
"vin": [
|
||||
{
|
||||
"txid": "25e8a26f60cf485768a1e6953b983675c867b7ab126b02e753c47b7db0c4be5e",
|
||||
"vout": 0,
|
||||
"scriptSig": {
|
||||
"asm": "",
|
||||
"hex": ""
|
||||
},
|
||||
"sequence": 4294967295
|
||||
}
|
||||
],
|
||||
"vout": [
|
||||
{
|
||||
"value": 0.00499900,
|
||||
"n": 0,
|
||||
"scriptPubKey": {
|
||||
"asm": "0 cee9f88288a5f4980191a28d7ae08ff584050da7",
|
||||
"hex": "0014cee9f88288a5f4980191a28d7ae08ff584050da7",
|
||||
"reqSigs": 1,
|
||||
"type": "witness_v0_keyhash",
|
||||
"addresses": [
|
||||
"tb1qem5l3q5g5h6fsqv352xh4cy07kzq2rd8gphqma"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"value": 0.00049990,
|
||||
"n": 1,
|
||||
"scriptPubKey": {
|
||||
"asm": "0 8d861ff6e8acf1ca2a3b3dd59c86f2e8a0aba75c",
|
||||
"hex": "00148d861ff6e8acf1ca2a3b3dd59c86f2e8a0aba75c",
|
||||
"reqSigs": 1,
|
||||
"type": "witness_v0_keyhash",
|
||||
"addresses": [
|
||||
"tb1q3krplahg4ncu523m8h2eephjazs2hf6ur8r6zp"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"unknown": {
|
||||
},
|
||||
"inputs": [
|
||||
{
|
||||
"witness_utxo": {
|
||||
"amount": 0.01000000,
|
||||
"scriptPubKey": {
|
||||
"asm": "0 2abb5d49ce7e753cbf5a9ffa8cdaf815bf1074f5c0bf495a93df8eb5112f65aa",
|
||||
"hex": "00202abb5d49ce7e753cbf5a9ffa8cdaf815bf1074f5c0bf495a93df8eb5112f65aa",
|
||||
"type": "witness_v0_scripthash",
|
||||
"address": "tb1q92a46jww0e6ne066nlagekhczkl3qa84czl5jk5nm78t2yf0vk4qte328m"
|
||||
}
|
||||
},
|
||||
"partial_signatures": {
|
||||
"03f52980d322acaf084bcef3216f3d84bfb672d1db26ce2861de3ec047bede140d": "304402203abb95d1965e4cea630a8b4890456d56698ff2dd5544cb79303cc28cb011cbb40220701faa927f8a19ca79b09d35c78d8d0a2187872117d9308805f7a896b07733f901"
|
||||
},
|
||||
"witness_script": {
|
||||
"asm": "2 033055ec2da9bbb34c2acb343692bfbecdef8fab8d114f0036eba01baec3888aa0 03f52980d322acaf084bcef3216f3d84bfb672d1db26ce2861de3ec047bede140d 2 OP_CHECKMULTISIG",
|
||||
"hex": "5221033055ec2da9bbb34c2acb343692bfbecdef8fab8d114f0036eba01baec3888aa02103f52980d322acaf084bcef3216f3d84bfb672d1db26ce2861de3ec047bede140d52ae",
|
||||
"type": "multisig"
|
||||
},
|
||||
"bip32_derivs": [
|
||||
{
|
||||
"pubkey": "033055ec2da9bbb34c2acb343692bfbecdef8fab8d114f0036eba01baec3888aa0",
|
||||
"master_fingerprint": "c1fdfe64",
|
||||
"path": "m"
|
||||
{
|
||||
"tx": {
|
||||
"txid": "ee82d3e0d225e0fb919130d68c5052b6e3c362c866acc54d89af975330bb4d16",
|
||||
"hash": "ee82d3e0d225e0fb919130d68c5052b6e3c362c866acc54d89af975330bb4d16",
|
||||
"version": 2,
|
||||
"size": 113,
|
||||
"vsize": 113,
|
||||
"weight": 452,
|
||||
"locktime": 0,
|
||||
"vin": [
|
||||
{
|
||||
"txid": "53ec62c5c2fe8b16ee2164e9699d16c7b8ac30ec53a696e55f09b79704b539b5",
|
||||
"vout": 0,
|
||||
"scriptSig": {
|
||||
"asm": "",
|
||||
"hex": ""
|
||||
},
|
||||
"sequence": 4294967295
|
||||
}
|
||||
],
|
||||
"vout": [
|
||||
{
|
||||
"value": 0.00999800,
|
||||
"n": 0,
|
||||
"scriptPubKey": {
|
||||
"asm": "0 cee9f88288a5f4980191a28d7ae08ff584050da7",
|
||||
"hex": "0014cee9f88288a5f4980191a28d7ae08ff584050da7",
|
||||
"reqSigs": 1,
|
||||
"type": "witness_v0_keyhash",
|
||||
"addresses": [
|
||||
"tb1qem5l3q5g5h6fsqv352xh4cy07kzq2rd8gphqma"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"value": 0.00999800,
|
||||
"n": 1,
|
||||
"scriptPubKey": {
|
||||
"asm": "0 8d861ff6e8acf1ca2a3b3dd59c86f2e8a0aba75c",
|
||||
"hex": "00148d861ff6e8acf1ca2a3b3dd59c86f2e8a0aba75c",
|
||||
"reqSigs": 1,
|
||||
"type": "witness_v0_keyhash",
|
||||
"addresses": [
|
||||
"tb1q3krplahg4ncu523m8h2eephjazs2hf6ur8r6zp"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"unknown": {
|
||||
},
|
||||
"inputs": [
|
||||
{
|
||||
"witness_utxo": {
|
||||
"amount": 0.01999800,
|
||||
"scriptPubKey": {
|
||||
"asm": "0 224cb503a7f7835799b9c22ee0c3c7d93d090356e30e70015c3ebbfa515a3074",
|
||||
"hex": "0020224cb503a7f7835799b9c22ee0c3c7d93d090356e30e70015c3ebbfa515a3074",
|
||||
"type": "witness_v0_scripthash",
|
||||
"address": "tb1qyfxt2qa877p40xdecghwps78my7sjq6kuv88qq2u86al5526xp6qfqjud0"
|
||||
}
|
||||
},
|
||||
"partial_signatures": {
|
||||
"038d73adf2c7ea33f9dc34b77b62b59af433c1de9c763332da79e83e155f96030e": "3044022040aae4f2ba37b1526524195f4a325d97d1317227b3c82aea55c5abd66810a7ec0220416e7c03e70a31232044addba454d6b37b6ace39ab163315d3293e343ae9513301"
|
||||
},
|
||||
"witness_script": {
|
||||
"asm": "2 038d73adf2c7ea33f9dc34b77b62b59af433c1de9c763332da79e83e155f96030e 03789f543423670e169667ff7e1f2da2a97df1b0912272e142d582451acebd0636 2 OP_CHECKMULTISIG",
|
||||
"hex": "5221038d73adf2c7ea33f9dc34b77b62b59af433c1de9c763332da79e83e155f96030e2103789f543423670e169667ff7e1f2da2a97df1b0912272e142d582451acebd063652ae",
|
||||
"type": "multisig"
|
||||
},
|
||||
"bip32_derivs": [
|
||||
{
|
||||
"pubkey": "03789f543423670e169667ff7e1f2da2a97df1b0912272e142d582451acebd0636",
|
||||
"master_fingerprint": "be686772",
|
||||
"path": "m"
|
||||
},
|
||||
{
|
||||
"pubkey": "038d73adf2c7ea33f9dc34b77b62b59af433c1de9c763332da79e83e155f96030e",
|
||||
"master_fingerprint": "d6043800",
|
||||
"path": "m/0'/0'/26'"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"bip32_derivs": [
|
||||
{
|
||||
"pubkey": "02fce26085452d07abc63bd389cb7dba9871e79bbecd08039291226be8232a9000",
|
||||
"master_fingerprint": "d6043800",
|
||||
"path": "m/0'/0'/24'"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
}
|
||||
],
|
||||
"fee": 0.00000200
|
||||
}
|
||||
machine1$ bitcoin-cli analyzepsbt $psbt_p1
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"has_utxo": true,
|
||||
"is_final": false,
|
||||
"next": "signer",
|
||||
"missing": {
|
||||
"signatures": [
|
||||
"be6867729bcc35ed065bb4c937557d371218a8e2"
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"estimated_vsize": 168,
|
||||
"estimated_feerate": 0.00001190,
|
||||
"fee": 0.00000200,
|
||||
"next": "signer"
|
||||
}
|
||||
```
|
||||
Esto demuestra que la información UTXO ha sido importada y que hay una _firma parcial_, pero que la firma de la entrada única aún no está completa.
|
||||
|
||||
Aquí está lo mismo en la otra máquina:
|
||||
```
|
||||
machine2$ psbt=cHNidP8BAHECAAAAAbU5tQSXtwlf5ZamU+wwrLjHFp1p6WQh7haL/sLFYuxTAAAAAAD/////AnhBDwAAAAAAFgAUzun4goil9JgBkaKNeuCP9YQFDad4QQ8AAAAAABYAFI2GH/borPHKKjs91ZyG8uigq6dcAAAAAAAAAAA=
|
||||
machine2$ psbt_p2=$(bitcoin-cli walletprocesspsbt $psbt | jq -r '.psbt')
|
||||
machine3$ echo $psbt_p2
|
||||
cHNidP8BAHECAAAAAbU5tQSXtwlf5ZamU+wwrLjHFp1p6WQh7haL/sLFYuxTAAAAAAD/////AnhBDwAAAAAAFgAUzun4goil9JgBkaKNeuCP9YQFDad4QQ8AAAAAABYAFI2GH/borPHKKjs91ZyG8uigq6dcAAAAAAABASu4gx4AAAAAACIAICJMtQOn94NXmbnCLuDDx9k9CQNW4w5wAVw+u/pRWjB0IgIDeJ9UNCNnDhaWZ/9+Hy2iqX3xsJEicuFC1YJFGs69BjZHMEQCIDJ71isvR2We6ym1QByLV5SQ+XEJD0SAP76fe1JU5PZ/AiB3V7ejl2H+9LLS6ubqYr/bSKfRfEqrp2FCMISjrWGZ6QEBBUdSIQONc63yx+oz+dw0t3titZr0M8HenHYzMtp56D4VX5YDDiEDeJ9UNCNnDhaWZ/9+Hy2iqX3xsJEicuFC1YJFGs69BjZSriIGA3ifVDQjZw4Wlmf/fh8toql98bCRInLhQtWCRRrOvQY2ENPtiCUAAACAAAAAgAYAAIAiBgONc63yx+oz+dw0t3titZr0M8HenHYzMtp56D4VX5YDDgRZu4lPAAAiAgNJzEMyT3rZS7QHqb8SvFCv2ee0MKRyVy8bY8tVUDT1KhDT7YglAAAAgAAAAIADAACAAA==
|
||||
```
|
||||
Tenga en cuenta nuevamente que gestionamos la firma de este multifirma generando un PSBT totalmente sin firmar con el UTXO correcto, luego permitiendo que cada uno de los usuarios procese ese PSBT por su cuenta, agregando entradas y firmas. Como resultado, tenemos dos PSBT, cada uno de los cuales contiene una firma y no la otra. Eso no funcionaría en el escenario clásico multifirma, porque todas las firmas tienen que ser serializadas. Aquí, en cambio, podemos iniciar sesión en paralelo y luego hacer uso del rol de Combinador para mezclarlas juntas.
|
||||
|
||||
Volvemos a ir a cualquiera de las dos máquinas y nos aseguramos de tener ambos PSBT en variables, luego los combinamos:
|
||||
```
|
||||
machine1$ psbt_p2="cHNidP8BAHECAAAAAbU5tQSXtwlf5ZamU+wwrLjHFp1p6WQh7haL/sLFYuxTAAAAAAD/////AnhBDwAAAAAAFgAUzun4goil9JgBkaKNeuCP9YQFDad4QQ8AAAAAABYAFI2GH/borPHKKjs91ZyG8uigq6dcAAAAAAABAIcCAAAAAtu5pTheUzdsTaMCEPj3XKboMAyYzABmIIeOWMhbhTYlAAAAAAD//////uSTLbibcqSd/Z9ieSBWJ2psv+9qvoGrzWEa60rCx9cAAAAAAP////8BuIMeAAAAAAAiACAiTLUDp/eDV5m5wi7gw8fZPQkDVuMOcAFcPrv6UVowdAAAAAAAACICA0nMQzJPetlLtAepvxK8UK/Z57QwpHJXLxtjy1VQNPUqENPtiCUAAACAAAAAgAMAAIAA"
|
||||
machine2$ psbt_c=$(bitcoin-cli combinepsbt '''["'$psbt_p1'", "'$psbt_p2'"]''')
|
||||
$ bitcoin-cli decodepsbt $psbt_c
|
||||
{
|
||||
"tx": {
|
||||
"txid": "ee82d3e0d225e0fb919130d68c5052b6e3c362c866acc54d89af975330bb4d16",
|
||||
"hash": "ee82d3e0d225e0fb919130d68c5052b6e3c362c866acc54d89af975330bb4d16",
|
||||
"version": 2,
|
||||
"size": 113,
|
||||
"vsize": 113,
|
||||
"weight": 452,
|
||||
"locktime": 0,
|
||||
"vin": [
|
||||
{
|
||||
"txid": "53ec62c5c2fe8b16ee2164e9699d16c7b8ac30ec53a696e55f09b79704b539b5",
|
||||
"vout": 0,
|
||||
"scriptSig": {
|
||||
"asm": "",
|
||||
"hex": ""
|
||||
},
|
||||
"sequence": 4294967295
|
||||
}
|
||||
],
|
||||
"vout": [
|
||||
{
|
||||
"value": 0.00999800,
|
||||
"n": 0,
|
||||
"scriptPubKey": {
|
||||
"asm": "0 cee9f88288a5f4980191a28d7ae08ff584050da7",
|
||||
"hex": "0014cee9f88288a5f4980191a28d7ae08ff584050da7",
|
||||
"reqSigs": 1,
|
||||
"type": "witness_v0_keyhash",
|
||||
"addresses": [
|
||||
"tb1qem5l3q5g5h6fsqv352xh4cy07kzq2rd8gphqma"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"value": 0.00999800,
|
||||
"n": 1,
|
||||
"scriptPubKey": {
|
||||
"asm": "0 8d861ff6e8acf1ca2a3b3dd59c86f2e8a0aba75c",
|
||||
"hex": "00148d861ff6e8acf1ca2a3b3dd59c86f2e8a0aba75c",
|
||||
"reqSigs": 1,
|
||||
"type": "witness_v0_keyhash",
|
||||
"addresses": [
|
||||
"tb1q3krplahg4ncu523m8h2eephjazs2hf6ur8r6zp"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"unknown": {
|
||||
},
|
||||
"inputs": [
|
||||
{
|
||||
"witness_utxo": {
|
||||
"amount": 0.01999800,
|
||||
"scriptPubKey": {
|
||||
"asm": "0 224cb503a7f7835799b9c22ee0c3c7d93d090356e30e70015c3ebbfa515a3074",
|
||||
"hex": "0020224cb503a7f7835799b9c22ee0c3c7d93d090356e30e70015c3ebbfa515a3074",
|
||||
"type": "witness_v0_scripthash",
|
||||
"address": "tb1qyfxt2qa877p40xdecghwps78my7sjq6kuv88qq2u86al5526xp6qfqjud0"
|
||||
}
|
||||
},
|
||||
"partial_signatures": {
|
||||
"038d73adf2c7ea33f9dc34b77b62b59af433c1de9c763332da79e83e155f96030e": "3044022040aae4f2ba37b1526524195f4a325d97d1317227b3c82aea55c5abd66810a7ec0220416e7c03e70a31232044addba454d6b37b6ace39ab163315d3293e343ae9513301",
|
||||
"03789f543423670e169667ff7e1f2da2a97df1b0912272e142d582451acebd0636": "30440220327bd62b2f47659eeb29b5401c8b579490f971090f44803fbe9f7b5254e4f67f02207757b7a39761fef4b2d2eae6ea62bfdb48a7d17c4aaba761423084a3ad6199e901"
|
||||
},
|
||||
"witness_script": {
|
||||
"asm": "2 038d73adf2c7ea33f9dc34b77b62b59af433c1de9c763332da79e83e155f96030e 03789f543423670e169667ff7e1f2da2a97df1b0912272e142d582451acebd0636 2 OP_CHECKMULTISIG",
|
||||
"hex": "5221038d73adf2c7ea33f9dc34b77b62b59af433c1de9c763332da79e83e155f96030e2103789f543423670e169667ff7e1f2da2a97df1b0912272e142d582451acebd063652ae",
|
||||
"type": "multisig"
|
||||
},
|
||||
"bip32_derivs": [
|
||||
{
|
||||
"pubkey": "03789f543423670e169667ff7e1f2da2a97df1b0912272e142d582451acebd0636",
|
||||
"master_fingerprint": "be686772",
|
||||
"path": "m"
|
||||
},
|
||||
{
|
||||
"pubkey": "038d73adf2c7ea33f9dc34b77b62b59af433c1de9c763332da79e83e155f96030e",
|
||||
"master_fingerprint": "d6043800",
|
||||
"path": "m/0'/0'/26'"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"bip32_derivs": [
|
||||
{
|
||||
"pubkey": "02fce26085452d07abc63bd389cb7dba9871e79bbecd08039291226be8232a9000",
|
||||
"master_fingerprint": "d6043800",
|
||||
"path": "m/0'/0'/24'"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"bip32_derivs": [
|
||||
{
|
||||
"pubkey": "0349cc43324f7ad94bb407a9bf12bc50afd9e7b430a472572f1b63cb555034f52a",
|
||||
"master_fingerprint": "d3ed8825",
|
||||
"path": "m/0'/0'/3'"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"fee": 0.00000200
|
||||
}
|
||||
$ bitcoin-cli analyzepsbt $psbt_c
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"has_utxo": true,
|
||||
"is_final": false,
|
||||
"next": "finalizer"
|
||||
}
|
||||
],
|
||||
"estimated_vsize": 168,
|
||||
"estimated_feerate": 0.00001190,
|
||||
"fee": 0.00000200,
|
||||
"next": "finalizer"
|
||||
}
|
||||
```
|
||||
¡Funcionó! Simplemente finalizamos, enviamos y terminamos:
|
||||
```
|
||||
machine2$ psbt_c_hex=$(bitcoin-cli finalizepsbt $psbt_c | jq -r '.hex')
|
||||
standup@btctest2:~$ bitcoin-cli -named sendrawtransaction hexstring=$psbt_c_hex
|
||||
ee82d3e0d225e0fb919130d68c5052b6e3c362c866acc54d89af975330bb4d16
|
||||
```
|
||||
Obviamente, no hubo una gran mejora en el uso de este método en comparación con la firma en serie de una transacción para una multifirma 2 de 2 cuando todos usaban `bitcoin-cli`: podríamos haber pasado una transacción sin procesar con firmas parciales de un usuario a otro tan fácilmente como enviar ese PSBT. Pero este fue el caso más simple. A medida que nos adentramos en multifirmas más complejas, esta metodología se vuelve cada vez mejor.
|
||||
|
||||
En primer lugar, es independiente de la plataforma. Siempre que todos utilicen un servicio que admita Bitcoin Core 0.17, todos podrán firmar esta transacción, lo cual no es cierto cuando los multifirmas clásicos se transmiten entre diferentes plataformas.
|
||||
|
||||
En segundo lugar, es mucho más escalable. Considere un multifirma de 3 de 5. Bajo la vieja metodología, tendría que pasar de persona a persona, aumentando enormemente los problemas si se rompe algún eslabón de la cadena. Aquí, otros usuarios solo tienen que enviar los PSBTs al Creador, y tan pronto como tenga suficiente, puede generar la transacción final.
|
||||
|
||||
## Utilice un PSBT para juntar dinero
|
||||
|
||||
Multifirmas como la utilizada en el ejemplo anterior se suelen utilizar para recibir pagos por trabajo colaborativo, ya sean regalías por un libro o pagos realizados a una empresa. En esa situación, el ejemplo anterior funciona muy bien: los dos participantes reciben su dinero y luego lo dividen. Pero, ¿qué pasa con el caso inverso, donde dos (o más) participantes quieren establecer una empresa conjunta y necesitan financiarla con dinero?
|
||||
|
||||
La respuesta tradicional es crear una multifirma y luego hacer que los participantes le envíen sus fondos individualmente. El problema es que el primer pagador tiene que depender de la buena fe del segundo, y eso no se basa en la fortaleza de Bitcoin, que es su _confianza sin depender de las contrapartes_. Afortunadamente, con la llegada de los PSBT, ahora podemos realizar pagos sin confianza que agrupan fondos.
|
||||
|
||||
> :book: ***¿Qué significa sin confianza?*** Sin confianza significa que ningún participante tiene que confiar en ningún otro participante. En su lugar, esperan que los protocolos de software garanticen que todo se ejecute de manera justa de la manera esperada. Bitcoin es un protocolo sin confianza porque no necesita que nadie más actúe de buena fe; el sistema lo gestiona. De manera similar, los PSBT permiten la creación sin confianza de transacciones que agrupan o dividen fondos.
|
||||
El siguiente ejemplo muestra dos usuarios que cada uno tiene 0.010 BTC que quieren agrupar en la dirección multifirma `tb1qyfxt2qa877p40xdecghwps78my7sjq6kuv88qq2u86al5526xp6qfqjud0`, creada anteriormente.
|
||||
```
|
||||
machine1$ bitcoin-cli listunspent
|
||||
[
|
||||
{
|
||||
"txid": "2536855bc8588e87206600cc980c30e8a65cf7f81002a34d6c37535e38a5b9db",
|
||||
"vout": 0,
|
||||
"address": "tb1qfg5y4fx979xkv4ezatc5eevufc8vh45553n4ut",
|
||||
"label": "",
|
||||
"scriptPubKey": "00144a284aa4c5f14d665722eaf14ce59c4e0ecbd694",
|
||||
"amount": 0.01000000,
|
||||
"confirmations": 2,
|
||||
"spendable": true,
|
||||
"solvable": true,
|
||||
"desc": "wpkh([d6043800/0'/0'/25']02bea222cf9ea1f49b392103058cc7c8741d76a553fe627c1c43fc3ef4404c9d54)#4hnkg9ml",
|
||||
"safe": true
|
||||
}
|
||||
]
|
||||
machine2$ bitcoin-cli listunspent
|
||||
[
|
||||
{
|
||||
"txid": "d7c7c24aeb1a61cdab81be6aefbf6c6a27562079629ffd9da4729bb82d93e4fe",
|
||||
"vout": 0,
|
||||
"address": "tb1qfqyyw6xrghm5kcrpkus3kl2l6dz4tpwrvn5ujs",
|
||||
"label": "",
|
||||
"scriptPubKey": "001448084768c345f74b6061b7211b7d5fd3455585c3",
|
||||
"amount": 0.01000000,
|
||||
"confirmations": 5363,
|
||||
"spendable": true,
|
||||
"solvable": true,
|
||||
"desc": "wpkh([d3ed8825/0'/0'/0']03ff6b94c119582a63dbae4fb530efab0ed5635f7c3b2cf171264ca0af3ecef33a)#gtmd2e2k",
|
||||
"safe": true
|
||||
}
|
||||
]
|
||||
```
|
||||
Ellas configuran variables para usar esas transacciones:
|
||||
```
|
||||
machine1$ utxo_txid_1=2536855bc8588e87206600cc980c30e8a65cf7f81002a34d6c37535e38a5b9db
|
||||
machine1$ utxo_vout_1=0
|
||||
machine1$ utxo_txid_2=d7c7c24aeb1a61cdab81be6aefbf6c6a27562079629ffd9da4729bb82d93e4fe
|
||||
machine1$ utxo_vout_2=0
|
||||
machine1$ multisig=tb1qyfxt2qa877p40xdecghwps78my7sjq6kuv88qq2u86al5526xp6qfqjud0
|
||||
```
|
||||
Y crea una PSBT:
|
||||
```
|
||||
machine1$ psbt=$(bitcoin-cli -named createpsbt inputs='''[ { "txid": "'$utxo_txid_1'", "vout": '$utxo_vout_1' }, { "txid": "'$utxo_txid_2'", "vout": '$utxo_vout_2' } ]''' outputs='''{ "'$multisig'": 0.019998 }''')
|
||||
```
|
||||
Así es como se ve:
|
||||
```
|
||||
machine1$ bitcoin-cli decodepsbt $psbt
|
||||
{
|
||||
"tx": {
|
||||
"txid": "53ec62c5c2fe8b16ee2164e9699d16c7b8ac30ec53a696e55f09b79704b539b5",
|
||||
"hash": "53ec62c5c2fe8b16ee2164e9699d16c7b8ac30ec53a696e55f09b79704b539b5",
|
||||
"version": 2,
|
||||
"size": 135,
|
||||
"vsize": 135,
|
||||
"weight": 540,
|
||||
"locktime": 0,
|
||||
"vin": [
|
||||
{
|
||||
"txid": "2536855bc8588e87206600cc980c30e8a65cf7f81002a34d6c37535e38a5b9db",
|
||||
"vout": 0,
|
||||
"scriptSig": {
|
||||
"asm": "",
|
||||
"hex": ""
|
||||
},
|
||||
"sequence": 4294967295
|
||||
},
|
||||
{
|
||||
"txid": "d7c7c24aeb1a61cdab81be6aefbf6c6a27562079629ffd9da4729bb82d93e4fe",
|
||||
"vout": 0,
|
||||
"scriptSig": {
|
||||
"asm": "",
|
||||
"hex": ""
|
||||
},
|
||||
"sequence": 4294967295
|
||||
}
|
||||
],
|
||||
"vout": [
|
||||
{
|
||||
"value": 0.01999800,
|
||||
"n": 0,
|
||||
"scriptPubKey": {
|
||||
"asm": "0 224cb503a7f7835799b9c22ee0c3c7d93d090356e30e70015c3ebbfa515a3074",
|
||||
"hex": "0020224cb503a7f7835799b9c22ee0c3c7d93d090356e30e70015c3ebbfa515a3074",
|
||||
"reqSigs": 1,
|
||||
"type": "witness_v0_scripthash",
|
||||
"addresses": [
|
||||
"tb1qyfxt2qa877p40xdecghwps78my7sjq6kuv88qq2u86al5526xp6qfqjud0"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"unknown": {
|
||||
},
|
||||
"inputs": [
|
||||
{
|
||||
},
|
||||
{
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
No importa que las transacciones sean propiedad de dos personas diferentes o que su información completa aparezca en dos máquinas diferentes. Este PSBT de financiación funcionará exactamente igual que el PSBT multifirma: una vez que todas las partes controladoras hayan firmado, se podrá finalizar la transacción.
|
||||
|
||||
Aquí está el proceso, esta vez pasando el PSBT parcialmente firmado de un usuario a otro en lugar de tener que combinar las cosas al final.
|
||||
```
|
||||
machine1$ bitcoin-cli walletprocesspsbt $psbt
|
||||
{
|
||||
"psbt": "cHNidP8BAIcCAAAAAtu5pTheUzdsTaMCEPj3XKboMAyYzABmIIeOWMhbhTYlAAAAAAD//////uSTLbibcqSd/Z9ieSBWJ2psv+9qvoGrzWEa60rCx9cAAAAAAP////8BuIMeAAAAAAAiACAiTLUDp/eDV5m5wi7gw8fZPQkDVuMOcAFcPrv6UVowdAAAAAAAAQEfQEIPAAAAAAAWABRKKEqkxfFNZlci6vFM5ZxODsvWlAEIawJHMEQCIGAiKIAWRXiw68o3pw61/cVNP7n2oH73S654XXgQ4kjHAiBtTBqmaF1iIzYGXrG4DadH8y6mTuCRVFDiPl+TLQDBJwEhAr6iIs+eofSbOSEDBYzHyHQddqVT/mJ8HEP8PvRATJ1UAAABAUdSIQONc63yx+oz+dw0t3titZr0M8HenHYzMtp56D4VX5YDDiEDeJ9UNCNnDhaWZ/9+Hy2iqX3xsJEicuFC1YJFGs69BjZSriICA3ifVDQjZw4Wlmf/fh8toql98bCRInLhQtWCRRrOvQY2BL5oZ3IiAgONc63yx+oz+dw0t3titZr0M8HenHYzMtp56D4VX5YDDhDWBDgAAAAAgAAAAIAaAACAAA==",
|
||||
"complete": false
|
||||
}
|
||||
machine2$ psbt_p="cHNidP8BAIcCAAAAAtu5pTheUzdsTaMCEPj3XKboMAyYzABmIIeOWMhbhTYlAAAAAAD//////uSTLbibcqSd/Z9ieSBWJ2psv+9qvoGrzWEa60rCx9cAAAAAAP////8BuIMeAAAAAAAiACAiTLUDp/eDV5m5wi7gw8fZPQkDVuMOcAFcPrv6UVowdAAAAAAAAQEfQEIPAAAAAAAWABRKKEqkxfFNZlci6vFM5ZxODsvWlAEIawJHMEQCIGAiKIAWRXiw68o3pw61/cVNP7n2oH73S654XXgQ4kjHAiBtTBqmaF1iIzYGXrG4DadH8y6mTuCRVFDiPl+TLQDBJwEhAr6iIs+eofSbOSEDBYzHyHQddqVT/mJ8HEP8PvRATJ1UAAABAUdSIQONc63yx+oz+dw0t3titZr0M8HenHYzMtp56D4VX5YDDiEDeJ9UNCNnDhaWZ/9+Hy2iqX3xsJEicuFC1YJFGs69BjZSriICA3ifVDQjZw4Wlmf/fh8toql98bCRInLhQtWCRRrOvQY2BL5oZ3IiAgONc63yx+oz+dw0t3titZr0M8HenHYzMtp56D4VX5YDDhDWBDgAAAAAgAAAAIAaAACAAA=="
|
||||
machine2$ psbt_f=$(bitcoin-cli walletprocesspsbt $psbt_p | jq -r '.psbt')
|
||||
machine2$ bitcoin-cli analyzepsbt $psbt_f
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"has_utxo": true,
|
||||
"is_final": true,
|
||||
"next": "extractor"
|
||||
},
|
||||
{
|
||||
"has_utxo": true,
|
||||
"is_final": true,
|
||||
"next": "extractor"
|
||||
}
|
||||
],
|
||||
"estimated_vsize": 189,
|
||||
"estimated_feerate": 0.00001058,
|
||||
"fee": 0.00000200,
|
||||
"next": "extractor"
|
||||
}
|
||||
machine2$ psbt_hex=$(bitcoin-cli finalizepsbt $psbt_f | jq -r '.hex')
|
||||
machine2$ bitcoin-cli -named sendrawtransaction hexstring=$psbt_hex
|
||||
53ec62c5c2fe8b16ee2164e9699d16c7b8ac30ec53a696e55f09b79704b539b5
|
||||
```
|
||||
¡Hemos utilizado un PSBT para reunir dinero sin confianza en una multifirma!
|
||||
|
||||
## Usa una PSBT para CoinJoin
|
||||
|
||||
CoinJoin es otra aplicación de Bitcoin que requiere desconfianza. Aquí, tiene una variedad de partes que no necesariamente se conocen entre sí juntando dinero y recuperándolo.
|
||||
|
||||
La metodología para administrarlo con PSBT es exactamente la misma que ha visto en los ejemplos anteriores, como lo demuestra el siguiente pseudocódigo:
|
||||
```
|
||||
$ psbt=$(bitcoin-cli -named createpsbt inputs='''[ { "txid": "'$utxo_txid_1'", "vout": '$utxo_vout_1' }, { "txid": "'$utxo_txid_2'", "vout": '$utxo_vout_2' }, { "txid": "'$utxo_txid_3'", "vout": '$utxo_vout_3' } ]''' outputs='''{ "'$split1'": 1.7,"'$split2'": 0.93,"'$split3'": 1.4 }''')
|
||||
```
|
||||
Cada usuario pone su propio UTXO y cada uno recibe una salida correspondiente.
|
||||
|
||||
La mejor manera de administrar un CoinJoin es enviar el PSBT base a todas las partes (que podrían ser numerosas), y luego hacer que cada una de ellas firme el PSBT y lo envíe de vuelta a una sola parte que combinará, finalizará y enviará.
|
||||
|
||||
## Resumen: Usando una transacción Bitcoin parcialmente firmada
|
||||
|
||||
Ahora ha visto el proceso de PSBT que aprendió en [§7.1](07_1_Creando_una_Transaccion_Bitcoin_Parcialmente_Firmada.md) en uso en tres ejemplos de la vida real: creación de una multifirma, agrupación de fondos y dentro de un CoinJoin. Todo esto era teóricamente posible en Bitcoin clásico al hacer que varias personas firmen transacciones cuidadosamente construidas, pero los PSBT lo hacen estandarizado y simple.
|
||||
|
||||
> :fire: ***¿Cuál es el poder de una PSBT?*** Un PSBT permite la creación de transacciones sin confianza entre múltiples partes y múltiples máquinas. Si más de una parte necesita financiar una transacción, si más de una parte necesita firmar una transacción o si una transacción debe crearse en una máquina y firmarse en otra, entonces un PSBT lo simplifica sin depender de la mecanismos de firma parcial no estandarizados que solían existir antes de PSBT.
|
||||
|
||||
Ese último punto, sobre la creación de una transacción en una máquina y la firma en otra, es un elemento de los PSBT al que aún no hemos llegado. Está en el corazón de las billeteras de hardware, donde a menudo desea crear una transacción en un nodo completo y luego pasarla a una billetera de hardware cuando se requiere una firma. Ese es el tema de la última sección (y nuestro cuarto ejemplo de la vida real) en este capítulo sobre PSBTs.
|
||||
|
||||
## ¿Qué sigue?
|
||||
|
||||
Continúe "Expandiendo transacciones de Bitcoin con PSBT" con [§7.3: Integrando con Hardware Wallets](07_3_Integrando_con_Hardware_Wallets.md).
|
475
es/07_3_Integrando_con_Hardware_Wallets.md
Normal file
475
es/07_3_Integrando_con_Hardware_Wallets.md
Normal file
@ -0,0 +1,475 @@
|
||||
# 7.3: Integrando con Hardware Wallets
|
||||
|
||||
> :information_source: **NOTA:** Esta sección se ha agregado recientemente al curso y es un borrador inicial que aún puede estar pendiente de revisión. Lector de advertencias.
|
||||
|
||||
Uno de los mayores poderes de los PSBT es la capacidad de transferir transacciones a billeteras de hardware. Esta será una gran herramienta de desarrollo para usted si continúa programando con Bitcoin. Sin embargo, no puede probarlo ahora si está utilizando una de las configuraciones que sugerimos para este curso: una máquina virtual en Linode según [§2.1](02_1_Configurando_un_Bitcoin-Core_VPS_con_StackScript.md) o una opción aún más remota como AWS según [§2.2](02_2_Configurando_Bitcoin_Core_Otros.md) — porque obviamente no tendrá forma de conectar una billetera de hardware a su máquina virtual remota.
|
||||
|
||||
> :book: ***¿Qué es una cartera de hardware?*** Una billetera de hardware es un dispositivo electrónico que mejora la seguridad de una criptomoneda al mantener todas las claves privadas en el dispositivo, en lugar de ponerlas en una computadora directamente conectada a Internet. Las billeteras de hardware tienen protocolos específicos para proporcionar interacciones en línea, generalmente administradas por un programa que habla con el dispositivo a través de un puerto USB. En este capítulo, administraremos una billetera de hardware con `bitcoin-cli` y el programa `hwy.py`.
|
||||
|
||||
Tiene tres opciones para avanzar a través de este capítulo sobre billeteras de hardware: (1) leer sin probar el código; (2) instale Bitcoin en una máquina local para probar completamente estos comandos; o (3) pasar directamente al [Capítulo 8: Expandiendo Transacciones Bitcoin en Otros Sentidos](08_0_Expandiendo_Bitcoin_Transacciones_Otros.md). Sugerimos la opción #1, pero si realmente quiere ensuciarse las manos, también daremos algo de apoyo a la #2 hablando sobre el uso de Macintosh (una plataforma de hardware compatible con [Bitcoin Standup](https://github.com/BlockchainCommons/Bitcoin-Standup)) para realizar pruebas.
|
||||
|
||||
> :warning: **ADVERTENCIA DE VERSIÓN:** Los PSBT son una innovación de Bitcoin Core v 0.17.0. Las versiones anteriores de Bitcoin Core no podrán funcionar con el PSBT mientras esté en progreso (aunque aún podrán reconocer la transacción final). La interfaz HWI apareció en Bitcoin Core v 0.18.0, pero siempre que utilice nuestra configuración sugerida con Bitcoin Standup, debería funcionar.
|
||||
|
||||
La metodología descrita en este capítulo para la integración con una billetera de hardware depende de la [Interfaz de billetera de hardware de Bitcoin](https://github.com/bitcoin-core/HWI) lanzada a través de Bitcoin Core y se basa en las [instrucciones de instalación](https://github.com/bitcoin-core/HWI/blob/master/README.md) y [uso](https://hwi.readthedocs.io) que se encuentran allí.
|
||||
|
||||
> :warning: **ADVERTENCIA DE FRESCURA:** La interfaz HWI es muy nueva y cruda en los bordes a partir de Bitcoin Core v 0.20.0. Puede ser difícil de instalar correctamente y puede tener errores poco intuitivos. Lo que sigue es una descripción de una configuración funcional, pero tomó varios intentos para hacerlo bien y su configuración puede variar.
|
||||
|
||||
## Instale Bitcoin Core en una máquina local
|
||||
|
||||
_Si solo planea leer esta sección y no probar estos comandos hasta una fecha futura cuando tenga un entorno de desarrollo local, puede omitir esta subsección, que trata sobre la creación de una instalación de Bitcoin Core en una máquina local como una Mac o Máquina Linux._
|
||||
|
||||
Hay versiones alternativas del script Bitcoin Standup que usó para crear su VM que se instalará en MacOS o en una máquina Linux que no sea Linode.
|
||||
|
||||
Si tiene MacOS, puede instalar [Bitcoin Standup MacOS](https://github.com/BlockchainCommons/Bitcoin-Standup-MacOS/blob/master/README.md).
|
||||
|
||||
Si tiene una máquina Linux local, puede instalar [Bitcoin Standup Linux Scripts](https://github.com/BlockchainCommons/Bitcoin-Standup-Scripts/blob/master/README.md).
|
||||
|
||||
Una vez que haya ejecutado Bitcoin Standup en su máquina local, querrá sincronizar la cadena de bloques "Testnet", asumiendo que continúa siguiendo la metodología estándar de este curso.
|
||||
|
||||
Usaremos Macintosh y Testnet para los ejemplos de esta sección.
|
||||
|
||||
### Cree un alias para Bitcoin-CLI
|
||||
|
||||
Cree un alias que ejecute `bitcoin-cli` desde el directorio correcto con los indicadores apropiados.
|
||||
|
||||
Aquí hay un ejemplo de alias de una Mac:
|
||||
```
|
||||
$ alias bitcoin-cli="~/StandUp/BitcoinCore/bitcoin-0.20.0/bin/bitcoin-cli -testnet"
|
||||
```
|
||||
Notará que no solo nos da la ruta completa, sino que también asegura que permanezcamos en Testnet.
|
||||
|
||||
## Instalar HWI en una máquina local
|
||||
|
||||
_Las siguientes instrucciones asumen nuevamente una Mac, y puede omitir nuevamente esta subsección si solo está leyendo este capítulo._
|
||||
|
||||
HWI es un programa de Bitcoin Core disponible en Python que se puede utilizar para interactuar con billeteras de hardware.
|
||||
|
||||
### Instalar Python
|
||||
|
||||
Debido a que HWI está escrito en `python`, necesitará instalarlo, así como algunos programas auxiliares.
|
||||
|
||||
Si aún no tiene las herramientas de línea de comando `xcode`, las necesitará:
|
||||
```
|
||||
$ xcode-select --install
|
||||
```
|
||||
|
||||
Si aún no tiene el administrador de paquetes Homebrew, debería instalarlo también. Las instrucciones actuales están disponibles en [sitio de Homebrew](https://brew.sh/). Al momento de escribir estas líneas, simplemente necesita::
|
||||
```
|
||||
$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
|
||||
```
|
||||
|
||||
Para una instalación por primera vez, también debe asegurarse de que su directorio `/usr/local/Frameworks` se haya creado correctamente:
|
||||
```
|
||||
$ sudo mkdir /usr/local/Frameworks
|
||||
$ sudo chown $(whoami):admin /usr/local/Frameworks
|
||||
```
|
||||
|
||||
Si tiene todo eso en su lugar, finalmente puede instalar Python:
|
||||
```
|
||||
$ brew install python
|
||||
$ brew install libusb
|
||||
```
|
||||
|
||||
### Instalar HWI
|
||||
|
||||
Ahora está listo para instalar HWI, que requiere clonar un repositorio de GitHub y ejecutar un script de instalación.
|
||||
|
||||
Si aun no tiene `git` instalado en su Mac, puede hacerlo simplemente intentando ejecutarlo así: `git --version`.
|
||||
|
||||
Luego puede clonar el repositorio HWI:
|
||||
```
|
||||
$ cd ~/StandUp
|
||||
$ git clone https://github.com/bitcoin-core/HWI.git
|
||||
```
|
||||
Luego, debe instalar el paquete y sus dependencias:
|
||||
```
|
||||
$ cd HWI
|
||||
HWI$ python3 setup.py install
|
||||
```
|
||||
|
||||
### Crear un alias para HWI
|
||||
|
||||
También querrá crear un alias aquí, variará según la ubicación real de su instalación:
|
||||
```
|
||||
$ alias hwi="~/Standup/HWI/hwi.py --chain test"
|
||||
```
|
||||
Nuevamente, hemos incluido una referencia a testnet en este alias.
|
||||
|
||||
## Prepare su Ledger
|
||||
|
||||
_También tuvimos que elegir una plataforma de billetera de hardware para esta demostración de HWI. Nuestra elección fue el Ledger, que ha sido durante mucho tiempo nuestro banco de pruebas para billeteras de hardware. Consulte [Información de soporte del dispositivo de HWI](https://github.com/bitcoin-core/HWI/blob/master/README.md#device-support) para obtener una lista de otros dispositivos compatibles. Si utiliza un dispositivo que no sea Ledger, deberá evaluar sus propias soluciones para prepararlo para su uso en Testnet, pero de lo contrario debería poder continuar con el curso tal como está escrito._
|
||||
|
||||
Si está trabajando con Bitcoins en su libro mayor, probablemente no tendrá que hacer nada. (Pero no sugerimos que se use con este curso).
|
||||
|
||||
Para trabajar con monedas de Testnet, como sugiere este curso, deberá realizar algunas actualizaciones:
|
||||
|
||||
1. Vaya a Configuración en su aplicación Ledger Live (es el engranaje), vaya a la pestaña "Funciones experimentales" y active el "Modo de desarrollador".
|
||||
2. Vaya al "Administrador" e instale "Prueba de Bitcoin". La versión actual requiere que primero instale "Bitcoin".
|
||||
3. Vaya al "Administrador", desplácese hasta su nueva "Prueba de Bitcoin" y "Agregar cuenta"
|
||||
|
||||
## Enlace a su Ledger
|
||||
|
||||
Para que un libro mayor sea accesible, debe iniciar sesión con su PIN y luego abrir la aplicación que desea usar, en este caso, la aplicación "Prueba de Bitcoin". Es posible que deba repetir esto de vez en cuando si su Ledger entra en reposo.
|
||||
|
||||
Una vez que haya hecho eso, puede pedirle a HWI que acceda al Libro mayor con el comando `enumerate`::
|
||||
```
|
||||
$ hwi enumerate
|
||||
[{"type": "ledger", "model": "ledger_nano_s", "path": "IOService:/AppleACPIPlatformExpert/PCI0@0/AppleACPIPCI/XHC1@14/XHC1@14000000/HS05@14100000/Nano S@14100000/Nano S@0/IOUSBHostHIDDevice@14100000,0", "fingerprint": "9a1d520b", "needs_pin_sent": false, "needs_passphrase_sent": false}]
|
||||
```
|
||||
Si recibe información en su dispositivo, ¡está listo! Como puede ver, verifica su tipo de billetera de hardware, proporciona otra información de identificación y le indica cómo comunicarse con el dispositivo. La `huella digital` (`9a1d520b`) es a lo que debe prestar especial atención, porque todas las interacciones con su billetera de hardware lo requerirán.
|
||||
|
||||
Si en su lugar obtuvo `[]`, entonces (1) no preparó su dispositivo Ledger ingresando su PIN y eligiendo la aplicación correcta, o (2) hay algo mal con su configuración de Python, probablemente una dependencia faltante: debería considerar desinstalarlo e intentarlo desde cero.
|
||||
|
||||
## Importar direcciones
|
||||
|
||||
La interacción con una billetera de hardware generalmente se divide en dos partes: buscar fondos y gastar fondos.
|
||||
|
||||
Puede buscar fondos importando direcciones desde su billetera de hardware a su nodo completo, usando HWI y `bitcoin-cli`.
|
||||
|
||||
### Crea una billetera
|
||||
|
||||
Para usar su billetera de hardware con `bitcoin-cli`, querrá crear una billetera con nombre específico en Bitcoin Core, usando el comando RPC `createwallet`, que es un comando que no hemos discutido anteriormente.
|
||||
```
|
||||
$ bitcoin-cli --named createwallet wallet_name="ledger" disable_private_keys="true"
|
||||
{
|
||||
"name": "ledger",
|
||||
"warning": ""
|
||||
}
|
||||
```
|
||||
En este caso, está creando un nuevo `ledger` de billetera sin claves privadas (ya que éstas terminarán en el dispositivo de Ledger).
|
||||
|
||||
> :book: ***¿Por qué nombrar billeteras?*** Hasta la fecha, este curso ha utilizado la billetera predeterminada ("") en Bitcoin Core. Esto está bien para muchos propósitos, pero es inadecuado si tiene una situación más compleja, como cuando está viendo claves desde una billetera de hardware. Aquí, queremos poder diferenciar de las claves de propiedad local (que se mantienen en la "" billetera) y las claves de propiedad remota (que se guardan en la billetera "ledger").
|
||||
|
||||
Ahora puede ver que la nueva billetera está en su lista de billeteras:
|
||||
```
|
||||
$ bitcoin-cli listwallets
|
||||
[
|
||||
"",
|
||||
"ledger"
|
||||
]
|
||||
```
|
||||
Debido a que ha creado una segunda billetera, algunos comandos ahora requerirán una marca `-rpcwallet =`, para especificar cuál está usando.
|
||||
|
||||
### Importar las claves
|
||||
|
||||
Ahora tiene que importar una lista de seguimiento de direcciones desde la billetera de hardware. Esto se hace con el comando `getkeypool` de HWI:
|
||||
```
|
||||
$ hwi -f 9a1d520b getkeypool 0 1000
|
||||
[{"desc": "wpkh([9a1d520b/84h/1h/0h]tpubDD7KTtoGzK9GuWUQcr1uTJazsAkqoXhdrwGXWVix6nPpNZmSbagZWD4QSaMsyK8YohAirGDPrWdRiEpKzTFB7DrTrqfzHCn7yi5EsqeR93S/0/*)#qttxy592", "range": [0, 1000], "timestamp": "now", "internal": false, "keypool": true, "active": true, "watchonly": true}, {"desc": "wpkh([9a1d520b/84h/1h/0h]tpubDD7KTtoGzK9GuWUQcr1uTJazsAkqoXhdrwGXWVix6nPpNZmSbagZWD4QSaMsyK8YohAirGDPrWdRiEpKzTFB7DrTrqfzHCn7yi5EsqeR93S/1/*)#3lw8ep4j", "range": [0, 1000], "timestamp": "now", "internal": true, "keypool": true, "active": true, "watchonly": true}]
|
||||
```
|
||||
Nos dirigimos a HWI con la `huella digital` y pedimos las primeras 1000 direcciones WPKH (Segwit nativo). El tipo de direcciones WPKH (native Segwit) es usado por defecto. A cambio, recibimos dos descriptores para el grupo de claves: uno para las direcciones de recepción y otro para las direcciones de cambio.
|
||||
|
||||
> :book: ***¿Qué es un grupo de claves?*** Un grupo de claves es un grupo de claves pregeneradas. Las billeteras HD modernas crean grupos de claves al continuar determinando nuevas direcciones jerárquicas basadas en la semilla original. La idea de los grupos de claves se implementó originalmente para facilitar los requisitos de respaldo de las billeteras. Esto permitió a un usuario generar un conjunto de claves y luego hacer una copia de seguridad de la billetera de inmediato, en lugar de requerir copias de seguridad después de que se creara cada nueva dirección. El concepto también ha demostrado ser muy útil en la actualidad, ya que permite importar un conjunto completo de direcciones futuras de un dispositivo a otro.
|
||||
|
||||
Los valores devueltos por `getkeypool` son el mismo tipo de descriptores que aprendimos en [§3.5: Entendiendo El Descriptor](03_5_Entendiendo_El_Descriptor.md). En ese momento, dijimos que eran más útiles para mover direcciones entre diferentes máquinas. Aquí está el ejemplo de la vida real: mover direcciones de una billetera de hardware al nodo Bitcoin Core, para que nuestra máquina conectada a la red pueda vigilar las claves que pertenecen a la billetera de hardware fuera de línea.
|
||||
|
||||
Tal como aprendió en [§3.5](03_5_Entendiendo_El_Descriptor.md), puede examinar estos descriptores con el RPC `getdescriptorinfo`:
|
||||
```
|
||||
$ bitcoin-cli getdescriptorinfo "wpkh([9a1d520b/84h/1h/0h]tpubDD7KTtoGzK9GuWUQcr1uTJazsAkqoXhdrwGXWVix6nPpNZmSbagZWD4QSaMsyK8YohAirGDPrWdRiEpKzTFB7DrTrqfzHCn7yi5EsqeR93S/0/*)#qttxy592"
|
||||
{
|
||||
"descriptor": "wpkh([9a1d520b/84'/1'/0']tpubDD7KTtoGzK9GuWUQcr1uTJazsAkqoXhdrwGXWVix6nPpNZmSbagZWD4QSaMsyK8YohAirGDPrWdRiEpKzTFB7DrTrqfzHCn7yi5EsqeR93S/0/*)#n65e7wjf",
|
||||
"checksum": "qttxy592",
|
||||
"isrange": true,
|
||||
"issolvable": true,
|
||||
"hasprivatekeys": false
|
||||
}
|
||||
```
|
||||
Como era de esperar, _no_ tenemos `privatekeys`, porque las billeteras de hardware se aferran a ellas.
|
||||
|
||||
Con los descriptores en la mano, puede importar las claves a su nueva billetera `ledger` usando el RPC `importmulti` que también conoció en [§3.5](03_5_Entendiendo_El_Descriptor.md). En este caso, simplemente coloque la respuesta completa que recibió de HWI en `'`s.
|
||||
```
|
||||
$ bitcoin-cli -rpcwallet=ledger importmulti '[{"desc": "wpkh([9a1d520b/84h/1h/0h]tpubDD7KTtoGzK9GuWUQcr1uTJazsAkqoXhdrwGXWVix6nPpNZmSbagZWD4QSaMsyK8YohAirGDPrWdRiEpKzTFB7DrTrqfzHCn7yi5EsqeR93S/0/*)#qttxy592", "range": [0, 1000], "timestamp": "now", "internal": false, "keypool": true, "active": true, "watchonly": true}, {"desc": "wpkh([9a1d520b/84h/1h/0h]tpubDD7KTtoGzK9GuWUQcr1uTJazsAkqoXhdrwGXWVix6nPpNZmSbagZWD4QSaMsyK8YohAirGDPrWdRiEpKzTFB7DrTrqfzHCn7yi5EsqeR93S/1/*)#3lw8ep4j", "range": [0, 1000], "timestamp": "now", "internal": true, "keypool": true, "active": true, "watchonly": true}]'
|
||||
[
|
||||
{
|
||||
"success": true
|
||||
},
|
||||
{
|
||||
"success": true
|
||||
}
|
||||
]
|
||||
```
|
||||
(Tenga en cuenta que HWI muestra de manera útil la ruta de derivación con `h`s para mostrar derivaciones reforzadas en lugar de `'`s, y calculó su suma de comprobación en consecuencia, de modo que no tengamos que hacer citas masivas como hicimos en §3.5).
|
||||
|
||||
_Podría_ ahora enumerar todas las direcciones de solo visualización que recibió usando el comando `getaddressesbylabel`. ¡Todas las 1000 direcciones de recepción están allí, en la billetera del `ledger`!
|
||||
```
|
||||
$ bitcoin-cli -rpcwallet=ledger getaddressesbylabel "" | more
|
||||
{
|
||||
"tb1qqqvnezljtmc9d7x52udpc0m9zgl9leugd2ur7y": {
|
||||
"purpose": "receive"
|
||||
},
|
||||
"tb1qqzvrm6hujdt93qctuuev5qc4499tq9fdk0prwf": {
|
||||
"purpose": "receive"
|
||||
},
|
||||
...
|
||||
}
|
||||
```
|
||||
## Reciba una Transacción
|
||||
|
||||
Obviamente, recibir una transacción es sencillo. Utilice `getnewaddress` para solicitar una de esas direcciones importadas:
|
||||
```
|
||||
$ bitcoin-cli -rpcwallet=ledger getnewaddress
|
||||
tb1qqqvnezljtmc9d7x52udpc0m9zgl9leugd2ur7y
|
||||
```
|
||||
Luego envíele dinero.
|
||||
|
||||
El poder de HWI es que puede ver los pagos desde su nodo Bitcoin Core, en lugar de tener que conectar su billetera de hardware y consultarlo.
|
||||
```
|
||||
$ bitcoin-cli -rpcwallet=ledger listunspent
|
||||
[
|
||||
{
|
||||
"txid": "c733533eb1c052242f9ed89cd8927aedb41852156e684634ee7c74028774e595",
|
||||
"vout": 1,
|
||||
"address": "tb1q948388a23pfsf52kz6skd5k4z4627jja2evztr",
|
||||
"label": "",
|
||||
"scriptPubKey": "00142d4f139faa885304d15616a166d2d51574af4a5d",
|
||||
"amount": 0.01000000,
|
||||
"confirmations": 12,
|
||||
"spendable": false,
|
||||
"solvable": true,
|
||||
"desc": "wpkh([9a1d520b/84'/1'/0'/0/0]02a013cf9c4b5f5689d9253036a3e477cf98689626f7814c94f092726f11b741ab)#9za8hlvk",
|
||||
"safe": true
|
||||
},
|
||||
{
|
||||
"txid": "5b3c4aeb811f9a119fd633b12a6927415cc61b8654628df58e9141cab804bab8",
|
||||
"vout": 0,
|
||||
"address": "tb1qqqvnezljtmc9d7x52udpc0m9zgl9leugd2ur7y",
|
||||
"label": "",
|
||||
"scriptPubKey": "001400193c8bf25ef056f8d4571a1c3f65123e5fe788",
|
||||
"amount": 0.01000000,
|
||||
"confirmations": 1,
|
||||
"spendable": false,
|
||||
"solvable": true,
|
||||
"desc": "wpkh([9a1d520b/84'/1'/0'/0/569]030168d9482e2b02d7027fb4a89edc54adaa1adf709334f647d0a1b0533828aec5)#sx9haake",
|
||||
"safe": true
|
||||
}
|
||||
]
|
||||
```
|
||||
## Cree una transacción con PSBT
|
||||
|
||||
Ver y recibir pagos es solo la mitad de la batalla. Es posible que también desee realizar pagos utilizando cuentas en su billetera de hardware. Este es el cuarto ejemplo de la vida real para el uso de PSBT, según el proceso descrito en [§7.1: Creando una Transacción Bitcoin Parcialmente Firmada](07_1_Creando_una_Transaccion_Bitcoin_Parcialmente_Firmada.md).
|
||||
|
||||
Los comandos funcionan exactamente igual. En este caso, use `walletcreatefundedpsbt` para formar su PSBT porque esta es una situación en la que no le importa qué UTXO se usan:
|
||||
```
|
||||
$ bitcoin-cli -named -rpcwallet=ledger walletcreatefundedpsbt inputs='''[]''' outputs='''[{"tb1qcaedd724gts3aug73m78c7nfsv9d8zs9q6h2kd":0.015}]'''
|
||||
{
|
||||
"psbt": "cHNidP8BAJoCAAAAAri6BLjKQZGO9Y1iVIYbxlxBJ2kqsTPWnxGaH4HrSjxbAAAAAAD+////leV0hwJ0fO40RmhuFVIYtO16ktic2J4vJFLAsT5TM8cBAAAAAP7///8CYOMWAAAAAAAWABTHctb5VULhHvEejvx8emmDCtOKBU+gBwAAAAAAFgAU9Ojd5ds3CJi1fIRWbj92CYhQgX0AAAAAAAEBH0BCDwAAAAAAFgAUABk8i/Je8Fb41FcaHD9lEj5f54giBgMBaNlILisC1wJ/tKie3FStqhrfcJM09kfQobBTOCiuxRiaHVILVAAAgAEAAIAAAACAAAAAADkCAAAAAQEfQEIPAAAAAAAWABQtTxOfqohTBNFWFqFm0tUVdK9KXSIGAqATz5xLX1aJ2SUwNqPkd8+YaJYm94FMlPCScm8Rt0GrGJodUgtUAACAAQAAgAAAAIAAAAAAAAAAAAAAIgID2UK1nupSfXC81nmB65XZ+pYlJp/W6wNk5FLt5ZCSx6kYmh1SC1QAAIABAACAAAAAgAEAAAABAAAAAA==",
|
||||
"fee": 0.00000209,
|
||||
"changepos": 1
|
||||
}
|
||||
```
|
||||
|
||||
Puede echar un vistazo al PSBT y verificar que parezca racional:
|
||||
```
|
||||
$ psbt="cHNidP8BAJoCAAAAAri6BLjKQZGO9Y1iVIYbxlxBJ2kqsTPWnxGaH4HrSjxbAAAAAAD+////leV0hwJ0fO40RmhuFVIYtO16ktic2J4vJFLAsT5TM8cBAAAAAP7///8CYOMWAAAAAAAWABTHctb5VULhHvEejvx8emmDCtOKBU+gBwAAAAAAFgAU9Ojd5ds3CJi1fIRWbj92CYhQgX0AAAAAAAEBH0BCDwAAAAAAFgAUABk8i/Je8Fb41FcaHD9lEj5f54giBgMBaNlILisC1wJ/tKie3FStqhrfcJM09kfQobBTOCiuxRiaHVILVAAAgAEAAIAAAACAAAAAADkCAAAAAQEfQEIPAAAAAAAWABQtTxOfqohTBNFWFqFm0tUVdK9KXSIGAqATz5xLX1aJ2SUwNqPkd8+YaJYm94FMlPCScm8Rt0GrGJodUgtUAACAAQAAgAAAAIAAAAAAAAAAAAAAIgID2UK1nupSfXC81nmB65XZ+pYlJp/W6wNk5FLt5ZCSx6kYmh1SC1QAAIABAACAAAAAgAEAAAABAAAAAA=="
|
||||
|
||||
$ bitcoin-cli decodepsbt $psbt
|
||||
{
|
||||
"tx": {
|
||||
"txid": "45f996d4ff8c9e9ab162f611c5b6ad752479ede9780f9903bdc80cd96619676d",
|
||||
"hash": "45f996d4ff8c9e9ab162f611c5b6ad752479ede9780f9903bdc80cd96619676d",
|
||||
"version": 2,
|
||||
"size": 154,
|
||||
"vsize": 154,
|
||||
"weight": 616,
|
||||
"locktime": 0,
|
||||
"vin": [
|
||||
{
|
||||
"txid": "5b3c4aeb811f9a119fd633b12a6927415cc61b8654628df58e9141cab804bab8",
|
||||
"vout": 0,
|
||||
"scriptSig": {
|
||||
"asm": "",
|
||||
"hex": ""
|
||||
},
|
||||
"sequence": 4294967294
|
||||
},
|
||||
{
|
||||
"txid": "c733533eb1c052242f9ed89cd8927aedb41852156e684634ee7c74028774e595",
|
||||
"vout": 1,
|
||||
"scriptSig": {
|
||||
"asm": "",
|
||||
"hex": ""
|
||||
},
|
||||
"sequence": 4294967294
|
||||
}
|
||||
],
|
||||
"vout": [
|
||||
{
|
||||
"value": 0.01500000,
|
||||
"n": 0,
|
||||
"scriptPubKey": {
|
||||
"asm": "0 c772d6f95542e11ef11e8efc7c7a69830ad38a05",
|
||||
"hex": "0014c772d6f95542e11ef11e8efc7c7a69830ad38a05",
|
||||
"reqSigs": 1,
|
||||
"type": "witness_v0_keyhash",
|
||||
"addresses": [
|
||||
"tb1qcaedd724gts3aug73m78c7nfsv9d8zs9q6h2kd"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"value": 0.00499791,
|
||||
"n": 1,
|
||||
"scriptPubKey": {
|
||||
"asm": "0 f4e8dde5db370898b57c84566e3f76098850817d",
|
||||
"hex": "0014f4e8dde5db370898b57c84566e3f76098850817d",
|
||||
"reqSigs": 1,
|
||||
"type": "witness_v0_keyhash",
|
||||
"addresses": [
|
||||
"tb1q7n5dmewmxuyf3dtus3txu0mkpxy9pqtacuprak"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"unknown": {
|
||||
},
|
||||
"inputs": [
|
||||
{
|
||||
"witness_utxo": {
|
||||
"amount": 0.01000000,
|
||||
"scriptPubKey": {
|
||||
"asm": "0 00193c8bf25ef056f8d4571a1c3f65123e5fe788",
|
||||
"hex": "001400193c8bf25ef056f8d4571a1c3f65123e5fe788",
|
||||
"type": "witness_v0_keyhash",
|
||||
"address": "tb1qqqvnezljtmc9d7x52udpc0m9zgl9leugd2ur7y"
|
||||
}
|
||||
},
|
||||
"bip32_derivs": [
|
||||
{
|
||||
"pubkey": "030168d9482e2b02d7027fb4a89edc54adaa1adf709334f647d0a1b0533828aec5",
|
||||
"master_fingerprint": "9a1d520b",
|
||||
"path": "m/84'/1'/0'/0/569"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"witness_utxo": {
|
||||
"amount": 0.01000000,
|
||||
"scriptPubKey": {
|
||||
"asm": "0 2d4f139faa885304d15616a166d2d51574af4a5d",
|
||||
"hex": "00142d4f139faa885304d15616a166d2d51574af4a5d",
|
||||
"type": "witness_v0_keyhash",
|
||||
"address": "tb1q948388a23pfsf52kz6skd5k4z4627jja2evztr"
|
||||
}
|
||||
},
|
||||
"bip32_derivs": [
|
||||
{
|
||||
"pubkey": "02a013cf9c4b5f5689d9253036a3e477cf98689626f7814c94f092726f11b741ab",
|
||||
"master_fingerprint": "9a1d520b",
|
||||
"path": "m/84'/1'/0'/0/0"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
},
|
||||
{
|
||||
"bip32_derivs": [
|
||||
{
|
||||
"pubkey": "03d942b59eea527d70bcd67981eb95d9fa9625269fd6eb0364e452ede59092c7a9",
|
||||
"master_fingerprint": "9a1d520b",
|
||||
"path": "m/84'/1'/0'/1/1"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"fee": 0.00000209
|
||||
}
|
||||
```
|
||||
Y como de costumbre, `analysepsbt` mostrará lo lejos que ha llegado:
|
||||
```
|
||||
$ bitcoin-cli analyzepsbt $psbt
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"has_utxo": true,
|
||||
"is_final": false,
|
||||
"next": "signer",
|
||||
"missing": {
|
||||
"signatures": [
|
||||
"00193c8bf25ef056f8d4571a1c3f65123e5fe788"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"has_utxo": true,
|
||||
"is_final": false,
|
||||
"next": "signer",
|
||||
"missing": {
|
||||
"signatures": [
|
||||
"2d4f139faa885304d15616a166d2d51574af4a5d"
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"estimated_vsize": 208,
|
||||
"estimated_feerate": 0.00001004,
|
||||
"fee": 0.00000209,
|
||||
"next": "signer"
|
||||
}
|
||||
```
|
||||
Debido a que importó ese conjunto de claves, `bitcoin-cli` tiene toda la información que necesita para completar las entradas, simplemente no puede firmar porque las claves privadas se guardan en la billetera de hardware.
|
||||
|
||||
Ahí es donde entra HWI, con el comando `signtx`. Simplemente envíe el PSBT:
|
||||
```
|
||||
$ hwi -f 9a1d520b signtx $psbt
|
||||
```
|
||||
Espere tener que jugar un poco con su billetera de hardware en este punto. El dispositivo probablemente le pedirá que confirme las entradas, las salidas y la tarifa. Cuando haya terminado, debería devolver un nuevo PSBT.
|
||||
|
||||
```
|
||||
{"psbt": "cHNidP8BAJoCAAAAAri6BLjKQZGO9Y1iVIYbxlxBJ2kqsTPWnxGaH4HrSjxbAAAAAAD+////leV0hwJ0fO40RmhuFVIYtO16ktic2J4vJFLAsT5TM8cBAAAAAP7///8CYOMWAAAAAAAWABTHctb5VULhHvEejvx8emmDCtOKBU+gBwAAAAAAFgAU9Ojd5ds3CJi1fIRWbj92CYhQgX0AAAAAAAEBH0BCDwAAAAAAFgAUABk8i/Je8Fb41FcaHD9lEj5f54giAgMBaNlILisC1wJ/tKie3FStqhrfcJM09kfQobBTOCiuxUcwRAIgAxkQlk2fqEMxvP54WWyiFhlfSul9sd4GzKDhfGpmlewCIHYej3zXWWMgWI6rixxQw9yzGozDaFPqQNNIvcFPk+lfASIGAwFo2UguKwLXAn+0qJ7cVK2qGt9wkzT2R9ChsFM4KK7FGJodUgtUAACAAQAAgAAAAIAAAAAAOQIAAAABAR9AQg8AAAAAABYAFC1PE5+qiFME0VYWoWbS1RV0r0pdIgICoBPPnEtfVonZJTA2o+R3z5holib3gUyU8JJybxG3QatHMEQCIH5t6T2yufUP7glYZ8YH0/PhDFpotSmjgZUhvj6GbCFIAiBcgXzyYl7IjYuaF3pJ7AgW1rLYkjeCJJ2M9pVUrq5vFwEiBgKgE8+cS19WidklMDaj5HfPmGiWJveBTJTwknJvEbdBqxiaHVILVAAAgAEAAIAAAACAAAAAAAAAAAAAACICA9lCtZ7qUn1wvNZ5geuV2fqWJSaf1usDZORS7eWQksepGJodUgtUAACAAQAAgAAAAIABAAAAAQAAAAA="}
|
||||
$ psbt_f="cHNidP8BAJoCAAAAAri6BLjKQZGO9Y1iVIYbxlxBJ2kqsTPWnxGaH4HrSjxbAAAAAAD+////leV0hwJ0fO40RmhuFVIYtO16ktic2J4vJFLAsT5TM8cBAAAAAP7///8CYOMWAAAAAAAWABTHctb5VULhHvEejvx8emmDCtOKBU+gBwAAAAAAFgAU9Ojd5ds3CJi1fIRWbj92CYhQgX0AAAAAAAEBH0BCDwAAAAAAFgAUABk8i/Je8Fb41FcaHD9lEj5f54giAgMBaNlILisC1wJ/tKie3FStqhrfcJM09kfQobBTOCiuxUcwRAIgAxkQlk2fqEMxvP54WWyiFhlfSul9sd4GzKDhfGpmlewCIHYej3zXWWMgWI6rixxQw9yzGozDaFPqQNNIvcFPk+lfASIGAwFo2UguKwLXAn+0qJ7cVK2qGt9wkzT2R9ChsFM4KK7FGJodUgtUAACAAQAAgAAAAIAAAAAAOQIAAAABAR9AQg8AAAAAABYAFC1PE5+qiFME0VYWoWbS1RV0r0pdIgICoBPPnEtfVonZJTA2o+R3z5holib3gUyU8JJybxG3QatHMEQCIH5t6T2yufUP7glYZ8YH0/PhDFpotSmjgZUhvj6GbCFIAiBcgXzyYl7IjYuaF3pJ7AgW1rLYkjeCJJ2M9pVUrq5vFwEiBgKgE8+cS19WidklMDaj5HfPmGiWJveBTJTwknJvEbdBqxiaHVILVAAAgAEAAIAAAACAAAAAAAAAAAAAACICA9lCtZ7qUn1wvNZ5geuV2fqWJSaf1usDZORS7eWQksepGJodUgtUAACAAQAAgAAAAIABAAAAAQAAAAA="
|
||||
```
|
||||
|
||||
Cuando analice esto, verá que está listo para finalizar:
|
||||
```
|
||||
$ bitcoin-cli analyzepsbt $psbt_f
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"has_utxo": true,
|
||||
"is_final": false,
|
||||
"next": "finalizer"
|
||||
},
|
||||
{
|
||||
"has_utxo": true,
|
||||
"is_final": false,
|
||||
"next": "finalizer"
|
||||
}
|
||||
],
|
||||
"estimated_vsize": 208,
|
||||
"estimated_feerate": 0.00001004,
|
||||
"fee": 0.00000209,
|
||||
"next": "finalizer"
|
||||
}
|
||||
```
|
||||
|
||||
En este punto, regresa al territorio estándar:
|
||||
```
|
||||
$ bitcoin-cli finalizepsbt $psbt_f
|
||||
{
|
||||
"hex": "02000000000102b8ba04b8ca41918ef58d6254861bc65c4127692ab133d69f119a1f81eb4a3c5b0000000000feffffff95e5748702747cee3446686e155218b4ed7a92d89cd89e2f2452c0b13e5333c70100000000feffffff0260e3160000000000160014c772d6f95542e11ef11e8efc7c7a69830ad38a054fa0070000000000160014f4e8dde5db370898b57c84566e3f76098850817d024730440220031910964d9fa84331bcfe78596ca216195f4ae97db1de06cca0e17c6a6695ec0220761e8f7cd7596320588eab8b1c50c3dcb31a8cc36853ea40d348bdc14f93e95f0121030168d9482e2b02d7027fb4a89edc54adaa1adf709334f647d0a1b0533828aec50247304402207e6de93db2b9f50fee095867c607d3f3e10c5a68b529a3819521be3e866c214802205c817cf2625ec88d8b9a177a49ec0816d6b2d8923782249d8cf69554aeae6f17012102a013cf9c4b5f5689d9253036a3e477cf98689626f7814c94f092726f11b741ab00000000",
|
||||
"complete": true
|
||||
}
|
||||
$ hex=02000000000102b8ba04b8ca41918ef58d6254861bc65c4127692ab133d69f119a1f81eb4a3c5b0000000000feffffff95e5748702747cee3446686e155218b4ed7a92d89cd89e2f2452c0b13e5333c70100000000feffffff0260e3160000000000160014c772d6f95542e11ef11e8efc7c7a69830ad38a054fa0070000000000160014f4e8dde5db370898b57c84566e3f76098850817d024730440220031910964d9fa84331bcfe78596ca216195f4ae97db1de06cca0e17c6a6695ec0220761e8f7cd7596320588eab8b1c50c3dcb31a8cc36853ea40d348bdc14f93e95f0121030168d9482e2b02d7027fb4a89edc54adaa1adf709334f647d0a1b0533828aec50247304402207e6de93db2b9f50fee095867c607d3f3e10c5a68b529a3819521be3e866c214802205c817cf2625ec88d8b9a177a49ec0816d6b2d8923782249d8cf69554aeae6f17012102a013cf9c4b5f5689d9253036a3e477cf98689626f7814c94f092726f11b741ab00000000
|
||||
$ bitcoin-cli sendrawtransaction $hex
|
||||
45f996d4ff8c9e9ab162f611c5b6ad752479ede9780f9903bdc80cd96619676d
|
||||
```
|
||||
¡Ha enviado fondos con éxito utilizando las claves privadas guardadas en su billetera de hardware!
|
||||
|
||||
## Aprenda otros comandos HWI
|
||||
|
||||
Hay una variedad de otros comandos disponibles para usar con HWI. En el momento de escribir este artículo, son:
|
||||
```
|
||||
numerate,getmasterxpub,signtx,getxpub,signmessage,getkeypool,getdescriptors,displayaddress,setup,wipe,restore,backup,promptpin,togglepassphrase,sendpin
|
||||
```
|
||||
|
||||
## Resumen: integración con billeteras de hardware
|
||||
Las billeteras de hardware pueden ofrecer una mejor protección al mantener sus claves privadas fuera de línea, protegidas en el hardware. Afortunadamente, todavía hay una forma de interactuar con ellos usando `bitcoin-cli`. Simplemente instale HWI y luego le permitirá (1) importar claves públicas para verlas; y (2) firmar transacciones usando su billetera de hardware.
|
||||
|
||||
> :fire: ***¿Cuál es el poder de HWI?*** HWI le permite interactuar con billeteras de hardware utilizando todos los comandos de `bitcoin-cli` que ha aprendido hasta la fecha. Puede realizar transacciones sin procesar de cualquier tipo y luego enviar PSBT a billeteras de hardware para firmar. Por lo tanto, tiene todo el poder de Bitcoin Core, pero también tiene la seguridad de un dispositivo de hardware.
|
||||
|
||||
## ¿Que sigue?
|
||||
|
||||
Expanda más las transacciones de Bitcoin con el [Capítulo ocho: Expandiendo Transacciones Bitcoin en Otros Sentidos](08_0_Expandiendo_Bitcoin_Transacciones_Otros.md) .
|
21
es/08_0_Expandiendo_Bitcoin_Transacciones_Otros.md
Normal file
21
es/08_0_Expandiendo_Bitcoin_Transacciones_Otros.md
Normal file
@ -0,0 +1,21 @@
|
||||
# Capítulo ocho: Expandiendo las transacciones de Bitcoin de otras formas
|
||||
|
||||
En la definición de transacciones básicas en el [Capítulo Seis](06_0_Expandiendo_las_Transacciones_Bitcoin_con_Multifirmas.md) se comentó que se enviaron _fondos_ _inmediatamente_, sin embargo ambos son elementos que se pueden cambiar. Esta sección final sobre la expansión de las transacciones de Bitcoin habla sobre cómo enviar cosas que no sean dinero en efectivo y cómo hacerlo en otro momento que no sea ahora.
|
||||
|
||||
## Objetivos de esta sección
|
||||
|
||||
Después de trabajar en este capítulo, un desarrollador podrá:
|
||||
|
||||
* Crear transacciones con tiempos de bloqueo
|
||||
* Crear transacciones con datos
|
||||
|
||||
Los objetivos de apoyo incluyen la capacidad de:
|
||||
|
||||
* Comprender los diferentes tipos de bloqueos de tiempo
|
||||
* Planificar para el poder del bloqueo de tiempo
|
||||
* Planificar para el poder de OP_RETURN
|
||||
|
||||
## Tabla de contenido
|
||||
|
||||
* [Sección uno: Enviando una transacción con bloqueo de tiempo](08_1_Enviando_una_Transaccion_con_Bloqueo_de_Tiempo.md)
|
||||
* [Sección dos: Enviando una transacción con datos](08_2_Enviando_una_Transaccion_con_Datos.md)
|
139
es/08_1_Enviando_una_Transaccion_con_Bloqueo_de_Tiempo.md
Normal file
139
es/08_1_Enviando_una_Transaccion_con_Bloqueo_de_Tiempo.md
Normal file
@ -0,0 +1,139 @@
|
||||
# 8.1: Enviando una transacción con un tiempo de bloqueo
|
||||
|
||||
Los capítulos anteriores mostraron dos formas diferentes de enviar fondos desde múltiples máquinas y a múltiples destinatarios. Pero hay otras dos formas de cambiar fundamentalmente las transacciones básicas. El primero de ellos es variar el tiempo eligiendo un tiempo de bloqueo. Esto le brinda la posibilidad de enviar transacciones sin procesar en algún momento en el futuro.
|
||||
|
||||
## Entender como funcionan los bloqueos de tiempo
|
||||
|
||||
Cuando crea una transacción de tiempo de bloqueo, la bloquea con un número que representa la altura de un bloque (si es un número pequeño) o una marca de tiempo UNIX (si es un número grande). Esto le dice a la red Bitcoin que la transacción no se puede poner en un bloque hasta que haya llegado la hora especificada o la cadena de bloques haya alcanzado la altura especificada.
|
||||
|
||||
>:book: _¿Que es la altura de bloque?_ Es el recuento total de bloques en la cadena, remontandose al bloque génesis de Bitcoin.
|
||||
|
||||
Cuando una transacción con tiempo de bloqueo está esperando para entrar en un bloque, se puede cancelar. Esto significa que está lejos, lejos de estar finalizada. De hecho, la capacidad de cancelar es el objetivo principal de una transacción con tiempo de bloqueo.
|
||||
|
||||
>:book: _¿Qué es un bloqueo de tiempo?_ Es lo mismo que un tiempo de bloqueo. Más específicamente, es lo que se denomina tiempo de bloqueo interno al código fuente de Bitcoin Core.
|
||||
|
||||
>:book: _¿Qué es Timelock?_ Locktime es solo una forma de bloquear las transacciones de Bitcoin hasta algún momento en el futuro; colectivamente, estos métodos se denominan bloqueos de tiempo. Locktime es el método de bloqueo de tiempo más básico. Bloquea una transacción completa con un tiempo absoluto, y está disponible a través de `bitcoin-cli` (por lo que es el único bloqueo de tiempo cubierto en esta sección). Un método paralelo, que bloquea una transacción con un tiempo relativo, se define en [BIP 68](https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki) y se cubre en [§11.3: Usando CSV en Scripts](11_3_Usando_CSV_en_Scripts.md).
|
||||
|
||||
> El lenguaje de Script de Bitcoin potencia aún más ambos tipos de bloqueos de tiempo, lo que permite el bloqueo de salidas individuales en lugar de transacciones completas. Los bloqueos de tiempo absolutos (como Locktime) están vinculados al código de operación de script OP_CHECKLOCKTIMEVERIFY, que se define en [BIP 65](https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki) y se cubre en [11.2: Usando CLTV en Scripts](11_2_Usando_CLTV_en_Scripts.md), mientras que los temporizadores relativos (como Timelock) están vinculados al código de operación de script OP_CHECKSEQUENCEVERIFY, que se define en [BIP 112](https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki) y también está cubierto en [§11.3](11_3_Usando_CSV_en_Scripts.md).
|
||||
|
||||
## ## Cree una transacción Locktime
|
||||
|
||||
Para crear una transacción de tiempo de bloqueo, primero debe determinar en qué establecerá el tiempo de bloqueo.
|
||||
|
||||
### Determine su tiempo de bloqueo por marca de tiempo UNIX
|
||||
|
||||
Con mayor frecuencia, establecerá el tiempo de bloqueo en una marca de tiempo de UNIX que representa una fecha y hora específicas. Puede calcular una marca de tiempo de UNIX en un sitio web tal como [Sello de tiempo de UNIX](http://www.unixtimestamp.com/) o en [Epoch Convertor](https://www.epochconverter.com/). Sin embargo, sería mejor [escribir su propio script](https://www.epochconverter.com/#code) en su máquina local, para que sepa que la marca de tiempo UNIX que recibe es precisa. Si no lo hace, al menos verifique dos veces en dos sitios diferentes.
|
||||
|
||||
>:book: _¿Por qué debería usar una marca de tiempo de UNIX?_ El uso de una marca de tiempo de UNIX facilita la vinculación definitiva de una transacción
|
||||
>a un momento específico, sin preocuparse por si la velocidad de creación de bloques podría cambiar en algún momento. En particular, si está creando un
|
||||
>tiempo de bloqueo que está muy alejado en el futuro, es lo más seguro que puede hacer. Pero, más allá de eso, es más intuitivo, ya que crea una
|
||||
>correlación directa entre alguna fecha del calendario y el momento en que se puede extraer la transacción.
|
||||
|
||||
>:warning: **ADVERTENCIA:** El tiempo de bloqueo con marcas de tiempo de UNIX tiene poco margen de maniobra: la liberación de bloques no es regular y los tiempos de bloqueo pueden adelantarse dos horas al tiempo real, por lo que un tiempo de bloqueo en realidad significa "dentro de unas pocos horas de este tiempo, más o menos".
|
||||
|
||||
### Calcule su tiempo de bloqueo por altura de bloque
|
||||
|
||||
Alternativamente, puede establecer el tiempo de bloqueo en un número más pequeño que represente la altura de un bloque. Para calcular la altura futura de su bloque, primero debe saber cuál es la altura actual del bloque. `bitcoin-cli getblockcount` le dirá cuál piensa su máquina local que es la altura del bloque. Es posible que desee volver a verificar con un explorador de Bitcoin.
|
||||
|
||||
Una vez que haya descubierto la altura actual, puede decidir qué tan lejos en el futuro establecerá su tiempo de bloqueo. Recuerde que, en promedio, se creará un nuevo bloque cada 10 minutos. Entonces, por ejemplo, si quisiera establecer el tiempo de bloqueo en una semana en el futuro, elegiría una altura de bloque de 6 x 24 x 7 = 1,008 bloques por delante que la actual.
|
||||
|
||||
>:book: _¿Por qué debería usar una altura de bloque?_ A diferencia de las marcas de tiempo, no hay confusión para las alturas de bloque. Si establece una altura de bloque de 120,000 para su tiempo de bloqueo, entonces no hay absolutamente ninguna forma de que entre en el bloque 119,999. Esto puede facilitar el control algorítmico de su transacción bloqueada. La desventaja es que no puede estar tan seguro de cuándo será exactamente el tiempo de bloqueo.
|
||||
|
||||
>:advertencia: ** ADVERTENCIA: ** Si desea establecer un tiempo de bloqueo de altura de bloque, debe establecer el tiempo de bloqueo en menos de 500 millones. Si lo establece en 500 millones o más, su número se interpretará como una marca de tiempo. Dado que la marca de tiempo de UNIX de 500 millones fue el 5 de noviembre de 1985, eso probablemente significa que su transacción será puesta en un bloque en la primera oportunidad de los mineros.
|
||||
|
||||
## Escriba su transacción
|
||||
|
||||
Una vez que haya descubierto su tiempo de bloqueo, todo lo que necesita hacer es escribir una transacción en crudo, con una tercera variable para `locktime`:
|
||||
|
||||
```
|
||||
$ rawtxhex=$(bitcoin-cli -named createrawtransaction inputs='''[ { "txid": "'$utxo_txid'", "vout": '$utxo_vout' } ]''' outputs='''{ "'$recipient'": 0.001, "'$changeaddress'": 0.00095 }''' locktime=1774650)
|
||||
```
|
||||
Tenga en cuenta que este uso de `locktime` es inferior a 500 millones, lo que significa que define una altura de bloque. En este caso, son solo unos pocos bloques más allá de la altura del bloque actual en el momento de escribir este artículo, con la intención de ejemplificar cómo funciona el tiempo de bloqueo sin sentarse durante mucho tiempo para esperar y ver qué sucede.
|
||||
|
||||
Así es como se ve la transacción creada:
|
||||
|
||||
```
|
||||
$ bitcoin-cli -named decoderawtransaction hexstring=$rawtxhex
|
||||
{
|
||||
"txid": "ba440b1dd87a7ccb6a200f087d2265992588284eed0ae455d0672aeb918cf71e",
|
||||
"hash": "ba440b1dd87a7ccb6a200f087d2265992588284eed0ae455d0672aeb918cf71e",
|
||||
"version": 2,
|
||||
"size": 113,
|
||||
"vsize": 113,
|
||||
"weight": 452,
|
||||
"locktime": 1774650,
|
||||
"vin": [
|
||||
{
|
||||
"txid": "0ad9fb6992dfe4ea90236b69852b3605c0175633b32996a486dcd0b2e739e385",
|
||||
"vout": 1,
|
||||
"scriptSig": {
|
||||
"asm": "",
|
||||
"hex": ""
|
||||
},
|
||||
"sequence": 4294967294
|
||||
}
|
||||
],
|
||||
"vout": [
|
||||
{
|
||||
"value": 0.00100000,
|
||||
"n": 0,
|
||||
"scriptPubKey": {
|
||||
"asm": "0 f333554cc0830d03a9c1f26758e2e7e0f155539f",
|
||||
"hex": "0014f333554cc0830d03a9c1f26758e2e7e0f155539f",
|
||||
"reqSigs": 1,
|
||||
"type": "witness_v0_keyhash",
|
||||
"addresses": [
|
||||
"tb1q7ve42nxqsvxs82wp7fn43ch8urc425ul5um4un"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"value": 0.00095000,
|
||||
"n": 1,
|
||||
"scriptPubKey": {
|
||||
"asm": "0 a37718a3510958112b6a766e0023ff251b6c2bfb",
|
||||
"hex": "0014a37718a3510958112b6a766e0023ff251b6c2bfb",
|
||||
"reqSigs": 1,
|
||||
"type": "witness_v0_keyhash",
|
||||
"addresses": [
|
||||
"tb1q5dm33g63p9vpz2m2wehqqglly5dkc2lmtmr98d"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
Tenga en cuenta que el número de secuencia (`4294967294`) es menor que` 0xffffffff`. Esta es una señalización necesaria para mostrar que la transacción incluye un tiempo de bloqueo. También lo hace automáticamente `bitcoin-cli`. Si, en cambio, el número de secuencia se establece en `0xffffffff`, se ignorará el tiempo de bloqueo.
|
||||
|
||||
>:information_source: **NOTA - SECUENCIA:** Este es el segundo uso del valor `nSequence` en Bitcoin. Al igual que con RBF, `nSequence` se usa nuevamente como opción de suscripción, esta vez para el uso del tiempo de bloqueo. 0xffffffff-1 (4294967294) es el valor preferido para señalar el tiempo de bloqueo porque intencionalmente no permite el uso de RBF (que requiere `nSequence < 0xffffffff-1`) y bloqueo de tiempo relativo (que requiere` nSequence < 0xf0000000`), los otros dos usos del valor `nSequence`. Si configura `nSequence` por debajo de `0xf0000000`, entonces también bloqueará con un tiempo relativo su transacción, que probablemente no sea lo que desea.
|
||||
|
||||
>:warning: ** ADVERTENCIA: ** Si está creando una transacción sin procesar de tiempo de bloqueo por algún otro medio que no sea `bitcoin-cli`, tendrá que establecer la secuencia a menos de `0xffffffff` a mano.
|
||||
|
||||
A estas alturas probablemente ya esté familiarizado con terminar las cosas:
|
||||
```
|
||||
$ signedtx=$(bitcoin-cli -named signrawtransactionwithwallet hexstring=$rawtxhex | jq -r '.hex')
|
||||
$ bitcoin-cli -named sendrawtransaction hexstring=$signedtx
|
||||
error code: -26
|
||||
error message:
|
||||
non-final
|
||||
```
|
||||
|
||||
¡Ups! ¿¡Qué error es ese!?
|
||||
|
||||
Desde 2013, generalmente no puede colocar la transacción bloqueada por tiempo en el mempool hasta que su bloqueo haya expirado. Sin embargo, aún puede retener la transacción, reenviéndola ocasionalmente a la red Bitcoin hasta que sea aceptada en el mempool. Alternativamente, puede enviar la transacción firmada (`$signedtx`) al destinatario, para que pueda colocarla en el mempool cuando el tiempo de bloqueo haya expirado.
|
||||
|
||||
Una vez transcurrido el tiempo de bloqueo, cualquiera puede enviar esa transacción firmada a la red, y el destinatario recibirá el dinero según lo previsto ... siempre que la transacción no se haya cancelado.
|
||||
|
||||
## Cancelar una transacción de Locktime
|
||||
|
||||
Cancelar una transacción de tiempo de bloqueo es _muy_ simple: envía una nueva transacción utilizando al menos una de las mismas UTXO.
|
||||
|
||||
## Resumen: Enviando una transacción con un tiempo de bloqueo
|
||||
|
||||
Locktime ofrece una forma de crear una transacción que _debería_ no ser retransmitida a la red y que _no será_ aceptada en un bloque hasta que llegue el momento apropiado. Mientras tanto, se puede cancelar simplemente reutilizando un UTXO.
|
||||
|
||||
>:fire: _¿Cuál es el poder del tiempo de bloqueo?_ El poder del tiempo de bloqueo puede no ser inmediatamente obvio debido a la capacidad de cancelarlo tan fácilmente. Sin embargo, es otra de las bases de los contratos inteligentes: tienen mucha utilidad en una variedad de aplicaciones de custodia o contractuales. Por ejemplo, considere una situación en la que un tercero tiene sus bitcoins. Para garantizar la devolución de sus bitcoins si el custodio alguna vez desapareciera, podrían producir una transacción de bloqueo de tiempo para devolverle las monedas y luego actualizarlas de vez en cuando con una nueva, en el futuro. Si alguna vez no se actualizaran, las monedas le regresarían cuando expirara el bloqueo de tiempo actual. El tiempo de bloqueo podría aplicarse de manera similar a una red de pago, donde la red contiene monedas mientras los participantes de la red las intercambian. Finalmente, un testamento ofrece un ejemplo de un contrato más complejo, en el que los pagos se envían a varias personas. Estos pagos se basarían en transacciones de tiempo de bloqueo y se actualizarían continuamente siempre que el propietario continúe mostrando signos de vida. (El factor unificador de todas estas aplicaciones es por supuesto, la _confianza_. Las transacciones simples de tiempo de bloqueo solo funcionan si se puede confiar en que el poseedor de las monedas las enviará en las condiciones adecuadas).
|
||||
|
||||
## ¿Que sigue?
|
||||
|
||||
Continúe "Expandiendo transacciones de Bitcoin" con [§8.2: Enviando una Transacción con Datos](08_2_Enviando_una_Transaccion_con_Datos.md).
|
125
es/08_2_Enviando_una_Transaccion_con_Datos.md
Normal file
125
es/08_2_Enviando_una_Transaccion_con_Datos.md
Normal file
@ -0,0 +1,125 @@
|
||||
# 8.2: Enviando una transacción con datos
|
||||
|
||||
En esta última forma para variar la manera en que envia una transacción básica es usar la transacción para enviar datos en lugar de fondos (o en realidad, además de fondos). Esto le brinda la capacidad de incrustar información en la cadena de bloques. Se realiza mediante un comando especial `OP_RETURN`.
|
||||
|
||||
¿El truco? Solo puede almacenar 80 bytes a la vez!
|
||||
|
||||
## Cree sus datos.
|
||||
|
||||
Lo primero que debe hacer es crear los 80 bytes (o menos) de datos que grabará en su `OP_RETURN`. Esto puede ser tan simple como preparar un mensaje o puede estar usando el "hash" de datos existentes. Por ejemplo, `sha256sum` produce 256 bits de datos, que son 32 bytes, muy por debajo de los límites:
|
||||
|
||||
```
|
||||
$ sha256sum contract.jpg
|
||||
b9f81a8919e5aba39aeb86145c684010e6e559b580a85003ae25d78237a12e75 contract.jpg
|
||||
$ op_return_data="b9f81a8919e5aba39aeb86145c684010e6e559b580a85003ae25d78237a12e75"
|
||||
```
|
||||
>:book: _¿Qué es un OP_RETURN?_ Todas las transacciones de Bitcoin se basan en scripts de código opcode que veremos en el próximo capítulo. El `OP_RETURN` es un código de operación simple que define una SALIDA como inválida. La convención ha dado como resultado que se utilice para incrustar datos en la cadena de bloques.
|
||||
|
||||
|
||||
## Prepare algún dinero
|
||||
|
||||
Su propósito al crear una transacción de datos no es enviar dinero a nadie, es poner datos en la cadena de bloques. Sin embargo, _debe_ enviar dinero para hacerlo. Solo necesita usar una dirección de cambio como su _único_ destinatario. Luego, puede identificar un UTXO y enviarlo a su dirección de cambio, menos una tarifa de transacción, mientras usa la misma transacción para crear un OP_RETURN.
|
||||
|
||||
Aquí está la configuración estándar:
|
||||
```
|
||||
$ bitcoin-cli listunspent
|
||||
[
|
||||
{
|
||||
"txid": "854a833b667049ac811b4cf1cad40fa7f8dce8b0f4c1018a58b84559b6e05f42",
|
||||
"vout": 0,
|
||||
"address": "tb1q6kgsjxuqwj3rwhkenpdfcjccalk06st9z0k0kh",
|
||||
"scriptPubKey": "0014d591091b8074a2375ed9985a9c4b18efecfd4165",
|
||||
"amount": 0.01463400,
|
||||
"confirmations": 1392,
|
||||
"spendable": true,
|
||||
"solvable": true,
|
||||
"desc": "wpkh([d6043800/0'/1'/12']02883bb5463e37d55252d8b3d5c2141b007b37c8a7db6211f75c955acc5ea325eb)#cjr03mru",
|
||||
"safe": true
|
||||
}
|
||||
]
|
||||
|
||||
$ utxo_txid=$(bitcoin-cli listunspent | jq -r '.[0] | .txid')
|
||||
$ utxo_vout=$(bitcoin-cli listunspent | jq -r '.[0] | .vout')
|
||||
$ changeaddress=$(bitcoin-cli getrawchangeaddress)
|
||||
```
|
||||
|
||||
## Escriba la transacción sin procesar
|
||||
|
||||
Ahora puede escribir una nueva transacción sin procesar con dos salidas: una es su dirección de cambio para recuperar (la mayor parte) de su dinero, la otra es una dirección de datos, que es el término `bitcoin-cli` para un OP_RETURN.
|
||||
|
||||
```
|
||||
rawtxhex=$(bitcoin-cli -named createrawtransaction inputs='''[ { "txid": "'$utxo_txid'", "vout": '$utxo_vout' } ]''' outputs='''{ "data": "'$op_return_data'", "'$changeaddress'": 0.0146 }''')
|
||||
```
|
||||
|
||||
Así es como se ve realmente esa transacción:
|
||||
```
|
||||
{
|
||||
"txid": "a600148ac3b05f0c774b8687a71c545077ea5dfb9677e5c6d708215053d892e8",
|
||||
"hash": "a600148ac3b05f0c774b8687a71c545077ea5dfb9677e5c6d708215053d892e8",
|
||||
"version": 2,
|
||||
"size": 125,
|
||||
"vsize": 125,
|
||||
"weight": 500,
|
||||
"locktime": 0,
|
||||
"vin": [
|
||||
{
|
||||
"txid": "854a833b667049ac811b4cf1cad40fa7f8dce8b0f4c1018a58b84559b6e05f42",
|
||||
"vout": 0,
|
||||
"scriptSig": {
|
||||
"asm": "",
|
||||
"hex": ""
|
||||
},
|
||||
"sequence": 4294967295
|
||||
}
|
||||
],
|
||||
"vout": [
|
||||
{
|
||||
"value": 0.00000000,
|
||||
"n": 0,
|
||||
"scriptPubKey": {
|
||||
"asm": "OP_RETURN b9f81a8919e5aba39aeb86145c684010e6e559b580a85003ae25d78237a12e75",
|
||||
"hex": "6a20b9f81a8919e5aba39aeb86145c684010e6e559b580a85003ae25d78237a12e75",
|
||||
"type": "nulldata"
|
||||
}
|
||||
},
|
||||
{
|
||||
"value": 0.01460000,
|
||||
"n": 1,
|
||||
"scriptPubKey": {
|
||||
"asm": "0 998a9b0ed076bbdec1d88da4f475b9dde75e3620",
|
||||
"hex": "0014998a9b0ed076bbdec1d88da4f475b9dde75e3620",
|
||||
"reqSigs": 1,
|
||||
"type": "witness_v0_keyhash",
|
||||
"addresses": [
|
||||
"tb1qnx9fkrksw6aaaswc3kj0gademhn4ud3q7cz4fm"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
```
|
||||
Como puede ver, esto envía la mayor parte del dinero directamente a la dirección de cambio (`tb1qnx9fkrksw6aaaswc3kj0gademhn4ud3q7cz4fm`) menos una pequeña tarifa de transacción. Más importante aún, la primera salida muestra un OP_RETURN con los datos (`b9f81a8919e5aba39aeb86145c684010e6e559b580a85003ae25d78237a12e75`) inmediatamente después.
|
||||
|
||||
## Envie la transacción sin procesar
|
||||
|
||||
Firme su transacción sin procesar y envíela, así muy pronto dicho OP_RETURN se integrará en la cadena de bloques!
|
||||
|
||||
## Verifique su OP_RETURN
|
||||
|
||||
Nuevamente, recuerde que puede ver esta transacción usando un explorador de cadena de bloques:
|
||||
[https://live.blockcypher.com/btc-testnet/tx/a600148ac3b05f0c774b8687a71c545077ea5dfb9677e5c6d708215053d892e8/](https://live.blockcypher.com/btc-testnet/tx/a600148ac3b05f0c774b8687a71c545077ea5dfb9677e5c6d708215053d892e8/)
|
||||
|
||||
Es posible que observe una advertencia sobre los datos que se encuentran en un "protocolo desconocido". Si estuviera diseñando un uso regular de datos OP_RETURN, probablemente lo marcaría con un prefijo especial para marcar ese protocolo. Entonces, los datos reales de OP_RETURN podrían ser algo así como "CONTRACTS3b110a164aa18d3a5ab064ba93fdce62". Este ejemplo no usó un prefijo para evitar enturbiar el espacio de datos.
|
||||
|
||||
## Resumen: Enviando una transacción con datos
|
||||
|
||||
Puede usar un opcode OP_RETURN para almacenar hasta 80 bytes de datos en la cadena de bloques. Haz esto con la palabra `data` en clave para una salida `vout`. También debe enviar dinero, pero simplemente devuélvalo a una dirección de cambio, menos una tarifa de transacción.
|
||||
|
||||
>:fire: ¿Cuál es el poder de OP_RETURN? El OP_RETURN abre posibilidades completamente nuevas para la cadena de bloques, porque puede incrustar datos que prueben que ciertas cosas sucedieron en ciertos momentos. Varias organizaciones han utilizado OP_RETURN como prueba de existencia, derechos de autor, monedas de colores y [otros fines](https://en.bitcoin.it/wiki/OP_RETURN). Aunque 80 bytes pueden parecer pocos datos, puede ser bastante efectivos si se utiliza OP_RETURN para almacenar hashes de los datos reales. Luego, puede probar la existencia de sus datos digitales demostrando que el hash coincide con el hash en la cadena de bloques.
|
||||
|
||||
Tenga en cuenta que existe cierta controversia sobre el uso de la cadena de bloques de Bitcoin de esta manera.
|
||||
|
||||
## ¿Que sigue?
|
||||
|
||||
Pase a "Codificar con Bitcoin" en [Capítulo nueve: Introduciendo Bitcoin Scripts](09_0_Introduciendo_Bitcoin_Scripts.md).
|
27
es/09_0_Introduciendo_Bitcoin_Scripts.md
Normal file
27
es/09_0_Introduciendo_Bitcoin_Scripts.md
Normal file
@ -0,0 +1,27 @@
|
||||
# Capítulo 9: Introduciendo Bitcoin Scripts
|
||||
|
||||
Hasta la fecha, hemos estado interactuando con Bitcoin a un nivel de abstracción relativamente alto. El programa `bitcoin-cli` ofrece acceso a una variedad de comandos RPC que admiten la creación y el control de transacciones de Bitcoin sin procesar que incluyen fondos, datos, bloqueos de tiempo y multisigs.
|
||||
|
||||
Sin embargo, Bitcoin ofrece mucha más complejidad que eso. Incluye un lenguaje de programación simple que se puede utilizar para crear condiciones de canje aún más complejas. Si las multifirma y los bloqueos de tiempo proporcionaron las bases de los contratos inteligentes, entonces Bitcoin Script se cimienta en esa base. Es el siguiente paso para empoderar a Bitcoin.
|
||||
|
||||
## Objetivos de este capítulo
|
||||
|
||||
Después de trabajar en este capítulo, un desarrollador podrá:
|
||||
|
||||
* Diseñar un script de Bitcoin
|
||||
* Aplicar un script de Bitcoin
|
||||
|
||||
Los objetivos de apoyo incluyen la capacidad de:
|
||||
|
||||
* Comprender el propósito de los scripts de Bitcoin
|
||||
* Comprender el script P2PKH
|
||||
* Comprender cómo funciona P2WPKH con secuencias de comandos
|
||||
* Comprender las necesidades de las pruebas de scripts de Bitcoin
|
||||
|
||||
## Tabla de contenido
|
||||
|
||||
* [Sección uno: Entendiendo la base de las transacciones](09_1_Entendiendo_la_Base_de_las_Transacciones.md)
|
||||
* [Sección dos: Ejecución de un script de Bitcoin](09_2_Ejecutando_un_Script_Bitcoin.md)
|
||||
* [Sección tres: Probando un Script Bitcoin](09_3_Probando_un_Script_Bitcoin.md)
|
||||
* [Sección cuatro: Codificando una P2PKH](09_4_Codificando_una_P2PKH.md)
|
||||
* [Sección cinco: Codificando una P2WPKH](09_5_Codificando_una_P2WPKH.md)
|
153
es/09_1_Entendiendo_la_Base_de_las_Transacciones.md
Normal file
153
es/09_1_Entendiendo_la_Base_de_las_Transacciones.md
Normal file
@ -0,0 +1,153 @@
|
||||
# 9.1: Entendiendo la base de las transacciones
|
||||
|
||||
La base de Bitcoin es la capacidad de proteger las transacciones, algo que se hace con un lenguaje de programación simple.
|
||||
|
||||
## Conozca las partes del rompecabezas criptográfico
|
||||
|
||||
Como se describe en el [Capítulo 1](01_0_Introduccion.md), los fondos en cada transacción de Bitcoin están bloqueados con un rompecabezas criptográfico. Para ser precisos, dijimos que Bitcoin se compone de "una secuencia de transacciones atómicas". Observamos que: "Cada transacción es autenticada por un remitente con la solución a un rompecabezas criptográfico anterior que se almacenó como un script. La nueva transacción está bloqueada para el destinatario con un nuevo rompecabezas criptográfico que también se almacena como un script". Esos scripts, que bloquean y desbloquean transacciones, están escritos en Bitcoin Script.
|
||||
|
||||
>:book: ***¿Qué es Bitcoin Script?*** Bitcoin Script es un lenguaje similar a Forth basado en pilas que evita los bucles a propósito y, por lo tanto, no es Turing completo. Se compone de códigos de operación individuales. Cada transacción en Bitcoin está bloqueada con un script de Bitcoin; cuando la transacción de bloqueo para un UTXO se ejecuta con las entradas correctas, ese UTXO se puede gastar.
|
||||
|
||||
El hecho de que las transacciones estén bloqueadas con scripts significa que pueden bloquearse de varias formas diferentes, lo que requiere una variedad de claves diferentes. De hecho, hemos conocido varios mecanismos de bloqueo diferentes hasta la fecha, cada uno de los cuales usaba diferentes códigos de operación:
|
||||
|
||||
* OP_CHECKSIG, que compara una clave pública con una firma, es la base de la dirección P2PKH clásica, como se detallará completamente en [§9.4: Codificando un script P2PKH](09_4_Codificando_una_P2PKH.md).
|
||||
|
||||
* OP_CHECKMULTISIG verifica de manera similar las multifirma, como se detallará completamente en [§10.4: Codificando una Multifirma](10_4_Codificando_una_Multifirma.md).
|
||||
|
||||
* OP_CHECKLOCKTIMEVERIFY y OP_SEQUENCEVERIFY forman la base de bloqueos de tiempo más complejos, como se detallará completamente en [§11.2: Usando CLTV en Scripts](11_2_Usando_CLTV_en_Scripts.md) y [§11.3: Usando CSV en Scripts](11_3_Usando_CSV_en_Scripts.md).
|
||||
|
||||
* OP_RETURN es la marca de una transacción no prescindible, por lo que se utiliza para transportar datos, como se mencionó en [§8.2: Envío de una transacción con datos](08_2_Enviando_una_Transaccion_con_Datos.md).
|
||||
|
||||
## Acceda a los scripts en sus transacciones
|
||||
|
||||
Es posible que no se dé cuenta, pero ya ha visto estos scripts de bloqueo y desbloqueo como parte de las transacciones sin procesar con las que ha estado trabajando. La mejor manera de examinar estos scripts con más profundidad es crear una transacción sin procesar y luego examinarla.
|
||||
|
||||
### Crear una transacción de prueba
|
||||
|
||||
Para examinar scripts de desbloqueo y bloqueo reales, cree una transacción sin procesar rápida tomando un UTXO Legacy no gastado y reenvíela a una dirección de cambio Legacy, menos la tarifa de transacción:
|
||||
|
||||
```
|
||||
$ utxo_txid=$(bitcoin-cli listunspent | jq -r '.[1] | .txid')
|
||||
$ utxo_vout=$(bitcoin-cli listunspent | jq -r '.[1] | .vout')
|
||||
$ recipient=$(bitcoin-cli -named getrawchangeaddress address_type=legacy)
|
||||
$ rawtxhex=$(bitcoin-cli -named createrawtransaction inputs='''[ { "txid": "'$utxo_txid'", "vout": '$utxo_vout' } ]''' outputs='''{ "'$recipient'": 0.0009 }''')
|
||||
$ signedtx=$(bitcoin-cli -named signrawtransactionwithwallet hexstring=$rawtxhex | jq -r '.hex')
|
||||
```
|
||||
|
||||
En realidad, no es necesario que la envíe: el objetivo es simplemente producir una transacción completa que pueda examinar.
|
||||
|
||||
>** NOTA:** ¿Por qué las direcciones heredadas (legacy)? Porque sus scripts son más significativos. Sin embargo, también ofreceremos un ejemplo de un SegWit P2WPKH nativo en [§9.5](09_5_Codificando_una_P2WPKH.md).
|
||||
|
||||
### Examine su transacción de prueba
|
||||
|
||||
Ahora puede examinar su transacción a profundidad mediante el uso de `decoderawtransaction` sobre el `$signedtx`:
|
||||
```
|
||||
$ bitcoin-cli -named decoderawtransaction hexstring=$signedtx
|
||||
{
|
||||
"txid": "34151dac704d94a269cd33f80be34c122152edc9bfbb9323852966bf0ce937ed",
|
||||
"hash": "34151dac704d94a269cd33f80be34c122152edc9bfbb9323852966bf0ce937ed",
|
||||
"version": 2,
|
||||
"size": 191,
|
||||
"vsize": 191,
|
||||
"weight": 764,
|
||||
"locktime": 0,
|
||||
"vin": [
|
||||
{
|
||||
"txid": "bb4362dec15e67d366088f5493c789f22fb4a604e767dae1f6a631687e2784aa",
|
||||
"vout": 0,
|
||||
"scriptSig": {
|
||||
"asm": "304402201cc39005b076cb06534cd084fcc522e7bf937c4c9654c1c9dfba68b92cbab7d1022066f273178febc7a37568e2e9f4dec980a2e9a95441abe838c7ef64c39d85849c[ALL] 0315a0aeb37634a71ede72d903acae4c6efa77f3423dcbcd6de3e13d9fd989438b",
|
||||
"hex": "47304402201cc39005b076cb06534cd084fcc522e7bf937c4c9654c1c9dfba68b92cbab7d1022066f273178febc7a37568e2e9f4dec980a2e9a95441abe838c7ef64c39d85849c01210315a0aeb37634a71ede72d903acae4c6efa77f3423dcbcd6de3e13d9fd989438b"
|
||||
},
|
||||
"sequence": 4294967295
|
||||
}
|
||||
],
|
||||
"vout": [
|
||||
{
|
||||
"value": 0.00090000,
|
||||
"n": 0,
|
||||
"scriptPubKey": {
|
||||
"asm": "OP_DUP OP_HASH160 06b5c6ba5330cdf738a2ce91152bfd0e71f9ec39 OP_EQUALVERIFY OP_CHECKSIG",
|
||||
"hex": "76a91406b5c6ba5330cdf738a2ce91152bfd0e71f9ec3988ac",
|
||||
"reqSigs": 1,
|
||||
"type": "pubkeyhash",
|
||||
"addresses": [
|
||||
"mg8S7F1gY3ivV9M9GrWwe6ziWvK2MFquCf"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
```
|
||||
Los dos scripts se encuentran en diferentes partes de la transación.
|
||||
|
||||
El `scriptSig` se encuentra en el` vin`. Este es el script _de desbloqueo_. Es lo que se ejecuta para acceder al UTXO que se utiliza para financiar esta transacción. Habrá un `scriptSig` por UTXO en una transacción.
|
||||
|
||||
El `scriptPubKey` se encuentra en el` vout`. Este es el script _de bloqueo_. Es lo que bloquea la nueva salida de la transacción. Habrá una `scriptPubKey` por salida en una transacción.
|
||||
|
||||
>:book:***¿Cómo interactúan scriptSig y scriptPubKey?*** El `scriptSig` de una transacción desbloquea el UTXO anterior; La salida de esta nueva transacción se bloqueará con un `scriptPubKey`, que a su vez puede ser desbloqueado por el` scriptSig` de la transacción que reutiliza ese UTXO.
|
||||
|
||||
### Lea los scripts en su transacción
|
||||
|
||||
Mire los dos scripts y verá que cada uno incluye dos representaciones diferentes: el `hex` es lo que realmente se almacena, aunque el lenguaje ensamblador más legible (`asm`) puede mostrarle lo que está sucediendo.
|
||||
|
||||
Eche un vistazo al `asm` del script de desbloqueo y verá por primera vez cómo se ve Bitcoin Scripting:
|
||||
|
||||
```
|
||||
04402201cc39005b076cb06534cd084fcc522e7bf937c4c9654c1c9dfba68b92cbab7d1022066f273178febc7a37568e2e9f4dec980a2e9a95441abe838c7ef64c39d85849c[ALL] 0315a0aeb37634a71ede72d903acae4c6efa77f3423dcbcd6de3e13d9fd989438b
|
||||
```
|
||||
|
||||
Da la casualidad de que ese lío de números es una firma de clave privada seguida de la clave pública asociada. O al menos eso es lo que es, con suerte, porque eso es lo que se requiere para desbloquear el UTXO P2PKH que está utilizando esta transacción.
|
||||
|
||||
Lea el script de bloqueo y verá que es mucho más obvio:
|
||||
|
||||
```
|
||||
OP_DUP OP_HASH160 06b5c6ba5330cdf738a2ce91152bfd0e71f9ec39 OP_EQUALVERIFY OP_CHECKSIG
|
||||
```
|
||||
|
||||
Ese es el método estándar en Bitcoin Script para bloquear una transacción P2PKH.
|
||||
|
||||
[§9.4](09_4_Codificando_una_P2PKH.md) explicará cómo estos dos scripts van juntos, pero primero necesitará saber cómo se evalúan los scripts de Bitcoin.
|
||||
|
||||
## Examine un tipo diferente de transacción
|
||||
|
||||
Antes de dejar atrás esta base, veremos un tipo diferente de secuencia de comandos de bloqueo. Aquí está el `scriptPubKey` de la transacción multisig que creó en [§6.1: Enviando una Transacción a una Dirección Multifirma](06_1_Enviando_una_Transaccion_a_una_Direccion_Multifirma.md).
|
||||
|
||||
```
|
||||
"scriptPubKey": {
|
||||
"asm": "OP_HASH160 a5d106eb8ee51b23cf60d8bd98bc285695f233f3 OP_EQUAL",
|
||||
"hex": "a914a5d106eb8ee51b23cf60d8bd98bc285695f233f387",
|
||||
"reqSigs": 1,
|
||||
"type": "scripthash",
|
||||
"addresses": [
|
||||
"2N8MytPW2ih27LctLjn6LfLFZZb1PFSsqBr"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Compare eso con el `scriptPubKey` de su nueva transacción P2PKH:
|
||||
|
||||
```
|
||||
"scriptPubKey": {
|
||||
"asm": "OP_DUP OP_HASH160 06b5c6ba5330cdf738a2ce91152bfd0e71f9ec39 OP_EQUALVERIFY OP_CHECKSIG",
|
||||
"hex": "76a91406b5c6ba5330cdf738a2ce91152bfd0e71f9ec3988ac",
|
||||
"reqSigs": 1,
|
||||
"type": "pubkeyhash",
|
||||
"addresses": [
|
||||
"mg8S7F1gY3ivV9M9GrWwe6ziWvK2MFquCf"
|
||||
]
|
||||
}
|
||||
```
|
||||
Estas dos transacciones están _definitivamente_ bloqueadas de diferentes formas. Bitcoin reconoce el primero como `scripthash` (P2SH) y el segundo como` pubkeyhash` (P2PKH), pero también debería poder ver la diferencia en los distintos códigos `asm`:`OP_HASH160 a5d106eb8ee51b23cf60d8bd98bc285695f233f3 OP_EQUAL` frente a `OP_DUP OP_HASH160 06b5c6ba5330cdf738a2ce91152bfd0e71f9ec39 OP_EQUALVERIFY OP_CHECKSIG`. Este es el poder de las secuencias de comandos: puede producir de manera muy simple algunos de los tipos de transacciones dramáticamente diferentes de los que aprendió en los capítulos anteriores.
|
||||
|
||||
## Resumen: Entendiendo la base de las transacciones
|
||||
|
||||
Cada transacción de Bitcoin incluye al menos un script de desbloqueo (`scriptSig`), que resuelve un rompecabezas criptográfico anterior, y al menos un script de bloqueo (`scriptPubKey`), que crea un nuevo rompecabezas criptográfico. Hay un "scriptSig" por entrada y un "scriptPubKey" por salida. Cada uno de estos scripts está escrito en Bitcoin Script, un lenguaje similar a Forth que potencia aún más a Bitcoin.
|
||||
|
||||
|
||||
>:fire:***¿Cuál es el poder de los scripts?*** Los scripts desbloquean todo el poder de los contratos inteligentes. Con los códigos de operación adecuados, puede tomar decisiones muy precisas sobre quién puede canjear fondos, cuándo pueden canjear fondos y cómo pueden canjear fondos. También se pueden codificar en un script reglas más complejas para el gasto corporativo, el gasto en asociaciones, el gasto por poder y otras metodologías. Incluso habilita servicios de Bitcoin más complejos, como Lightning y sidechains.
|
||||
|
||||
## ¿Qué sigue?
|
||||
|
||||
Continúe "Introduciendo los scripts de Bitcoin" con [§9.2: Ejecutando un Script Bitcoin](09_2_Ejecutando_un_Script_Bitcoin.md).
|
128
es/09_2_Ejecutando_un_Script_Bitcoin.md
Normal file
128
es/09_2_Ejecutando_un_Script_Bitcoin.md
Normal file
@ -0,0 +1,128 @@
|
||||
# 9.2: Ejecutando un script Bitcoin
|
||||
|
||||
Los scripts de Bitcoin pueden no parecer inicialmente tan intuitivos, sin embargo su ejecución es bastante simple, utilizando la notación polaca inversa y una pila.
|
||||
|
||||
## Comprenda el lenguaje de secuencias de comandos
|
||||
|
||||
Un script de Bitcoin tiene tres partes: tiene una línea de entrada; tiene una pila para almacenamiento; y tiene comandos específicos para su ejecución.
|
||||
|
||||
### Entender el orden
|
||||
|
||||
Los scripts de Bitcoin se ejecutan de izquierda a derecha. Eso suena bastante fácil, porque es la misma forma en que lee. Sin embargo, en realidad podría ser el elemento menos intuitivo de Bitcoin Script, porque significa que las funciones no se ven como usted esperaría. En cambio, _los operandos van antes que el operador_.
|
||||
|
||||
Por ejemplo, si estuviera sumando "1" y "2", su script de Bitcoin para eso sería `1 2 OP_ADD`, no "1 + 2". Como sabemos que el operador OP_ADD toma dos entradas, sabemos que las dos entradas anteriores son sus operandos.
|
||||
|
||||
>:warning: **ADVERTENCIA:** Técnicamente, todo en Bitcoin Script es un código de operación, por lo que sería más apropiado registrar el ejemplo anterior como OP_1 OP_2 OP_ADD. En nuestros ejemplos, no nos preocupamos por cómo se evaluarán las constantes, ya que ese es un tema de traducción, como se explica en [10.2: Construyendo la Estructura de P2SH](10_2_Construyendo_la_Estructura_de_P2SH.md). Algunos escritores prefieren dejar el prefijo "OP" fuera de todos los operadores, pero nosotros hemos optado por no hacerlo.
|
||||
|
||||
### Entienda la pila
|
||||
|
||||
En realidad, no es del todo correcto decir que un operador se aplica a las entradas anteriores. Realmente, un operador aplica a las entradas superiores en la pila de Bitcoin.
|
||||
|
||||
>:book: ***¿Qué es una pila?*** Una pila es una estructura de datos LIFO (último en entrar, primero en salir). Tiene dos funciones de acceso: Empujar y quitar. Empujar (push) coloca un nuevo objeto en la parte superior de la pila, empujando hacia abajo todo lo que está debajo. Y la fuunció de quitar (Pop) elimina el objeto superior de la pila.
|
||||
|
||||
Siempre que Bitcoin Script encuentra una constante, la empuja a la pila. Entonces, el ejemplo anterior de `1 2 OP_ADD` en realidad se vería así cuando se procesó:
|
||||
|
||||
```
|
||||
Script: 1 2 OP_ADD
|
||||
Stack: [ ]
|
||||
|
||||
Script: 2 OP_ADD
|
||||
Stack: [ 1 ]
|
||||
|
||||
Script: OP_ADD
|
||||
Stack: [ 1 2 ]
|
||||
```
|
||||
_Tenga en cuenta que en este y en los siguientes ejemplos, la parte superior de la pila está a la derecha y la parte inferior a la izquierda._
|
||||
|
||||
### Comprenda los códigos de operación
|
||||
|
||||
Cuando un script de Bitcoin encuentra un operador, lo evalúa. Cada operador saca cero o más elementos de la pila como entradas, generalmente uno o dos. Luego los procesa de una manera específica antes de devolver cero o más elementos a la pila, generalmente uno o dos.
|
||||
|
||||
>:book: ***¿Qué es un opcode?*** Opcode significa "código de operación". Por lo general, está asociado con el código en lenguaje de máquina y es una función simple (u "operador").
|
||||
|
||||
OP_ADD saca dos elementos de la pila (aquí: 2 y luego 1), luego suma y vuelve a colocar el resultado en la pila (aquí: 3).
|
||||
|
||||
```
|
||||
Script:
|
||||
Running: 1 2 OP_ADD
|
||||
Stack: [ 3 ]
|
||||
```
|
||||
|
||||
## Aumente la complejidad
|
||||
|
||||
Se crean scripts más complejos ejecutando más comandos en orden. Deben evaluarse cuidadosamente de izquierda a derecha, para que pueda comprender el estado de la pila a medida que se ejecuta cada nuevo comando. Cambiará constantemente, como resultado de operadores anteriores:
|
||||
|
||||
```
|
||||
Script: 3 2 OP_ADD 4 OP_SUB
|
||||
Stack: [ ]
|
||||
|
||||
Script: 2 OP_ADD 4 OP_SUB
|
||||
Stack: [ 3 ]
|
||||
|
||||
Script: OP_ADD 4 OP_SUB
|
||||
Stack: [ 3 2 ]
|
||||
|
||||
Script: 4 OP_SUB
|
||||
Running: 3 2 OP_ADD
|
||||
Stack: [ 5 ]
|
||||
|
||||
Script: OP_SUB
|
||||
Stack: [ 5 4 ]
|
||||
|
||||
Script:
|
||||
Running: 5 4 OP_SUB
|
||||
Stack: [ 1 ]
|
||||
```
|
||||
|
||||
## Comprenda el uso del script de Bitcoin
|
||||
|
||||
Eso es prácticamente Bitcoin Scripting ... aparte de algunas complejidades de cómo este lenguaje de scripting interactúa con el propio Bitcoin.
|
||||
|
||||
### Comprenda scriptSig y scriptPubKey
|
||||
|
||||
Como hemos visto, cada entrada para una transacción de Bitcoin contiene un `scriptSig` que se usa para desbloquear el `scriptPubKey` del UXTO asociado. Están _efectivamente_ concatenados juntos, lo que significa que `scriptSig` y `scriptPubKey` se ejecutan juntos, en ese orden.
|
||||
|
||||
Por lo tanto, suponga que un UTXO estaba bloqueado con una scriptPubKey que incluía `OP_ADD 99 OP_EQUAL`, lo que requiere como entrada dos números que sumen noventa y nueve, y suponga que el `scriptSig` de `1 98` fue ejecutado para desbloquearlo. Los dos scripts se ejecutarían efectivamente en el orden `1 98 OP_ADD 99 OP_EQUAL`.
|
||||
|
||||
Evalúe el resultado:
|
||||
```
|
||||
Script: 1 98 OP_ADD 99 OP_EQUAL
|
||||
Stack: []
|
||||
|
||||
Script: 98 OP_ADD 99 OP_EQUAL
|
||||
Stack: [ 1 ]
|
||||
|
||||
Script: OP_ADD 99 OP_EQUAL
|
||||
Stack: [ 1 98 ]
|
||||
|
||||
Script: 99 OP_EQUAL
|
||||
Running: 1 98 OP_ADD
|
||||
Stack: [ 99 ]
|
||||
|
||||
Script: OP_EQUAL
|
||||
Stack: [ 99 99 ]
|
||||
|
||||
Script:
|
||||
Running: 99 99 OP_EQUAL
|
||||
Stack: [ True ]
|
||||
```
|
||||
Esta abstracción no es del todo precisa: por razones de seguridad, el `scriptSig` se ejecuta, luego el contenido de la pila se transfiere al `scriptPubKey` para ejecutarlo, pero es lo suficientemente preciso para comprender cómo la llave del `scriptSig` encaja en la cerradura del `scriptPubKey`.
|
||||
|
||||
>:warning **ADVERTENCIA** Lo anterior es un tipo de transacción no estándar. En realidad, no sería aceptado por los nodos que ejecutan Bitcoin Core con la configuración estándar. [§10.1: Entendiendo la Base de P2SH](10_1_Entendiendo_la_Base_de_P2SH.md) analiza cómo se podría ejecutar un script de Bitcoin como este, utilizando el poder de P2SH.
|
||||
|
||||
### Obtenga los resultados
|
||||
|
||||
Bitcoin verificará una transacción y permitirá que el UTXO sea gastado si se cumplen dos criterios durante la ejecución de `scriptSig` y `scriptPubKey`:
|
||||
|
||||
1. La ejecución no se marcó como inválida en ningún momento, por ejemplo, con un OP_VERIFY fallido o el uso de un código de operación deshabilitado.
|
||||
2. El elemento superior de la pila al final de la ejecución es verdadero (distinto de cero).
|
||||
|
||||
En el ejemplo anterior, la transacción se realizaría correctamente porque la pila tiene un `True` en la parte superior. Pero sería igualmente permisible terminar con una pila completa y el número `42` en la parte superior.
|
||||
|
||||
## Resumen: Ejecutando un script Bitcoin
|
||||
|
||||
Para procesar un script de Bitcoin, un `scriptSig` se ejecuta despúes del `scriptPubKey` que está desbloqueando. Estos comandos se ejecutan en orden, de izquierda a derecha, con constantes que se insertan en una pila y los operadores extraen elementos de esa pila y luego devuelven los resultados. Si el script no se detiene en el medio y si el elemento en la parte superior de la pila al final no es cero, entonces el UTXO está desbloqueado.
|
||||
|
||||
## ¿Que sigue?
|
||||
|
||||
Continúe "Introduciendo los scripts de Bitcoin" en [§9.3: Probando un script Bitcoin](09_3_Probando_un_Script_Bitcoin.md).
|
210
es/09_3_Probando_un_Script_Bitcoin.md
Normal file
210
es/09_3_Probando_un_Script_Bitcoin.md
Normal file
@ -0,0 +1,210 @@
|
||||
# 9.3: Probando un script de Bitcoin
|
||||
|
||||
Bitcoin Scripting permite un control considerable adicional sobre las transacciones de Bitcoin, pero también es algo peligroso. Como describiremos en [§10.1](10_1_Entendiendo_la_Base_de_P2SH.md), los scripts reales están algo aislados de la red Bitcoin, lo que significa que es posible escribir un script y hacer que la red lo acepte incluso si es imposible canjearlo desde ese script. Por lo tanto, debe probar a fondo sus scripts antes de invertir su dinero en ellos.
|
||||
|
||||
Por lo tanto, este capítulo describe un método principal para probar los scripts de Bitcoin, que también usaremos para ejemplos ocasionales en el resto de esta sección.
|
||||
|
||||
## Instalar btcdeb
|
||||
|
||||
Bitcoin Script Debugger (`btcdeb`) de @kallewoof es uno de los métodos más confiables que hemos encontrado para depurar Bitcoin Scripts. Sin embargo, requiere configurar C++ y algunos otros accesorios en su máquina, por lo que también ofreceremos algunas otras opciones hacia el final de este capítulo.
|
||||
|
||||
Primero, debe clonar el repositorio `btcdeb` de GitHub, que también requerirá la instalación `git` si aún no lo tiene.
|
||||
|
||||
```
|
||||
$ sudo apt-get install git
|
||||
$ git clone https://github.com/bitcoin-core/btcdeb.git
|
||||
```
|
||||
Tenga en cuenta que cuando ejecute `git clone` se copiará `btcdeb` en su directorio actual. Hemos elegido hacerlo en nuestro directorio `~standup`.
|
||||
```
|
||||
$ ls
|
||||
bitcoin-0.20.0-x86_64-linux-gnu.tar.gz btcdeb laanwj-releases.asc SHA256SUMS.asc
|
||||
```
|
||||
Posteriormente debe instalar C++ y otros paquetes requeridos.
|
||||
```
|
||||
$ sudo apt-get install autoconf libtool g++ pkg-config make
|
||||
```
|
||||
También debe instalar readline, ya que esto hace que el depurador sea mucho más fácil de usar al admitir el historial usando las flechas arriba / abajo, movimiento de izquierda a derecha, autocompletado usando la pestaña y otras buenas interfaces de usuario.
|
||||
```
|
||||
$ sudo apt-get install libreadline-dev
|
||||
```
|
||||
Ahora está listo para compilar e instalar `btcdeb`:
|
||||
```
|
||||
$ cd btcdeb
|
||||
$ ./autogen.sh
|
||||
$ ./configure
|
||||
$ make
|
||||
$ sudo make install
|
||||
```
|
||||
Después de todo eso, debería tener una copia de `btcdeb`:
|
||||
```
|
||||
$ which btcdeb
|
||||
/usr/local/bin/btcdeb
|
||||
```
|
||||
|
||||
## Utilice btcdeb
|
||||
|
||||
`btcdeb` funciona como un depurador estándar. Toma una secuencia de comandos (así como cualquier número de entradas de la pila) como argumento de inicio. A continuación, puede usar `step` para recorrer el script.
|
||||
|
||||
Si, en cambio, lo inicia sin argumentos, simplemente obtiene un intérprete donde puede emitir `exec [opcode]` comandos para realizar acciones directamente.
|
||||
|
||||
### Utilice btcdeb para un ejemplo de adición
|
||||
|
||||
El siguiente ejemplo muestra el uso de `btcdeb` para el ejemplo de adición de la sección anterior, `1 2 OP_ADD`
|
||||
```
|
||||
$ btcdeb '[1 2 OP_ADD]'
|
||||
btcdeb 0.2.19 -- type `btcdeb -h` for start up options
|
||||
warning: ambiguous input 1 is interpreted as a numeric value; use OP_1 to force into opcode
|
||||
warning: ambiguous input 2 is interpreted as a numeric value; use OP_2 to force into opcode
|
||||
miniscript failed to parse script; miniscript support disabled
|
||||
valid script
|
||||
3 op script loaded. type `help` for usage information
|
||||
script | stack
|
||||
--------+--------
|
||||
1 |
|
||||
2 |
|
||||
OP_ADD |
|
||||
#0000 1
|
||||
```
|
||||
Muestra nuestro script inicial, que se ejecuta de arriba a abajo, y también muestra lo que se ejecutará a continuación en el script.
|
||||
|
||||
Escribimos `step` y avanza un paso tomando el primer elemento del script y empujándolo a la pila:
|
||||
```
|
||||
btcdeb> step
|
||||
<> PUSH stack 01
|
||||
script | stack
|
||||
--------+--------
|
||||
2 | 01
|
||||
OP_ADD |
|
||||
#0001 2
|
||||
```
|
||||
Y otra vez:
|
||||
```
|
||||
btcdeb> step
|
||||
<> PUSH stack 02
|
||||
script | stack
|
||||
--------+--------
|
||||
OP_ADD | 02
|
||||
| 01
|
||||
#0002 OP_ADD
|
||||
```
|
||||
Ahora ejecutamos el `OP_ADD` y hay una gran emoción porque ese código de operación saca los dos primeros elementos de la pila, los suma y luego empuja su suma a la pila.
|
||||
```
|
||||
btcdeb> step
|
||||
<> POP stack
|
||||
<> POP stack
|
||||
<> PUSH stack 03
|
||||
script | stack
|
||||
--------+--------
|
||||
| 03
|
||||
```
|
||||
Y ahí es donde termina nuestra secuencia de comandos, sin nada más que ejecutar y un `03` posicionado en la parte superior de nuestra pila como resultado de la secuencia de comandos.
|
||||
|
||||
> **NOTA:** `btcdeb` permite repetir el comando anterior presionando enter. Haremos esto en los siguientes ejemplos, así que no se sorprenda de las indicaciones `btcdeb` sin nada como entrada. Está simplemente repitiendo el comando previo (a menudo `step`).
|
||||
|
||||
### Utilice btcdeb para un ejemplo de resta
|
||||
|
||||
La sección anterior también incluyó un ejemplo de secuencias de comandos con resta un poco más compleja : `3 2 OP_ADD 4 OP_SUB`. Así es como se ve:
|
||||
```
|
||||
$ btcdeb '[3 2 OP_ADD 4 OP_SUB]'
|
||||
btcdeb 0.2.19 -- type `btcdeb -h` for start up options
|
||||
warning: ambiguous input 3 is interpreted as a numeric value; use OP_3 to force into opcode
|
||||
warning: ambiguous input 2 is interpreted as a numeric value; use OP_2 to force into opcode
|
||||
warning: ambiguous input 4 is interpreted as a numeric value; use OP_4 to force into opcode
|
||||
miniscript failed to parse script; miniscript support disabled
|
||||
valid script
|
||||
5 op script loaded. type `help` for usage information
|
||||
script | stack
|
||||
--------+--------
|
||||
3 |
|
||||
2 |
|
||||
OP_ADD |
|
||||
4 |
|
||||
OP_SUB |
|
||||
#0000 3
|
||||
btcdeb> step
|
||||
<> PUSH stack 03
|
||||
script | stack
|
||||
--------+--------
|
||||
2 | 03
|
||||
OP_ADD |
|
||||
4 |
|
||||
OP_SUB |
|
||||
#0001 2
|
||||
btcdeb>
|
||||
<> PUSH stack 02
|
||||
script | stack
|
||||
--------+--------
|
||||
OP_ADD | 02
|
||||
4 | 03
|
||||
OP_SUB |
|
||||
#0002 OP_ADD
|
||||
btcdeb>
|
||||
<> POP stack
|
||||
<> POP stack
|
||||
<> PUSH stack 05
|
||||
script | stack
|
||||
--------+--------
|
||||
4 | 05
|
||||
OP_SUB |
|
||||
#0003 4
|
||||
btcdeb>
|
||||
<> PUSH stack 04
|
||||
script | stack
|
||||
--------+--------
|
||||
OP_SUB | 04
|
||||
| 05
|
||||
#0004 OP_SUB
|
||||
btcdeb>
|
||||
<> POP stack
|
||||
<> POP stack
|
||||
<> PUSH stack 01
|
||||
script | stack
|
||||
--------+--------
|
||||
| 01
|
||||
```
|
||||
Volveremos a `btcdeb` de vez en cuando, y seguirá siendo una excelente herramienta para probar sus propios scripts.
|
||||
|
||||
### Usar el poder de btcdeb
|
||||
|
||||
`btcdeb` también tiene algunas funciones más poderosas, como `print` and `stack`, que le muestran el script y la pila en cualquier momento.
|
||||
|
||||
Por ejemplo, en la secuencia de comandos anterior, una vez que haya avanzado al comando `OP_ADD`, puede ver lo siguiente:
|
||||
```
|
||||
btcdeb> print
|
||||
#0000 3
|
||||
#0001 2
|
||||
-> #0002 OP_ADD
|
||||
#0003 4
|
||||
#0004 OP_SUB
|
||||
btcdeb> stack
|
||||
<01> 02 (top)
|
||||
<02> 03
|
||||
```
|
||||
El uso de estos comandos puede hacer que sea más fácil ver lo que está sucediendo y dónde se encuentra.
|
||||
|
||||
## Probar un script en línea
|
||||
|
||||
También hay algunos simuladores web que puede utilizar para probar scripts en línea. Pueden ser superiores a una herramienta de línea de comandos al ofrecer una salida más gráfica, pero también encontramos que tienden a tener deficiencias.
|
||||
|
||||
En el pasado, hemos intentado brindar pautas detalladas sobre el uso de sitios como [Script Playground](http://www.crmarsh.com/script-playground/) o [Bitcoin Online Script Debugger](https://bitcoin-script-debugger.visvirial.com/), pero se desactualizan y / o desaparecen demasiado rápido para mantenerse al día con ellos.
|
||||
|
||||
Suponga que estos depuradores tienen la gran ventaja de mostrar las cosas visual y explícitamente que le dicen si un script tiene éxito (se desbloquea) o falla (permanece bloqueado). Asumimos que tienen desventajas con las firmas, donde muchos de ellos siempre regresan `true` para las pruebas de firmas o tienen mecanismos muy engorrosos para incorporarlas.
|
||||
|
||||
|
||||
## Pruebe un script con Bitcoin
|
||||
|
||||
Incluso con una gran herramienta como `btcdeb` o recursos transitorios como los diversos probadores de scripts en línea, no está trabajando con un ambiente real. No puede garantizar que sigan las reglas de consenso de Bitcoin, lo que significa que no puede garantizar sus resultados. Por ejemplo, Script Playground dice explícitamente que ignora un error implícito en las firmas múltiples de Bitcoin. Esto significa que cualquier código multifirma que pruebe con éxito en Script Playground se romperá en el mundo real.
|
||||
|
||||
Entonces, la única forma de probar _realmente_ los scripts de Bitcoin es probándolos en Testnet.
|
||||
|
||||
Y como se hace eso? Da la casualidad que es el tema del [capítulo 10](10_0_Embebiendo_Bitcoin_Scripts_en_Transacciones_P2SH.md), que busca introducir estos scripts abstractos en el mundo real de Bitcoin incrustándolos en transacciones P2SH. (Pero incluso entonces, probablemente necesitará una API para impulsar su transacción P2SH a la red Bitcoin, por lo que las pruebas completas seguirán siendo una forma en el futuro).
|
||||
|
||||
_Independientemente_ de los otros métodos de prueba que haya utilizado, probar un script en Testnet debería ser su prueba final antes de poner su script en Mainnet. No confíe en que su código sea correcto; no se limite a mirarlo. Ni siquiera confíe en los simuladores o depuradores que ha estado usando. Hacerlo es otra excelente manera de perder fondos en Bitcoin.
|
||||
|
||||
## Resumen: probando un script de Bitcoin
|
||||
|
||||
Debería instalar `btcdeb` como una herramienta de línea de comandos para probar sus scripts de Bitcoin. En el momento de escribir este artículo, produce resultados precisos que pueden recorrer todo el proceso de creación de scripts. También puede buscar en algunos sitios en línea para obtener una representación más visual. Cuando haya terminado, deberá ir a testnet para asegurarse de que todo funciona correctamente, antes de implementarlo de manera más general.
|
||||
|
||||
## ¿Que sigue?
|
||||
|
||||
Continue con "Introduciendo Bitcoin Scripts" con nuestro primer ejemplo de la vida real: [§9.4: Codificando una P2PKH](09_4_Codificando_una_P2PKH.md).
|
395
es/09_4_Codificando_una_P2PKH.md
Normal file
395
es/09_4_Codificando_una_P2PKH.md
Normal file
@ -0,0 +1,395 @@
|
||||
# 9.4: Codificando una P2PKH
|
||||
|
||||
Las direcciones P2PKH están perdiendo popularidad rápidamente debido a la llegada de SegWit, pero, no obstante, siguen siendo un gran bloque de construcción para comprender Bitcoin, y especialmente para comprender los scripts de Bitcoin. (Echaremos un vistazo rápido a cómo los scripts P2WPKH nativos de Segwit funcionan de manera diferente en la siguiente sección).
|
||||
|
||||
## Comprenda el script de desbloqueo
|
||||
|
||||
Durante mucho tiempo hemos dicho que cuando los fondos se envían a una dirección de Bitcoin, están bloqueados con la clave privada asociada con esa dirección. Esto se gestiona a través del `scriptPubKey` de una transacción P2PKH, que está diseñada de tal manera que requiere que el destinatario tenga la clave privada asociada a la dirección P2PKH Bitcoin. Para ser precisos, el destinatario debe proporcionar tanto la clave pública vinculada a la clave privada como una firma generada por la clave privada.
|
||||
|
||||
Revise nuevamente la transacción que creó en [§9.1](09_1_Entendiendo_la_base_de_las_Transacciones.md):
|
||||
```
|
||||
$ bitcoin-cli -named decoderawtransaction hexstring=$signedtx
|
||||
{
|
||||
"txid": "34151dac704d94a269cd33f80be34c122152edc9bfbb9323852966bf0ce937ed",
|
||||
"hash": "34151dac704d94a269cd33f80be34c122152edc9bfbb9323852966bf0ce937ed",
|
||||
"version": 2,
|
||||
"size": 191,
|
||||
"vsize": 191,
|
||||
"weight": 764,
|
||||
"locktime": 0,
|
||||
"vin": [
|
||||
{
|
||||
"txid": "bb4362dec15e67d366088f5493c789f22fb4a604e767dae1f6a631687e2784aa",
|
||||
"vout": 0,
|
||||
"scriptSig": {
|
||||
"asm": "304402201cc39005b076cb06534cd084fcc522e7bf937c4c9654c1c9dfba68b92cbab7d1022066f273178febc7a37568e2e9f4dec980a2e9a95441abe838c7ef64c39d85849c[ALL] 0315a0aeb37634a71ede72d903acae4c6efa77f3423dcbcd6de3e13d9fd989438b",
|
||||
"hex": "47304402201cc39005b076cb06534cd084fcc522e7bf937c4c9654c1c9dfba68b92cbab7d1022066f273178febc7a37568e2e9f4dec980a2e9a95441abe838c7ef64c39d85849c01210315a0aeb37634a71ede72d903acae4c6efa77f3423dcbcd6de3e13d9fd989438b"
|
||||
},
|
||||
"sequence": 4294967295
|
||||
}
|
||||
],
|
||||
"vout": [
|
||||
{
|
||||
"value": 0.00090000,
|
||||
"n": 0,
|
||||
"scriptPubKey": {
|
||||
"asm": "OP_DUP OP_HASH160 06b5c6ba5330cdf738a2ce91152bfd0e71f9ec39 OP_EQUALVERIFY OP_CHECKSIG",
|
||||
"hex": "76a91406b5c6ba5330cdf738a2ce91152bfd0e71f9ec3988ac",
|
||||
"reqSigs": 1,
|
||||
"type": "pubkeyhash",
|
||||
"addresses": [
|
||||
"mg8S7F1gY3ivV9M9GrWwe6ziWvK2MFquCf"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
Puede ver que su `scriptSig` o secuencia de comandos de desbloqueo tiene dos valores. Eso es un `<signature>` (y un `[ALL]`) y un `<pubKey>`:
|
||||
```
|
||||
304402201cc39005b076cb06534cd084fcc522e7bf937c4c9654c1c9dfba68b92cbab7d1022066f273178febc7a37568e2e9f4dec980a2e9a95441abe838c7ef64c39d85849c[ALL] 0315a0aeb37634a71ede72d903acae4c6efa77f3423dcbcd6de3e13d9fd989438b
|
||||
```
|
||||
Eso es todo lo que es un script de desbloqueo! (Para un P2PKH.)
|
||||
|
||||
## Comprenda el script de bloqueo
|
||||
|
||||
Recuerde que cada script de desbloqueo desbloquea un UTXO anterior. En el ejemplo anterior, `vin` revela que en realidad está desbloqueando el vout `0` de la transacción con txid `bb4362dec15e67d366088f5493c789f22fb4a604e767dae1f6a631687e2784aa`.
|
||||
|
||||
Puede examinar ese UTXO con `gettransaction`.
|
||||
|
||||
```
|
||||
$ bitcoin-cli gettransaction "bb4362dec15e67d366088f5493c789f22fb4a604e767dae1f6a631687e2784aa"
|
||||
{
|
||||
"amount": 0.00095000,
|
||||
"confirmations": 12,
|
||||
"blockhash": "0000000075a4c1519da5e671b15064734c42784eab723530a6ace83ca1e66d3f",
|
||||
"blockheight": 1780789,
|
||||
"blockindex": 132,
|
||||
"blocktime": 1594841768,
|
||||
"txid": "bb4362dec15e67d366088f5493c789f22fb4a604e767dae1f6a631687e2784aa",
|
||||
"walletconflicts": [
|
||||
],
|
||||
"time": 1594841108,
|
||||
"timereceived": 1594841108,
|
||||
"bip125-replaceable": "no",
|
||||
"details": [
|
||||
{
|
||||
"address": "mmX7GUoXq2wVcbnrnFJrGKsGR14fXiGbD9",
|
||||
"category": "receive",
|
||||
"amount": 0.00095000,
|
||||
"label": "",
|
||||
"vout": 0
|
||||
}
|
||||
],
|
||||
"hex": "020000000001011efcc3bf9950ac2ea08c53b43a0f8cc21e4b5564e205f996f7cadb7d13bb79470000000017160014c4ea10874ae77d957e170bd43f2ee828a8e3bc71feffffff0218730100000000001976a91441d83eaffbf80f82dee4c152de59a38ffd0b602188ac713b10000000000017a914b780fc2e945bea71b9ee2d8d2901f00914a25fbd8702473044022025ee4fd38e6865125f7c315406c0b3a8139d482e3be333727d38868baa656d3d02204b35d9b5812cb85894541da611d5cec14c374ae7a7b8ba14bb44495747b571530121033cae26cb3fa063c95e2c55a94bd04ab9cf173104555efe448b1bfc3a68c8f873342c1b00"
|
||||
}
|
||||
```
|
||||
Pero como puede ver no obtuvo el `scriptPubKey` con el comando `gettransaction`. Debe dar un paso adicional para recuperar eso examinando la información de la transacción sin procesar (esa es la `hex`) con `decoderawtransaction`:
|
||||
|
||||
```
|
||||
$ hex=$(bitcoin-cli gettransaction "bb4362dec15e67d366088f5493c789f22fb4a604e767dae1f6a631687e2784aa" | jq -r '.hex')
|
||||
$ bitcoin-cli decoderawtransaction $hex
|
||||
{
|
||||
"txid": "bb4362dec15e67d366088f5493c789f22fb4a604e767dae1f6a631687e2784aa",
|
||||
"hash": "6866490b16a92d68179e1cf04380fd08f16ec80bf66469af8d5e78ae624ff202",
|
||||
"version": 2,
|
||||
"size": 249,
|
||||
"vsize": 168,
|
||||
"weight": 669,
|
||||
"locktime": 1780788,
|
||||
"vin": [
|
||||
{
|
||||
"txid": "4779bb137ddbcaf796f905e264554b1ec28c0f3ab4538ca02eac5099bfc3fc1e",
|
||||
"vout": 0,
|
||||
"scriptSig": {
|
||||
"asm": "0014c4ea10874ae77d957e170bd43f2ee828a8e3bc71",
|
||||
"hex": "160014c4ea10874ae77d957e170bd43f2ee828a8e3bc71"
|
||||
},
|
||||
"txinwitness": [
|
||||
"3044022025ee4fd38e6865125f7c315406c0b3a8139d482e3be333727d38868baa656d3d02204b35d9b5812cb85894541da611d5cec14c374ae7a7b8ba14bb44495747b5715301",
|
||||
"033cae26cb3fa063c95e2c55a94bd04ab9cf173104555efe448b1bfc3a68c8f873"
|
||||
],
|
||||
"sequence": 4294967294
|
||||
}
|
||||
],
|
||||
"vout": [
|
||||
{
|
||||
"value": 0.00095000,
|
||||
"n": 0,
|
||||
"scriptPubKey": {
|
||||
"asm": "OP_DUP OP_HASH160 41d83eaffbf80f82dee4c152de59a38ffd0b6021 OP_EQUALVERIFY OP_CHECKSIG",
|
||||
"hex": "76a91441d83eaffbf80f82dee4c152de59a38ffd0b602188ac",
|
||||
"reqSigs": 1,
|
||||
"type": "pubkeyhash",
|
||||
"addresses": [
|
||||
"mmX7GUoXq2wVcbnrnFJrGKsGR14fXiGbD9"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"value": 0.01063793,
|
||||
"n": 1,
|
||||
"scriptPubKey": {
|
||||
"asm": "OP_HASH160 b780fc2e945bea71b9ee2d8d2901f00914a25fbd OP_EQUAL",
|
||||
"hex": "a914b780fc2e945bea71b9ee2d8d2901f00914a25fbd87",
|
||||
"reqSigs": 1,
|
||||
"type": "scripthash",
|
||||
"addresses": [
|
||||
"2N9yWARt5E3TQsX2RjsauxSZaEZVhinAS4h"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
Ahora puede mirar el `vout` `0` y ver que estaba bloqueado con la `scriptPubKey` de `OP_DUP OP_HASH160 41d83eaffbf80f82dee4c152de59a38ffd0b6021 OP_EQUALVERIFY OP_CHECKSIG`. Esa es la metodología de bloqueo estándar utilizada para una dirección P2PKH anterior con el `<pubKeyHash>` bloqueado en el medio.
|
||||
|
||||
Ejecutarlo demostrará cómo funciona.
|
||||
|
||||
## Ejecute un script P2PKH
|
||||
|
||||
Cuando desbloquea un UTXO P2PKH, (efectivamente) concatena los scripts de desbloqueo y bloqueo. Para una dirección P2PKH, como el ejemplo utilizado en este capítulo, que produce:
|
||||
|
||||
```
|
||||
Script: <signature> <pubKey> OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
|
||||
```
|
||||
Con eso en conjunto, puede examinar cómo se desbloquea un UTXO P2PKH.
|
||||
|
||||
Primero, pone las constantes iniciales en la pila, y luego hace un duplicado de la pubKey con `OP_DUP`:
|
||||
```
|
||||
Script: <signature> <pubKey> OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
|
||||
Stack: [ ]
|
||||
|
||||
Script: <pubKey> OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
|
||||
Stack: [ <signature> ]
|
||||
|
||||
Script: OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
|
||||
Stack: [ <signature> <pubKey> ]
|
||||
|
||||
Script: OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
|
||||
Running: <pubKey> OP_DUP
|
||||
Stack: [ <signature> <pubKey> <pubKey> ]
|
||||
```
|
||||
¿Por qué el duplicado? Porque es necesario comprobar los dos elementos de desbloqueo: la clave pública y la firma.
|
||||
|
||||
A continuación, `OP_HASH160` saca el resultado de la pila `<pubKey>`, lo codifica y vuelve a colocar el resultado en la pila.
|
||||
```
|
||||
Script: <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
|
||||
Running: <pubKey> OP_HASH160
|
||||
Stack: [ <signature> <pubKey> <pubKeyHash> ]
|
||||
```
|
||||
Luego, coloca el `<pubKeyHash>` que estaba en el script de bloqueo en la pila:
|
||||
```
|
||||
Script: OP_EQUALVERIFY OP_CHECKSIG
|
||||
Stack: [ <signature> <pubKey> <pubKeyHash> <pubKeyHash> ]
|
||||
```
|
||||
`OP_EQUALVERIFY` es efectivamente dos códigos de operación: `OP_EQUAL`, que saca dos elementos de la pila y empuja `True` o `False` en función de la comparación y `OP_VERIFY` que muestra ese resultado e inmediatamente marca la transacción como inválida si es `False`. (El capítulo 12 habla más sobre el uso de `OP_VERIFY` como condicional).
|
||||
|
||||
Suponiendo que los dos `<pubKeyHash>es` son iguales, obtendrá el siguiente resultado:
|
||||
```
|
||||
Script: OP_CHECKSIG
|
||||
Running: <pubKeyHash> <pubKeyHash> OP_EQUALVERIFY
|
||||
Stack: [ <signature> <pubKey> ]
|
||||
```
|
||||
En este punto, ha demostrado que el `<pubKey>` provisto en el `scriptSig` hashea a la dirección de Bitcoin en cuestión, por lo que sabe que el receptor conocía la clave pública. Pero también necesita demostrar el conocimiento de la clave privada, lo cual se hace con `OP_CHECKSIG`, lo que confirma que la firma del script de desbloqueo coincide con esa clave pública
|
||||
```
|
||||
Script:
|
||||
Running: <signature> <pubKey> OP_CHECKSIG
|
||||
Stack: [ True ]
|
||||
```
|
||||
El script ahora finaliza y, si tuvo éxito, la transacción puede volver a gastar el UTXO en cuestión.
|
||||
|
||||
### Use btcdeb para un ejemplo P2PKH
|
||||
|
||||
Probar transacciones reales de Bitcoin con `btcdeb` es un poco más complicado, porque necesita conocer la clave pública y la firma para que todo funcione, y generar esta última es algo difícil. Sin embargo, una forma de probar las cosas es dejar que Bitcoin haga el trabajo por usted generando una transacción que _desbloquearía_ un UTXO. Eso es lo que ha hecho anteriormente: generar la transacción para gastar el UTXO hizo que `bitcoin-cli` calcule la `<firma> `y la `<pubKey>`. Luego, mira la información de transacción sin procesar del UTXO para aprender el script de bloqueo, incluido el `<pubKeyHash>`
|
||||
|
||||
Usted puede poner juntos el script de bloqueo, la firma y la clave pública usando `btcdeb`, mostrando lo simple que es un script P2PKH.
|
||||
|
||||
```
|
||||
$ btcdeb '[304402201cc39005b076cb06534cd084fcc522e7bf937c4c9654c1c9dfba68b92cbab7d1022066f273178febc7a37568e2e9f4dec980a2e9a95441abe838c7ef64c39d85849c 0315a0aeb37634a71ede72d903acae4c6efa77f3423dcbcd6de3e13d9fd989438b OP_DUP OP_HASH160 41d83eaffbf80f82dee4c152de59a38ffd0b6021 OP_EQUALVERIFY OP_CHECKSIG]'
|
||||
btcdeb 0.2.19 -- type `btcdeb -h` for start up options
|
||||
unknown key ID 41d83eaffbf80f82dee4c152de59a38ffd0b6021: returning fake key
|
||||
valid script
|
||||
7 op script loaded. type `help` for usage information
|
||||
script | stack
|
||||
-------------------------------------------------------------------+-------------------------------------------------------------------
|
||||
304402201cc39005b076cb06534cd084fcc522e7bf937c4c9654c1c9dfba68b... |
|
||||
0315a0aeb37634a71ede72d903acae4c6efa77f3423dcbcd6de3e13d9fd989438b |
|
||||
OP_DUP |
|
||||
OP_HASH160 |
|
||||
41d83eaffbf80f82dee4c152de59a38ffd0b6021 |
|
||||
OP_EQUALVERIFY |
|
||||
OP_CHECKSIG |
|
||||
|
|
||||
|
|
||||
#0000 304402201cc39005b076cb06534cd084fcc522e7bf937c4c9654c1c9dfba68b92cbab7d1022066f273178febc7a37568e2e9f4dec980a2e9a95441abe838c7ef64c39d85849c
|
||||
```
|
||||
Ahora empuje la `<firma>` y la `<pubKey>` en la pila:
|
||||
|
||||
```
|
||||
btcdeb> step
|
||||
<> PUSH stack 304402201cc39005b076cb06534cd084fcc522e7bf937c4c9654c1c9dfba68b92cbab7d1022066f273178febc7a37568e2e9f4dec980a2e9a95441abe838c7ef64c39d85849c
|
||||
script | stack
|
||||
-------------------------------------------------------------------+-------------------------------------------------------------------
|
||||
0315a0aeb37634a71ede72d903acae4c6efa77f3423dcbcd6de3e13d9fd989438b | 304402201cc39005b076cb06534cd084fcc522e7bf937c4c9654c1c9dfba68b...
|
||||
OP_DUP |
|
||||
OP_HASH160 |
|
||||
41d83eaffbf80f82dee4c152de59a38ffd0b6021 |
|
||||
OP_EQUALVERIFY |
|
||||
OP_CHECKSIG |
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
#0001 0315a0aeb37634a71ede72d903acae4c6efa77f3423dcbcd6de3e13d9fd989438b
|
||||
btcdeb> step
|
||||
<> PUSH stack 0315a0aeb37634a71ede72d903acae4c6efa77f3423dcbcd6de3e13d9fd989438b
|
||||
script | stack
|
||||
-------------------------------------------------------------------+-------------------------------------------------------------------
|
||||
OP_DUP | 0315a0aeb37634a71ede72d903acae4c6efa77f3423dcbcd6de3e13d9fd989438b
|
||||
OP_HASH160 | 304402201cc39005b076cb06534cd084fcc522e7bf937c4c9654c1c9dfba68b...
|
||||
41d83eaffbf80f82dee4c152de59a38ffd0b6021 |
|
||||
OP_EQUALVERIFY |
|
||||
OP_CHECKSIG |
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
```
|
||||
Ahora ejecute un `OP_DUP` y un `OP_HASH` a la `<pubKey>`:
|
||||
|
||||
```
|
||||
#0002 OP_DUP
|
||||
btcdeb> step
|
||||
<> PUSH stack 0315a0aeb37634a71ede72d903acae4c6efa77f3423dcbcd6de3e13d9fd989438b
|
||||
script | stack
|
||||
-------------------------------------------------------------------+-------------------------------------------------------------------
|
||||
OP_HASH160 | 0315a0aeb37634a71ede72d903acae4c6efa77f3423dcbcd6de3e13d9fd989438b
|
||||
41d83eaffbf80f82dee4c152de59a38ffd0b6021 | 0315a0aeb37634a71ede72d903acae4c6efa77f3423dcbcd6de3e13d9fd989438b
|
||||
OP_EQUALVERIFY | 304402201cc39005b076cb06534cd084fcc522e7bf937c4c9654c1c9dfba68b...
|
||||
OP_CHECKSIG |
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
#0003 OP_HASH160
|
||||
btcdeb> step
|
||||
<> POP stack
|
||||
<> PUSH stack 41d83eaffbf80f82dee4c152de59a38ffd0b6021
|
||||
script | stack
|
||||
-------------------------------------------------------------------+-------------------------------------------------------------------
|
||||
41d83eaffbf80f82dee4c152de59a38ffd0b6021 | 41d83eaffbf80f82dee4c152de59a38ffd0b6021
|
||||
OP_EQUALVERIFY | 0315a0aeb37634a71ede72d903acae4c6efa77f3423dcbcd6de3e13d9fd989438b
|
||||
OP_CHECKSIG | 304402201cc39005b076cb06534cd084fcc522e7bf937c4c9654c1c9dfba68b...
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
```
|
||||
Empuja el `<pubKeyHash>` del script de bloqueo en la pila y lo verifica:
|
||||
```
|
||||
#0004 41d83eaffbf80f82dee4c152de59a38ffd0b6021
|
||||
btcdeb> step
|
||||
<> PUSH stack 41d83eaffbf80f82dee4c152de59a38ffd0b6021
|
||||
script | stack
|
||||
-------------------------------------------------------------------+-------------------------------------------------------------------
|
||||
OP_EQUALVERIFY | 41d83eaffbf80f82dee4c152de59a38ffd0b6021
|
||||
OP_CHECKSIG | 41d83eaffbf80f82dee4c152de59a38ffd0b6021
|
||||
| 0315a0aeb37634a71ede72d903acae4c6efa77f3423dcbcd6de3e13d9fd989438b
|
||||
| 304402201cc39005b076cb06534cd084fcc522e7bf937c4c9654c1c9dfba68b...
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
#0005 OP_EQUALVERIFY
|
||||
btcdeb> step
|
||||
<> POP stack
|
||||
<> POP stack
|
||||
<> PUSH stack 01
|
||||
<> POP stack
|
||||
script | stack
|
||||
-------------------------------------------------------------------+-------------------------------------------------------------------
|
||||
OP_CHECKSIG | 0315a0aeb37634a71ede72d903acae4c6efa77f3423dcbcd6de3e13d9fd989438b
|
||||
| 304402201cc39005b076cb06534cd084fcc522e7bf937c4c9654c1c9dfba68b...
|
||||
|
|
||||
| and_v(
|
||||
| sig(304402201cc39005b076cb06534cd084fcc522e7bf937c4c9654c1c...
|
||||
| and_v(
|
||||
| pk(0315a0aeb37634a71ede72d903acae4c6efa77f3423dcbcd6de3...
|
||||
| c:pk_h(030500000000000000000000000000000000000000000000...
|
||||
| )
|
||||
|
|
||||
| )
|
||||
|
|
||||
|
||||
```
|
||||
En este punto, todo lo que se requiere es el `OP_CHECKSIG`:
|
||||
```
|
||||
#0006 OP_CHECKSIG
|
||||
btcdeb> step
|
||||
error: Signature is found in scriptCode
|
||||
```
|
||||
|
||||
(Desafortunadamente, esta verificación puede o no funcionar en algún momento debido a los caprichos del código Bitcoin Core y btcdeb).
|
||||
|
||||
Como se muestra, un P2PKH es bastante simple: su protección proviene de la fuerza de su criptografía.
|
||||
|
||||
### Cómo buscar una clave pública y una firma a mano
|
||||
|
||||
¿Qué pasaría si quisiera generar la información necesaria de la `<signature>` y `<PubKey>` para desbloquear un UTXO usted mismo, sin tener que apoyarse en `bitcoin-cli` para crear una transacción?
|
||||
|
||||
Resulta que es bastante fácil obtener una `<pubKey>`. Solo necesita usar `getaddressinfo` para examinar la dirección donde se encuentra actualmente el UTXO:
|
||||
|
||||
```
|
||||
$ bitcoin-cli getaddressinfo mmX7GUoXq2wVcbnrnFJrGKsGR14fXiGbD9
|
||||
{
|
||||
"address": "mmX7GUoXq2wVcbnrnFJrGKsGR14fXiGbD9",
|
||||
"scriptPubKey": "76a91441d83eaffbf80f82dee4c152de59a38ffd0b602188ac",
|
||||
"ismine": true,
|
||||
"solvable": true,
|
||||
"desc": "pkh([f004311c/0'/0'/2']0315a0aeb37634a71ede72d903acae4c6efa77f3423dcbcd6de3e13d9fd989438b)#t3g5mjk9",
|
||||
"iswatchonly": false,
|
||||
"isscript": false,
|
||||
"iswitness": false,
|
||||
"pubkey": "0315a0aeb37634a71ede72d903acae4c6efa77f3423dcbcd6de3e13d9fd989438b",
|
||||
"iscompressed": true,
|
||||
"ischange": false,
|
||||
"timestamp": 1594835792,
|
||||
"hdkeypath": "m/0'/0'/2'",
|
||||
"hdseedid": "f058372260f71fea37f7ecab9e4c5dc25dc11eac",
|
||||
"hdmasterfingerprint": "f004311c",
|
||||
"labels": [
|
||||
""
|
||||
]
|
||||
}
|
||||
```
|
||||
Sin embargo, descubrir esa firma requiere comprender realmente los detalles de cómo se crean las transacciones de Bitcoin. Así que dejamos eso como un estudio avanzado para el lector: crear una transacción `bitcoin-cli` para "resolver" un UTXO es la mejor solución para eso por el momento.
|
||||
|
||||
## Resumen: Codificando un pago al hash de una clave pública
|
||||
|
||||
Enviar a una dirección P2PKH era relativamente fácil cuando solo usaba `bitcoin-cli`. Al examinar el script de Bitcoin subyacente, se ponen al descubierto las funciones criptográficas que estaban implícitas en la financiación de esa transacción: cómo se desbloqueó el UTXO con una firma y una clave pública.
|
||||
|
||||
## ¿Que sigue?
|
||||
|
||||
Continúe "Introduciendo los scripts de Bitcoin" con [§9.5: Codificando una P2WPKH](09_5_Codificando_una_P2WPKH.md).
|
123
es/09_5_Codificando_una_P2WPKH.md
Normal file
123
es/09_5_Codificando_una_P2WPKH.md
Normal file
@ -0,0 +1,123 @@
|
||||
# 9.5: Codificando una P2WPKH
|
||||
|
||||
> :information_source: **NOTA:** Esta sección se ha agregado recientemente al curso y es un borrador inicial que aún puede estar pendiente de revisión. Lectura con advertencias.
|
||||
|
||||
Las UXTO's P2PKH están bien para explicar la forma fundamental en que funcionan los scripts de Bitcoin, pero ¿qué pasa con los scripts nativos de SegWit P2WPKH, que se están convirtiendo cada vez más en la mayoría de las transacciones de Bitcoin? Resulta que las direcciones P2WPKH no usan scripts de Bitcoin como lo hacen las direcciones tradicionales de Bitcoin, por lo que esta sección es realmente una digresión hacia el scripting de este capítulo, aunque es importante porque describe la otra forma principal en la cual bitcoin puede ser enviado.
|
||||
|
||||
## Vea un script P2WPKH
|
||||
|
||||
Es bastante fácil ver cómo se ve un script P2WPKH. La siguiente transacción sin procesar se creó gastando un UXTO P2WPKH y luego enviando el dinero a una dirección de cambio P2WPKH, tal como hicimos con una dirección heredada en [§9.1](09_1_Entendiendo_la_base_de_las_Transacciones.md).
|
||||
```
|
||||
$ bitcoin-cli -named decoderawtransaction hexstring=$signedtx
|
||||
{
|
||||
"txid": "bdf8f12768a9870d41ac280f8bb4f8ecd9d2fa66fffc75606811f5751c17cb3a",
|
||||
"hash": "ec09c84cae48694bec7fd3461b3c5b38a76829c56e9d876037bf2484d443174b",
|
||||
"version": 2,
|
||||
"size": 191,
|
||||
"vsize": 110,
|
||||
"weight": 437,
|
||||
"locktime": 0,
|
||||
"vin": [
|
||||
{
|
||||
"txid": "3f5417bc7a3a4144d715f3f006d35ea2b405f06091cbb9ce492e04ccefe02b18",
|
||||
"vout": 0,
|
||||
"scriptSig": {
|
||||
"asm": "",
|
||||
"hex": ""
|
||||
},
|
||||
"txinwitness": [
|
||||
"3044022064f633ccfc4e937ef9e3edcaa9835ea9a98d31fbea1622c1d8a38d4e7f8f6cb602204bffef45a094de1306f99da055bd5a603a15c277a59a48f40a615aa4f7e5038001",
|
||||
"03839e6035b33e37597908c83a2f992ec835b093d65790f43218cb49ffe5538903"
|
||||
],
|
||||
"sequence": 4294967295
|
||||
}
|
||||
],
|
||||
"vout": [
|
||||
{
|
||||
"value": 0.00090000,
|
||||
"n": 0,
|
||||
"scriptPubKey": {
|
||||
"asm": "0 92a0db923b3a13eb576a40c4b35515aa30206cba",
|
||||
"hex": "001492a0db923b3a13eb576a40c4b35515aa30206cba",
|
||||
"reqSigs": 1,
|
||||
"type": "witness_v0_keyhash",
|
||||
"addresses": [
|
||||
"tb1qj2sdhy3m8gf7k4m2grztx4g44gczqm96y6sszv"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Probablemente hay dos cosas sorprendentes aquí: (1) No hay `scriptSig` para desbloquear la transacción anterior; y (2) el `scriptPubKey` para bloquear la nueva transacción es justo 0 92a0db923b3a13eb576a40c4b35515aa30206cb.
|
||||
|
||||
Eso es, simplemente, ¡porque P2WPKH funciona de manera diferente!
|
||||
|
||||
## Comprenda una transacción P2WPKH
|
||||
|
||||
Una transacción P2WPKH contiene la misma información que una transacción P2PKH clásica, aunque la coloca en lugares extraños y no dentro de un script Bitcoin tradicional, y ese es el punto exacto de las transacciones SegWit, el hecho de extraer la información del "testigo", que sirve para indicar las claves públicas y las firmas, fuera de la transacción para admitir un cambio en el tamaño del bloque.
|
||||
|
||||
Pero, si observa con atención, verá que el vacío `scriptSig` ha sido reemplazado por dos entradas en una nueva sección `txinwitness`. Si examina sus tamaños y formato, deberían parecerle familiares: son una firma y una clave pública. Del mismo modo, si mira en el `scriptPubKey`, verá que está compuesto por un 0 (en realidad: `OP_0`, es el número de versión de SegWit) y otro número largo, que es el hash de clave pública.
|
||||
|
||||
|
||||
Aquí hay una comparación de nuestros dos ejemplos:
|
||||
| Type | PubKeyHash | PubKey | Signature |
|
||||
|----------------|----------|-------------|---------|
|
||||
| SegWit | 92a0db923b3a13eb576a40c4b35515aa30206cba | 03839e6035b33e37597908c83a2f992ec835b093d65790f43218cb49ffe5538903 | 3044022064f633ccfc4e937ef9e3edcaa9835ea9a98d31fbea1622c1d8a38d4e7f8f6cb602204bffef45a094de1306f99da055bd5a603a15c277a59a48f40a615aa4f7e5038001 |
|
||||
| non-SegWit | 06b5c6ba5330cdf738a2ce91152bfd0e71f9ec39 | 0315a0aeb37634a71ede72d903acae4c6efa77f3423dcbcd6de3e13d9fd989438b | 04402201cc39005b076cb06534cd084fcc522e7bf937c4c9654c1c9dfba68b92cbab7d1022066f273178febc7a37568e2e9f4dec980a2e9a95441abe838c7ef64c39d85849c |
|
||||
|
||||
Entonces, ¿cómo funciona esto? Depende de que el código antiguo interprete esto como una transacción válida y el nuevo código sepa verificar la nueva información del "testigo".
|
||||
|
||||
### Lea un script de SegWit en una máquina antigua
|
||||
|
||||
Si un nodo no ha sido actualizado para admitir SegWit, entonces ejecuta el truco habitual de concatenar el `scriptSig` y el `scriptPubKey`. Esto produce: `0 92a0db923b3a13eb576a40c4b35515aa30206cba` (porque solo hay un `scriptPubKey`). Ejecutar eso producirá una pila con todo lo que contiene en orden inverso:
|
||||
|
||||
```
|
||||
$ btcdeb '[0 92a0db923b3a13eb576a40c4b35515aa30206cba]'
|
||||
btcdeb 0.2.19 -- type `btcdeb -h` for start up options
|
||||
miniscript failed to parse script; miniscript support disabled
|
||||
valid script
|
||||
2 op script loaded. type `help` for usage information
|
||||
script | stack
|
||||
-----------------------------------------+--------
|
||||
0 |
|
||||
92a0db923b3a13eb576a40c4b35515aa30206cba |
|
||||
#0000 0
|
||||
btcdeb> step
|
||||
<> PUSH stack
|
||||
script | stack
|
||||
-----------------------------------------+--------
|
||||
92a0db923b3a13eb576a40c4b35515aa30206cba | 0x
|
||||
#0001 92a0db923b3a13eb576a40c4b35515aa30206cba
|
||||
btcdeb> step
|
||||
<> PUSH stack 92a0db923b3a13eb576a40c4b35515aa30206cba
|
||||
script | stack
|
||||
-----------------------------------------+-----------------------------------------
|
||||
| 92a0db923b3a13eb576a40c4b35515aa30206cba
|
||||
| 0x
|
||||
```
|
||||
|
||||
Los scripts de Bitcoin se consideran exitosos si hay algo en la pila y no es cero, por lo que los scripts de SegWit tienen éxito automáticamente en los nodos antiguos siempre que el `scriptPubKey` se cree correctamente con un hash de clave pública distinto de cero. Esto se llama una transacción "cualquiera puede gastar", porque los nodos antiguos verificaron que eran correctos sin necesidad de firmas.
|
||||
|
||||
> :book: ***¿Porqué los nodos antiguos no pueden robar UTXOs SegWit ?*** SegWit se habilitó en la red Bitcoin cuando el 95% de los mineros señalaron que estaban listos para comenzar a usarlo. Eso significa que solo el 5% de los nodos en ese momento podrían haber registrado transacciones SegWit que _cualquiera pueda gastar_ como válidas sin pasar por el trabajo adecuado de verificar el `txinwitness`. Si incorporaron incorrectamente un UTXO inválido que _cualquiera puede gastar_ en un bloque, el otro 95% de los nodos se negaría a validar ese bloque, por lo que rápidamente quedaría huérfano en lugar de agregarse a la cadena de bloques "principal". (Ciertamente, el 51% de los nodos podría optar por dejar de interpretar correctamente las transacciones de SegWit, pero el 51% de los nodos puede hacer cualquier cosa en una red de consenso como una cadena de bloques)
|
||||
|
||||
Debido a que los nodos antiguos siempre ven los scripts de SegWit como correctos, siempre los verificarán, incluso sin comprender su contenido.
|
||||
|
||||
### Lea un script de SegWit en una máquina nueva
|
||||
|
||||
Una máquina que entiende cómo funciona SegWit hace exactamente las mismas cosas que haría con un antiguo script P2PKH, pero no usa un script per se: simplemente sabe que necesita hacer un hash de la clave pública en el `txinwitness`, compruébelo contra la clave hasheada después del número de versión en el `scriptPubKey` y luego ejecuta `OP_CHECKSIG` en la firma y la clave pública en el `txinwitness`.
|
||||
|
||||
Entonces, es otra forma de hacer lo mismo, pero sin tener los scripts integrados en las transacciones. (En su lugar, el proceso está integrado en el software del nodo).
|
||||
|
||||
## Resumen: Codificando un pago a un hash de una clave pública Witness
|
||||
|
||||
En gran medida usted no codifica un script P2WPKH. En cambio, Bitcoin Core crea la transacción de una manera diferente, colocando la información del testigo en un lugar diferente en lugar del tradicional `scriptSig`. Eso significa que los P2WPKH son una digresión de los scripts de Bitcoin de esta parte del libro, porque son una expansión de Bitcoin que se aleja del scripting tradicional.
|
||||
|
||||
Sin embargo, SegWit también fue un uso inteligente de los scripts de Bitcoin. Sabiendo que habría nodos que no se actualizarían y necesitarían ser compatibles con versiones anteriores, los desarrolladores crearon el formato P2WPKH para que generara un script que siempre se validara en los nodos antiguos (mientras que ese script proporcionaba información a los nuevos nodos en la forma de un número de versión y una clave pública hasheada).
|
||||
|
||||
Cuando está programando desde la línea de comandos, fundamentalmente no tiene que preocuparse por esto, aparte de saber que no encontrará scripts tradicionales en transacciones SegWit sin procesar (que, nuevamente, era el punto).
|
||||
|
||||
## ¿Que sigue?
|
||||
|
||||
Continúe "Codificando Bitcoin" con el [Capítulo 10: Embebiendo Bitcoin Scripts en Transacciones P2SH](10_0_Embebiendo_Bitcoin_Scripts_en_Transacciones_P2SH.md).
|
26
es/10_0_Embebiendo_Bitcoin_Scripts_en_Transacciones_P2SH.md
Normal file
26
es/10_0_Embebiendo_Bitcoin_Scripts_en_Transacciones_P2SH.md
Normal file
@ -0,0 +1,26 @@
|
||||
# Capítulo 10: Incrustación de Bitcoin Scripts en Transacciones P2SH
|
||||
|
||||
Bitcoin Script desciende varios niveles de abstracción, lo que le permite controlar minusciosamente las condiciones de canje de los fondos de Bitcoin. Pero, ¿cómo incorpora realmente esos Bitcoin Scripts en las transacciones que ha estado construyendo hasta la fecha? La respuesta es un nuevo tipo de transacción de Bitcoin, el P2SH.
|
||||
|
||||
## Objetivos de Este Capítulo
|
||||
|
||||
Después de trabajar en este capítulo, un desarrollador podrá:
|
||||
|
||||
* Diseñar una Transacción P2SH
|
||||
* Aplicar un Bitcoin Script P2SH
|
||||
|
||||
Los objetivos de apoyo incluyen la capacidad de:
|
||||
|
||||
* Comprender el Script P2SH
|
||||
* Comprender el Script Multifirma
|
||||
* Comprender las Diversas Variaciones de los Scripts de Segwit
|
||||
* Comprender Cómo Gastar Fondos Enviados a un P2SH
|
||||
|
||||
## Tabla de Contenido
|
||||
|
||||
* [Sección Uno: Comprender la Base de P2SH](10_1_Entendiendo_la_Base_de_P2SH.md)
|
||||
* [Sección Dos: Construyendo la Estructura de P2SH](10_2_Construyendo_la_Estructura_de_P2SH.md)
|
||||
* [Sección Tres: Ejecución de un Bitcoin Script con P2SH](10_3_Ejecutando_un_Script_Bitcoin_con_P2SH.md)
|
||||
* [Sección Cuatro: Creación de un Script de Multifirma](10_4_Codificando_una_Multifirma.md)
|
||||
* [Sección Cinco: Creación de un Script de Segwit](10_5_Codificando_un_Script_Segwit.md)
|
||||
* [Sección Seis: Gasto en Transacciones P2SH](10_6_Gastando_una_Transaccion_P2SH.md)
|
99
es/10_1_Entendiendo_la_Base_de_P2SH.md
Normal file
99
es/10_1_Entendiendo_la_Base_de_P2SH.md
Normal file
@ -0,0 +1,99 @@
|
||||
# 10.1: Entendiendo la Base de P2SH
|
||||
|
||||
Sabe que los scripts de Bitcoin se pueden usar para controlar el canje de UTXOs. El siguiente paso es crear sus propios scripts ... pero eso requiere una técnica muy específica.
|
||||
|
||||
## Conozca los Estándares de Bitcoin
|
||||
|
||||
Aquí está la trampa para usar los scripts de Bitcoin: por razones de seguridad, la mayoría de los nodos de Bitcoin solo aceptarán seis tipos de transacciones de Bitcoin "estándar".
|
||||
|
||||
* __Pagar a Clave Pública (Pay to Public Key, P2PK)__ — Una transacción antigua y obsoleta (`<pubKey> OP_CHECKSIG`) que ha sido reemplazada por la mejor seguridad de P2PKH.
|
||||
* __Pagar al Testigo del Hash de la Clave Pública (Pay to Public Key Hash, P2PKH)__ — Una transacción (`OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG`) que paga el hash de una clave pública.
|
||||
* __Pagar Para Ser Testigo de Hash de Clave Pública (Pay to Witness Public Key Hash, P2WPKH)__ — El tipo más nuevo de transacción de clave pública. Es solo (`OP_0 <pubKeyHash`) porque depende del consenso del minero para funcionar, como se describe en [§9.5](09_5_Codificando_una_P2WPKH.md).
|
||||
* __Multifirma (Multisig)__ — Una transacción para un grupo de claves, como se explica con más detalle en [§10.4: Codificando una Multifirma](10_4_Codificando_una_Multifirma.md).
|
||||
* __Datos Nulos (Null Data)__ — Una transacción invencible (`OP_RETURN Data`).
|
||||
* __Pagar a Script Hash (Pay to Script Hash, P2SH)__ — Una transacción que paga a un script específico, como se explica con más detalle aqui.
|
||||
|
||||
Entonces, ¿cómo se escribe un script de Bitcoin más complejo? La respuesta está en ese último tipo de transacción estándar, el P2SH. Puede poner cualquier tipo de script largo y complejo en una transacción P2SH, y siempre que siga las reglas estándar para incrustar su script y canjear los fondos, obtendrá todos los beneficios de Bitcoin Scripting.
|
||||
|
||||
> :warning: **ADVERTENCIA DE VERSIÓN:** Los scripts P2SH arbitrarios solo se convirtieron en estándar a partir de Bitcoin Core 0.10.0. Antes de eso, solo se permitían P2SH Multifirmas.
|
||||
|
||||
## Entender el P2SH Script
|
||||
|
||||
Ya vio una transacción P2SH cuando creó una firma múltiple en [§6.1: Envío de una Transacción a una Multifirma](06_1_Enviando_una_Transaccion_a_una_Direccion_Multifirma.md). Aunque multifirma es uno de los tipos de transacciones estándar, `bitcoin-cli` simplifica el uso de sus multifirmas al incrustarlas en transacciones P2SH, como se describe con más detalle en [§10.4: Codificando una Multifirma](10_4_Codificando_una_Multifirma.md).
|
||||
|
||||
Entonces, veamos una vez más el `scriptPubKey` de ese P2SH multifirma:
|
||||
```
|
||||
"scriptPubKey": {
|
||||
"asm": "OP_HASH160 a5d106eb8ee51b23cf60d8bd98bc285695f233f3 OP_EQUAL",
|
||||
"hex": "a914a5d106eb8ee51b23cf60d8bd98bc285695f233f387",
|
||||
"reqSigs": 1,
|
||||
"type": "scripthash",
|
||||
"addresses": [
|
||||
"2N8MytPW2ih27LctLjn6LfLFZZb1PFSsqBr"
|
||||
]
|
||||
}
|
||||
```
|
||||
El script de bloqueo es bastante simple: `OP_HASH160 a5d106eb8ee51b23cf60d8bd98bc285695f233f3 OP_EQUAL`. Como de costumbre, hay una gran cantidad de datos en el medio. Este es un hash de otro script de bloqueo oculto (`redeemScript`) que solo se revelará cuando se canjeen los fondos. En otras palabras, el script de bloqueo estándar para una dirección P2SH es: `OP_HASH160 <redeemScriptHash> OP_EQUAL`.
|
||||
|
||||
> :book: ***¿Qué es un redeemScript?*** Cada transacción P2SH lleva la huella digital de un script de bloqueo oculto dentro de ella como un hash de 20 bytes. Cuando se canjea una transacción P2SH, el `redeemScript` completo (sin hash) se incluye como parte del `scriptSig`. Bitcoin se asegurará de que el `redeemScript` coincida con el hash; luego ejecuta el `redeemScript` para ver si los fondos se pueden gastar (o no).
|
||||
|
||||
¡Uno de los elementos interesantes de las transacciones P2SH es que ni el remitente ni la cadena de bloques saben realmente qué es el `redeemScript`! Un remitente simplemente envía a una dirección P2SH estandarizada marcada con un prefijo "2" y no se preocupa por cómo el destinatario va a recuperar los fondos al final.
|
||||
|
||||
> :link: **TESTNET vs MAINNET:** en testnet, el prefijo para las direcciones P2SH es `2`, mientras que en mainnet, es `3`.
|
||||
|
||||
## Entender Cómo Crear un Script P2SH
|
||||
|
||||
Dado que el script de bloqueo visible para una transacción P2SH es tan simple, crear una transacción de este tipo también es bastante simple. En teoria. Todo lo que necesita hacer es crear una transacción cuyo script de bloqueo incluya un hash de 20 bytes del `redeemScript`. Ese hash se realiza con el estándar de Bitcoin `OP_HASH160`.
|
||||
|
||||
> :book: ***Qué es OP_HASH160?*** La operación hash estándar para Bitcoin realiza un hash SHA-256, luego un HASH RIPEMD-160.
|
||||
|
||||
En general, se requieren cuatro pasos:
|
||||
|
||||
1. Cree un script de bloqueo arbitrario con Bitcoin Script.
|
||||
2. Cree una versión serializada de ese script de bloqueo.
|
||||
3. Realice un hash SHA-256 en esos bytes serializados.
|
||||
4. Realice un hash RIPEMD-160 en los resultados de ese hash SHA-256.
|
||||
|
||||
Cada uno de esos pasos, por supuesto, requiere algo de trabajo por sí solo, y algunos de ellos pueden ser bastante intrincados. La buena noticia es que realmente no tiene que preocuparse por por ellos, porque son lo sucifientemente complejos como para que normalmente tenga una API que se encargue de todo por usted.
|
||||
|
||||
Entonces, por ahora, solo le proporcionaremos una descripción general, para que comprenda la metodología general. En [§10.2: Construyendo la Estructura de P2SH](10_2_Construyendo_la_Estructura_de_P2SH.md) proporcionaremos una mirada más profunda a la creación de scripts, en caso de que alguna vez quiera comprender las entrañas de este proceso.
|
||||
|
||||
## Comprender Cómo Enviar una Transacción de Script P2SH
|
||||
|
||||
Entonces, ¿cómo envía realmente su transacción P2SH? Nuevamente, la teoría es muy simple:
|
||||
|
||||
1. Incruste su hash en un script `OP_HASH160 <redeemScriptHash> OP_EQUAL`.
|
||||
2. Traducir eso a código hexadecimal.
|
||||
3. Usa ese hexademical como su `scriptPubKey`.
|
||||
4. Crea el resto de la transacción.
|
||||
|
||||
Desafortunadamente, este es otro lugar donde necesitará recurrir a las API, en gran parte porque `bitcoin-cli` no proporciona ningún soporte para la creación de transacciones P2SH. (Puede redimirlos muy bien.)
|
||||
|
||||
## Entender Cómo Desbloquear una Transacción de Script P2SH
|
||||
|
||||
El truco para canjear una transacción P2SH es que el destinatario debe haber guardado el script de bloqueo serializado secreto que fue codificado para crear la dirección P2SH. Esto se llama `redeemScript` porque es lo que el destinatario necesita para canjear sus fondos.
|
||||
|
||||
Un `scriptSig` de desbloqueo para una transacción P2SH se forma como: `... data ... <redeemScript>`. Los `datos` deben ser _solo_ datos que se insertan en la pila, no operadores. ([BIP 16](https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki) los llama firmas, pero eso no es un requisito real.)
|
||||
|
||||
> :warning: **ADVERTENCIA:** Aunque las firmas no son un requisito, un script P2SH en realidad no es muy seguro si no requiere al menos una firma en sus entradas. Las razones de esto se describen en [§13.1: Escritura de Scripts de Rompecabezas](13_1_Escribiendo_Puzzle_Scripts.md).
|
||||
|
||||
Cuando se canjea un UTXO, se ejecuta en dos rondas de verificación:
|
||||
|
||||
1. Primero, el `redeemScript` en el `scriptSig` es codificado y se compara con el script codificado en el `scriptPubKey`.
|
||||
2. Si coinciden, comienza una segunda ronda de verificación.
|
||||
3. En segundo lugar, el `redeemScript` se ejecuta utilizando los datos anteriores que se insertaron en la pila.
|
||||
4. Si esa segunda ronda de verificación _también_ tiene éxito, el UTXO se desbloquea.
|
||||
|
||||
Si bien no puede crear fácilmente una transacción P2SH sin una API, debería poder canjear fácilmente una transacción P2SH con `bitcoin-cli`. De hecho, ya lo hizo en [§6.2: Envío de una Transacción a un Multifirma](06_2_Gastando_una_Transaccion_con_una_Direccion_Multifirma.md). El proceso exacto se describe en [§10.6: Gasto de una Transacción P2SH](10_6_Gastando_una_Transaccion_P2SH.md), una vez que hayamos terminado con todas las complejidades de la creación de transacciones P2SH.
|
||||
|
||||
> :warning: **ADVERTENCIA:** Puede crear una transacción perfectamente válida con un código redeemScript correctamente codificado, pero si el código redeemScript no se ejecuta o no se ejecuta correctamente, sus fondos se perderán para siempre. Por eso es tan importante probar sus secuencias de comandos, como se explíca en [§9.3: Prueba de una Bitcoin Script](09_3_Probando_un_Script_Bitcoin.md).
|
||||
|
||||
## Resumen: Comprensión de la Base de P2SH
|
||||
|
||||
Los scripts arbitrarios de Bitcoin no son estándar en Bitcoin. Sin embargo, puede incorporarlos en transacciones estándar utilizando el tipo de dirección P2SH. Simplemente aplica un hash a su script como parte del script de bloqueo, luego lo revela y lo ejecuta como parte del script de desbloqueo. Siempre que pueda satisfacer el `redeemScript`, el UTXO se puede gastar.
|
||||
|
||||
> :fire: ***¿Cuál es el Poder de P2SH?*** Ya conoce el poder de Bitcoin Script, el cual le permite crear contratos inteligentes más complejos de todo tipo. P2SH es lo que realmente libera ese poder al permitirle incluir un script de Bitcoin arbitrario en las transacciones estándar de Bitcoin.
|
||||
|
||||
## Que Sigue?
|
||||
|
||||
Continúe "Incrustando Bitcoin Scripts" con [§10.2: Construyendo la Estructura de P2SH](10_2_Construyendo_la_Estructura_de_P2SH.md).
|
180
es/10_2_Construyendo_la_Estructura_de_P2SH.md
Normal file
180
es/10_2_Construyendo_la_Estructura_de_P2SH.md
Normal file
@ -0,0 +1,180 @@
|
||||
# 10.2: Construyendo la Estructura de P2SH
|
||||
|
||||
En la sección anterior, analizamos la teoría de cómo crear transacciones P2SH para contener Scripts de Bitcoin. La práctica real de hacerlo es _mucho más difícil_, pero en aras de la exhaustividad, lo veremos aquí. Probablemente esto no sea algo que haría sin una API, por lo que si se vuelve demasiado intimidante, tenga en cuenta que voleremos a los scripts prístinos y de alto nivel en un momento.
|
||||
|
||||
## Crear una Script de Bloqueo
|
||||
|
||||
Cualquier transacción P2SH comienza con un script de bloqueo. Este es el tema de los capítulos 9 y 11-12. Puede utilizar cualquiera de los métodos de Bitcoin Script que se describen en el mismo para crear cualquier tipo de script de bloqueo, siempre que el `redeemScript` serializado resultante sea de 520 bytes o menos.
|
||||
|
||||
> :book: ***¿Por qué los scripts P2SH están limitados a 520 bytes?*** Como ocurre con muchas cosas en Bitcoin, la respuesta es la compatibilidad con versiones anteriores: la nueva funcionalidad debe construirse constantemente dentro de las viejas limitaciones del sistema. En este caso, 520 bytes es el máximo que se puede insertar en la pila a la vez. Dado que todo el código de canje se incluye en la pila como parte del proceso de canje alcanza ese límite.
|
||||
|
||||
## Serializar un Script de Bloqueo de la Manera Difícil
|
||||
|
||||
Después de crear un script de bloqueo, debe serializarlo antes de que pueda ingresarse en Bitcoin. Este es un proceso de dos partes. Primero, debe convertirlo en código hexadecimal, luego debe transformar ese hexadecimal en binario.
|
||||
|
||||
### Crea el Código Hex
|
||||
|
||||
Crear el código hexadecimal necesario para serializar un script es una traducción simple y algo lo suficientemente complejo como para ir más allá de cualquier script de shell que probablemente escriba. Este paso es una de las principales razones por las que necesita una API para crear transacciones P2SH.
|
||||
|
||||
Puede crear un código hexadecimal siguiendo el script de bloqueo y convirtiendo cada elemento en un comando hexadecimal de un byte, posiblemente seguido de datos adicionales, según la guía de la [página de Bitcoin Wiki Script](https://en.bitcoin.it/wiki/Script):
|
||||
|
||||
* Los operadores se traducen al byte correspondiente para ese código de operación
|
||||
* Las constantes 1-16 se traducen a códigos de operación 0x51 a 0x61 (OP_1 a OP_16)
|
||||
* La constante -1 se traduce a código de operación 0x4f (OP_1NEGATE)
|
||||
* Otras constantes están precedidas por los códigos de operación 0x01 a 0x4e (OP_PUSHDATA, con el número que especifica cuántos bytes insertar)
|
||||
* Los enteros se traducen a hexadecimal usando notación little-endian signed-magnitude.
|
||||
|
||||
### Traducir Enteros
|
||||
|
||||
Los números enteros son la parte más problemática de la traducción de un script de bloqueo.
|
||||
|
||||
Primero, debe verificar que su número esté entre -2147483647 y 2147483647, el rango de enteros de cuatro bytes cuando se usa el byte más significativo para firmar.
|
||||
|
||||
En segundo lugar, debe traducir el valor decimal a haxadecimal y rellenarlo con un número par de dígitos. Esto se puede hacer con el comando `printf`:
|
||||
```
|
||||
$ integer=1546288031
|
||||
$ hex=$(printf '%08x\n' $integer | sed 's/^\(00\)*//')
|
||||
$ echo $hex
|
||||
5c2a7b9f
|
||||
```
|
||||
En tercer lugar, debe agregar un byte inicial adicional de `00` si el dígito superior es "8" o más, para que el número no se interprete como negativo.
|
||||
```
|
||||
$ hexfirst=$(echo $hex | cut -c1)
|
||||
$ [[ 0x$hexfirst -gt 0x7 ]] && hex="00"$hex
|
||||
```
|
||||
En cuatro lugar, debe traducir el hex de big-endian (el byte menos significativo al final) a little-endian (el byte menos significativo primero). Puede hacer esto con el comando `tac`:
|
||||
```
|
||||
$ lehex=$(echo $hex | tac -rs .. | echo "$(tr -d '\n')")
|
||||
$ echo $lehex
|
||||
9f7b2a5c
|
||||
```
|
||||
Además, siempre necesita saber el tamaño de cualquier dato que coloque en la pila, de modo que pueda precederlo con el código de operación adecuado. Puede recordar que cada dos caracteres hexadecimales es un byte. O puede user `echo -n` canalizado a `wc -c`, y dividirlo por la mitad:
|
||||
```
|
||||
$ echo -n $lehex | wc -c | awk '{print $1/2}'
|
||||
4
|
||||
```
|
||||
Con todo ese procidimiento complejo, sabría que podría traducir el entero 1546288031 en un opcode `04` (para insertar cuatro bytes en la pila) seguido de `9f7b2a5c` (la representación hex little-endian de 1546288031).
|
||||
|
||||
Si en cambio tuviera un número negativo, necesitaría (1) hacer sus cáclulos en el valor absoluto del número, luego (2) bit a bit o 0x80 para su resultado final de little-endian result. Por ejemplo, `9f7b2a5c`, que es 1546288031, se convertiría en `9f7b2adc`, que es -1546288031:
|
||||
```
|
||||
$ neglehex=$(printf '%x\n' $((0x$lehex | 0x80)))
|
||||
$ echo $neglehex
|
||||
9f7b2adc
|
||||
```
|
||||
### Transformar el Hexadecimal en Binario
|
||||
|
||||
Para completar su serialización, traduzca el código hexadecimal a binario. En la línea de comando, esto solo requiere una simple invocación de `xxd -r -p`. Sin embargo, es probable que desee hacerlo como parte de una única tubería que también aplicará un hash al script ...
|
||||
|
||||
## Ejecute el Script de Conversión de Enteros
|
||||
|
||||
Un script complejo para cambiar un entero entre -2147483647 y 2147483647 a una representación de little-endian signed-magnitude se puede encontrar en el [directorio de código src](../src/10_2_integer2lehex.sh). Puede descargarlo como `integer2lehex.sh`.
|
||||
|
||||
> :warning: **ADVERTENCIA:** Esta script no se ha comprobado de forma exhaustiva. Se va a usarlo para crear scripts de bloqueo reales, debe asegurarse de verificar y probar sus resultados.
|
||||
|
||||
Asegúrese de que los permisos del script sean correctos:
|
||||
```
|
||||
$ chmod 755 integer2lehex.sh
|
||||
```
|
||||
Luego puede ejecutar el script de la siguiente manera:
|
||||
```
|
||||
$ ./integer2lehex.sh 1546288031
|
||||
Integer: 1546288031
|
||||
LE Hex: 9f7b2a5c
|
||||
Length: 4 bytes
|
||||
Hexcode: 049f7b2a5c
|
||||
|
||||
$ ./integer2lehex.sh -1546288031
|
||||
Integer: -1546288031
|
||||
LE Hex: 9f7b2adc
|
||||
Length: 4 bytes
|
||||
Hexcode: 049f7b2adc
|
||||
```
|
||||
|
||||
## Analizar un P2SH Multifirma
|
||||
|
||||
Para comprender mejor este proceso, aplicaremos ingeniería inversa al P2SH multifirma que creamos en [§6.1: Envío de una Transacción a un Multifirma](06_1_Enviando_una_Transaccion_a_una_Direccion_Multifirma.md). Eche un vistazo al `redeemScript` que usó, que ahora sabe que es la versión serializada en hex del script de bloqueo:
|
||||
```
|
||||
522102da2f10746e9778dd57bd0276a4f84101c4e0a711f9cfd9f09cde55acbdd2d1912102bfde48be4aa8f4bf76c570e98a8d287f9be5638412ab38dede8e78df82f33fa352ae
|
||||
```
|
||||
Puede traducir esto de nuevo a Script a mano usando la [página de Bitcoin Wiki Script](https://en.bitcoin.it/wiki/Script) como referencia. Solo mire un byte (dos caracteres hex) de datos a la vez, a menos que un comando OP_PUSHDATA le indique que mire más (un opcode en el rango de 0x01 a 0x4e).
|
||||
|
||||
Todo el guión se dividirá de la siguiente manera:
|
||||
```
|
||||
52 / 21 / 02da2f10746e9778dd57bd0276a4f84101c4e0a711f9cfd9f09cde55acbdd2d191 / 21 / 02bfde48be4aa8f4bf76c570e98a8d287f9be5638412ab38dede8e78df82f33fa3 / 52 / ae
|
||||
```
|
||||
Esto es lo que significan las partes individuales:
|
||||
|
||||
* 0x52 = OP_2
|
||||
* 0x21 = OP_PUSHDATA 33 bytes (hex: 0x21)
|
||||
* 0x02da2f10746e9778dd57bd0276a4f84101c4e0a711f9cfd9f09cde55acbdd2d191 = los siguientes 33 bytes (public-key hash)
|
||||
* 0x21 = OP_PUSHDATA 33 bytes (hex: 0x21)
|
||||
* 0x02bfde48be4aa8f4bf76c570e98a8d287f9be5638412ab38dede8e78df82f33fa3 = los siguientes 33 bytes (public-key hash)
|
||||
* 0x52 = OP_2
|
||||
* 0xae = OP_CHECKMULTISIG
|
||||
|
||||
En otras palabras, ese `redeemScript` era una traducción de `2 02da2f10746e9778dd57bd0276a4f84101c4e0a711f9cfd9f09cde55acbdd2d191 02bfde48be4aa8f4bf76c570e98a8d287f9be5638412ab38dede8e78df82f33fa3 2 OP_CHECKMULTISIG`. Regresaremos a este script en [§10.4: Creación de una Script Multifirma](10_4_Codificando_una_Multifirma.md) cuando detallemos exactamente cómo funcionan las multifirmas dentro del paradigma P2SH.
|
||||
|
||||
Si desea una mano mecánica con este tipo de traducción en el futuro, puede usar `bitcoin-cli decodescript`:
|
||||
```
|
||||
$ bitcoin-cli -named decodescript hexstring=522102da2f10746e9778dd57bd0276a4f84101c4e0a711f9cfd9f09cde55acbdd2d1912102bfde48be4aa8f4bf76c570e98a8d287f9be5638412ab38dede8e78df82f33fa352ae
|
||||
{
|
||||
"asm": "2 02da2f10746e9778dd57bd0276a4f84101c4e0a711f9cfd9f09cde55acbdd2d191 02bfde48be4aa8f4bf76c570e98a8d287f9be5638412ab38dede8e78df82f33fa3 2 OP_CHECKMULTISIG",
|
||||
"reqSigs": 2,
|
||||
"type": "multisig",
|
||||
"addresses": [
|
||||
"mmC2x2FoYwBnVHMPRUAzPYg6WDA31F1ot2",
|
||||
"mhwZFJUnWqTqy4Y7pXVum88qFtUnVG1keM"
|
||||
],
|
||||
"p2sh": "2N8MytPW2ih27LctLjn6LfLFZZb1PFSsqBr",
|
||||
"segwit": {
|
||||
"asm": "0 6fe9f451ccedb8e4090b822dcad973d0388a37b4c89fd1aed485110adecab2a9",
|
||||
"hex": "00206fe9f451ccedb8e4090b822dcad973d0388a37b4c89fd1aed485110adecab2a9",
|
||||
"reqSigs": 1,
|
||||
"type": "witness_v0_scripthash",
|
||||
"addresses": [
|
||||
"tb1qdl5lg5wvakuwgzgtsgku4ktn6qug5da5ez0artk5s5gs4hk2k25szvjky9"
|
||||
],
|
||||
"p2sh-segwit": "2NByn92W1vH5oQC1daY69F5sU7PEStKKQBR"
|
||||
}
|
||||
}
|
||||
```
|
||||
Es especialmente útil para verificar su trabajo cuando está serializando.
|
||||
|
||||
## Serializar un Script de Bloqueo de Forma Sencilla
|
||||
|
||||
Cuando instaló `btcdeb` en [§9.3](09_3_Probando_un_Script_Bitcoin.md) también instaló `btcc` que se puede usar para seralizar scripts de Bitcoin:
|
||||
```
|
||||
$ btcc 2 02da2f10746e9778dd57bd0276a4f84101c4e0a711f9cfd9f09cde55acbdd2d191 02bfde48be4aa8f4bf76c570e98a8d287f9be5638412ab38dede8e78df82f33fa3 2 OP_CHECKMULTISIG
|
||||
warning: ambiguous input 2 is interpreted as a numeric value; use OP_2 to force into opcode
|
||||
warning: ambiguous input 2 is interpreted as a numeric value; use OP_2 to force into opcode
|
||||
522102da2f10746e9778dd57bd0276a4f84101c4e0a711f9cfd9f09cde55acbdd2d1912102bfde48be4aa8f4bf76c570e98a8d287f9be5638412ab38dede8e78df82f33fa352ae
|
||||
```
|
||||
Eso es mucho más fácil que averiguarlo a mano!
|
||||
|
||||
También considere el Python [Compilador de Script de Transacciones](https://github.com/Kefkius/txsc), que traduce de ida y vuelta.
|
||||
|
||||
## Hash un Script Serializado
|
||||
|
||||
Después de haber creado un script de bloqueo y de serializarlo, el tercer paso para crear una transacción P2SH es aplicar un hash al script de bloqueo. Como se señalo anteriormente, un hash OP_HASH160 de 20 bytes se crea mediante una combinación de un hash SHA-256 y un hash RIPEMD-160. El hash de un script serializado requiere dos comandos: `openssl dgst -sha256 -binary` hace el hash SHA-256 y genera un binario que se enviará a través de la tuberia, luego `openssl dgst -rmd160` toma ese flujo binario, hace un hash RIPEMD-160, y finalmente genera un código hexadecimal legible por humanos.
|
||||
|
||||
Aquí está la tubería completa, incluida la transformación anterior del script serializado hexadecimal en binario:
|
||||
```
|
||||
$ redeemScript="522102da2f10746e9778dd57bd0276a4f84101c4e0a711f9cfd9f09cde55acbdd2d1912102bfde48be4aa8f4bf76c570e98a8d287f9be5638412ab38dede8e78df82f33fa352ae"
|
||||
$ echo -n $redeemScript | xxd -r -p | openssl dgst -sha256 -binary | openssl dgst -rmd160
|
||||
(stdin)= a5d106eb8ee51b23cf60d8bd98bc285695f233f3
|
||||
```
|
||||
## Crear un Transacción P2SH
|
||||
|
||||
La creación de su hash de 20 bytes solo le brinda el hash en el centro de un script de bloqueo P2SH. Aún debe juntarlo con los otros códigos de operación que crean una transacción P2SH estándar: `OP_HASH160 a5d106eb8ee51b23cf60d8bd98bc285695f233f3 OP_EQUAL`.
|
||||
|
||||
Dependiendo de su API, es posible que pueda ingresar esto como un `scriptPubKey` de estilo `asm` para su transacción, o puede que tenga que traducirlo también al código `hex`. Si tiene que traducir, use los mismos métodos descritos anteriormente para "Crear el Código Hex" (o use `btcc`), lo que da resultado `a914a5d106eb8ee51b23cf60d8bd98bc285695f233f387`.
|
||||
|
||||
Tenga en cuenta que la `hex scriptPubKey` para la transacción P2SH Script _siempre_ comenzará con un `a914`, que es el `OP_HASH160` seguido de un `OP_PUSHDATA` de 20 bytes (hex: `0x14`); y _siempre_ terminará con un `87`, que es un `OP_EQUAL`. Entonces, todo lo que tiene que hacer es colocar su script de canje con hash entre esos números.
|
||||
|
||||
## Resumen: Construyendo la Base de P2SH
|
||||
|
||||
En realidad, la creación del script de bloqueo P2SH se sumerge en las entrañas de Bitcoin más que nunca. Aunque es útil saber cómo funciona todo esto a un nivel muy bajo, lo más probable es que tenga una API que se encargue de todo el trabajo pesado por usted. Su tarea será simplemente crear el script de Bitcoin para hacer el bloqueo ... que es el tema principal de los capítulos 9 y 11-12.
|
||||
|
||||
## ¿Que Sigue?
|
||||
|
||||
Continúe "Incrustando Bitcoin Scripts" con [§10.3: Ejecución de un Bitcoin Script con P2SH](10_3_Ejecutando_un_Script_Bitcoin_con_P2SH.md).
|
100
es/10_3_Ejecutando_un_Script_Bitcoin_con_P2SH.md
Normal file
100
es/10_3_Ejecutando_un_Script_Bitcoin_con_P2SH.md
Normal file
@ -0,0 +1,100 @@
|
||||
# 10.3: Ejecución de un Bitcoin Script con P2SH
|
||||
|
||||
Ahora que concoce la teoría y la práctica detrás de las direcciones P2SH, está listo para convertir un script de Bitcoin no estándar en una transacción real. Reutilizaremos la secuencia de comandos de bloqueo simple de [§9.2: Ejecución de un Bitcoin Script](09_2_Ejecutando_un_Script_Bitcoin.md), `OP_ADD 99 OP_EQUAL`.
|
||||
|
||||
## Crear una Transacción P2SH
|
||||
|
||||
Para bloquear una transacción con este script, haga lo siguiente:
|
||||
|
||||
1. Serializar `OP_ADD 99 OP_EQUAL`:
|
||||
1. OP_ADD = 0x93 — una traducción simple de un opcode
|
||||
2. 99 = 0x01, 0x63 — este opcode empuja un byte a la pila, 99 (hex: 0x63)
|
||||
* No se preocupe por la conversión endian porque es solo un byte
|
||||
3. OP_EQUAL = 0x87 — una tradducion simple de un opcode
|
||||
4. `<serialized99Equal>` = "93016387"
|
||||
|
||||
```
|
||||
$ btcc OP_ADD 99 OP_EQUAL
|
||||
93016387
|
||||
```
|
||||
|
||||
2. Guarde `<serialized99Equal>` para referencia futura como `redeemScript`.
|
||||
1. `<redeemScript>` = "93016387"
|
||||
3. SHA-256 y RIPEMD-160 hash el script serializado.
|
||||
1. `<hashed99Equal>` = "3f58b4f7b14847a9083694b9b3b52a4cea2569ed"
|
||||
4. Produzca un script de bloqueo P2SH que incluya el `<hashed99Equal>`.
|
||||
1. `scriptPubKey` = "a9143f58b4f7b14847a9083694b9b3b52a4cea2569ed87"
|
||||
|
||||
Luego puede crear una transacción usando esta `scriptPubKey`, probablemente a través de una API.
|
||||
|
||||
## Desbloquear la Transacción P2SH
|
||||
|
||||
Para desbloquear esta transacción se requiere que el destinatario produzca un `scriptSig` que anteponga dos constantes que sumen noventa y nueve al script serializado: `1 98 <serialized99Equal>`.
|
||||
|
||||
### Ejecute la Primera Ronda de Validación
|
||||
|
||||
El proceso de desbloqueo de la transacción P2SH comienza con una primera ronda de validación, que verifica que el script de canje coincida con el valor hash en el script de bloqueo.
|
||||
|
||||
Concatenar `scriptSig` y `scriptPubKey` y ejecutarlos, como de costumbre:
|
||||
```
|
||||
Script: 1 98 <serialized99Equal> OP_HASH160 <hashed99Equal> OP_EQUAL
|
||||
Stack: []
|
||||
|
||||
Script: 98 <serialized99Equal> OP_HASH160 <hashed99Equal> OP_EQUAL
|
||||
Stack: [ 1 ]
|
||||
|
||||
Script: <serialized99Equal> OP_HASH160 <hashed99Equal> OP_EQUAL
|
||||
Stack: [ 1 98 ]
|
||||
|
||||
Script: OP_HASH160 <hashed99Equal> OP_EQUAL
|
||||
Stack: [ 1 98 <serialized99Equal> ]
|
||||
|
||||
Script: <hashed99Equal> OP_EQUAL
|
||||
Running: <serialized99Equal> OP_HASH160
|
||||
Stack: [ 1 98 <hashed99Equal> ]
|
||||
|
||||
Script: OP_EQUAL
|
||||
Stack: [ 1 98 <hashed99Equal> <hashed99Equal> ]
|
||||
|
||||
Script:
|
||||
Running: <hashed99Equal> <hashed99Equal> OP_EQUAL
|
||||
Stack: [ 1 98 True ]
|
||||
```
|
||||
La secuencia de comandos termina con un `True` en la parte superior de la pila, por lo que tiene éxito ... a pesar de que hay otros cruft debajo de él.
|
||||
|
||||
Sin embargo, debido a que se trataba de un script P2SH, la ejecución no se realiza.
|
||||
|
||||
### Ejecute la Segunda Ronda de Validación
|
||||
|
||||
Para la segunda ronda de validación, verifique que los valores en el script de desbloqueo satisfagan el `redeemScript`: deserialice el `redeemScript` ("93016387" = "OP_ADD 99 OP_EQUAL"), luego ejecútelo usando los elementos del `scriptSig` antes del script serializado:
|
||||
|
||||
```
|
||||
Script: 1 98 OP_ADD 99 OP_EQUAL
|
||||
Stack: [ ]
|
||||
|
||||
Script: 98 OP_ADD 99 OP_EQUAL
|
||||
Stack: [ 1 ]
|
||||
|
||||
Script: OP_ADD 99 OP_EQUAL
|
||||
Stack: [ 1 98 ]
|
||||
|
||||
Script: 99 OP_EQUAL
|
||||
Running: 1 98 OP_ADD
|
||||
Stack: [ 99 ]
|
||||
|
||||
Script: OP_EQUAL
|
||||
Stack: [ 99 99 ]
|
||||
|
||||
Script:
|
||||
Running: 99 99 OP_EQUAL
|
||||
Stack: [ True ]
|
||||
```
|
||||
Con esa segunda validación _también_ verdadera, el UTXO ahora se puede gastar!
|
||||
|
||||
## Resumen: Creación de un Bitcoin Script con P2SH
|
||||
|
||||
Una vez que conozca la técnica de construcción de P2SH, cualquier script se puede incrustar en una transacción de Bitcoin; y una vez que comprenda la técnica de validación de P2SH, es fácil ejecutar los scripts en dos rondas.
|
||||
|
||||
## Que Sigue?
|
||||
|
||||
Continúe "Incrustando Bitcoin Scripts" con [§10.4: Codificando una Multifirma](10_4_Codificando_una_Multifirma.md).
|
149
es/10_4_Codificando_una_Multifirma.md
Normal file
149
es/10_4_Codificando_una_Multifirma.md
Normal file
@ -0,0 +1,149 @@
|
||||
# 10.4: Codificando una Multifirma
|
||||
|
||||
Antes de cerrar esta introducción a las secuencias de comandos P2SH, vale la pena examinar un ejemplo más realista. Desde [§6.1](06_1_Enviando_una_Transaccion_a_una_Direccion_Multifirma.md), hemos estado diciendo casualmente que la interfaz `bitcoin-cli` envuelve su transacción multifirma en una transacción P2SH. De hecho, esta es la metodología estándar para crear multifirmas en Blockchain. Así es como funciona eso en profundidad.
|
||||
|
||||
## Entender el Código Multifirma
|
||||
|
||||
Las transacciones multifirma se crean en Bitcoin utlizando el código `OP_CHECKMULTISIG`. `OP_CHECKMULTISIG` espera una larga cadena de argumentos con este aspecto: `0 ... sigs ... <m> ... addresses ... <n> OP_CHECKMULTISIG`. Cuando se ejecuta `OP_CHECKMULTISIG` hace lo siguiente:
|
||||
|
||||
1. Saca el primer valor de la pila (`<n>`).
|
||||
2. Saca los valores "n" de la pila como direcciones de Bitcoin (claves públicas con hash).
|
||||
3. Saca el siguiente valor de la pila (`<m>`).
|
||||
4. Saca los valores "m" de la pila como posibles firmas.
|
||||
5. Saca un `0` de la pila debido a un error en la codificación.
|
||||
6. Compara las firmas con las direcciones de Bitcoin.
|
||||
7. Empuja un `True` o `False` según el resultado.
|
||||
|
||||
Los operandos de `OP_MULTISIG` se dividen típicamente, con el `0` y las firmas provenientes del script de desbloqueo y la "m", "n", y las direcciones se detallan en el script de bloqueo.
|
||||
|
||||
El requisito de que `0` como primer operando de `OP_CHECKMULTISIG` es una regla de consenso. Debido a que la versión original de `OP_CHECKMULTISIG` sacó accidentalmente un elemento adicional de la pila, Bitcoin debe seguir para siempre ese estándar, para que no se rompan accidentalmente los complejos scripts de canje de ese período de tiempo, haciendo que los fondos antiguos no se puedan canjear.
|
||||
|
||||
> :book: ***¿Qué es una regla de consenso?*** Estas son las reglas que siguen los nodos de Bitcoin para trabajar juntos. En gran parte, están definidos por el código Bitcoin Core. Estas reglas incluyen muchos mandatos obvios como el límite de la cantidad de Bitcoins que se crean para cada bloque y las reglas sobre cómo se pueden respetar las transacciones. Sin embargo, también incluyen correciones para errores que han aparecido a lo largo de los años, porque una vez que se ha introducido un error en la base de código de Bitcoin, debe recibir soporte continuo para evitar que los antiguos Bitcoins se vuelvan no gastables.
|
||||
|
||||
## Crear una Multifima Sin Procesar
|
||||
|
||||
Como se explica en [§10.1: Entendiendo la Base de P2SH](10_1_Entendiendo_la_Base_de_P2SH.md), las multifirmas son uno de los tipos de transacciones estándar de Bitcoin. Se puede crear una transacción con un script de bloqueo que utiliza el comando `OP_CHECKMULTISIG` sin procesar, y se aceptará en un bloque. Esta es la metodología clásica para usar multifirmas en Bitcoin.
|
||||
|
||||
Como ejemplo, volveremos a visitar la multifirma creado en [§6.1: Enviando una Transacción con una Multifirma](06_1_Enviando_una_Transaccion_a_una_Direccion_Multifirma.md) una útltima vez y crearemos un nuevo script de bloqueo para esta utilizando dicha metodología. Como recordará, se trataba de una multifirma 2 de 2 construida a partir de `$address1` y `$address2`.
|
||||
|
||||
Como el script de bloqueo `OP_CHECKMULTISIG` requiere la "m" (`2`), las direcciones y la "n" (`2`), puede escribir la siguiente `scriptPubKey`:
|
||||
```
|
||||
2 $address1 $address2 2 OP_CHECKMULTISIG
|
||||
```
|
||||
Si esto le parece familiar, es porque es la multifirma que deserializó en [§10.2: Construyendo la Estructura de P2SH](10_2_Construyendo_la_Estructura_de_P2SH.md).
|
||||
```
|
||||
2 02da2f10746e9778dd57bd0276a4f84101c4e0a711f9cfd9f09cde55acbdd2d191 02bfde48be4aa8f4bf76c570e98a8d287f9be5638412ab38dede8e78df82f33fa3 2 OP_CHECKMULTISIG
|
||||
```
|
||||
|
||||
> **ADVERTENCIA:** Para las firmas clásicas `OP_CHECKMULTISIG`, "n" debe ser ≤ 3 para que la transacción sea estándar.
|
||||
|
||||
## Desbloquear un Multifirma Sin Procesar
|
||||
|
||||
El `scriptSig` para una dirección estándar multifirma debe enviar los operandos que faltan para `OP_CHECKMULTISIG`: un `0` seguido de "m" firmas. Por ejemplo:
|
||||
```
|
||||
0 $signature1 $signature2
|
||||
```
|
||||
|
||||
### Ejecutar una Guion de Multifirmas Sin Procesar
|
||||
|
||||
Para gastar un UTXO multifirma, ejecute `scriptSig` y `scriptPubKey` de la siguiente manera:
|
||||
```
|
||||
Script: 0 $signature1 $signature2 2 $address1 $address2 2 OP_CHECKMULTISIG
|
||||
Stack: [ ]
|
||||
```
|
||||
Primero, coloca todas las constantes en la pila:
|
||||
```
|
||||
Script: OP_CHECKMULTISIG
|
||||
Stack: [ 0 $signature1 $signature2 2 $address1 $address2 2 ]
|
||||
```
|
||||
Entonces, el `OP_CHECKMULTISIG` comienza a ejecutarse. Primero se saca el "2":
|
||||
```
|
||||
Running: OP_CHECKMULTISIG
|
||||
Stack: [ 0 $signature1 $signature2 2 $address1 $address2 ]
|
||||
```
|
||||
Luego, el "2" le dice a `OP_CHECKMULTISIG ` que muestre dos direcciones:
|
||||
```
|
||||
Running: OP_CHECKMULTISIG
|
||||
Stack: [ 0 $signature1 $signature2 2 ]
|
||||
```
|
||||
Luego, el siguiente "2" se saca:
|
||||
```
|
||||
Running: OP_CHECKMULTISIG
|
||||
Stack: [ 0 $signature1 $signature2 ]
|
||||
```
|
||||
Luego, el "2" le dice a `OP_CHECKMULTISIG` que saque dos firmas:
|
||||
```
|
||||
Running: OP_CHECKMULTISIG
|
||||
Stack: [ 0 ]
|
||||
```
|
||||
Luego, se saca un elemento más por error:
|
||||
```
|
||||
Running: OP_CHECKMULTISIG
|
||||
Stack: [ ]
|
||||
```
|
||||
Luego, `OP_CHECKMULTISIG` completa su operación comparando las firmas "m" con las direcciones "n":
|
||||
```
|
||||
Script:
|
||||
Stack: [ True ]
|
||||
```
|
||||
## Entender las Limitaciones de los Scripts de Multifirmas Sin Procesar
|
||||
|
||||
Desafortunadamente, la técnica de incrustar una multifirma sin procesar en una transacción tiene algunos inconvenientes notables:
|
||||
|
||||
1. Debido a que no existe un formato de dirección estándar para multifirma, cada remitente debe: ingresar un script multifirma largo y engorroso; tener un software que permita esto; y ser de confianza para no estropearlo.
|
||||
2. Debido a que las múltiples funciones pueden ser mucho más largas que los script de bloqueo típicos, la cadena de bloques incurre en más costos. Esto requiere tarifas de transacción más altas por parte del remitente y crea más molestias para cada nodo.
|
||||
|
||||
Estos eran generalmente problemas con cualquier tipo de script de Bitcoin complejo, pero rápidamente se convirtieron en problemas muy reales cuando se aplicaron a multifirmas, que fueron algunos de los primeros scripts complejos que se utilizaron ampliamente en la red de Bitcoin. Las transacciones P2SH se crearon para resolver estos problemas a partir de 2012.
|
||||
|
||||
> :book: ***¿Qué es un P2SH multifirma?*** Las multifirmas P2SH fueron la primera implementación de transacciones P2SH. Simplemente empaquetan una transacción multifirma estándar en una transacción P2SH estándar. Esto permite la estandarización de direcciones; reduce el almacenamiento de datos; y aumenta los recuentos de "m" y "n".
|
||||
|
||||
## Crear un P2SH Multifirma
|
||||
|
||||
Las multifirmas P2SH son la metodología moderna para crear multifirmas en las Blockchains. Se pueden crear de forma muy sencilla, utilizando el mismo proceso visto en las secciones anteriores.
|
||||
|
||||
### Crear la Cerradura para P2SH Multifirma
|
||||
|
||||
Para crear una multifirma P2SH, siga los pasos estándar para crear un script de bloqueo P2SH:
|
||||
|
||||
1. Serialice `2 $address1 $address2 2 OP_CHECKMULTISIG`.
|
||||
1. `<serializedMultiSig>` = "522102da2f10746e9778dd57bd0276a4f84101c4e0a711f9cfd9f09cde55acbdd2d1912102bfde48be4aa8f4bf76c570e98a8d287f9be5638412ab38dede8e78df82f33fa352ae"
|
||||
2. Guarde `<serializedMultiSig>` para referencia futura como redeemScript.
|
||||
1. `<redeemScript>` = "522102da2f10746e9778dd57bd0276a4f84101c4e0a711f9cfd9f09cde55acbdd2d1912102bfde48be4aa8f4bf76c570e98a8d287f9be5638412ab38dede8e78df82f33fa352ae"
|
||||
3. SHA-256 y RIPEMD-160 procesan el script serializado.
|
||||
1. `<hashedMultiSig>` = "a5d106eb8ee51b23cf60d8bd98bc285695f233f3"
|
||||
4. Produzca un script de bloqueo P2SH Multifirma que incluya el script hash (`OP_HASH160 <hashedMultisig> OP_EQUAL`).
|
||||
1. `scriptPubKey` = "a914a5d106eb8ee51b23cf60d8bd98bc285695f233f387"
|
||||
|
||||
Luego puede crear una transacción usando esa `scriptPubKey`.
|
||||
|
||||
## Desbloquear la Multifirma P2SH
|
||||
|
||||
Para desbloquear esta transacción multifirma es necesario que el destinatario produzca un scriptSig que incluya las dos firmas y el `redeemScript`.
|
||||
|
||||
### Ejecute la Primera Ronda de Validación P2SH
|
||||
|
||||
Para desbloquear el P2SH multifirma, primero confirme el script:
|
||||
|
||||
1. Producir un script de desbloqueo de `0 $signature1 $signature2 <serializedMultiSig>`.
|
||||
2. Concatenar eso con el script de bloqueo de `OP_HASH160 <hashedMultisig> OP_EQUAL`.
|
||||
3. Validar `0 $signature1 $signature2 <serializedMultiSig> OP_HASH160 <hashedMultisig> OP_EQUAL`.
|
||||
4. Es correcto si el `<serializedMultisig>` coincide con el `<hashedMultisig>`.
|
||||
|
||||
### Ejecute la Segunda Ronda de Validación P2SH
|
||||
|
||||
Luego, ejecute el script multifirma:
|
||||
|
||||
1. Deserializar `<serializedMultiSig>` a `2 $address1 $address2 2 OP_CHECKMULTISIG`.
|
||||
2. Concatenar eso con los operandos anteriores en el script de desbloqueo, `0 $signature1 $signature2`.
|
||||
3. Validar `0 $signature1 $signature2 2 $address1 $address2 2 OP_CHECKMULTISIG`.
|
||||
4. Es correcto si los operandos cumplen con la deserialización `redeemScript`.
|
||||
|
||||
Ahora sabe cómo se creó realmente la transacción multifirma en [§6.1](06_1_Enviando_una_Transaccion_a_una_Direccion_Multifirma.md), cómo se validó para el gasto y por qué ese `redeemScript` era tan importante.
|
||||
|
||||
## Resumen: Creación de Guiones de Multifirmas
|
||||
|
||||
Las multifirmas son un tipo de transacción estándar, pero su uso es un poco complicado, por lo que se incorporan regularmente en las transacciones P2SH, como fue el caso en [§6.1](06_1_Enviando_una_Transaccion_a_una_Direccion_Multifirma.md) cuando creamos nuestras primeras multifirmas. El resultado es más limpio, más pequeño y más estandarizado — pero lo que es más importante, es un gran ejemplo del mundo real cómo funcionan realmente los scripts P2SH.
|
||||
|
||||
## Que Sigue?
|
||||
|
||||
Continúe "Incrustando Bitcoin Scripts" con [§10.5: Codificando un Script Segwit](10_5_Codificando_un_Script_Segwit.md)
|
132
es/10_5_Codificando_un_Script_Segwit.md
Normal file
132
es/10_5_Codificando_un_Script_Segwit.md
Normal file
@ -0,0 +1,132 @@
|
||||
# 10.5: Codificando un Script Segwit
|
||||
|
||||
> :information_source: **NOTA:** Esta sección se ha agregado recientemente al curso y es un borrador inicial que aún puede estar pendiente de revisión. Lector de advertencias.
|
||||
|
||||
Segwit introdujo una serie de nuevas opciones para los tipos de direcciones (y, por lo tanto, secuencias de comandos). [§9.5: Codificando una P2WPKH](09_5_Codificando_una_P2WPKH.md) explicó cómo el nuevo tipo de dirección Bech32 variaba los scripts estándar encontrados en la mayoría de las transacciones tradicionales. Este capitulo analiza los otros tres tipos de scripts introducidos por la actualización de Segwit: el P2SH-Segwit (que era la dirección de transición "Segwit anidada", cuando Segwit entró en uso), el P2WSH (que es el equivalente Segwit de la dirección P2SH, al igual que P2WPKH es el equivalente Segwit de la dirección P2PKH), y la dirección P2WSH anidada.
|
||||
|
||||
Esta es otra situación en la que realmente no tendrá que preocuparse por estos matices mientras trabaja con `bitcoin-cli`, pero es útil saber cómo funciona todo.
|
||||
|
||||
## Entender un Script de P2SH-Segwit
|
||||
|
||||
La dirección P2SH-Segwit es una raza en extinción. Básicamente, fue una medida provisional mientras Bitcoin estaba en transición a Segwit que permitía a un usuario crear una dirección de Segwit y luego tener a alguien con un intercambio o fondo de biletera no habilitado para Segwit que se dirigiera.
|
||||
|
||||
Si alguna vez necesita usar uno, hay una opción para crear una dirección P2SH-Segwit usando `getnewaddress`:
|
||||
```
|
||||
$ bitcoin-cli getnewaddress -addresstype p2sh-segwit
|
||||
2NEzBvokxh4ME4ahdT18NuSSoYvvhS7EnMU
|
||||
```
|
||||
La dirección comienza con un `2` (o un `3`) que la revela como un guión.
|
||||
|
||||
> :book: ***¿Por qué los nodos antiguos no pueden enviar a direcciones nativas de Segwit?*** [§10.1](10_1_Entendiendo_la_Base_de_P2SH.md) señaló que había un número determinado de transacciones de Bitcoin "estándar". En realidad, no puede bloquear una transacción con un script que no sea uno de esos tipos estándar. Segwit ahora se reconoce como uno de esos estándares, pero un nodo antiguo no lo sabrá, por lo que se negará a enviar una transacción de este tipo para la protección del remitente. Envolver una dirección Segwit dentro de un hash de script estándar resuelve el problema.
|
||||
|
||||
Cuando mira un UTXO enviado a esa dirección, puede ver que el `desc` es diferente, revelando una dirección WPKH envuelta en un script:
|
||||
```
|
||||
$ bitcoin-cli listunspent
|
||||
{
|
||||
"txid": "ed752673bfd4338ccf0995983086da846ad652ae0f28280baf87f9fd44b3c45f",
|
||||
"vout": 1,
|
||||
"address": "2NEzBvokxh4ME4ahdT18NuSSoYvvhS7EnMU",
|
||||
"redeemScript": "001443ab2a09a1a5f2feb6c799b5ab345069a96e1a0a",
|
||||
"scriptPubKey": "a914ee7aceea0865a05a29a28d379cf438ac5b6cd9c687",
|
||||
"amount": 0.00095000,
|
||||
"confirmations": 1,
|
||||
"spendable": true,
|
||||
"solvable": true,
|
||||
"desc": "sh(wpkh([f004311c/0'/0'/3']03bb469e961e9a9cd4c23db8442d640d9b0b11702dc0126462ac9eb88b64a4dd48))#p29e839h",
|
||||
"safe": true
|
||||
}
|
||||
```
|
||||
Más importante aún, hay un `redeemScript`, que decodifica a `OP_0 OP_PUSHDATA (20 bytes) 3ab2a09a1a5f2feb6c799b5ab345069a96e1a0a`. Deberia parecer familiar, porque es un `OP_0` seguido de un código hexadecimal de 20 bytes de un hash de clave pública. En otras palabras, un P2SH-SegWit es solo un SegWit `scriptPubKey` atascado en un script. Eso es todo al respecto. Coincide precisamente con la forma en que las multifirmas modernas son un multifirma puesto dentro de un P2SH, como se explica en [§10.4: Codificando una Multifirma](10_4_Codificando_una_Multifirma.md).
|
||||
|
||||
Por el contrario, cuando gastamos esta transacción, se ve exactamente como un P2SH:
|
||||
```
|
||||
$ bitcoin-cli getrawtransaction ed752673bfd4338ccf0995983086da846ad652ae0f28280baf87f9fd44b3c45f 1
|
||||
{
|
||||
"txid": "ed752673bfd4338ccf0995983086da846ad652ae0f28280baf87f9fd44b3c45f",
|
||||
"hash": "aa4b1c2bde86ea446c9a9db2f77e27421316f26a8d88869f5b195f03b1ac4f23",
|
||||
"version": 2,
|
||||
"size": 247,
|
||||
"vsize": 166,
|
||||
"weight": 661,
|
||||
"locktime": 1781316,
|
||||
"vin": [
|
||||
{
|
||||
"txid": "59178b02cfcbdee51742a4b2658df35b63b51115a53cf802bc6674fd94fa593a",
|
||||
"vout": 1,
|
||||
"scriptSig": {
|
||||
"asm": "00149ef51fb1f5adb44e20eff758d34ae64fa781fa4f",
|
||||
"hex": "1600149ef51fb1f5adb44e20eff758d34ae64fa781fa4f"
|
||||
},
|
||||
"txinwitness": [
|
||||
"3044022069a23fcfc421b44c622d93b7639a2152f941dbfd031970b8cef69e6f8e97bd46022026cb801f38a1313cf32a8685749546a5825b1c332ee4409db82f9dc85d99086401",
|
||||
"030aec1384ae0ef264718b8efc1ef4318c513403d849ea8466ef2e4acb3c5ccce6"
|
||||
],
|
||||
"sequence": 4294967294
|
||||
}
|
||||
],
|
||||
"vout": [
|
||||
{
|
||||
"value": 8.49029534,
|
||||
"n": 0,
|
||||
"scriptPubKey": {
|
||||
"asm": "OP_HASH160 b4b656f4c4b14ee0d098299d1d6eb42d2e22adcd OP_EQUAL",
|
||||
"hex": "a914b4b656f4c4b14ee0d098299d1d6eb42d2e22adcd87",
|
||||
"reqSigs": 1,
|
||||
"type": "scripthash",
|
||||
"addresses": [
|
||||
"2N9ik3zihJ91VGNF55sZFe9GiCAXh2cVKKW"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"value": 0.00095000,
|
||||
"n": 1,
|
||||
"scriptPubKey": {
|
||||
"asm": "OP_HASH160 ee7aceea0865a05a29a28d379cf438ac5b6cd9c6 OP_EQUAL",
|
||||
"hex": "a914ee7aceea0865a05a29a28d379cf438ac5b6cd9c687",
|
||||
"reqSigs": 1,
|
||||
"type": "scripthash",
|
||||
"addresses": [
|
||||
"2NEzBvokxh4ME4ahdT18NuSSoYvvhS7EnMU"
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"hex": "020000000001013a59fa94fd7466bc02f83ca51511b5635bf38d65b2a44217e5decbcf028b175901000000171600149ef51fb1f5adb44e20eff758d34ae64fa781fa4ffeffffff029e299b320000000017a914b4b656f4c4b14ee0d098299d1d6eb42d2e22adcd87187301000000000017a914ee7aceea0865a05a29a28d379cf438ac5b6cd9c68702473044022069a23fcfc421b44c622d93b7639a2152f941dbfd031970b8cef69e6f8e97bd46022026cb801f38a1313cf32a8685749546a5825b1c332ee4409db82f9dc85d9908640121030aec1384ae0ef264718b8efc1ef4318c513403d849ea8466ef2e4acb3c5ccce6442e1b00",
|
||||
"blockhash": "0000000069cbe44925fab2d472870608c7e1e241a1590fd78be10c63388ed6ee",
|
||||
"confirmations": 282952,
|
||||
"time": 1595360859,
|
||||
"blocktime": 1595360859
|
||||
}
|
||||
```
|
||||
Esto confirma que esto es solo un P2SH normal, bloqueado por `"OP_DUP OP_HASH160 41d83eaffbf80f82dee4c152de59a38ffd0b6021 OP_EQUALVERIFY OP_CHECKSIG"`. Es cuando se ejecuta el script de canje que ocurre la magia. Al igual que con un P2WPKH, un nodo antiguo verá `OP_0 OP_PUSHDATA (20 bytes) 3ab2a09a1a5f2feb6c799b5ab345069a96e1a0a` y lo verificará automáticamente, mientras que un nuevo nodo lo verá, sabrá que es un P2WPKH, y así saldrá con los `testigos`. See [§9.5: Codificando una P2WPKH](09_5_Codificando_una_P2WPKH.md).
|
||||
|
||||
Cada `vout` tiene el formato `OP_HASH160 <HASH> OP_EQUAL`. Eso es un P2SH normal según [§10.2](10_2_Construyendo_la_Estructura_de_P2SH.md), lo que significa que es solo cuando se ejecuta el script de canje que ocurre la magia. Al igual que con un P2WPKH, un nodo antiguo verá `OP_0 OP_PUSHDATA (20 bytes) 3ab2a09a1a5f2feb6c799b5ab345069a96e1a0a` en el script de canje y lo verificará automáticamente, mientras que un nuevo nodo lo verá, sabrá que es un P2WPKH, y así irá a los `witnesses`. Consulte [§9.5: Codificando una P2WPKH](09_5_Codificando_una_P2WPKH.md).
|
||||
|
||||
> :book: ***¿Cuáles son las desventajas de las transacciones segwit anidadas?*** Son más grandes que las transacciones nativas de Segwit, por lo que obtiene algunas de las ventajas de Segwit, pero no todas.
|
||||
|
||||
## Entender un Script P2WSH
|
||||
|
||||
Por el contrario, las transacciones P2WSH deberían tener un uso cada vez mayor, ya que son el reemplazo nativo de Segwit para P2SH, ofreciendo las mismas ventajas de tamaño de bloque que se crearon con transacciones nativas Segwit P2WPKH.
|
||||
|
||||
Este es un ejemplo de dirección P2WSH:
|
||||
[https://blockstream.info/testnet/address/tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7](https://blockstream.info/testnet/address/tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7)
|
||||
|
||||
Los detalles muestran que un UTXO enviado a esta dirección está bloqueado con una `scriptPubKey` como esta:
|
||||
```
|
||||
OP_0 OP_PUSHDATA (32 bytes) 1863143c14c5166804bd19203356da136c985678cd4d27a1b8c6329604903262
|
||||
```
|
||||
Esto funciona como una dirección P2WPKH, la única diferencia es que un lugar de un hash de clave pública de 20 bytes, el UTXO incluye un hash de script de 32 bytes. Al igual que con un P2WPKH, los nodos antiguos solo verifican esto, mientras que los nuevos nodos reconocen que se trata de un P2WSH y, por lo tanto, verifican internamente el script como se describe en las secciones anteriores, pero utilizando los datos del `testigo`, que ahora incluye el script de canje.
|
||||
También hay una variante más, un script P2WSH incrustado en un script P2SH, que funciona de manera muy similar al P2SH-Segwit descrito anterioremente, pero para scripts P2WSH anidados. (Whew!)
|
||||
|
||||
## Resumen: Programando un script Segwit
|
||||
|
||||
Hay dos tipos de scripts P2SH que se relacionan con Segwit.
|
||||
|
||||
La dirección P2SH-Segwit es una dirección Segwit anidada que incrusta el simple `scriptPubkey` de Segwit dentro de un script, al igual que las multifirmas están incrustadas en los scripts hoy en día: la clave de estilo Segwit se desenrolla y luego se analiza como de costumbre en una máquina que entiende Segwit. El propósito es la compatibilidad con versiones anteriores de nodos antiguos que, de otro modo, no podrían enviarse a direcciones nativas de Segwit.
|
||||
|
||||
La dirección P2WSH es una variante Segwit de P2SH, al igual que P2WPKH es una variante Segwit de P2WSH. Funciona con la misma lógica y se identifica por tener un hash de 32 bytes en lugar de un hash de 20 bytes. El propósito es extender las ventajas de Segwit a otros tipos de scripts.
|
||||
|
||||
## Que Sigue?
|
||||
|
||||
Continúe "Incrustando Bitcoin Scripts" con [§10.6: Gastando una Transacción P2SH](10_6_Gastando_una_Transaccion_P2SH.md).
|
42
es/10_6_Gastando_una_Transaccion_P2SH.md
Normal file
42
es/10_6_Gastando_una_Transaccion_P2SH.md
Normal file
@ -0,0 +1,42 @@
|
||||
# 10.6: Gastando una Transacción P2SH
|
||||
|
||||
Antes de cerrar esta descripcion general de las transacciones P2SH, veremos cómo gastarlas. Esta sección es principalmente una descripción general, que hace referencia a una sección anterior en la que _ya_ gastamos una transacción P2SH.
|
||||
|
||||
## Utilice el Guión de Canjear
|
||||
|
||||
Como vimos en [§6.2: Gastando una Transacción con una Multifirma](06_2_Gastando_una_Transaccion_con_una_Direccion_Multifirma.md), gastar una transacción P2SH se trata de tener esa versión serializada del script de bloqueo, el llamado _redeemScript_. Entonces, el primer paso para poder gastar una transacción P2SH es asegurarse de guardar el _redeemScript_ antes de dar la dirección P2SH a todos.
|
||||
|
||||
### Recoge Sus Variables
|
||||
|
||||
Debido a que las direcciones P2SH distintas de las direcciones segwit anidadas y mulifirmas especiales no están integradas en `bitcoin-cli` no habrá atajos para el gasto P2SH como viste en [§6.3: Enviando una Multifirma Automatizada](06_3_Enviando_una_Multifirma_Automatizada.md). ¡Necesitará recopilar todas las variables más complejas por su cuenta!
|
||||
|
||||
Esto significa que debe recopilar:
|
||||
|
||||
* El `hex` de la `scriptPubKey` para la transacción que está gastando
|
||||
* El `redeemScript` serializado
|
||||
* Cualquier clave privada, ya que estará firmando a mano
|
||||
* Todos los `txids`, `vouts`, y `direcciones` regulares que necesitaría
|
||||
|
||||
## Crear la Transacción
|
||||
|
||||
Como vimos en §6.2, la creación de una transacción es bastante estándar:
|
||||
```
|
||||
$ rawtxhex=$(bitcoin-cli -named createrawtransaction inputs='''[ { "txid": "'$utxo_txid'", "vout": '$utxo_vout' } ]''' outputs='''{ "'$recipient'": 0.00005}''')
|
||||
$ echo $rawtxhex
|
||||
020000000121654fa95d5a268abf96427e3292baed6c9f6d16ed9e80511070f954883864b10000000000ffffffff0188130000000000001600142c48d3401f6abed74f52df3f795c644b4398844600000000
|
||||
```
|
||||
Sin embargo, la firma requiere ingresar información adicional para (1) `scriptPubKey`; (2) el `redeemScript`; y (3) cualquier clave privada requerida.
|
||||
|
||||
Este es el ejemplo de cómo hacerlo para esa multifirma incrustada en P2SH en §6.2:
|
||||
```
|
||||
$ bitcoin-cli -named signrawtransactionwithkey hexstring=$rawtxhex prevtxs='''[ { "txid": "'$utxo_txid'", "vout": '$utxo_vout', "scriptPubKey": "'$utxo_spk'", "redeemScript": "'$redeem_script'" } ]''' privkeys='["cNPhhGjatADfhLD5gLfrR2JZKDE99Mn26NCbERsvnr24B3PcSbtR"]'
|
||||
```
|
||||
Con cualquier otro tipo de P2SH, incluirá un `redeemscript` diferente, pero por lo demás, la práctica es exactamente la misma. La única diferencia es que después de dos capítulos de trabajo en Scripts, ahora comprende qué es el `scriptPubKey` y qué es el `redeemScript`, así que con suerte lo que eran elementos misteriosos hace cuatro capítulos ahora es viejo sombrero.
|
||||
|
||||
## Resumen: Gastar una Transacción P2SH
|
||||
|
||||
Ya gastó un P2SH en el Capítulo 6, cuando reenvió una transacción multifirma de la manera difícil, lo que requirió alinear la información de `scriptPubKey` y `redeemScript`. Ahora sabe que el `scriptPubKey` es un script de bloqueo P2SH estandarizado, mientras que el `redeemScript` coincide con un hash en ese script de bloqueo y que necesita poder ejecutarlo con las variables adecuadas para recibir un resultado `True`. Pero aparte de saber más, no hay nada nuevo en gastar una transacciónn P2SH, porque ya lo hizo!
|
||||
|
||||
## Que Sigue?
|
||||
|
||||
Avanzar a través de "Bitcoin Scripting" con el [Capítulo Once: Potenciando Bloqueos de Tiempo con Bitcoin Scripts](11_0_Potenciando_Bloqueos_de_Tiempo_con_Bitcoin_Scripts.md).
|
@ -0,0 +1,23 @@
|
||||
# Capitulo 11: Potenciando Bloqueos de Tiempo con Bitcoin Scripts
|
||||
|
||||
La mejora que introdujo `nLockTime` en [§8.1](08_1_Enviando_una_Transaccion_con_Bloqueo_de_Tiempo.md) fue solo el comienzo del principio de los bloqueos de tiempo. Cuando comienza a escribir Bitcoin Scripts, dispone de dos opcodes de bloqueo de tiempo.
|
||||
|
||||
## Objetivos para este Capitulo
|
||||
|
||||
Después de trabajar en este capítulo, un desarrollador podrá:
|
||||
|
||||
* Decidir cual bloqueo de tiempo usar.
|
||||
* Crear Scripts con CLTV.
|
||||
* Crear Scripts con CSV.
|
||||
|
||||
Los objetivos de apoyo incluyen la capacidad de:
|
||||
|
||||
* Entender las diferencias entre los diferentes bloqueos de tiempo.
|
||||
* Generar tiempos relativos.
|
||||
|
||||
## Tabla de contenido:
|
||||
|
||||
* [Sección Uno: Entendiendo las Opciones de los Bloqueos de Tiempo](11_1_Entendiendo_las_Opciones_de_los_Bloqueos_de_Tiempo.md)
|
||||
* [Sección Dos: Usando CLTV en Scripts](11_2_Usando_CLTV_en_Scripts.md)
|
||||
* [Sección Tres: Usando CSV en Scripts](11_3_Usando_CSV_en_Scripts.md)
|
||||
|
@ -0,0 +1,49 @@
|
||||
# 11.1: Entendiendo las Opciones de los Bloqueos de Tiempo
|
||||
|
||||
En [§8.1: Enviando una Transacción con Bloqueo de Tiempo](08_1_Enviando_una_Transaccion_con_Bloqueo_de_Tiempo.md), `nLocktime` ofrecía una gran primera opción para bloquear transacciones así no podían ser gastadas hasta cierto punto en el futuro - basado tanto en el tiempo como en la altura de bloque. Pero, este no es el único modo de poner un bloqueo temporal sobre una transacción.
|
||||
|
||||
## Comprender las Limitaciones de nLockTime
|
||||
|
||||
`nLockTime` es una forma simple y poderosa de bloquear una transacción, pero tiene algunas limitaciones:
|
||||
|
||||
1. **No División.** `nLocktime` bloquea la transacción completa.
|
||||
2. **No Retransmisión.** La mayoría de los nodos modernos no aceptaran un `nLockTime` dentro de la mempool hasta que este casi finalizado.
|
||||
3. **No Scripts.** El original, simple uso de `nLockTime` no permitía su utilización en Scripts.
|
||||
4. **No Protección.** `nLockTime` permite que los fondos sean gastados con una transacción diferente, no bloqueada.
|
||||
|
||||
El último item era el factor decisivo para `nLockTime`. Este prevenía una transacción de ser gastada, pero no prevenía que los mismos fondos fueran usados en una transacción diferente. Es decir, tenía sus casos de uso, pero todo dependía de la confianza.
|
||||
|
||||
## Comprender las Posibilidades de los Scripts con Bloqueos de Tiempo
|
||||
|
||||
En años mas recientes, Bitcoin Core se ha expandido para permitir la manipulación de los bloqueos de tiempo al nivel de opcode con _OP_CHECKLOCKTIMEVERIFY_ (CLTV) y _OP_CHECKSEQUENCEVERIFY_ (CSV). Ambos trabajan bajo una nueva metodología que potencia aún más a Bitcoin.
|
||||
|
||||
_Son Opcodes._ Porque son opcodes, CLTV y CSV pueden ser usados como parte de condiciones de canje mas complejas. Habitualmente son relacionadas con condicionales descriptos en el próximo capítulo.
|
||||
|
||||
_Bloquean Outputs._ Porque son opcodes que son incluidos en las transacciones como parte de `sigPubKey`, solo bloquean un solo output. Esto significa que las transacciones son aceptadas en toda la red Bitcoin y que los UTXOs usados para financiar esas transacciones son gastados. No hay vuelta atrás en una transacción temporalmente bloqueada con CLTV o CSV como hay con una simple `nLockTime`. Volver a gastar los UTXO resultantes requiere entonces que las condiciones del bloqueo de tiempo sean satisfechas.
|
||||
|
||||
Aquí hay un obstáculo para usar bloqueos de tiempo: _Son bloqueos de una vía._ Los Bloqueos de tiempo están diseñados para desbloquear fondos en un cierto tiempo. No pueden re-bloquear un fondo: una vez que un fondo bloqueado temporalmente se desbloquea, va a permanecer siempre disponible para gastar.
|
||||
|
||||
### Comprender las Posibilidades de CLTV
|
||||
|
||||
_OP_CHECKLOCKTIMEVERIFY_ o CLTV es compatible con el clásico `nLockTime`, pero en el nuevo paradigma basado en opcodes. Permite a un UTXO volverse accesible en un cierto tiempo o a una cierta altura de bloque.
|
||||
|
||||
CLTV fue detallado inicialmente en [BIP 65](https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki).
|
||||
|
||||
### Comprender las Posibilidades de CSV
|
||||
|
||||
_OP_CHECKSEQUENCEVERIFY_ o CSV depende de un nuevo tipo de "bloqueo de tiempo relativo", el cual es configurado en el campo _nSequence_ de la transacción. Como siempre, puede ser configurado tanto con tiempo como con altura de bloque. Si es configurado como tiempo, "n", entonces una transacción con bloqueo de tiempo relativo es gastable "n x 512" segundos después de que su UTXO fue minado, y si es configurado como bloque, "n", entonces una transacción con bloqueo de tiempo es gastable "n" bloques después de que su UTXO fue minado.
|
||||
|
||||
El uso de `nSequence` para bloqueos de tiempo relativos fue detallado por primera vez en [BIP 68](https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki), luego el opcode CSV fue agregado en [BIP 112](https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki).
|
||||
|
||||
## Resumen: Entendiendo las Opciones de los Bloqueos de Tiempo
|
||||
|
||||
Tiene ahora 4 opciones de Bloqueo de Tiempo:
|
||||
|
||||
* `nLockTime` para mantener una transacción fuera de la cadena de bloques hasta un tiempo específico.
|
||||
* `nSequence` para mantener una transacción fuera de la cadena de bloques hasta un tiempo relativo.
|
||||
* CLTV para hacer un UTXO no gastable hasta un tiempo específico.
|
||||
* CSV para hacer un UTXO no gastable hasta un tiempo relativo.
|
||||
|
||||
## ¿Que sigue?
|
||||
|
||||
Continúe "Potenciando los Bloqueos de Tiempo" con [§11.2: Usando CLTV en Scripts](11_2_Usando_CLTV_en_Scripts.md).
|
152
es/11_2_Usando_CLTV_en_Scripts.md
Normal file
152
es/11_2_Usando_CLTV_en_Scripts.md
Normal file
@ -0,0 +1,152 @@
|
||||
# 11.2: Usando CLTV en Scripts
|
||||
|
||||
`OP_CHECKLOCKTIMEVERIFY` (o CLTV) es el complemento natural a `nLockTime`. Este traslada la idea de transacciones bloqueantes por tiempo absoluto o altura de bloques al reino de los opcodes, permitiendo el bloqueo de UTXOs individuales.
|
||||
|
||||
> :warning: **ADVERTENCIA DE VERSIÓN:** CLTV fue lanzado con Bitcoin Core 0.11.2, pero debería estar ampliamente implementado en este momento.
|
||||
|
||||
## Recordar nLockTime
|
||||
|
||||
Antes de profundizar en CLTV, primero debe recordar como funciona `nLockTime`.
|
||||
|
||||
Como fue detallado en [§8.1: Enviando una Transacción con Bloqueo de Tiempo](08_1_Enviando_una_Transaccion_con_Bloqueo_de_Tiempo.md), el bloqueo de tiempo es habilitado configurando dos variables, `nLockTime` y `nSequence`. `nSequence` debe ser configurada a menos de 0xffffffff (habitualmente: 0xffffffff-1), luego el `nLockTime` es interpretado como sigue:
|
||||
|
||||
* Si el `nLockTime` es menor que 500 millones, es interpretado como altura de bloque.
|
||||
* Si el `nLockTime` es 500 millones o mas, es interpretado como una estampa de tiempo UNIX.
|
||||
|
||||
Una transacción con `nLockTime` configurado no puede ser gastada (o incluso puesta en la cadena de bloques) hasta que la altura de bloque o tiempo es alcanzado. Mientras tanto, la transacción puede ser cancelada gastando cualquiera de los UTXOs que forman la transacción.
|
||||
|
||||
## Comprender el opcode CLTV
|
||||
|
||||
`OP_CHECKLOCKTIMEVERIFY` funciona dentro del mismo paradigma de las alturas de bloques absolutas o los tiempos absolutos UNIX, pero este se ejecuta como parte de un Bitcoin Script. Este lee un argumento, el cual puede ser la altura de bloque o el tiempo absoluto UNIX. A través de una complicada metodología, compara esos argumentos con el tiempo actual. Si es anterior, el script falla; si la condición es cumplida, el script continua.
|
||||
|
||||
A raíz de que CLTV es solo parte de un script (y presumiblemente parte de una transacción P2SH), una transacción CLTV no es dejada fuera de la mempool como las transacciones `nLockTime`; tan pronto como es verificada, es incluida en la cadena de bloques y los fondos se consideran gastados. El truco es que todos los outputs que fueron bloqueados con CLTV no se encuentran disponibles para _gastar nuevamente_ hasta que CLTV lo permita.
|
||||
|
||||
### Comprender el Tiempo Absoluto de CLTV.
|
||||
|
||||
Así es como `OP_CHECKLOCKTIMEVERIFY` se usaría como chequeo comparando con el 24 de Mayo de 2017:
|
||||
```
|
||||
1495652013 OP_CHECKLOCKTIMEVERIFY
|
||||
```
|
||||
Pero, usualmente representaremos esta abstracción de la siguiente manera:
|
||||
```
|
||||
<24 de Mayo de 2017> OP_CHECKLOCKTIMEVERIFY
|
||||
```
|
||||
O la siguiente:
|
||||
```
|
||||
<Tiempo Absoluto> OP_CHECKLOCKTIMEVERIFY
|
||||
```
|
||||
|
||||
### Comprender la Altura Absoluta de Bloque de CLTV
|
||||
|
||||
Así es como `OP_CHECKLOCKTIMEVERIFY` se chequearía contra la altura de bloque que fue alcanzada el 24 de Mayo de 2017:
|
||||
```
|
||||
467951 OP_CHECKLOCKTIMEVERIFY
|
||||
```
|
||||
Pero, usualmente, lo abstraeremos de la siguiente manera:
|
||||
```
|
||||
<AlturaAbsolutaDeBloque> OP_CHECKLOCKTIMEVERIFY
|
||||
```
|
||||
|
||||
### Comprender Como Realmente Funciona CLTV
|
||||
|
||||
La explicación de arriba es suficiente para usar y entender CLTV. Sin embargo, [BIP 65](https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki), expone todos los detalles.
|
||||
|
||||
Un script bloqueante solo permitirá a una transacción volver a gastar un UTXO bloqueado con CLTV si `OP_CHECKLOCKTIMEVALUE` verifica todo lo siguiente:
|
||||
|
||||
* El campo `nSequence` debe ser configurado a menos de 0xffffffff, usualmente 0xfffffffff-1, para evitar conflictos con los bloqueos de tiempo relativos.
|
||||
* CLTV debe sacar un operando fuera de la pila y este debe ser mayor o igual a 0.
|
||||
* Tanto el operando de la pila como `nLockTime` deben estar sobre o debajo de los 500 millones, para representar el mismo tipo de bloqueo de tiempo absoluto.
|
||||
* El valor `nLockTime` debe ser mayor o igual al del operando de la pila.
|
||||
|
||||
Entonces, la primera cosa a notar aquí es que `nLockTime` sigue siendo usado con CLTV. Para ser precisos, es requerido en las transacciones que intentan _volver a gastar_ un UTXO bloqueado temporalmente con CLTV. Esto significa, que no es parte de los requerimientos del script. Es solo un temporizador que es usado para liberar fondos, _como esta definido en el script_.
|
||||
|
||||
Esto es gestionado a través de un perspicaz entendimiento de como `nLockTime` funciona: un valor para `nLockTime` debe ser siempre elegido para que sea menor o igual al tiempo presente (o altura de bloque), para que así la transacción que vuelve a gastar los fondos pueda ser incluida en la cadena de bloques. Sin embargo, debido a los requerimientos de CLTV, un valor también debe ser elegido para ser mayor o igual al operando CLTV. La unión de estos dos conjuntos es `NULL` hasta que el tiempo actual sea igual al operando CLTV. Después de todo, cualquier valor puede ser elegido entre el operando CLTV y el tiempo actual. Usualmente, usted solo lo configurara al tiempo actual (o bloque).
|
||||
|
||||
## Escribir un Script CLTV.
|
||||
|
||||
`OP_CHECKLOCKTIMEVERIFY` incluye un `OP_VERIFY`, lo que significa que se detendrá inmediatamente el script si su verificación no tiene éxito. Tiene otra peculiaridad: a diferencia de la mayoría de los comandos de verificación, este deja lo que se esta comprobando en la pila (solo en caso de que quiera hacer mas comparaciones contra el tiempo). Esto significa que un `OP_CHECKLOCKTIMEVERIFY` es usualmente seguido por un `OP_DROP` para limpiar la pila.
|
||||
|
||||
El siguiente simple script de bloqueo puede ser usado para transformar el output de una transacción P2PKH a una transacción P2PKH con bloqueo de tiempo.
|
||||
```
|
||||
<AñoSiguiente> OP_CHECKLOCKTIMEVERIFY OP_DROP OP_DUP OP_HASH160 <HashLlavePública> OP_EQUALVERIFY OP_CHECKSIG
|
||||
```
|
||||
|
||||
### Codificar un Script CLTV
|
||||
|
||||
Por supuesto, como con cualquier Bitcoin Script complejo, este script CLTV sera codificado de hecho en un script P2SH, como se explica en [§10.1: Entendiendo la Base de P2SH](10_1_Entendiendo_la_Base_de_P2SH.md) y [§10.2: Construyendo la estructura de P2SH](10_2_Construyendo_la_Estructura_de_P2SH.md).
|
||||
|
||||
Asumiendo que `<SiguienteAño>` fuera el entero "1546288031" (hexadecimal en "little-endian": 0x9f7b2a5c) y `<HashLlavePública>` fuera "371c20fb2e9899338ce5e99908e64fd30b789313", este `redeemScript` seria construido como:
|
||||
```
|
||||
OP_PUSHDATA (4 bytes) 0x9f7b2a5c OP_CHECKLOCKTIMEVERIFY OP_DROP OP_DUP OP_HASH160 OP_PUSHDATA (20 bytes) 0x371c20fb2e9899338ce5e99908e64fd30b789313 OP_EQUALVERIFY OP_CHECKSIG
|
||||
```
|
||||
El cual se traduce a hexadecimal como:
|
||||
```
|
||||
04 9f7b2a5c b1 75 76 a9 14 371c20fb2e9899338ce5e99908e64fd30b789313 88 ac
|
||||
```
|
||||
O si lo prefiere:
|
||||
```
|
||||
$ btcc 0x9f7b2a5c OP_CHECKLOCKTIMEVERIFY OP_DROP OP_DUP OP_HASH160 0x371c20fb2e9899338ce5e99908e64fd30b789313 OP_EQUALVERIFY OP_CHECKSIG
|
||||
049f7b2a5cb17576a914371c20fb2e9899338ce5e99908e64fd30b78931388ac
|
||||
```
|
||||
El RPC `decodescript` puede verificar que lo hicimos bien:
|
||||
```
|
||||
{
|
||||
"asm": "1546288031 OP_CHECKLOCKTIMEVERIFY OP_DROP OP_DUP OP_HASH160 371c20fb2e9899338ce5e99908e64fd30b789313 OP_EQUALVERIFY OP_CHECKSIG",
|
||||
"type": "nonstandard",
|
||||
"p2sh": "2MxANZMPo1b2jGaeKTv9rwcBEiXcXYCc3x9",
|
||||
"segwit": {
|
||||
"asm": "0 07e55bf1eaedf43ec52af57b77ad7330506c209a70d17fa2e1853304aa8e4e5b",
|
||||
"hex": "002007e55bf1eaedf43ec52af57b77ad7330506c209a70d17fa2e1853304aa8e4e5b",
|
||||
"reqSigs": 1,
|
||||
"type": "witness_v0_scripthash",
|
||||
"addresses": [
|
||||
"tb1qqlj4hu02ah6ra3f274ah0ttnxpgxcgy6wrghlghps5esf25wfedse4yw4w"
|
||||
],
|
||||
"p2sh-segwit": "2N4HTwMjVdm38bdaQ5h3X3VktLY74D2qBoK"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
No vamos a estar mostrando continuamente como todos los Bitcoin Scripts se codifican en transacciones P2SH, pero en su lugar ofrecemos estas abreviaturas: cuando describimos un script, sera un `redeemScript`, el cual sera normalmente serializado y codificado mediante una función hash en el script con bloqueo de tiempo y serializado en el script de desbloqueo; cuando mostremos un procedimiento de desbloqueo, sera la segunda ronda de validaciones, siguiendo la confirmación del hash del script con bloqueo de tiempo.
|
||||
|
||||
## Gastar un UTXO CLTV
|
||||
|
||||
Para poder gastar un UTXO que esta bloqueado con CLTV, debe configurar `nLockTime` en su nueva transacción, Usualmente, solo querrá configurarlo al tiempo actual o bloque actual, como corresponde. Mientras el tiempo CLTV o la altura de bloque se encuentre en el pasado, y mientras suministre cualquier otro dato requerido por el script de desbloqueo, sera capaz de procesar el UTXO.
|
||||
|
||||
En el caso del ejemplo de arriba, el siguiente script de desbloqueo sera suficiente, dado que `nLockTime` fue configurado a algún momento antes de la fecha `<SiguienteAño>`, y que fuera, en efecto, al menos `<SiguienteAño>`:
|
||||
|
||||
### Correr un Script CLTV
|
||||
|
||||
Para correr el Script, deberá primero concatenar los scripts de desbloqueo y de bloqueo:
|
||||
```
|
||||
Script: <firma> <LlavePública> <SiguienteAño> OP_CHECKLOCKTIMEVERIFY OP_DROP OP_DUP OP_HASH160 <HashLlavePública> OP_EQUALVERIFY OP_CHECKSIG
|
||||
Stack: [ ]
|
||||
```
|
||||
Las tres constantes serán empujadas en la pila:
|
||||
```
|
||||
Script: OP_CHECKLOCKTIMEVERIFY OP_DROP OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
|
||||
Stack: [ <firma> <LlavePública> <SiguienteAño> ]
|
||||
```
|
||||
Luego, corre `OP_CHECKLOCKTIMEVERIFY`. Este encuentra algo en la pila y verifica que `nSequence` no sea 0xffffffff. Finalmente, compara `<SiguienteAño>` con `nLockTime`. Si ambos tienen el mismo tipo de representación y si `nLockTime >= <SiguienteAño>`, entonces procesa exitosamente (caso contrario, finaliza el script):
|
||||
```
|
||||
Script: OP_DROP OP_DUP OP_HASH160 <HashLlavePública> OP_EQUALVERIFY OP_CHECKSIG
|
||||
Running: <SiguienteAño> OP_CHECKLOCKTIMEVERIFY
|
||||
Stack: [ <firma> <LlavePública> <SiguienteAño> ]
|
||||
```
|
||||
Luego, `OP_DROP` se deshace de `<SiguienteAño>`, que quedaba rondando:
|
||||
```
|
||||
Script: OP_DUP OP_HASH160 <HashLlavePública> OP_EQUALVERIFY OP_CHECKSIG
|
||||
Running: <SiguienteAño> OP_DROP
|
||||
Stack: [ <firma> <LlavePública> ]
|
||||
```
|
||||
Finalmente, el resto del script se ejecuta, el cual es un chequeo normal de una firma y una llave pública.
|
||||
|
||||
## Resumen: Usando CLTV en Scripts
|
||||
|
||||
`OP_CHECKLOCKTIMEVERIFY` es un simple opcode que solo recibe un solo argumento, lo interpreta como altura de bloque o una estampa de tiempo UNIX, y solo permite a sus UTXO ser desbloqueadas si la altura de bloque o la estampa de tiempo UNIX esta en el pasado. Configurar `nLockTime` en la transacción de gasto es lo que permite a Bitcoin hacer este cálculo.
|
||||
|
||||
> :fire: ***¿Cual es el Poder de CLTV?** Usted ya a visto que los simples bloqueos de tiempo son las bases de los Contratos Inteligentes. CLTV toma el siguiente paso. Ahora puede garantizar que un UTXO no pueda ser gastado antes de cierto tiempo _y_ garantizar que no sera gastado tampoco. En su forma mas simple, esto podría ser usado para crear un fondo al que alguien solo pueda acceder cuando haya alcanzado los 18 años o un fondo de retiro al que solo pueda acceder cuando llegue a los 50. Sin embargo, su verdadero poder surge cuando es combinado con condicionales, donde el CLTV solo se activa ante ciertas situaciones.
|
||||
|
||||
## ¿Que sigue?
|
||||
|
||||
Continúe "Potenciando el Bloqueo de Tiempo" con [§11.3: Usando CSV en Scripts](11_3_Usando_CSV_en_Scripts.md).
|
148
es/11_3_Usando_CSV_en_Scripts.md
Normal file
148
es/11_3_Usando_CSV_en_Scripts.md
Normal file
@ -0,0 +1,148 @@
|
||||
# 11.3: Usando CSV en Scripts
|
||||
|
||||
`nLockTime` y `OP_CHECKLOCKTIMEVERIFY` (o CLTV) son solo una lado de la ecuación de los bloqueos de tiempo. En el otro lado están `nSequence` y `OP_CHECKSEQUENCEVERIFY`, las cuales pueden ser usadas para chequear contra tiempos relativos en lugar de tiempos absolutos.
|
||||
|
||||
> :warning: **ADVERTENCIA DE VERSIÓN:** CSV fue lanzado con Bitcoin Core 0.12.1, en la primavera de 2016.
|
||||
|
||||
## Entienda nSequence
|
||||
|
||||
Todo input dentro de una transacción tiene un valor `nSequence` (o si usted prefiere `sequence`). Este a sido una herramienta primaria en la expansión de Bitcoin, como fue discutido previamente en [5.2: Reenviando una Transacción con RBF](05_2_Reenviando_a_Transaccion_con_RBF.md) y [8.1: Enviando una Transacción con Bloqueo de Tiempo](08_1_Enviando_una_Transaccion_con_Bloqueo_de_Tiempo.md), donde fue usado para señalar RBF y `nLockTime`, respectivamente. Sin embargo, hay un uso mas para `nSequence`, descrito por [BIP 68](https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki): usted puede usarlo para crear un bloqueo de tiempo relativo en una transacción.
|
||||
|
||||
Un bloqueo de tiempo relativo es un bloqueo de tiempo sobre un input especifico de una transacción y es calculado en relación a la fecha de minado del UTXO siendo usado como input. Por ejemplo, si un UTXO fue minado en el bloque #468260 y una transacción fue creada donde al input para este UTXO se le dio un `nSequence` de 100, entonces la nueva transacción no va a poder ser minada hasta el bloque #468360.
|
||||
|
||||
Fácil!
|
||||
|
||||
> :information_source: **NOTA — SECUENCIA:** Este es el tercer uso del valor `nSequence` en Bitcoin. Cualquier valor `nSequence` sin el trigésimo segundo bit configurado (1<<31),de 0x00000001 a 0x7ffffffff, sera interpretado como un bloqueo de tiempo relativo. Si `nVersion ≥ 2` (el cual es el valor por defecto desde Bitcoin Core 0.14.0). Debe ser cuidadoso para asegurarse que los bloqueos de tiempo relativo no entran en conflicto con los otros dos usos de `nSequence`, para señalar `nTimeLock` y RBF. `nTimeLock` usualmente se configura a un valor de 0xffffffff-1, donde un bloqueo de tiempo relativo no es permitido; y RBF usualmente configura su valor a "1", donde un bloqueo de tiempo relativo es irrelevante, porque este define un bloqueo de tiempo de 1 bloque.
|
||||
|
||||
> En general, recuerda: con un valor de `nVersion` de 2, un valor de `nSequence` de 0x00000001 a 0x7fffffff permite un bloqueo relativo de tiempo, RBF, y `nTimeLock`; un valor de `nSequence` de 0x7fffffff a 0xffffffff-2 permite RBF y `nTimeLock`; un valor `nSequence` de 0xffffffff-1 permite solo `nTimeLock`; un valor `nSequence` igual a 0xffffffff no habilita nada; y `nVersion` puede ser configurada al valor 1 para no permitir los bloqueos de tiempo relativo para cualquier valor de `nSequence`. Uf!
|
||||
|
||||
### Crea una transacción CSV con Tiempo de Bloque Relativo
|
||||
|
||||
El formato para usar `nSequence` para representar bloqueos de tiempo relativo esta definido en [BIP 68](https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki) y es levemente mas complejo que solo introducir un numero, como hizo para `nTimeLock`. En su lugar, las especificaciones BIP dividen los cuatro bytes en tres partes:
|
||||
|
||||
* Los primeros dos bytes son usados para especificar un bloqueo de tiempo relativo.
|
||||
* El vigésimo tercer bit es usado para señalar positivamente si el bloqueo se refiere a un tiempo en lugar de a una altura de bloque.
|
||||
* El trigésimo segundo bit es usado para señalar positivamente si los bloqueos de tiempo relativos están desactivados.
|
||||
|
||||
Con todo eso dicho, la construcción de un bloqueo relativo de tiempo basado en el bloque es todavía bastante fácil, porque los dos bits marcados son configurados a un valor `0`, por lo que solo tiene que configurar `nSequence` a un valor entre 1 y 0xffff (65535). La nueva transacción puede ser minada ese numero de bloques después de que el UTXO asociado fue minado.
|
||||
|
||||
### Crea una transacción CSV de Tiempo Relativo
|
||||
|
||||
Puede en cambio configurar `nSequence` como un tiempo relativo, donde el bloque dura por 512 segundos multiplicado por el valor de `nSequence`.
|
||||
|
||||
Con el fin de hacer eso:
|
||||
|
||||
1. Decida cuan lejos en el futuro configurar su bloqueo de tiempo relativo.
|
||||
2. Convierta ese valor a segundos.
|
||||
3. Divida por 512.
|
||||
4. Redondee ese valor hacia arriba o abajo y configure `nSequence` a ese valor.
|
||||
5. Configure el vigésimo tercer bit a verdadero.
|
||||
|
||||
Para configurar un tiempo de 6 meses en el futuro, debe primero calcularlo como sigue:
|
||||
```
|
||||
$ segundos=$((6*30*24*60*60))
|
||||
$ nvalor=$(($segundos/512))
|
||||
```
|
||||
Luego, conviértalo a hexadecimal:
|
||||
```
|
||||
$ valorhexadecimal=$(printf '%x\n' $nvalor)
|
||||
```
|
||||
Finalmente, haga un or bit a bit del vigésimo tercer bit dentro del valor hexadecimal que creo:
|
||||
```
|
||||
$ valorrelativo=$(printf '%x\n' $((0x$valorhexadecimal | 0x400000)))
|
||||
$ echo $valorrelativo
|
||||
4224679
|
||||
```
|
||||
Si usted convierte el valor a binario vera que 4224679 = 10000000111011010100111. El vigésimo tercer dígito es configurado a "1"; mientras tanto, los primeros 2 bytes, 0111011010100111, convierta a 76A7 en hexadecimal o 30375 en decimal. Multiplique eso por 512 y obtendrá 15.55 millones de segundos, lo que es, de hecho, 180 días.
|
||||
|
||||
## Crea una transacción con Bloqueo de Tiempo Relativo
|
||||
|
||||
¿Entonces, usted quiere crear una transacción simple con bloqueo de tiempo relativo? Todo lo que tiene que hacer es emitir una transacción donde el valor `nSequence` en un input es configurado como se muestra arriba: con el valor `nSequence` para ese input configurado de forma tal que los primeros dos bytes definan el bloqueo de tiempo, el vigésimo tercer bit defina el tipo de bloque de tiempo y el trigésimo segundo bit tenga un valor de falso.
|
||||
|
||||
Emita la transacción y usted vera que no puede ser minada legalmente hasta que suficientes bloques o suficiente tiempo haya pasado mas allá del tiempo en el que esa UTXO fue minada.
|
||||
|
||||
Prácticamente nadie hace eso. En el [BIP 68](https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki) definiciones para `nSequence` fueron incorporadas dentro de Bitcoin Core al mismo tiempo que [BIP 112](https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki), el cual describe el opcode CSV, el equivalente al `nSequence` para el opcode CLTV. Al igual que CLTV, CSV ofrece capacidades mejoradas. Entonces, casi todo el uso de bloqueos de tiempo relativo han sido con el opcode CSV, no con el valor crudo `nSequence` por si mismo.
|
||||
|
||||
| | Bloqueos de Tiempo Absolutos | Bloqueos de Tiempo Absolutos |
|
||||
|:-----------------------:|------------------------------|------------------------------|
|
||||
| **Bloquea transacción** | nTimeLock | nSequence |
|
||||
| **Bloquea Output** | OP_CHECKLOCKTIMEVERIFY | OP_CHECKSEQUENCEVERIFY |
|
||||
|
||||
## Entienda el Opcode CSV
|
||||
|
||||
`OP_SEQUENCEVERIFY` en Bitcoin Scripts funciona bastante parecido a `OP_LOCKTIMEVERIFY`.
|
||||
|
||||
Puede que requiera conservar una UTXO por una centena de bloques mas allá de su minado:
|
||||
```
|
||||
100 OP_CHECKSEQUENCEVERIFY
|
||||
```
|
||||
O puede hacer un calculo mas complejo que requiera que conserve un UTXO por seis meses, en cuyo caso terminara con un numero mas complejo:
|
||||
```
|
||||
4224679 OP_CHECKSEQUENCEVERIFY
|
||||
```
|
||||
En este caso usaremos una abreviatura:
|
||||
```
|
||||
<+6Meses> OP_CHECKSEQUENCEVERIFY
|
||||
```
|
||||
|
||||
> :warning: **ADVERTENCIA:** Recuerde que un bloqueo de tiempo relativo es un lapso de tiempo desde el minado de el UTXO usado como input. _No_ es un lapso de tiempo después de que la transacción es creada. Si usa un UTXO que ya ha sido confirmado una centena de veces, y usted configura un bloqueo de tiempo de 100 bloques sobre este, sera elegible para minarse inmediatamente. Los bloqueos de tiempo relativos tienen usos bien específicos, pero probablemente no apliquen si su único objetivo es determinar algún tiempo fijado en el futuro.
|
||||
|
||||
### Entienda Como Funciona Realmente CSV
|
||||
|
||||
CSV tiene muchas de las sutilezas en su uso como CLTV:
|
||||
|
||||
* El campo `nVersion` le debe ser asignado el valor 2 o mayor.
|
||||
* El campo `nSequence` debe ser menor que 0x80000000.
|
||||
* Cuando CSV es ejecutado, debe haber un operando en la pila que este entre 0 y 0xf0000000-1.
|
||||
* Ambos, el operando de la pila y `nSequence` deben tener el mismo valor en el vigésimo tercer bit.
|
||||
* El valor `nSequence` debe ser mayor o igual al operando de la pila.
|
||||
|
||||
Tal como con CLTV, cuando esta gastando un UTXO con CSV, en sus condiciones de bloqueo, debe configurar el campo `nSequence` para habilitar la transacción. Usted usualmente lo configurara al valor exacto del script bloqueante.
|
||||
|
||||
## Escriba un Script CSV
|
||||
|
||||
Al igual que `OP_CHECKLOCKTIMEVERIFY`, `OP_CHECKSEQUENCEVERIFY` incluye un `OP_VERIFY` implícito y deja sus argumentos en la pila, requiriendo un `OP_DROP` cuando haya terminado.
|
||||
|
||||
Un script que bloqueara fondos hasta que hayan pasado seis meses después del minado del input, y que requerirá una firma P2PKH estándar se vera de la siguiente manera:
|
||||
```
|
||||
<+6Meses> OP_CHECKSEQUENCEVERIFY OP_DROP OP_DUP OP_HASH160 <HashLlavePublica> OP_EQUALVERIFY OP_CHECKSIG
|
||||
```
|
||||
|
||||
### Codifique un Script CSV
|
||||
|
||||
Cuando codifica un script CSV, sea cuidadoso en como codifica el valor entero para el bloqueo de tiempo relativo. Este debe pasarse como un entero de 3 bytes, lo que significa que se ignora el byte mas grande, lo cual podría no activar el bloqueo de tiempo relativo. Dado que es un entero, asegúrese de convertirlo al formato 'little-endian'.
|
||||
|
||||
Esto puede realizarse con el shell script `integer2lehex.sh` del capitulo previo.
|
||||
|
||||
Para un tiempo relativo de 100 bloques:
|
||||
```
|
||||
$ ./integer2lehex.sh 100
|
||||
Integer: 100
|
||||
LE Hex: 64
|
||||
Length: 1 bytes
|
||||
Hexcode: 0164
|
||||
```
|
||||
Aunque eso debería ser rellenado a `000064`, requiriendo un código de `03000064`.
|
||||
|
||||
Para un tiempo relativo de 6 meses:
|
||||
```
|
||||
$ ./integer2lehex.sh 4224679
|
||||
Integer: 4224679
|
||||
LE Hex: a77640
|
||||
Length: 3 bytes
|
||||
Hexcode: 03a77640
|
||||
```
|
||||
|
||||
## Gaste una UTXO CSV
|
||||
|
||||
Para gastar un UTXO bloqueado con un script CSV, debe configurar el valor `nSequence` de ese input a un valor mas grande que el requerido en el script, pero menor que el tiempo entre el UTXO y el bloque actual. Sí, esto significa que usted necesita saber exactamente el requerimiento en el script bloqueante... pero tiene una copia de `redeemScript`, entonces, si no conoce los requerimientos, deserializa la copia y luego configura el valor `nSequence` al numero que se muestra en esta.
|
||||
|
||||
## Resumen: Usando CSV en Scripts
|
||||
|
||||
`nSequence` y CSV ofrecen una alternativa a `nLockTime` y CLTV donde usted bloquea una transacción basada en un tiempo relativo desde que el input fue minado, en lugar de basar el bloqueo en un tiempo fijado en el futuro. Estos funcionan casi de la misma manera, mas allá del hecho que el valor de `nSequence` es codificado levemente distinto que el valor de `nLockTime`, con bits específicos significando cosas especificas.
|
||||
|
||||
> :fire: ***¿Cual es el poder de CSV?*** CSV no es solo una forma perezosa de bloquear, cuando usted no quiere calcular un tiempo en el futuro. En su lugar, es un paradigma totalmente diferente, un bloqueo que utilizaría si fuera importante crear una duración mínima especifica cuando una transacción es minada y cuando sus fondos pueden ser re-gastados. El uso mas obvio es (una vez mas) para deposito, cuando usted quiere un tiempo preciso entre el input de los fondos y su output. Sin embargo, tiene posibilidades mucho mas poderosas en transacciones fuera de la cadena, incluyendo canales de pago. Esas aplicaciones son por definición construidas sobre transacciones que no han sido puestas en la cadena de bloques, lo cual significa que si son introducidas en la cadena un lapso de tiempo forzado podría ser muy útil. [Contratos por Bloqueos de Tiempo Hasheados](https://en.bitcoin.it/wiki/Hashed_Timelock_Contracts) ha sido una de estas implementaciones, potenciando la red de pagos Lightning. Estos son debatidos en [§13.3: Potenciando Bitcoin con Scripts](13_3_Potenciando_Bitcoin_con_Scripts.md).
|
||||
|
||||
## ¿Que sigue?
|
||||
|
||||
Avanza a través de "Bitcoin Scripting" con [12.0: Expandiendo Scripts Bitcoin](12_0_Expandiendo_Scripts_Bitcoin.md)
|
20
es/12_0_Expandiendo_Scripts_Bitcoin.md
Normal file
20
es/12_0_Expandiendo_Scripts_Bitcoin.md
Normal file
@ -0,0 +1,20 @@
|
||||
# Capítulo 12: Expandiendo los scripts de Bitcoin
|
||||
|
||||
Todavía hay un poco más en los scripts de Bitcoin. Los condicionales le brindan acceso completo al control de flujo, mientras que una variedad de otros códigos de operación pueden ampliar sus posibilidades.
|
||||
|
||||
## Objetivos de este capítulo
|
||||
|
||||
Después de trabajar en este capítulo, un desarrollador podrá:
|
||||
|
||||
* Decidir cómo utilizar los scripts condicionales
|
||||
* Decidir cómo utilizar otros códigos de operación de script
|
||||
|
||||
Los objetivos de apoyo incluyen la capacidad de:
|
||||
|
||||
* Comprender la gama completa de posibilidades del Scripting
|
||||
* Identificar cómo obtener más información sobre los códigos de operación (opcodes)
|
||||
|
||||
## Tabla de contenido
|
||||
|
||||
* [Sección uno: Usando scripts condicionales](12_1_Usando_Script_Condicionales.md)
|
||||
* [Sección dos: Usando otros comandos de scripting](12_2_Usando_Otros_Comandos_de_Scripting.md)
|
262
es/12_1_Usando_Script_Condicionales.md
Normal file
262
es/12_1_Usando_Script_Condicionales.md
Normal file
@ -0,0 +1,262 @@
|
||||
# 12.1: Usando scripts condicionales
|
||||
|
||||
Hay un aspecto final del Scripting de Bitcoin que es crucial para desbloquear su verdadero poder: los condicionales le permiten crear varias rutas de ejecución.
|
||||
|
||||
# Entienda VERIFY
|
||||
|
||||
Ya ha visto un condicional en los scripts: `OP_VERIFY` (0x69). Quita el elemento superior de la pila y comprueba si es verdadero; si no, finaliza la ejecución del script.
|
||||
|
||||
Verify generalmente se incorpora a otros códigos de operación. Ya ha visto `OP_EQUALVERIFY` (0xad),` OP_CHECKLOCKTIMEVERIFY` (0xb1) y `OP_CHECKSEQUENCEVERIFY` (0xb2). Cada uno de estos códigos de operación realiza su acción principal (comparar igualdad, verificar tiempo de bloqueo o secuencia de verificación) y luego realiza una verificación. Los otros códigos de operación de verificación que no ha visto son: `OP_NUMEQUALVERIFY` (0x9d),` OP_CHECKSIGVERIFY` (0xad) y `OP_CHECKMULTISIGVERIFY` (0xaf).
|
||||
|
||||
Entonces, ¿cómo es `OP_VERIFY` un condicional? Es el tipo de condicional más poderoso. Usando `OP_VERIFY`, _si_ una condición es verdadera,
|
||||
el Script continúa ejecutándose, _de lo contrario_ el script finaliza. Así es como verifica las condiciones que son absolutamente necesarias para que
|
||||
un script tenga éxito. Por ejemplo, el script P2PKH (`OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG`) tiene dos condiciones requeridas: (1) que la clave pública proporcionada coincide con el hash de clave pública; y (2) que la firma proporcionada coincida con esa clave pública.
|
||||
Un `OP_EQUALVERIFY` se usa para la comparación de la clave pública luego del hash y el hash de la clave pública porque es una condición absolutamente necesaria.
|
||||
No _desea_ que el script continúe si eso falla.
|
||||
|
||||
Puede notar que no hay `OP_VERIFY` al final de este script (o de la mayoría de estos), a pesar de que también se requiere la condición final.
|
||||
Eso es porque Bitcoin efectivamente hace un `OP_VERIFY` al final de cada Script, para asegurar que el resultado final de la pila sea verdadero.
|
||||
No _desea_ hacer un `OP_VERIFY` antes del final del script, ¡porque necesita dejar algo en la pila para ser probado!
|
||||
|
||||
## Comprenda if / then
|
||||
|
||||
El otro condicional importante en Bitcoin Script es el clásico `OP_IF` (0x63) /` OP_ELSE` (0x67) / `OP_ENDIF` (0x68).
|
||||
Este es un control de flujo típico: si `OP_IF` detecta una declaración verdadera, ejecuta el bloque debajo de ella; de lo contrario, si hay un `OP_ELSE`,
|
||||
lo ejecuta; y `OP_ENDIF` marca el final del bloque final.
|
||||
|
||||
> :warning: **ADVERTENCIA:** Estos condicionales también son técnicamente códigos de operación, pero al igual que con los números pequeños,
|
||||
> dejaremos el prefijo `OP_` desactivado para mayor brevedad y claridad. Por lo tanto, escribiremos `IF`,`ELSE` y `ENDIF` en lugar de` OP_IF`, `OP_ELSE` y `OP_ENDIF`.
|
||||
|
||||
### Comprenda el ordenamiento de if / then
|
||||
|
||||
Hay dos grandes inconvenientes para los condicionales. Hacen que sea más difícil leer y evaluar los scripts si no se tiene cuidado.
|
||||
|
||||
Primero, el condicional `IF` verifica la verdad de lo que está _ antes de él_ (es decir, lo que está en la pila), no lo que está después.
|
||||
|
||||
En segundo lugar, el condicional `IF` tiende a estar en el script de bloqueo y lo que está comprobando tiende a estar en el script de desbloqueo.
|
||||
|
||||
Por supuesto, podría decirse, así es como funciona Bitcoin Script. Los condicionales usan la notación polaca inversa y adoptan el paradigma estándar de desbloqueo / bloqueo, al igual que _todo lo demás_ en el scripting de Bitcoin.
|
||||
Todo eso es cierto, pero también va en contra de la forma estándar en que leemos los condicionales IF / ELSE en otros lenguajes de programación; por lo tanto, es fácil leer inconscientemente los condicionales de Bitcoin incorrectamente.
|
||||
|
||||
Considere el siguiente código: `IF OP_DUP OP_HASH160 <pubKeyHashA> ELSE OP_DUP OP_HASH160 <pubKeyHashB> ENDIF OP_EQUALVERIFY OP_CHECKSIG`.
|
||||
|
||||
Mirar condicionales en notación de prefijo puede llevarlo a leer esto como:
|
||||
|
||||
```
|
||||
IF (OP_DUP) THEN
|
||||
|
||||
OP_HASH160
|
||||
OP_PUSHDATA <pubKeyHashA>
|
||||
|
||||
ELSE
|
||||
|
||||
OP_DUP
|
||||
OP_HASH160
|
||||
OP_PUSHDATA <pubKeyHashB>
|
||||
|
||||
ENDIF
|
||||
|
||||
OP_EQUALVERIFY
|
||||
OP_CHECKSIG
|
||||
```
|
||||
|
||||
Entonces, podría pensar, si el `OP_DUP` es exitoso, entonces podemos hacer el primer bloque, de lo contrario, el segundo.
|
||||
¡Pero eso no tiene ningún sentido! ¡¿Por qué el `OP_DUP` no tendría éxito ?!
|
||||
|
||||
Y, de hecho, no tiene ningún sentido, porque accidentalmente leemos la declaración usando la notación incorrecta. La lectura correcta de esto es:
|
||||
|
||||
```
|
||||
IF
|
||||
|
||||
OP_DUP
|
||||
OP_HASH160
|
||||
OP_PUSHDATA <pubKeyHashA>
|
||||
|
||||
ELSE
|
||||
|
||||
OP_DUP
|
||||
OP_HASH160
|
||||
OP_PUSHDATA <pubKeyHashB>
|
||||
|
||||
ENDIF
|
||||
|
||||
OP_EQUALVERIFY
|
||||
OP_CHECKSIG
|
||||
```
|
||||
|
||||
La declaración que se evaluará como "Verdadero" o "Falso" se coloca en la _pila_ antes de ejecutar el "IF", luego se ejecuta el bloque de código correcto en función de ese resultado.
|
||||
|
||||
Este código de ejemplo en particular está destinado a ser una firma múltiple 1 de 2 de un pobre hombre.
|
||||
El propietario de `<privKeyA>` pondría `<signatureA> <pubKeyA> True` en su script de desbloqueo, mientras que el propietario de` <privKeyB> `pondría` <signatureB> <pubKeyB> False` en su script de desbloqueo.
|
||||
Ese final de "Verdadero" o "Falso" es lo que marca la declaración `IF` / `ELSE`. Le dice al script con qué hash de clave pública se debe verificar, luego el `OP_EQUALVERIFY` y el `OP_CHECKSIG` al final hacen el trabajo real.
|
||||
|
||||
### Ejecute un If / Then multifirma
|
||||
|
||||
Con un conocimiento básico de los condicionales de Bitcoin en la mano, ahora estamos listos para ejecutar un script.
|
||||
Lo haremos creando una ligera variante de la firma múltiple 1 de 2 de nuestro pobre hombre, donde nuestros usuarios no tienen que recordar si son "Verdaderos" o "Falsos".
|
||||
En cambio, si es necesario, el script verifica ambos hash de clave pública, requiriendo que solo uno tenga éxito:
|
||||
|
||||
```
|
||||
OP_DUP OP_HASH160 <pubKeyHashA> OP_EQUAL
|
||||
IF
|
||||
|
||||
OP_CHECKSIG
|
||||
|
||||
ELSE
|
||||
|
||||
OP_DUP OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG
|
||||
|
||||
ENDIF
|
||||
|
||||
```
|
||||
|
||||
¡Recuerde su notación polaca inversa! ¡Esa declaración `IF` se refiere al` OP_EQUAL` previo, no al `OP_CHECKSIG` siguiente!
|
||||
|
||||
#### Ejecute la rama verdadera
|
||||
|
||||
Así es como se ejecuta realmente si se desbloquea con `<signatureA> <pubKeyA>`:
|
||||
|
||||
```
|
||||
Script: <signatureA> <pubKeyA> OP_DUP OP_HASH160 <pubKeyHashA> OP_EQUAL IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG ENDIF
|
||||
Stack: [ ]
|
||||
```
|
||||
|
||||
Primero, colocamos constantes en la pila:
|
||||
|
||||
```
|
||||
Script: OP_DUP OP_HASH160 <pubKeyHashA> OP_EQUAL IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG ENDIF
|
||||
Stack: [ <signatureA> <pubKeyA> ]
|
||||
```
|
||||
|
||||
Luego ejecutamos los primeros comandos obvios, `OP_DUP` y` OP_HASH160` y colocamos otra constante en la pila:
|
||||
|
||||
```
|
||||
Script: OP_HASH160 <pubKeyHashA> OP_EQUAL IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG ENDIF
|
||||
Running: <pubKeyA> OP_DUP
|
||||
Stack: [ <signatureA> <pubKeyA> <pubKeyA> ]
|
||||
|
||||
Script: <pubKeyHashA> OP_EQUAL IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG ENDIF
|
||||
Running: <pubKeyA> OP_HASH160
|
||||
Stack: [ <signatureA> <pubKeyA> <pubKeyHashA> ]
|
||||
|
||||
Script: OP_EQUAL IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG ENDIF
|
||||
Stack: [ <signatureA> <pubKeyA> <pubKeyHashA> <pubKeyHashA> ]
|
||||
```
|
||||
|
||||
A continuación, ejecutamos el `OP_EQUAL`, que es lo que va a alimentar el `IF`:
|
||||
|
||||
```
|
||||
Script: IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG ENDIF
|
||||
Running: <pubKeyHashA> <pubKeyHashA> OP_EQUAL
|
||||
Stack: [ <signatureA> <pubKeyA> True ]
|
||||
```
|
||||
|
||||
Ahora se ejecuta el `IF`, y como hay un` Verdadero`, solo se ejecuta el primer bloque, eliminando el resto:
|
||||
|
||||
```
|
||||
Script: OP_CHECKSIG
|
||||
Running: True IF
|
||||
Stack: [ <signatureA> <pubKeyA> ]
|
||||
```
|
||||
|
||||
Y el `OP_CHECKSIG` terminará siendo`True` también:
|
||||
|
||||
```
|
||||
Script:
|
||||
Running: <signatureA> <pubKeyA> OP_CHECKSIG
|
||||
Stack: [ True ]
|
||||
```
|
||||
|
||||
#### Ejecute la rama falsa
|
||||
|
||||
Así es como se ejecuta realmente si se desbloquea con `<signatureB> <pubKeyB>`:
|
||||
|
||||
```
|
||||
Script: <signatureB> <pubKeyB> OP_DUP OP_HASH160 <pubKeyHashA> OP_EQUAL IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG ENDIF
|
||||
Stack: [ ]
|
||||
```
|
||||
|
||||
Primero, colocamos constantes en la pila:
|
||||
|
||||
```
|
||||
Script: OP_DUP OP_HASH160 <pubKeyHashA> OP_EQUAL IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG ENDIF
|
||||
Stack: [ <signatureB> <pubKeyB> ]
|
||||
```
|
||||
|
||||
Luego ejecutamos los primeros comandos obvios, `OP_DUP` y` OP_HASH160` y colocamos otra constante en la pila:
|
||||
|
||||
```
|
||||
Script: OP_HASH160 <pubKeyHashA> OP_EQUAL IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG ENDIF
|
||||
Running: <pubKeyB> OP_DUP
|
||||
Stack: [ <signatureB> <pubKeyB> <pubKeyB> ]
|
||||
|
||||
Script: <pubKeyHashA> OP_EQUAL IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG ENDIF
|
||||
Running: <pubKeyB> OP_HASH160
|
||||
Stack: [ <signatureB> <pubKeyB> <pubKeyHashB> ]
|
||||
|
||||
Script: OP_EQUAL IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG ENDIF
|
||||
Stack: [ <signatureB> <pubKeyB> <pubKeyHashB> <pubKeyHashA> ]
|
||||
```
|
||||
|
||||
A continuación, ejecutamos el `OP_EQUAL`, que es lo que va a alimentar el `IF`:
|
||||
|
||||
```
|
||||
Script: IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG ENDIF
|
||||
Running: <pubKeyHashB> <pubKeyHashA> OP_EQUAL
|
||||
Stack: [ <signatureB> <pubKeyB> False ]
|
||||
```
|
||||
|
||||
¡Hey! El resultado fue `False` porque` <pubKeyHashB> `no es igual a` <pubKeyHashA> `. Ahora, cuando se ejecuta `IF`, se reduce el codigo a solo la declaración `ELSE`:
|
||||
|
||||
```
|
||||
Script: OP_DUP OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG
|
||||
Running: False IF
|
||||
Stack: [ <signatureB> <pubKeyB> ]
|
||||
```
|
||||
|
||||
Luego, repasamos todas las galimatías nuevamente comenzando con otro `OP_DUP`, pero eventualmente probando contra el otro` pubKeyHash`:
|
||||
|
||||
```
|
||||
Script: OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG
|
||||
Running: <pubKeyB> OP_DUP
|
||||
Stack: [ <signatureB> <pubKeyB> <pubKeyB> ]
|
||||
|
||||
Script: <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG
|
||||
Running: <pubKeyB> OP_HASH160
|
||||
Stack: [ <signatureB> <pubKeyB> <pubKeyHashB> ]
|
||||
|
||||
Script: OP_EQUALVERIFY OP_CHECKSIG
|
||||
Stack: [ <signatureB> <pubKeyB> <pubKeyHashB> <pubKeyHashB> ]
|
||||
|
||||
Script:OP_CHECKSIG
|
||||
Running: <pubKeyHashB> <pubKeyHashB> OP_EQUALVERIFY
|
||||
Stack: [ <signatureB> <pubKeyB> ]
|
||||
|
||||
Script:
|
||||
Running: <signatureB> <pubKeyB> OP_CHECKSIG
|
||||
Stack: [ True ]
|
||||
```
|
||||
|
||||
Esto probablemente no sea tan eficiente como un verdadero multisig de Bitcoin, pero es un buen ejemplo de cómo los resultados introducidos en la pila por pruebas anteriores pueden usarse para alimentar condicionales futuros.
|
||||
En este caso, es el fallo de la primera firma lo que le dice al condicional que debe ir a comprobar la segunda.
|
||||
|
||||
## Entienda otras condiciones
|
||||
|
||||
Hay algunos otros condicionales importantes. El grande es `OP_NOTIF` (0x64), que es lo opuesto a`OP_IF`: ejecuta el siguiente bloque si el elemento superior es `False`.
|
||||
Se puede colocar un `ELSE` con él, que como de costumbre se ejecuta si no se ejecuta el primer bloque. Aún termina con `OP_ENDIF`.
|
||||
|
||||
También hay un `OP_IFDUP` (0x73), que duplica el elemento de la pila superior solo si no es 0.
|
||||
|
||||
Estas opciones se utilizan con mucha menos frecuencia que la construcción principal `IF` /` ELSE` / `ENDIF`.
|
||||
|
||||
## Resumen: Usando scripts condicionales
|
||||
|
||||
Los condicionales en Bitcoin Script le permiten detener el script (usando `OP_VERIFY`) o elegir diferentes ramas de ejecución (usando`OP_IF`).
|
||||
Sin embargo, leer `OP_IF` puede ser un poco complicado. Recuerde que es el elemento empujado a la pila _antes_ de que se ejecute `OP_IF` el que controla su ejecución; ese elemento generalmente será parte del script de desbloqueo (o bien, un resultado directo de los elementos del script de desbloqueo).
|
||||
|
||||
> :fire: **¿Cuál es el poder de los condicionales?** Los condicionales de script son el último bloque de construcción principal en los scripts de Bitcoin. Son lo que se requiere para convertir scripts de Bitcoin simples y estáticos en scripts de Bitcoin complejos y dinámicos que pueden evaluarse de manera diferente en función de diferentes momentos, diferentes circunstancias o diferentes entradas de usuario.
|
||||
> En otras palabras, son la base final de los contratos inteligentes.
|
||||
|
||||
## ¿Que sigue?
|
||||
|
||||
Continúe "Expandiendo los scripts de Bitcoin" con [§12.2: Usando Otros Comandos de Scripting](12_2_Usando_Otros_Comandos_de_Scripting.md).
|
85
es/12_2_Usando_Otros_Comandos_de_Scripting.md
Normal file
85
es/12_2_Usando_Otros_Comandos_de_Scripting.md
Normal file
@ -0,0 +1,85 @@
|
||||
# 12.2: Usando otros comandos de scripting
|
||||
|
||||
Es posible que ya tenga a mano la mayoría de los códigos de operación de Bitcoin Script que utilizará en la mayoría de los scripts. Sin embargo, Bitcoin Script ofrece muchas más opciones, que podrían ser exactamente lo que necesita para crear el instrumento financiero de sus sueños.
|
||||
|
||||
Debería consultar la [página de Bitcoin Script](https://en.bitcoin.it/wiki/Script) para obtener una visión más detallada de todos estos y muchos otros comandos. Esta sección solo destaca los códigos de operación más notables.
|
||||
|
||||
## Comprenda los códigos de operación aritméticos
|
||||
|
||||
Los códigos de operación aritméticos manipulan o prueban números.
|
||||
|
||||
Manipular un número:
|
||||
|
||||
* OP_1ADD (0x8b) - Incremento en uno
|
||||
* OP_1SUB (0x8c) - disminución en uno
|
||||
* OP_NEGATE (0x8f) - Invierte el signo del número
|
||||
* OP_ABS (0x90) - Hacer que el número sea positivo
|
||||
* OP_NOT (0x91) - Voltea 1 y 0, de lo contrario 0
|
||||
|
||||
Vea también: `OP_0NOTEQUAL` (0x92)
|
||||
|
||||
Manipular dos números matemáticamente:
|
||||
|
||||
* OP_ADD (0x93) - Suma dos números
|
||||
* OP_SUB (0x94) - Resta dos números
|
||||
* OP_MIN (0xa3) - Devuelve el menor de dos números
|
||||
* OP_MAX (0xa4) - Devuelve el mayor de dos números
|
||||
|
||||
Manipular dos números de forma lógica:
|
||||
|
||||
* OP_BOOLAND (0x9a) - 1 si ambos números no son 0, de lo contrario 0
|
||||
* OP_BOOLOR (0x9b) - 1 si alguno de los números no es 0, de lo contrario 0
|
||||
|
||||
Comparar dos números
|
||||
|
||||
* OP_NUMEQUAL (0x9c) - 1 si ambos números son iguales, de lo contrario 0
|
||||
* OP_LESSTHAN (0x9f) - 1 si el primer número es menor que el segundo, de lo contrario 0
|
||||
* OP_GREATERTHAN (0xa0) - 1 si el primer número es mayor que el segundo, de lo contrario 0
|
||||
* OP_LESSTHANOREQUAL (0xa1) - 1 si el primer número es menor o igual que el segundo, de lo contrario 0
|
||||
* OP_GREATERTHANOREQUAL (0xa2) - 1 si el primer número es mayor o igual que el segundo, de lo contrario 0
|
||||
|
||||
Vea también: `OP_NUMEQUALVERIFY` (0x9d),`OP_NUMNOTEQUAL` (0x9e)
|
||||
|
||||
Probar tres números:
|
||||
|
||||
* OP_WITHIN (0xa5) - 1 si un número está en el rango de otros dos números
|
||||
|
||||
## Comprenda los códigos de operación de pila
|
||||
|
||||
Hay una cantidad sorprendente de códigos de operación de pila, pero aparte de `OP_DROP`,`OP_DUP` y, a veces, `OP_SWAP` generalmente no son necesarios si se tiene cuidado con el orden de las pilas. No obstante, aquí hay algunos de los más interesantes:
|
||||
|
||||
* OP_DEPTH (0x74) - Empuja el tamaño de la pila
|
||||
* OP_DROP (0x75) - Aparece el elemento de la pila superior
|
||||
* OP_DUP (0x76) - duplica el elemento de la pila superior
|
||||
* OP_PICK (0x79) - Duplica el enésimo elemento de la pila como la parte superior de la pila
|
||||
* OP_ROLL (0x7a) - Mueve el enésimo elemento de la pila a la parte superior de la pila
|
||||
* OP_SWAP (0x7c) - intercambia los dos elementos superiores de la pila
|
||||
|
||||
Vea también: `OP_TOALTSTACK` (0x6b),`OP_FROMALTSTACK` (0x6c), `OP_2DROP` (0x6d),`OP_2DUP` (0x6e), `OP_3DUP` (0x6f),`OP_2OVER` (0x70), `OP_271` ), `OP_2ROT` (0x71), `OP_2SWAP` (0x72), `OP_IFDUP` (0x73), `OP_NIP` (0x77), `OP_OVER` (0x78), `OP_ROT` (0x7b) y `OP_TUCK` (0x7d).
|
||||
|
||||
## Comprenda los códigos de operación criptográficos
|
||||
|
||||
Por último, una variedad de códigos de operación admiten hash y verificación de firmas:
|
||||
|
||||
Hash:
|
||||
|
||||
* OP_RIPEMD160 (0xa6) - RIPEMD-160
|
||||
* OP_SHA1 (0xa7) - SHA-1
|
||||
* OP_SHA256 (0xa8) - SHA-256
|
||||
* OP_HASH160 (0xa9) - SHA-256 + RIPEMD-160
|
||||
* OP_HASH256 (0xaa) - SHA-256 + SHA-256
|
||||
|
||||
Comprobar firmas:
|
||||
|
||||
* OP_CHECKSIG (0xac) - Verifique una firma
|
||||
* OP_CHECKMULTISIG (0xae) - Verifica un multisig de m de n
|
||||
|
||||
Consulte también: `OP_CODESEPARATOR` (0xab),`OP_CHECKSIGVERIFY` (0xad) y `OP_CHECKMULTISIGVERIFY` (0xaf).
|
||||
|
||||
## Resumen: Usando otros comandos de scripting
|
||||
|
||||
Bitcoin Script incluye una amplia variedad de códigos de operación aritméticos, de pila y criptográficos. La mayoría de estos códigos de operación adicionales probablemente no sean tan comunes como los que se discutieron en las secciones anteriores, pero no obstante, están disponibles si son justo lo que necesita para escribir su script.
|
||||
|
||||
## ¿Que sigue?
|
||||
|
||||
Avance a través de "Scripts de Bitcoin" con el [Capítulo trece: Diseñando scripts de bitcoin reales](13_0_Disenando_Bitcoin_Scripts_Reales.md).
|
21
es/13_0_Disenando_Bitcoin_Scripts_Reales.md
Normal file
21
es/13_0_Disenando_Bitcoin_Scripts_Reales.md
Normal file
@ -0,0 +1,21 @@
|
||||
# Capítulo 13: Diseñando Bitcoin Scripts Reales
|
||||
|
||||
Nuestros scripts de Bitcoin hasta la fecha han sido en gran parte ejemplos teóricos, porque todavía hemos estado juntando las piezas del rompecabezas. Ahora, con el repertorio completo de Bitcoin Script en la mano, estamos listos para profundizar en varios Scripts de Bitcoin del mundo real y ver cómo funcionan.
|
||||
|
||||
## Objetivos de este capítulo
|
||||
|
||||
Después de trabajar en este capítulo, un desarrollador podrá:
|
||||
|
||||
* Evaluar los scripts de Bitcoin del mundo real
|
||||
* Crear scripts de Bitcoin del mundo real
|
||||
|
||||
Los objetivos de apoyo incluyen la capacidad de:
|
||||
|
||||
* Comprender los scripts de Bitcoin existentes
|
||||
* Comprender la importancia de las firmas
|
||||
|
||||
## Tabla de contenido
|
||||
|
||||
* [Sección uno: Escribiendo scripts rompecabezas](13_1_Escribiendo_Puzzle_Scripts.md)
|
||||
* [Sección dos: Escribiendo scripts multifirma complejos](13_2_Escribiendo_Scripts_Multifirma_Complejos.md)
|
||||
* [Sección tres: Potenciando Bitcoin con Scripts](13_3_Potenciando_Bitcoin_con_Scripts.md)
|
523
es/13_1_Escribiendo_Puzzle_Scripts.md
Normal file
523
es/13_1_Escribiendo_Puzzle_Scripts.md
Normal file
@ -0,0 +1,523 @@
|
||||
# 13.1: Escribir scripts rompecabezas
|
||||
|
||||
Los scripts de Bitcoin realmente _no_ tienen que depender del conocimiento de una clave secreta. En cambio, pueden ser rompecabezas de cualquier tipo.
|
||||
|
||||
## Escribir scripts de álgebra simples
|
||||
|
||||
Nuestro primer script real, de [§9.2: Ejecutando un script de Bitcoin](09_2_Ejecutando_un_Script_Bitcoin.md) fue un acertijo algebraico. Ese script de Bitcoin, `OP_ADD 99 OP_EQUAL`, podría haberse descrito alternativamente como` x + y = 99`.
|
||||
|
||||
Este tipo de script no tiene mucha aplicabilidad en el mundo real, ya que es demasiado fácil reclamar los fondos. Pero, un concurso de resolución de acertijos que distribuya pequeñas cantidades de satoshis podría ofrecerlo como un entretenimiento divertido.
|
||||
|
||||
Más notablemente, la creación de acertijos alegebraicos le brinda una buena comprensión de cómo funcionan las funciones aritméticas en Bitcoin Script.
|
||||
|
||||
### Escriba un script multiplicador
|
||||
|
||||
Bitcoin Script tiene varios códigos de operación que se desactivaron para mantener la seguridad del sistema. Uno de ellos es `OP_MUL`, que habría permitido la multiplicación ... pero está deshabilitado.
|
||||
|
||||
Entonces, ¿cómo escribirías una función algebraica como `3x + 7 = 13`?
|
||||
|
||||
La respuesta más obvia es `OP_DUP`, el número ingresado desde el script de bloqueo dos veces. Luego puede presionar el `7` y seguir sumando hasta obtener el total. El script de bloqueo completo se vería así: `OP_DUP OP_DUP 7 OP_ADD OP_ADD OP_ADD 13 OP_EQUAL`.
|
||||
|
||||
Así es como se ejecutaría si se ejecutara con el script de desbloqueo correcto de `2`:
|
||||
|
||||
```
|
||||
Script: 2 OP_DUP OP_DUP 7 OP_ADD OP_ADD OP_ADD 13 OP_EQUAL
|
||||
Stack: [ ]
|
||||
|
||||
Script: OP_DUP OP_DUP 7 OP_ADD OP_ADD OP_ADD 13 OP_EQUAL
|
||||
Stack: [ 2 ]
|
||||
|
||||
Script: OP_DUP 7 OP_ADD OP_ADD OP_ADD 13 OP_EQUAL
|
||||
Running: 2 OP_DUP
|
||||
Stack: [ 2 2 ]
|
||||
|
||||
Script: 7 OP_ADD OP_ADD OP_ADD 13 OP_EQUAL
|
||||
Running: 2 OP_DUP
|
||||
Stack: [ 2 2 2 ]
|
||||
|
||||
Script: OP_ADD OP_ADD OP_ADD 13 OP_EQUAL
|
||||
Stack: [ 2 2 2 7 ]
|
||||
|
||||
Script: OP_ADD OP_ADD 13 OP_EQUAL
|
||||
Running: 2 7 OP_ADD
|
||||
Stack: [ 2 2 9 ]
|
||||
|
||||
Script: OP_ADD 13 OP_EQUAL
|
||||
Running: 2 9 OP_ADD
|
||||
Stack: [ 2 11 ]
|
||||
|
||||
Script: 13 OP_EQUAL
|
||||
Running: 2 11 OP_ADD
|
||||
Stack: [ 13 ]
|
||||
|
||||
Script: OP_EQUAL
|
||||
Stack: [ 13 13 ]
|
||||
|
||||
Script:
|
||||
Running: 13 13 OP_EQUAL
|
||||
Stack: [ True ]
|
||||
```
|
||||
O si prefiere `btcdeb`:
|
||||
|
||||
```
|
||||
$ btcdeb '[2 OP_DUP OP_DUP 7 OP_ADD OP_ADD OP_ADD 13 OP_EQUAL]'
|
||||
btcdeb 0.2.19 -- type `btcdeb -h` for start up options
|
||||
valid script
|
||||
9 op script loaded. type `help` for usage information
|
||||
script | stack
|
||||
---------+--------
|
||||
2 |
|
||||
OP_DUP |
|
||||
OP_DUP |
|
||||
7 |
|
||||
OP_ADD |
|
||||
OP_ADD |
|
||||
OP_ADD |
|
||||
13 |
|
||||
OP_EQUAL |
|
||||
|
||||
#0000 2
|
||||
btcdeb> step
|
||||
<> PUSH stack 02
|
||||
script | stack
|
||||
---------+--------
|
||||
OP_DUP | 02
|
||||
OP_DUP |
|
||||
7 |
|
||||
OP_ADD |
|
||||
OP_ADD |
|
||||
OP_ADD |
|
||||
13 |
|
||||
OP_EQUAL |
|
||||
|
||||
#0001 OP_DUP
|
||||
btcdeb> step
|
||||
<> PUSH stack 02
|
||||
script | stack
|
||||
---------+--------
|
||||
OP_DUP | 02
|
||||
7 | 02
|
||||
OP_ADD |
|
||||
OP_ADD |
|
||||
OP_ADD |
|
||||
13 |
|
||||
OP_EQUAL |
|
||||
|
||||
#0002 OP_DUP
|
||||
btcdeb> step
|
||||
<> PUSH stack 02
|
||||
script | stack
|
||||
---------+--------
|
||||
7 | 02
|
||||
OP_ADD | 02
|
||||
OP_ADD | 02
|
||||
OP_ADD |
|
||||
13 |
|
||||
OP_EQUAL |
|
||||
|
||||
#0003 7
|
||||
btcdeb> step
|
||||
<> PUSH stack 07
|
||||
script | stack
|
||||
---------+--------
|
||||
OP_ADD | 07
|
||||
OP_ADD | 02
|
||||
OP_ADD | 02
|
||||
13 | 02
|
||||
OP_EQUAL |
|
||||
|
||||
#0004 OP_ADD
|
||||
btcdeb> step
|
||||
<> POP stack
|
||||
<> POP stack
|
||||
<> PUSH stack 09
|
||||
script | stack
|
||||
---------+--------
|
||||
OP_ADD | 09
|
||||
OP_ADD | 02
|
||||
13 | 02
|
||||
OP_EQUAL |
|
||||
|
||||
#0005 OP_ADD
|
||||
btcdeb> step
|
||||
<> POP stack
|
||||
<> POP stack
|
||||
<> PUSH stack 0b
|
||||
script | stack
|
||||
---------+--------
|
||||
OP_ADD | 0b
|
||||
13 | 02
|
||||
OP_EQUAL |
|
||||
|
||||
#0006 OP_ADD
|
||||
btcdeb> step
|
||||
<> POP stack
|
||||
<> POP stack
|
||||
<> PUSH stack 0d
|
||||
script | stack
|
||||
---------+--------
|
||||
13 | 0d
|
||||
OP_EQUAL |
|
||||
#0007 13
|
||||
btcdeb> step
|
||||
<> PUSH stack 0d
|
||||
script | stack
|
||||
---------+--------
|
||||
OP_EQUAL | 0d
|
||||
| 0d
|
||||
|
||||
#0008 OP_EQUAL
|
||||
btcdeb> step
|
||||
<> POP stack
|
||||
<> POP stack
|
||||
<> PUSH stack 01
|
||||
script | stack
|
||||
---------+--------
|
||||
| 01
|
||||
```
|
||||
|
||||
### Escriba un sistema de ecuaciones
|
||||
|
||||
¿Qué pasaría si quisiera escribir un sistema de ecuaciones, como `x + y = 3`,` y + z = 5` y `x + z = 4`? Un poco de álgebra te dice que las respuestas son `x = 1`,` y = 2` y `z = 3`. Pero, ¿cómo lo escribe?
|
||||
|
||||
Lo más obvio es que después de que el redentor de los fondos ingrese los tres números, necesitará dos copias de cada número, ya que cada número entra en dos ecuaciones diferentes. `OP_3DUP` se encarga de eso y da como resultado que`x y z x y z` esté en la pila. Sacar dos elementos a la vez le dará `y z`,` z x` y `x y`. ¡Voila! Estas son las tres ecuaciones, ¡así que solo necesita sumarlas y probarlas en el orden correcto! Aquí está el script completo: `OP_3DUP OP_ADD 5 OP_EQUALVERIFY OP_ADD 4 OP_EQUALVERIFY OP_ADD 3 OP_EQUAL`.
|
||||
|
||||
Así es como se ejecuta con el script de desbloqueo correcto de `1 2 3`:
|
||||
|
||||
```
|
||||
Script: 1 2 3 OP_3DUP OP_ADD 5 OP_EQUALVERIFY OP_ADD 4 OP_EQUALVERIFY OP_ADD 3 OP_EQUAL
|
||||
Stack: [ ]
|
||||
|
||||
Script: OP_3DUP OP_ADD 5 OP_EQUALVERIFY OP_ADD 4 OP_EQUALVERIFY OP_ADD 3 OP_EQUAL
|
||||
Stack: [ 1 2 3 ]
|
||||
|
||||
Script: OP_ADD 5 OP_EQUALVERIFY OP_ADD 4 OP_EQUALVERIFY OP_ADD 3 OP_EQUAL
|
||||
Running: 1 2 3 OP_3DUP
|
||||
Stack: [ 1 2 3 1 2 3 ]
|
||||
|
||||
Script: 5 OP_EQUALVERIFY OP_ADD 4 OP_EQUALVERIFY OP_ADD 3 OP_EQUAL
|
||||
Running: 2 3 OP_ADD
|
||||
Stack: [ 1 2 3 1 5 ]
|
||||
|
||||
Script: OP_EQUALVERIFY OP_ADD 4 OP_EQUALVERIFY OP_ADD 3 OP_EQUAL
|
||||
Stack: [ 1 2 3 1 5 5 ]
|
||||
|
||||
Script: OP_ADD 4 OP_EQUALVERIFY OP_ADD 3 OP_EQUAL
|
||||
Running: 5 5 OP_EQUALVERIFY
|
||||
Stack: [ 1 2 3 1 ] — Does Not Exit
|
||||
|
||||
Script: 4 OP_EQUALVERIFY OP_ADD 3 OP_EQUAL
|
||||
Running: 3 1 OP_ADD
|
||||
Stack: [ 1 2 4 ]
|
||||
|
||||
Script: OP_EQUALVERIFY OP_ADD 3 OP_EQUAL
|
||||
Stack: [ 1 2 4 4 ]
|
||||
|
||||
Script: OP_ADD 3 OP_EQUAL
|
||||
Running: 4 4 OP_EQUALVERIFY
|
||||
Stack: [ 1 2 ] — Does Not Exit
|
||||
|
||||
Script: 3 OP_EQUAL
|
||||
Running: 1 2 OP_ADD
|
||||
Stack: [ 3 ]
|
||||
|
||||
Script: OP_EQUAL
|
||||
Stack: [ 3 3 ]
|
||||
|
||||
Script:
|
||||
Running: 3 3 OP_EQUAL
|
||||
Stack: [ True ]
|
||||
```
|
||||
|
||||
Aquí está en `btcdeb`:
|
||||
|
||||
```
|
||||
$ btcdeb '[1 2 3 OP_3DUP OP_ADD 5 OP_EQUALVERIFY OP_ADD 4 OP_EQUALVERIFY OP_ADD 3 OP_EQUAL]'
|
||||
btcdeb 0.2.19 -- type `btcdeb -h` for start up options
|
||||
valid script
|
||||
13 op script loaded. type `help` for usage information
|
||||
script | stack
|
||||
---------------+--------
|
||||
1 |
|
||||
2 |
|
||||
3 |
|
||||
OP_3DUP |
|
||||
OP_ADD |
|
||||
5 |
|
||||
OP_EQUALVERIFY |
|
||||
OP_ADD |
|
||||
4 |
|
||||
OP_EQUALVERIFY |
|
||||
OP_ADD |
|
||||
3 |
|
||||
OP_EQUAL |
|
||||
|
||||
#0000 1
|
||||
btcdeb> step
|
||||
<> PUSH stack 01
|
||||
script | stack
|
||||
---------------+--------
|
||||
2 | 01
|
||||
3 |
|
||||
OP_3DUP |
|
||||
OP_ADD |
|
||||
5 |
|
||||
OP_EQUALVERIFY |
|
||||
OP_ADD |
|
||||
4 |
|
||||
OP_EQUALVERIFY |
|
||||
OP_ADD |
|
||||
3 |
|
||||
OP_EQUAL |
|
||||
|
||||
#0001 2
|
||||
btcdeb> step
|
||||
<> PUSH stack 02
|
||||
script | stack
|
||||
---------------+--------
|
||||
3 | 02
|
||||
OP_3DUP | 01
|
||||
OP_ADD |
|
||||
5 |
|
||||
OP_EQUALVERIFY |
|
||||
OP_ADD |
|
||||
4 |
|
||||
OP_EQUALVERIFY |
|
||||
OP_ADD |
|
||||
3 |
|
||||
OP_EQUAL |
|
||||
|
||||
#0002 3
|
||||
btcdeb> step
|
||||
<> PUSH stack 03
|
||||
script | stack
|
||||
---------------+--------
|
||||
OP_3DUP | 03
|
||||
OP_ADD | 02
|
||||
5 | 01
|
||||
OP_EQUALVERIFY |
|
||||
OP_ADD |
|
||||
4 |
|
||||
OP_EQUALVERIFY |
|
||||
OP_ADD |
|
||||
3 |
|
||||
OP_EQUAL |
|
||||
|
||||
#0003 OP_3DUP
|
||||
btcdeb> step
|
||||
<> PUSH stack 01
|
||||
<> PUSH stack 02
|
||||
<> PUSH stack 03
|
||||
script | stack
|
||||
---------------+--------
|
||||
OP_ADD | 03
|
||||
5 | 02
|
||||
OP_EQUALVERIFY | 01
|
||||
OP_ADD | 03
|
||||
4 | 02
|
||||
OP_EQUALVERIFY | 01
|
||||
OP_ADD |
|
||||
3 |
|
||||
OP_EQUAL |
|
||||
|
||||
#0004 OP_ADD
|
||||
btcdeb> step
|
||||
<> POP stack
|
||||
<> POP stack
|
||||
<> PUSH stack 05
|
||||
script | stack
|
||||
---------------+--------
|
||||
5 | 05
|
||||
OP_EQUALVERIFY | 01
|
||||
OP_ADD | 03
|
||||
4 | 02
|
||||
OP_EQUALVERIFY | 01
|
||||
OP_ADD |
|
||||
3 |
|
||||
OP_EQUAL |
|
||||
|
||||
#0005 5
|
||||
btcdeb> step
|
||||
<> PUSH stack 05
|
||||
script | stack
|
||||
---------------+--------
|
||||
OP_EQUALVERIFY | 05
|
||||
OP_ADD | 05
|
||||
4 | 01
|
||||
OP_EQUALVERIFY | 03
|
||||
OP_ADD | 02
|
||||
3 | 01
|
||||
OP_EQUAL |
|
||||
|
||||
#0006 OP_EQUALVERIFY
|
||||
btcdeb> step
|
||||
<> POP stack
|
||||
<> POP stack
|
||||
<> PUSH stack 01
|
||||
<> POP stack
|
||||
script | stack
|
||||
---------------+--------
|
||||
OP_ADD | 01
|
||||
4 | 03
|
||||
OP_EQUALVERIFY | 02
|
||||
OP_ADD | 01
|
||||
3 |
|
||||
OP_EQUAL |
|
||||
|
||||
#0007 OP_ADD
|
||||
btcdeb> step
|
||||
<> POP stack
|
||||
<> POP stack
|
||||
<> PUSH stack 04
|
||||
script | stack
|
||||
---------------+--------
|
||||
4 | 04
|
||||
OP_EQUALVERIFY | 02
|
||||
OP_ADD | 01
|
||||
3 |
|
||||
OP_EQUAL |
|
||||
|
||||
#0008 4
|
||||
btcdeb> step
|
||||
<> PUSH stack 04
|
||||
script | stack
|
||||
---------------+--------
|
||||
OP_EQUALVERIFY | 04
|
||||
OP_ADD | 04
|
||||
3 | 02
|
||||
OP_EQUAL | 01
|
||||
|
||||
#0009 OP_EQUALVERIFY
|
||||
btcdeb> step
|
||||
<> POP stack
|
||||
<> POP stack
|
||||
<> PUSH stack 01
|
||||
<> POP stack
|
||||
script | stack
|
||||
---------------+--------
|
||||
OP_ADD | 02
|
||||
3 | 01
|
||||
OP_EQUAL |
|
||||
|
||||
#0010 OP_ADD
|
||||
btcdeb> step
|
||||
<> POP stack
|
||||
<> POP stack
|
||||
<> PUSH stack 03
|
||||
script | stack
|
||||
---------------+--------
|
||||
3 | 03
|
||||
OP_EQUAL |
|
||||
|
||||
#0011 3
|
||||
btcdeb> step
|
||||
<> PUSH stack 03
|
||||
script | stack
|
||||
---------------+--------
|
||||
OP_EQUAL | 03
|
||||
| 03
|
||||
|
||||
#0012 OP_EQUAL
|
||||
btcdeb> step
|
||||
<> POP stack
|
||||
<> POP stack
|
||||
<> PUSH stack 01
|
||||
script | stack
|
||||
---------------+--------
|
||||
| 01
|
||||
```
|
||||
> :warning: **ADVERTENCIA** `btcdeb` no solo es útil para proporcionar visualización de estos scripts, sino también para verificar los resultados. Efectivamente, nos equivocamos la primera vez, probando las ecuaciones en el orden incorrecto. Así de fácil es cometer un error financieramente fatal en un script de Bitcoin, y es por eso que cada script debe ser probado.
|
||||
|
||||
## Escriba scripts computacionales simples
|
||||
|
||||
Aunque los scripts de acertijos son triviales, en realidad pueden tener una utilidad en el mundo real si desea realizar un cálculo colectivo. Simplemente crea un script que requiere la respuesta al cálculo y envía fondos a la dirección P2SH como recompensa. Se quedará ahí hasta que alguien dé la respuesta.
|
||||
|
||||
Por ejemplo, Peter Todd [ofreció recompensas](https://bitcointalk.org/index.php?topic=293382.0) por resolver ecuaciones que demuestran colisiones para algoritmos criptográficos estándar. Aquí estaba su script para confirmar una colisión SHA1: `OP_2DUP OP_EQUAL OP_NOT OP_VERIFY OP_SHA1 OP_SWAP OP_SHA1 OP_EQUAL`. Requiere dos entradas, que serán los dos números que colisionen.
|
||||
|
||||
Así es como funciona con respuestas correctas.
|
||||
|
||||
Primero, completamos nuestra pila:
|
||||
|
||||
```
|
||||
Script: <numA> <numB> OP_2DUP OP_EQUAL OP_NOT OP_VERIFY OP_SHA1 OP_SWAP OP_SHA1 OP_EQUAL
|
||||
Stack: [ ]
|
||||
|
||||
Script: OP_2DUP OP_EQUAL OP_NOT OP_VERIFY OP_SHA1 OP_SWAP OP_SHA1 OP_EQUAL
|
||||
Stack: [ <numA> <numB> ]
|
||||
|
||||
Script: OP_EQUAL OP_NOT OP_VERIFY OP_SHA1 OP_SWAP OP_SHA1 OP_EQUAL
|
||||
Running: <numA> <numB> OP_2DUP
|
||||
Stack: [ <numA> <numB> <numA> <numB> ]
|
||||
```
|
||||
|
||||
Luego, nos aseguramos de que los dos números no sean iguales, saliendo si lo son:
|
||||
|
||||
```
|
||||
Script: OP_NOT OP_VERIFY OP_SHA1 OP_SWAP OP_SHA1 OP_EQUAL
|
||||
Running: <numA> <numB> OP_EQUAL
|
||||
Stack: [ <numA> <numB> False ]
|
||||
|
||||
Script: OP_VERIFY OP_SHA1 OP_SWAP OP_SHA1 OP_EQUAL
|
||||
Running: False OP_NOT
|
||||
Stack: [ <numA> <numB> True ]
|
||||
|
||||
Script: OP_SHA1 OP_SWAP OP_SHA1 OP_EQUAL
|
||||
Running: True OP_VERIFY
|
||||
Stack: [ <numA> <numB> ] — Does Not Exit
|
||||
```
|
||||
|
||||
Ahora creamos dos SHA:
|
||||
|
||||
```
|
||||
Script: OP_SWAP OP_SHA1 OP_EQUAL
|
||||
Running: <numB> OP_SHA1
|
||||
Stack: [ <numA> <hashB> ]
|
||||
|
||||
Script: OP_SHA1 OP_EQUAL
|
||||
Running: <numA> <hashB> OP_SWAP
|
||||
Stack: [ <hashB> <numA> ]
|
||||
|
||||
Script: OP_EQUAL
|
||||
Running: <numA> OP_SHA1
|
||||
Stack: [ <hashB> <hashA> ]
|
||||
```
|
||||
|
||||
Finalmente, veremos si coinciden.
|
||||
|
||||
```
|
||||
Script:
|
||||
Running: <hashB> <hashA> OP_EQUAL
|
||||
Stack: [ True ]
|
||||
```
|
||||
|
||||
Este es un buen script porque muestra un uso cuidadoso de la lógica (con `OP_NOT` y` OP_VERIFY`) y un buen uso de las funciones de pila (con `OP_SWAP`). Es un gran ejemplo de una función del mundo real. Y es del mundo muy real. Cuando [SHA-1 se rompió](https://shattered.io/), 2.48 BTC se liberaron rápidamente de la dirección, con un valor total de aproximadamente $ 3,000 en ese momento.
|
||||
|
||||
`btcdeb` se puede ejecutar para probar la colisión (y el script):
|
||||
|
||||
```
|
||||
$ btcdeb '[255044462d312e330a25e2e3cfd30a0a0a312030206f626a0a3c3c2f57696474682032203020522f4865696768742033203020522f547970652034203020522f537562747970652035203020522f46696c7465722036203020522f436f6c6f7253706163652037203020522f4c656e6774682038203020522f42697473506572436f6d706f6e656e7420383e3e0a73747265616d0affd8fffe00245348412d3120697320646561642121212121852fec092339759c39b1a1c63c4c97e1fffe017f46dc93a6b67e013b029aaa1db2560b45ca67d688c7f84b8c4c791fe02b3df614f86db1690901c56b45c1530afedfb76038e972722fe7ad728f0e4904e046c230570fe9d41398abe12ef5bc942be33542a4802d98b5d70f2a332ec37fac3514e74ddc0f2cc1a874cd0c78305a21566461309789606bd0bf3f98cda8044629a1 255044462d312e330a25e2e3cfd30a0a0a312030206f626a0a3c3c2f57696474682032203020522f4865696768742033203020522f547970652034203020522f537562747970652035203020522f46696c7465722036203020522f436f6c6f7253706163652037203020522f4c656e6774682038203020522f42697473506572436f6d706f6e656e7420383e3e0a73747265616d0affd8fffe00245348412d3120697320646561642121212121852fec092339759c39b1a1c63c4c97e1fffe017346dc9166b67e118f029ab621b2560ff9ca67cca8c7f85ba84c79030c2b3de218f86db3a90901d5df45c14f26fedfb3dc38e96ac22fe7bd728f0e45bce046d23c570feb141398bb552ef5a0a82be331fea48037b8b5d71f0e332edf93ac3500eb4ddc0decc1a864790c782c76215660dd309791d06bd0af3f98cda4bc4629b1 OP_2DUP OP_EQUAL OP_NOT OP_VERIFY OP_SHA1 OP_SWAP OP_SHA1 OP_EQUAL]'
|
||||
```
|
||||
|
||||
Las otras [recompensas](https://bitcointalk.org/index.php?topic=293382.0) de Peter Todd permanecen sin reclamar en el momento de escribir este artículo. Todos están escritos de la misma manera que en el ejemplo SHA-1 anterior.
|
||||
|
||||
## Comprenda las limitaciones de los scripts de rompecabezas
|
||||
|
||||
Los scripts de rompecabezas son excelentes para examinar más a fondo los scripts de Bitcoin, pero solo los verá en el mundo real si tienen pequeñas cantidades de fondos o si están destinados a ser canjeados por usuarios muy hábiles. Hay una razón para esto: no son seguras.
|
||||
|
||||
Aquí es donde cae la seguridad:
|
||||
|
||||
Primero, cualquiera puede redimirlos sin saber mucho de un secreto. Tienen que tener el `redeemScript`, que ofrece cierta protección, pero una vez que lo hacen, ese es probablemente el único secreto que es necesario, a menos que su rompecabezas sea _realmente_ difícil, como un rompecabezas computacional.
|
||||
|
||||
En segundo lugar, la redención real no es segura. Normalmente, una transacción de Bitcoin está protegida por la firma. Debido a que la firma cubre la transacción, nadie en la red puede reescribir esa transacción para enviarla a su dirección sin invalidar la firma (y por lo tanto la transacción). Eso no es cierto con transacciones cuyas entradas son solo números. Cualquiera podría tomar la transacción y reescribirla para permitirles robar los fondos. Si pueden introducir su transacción en un bloque antes que la suya, ganan y usted no obtiene el dinero del rompecabezas. Hay soluciones para esto, pero implican minar el bloque usted mismo o hacer que un grupo de confianza lo mine, y ninguna de esas opciones es racional para un usuario promedio de Bitcoin.
|
||||
|
||||
Sin embargo, las recompensas criptográficas de Peter Todd demuestran que los scripts de rompecabezas tienen alguna aplicación en el mundo real.
|
||||
|
||||
## Resumen: Escribiendo script rompecabezas
|
||||
|
||||
Los scripts de rompecabezas son una gran introducción a los scripts de Bitcoin más realistas y complejos. Demuestran el poder de las funciones matemáticas y de pila en Bitcoin Script y cómo se pueden combinar cuidadosamente para crear preguntas que requieren respuestas muy específicas. Sin embargo, su uso en el mundo real también está limitado por los problemas de seguridad inherentes a las transacciones de Bitcoin no firmadas.
|
||||
|
||||
> :fire: ***¿Cuál es el poder de los scripts rompecabezas?*** A pesar de sus limitaciones, los guiones de rompecabezas se han utilizado en el mundo real como premios por recompensas computacionales. Cualquiera que pueda resolver un rompecabezas complejo, cuya solución presumiblemente tenga algún impacto en el mundo real, puede ganar la recompensa. Si pueden conservarlo es otra cuestión.
|
||||
|
||||
## ¿Que sigue?
|
||||
|
||||
Continúe "Diseñando scripts de Bitcoin reales" con [§13.2: Escribiendo scripts multifirma complejos](13_2_Escribiendo_Scripts_Multifirma_Complejos.md)
|
174
es/13_2_Escribiendo_Scripts_Multifirma_Complejos.md
Normal file
174
es/13_2_Escribiendo_Scripts_Multifirma_Complejos.md
Normal file
@ -0,0 +1,174 @@
|
||||
# 13.2: Escritura de scripts complejos multifirma
|
||||
|
||||
Hasta la fecha, las multifirma descritas en estos documentos han sido completamente simples, de la forma m-de-n o n-de-n. Sin embargo, es posible que desee transacciones multifirmas más complejas, en las que los cofirmantes varían o en las que pueden estar disponibles diferentes opciones con el tiempo.
|
||||
|
||||
## Escriba una multifirma de umbral
|
||||
|
||||
Una multifirma de umbral requiere que firmen diferentes números de personas dependiendo de quién esté firmando.
|
||||
|
||||
### Escribir una multifirma con un solo firmante o cofirmantes
|
||||
|
||||
Imagine una corporación donde el presidente o dos de cada tres vicepresidentes pudieran estar de acuerdo con el uso de los fondos.
|
||||
|
||||
Puede escribir esto creando una declaración `IF` /` ELSE` / `ENDIF` que tenga dos bloques, uno para el presidente y su firma uno de uno y otro para los vicepresidentes y sus dos de tres firmas. Luego puede determinar qué bloque usar en función de cuántas firmas hay en el script de desbloqueo. El uso de `OP_DEPTH 1 OP_EQUAL` le dirá si hay un elemento en la pila, y luego continuará desde allí.
|
||||
|
||||
El script de bloqueo completo sería `OP_DEPTH 1 OP_EQUAL IF <pubKeyPres> OP_CHECKSIGNATURE ELSE 2 <pubKeyVPA> <pubKeyVPB> <pubKeyVPC> 3 OP_CHECKMULTISIG ENDIF`
|
||||
|
||||
Si lo ejecuta el presidente, se vería así:
|
||||
|
||||
```
|
||||
Script: <sigPres> OP_DEPTH 1 OP_EQUAL IF <pubKeyPres> OP_CHECKSIGNATURE ELSE 2 <pubKeyVPA> <pubKeyVPB> <pubKeyVPC> 3 OP_CHECKMULTISIG ENDIF
|
||||
Stack: [ ]
|
||||
|
||||
Script: OP_DEPTH 1 OP_EQUAL IF <pubKeyPres> OP_CHECKSIGNATURE ELSE 2 <pubKeyVPA> <pubKeyVPB> <pubKeyVPC> 3 OP_CHECKMULTISIG ENDIF
|
||||
Stack: [ <sigPres> ]
|
||||
|
||||
Script: 1 OP_EQUAL IF <pubKeyPres> OP_CHECKSIGNATURE ELSE 2 <pubKeyVPA> <pubKeyVPB> <pubKeyVPC> 3 OP_CHECKMULTISIG ENDIF
|
||||
Running: <SigPres> OP_DEPTH
|
||||
Stack: [ <sigPres> 1 ]
|
||||
|
||||
Script: OP_EQUAL IF <pubKeyPres> OP_CHECKSIGNATURE ELSE 2 <pubKeyVPA> <pubKeyVPB> <pubKeyVPC> 3 OP_CHECKMULTISIG ENDIF
|
||||
Stack: [ <sigPres> 1 1 ]
|
||||
|
||||
Script: IF <pubKeyPres> OP_CHECKSIGNATURE ELSE 2 <pubKeyVPA> <pubKeyVPB> <pubKeyVPC> 3 OP_CHECKMULTISIG ENDIF
|
||||
Running: 1 1 OP_EQUAL
|
||||
Stack: [ <sigPres> True ]
|
||||
```
|
||||
|
||||
Debido a que el resultado es "Verdadero", la secuencia de comandos ahora se contrae en la declaración `IF`:
|
||||
|
||||
```
|
||||
Script: <pubKeyPres> OP_CHECKSIGNATURE
|
||||
Running: True IF
|
||||
Stack: [ <sigPres> ]
|
||||
|
||||
Script: OP_CHECKSIGNATURE
|
||||
Stack: [ <sigPres> <pubKeyPres> ]
|
||||
|
||||
Script:
|
||||
Running: <sigPres> <pubKeyPres> OP_CHECKSIGNATURE
|
||||
Stack: [ True ]
|
||||
```
|
||||
|
||||
Si lo ejecutan dos vicepresidentes, se vería así:
|
||||
|
||||
```
|
||||
Script: 0 <sigVPA> <sigVPB> OP_DEPTH 1 OP_EQUAL IF <pubKeyPres> OP_CHECKSIGNATURE ELSE 2 <pubKeyVPA> <pubKeyVPB> <pubKeyVPC> 3 OP_CHECKMULTISIG ENDIF
|
||||
Stack: [ ]
|
||||
|
||||
Script: OP_DEPTH 1 OP_EQUAL IF <pubKeyPres> OP_CHECKSIGNATURE ELSE 2 <pubKeyVPA> <pubKeyVPB> <pubKeyVPC> 3 OP_CHECKMULTISIG ENDIF
|
||||
Stack: [ 0 <sigVPA> <sigVPB> ]
|
||||
|
||||
Script: 1 OP_EQUAL IF <pubKeyPres> OP_CHECKSIGNATURE ELSE 2 <pubKeyVPA> <pubKeyVPB> <pubKeyVPC> 3 OP_CHECKMULTISIG ENDIF
|
||||
Running: 0 <sigVPA> <sigVPB> OP_DEPTH
|
||||
Stack: [ 0 <sigVPA> <sigVPB> 3 ]
|
||||
|
||||
Script: OP_EQUAL IF <pubKeyPres> OP_CHECKSIGNATURE ELSE 2 <pubKeyVPA> <pubKeyVPB> <pubKeyVPC> 3 OP_CHECKMULTISIG ENDIF
|
||||
Stack: [ 0 <sigVPA> <sigVPB> 3 1 ]
|
||||
|
||||
Script: IF <pubKeyPres> OP_CHECKSIGNATURE ELSE 2 <pubKeyVPA> <pubKeyVPB> <pubKeyVPC> 3 OP_CHECKMULTISIG ENDIF
|
||||
Running: 3 1 OP_EQUAL
|
||||
Stack: [ 0 <sigVPA> <sigVPB> False ]
|
||||
```
|
||||
|
||||
Debido a que el resultado es `False`, la secuencia de comandos ahora se contrae en la declaración "ELSE":
|
||||
|
||||
```
|
||||
Script: 2 <pubKeyVPA> <pubKeyVPB> <pubKeyVPC> 3 OP_CHECKMULTISIG
|
||||
Running: False IF
|
||||
Stack: [ 0 <sigVPA> <sigVPB> ]
|
||||
|
||||
Script: OP_CHECKMULTISIG
|
||||
Stack: [ 0 <sigVPA> <sigVPB> 2 <pubKeyVPA> <pubKeyVPB> <pubKeyVPC> 3 ]
|
||||
|
||||
Script:
|
||||
Running: 0 <sigVPA> <sigVPB> 2 <pubKeyVPA> <pubKeyVPB> <pubKeyVPC> 3 OP_CHECKMULTISIG
|
||||
Stack: [ ]
|
||||
```
|
||||
|
||||
Puede notar que la firma del presidente solo usa un simple `OP_CHECKSIGNATURE` en lugar del código más complejo que generalmente se requiere para un P2PKH.
|
||||
Podrían salirse con la suya al incluir la clave pública en el script de bloqueo, obviando las galimatías habituales, porque está codificado y no se revelará (a través del `redeemScript`) hasta que se desbloquee la transacción.
|
||||
Esto también permite que todos los posibles firmantes firmen utilizando la misma metodología.
|
||||
|
||||
El único problema posible es si el presidente está distraído y accidentalmente firma una transacción con uno de sus vicepresidentes, porque este recuerda que se trata de una multifirma 2 de 3. Una opción es decidir que es una condición de falla aceptable, porque el presidente está usando la multifirma incorrectamente. Otra opción es convertir la multifirma 2 de 3 en una 2 de 4, en caso de que el presidente no tolere la falla: `OP_DEPTH 1 OP_EQUAL IF <pubKeyPres> OP_CHECKSIGNATURE ELSE 2 <pubKeyVPA> <pubKeyVPB> < pubKeyVPC> <pubKeyPres> 4 OP_CHECKMULTISIG ENDIF`. Esto le permitiría al presidente firmar por error con cualquier vicepresidente, pero no afectaría las cosas si dos vicepresidentes quisieran firmar (correctamente).
|
||||
|
||||
### Escriba una multifirma con un firmante obligatorio
|
||||
|
||||
Otra posibilidad de las multifirmas implica tener una multifirma m-de-n donde se requiere uno de los firmantes. Por lo general, esto se puede gestionar dividiendo la multifirma en varios m de n-1. Por ejemplo, una firma múltiple de 2 de 3 en la que se requiere uno de los firmantes sería en realidad dos firmas múltiples de 2 de 2, cada una con el firmante requerido.
|
||||
|
||||
Aquí hay una forma sencilla de escribir eso:
|
||||
|
||||
```
|
||||
OP_3DUP
|
||||
2 <pubKeyRequired> <pubKeyA> 2 OP_CHECKMULTISIG
|
||||
NOTIF
|
||||
|
||||
2 <pubKeyRequired> <pubKeyB> 2 OP_CHECKMULTISIG
|
||||
|
||||
ENDIF
|
||||
```
|
||||
El script de desbloqueo sería `0 <pubKeyRequired> <pubKeyA>` o `0 <pubKeyRequired> <pubKeyB>`.
|
||||
|
||||
Primero, el script verificaría las firmas con `<pubKeyRequired> <pubKeyA>`. Si eso falla, verificaría con `<pubKeyRequired> <pubKeyB>`.
|
||||
|
||||
El resultado del `OP_CHECKMULTISIG` final que se ejecutó se dejará en la parte superior de la pila (aunque habrá cruft debajo si el primero tuvo éxito).
|
||||
|
||||
## Escriba un fideicomiso multifirma
|
||||
|
||||
Hemos hablado mucho sobre fideicomisos. Multifirmas complejas combinadas con bloqueos de tiempo ofrecen una forma automatizada de crearlas de manera robusta.
|
||||
|
||||
Imagínese la compradora de vivienda Alice y el vendedor de vivienda Bob que están trabajando con un agente de depósito en garantía. La manera fácil de programar esto sería como una firma múltiple en la que dos de las tres partes podrían liberar el dinero: el vendedor y el comprador están de acuerdo o el agente de depósito en garantía se hace cargo y está de acuerdo con una de las partes: `2 <pubKeyA> <pubKeyB> <pubKeyEscrow> 3 OP_CHECKMULTISG`.
|
||||
|
||||
Sin embargo, esto debilita el poder del agente de custodia y permite que el vendedor y el comprador tomen accidentalmente una mala decisión entre ellos, que es una de las cosas que un sistema de custodia está diseñado para evitar. Entonces, podría ser que lo que realmente queremos es el sistema que acabamos de diseñar, donde el agente de custodia es una parte requerida en multifirma 2 de 3: `OP_3DUP 2 <pubKeyEscrow> <pubKeyA> 2 OP_CHECKMULTISIG NOTIF 2 <pubKeyEscrow > <pubKeyB> 2 OP_CHECKMULTISIG ENDIF`.
|
||||
|
||||
Sin embargo, esto no pasa la prueba de caminar frente a un autobús. Si el agente de depósito en garantía muere o huye a las Bahamas durante el depósito en garantía, el comprador y el vendedor pierden mucho dinero. Aquí es donde entra en juego un bloqueo de tiempo. Puede crear una prueba adicional que solo se ejecutará si hemos pasado el final de nuestro período de depósito en garantía. En esta situación, permite que el comprador y el vendedor firmen juntos:
|
||||
|
||||
```
|
||||
OP_3DUP
|
||||
2 <pubKeyEscrow> <pubKeyA> 2 OP_CHECKMULTISIG
|
||||
NOTIF
|
||||
|
||||
OP_3DUP
|
||||
2 <pubKeyEscrow> <pubKeyB> 2 OP_CHECKMULTISIG
|
||||
NOTIF
|
||||
|
||||
<+30Days> OP_CHECKSEQUENCEVERIFY OP_DROP
|
||||
2 <pubKeyA> <pubKeyB> 2 OP_CHECKMULTISIG
|
||||
|
||||
ENDIF
|
||||
ENDIF
|
||||
```
|
||||
|
||||
Primero, prueba una firma para el comprador y el agente de custodia, luego una firma para el vendedor y el agente de custodia. Si ambos fallan y han pasado 30 días, también permite una firma para el comprador y el vendedor.
|
||||
|
||||
### Escriba una fideicomiso multifirma centrado en el comprador
|
||||
|
||||
[BIP 112](https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki#Escrow_with_Timeout) ofrece un ejemplo diferente de este tipo de depósito en garantía que no tiene las protecciones adicionales para evitar que se pierda el agente de depósito en garantía, pero que le da a Alice el control total si falla el depósito en garantía.
|
||||
|
||||
```
|
||||
IF
|
||||
|
||||
2 <pubKeyA> <pubKeyB> <pubKeyEscrow> 3 OP_CHECKMULTISIG
|
||||
|
||||
ELSE
|
||||
|
||||
<+30Days> OP_CHECKSEQUENCEVERIFY OP_DROP
|
||||
<pubKeyA> OP_CHECKSIGNATURE
|
||||
|
||||
ENDIF
|
||||
```
|
||||
Aquí, dos de los tres firmantes pueden liberar el dinero en cualquier momento, pero después de 30 días, Alice puede recuperar su dinero por su cuenta.
|
||||
|
||||
Tenga en cuenta que esta secuencia de comandos requiere que se pase un "Verdadero" o un "Falso" para identificar qué rama se está utilizando. Esta es una forma más simple y menos intensiva desde el punto de vista informático para admitir ramas en un script de Bitcoin; es bastante común.
|
||||
|
||||
Al principio, se permitiría el siguiente `sigScript`:` 0 <signer1> <signer2> True`. Después de 30 días, Alice podría producir un `sigScript` como este:` <sigA> False`.
|
||||
|
||||
## Resumen: Escribiendo scripts multifirma complejos
|
||||
|
||||
Por lo general, se pueden crear multifirmas más complejas combinando firmas o multifirmas con condicionales y pruebas. Las multifirmas resultantes pueden ser variables, requiriendo diferentes números de firmantes en función de quiénes son y cuándo están firmando.
|
||||
|
||||
> :fire: ***¿Cuál es el poder de los scripts multisig complejos?*** Más allá de todo lo que hemos visto hasta la fecha, los scripts multifirma complejos son contratos verdaderamente inteligentes. Pueden ser muy precisos sobre quién puede firmar y cuándo. Se pueden admitir corporaciones multinivel, asociaciones y depósitos en garantía. El uso de otras funciones poderosas como los bloqueos de tiempo puede proteger aún más estos fondos, lo que permite que se liberen o incluso se devuelvan en determinados momentos.
|
||||
|
||||
## ¿Que sigue?
|
||||
|
||||
Continúe "Diseñando scripts de Bitcoin reales" con [§13.3: Potenciando Bitcoin con scripts](13_3_Potenciando_Bitcoin_con_Scripts.md).
|
317
es/13_3_Potenciando_Bitcoin_con_Scripts.md
Normal file
317
es/13_3_Potenciando_Bitcoin_con_Scripts.md
Normal file
@ -0,0 +1,317 @@
|
||||
# 13.3: Potenciando Bitcoin con scripts
|
||||
|
||||
Los scripts de Bitcoin pueden ir mucho más allá de los instrumentos financieros relativamente simples detallados hasta la fecha. También son la base de usos más complejos de la red Bitcoin, como lo demuestran estos ejemplos del mundo real de funcionalidad fuera de la cadena, extraídos de los ejemplos de Lightning Network en [BIP 112](https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki).
|
||||
|
||||
## Bloqueo para Lightning Network
|
||||
|
||||
[Lightning Network](https://rusty.ozlabs.org/?p=450) es un canal de pago que permite a los usuarios retirar fondos de la cadena y participar en numerosas microtransacciones antes de finalizar el canal de pago y devolver los fondos a Bitcoin. Los beneficios incluyen tarifas más bajas y velocidades de transacción más rápidas. Se discute con más detalle, con ejemplos de cómo usarlo desde la línea de comando, comenzando el [Capítulo 19](19_0_Entendiendo_Su_Configuracion_Lightning.md).
|
||||
|
||||
[BIP 112](https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki) contiene algunos ejemplos de cómo se podrían generar estas transacciones fuera de la cadena, utilizando scripts de bloqueo de Bitcoin.
|
||||
|
||||
### Bloqueo con transacciones de compromiso revocable
|
||||
|
||||
El truco con Lightning es el hecho de que está fuera de la cadena. Para usar Lightning, los participantes bloquean los fondos de forma conjunta en la cadena de bloques de Bitcoin con una multifirma n-de-n. Luego, se involucran en una serie de transacciones entre ellos. Cada nueva "transacción de compromiso" divide esos fondos conjuntos de una manera diferente; estas transacciones están parcialmente firmadas pero _no se colocan en la cadena de bloques_.
|
||||
|
||||
Si tiene una gran cantidad de transacciones no publicadas, cualquiera de las cuales _podría_ publicarse a la cadena de bloques, ¿cómo puede evitar que uno de los participantes vuelva a una transacción anterior que sea más beneficiosa para ellos? La respuesta es la _revocación_. Un ejemplo simplificado en BIP 112, que ofrece uno de los escalones base hacia Lightning, muestra cómo: le da al participante que se vería perjudicado por la reversión a una transacción revocada la capacidad de reclamar los fondos él mismo si el otro participante intenta usar ilegítimamente la transacción revocada.
|
||||
|
||||
Por ejemplo, suponga que Alice y Bob actualizan la transacción de compromiso para darle más fondos a Bob (efectivamente: Alice envió fondos a Bob a través de la red Lightning). Firman parcialmente nuevas transacciones, pero también ofrecen su propio `revokeCode` para transacciones anteriores. Esto garantiza efectivamente que no publicarán transacciones anteriores, porque hacerlo permitiría a su contraparte reclamar esos fondos anteriores.
|
||||
|
||||
Entonces, ¿cómo se ve la transacción anterior? Era una transacción de compromiso que mostraba fondos destinados a Alice, antes de que se los diera a Bob. Tenía un script de bloqueo de la siguiente manera:
|
||||
|
||||
```
|
||||
OP_HASH160
|
||||
<revokeHash>
|
||||
OP_EQUAL
|
||||
|
||||
IF
|
||||
|
||||
<pubKeyBob>
|
||||
|
||||
ELSE
|
||||
|
||||
<+24Hours>
|
||||
OP_CHECKSEQUENCEVERIFY
|
||||
OP_DROP
|
||||
<pubKeyAlice>
|
||||
|
||||
ENDIF
|
||||
OP_CHECKSIG
|
||||
```
|
||||
|
||||
El bloque `ELSE` es donde Alice obtuvo sus fondos, después de un retraso de 24 horas. Sin embargo, ahora ha sido reemplazado; ese es el objetivo de un canal de pago al estilo Lightning, después de todo. En esta situación, esta transacción nunca debe publicarse. Bob no tiene ningún incentivo para hacerlo porque tiene una transacción más nueva, lo que lo beneficia más porque le han enviado algunos de los fondos de Alice. Alice tampoco tiene ningún incentivo, porque pierde los fondos si lo intenta debido a ese `revokeCode`. Por lo tanto, nadie coloca la transacción en la cadena de bloques y las transacciones fuera de la cadena continúan.
|
||||
|
||||
Vale la pena explorar cómo funcionaría este script en una variedad de situaciones, la mayoría de las cuales involucran a Alice tratando de hacer trampa volviendo a esta transacción anterior, que describe los fondos _antes_ que Alice enviara algunos de ellos a Bob.
|
||||
|
||||
#### Ejecute el script de bloqueo para una Alice tramposa, con código de revocación
|
||||
|
||||
Alice podría intentar usar el código de revocación que le dio a Bob para reclamar los fondos de inmediato. Ella escribe un script de bloqueo de `<sigAlice> <revokeCode>`:
|
||||
|
||||
```
|
||||
Script: <sigAlice> <revokeCode> OP_HASH160 <revokeHash> OP_EQUAL IF <pubKeyBob> ELSE <+24Hours> OP_CHECKSEQUENCEVERIFY OP_DROP <pubKeyAlice> ENDIF OP_CHECKSIG
|
||||
Stack: [ ]
|
||||
|
||||
Script: OP_HASH160 <revokeHash> OP_EQUAL IF <pubKeyBob> ELSE <+24Hours> OP_CHECKSEQUENCEVERIFY OP_DROP <pubKeyAlice> ENDIF OP_CHECKSIG
|
||||
Stack: [ <sigAlice> <revokeCode> ]
|
||||
|
||||
Script: <revokeHash> OP_EQUAL IF <pubKeyBob> ELSE <+24Hours> OP_CHECKSEQUENCEVERIFY OP_DROP <pubKeyAlice> ENDIF OP_CHECKSIG
|
||||
Running: <revokeCode> OP_HASH160
|
||||
Stack: [ <sigAlice> <revokeHash> ]
|
||||
|
||||
Script: OP_EQUAL IF <pubKeyBob> ELSE <+24Hours> OP_CHECKSEQUENCEVERIFY OP_DROP <pubKeyAlice> ENDIF OP_CHECKSIG
|
||||
Stack: [ <sigAlice> <revokeHash> <revokeHash> ]
|
||||
|
||||
Script: IF <pubKeyBob> ELSE <+24Hours> OP_CHECKSEQUENCEVERIFY OP_DROP <pubKeyAlice> ENDIF OP_CHECKSIG
|
||||
Running: <revokeHash> <revokeHash> OP_EQUAL
|
||||
Stack: [ <sigAlice> True ]
|
||||
```
|
||||
|
||||
El `OP_EQUAL` alimenta la declaración` IF`. Debido a que Alice usa el `revokeCode`, ingresa a la sucursal que le permite canjear los fondos inmediatamente, colapsando el resto del script a` <pubKeyBob> `(dentro del condicional) y`OP_CHECKSIG` (después).
|
||||
|
||||
```
|
||||
Script: <pubKeyBob> OP_CHECKSIG
|
||||
Running: True IF
|
||||
Stack: [ <sigAlice> ]
|
||||
```
|
||||
¡Maldiciones! ¡Solo Bob puede firmar inmediatamente usando el `redeemCode`!
|
||||
|
||||
```
|
||||
Script: OP_CHECKSIG
|
||||
Stack: [ <sigAlice> <pubKeyBob> ]
|
||||
|
||||
Script:
|
||||
Running: <sigAlice> <pubKeyBob> OP_CHECKSIG
|
||||
Stack: [ False ]
|
||||
```
|
||||
|
||||
#### Ejecute el script de bloqueo para una Alice tramposa, sin código de revocación
|
||||
|
||||
Entonces, ¿qué pasa si Alice intenta usar su propia firma, sin el `revokeCode`? Ella usa un script de desbloqueo de `<sigAlice> <notRevokeCode>`.
|
||||
|
||||
```
|
||||
Script: <sigAlice> 0 OP_HASH160 <revokeHash> OP_EQUAL IF <pubKeyBob> ELSE <+24Hours> OP_CHECKSEQUENCEVERIFY OP_DROP <pubKeyAlice> ENDIF OP_CHECKSIG
|
||||
Stack: [ ]
|
||||
|
||||
Script: OP_HASH160 <revokeHash> OP_EQUAL IF <pubKeyBob> ELSE <+24Hours> OP_CHECKSEQUENCEVERIFY OP_DROP <pubKeyAlice> ENDIF OP_CHECKSIG
|
||||
Stack: [ <sigAlice> 0 ]
|
||||
|
||||
Script: <revokeHash> OP_EQUAL IF <pubKeyBob> ELSE <+24Hours> OP_CHECKSEQUENCEVERIFY OP_DROP <pubKeyAlice> ENDIF OP_CHECKSIG
|
||||
Running: 0 OP_HASH160
|
||||
Stack: [ <sigAlice> <0Hash> ]
|
||||
|
||||
Script: OP_EQUAL IF <pubKeyBob> ELSE <+24Hours> OP_CHECKSEQUENCEVERIFY OP_DROP <pubKeyAlice> ENDIF OP_CHECKSIG
|
||||
Stack: [ <sigAlice> <0Hash> <revokeHash> ]
|
||||
|
||||
Script: IF <pubKeyBob> ELSE <+24Hours> OP_CHECKSEQUENCEVERIFY OP_DROP <pubKeyAlice> ENDIF OP_CHECKSIG
|
||||
Running: <0Hash> <revokeHash> OP_EQUAL
|
||||
Stack: [ <sigAlice> False ]
|
||||
```
|
||||
|
||||
Ahora colapsamos hasta la declaración `ELSE` y lo que viene después del condicional:
|
||||
|
||||
```
|
||||
Script: <+24Hours> OP_CHECKSEQUENCEVERIFY OP_DROP <pubKeyAlice> OP_CHECKSIG
|
||||
Running: False IF
|
||||
Stack: [ <sigAlice> ]
|
||||
|
||||
Script: OP_CHECKSEQUENCEVERIFY OP_DROP <pubKeyAlice> OP_CHECKSIG
|
||||
Stack: [ <sigAlice> <+24Hours> ]
|
||||
```
|
||||
|
||||
¡Y luego Alice está frustrada nuevamente porque no han pasado 24 horas!
|
||||
|
||||
```
|
||||
Script: OP_DROP <pubKeyAlice> OP_CHECKSIG
|
||||
Running: <+24Hours> OP_CHECKSEQUENCEVERIFY
|
||||
Stack: [ <sigAlice> <+24Hours> ] — Script EXITS
|
||||
```
|
||||
|
||||
#### Ejecute el script de bloqueo para un Bob victimizado
|
||||
|
||||
Lo que esto significa es que Bob tiene 24 horas para reclamar sus fondos si Alice alguna vez intenta hacer trampa, usando el `<revokeCode>` y su firma como su script de desbloqueo:
|
||||
|
||||
```
|
||||
Script: <SigBob> <revokeCode> OP_HASH160 <revokeHash> OP_EQUAL IF <pubKeyBob> ELSE <+24Hours> OP_CHECKSEQUENCEVERIFY OP_DROP <pubKeyAlice> ENDIF OP_CHECKSIG
|
||||
Stack: [ ]
|
||||
|
||||
Script: OP_HASH160 <revokeHash> OP_EQUAL IF <pubKeyBob> ELSE <+24Hours> OP_CHECKSEQUENCEVERIFY OP_DROP <pubKeyAlice> ENDIF OP_CHECKSIG
|
||||
Stack: [ <SigBob> <revokeCode> ]
|
||||
|
||||
Script: <revokeHash> OP_EQUAL IF <pubKeyBob> ELSE <+24Hours> OP_CHECKSEQUENCEVERIFY OP_DROP <pubKeyAlice> ENDIF OP_CHECKSIG
|
||||
Running: <revokeCode> OP_HASH160
|
||||
Stack: [ <SigBob> <revokeHash> ]
|
||||
|
||||
Script: OP_EQUAL IF <pubKeyBob> ELSE <+24Hours> OP_CHECKSEQUENCEVERIFY OP_DROP <pubKeyAlice> ENDIF OP_CHECKSIG
|
||||
Stack: [ <SigBob> <revokeHash> <revokeHash> ]
|
||||
|
||||
Script: IF <pubKeyBob> ELSE <+24Hours> OP_CHECKSEQUENCEVERIFY OP_DROP <pubKeyAlice> ENDIF OP_CHECKSIG
|
||||
Running: <revokeHash> <revokeHash> OP_EQUAL
|
||||
Stack: [ <SigBob> True ]
|
||||
|
||||
Script: <pubKeyBob> OP_CHECKSIG
|
||||
Running: True IF
|
||||
Stack: [ <SigBob> ]
|
||||
|
||||
Script: OP_CHECKSIG
|
||||
Stack: [ <SigBob> <pubKeyBob> ]
|
||||
|
||||
Script:
|
||||
Running: <SigBob> <pubKeyBob> OP_CHECKSIG
|
||||
Stack: [ True ]
|
||||
```
|
||||
|
||||
#### Ejecute el script de bloqueo para una Alice virtuosa
|
||||
|
||||
Todas las transacciones de compromiso de Alice están bloqueadas con este mismo script de bloqueo, ya sea que hayan sido revocadas o no. Eso significa que la transacción de compromiso más reciente, que es la válida actualmente, también está bloqueada. Alice nunca ha enviado una nueva transacción a Bob y, por lo tanto, nunca le envió el `revokeCode` anterior.
|
||||
|
||||
En esta situación, podría publicar virtuosamente la transacción, cerrando el canal proto-Lightning. Ella pone la transacción en la cadena y espera 24 horas. Bob no puede hacer nada al respecto porque no tiene el código de recuperación. Luego, después de la espera, Alice reclama sus fondos. (Bob hace lo mismo con su propia transacción de compromiso final).
|
||||
|
||||
### Bloqueo con contratos codificados con bloqueo de tiempo y hashes
|
||||
|
||||
Las Transacciones de Compromiso Revocable fueron solo un trampolín hacia Lightning. La Lightning Network real utiliza un mecanismo más complejo llamado [contrato de bloqueo de tiempo hash](https://en.bitcoin.it/wiki/Hashed_Timelock_Contracts), o HTLC.
|
||||
|
||||
El objetivo principal de los HTLCs es crear una red integral de participantes. Las transacciones ya no son solo entre un par de participantes que han ingresado a la red juntos, sino que ahora pueden ser entre personas previamente no asociadas. Cuando se envían fondos, se crea una serie de transacciones, cada una de ellas bloqueada con un `secretHash`. Cuando se revela el `secretCode` correspondiente, se puede gastar toda la cadena de transacciones. Esto es lo que permite que las transacciones singulares se conviertan realmente en una red.
|
||||
|
||||
También hay un poco más de complejidad en los scripts de bloqueo de Lightning Network. Hay bloqueos separados para el remitente y el destinatario de cada transacción que son más divergentes que las diferentes transacciones de compromiso mencionadas en la sección anterior. Vamos a mostrarlos a ambos para demostrar el poder de estos scripts de bloqueo, pero no vamos a detenernos en cómo interactúan entre sí.
|
||||
|
||||
#### Bloquee la transacción del destinatario
|
||||
|
||||
Una vez más, comenzaremos a ver la transacción de compromiso de Alice, que muestra los fondos que recibió:
|
||||
|
||||
```
|
||||
OP_HASH160
|
||||
OP_DUP
|
||||
<secretHash>
|
||||
OP_EQUAL
|
||||
|
||||
IF
|
||||
|
||||
<+24Hours>
|
||||
OP_CHECKSEQUENCEVERIFY
|
||||
OP_2DROP
|
||||
<pubKeyAlice>
|
||||
|
||||
ELSE
|
||||
|
||||
<revokeHash>
|
||||
OP_EQUAL
|
||||
|
||||
OP_NOTIF
|
||||
|
||||
<Date>
|
||||
OP_CHECKLOCKTIMEVERIFY
|
||||
OP_DROP
|
||||
|
||||
ENDIF
|
||||
|
||||
<pubKeyBob>
|
||||
|
||||
ENDIF
|
||||
|
||||
OP_CHECKSIG
|
||||
```
|
||||
|
||||
La clave de estos nuevos HTLC es el `secretHash`, que dijimos es lo que permite que una transacción abarque la red. Cuando la transacción se ha extendido desde su originador hasta su destinatario previsto, se revela el `secretCode`, que permite a todos los participantes crear un `secretHash` y desbloquear toda la red de pagos.
|
||||
|
||||
Una vez que se ha revelado el `secretCode`, se abre la rama `IF`: Alice puede reclamar los fondos 24 horas después de que la transacción se haya realizado en la red Bitcoin.
|
||||
|
||||
Sin embargo, también existe la oportunidad de que Bob reclame sus fondos, que aparecen en la rama `ELSE`. Puede hacerlo si la transacción ha sido revocada (pero Alice la pone en la cadena de bloques de todos modos), _o si_ ha finalizado un tiempo de espera absoluto.
|
||||
|
||||
#### Bloquee la transacción del remitente
|
||||
|
||||
Aquí está el script de bloqueo de transacción de compromiso alternativo utilizado por el remitente:
|
||||
|
||||
```
|
||||
OP_HASH160
|
||||
OP_DUP
|
||||
<secretHash>
|
||||
OP_EQUAL
|
||||
OP_SWAP
|
||||
<revokeHash>
|
||||
OP_EQUAL
|
||||
OP_ADD
|
||||
|
||||
IF
|
||||
|
||||
<pubKeyAlice>
|
||||
|
||||
ELSE
|
||||
|
||||
<Date>
|
||||
OP_CHECKLOCKTIMEVERIFY
|
||||
<+24Hours>
|
||||
OP_CHECKSEQUENCEVERIFY
|
||||
OP_2DROP
|
||||
<pubKeyBob>
|
||||
|
||||
ENDIF
|
||||
OP_CHECKSIG
|
||||
```
|
||||
|
||||
La parte inicial de su script es bastante inteligente y, por lo tanto, vale la pena ejecutarla:
|
||||
|
||||
```
|
||||
Initial Script: <suppliedCode> OP_HASH160 OP_DUP <secretHash> OP_EQUAL OP_SWAP <revokeHash> OP_EQUAL OP_ADD
|
||||
Stack: [ ]
|
||||
|
||||
Initial Script: OP_HASH160 OP_DUP <secretHash> OP_EQUAL OP_SWAP <revokeHash> OP_EQUAL OP_ADD
|
||||
Stack: [ <suppliedCode> ]
|
||||
|
||||
Initial Script: OP_DUP <secretHash> OP_EQUAL OP_SWAP <revokeHash> OP_EQUAL OP_ADD
|
||||
Running: <suppliedCode> OP_HASH160
|
||||
Stack: [ <suppliedHash> ]
|
||||
|
||||
Initial Script: <secretHash> OP_EQUAL OP_SWAP <revokeHash> OP_EQUAL OP_ADD
|
||||
Running: <suppliedHash> OP_DUP
|
||||
Stack: [ <suppliedHash> <suppliedHash> ]
|
||||
|
||||
Initial Script: OP_EQUAL OP_SWAP <revokeHash> OP_EQUAL OP_ADD
|
||||
Stack: [ <suppliedHash> <suppliedHash> <secretHash> ]
|
||||
|
||||
Initial Script: OP_SWAP <revokeHash> OP_EQUAL OP_ADD
|
||||
Running: <suppliedHash> <secretHash> OP_EQUAL
|
||||
Stack: [ <suppliedHash> <wasItSecretHash?> ]
|
||||
|
||||
Initial Script: <revokeHash> OP_EQUAL OP_ADD
|
||||
Running: <suppliedHash> <wasItSecretHash?> OP_SWAP
|
||||
Stack: [ <wasItSecretHash?> <suppliedHash> ]
|
||||
|
||||
Initial Script: OP_EQUAL OP_ADD
|
||||
Stack: [ <wasItSecretHash?> <suppliedHash> <revokeHash> ]
|
||||
|
||||
Initial Script: OP_ADD
|
||||
Running: <suppliedHash> <revokeHash> OP_EQUAL
|
||||
Stack: [ <wasItSecretHash?> <wasItRevokeHash?> ]
|
||||
|
||||
Initial Script:
|
||||
Running: <wasItSecretHash?> <wasItRevokeHash?> OP_ADD
|
||||
Stack: [ <wasItSecretOrRevokeHash?> ]
|
||||
```
|
||||
|
||||
La ejecución del script revela que las comprobaciones iniciales, por encima de `IF` /` ELSE` / `ENDIF`, determinan si el hash era _o_ el` secretCode` _o_ el `revokeCode`. Si es así, Alice puede tomar los fondos en el primer bloque. De lo contrario, Bob puede tomar los fondos, pero solo después de que Alice haya tenido su oportunidad y después de que hayan transcurrido el tiempo de espera de 24 horas y el tiempo de espera absoluto.
|
||||
|
||||
#### Comprenda los HTLCs
|
||||
|
||||
Los HTLCs son bastante complejos y esta descripción general no intenta explicar todas sus complejidades. La [descripción general](https://rusty.ozlabs.org/?p=462) de Rusty Russell explica más, y hay incluso más detalles en su artículo [Deployable Lightning](https://github.com/ElementsProject/lightning/blob/master/doc/deployable-lightning.pdf). Pero no se preocupe si algunas de las complejidades aún se le escapan, particularmente las interrelaciones de los dos guiones.
|
||||
|
||||
A los efectos de este tutorial, hay dos lecciones importantes para los HTLC:
|
||||
|
||||
* Comprenda que se puede crear una estructura muy compleja como un HTLC con Bitcoin Script.
|
||||
* Analizar cómo ejecutar cada uno de los scripts HTLC.
|
||||
|
||||
Vale la pena dedicar tiempo a ejecutar cada uno de los dos scripts HTLC a través de cada una de sus permutaciones, un elemento de la pila a la vez.
|
||||
|
||||
## Resumen: Potenciando Bitcoin con scripts
|
||||
|
||||
Cerramos nuestro examen de los scripts de Bitcoin con un vistazo a lo realmente poderosos que pueden ser. En 20 códigos de operación o menos, un script de Bitcoin puede formar la base de todo un canal de pago fuera de la cadena. De manera similar, las cadenas laterales vinculadas de dos vías son el producto de menos de veinte códigos de operación, como también se indica brevemente en [BIP 112](https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki).
|
||||
|
||||
Si alguna vez ha visto funciones complejas de Bitcoin o sistemas adyacentes a Bitcoin, probablemente se hayan construido sobre scripts de Bitcoin. Y ahora tiene todas las herramientas para hacer lo mismo por usted mismo.
|
||||
|
||||
## ¿Que sigue?
|
||||
|
||||
Continúe con "Usando Tor" con el [Capítulo catorce: Usando Tor](14_0_Usando_Tor.md).
|
||||
|
||||
O, si lo prefiere, hay dos caminos alternativos:
|
||||
|
||||
Si desea mantenerse enfocado en Bitcoin, pase a "Programación con RPC" con el [Capítulo Dieciséis: Hablando a Bitcoind con C](16_0_Hablando_a_Bitcoind_con_C.md).
|
||||
|
||||
O, si desea concentrarse en la línea de comandos porque no es un programador, puede pasar al [Capítulo diecinueve: Entendiendo su configuración Lightning](19_0_Entendiendo_Su_Configuracion_Lightning.md) para continuar su educación en línea de comandos con Lightning Network.
|
21
es/14_0_Usando_Tor.md
Normal file
21
es/14_0_Usando_Tor.md
Normal file
@ -0,0 +1,21 @@
|
||||
# Capítulo 14: Usando Tor
|
||||
|
||||
Tor es uno de los programas estándar instalados por [Bitcoin Standup](https://github.com/BlockchainCommons/Bitcoin-Standup-Scripts). Ayudará a mantener su servidor seguro, lo cual es de vital importancia cuando se trata de criptomonedas. Este capítulo se aparta momentáneamente de Bitcoin para ayudarlo a comprender esta infraestructura de seguridad central.
|
||||
|
||||
## Objetivos de este capítulo
|
||||
|
||||
Después de trabajar en este capítulo, un desarrollador podrá:
|
||||
|
||||
* Usar una configuración de Tor
|
||||
* Realizar el mantenimiento de Tor
|
||||
|
||||
Los objetivos de apoyo incluyen la capacidad de:
|
||||
|
||||
* Comprender la red Tor
|
||||
* Comprender los distintos puertos de Bitcoin
|
||||
|
||||
## Table of Contents
|
||||
|
||||
* [Sección uno: Verificación de la configuración de Tor](14_1_Verificando_Su_Configuracion_Tor.md)
|
||||
* [Sección dos: Cambiar sus servicios ocultos de Bitcoin](14_2_Cambiando_Sus_Servicios_Bitcoin_Ocultos.md)
|
||||
* [Sección tres: Agregar servicios ocultos SSH](14_3_Agregando_Servicios_SSH_Ocultos.md)
|
367
es/14_1_Verificando_Su_Configuracion_Tor.md
Normal file
367
es/14_1_Verificando_Su_Configuracion_Tor.md
Normal file
@ -0,0 +1,367 @@
|
||||
# 14.1: Verificación de la configuración de Tor
|
||||
|
||||
> :information_source: **NOTA:** Esta sección se ha agregado recientemente al curso y es un borrador inicial que aún puede estar pendiente de revisión. Lectura con advertencias.
|
||||
|
||||
Si realizó una instalación estándar con [Bitcoin Standup](https://github.com/BlockchainCommons/Bitcoin-Standup), entonces debería tener Tor configurado como parte de su nodo Bitcoin: Tor está instalado y ha creado servicios ocultos para los puertos RPC de Bitcoin; mientras que también se ha creado una dirección de cebolla para `bitcoind`. Esta sección habla sobre qué es todo eso y qué hacer con él.
|
||||
|
||||
> :book: ***Qué es Tor?*** Tor es una red de anonimato y superposición de baja latencia basada en enrutamiento de cebolla y diseño de construcción de rutas para permitir la comunicación anónima. Es un software gratuito y de código abierto con el nombre derivado del acrónimo del nombre del proyecto de software original: "The Onion Router".
|
||||
|
||||
> :book: ***Por qué usar Tor para Bitcoin?*** La red Bitcoin es una red de igual a igual que escucha las transacciones y las propaga utilizando una dirección IP pública. Al conectarse a la red sin usar Tor, compartiría su dirección IP, lo que podría exponer su ubicación, su tiempo de actividad y otros detalles a terceros, lo cual es una práctica de privacidad indeseable. Para protegerse en línea, debe usar herramientas como Tor para ocultar los detalles de su conexión. Tor permite mejorar su privacidad en línea ya que sus datos están codificados criptográficamente y pasan por diferentes nodos, cada uno decodificando una sola capa (de ahí la metáfora de la cebolla).
|
||||
|
||||
## Entender Tor
|
||||
|
||||
Entonces, ¿cómo funciona Tor?
|
||||
|
||||
Cuando un usuario quiere conectarse a un servidor de Internet, Tor intenta construir una ruta formada por al menos tres nodos relés de Tor, llamados Guard (entrada), Middle (medios) y Exit (salida). Mientras se construye esta ruta, se negocian claves de cifrado simétricas; cuando un mensaje se mueve a lo largo de la ruta, cada relé elimina su capa de cifrado. De esta manera, el mensaje llega al destino final en su forma original, y cada parte solo conoce el salto anterior y el siguiente y no puede determinar el origen ni el destino.
|
||||
|
||||
Así es como se ve una conexión sin Tor:
|
||||
```
|
||||
20:58:03.804787 IP bitcoin.36300 > lb-140-82-114-25-iad.github.com.443: Flags [P.], seq 1:30, ack 25, win 501, options [nop,nop,TS val 3087919981 ecr 802303366], length 29
|
||||
```
|
||||
Por el contrario, con Tor se transmite mucha menos información sobre las máquinas reales:
|
||||
```
|
||||
21:06:52.744602 IP bitcoin.58776 > 195-xxx-xxx-x.rev.pxxxxxm.eu.9999: Flags [P.], seq 264139:265189, ack 3519373, win 3410, options [nop,nop,TS val 209009853 ecr 3018177498], length 1050
|
||||
21:06:52.776968 IP 195-xxx-xxx-x.rev.pxxxxxm.eu.9999 > bitcoin.58776: Flags [.], ack 265189, win 501, options [nop,nop,TS val 3018177533 ecr 209009853], length 0
|
||||
```
|
||||
En pocas palabras: Tor encripta sus datos de tal manera que oculta su origen, su destino y los servicios que está utilizando, mientras que un protocolo de encriptación estándar como TLS solo protege lo que contienen sus datos.
|
||||
|
||||
### Comprender la arquitectura de la red Tor
|
||||
|
||||
La arquitectura básica de la red Tor se compone de los siguientes componentes:
|
||||
|
||||
* **Client Tor (OP or Onion Proxy).** Un cliente Tor instala software local que actúa como un proxy cebolla. Empaqueta los datos de la aplicación en celdas que son todas del mismo tamaño (512 bytes), que luego envía a la red Tor. Una celda es la unidad básica de transmisión Tor.
|
||||
* **Nodo de cebolla (OR o enrutador de cebolla).** Un nodo de cebolla transmite células provenientes del cliente Tor y de servidores en línea. Hay tres tipos de nodos de cebolla: de entrada (Guardia), nodos intermedios (Medio) y nodos de salida (Salida).
|
||||
* **Servidor de directorio.** Un servidor de directorio almacena información sobre los enrutadores de cebolla y los servidores de cebolla (servicios ocultos), como sus claves públicas.
|
||||
* **Onion Server (servidor oculto).** Un servidor cebolla admite aplicaciones TCP como páginas web o IRC como servicios.
|
||||
|
||||
### Comprender las limitaciones de Tor
|
||||
|
||||
Tor no es una herramienta perfecta. Debido a que la información de la red Tor se descifra en los nodos de salida antes de enviarse a sus destinos finales, teóricamente un observador podría recopilar suficientes metadatos para comprometer el anonimato y potencialmente identificar a los usuarios.
|
||||
|
||||
También hay estudios que sugieren que posibles exploits de la protección anti-DoS de Bitcoin podrían permitir a un atacante obligar a otros usuarios que usan Tor a conectarse exclusivamente a través de sus nodos de salida o sus pares de Bitcoin, aislando al cliente del resto de la red de Bitcoin. y exponerlos a la censura, la correlación y otros ataques.
|
||||
|
||||
Del mismo modo, los usuarios de Tor con Bitcoin podrían ser atacados mediante huellas dactilares configurando una cookie de dirección en sus nodos. Esto también permitiría la correlación y por tanto la desanonimización.
|
||||
|
||||
Mientras tanto, incluso sobre Tor, Bitcoin es solo un servicio pseudoanónimo debido a los muchos peligros de correlación que se derivan del propio libro mayor permanente. Esto significa que el uso de Bitcoin en Tor tiene más probabilidades de ser desanonimizado que otros servicios (y podría llevar a la desanonimización de otras actividades).
|
||||
|
||||
Dicho esto, Tor generalmente se considera más seguro que la alternativa, que es la navegación no anónima.
|
||||
|
||||
## Verifica tu configuración de Tor
|
||||
|
||||
Entonces, ¿cómo verifica que ha habilitado Tor? Si lo instaló con Bitcoin Standup, lo siguiente verificará que Tor se esté ejecutando en su sistema
|
||||
```
|
||||
$ sudo -u debian-tor tor --verify-config
|
||||
```
|
||||
|
||||
Si Tor está instalado correctamente, debería salir así:
|
||||
```
|
||||
Jun 26 21:52:09.230 [notice] Tor 0.4.3.5 running on Linux with Libevent 2.0.21-stable, OpenSSL 1.0.2n, Zlib 1.2.11, Liblzma 5.2.2, and Libzstd N/A.
|
||||
Jun 26 21:52:09.230 [notice] Tor can't help you if you use it wrong! Learn how to be safe at https://www.torproject.org/download/download#warning
|
||||
Jun 26 21:52:09.230 [notice] Read configuration file "/etc/tor/torrc".
|
||||
Configuration was valid
|
||||
```
|
||||
> :warning: **ADVERTENCIA:** Esto solo significa que Tor se está ejecutando, no que se esté usando para todas (o algunas) conexiones.
|
||||
|
||||
### Verifique su configuración de Tor para RPC
|
||||
|
||||
El propósito más importante de Tor, instalado por Bitcoin Standup, es ofrecer servicios ocultos para los puertos RPC que se utilizan para enviar comandos de estilo de línea de comandos `bitcoind`.
|
||||
|
||||
> :book: ***Qué es un servicio oculto de Tor?*** Un servicio oculto (también conocido como "un servicio de cebolla") es un servicio al que se puede acceder a través de Tor. La conexión realizada a ese servicio a través de la red Onion será anónima.
|
||||
|
||||
El archivo de configuración Tor se encuentra en `/etc/tor/torrc`. Si lo revisa, debería ver los siguientes servicios para proteger sus puertos RPC:
|
||||
```
|
||||
HiddenServiceDir /var/lib/tor/standup/
|
||||
HiddenServiceVersion 3
|
||||
HiddenServicePort 1309 127.0.0.1:18332
|
||||
HiddenServicePort 1309 127.0.0.1:18443
|
||||
HiddenServicePort 1309 127.0.0.1:8332
|
||||
```
|
||||
> :link: **TESTNET vs MAINNET:** Mainnet RPC se ejecuta en el puerto 8332, testnet en el puerto 18332.
|
||||
|
||||
> :information_source: **NOTA:** El directorio `HiddenServiceDires` es donde todos los archivos se mantienen para este servicio en particular. Si necesita buscar su dirección de cebolla, claves de acceso o agregar clientes autorizados, ¡aquí es donde debe hacerlo!
|
||||
|
||||
La forma más sencilla de probar su servicio oculto de RPC es utilizar la API [QuickConnect](https://github.com/BlockchainCommons/Bitcoin-Standup/blob/master/Docs/Quick-Connect-API.md) integrada en Bitcoin Standup. Simplemente descargue el código QR que se encuentra en `/qrcode.png` y escanéelo con una billetera o un nodo que admita QuickConnect, como [The Gordian Wallet](https://github.com/BlockchainCommons/FullyNoded-2). Cuando escanee el QR, debería ver que la billetera se sincroniza con su nodo; lo hace utilizando los servicios ocultos de RPC.
|
||||
|
||||
La forma más difícil de probar su servicio oculto RPC es enviar un comando a `bitcoin-cli` con torify, lo que le permite traducir un comando normal de UNIX a un comando protegido por Tor. Es difícil porque necesita obtener tres datos.
|
||||
|
||||
1. **Su puerto de servicio oculto.** Esto viene de `/etc/tor/torrc/`. De forma predeterminada, es el puerto 1309.
|
||||
2. **Su dirección Tor.** Esto está en el archivo `hostname` en el `HiddenServiceDir` directorio definido en `/etc/tor/torrc`. Por defecto el archivo es asi `/var/lib/tor/standup/hostname`. Está protegido, por lo que deberá usar `sudo` para acceder a este.:
|
||||
```
|
||||
$ sudo more /var/lib/tor/standup/hostname
|
||||
mgcym6je63k44b3i5uachhsndayzx7xi4ldmwrm7in7yvc766rykz6yd.onion
|
||||
```
|
||||
3. **Su contraseña RPC.** Esto está en `~/.bitcoin/bitcoin.conf`
|
||||
|
||||
Cuando tenga toda esa información, puede emitir un comando `bitcoin-cli` usando `torify` especificando `-rpcconnect` como su dirección de cebolla, `-rpcport` como su puerto de servicio oculto y `-rpcpassword` como su contraseña:
|
||||
|
||||
```
|
||||
$ torify bitcoin-cli -rpcconnect=mgcym6je63k44b3i5uachhsndayzx7xi4ldmwrm7in7yvc766rykz6yd.onion -rpcport=1309 -rpcuser=StandUp -rpcpassword=685316cc239c24ba71fd0969fa55634f getblockcount
|
||||
```
|
||||
|
||||
### Verifique su configuración de Tor para Bitcoind
|
||||
|
||||
Bitcoin Standup también garantiza que `bitcoind` esté configurado para comunicarse opcionalmente en una dirección de cebolla.
|
||||
|
||||
Puede verificar la configuración inicial de Tor para `bitcoind` haciendo grepping para "tor" en el fichero `debug.log` en su directorio de datos:
|
||||
```
|
||||
$ grep "tor:" ~/.bitcoin/testnet3/debug.log
|
||||
2021-06-09T14:07:04Z tor: ADD_ONION successful
|
||||
2021-06-09T14:07:04Z tor: Got service ID vazr3k6bgnfafmdpcmbegoe5ju5kqyz4tk7hhntgaqscam2qupdtk2yd, advertising service vazr3k6bgnfafmdpcmbegoe5ju5kqyz4tk7hhntgaqscam2qupdtk2yd.onion:18333
|
||||
2021-06-09T14:07:04Z tor: Cached service private key to /home/standup/.bitcoin/testnet3/onion_v3_private_key
|
||||
```
|
||||
> :information_source: **NOTA:** Bitcoin Core ya no admite direcciones v2. La compatibilidad con Tor v2 se eliminó en # [#22050](https://github.com/bitcoin/bitcoin/pull/22050)
|
||||
|
||||
> **TESTNET vs MAINNET:** Mainnet `bitcoind` responde en el puerto 8333, testnet en el puerto 18333.
|
||||
|
||||
Puede verificar que se ha creado un servicio oculto Tor para Bitcoin con la llamada RPC `getnetworkinfo`:
|
||||
|
||||
```
|
||||
$ bitcoin-cli getnetworkinfo
|
||||
...
|
||||
"localaddresses": [
|
||||
{
|
||||
"address": "173.255.245.83",
|
||||
"port": 18333,
|
||||
"score": 1
|
||||
},
|
||||
{
|
||||
"address": "2600:3c01::f03c:92ff:fe86:f26",
|
||||
"port": 18333,
|
||||
"score": 1
|
||||
},
|
||||
{
|
||||
"address": "vazr3k6bgnfafmdpcmbegoe5ju5kqyz4tk7hhntgaqscam2qupdtk2yd.onion",
|
||||
"port": 18333,
|
||||
"score": 4
|
||||
}
|
||||
],
|
||||
...
|
||||
```
|
||||
Esto muestra tres direcciones para acceder a su servidor Bitcoin, una dirección IPv4 (`173.255.245.83`), una dirección IPv6 (`2600:3c01::f03c:92ff:fe86:f26`), y una dirección Tor (`vazr3k6bgnfafmdpcmbegoe5ju5kqyz4tk7hhntgaqscam2qupdtk2yd.onion`).
|
||||
|
||||
> :warning: **ADVERTENCIA:** Obviamente: ¡nunca revele su dirección Tor de una manera que esté asociada con su nombre u otra PII!
|
||||
|
||||
Puede ver información similar con `getnetworkinfo`.
|
||||
```
|
||||
bitcoin-cli getnetworkinfo
|
||||
{
|
||||
"version": 200000,
|
||||
"subversion": "/Satoshi:0.20.0/",
|
||||
"protocolversion": 70015,
|
||||
"localservices": "0000000000000408",
|
||||
"localservicesnames": [
|
||||
"WITNESS",
|
||||
"NETWORK_LIMITED"
|
||||
],
|
||||
"localrelay": true,
|
||||
"timeoffset": 0,
|
||||
"networkactive": true,
|
||||
"connections": 10,
|
||||
"networks": [
|
||||
{
|
||||
"name": "ipv4",
|
||||
"limited": false,
|
||||
"reachable": true,
|
||||
"proxy": "",
|
||||
"proxy_randomize_credentials": false
|
||||
},
|
||||
{
|
||||
"name": "ipv6",
|
||||
"limited": false,
|
||||
"reachable": true,
|
||||
"proxy": "",
|
||||
"proxy_randomize_credentials": false
|
||||
},
|
||||
{
|
||||
"name": "onion",
|
||||
"limited": false,
|
||||
"reachable": true,
|
||||
"proxy": "127.0.0.1:9050",
|
||||
"proxy_randomize_credentials": true
|
||||
}
|
||||
],
|
||||
"relayfee": 0.00001000,
|
||||
"incrementalfee": 0.00001000,
|
||||
"localaddresses": [
|
||||
{
|
||||
"address": "173.255.245.83",
|
||||
"port": 18333,
|
||||
"score": 1
|
||||
},
|
||||
{
|
||||
"address": "2600:3c01::f03c:92ff:fe86:f26",
|
||||
"port": 18333,
|
||||
"score": 1
|
||||
},
|
||||
{
|
||||
"address": "vazr3k6bgnfafmdpcmbegoe5ju5kqyz4tk7hhntgaqscam2qupdtk2yd.onion",
|
||||
"port": 18333,
|
||||
"score": 4
|
||||
}
|
||||
],
|
||||
"warnings": ""
|
||||
}
|
||||
```
|
||||
Este servicio oculto permitirá conexiones anónimas a su `bitcoind` en la red Bitcoin.
|
||||
|
||||
> :warning: **ADVERTENCIA:** Ejecutar Tor y tener un servicio oculto de Tor no le obliga ni a usted ni a sus compañeros a usar Tor.
|
||||
|
||||
### Verifique su configuración de Tor para los pares
|
||||
|
||||
Usando el comando RPC `getpeerinfo`, puede ver qué nodos están conectados a su nodo y verificar si están conectados con Tor.
|
||||
|
||||
```
|
||||
$ bitcoin-cli getpeerinfo
|
||||
```
|
||||
Algunos pueden estar conectados a través de Tor:
|
||||
```
|
||||
...
|
||||
{
|
||||
"id": 9,
|
||||
"addr": "nkv.......xxx.onion:8333",
|
||||
"addrbind": "127.0.0.1:51716",
|
||||
"services": "000000000000040d",
|
||||
"servicesnames": [
|
||||
"NETWORK",
|
||||
"BLOOM",
|
||||
"WITNESS",
|
||||
"NETWORK_LIMITED"
|
||||
],
|
||||
"relaytxes": true,
|
||||
"lastsend": 1593981053,
|
||||
"lastrecv": 1593981057,
|
||||
"bytessent": 1748,
|
||||
"bytesrecv": 41376,
|
||||
"conntime": 1593980917,
|
||||
"timeoffset": -38,
|
||||
"pingwait": 81.649295,
|
||||
"version": 70015,
|
||||
"subver": "/Satoshi:0.20.0/",
|
||||
"inbound": false,
|
||||
"addnode": false,
|
||||
"startingheight": 637875,
|
||||
"banscore": 0,
|
||||
"synced_headers": -1,
|
||||
"synced_blocks": -1,
|
||||
"inflight": [
|
||||
],
|
||||
"whitelisted": false,
|
||||
"permissions": [
|
||||
],
|
||||
"minfeefilter": 0.00000000,
|
||||
"bytessent_per_msg": {
|
||||
"addr": 55,
|
||||
"feefilter": 32,
|
||||
"getaddr": 24,
|
||||
"getheaders": 1053,
|
||||
"inv": 280,
|
||||
"ping": 32,
|
||||
"pong": 32,
|
||||
"sendcmpct": 66,
|
||||
"sendheaders": 24,
|
||||
"verack": 24,
|
||||
"version": 126
|
||||
},
|
||||
"bytesrecv_per_msg": {
|
||||
"addr": 30082,
|
||||
"feefilter": 32,
|
||||
"getdata": 280,
|
||||
"getheaders": 1053,
|
||||
"headers": 106,
|
||||
"inv": 9519,
|
||||
"ping": 32,
|
||||
"pong": 32,
|
||||
"sendcmpct": 66,
|
||||
"sendheaders": 24,
|
||||
"verack": 24,
|
||||
"version": 126
|
||||
}
|
||||
}
|
||||
...
|
||||
```
|
||||
Es posible que algunos no, como ésta conexión IPv6:
|
||||
```
|
||||
...
|
||||
{
|
||||
"id": 17,
|
||||
"addr": "[2001:638:a000:4140::ffff:191]:18333",
|
||||
"addrlocal": "[2600:3c01::f03c:92ff:fe86:f26]:36344",
|
||||
"addrbind": "[2600:3c01::f03c:92ff:fe86:f26]:36344",
|
||||
"services": "0000000000000409",
|
||||
"servicesnames": [
|
||||
"NETWORK",
|
||||
"WITNESS",
|
||||
"NETWORK_LIMITED"
|
||||
],
|
||||
"relaytxes": true,
|
||||
"lastsend": 1595447081,
|
||||
"lastrecv": 1595447067,
|
||||
"bytessent": 12250453,
|
||||
"bytesrecv": 2298711417,
|
||||
"conntime": 1594836414,
|
||||
"timeoffset": -1,
|
||||
"pingtime": 0.165518,
|
||||
"minping": 0.156638,
|
||||
"version": 70015,
|
||||
"subver": "/Satoshi:0.20.0/",
|
||||
"inbound": false,
|
||||
"addnode": false,
|
||||
"startingheight": 1780784,
|
||||
"banscore": 0,
|
||||
"synced_headers": 1781391,
|
||||
"synced_blocks": 1781391,
|
||||
"inflight": [
|
||||
],
|
||||
"whitelisted": false,
|
||||
"permissions": [
|
||||
],
|
||||
"minfeefilter": 0.00001000,
|
||||
"bytessent_per_msg": {
|
||||
"addr": 4760,
|
||||
"feefilter": 32,
|
||||
"getaddr": 24,
|
||||
"getdata": 8151183,
|
||||
"getheaders": 1085,
|
||||
"headers": 62858,
|
||||
"inv": 3559475,
|
||||
"ping": 162816,
|
||||
"pong": 162816,
|
||||
"sendcmpct": 132,
|
||||
"sendheaders": 24,
|
||||
"tx": 145098,
|
||||
"verack": 24,
|
||||
"version": 126
|
||||
},
|
||||
"bytesrecv_per_msg": {
|
||||
"addr": 33877,
|
||||
"block": 2291124374,
|
||||
"feefilter": 32,
|
||||
"getdata": 9430,
|
||||
"getheaders": 1085,
|
||||
"headers": 60950,
|
||||
"inv": 2019175,
|
||||
"ping": 162816,
|
||||
"pong": 162816,
|
||||
"sendcmpct": 66,
|
||||
"sendheaders": 24,
|
||||
"tx": 5136622,
|
||||
"verack": 24,
|
||||
"version": 126
|
||||
}
|
||||
}
|
||||
...
|
||||
```
|
||||
|
||||
Tener una dirección Tor para su `bitcoind` probablemente sea algo menos útil que tener una dirección Tor para sus conexiones RPC. Eso es en parte porque no se recomienda intentar enviar todas sus conexiones de Bitcoin a través de Tor, y en parte porque proteger sus comandos RPC es realmente lo importante: es mucho más probable que lo haga de forma remota, desde una billetera de software como The Gordian. Wallet, mientras que es más probable que su servidor esté en su oficina, sótano o búnker.
|
||||
|
||||
No obstante, hay formas de forzar que `bitcoind` use Tor, como se explica en la siguiente sección.
|
||||
|
||||
## Resumen: verificación de la configuración de Tor
|
||||
|
||||
Tor es un paquete de software instalado como parte de Bitcoin Standup que le permite intercambiar comunicaciones de forma anónima. Protegerá tanto sus puertos RPC (8332 o 18332) como sus puertos `bitcoind` (8333 o 18333), ¡pero debe conectarse activamente a la dirección de cebolla para usarlos! Tor es una piedra de construcción de privacidad y seguridad para su configuración de Bitcoin, y puede verificar que está disponible y vinculado a Bitcoin con unos pocos comandos simples.
|
||||
|
||||
> :fire: ***Cuál es el poder de Tor?*** Muchos ataques a los usuarios de Bitcoin dependen de saber quién es la víctima y de que están realizando transacciones con Bitcoins. Tor puede protegerle de eso ocultando dónde está y qué está haciendo. Es particularmente importante si desea conectarse a su propio nodo de forma remota a través de una billetera de software, y puede ser crucial si lo hace en algún país donde es posible que no sienta que su uso de Bitcoin es apreciado o protegido. Si debe llevar sus servicios de Bitcoin a la carretera, asegúrese de que su billetera sea totalmente compatible con Tor e intercambie todos los comandos RPC con su servidor utilizando ese protocolo.
|
||||
|
||||
## Que sigue?
|
||||
|
||||
Continue "Entendiendo Tor" con [§14.2: Cambiando sus servicios ocultos Bitcoin](14_2_Cambiando_Sus_Servicios_Bitcoin_Ocultos.md).
|
77
es/14_2_Cambiando_Sus_Servicios_Bitcoin_Ocultos.md
Normal file
77
es/14_2_Cambiando_Sus_Servicios_Bitcoin_Ocultos.md
Normal file
@ -0,0 +1,77 @@
|
||||
# Capítulo 14.2: Cambiar sus servicios ocultos de Bitcoin
|
||||
|
||||
> :information_source: **NOTA:** Esta sección se ha agregado recientemente al curso y es un borrador inicial que aún puede estar pendiente de revisión. Lectura de advertencias.
|
||||
|
||||
Tiene un servicio Tor en funcionamiento, pero con el tiempo es posible que desee restablecerlo o ajustarlo.
|
||||
|
||||
## Asegure sus servicios ocultos
|
||||
|
||||
Tor le permite limitar qué clientes hablan con sus servicios ocultos. Si aún no autorizó a su cliente durante la configuración de su servidor debe hacer lo siguiente:
|
||||
|
||||
|
||||
1. Solicite su clave pública de autenticación Tor V3 a su cliente. (En [GordianWallet](https://github.com/BlockchainCommons/GordianWallet-iOS), está disponible en el menú de configuración)
|
||||
2. Vaya al subdirectorio apropiado para su servicio oculto de Bitcoin, que si utilizó Bitcoin Standup es `/var/lib/tor/standup/`.
|
||||
3. Vaya al subdirectorio `authorized_clients`.
|
||||
4. Agregue un archivo llamado `[anything].auth`. El `[anything]` puede ser cualquier cosa realmente.
|
||||
5. Coloque la clave pública (y nada más) en el archivo.
|
||||
|
||||
Una vez que haya agregado un archivo `.auth` al subdirectorio `authorized_client`, solo los clientes autorizados podrán comunicarse con ese servicio oculto. Puede agregar ~330 claves públicas diferentes para habilitar diferentes clientes.
|
||||
|
||||
## Restabelcer su dirección de cebolla para `bitcoind`
|
||||
|
||||
Si alguna vez desea restablecer su dirección de cebolla para `bitcoind`, simplemente elimine la `onion_private_key` en su directorio de datos, como por ejemplo `~/.bitcoin/testnet`:
|
||||
```
|
||||
$ cd ~/.bitcoin/testnet
|
||||
$ rm onion_private_key
|
||||
```
|
||||
Cuando reinicie, se generará una nueva dirección de cebolla:
|
||||
```
|
||||
2020-07-22T23:52:27Z tor: Got service ID pyrtqyiqbwb3rhe7, advertising service pyrtqyiqbwb3rhe7.onion:18333
|
||||
2020-07-22T23:52:27Z tor: Cached service private key to /home/standup/.bitcoin/testnet3/onion_private_key
|
||||
```
|
||||
|
||||
## Restablezca su dirección de cebolla RPC
|
||||
|
||||
Si desea restablecer su dirección de cebolla para el acceso RPC, de manera similar borre el `HiddenServiceDirectory` apropiado y reinicie Tor:
|
||||
```
|
||||
$ sudo rm -rf /var/lib/tor/standup/
|
||||
$ sudo /etc/init.d/tor restart
|
||||
```
|
||||
|
||||
> :warning: **ADVERTENCIA:** Restablecer su dirección de cebolla RPC desconectará cualquier billetera móvil u otros servicios que haya conectado usando la API de Quicklink. Haga esto con extrema precaución.
|
||||
|
||||
## Forzar el uso de Tor para `bitcoind`
|
||||
|
||||
Finalmente, puede forzar el uso de Tor `bitcoind` agregando lo siguiente a su bitcoin.conf:
|
||||
```
|
||||
proxy=127.0.0.1:9050
|
||||
listen=1
|
||||
bind=127.0.0.1
|
||||
onlynet=onion
|
||||
```
|
||||
Luego, deberá agregar nodos de semillas basados en cebolla u otros nodos a su configuración, una vez más editando `bitcoin.conf`:
|
||||
```
|
||||
seednode=address.onion
|
||||
seednode=address.onion
|
||||
seednode=address.onion
|
||||
seednode=address.onion
|
||||
addnode=address.onion
|
||||
addnode=address.onion
|
||||
addnode=address.onion
|
||||
addnode=address.onion
|
||||
```
|
||||
Luego, reinicie `tor` y `bitcoind`.
|
||||
|
||||
Ahora debería comunicarse exclusivamente en Tor. Pero, a menos que se encuentre en un estado hostil, este nivel de anonimato probablemente no sea necesario.
|
||||
Tampoco es particularmente recomendable: puede disminuir en gran medida su número de pares potenciales, provocando problemas de censura o incluso de correlación.
|
||||
También puede ver un retraso. Y esta configuración puede darle una falsa sensación de anonimato que realmente no existe en la red Bitcoin.
|
||||
|
||||
> :warning: **ADVERTENCIA:** Esta configuración no está probada! ¡Úselo bajo su propio riesgo!
|
||||
|
||||
## Resumen: cambio de los servicios ocultos de Bitcoin
|
||||
|
||||
Probablemente no necesitará engañar con sus servicios de Onion una vez que los haya verificado, pero en caso de que lo haga, aquí le mostramos cómo restablecer una dirección de Tor que se ha visto comprometida o pasar al uso exclusivo de Tor para su `bitcoind`.
|
||||
|
||||
## Que sigue?
|
||||
|
||||
Continue "Entendiendo Tor" con [14.3: Agregando Servicios SSH Ocultos](14_3_Agregando_Servicios_SSH_Ocultos.md).
|
66
es/14_3_Agregando_Servicios_SSH_Ocultos.md
Normal file
66
es/14_3_Agregando_Servicios_SSH_Ocultos.md
Normal file
@ -0,0 +1,66 @@
|
||||
# Capítulo 14.3: Agregar servicios ocultos SSH
|
||||
|
||||
> :information_source: **NOTE:** Esta sección se ha agregado recientemente al curso y es un borrador inicial que aún puede estar pendiente de revisión. Lectura con advertencias.
|
||||
|
||||
Hasta la fecha, ha usado Tor con sus servicios de Bitcoin, pero también puede usarlo para proteger otros servicios en su máquina, mejorando su seguridad y privacidad. Esta sección demuestra cómo mediante la introducción de un servicio `ssh` oculto para iniciar sesión de forma remota usando Tor.
|
||||
|
||||
## Crear servicios ocultos SSH
|
||||
|
||||
Los nuevos servicios se crean agregándolos al archivo `/etc/tor/torrc`:
|
||||
```
|
||||
$ su
|
||||
# cat >> /etc/tor/torrc << EOF
|
||||
HiddenServiceDir /var/lib/tor/hidden-service-ssh/
|
||||
HiddenServicePort 22 127.0.0.1:22
|
||||
EOF
|
||||
# exit
|
||||
```
|
||||
Esto es lo que eso significa:
|
||||
|
||||
* HiddenServiceDir: Indica que tiene un directorio de servicio oculto con la configuración necesaria en esta ruta.
|
||||
* HiddenServicePort: Indica el puerto tor que se utilizará; en el caso de SSH, suele ser 22.
|
||||
|
||||
Después de agregar las líneas apropiadas a su archiv `torrc`, deberá reiniciar Tor:
|
||||
|
||||
```
|
||||
$ sudo /etc/init.d/tor restart
|
||||
```
|
||||
Después del reinicio, su directorio `HiddenServiceDir` debería tener nuevos archivos de la siguiente manera:
|
||||
```
|
||||
$ sudo ls -l /var/lib/tor/hidden-service-ssh
|
||||
total 16
|
||||
drwx--S--- 2 debian-tor debian-tor 4096 Jul 22 14:55 authorized_clients
|
||||
-rw------- 1 debian-tor debian-tor 63 Jul 22 14:56 hostname
|
||||
-rw------- 1 debian-tor debian-tor 64 Jul 22 14:55 hs_ed25519_public_key
|
||||
-rw------- 1 debian-tor debian-tor 96 Jul 22 14:55 hs_ed25519_secret_key
|
||||
```
|
||||
El archivo `hostname` de este directorio contiene su nueva identificación de cebolla:
|
||||
```
|
||||
$ sudo cat /var/lib/tor/hidden-service-ssh/hostname
|
||||
qwkemc3vusd73glx22t3sglf7izs75hqodxsgjqgqlujemv73j73qpid.onion
|
||||
```
|
||||
Puede conectarse al `ssh` servicio oculto usando `torify` y esa dirección:
|
||||
```
|
||||
$ torify ssh standup@qwkemc3vusd73glx22t3sglf7izs75hqodxsgjqgqlujemv73j73qpid.onion
|
||||
The authenticity of host 'qwkemc3vusd73glx22t3sglf7izs75hqodxsgjqgqlujemv73j73qpid.onion (127.42.42.0)' can't be established.
|
||||
ECDSA key fingerprint is SHA256:LQiWMtM8qD4Nv7eYT1XwBPDq8fztQafEJ5nfpNdDtCU.
|
||||
Are you sure you want to continue connecting (yes/no)? yes
|
||||
Warning: Permanently added 'qwkemc3vusd73glx22t3sglf7izs75hqodxsgjqgqlujemv73j73qpid.onion' (ECDSA) to the list of known hosts.
|
||||
standup@qwkemc3vusd73glx22t3sglf7izs75hqodxsgjqgqlujemv73j73qpid.onion's password:
|
||||
```
|
||||
## Resumen: Agregar servicios ocultos SSH
|
||||
|
||||
Ahora que tiene Tor instalado y sabe cómo usarlo, puede agregar otros servicios a Tor. Simplemente agregue líneas a su `torrc` (en su servidor), luego conéctese con `torify` (en su cliente).
|
||||
|
||||
> :fire: ***¿Cuál es el poder de otros servicios ocultos?*** Cada vez que accede a un servicio en su servidor de forma remota, deja huellas en la red. Incluso si los datos están encriptados por algo como SSH (o TLS), los merodeadores en la red pueden ver desde dónde se está conectando, a dónde se está conectando y qué servicio está utilizando. ¿Importa esto? Esta es la pregunta que debe hacer. Pero si la respuesta es "Sí", puede proteger la conexión con un servicio oculto.
|
||||
|
||||
|
||||
## ¿Que sigue?
|
||||
|
||||
Para un tipo diferente de privacidad pase a "Usando i2p" en el [Capítulo quince](15_0_Usando_i2p.md).
|
||||
|
||||
O, si lo prefiere, hay dos caminos alternativos:
|
||||
|
||||
Si desea mantenerse enfocado en Bitcoin, continúe con "Programación con RPC" con [Capítulo 16: Hablar con Bitcoind con C](16_0_Hablando_a_Bitcoind_con_C.md).
|
||||
|
||||
O, si no es un programador, puede pasar al [Capítulo 19: Entendiendo la configuración de Lightning](19_0_Entendiendo_Su_Configuracion_Lightning.md) para continuar con su educación de línea de comandos con la red Lightning.
|
31
es/15_0_Usando_i2p.md
Normal file
31
es/15_0_Usando_i2p.md
Normal file
@ -0,0 +1,31 @@
|
||||
# Capítulo 15: Usando i2p
|
||||
|
||||
El Proyecto Internet Invisible (I2P) es una capa de red totalmente encriptada. Esta usa una [base de datos](https://geti2p.net/en/docs/how/network-database) distribuida y túneles unidireccionales encriptados entre usted y sus pares.
|
||||
|
||||
Diferencias básicas entre Tor y i2p:
|
||||
|
||||
| | Tor | i2p |
|
||||
| :--- | :---: | ---: |
|
||||
| Enrutamiento | [Onion](https://www.onion-router.net/) | [Garlic](https://geti2p.net/en/docs/how/garlic-routing) |
|
||||
| Base de Datos de Red | [Servidores Directorio](https://blog.torproject.org/possible-upcoming-attempts-disable-tor-network) de confianza | [Base de Datos de Red Distribuida](https://geti2p.net/en/docs/how/network-database) |
|
||||
| Retransmisión | Conexiones encriptadas **bidireccionales** entre cada Retransmisor | Conexiones **unidireccionales** entre cada servidor con sus túneles |
|
||||
| Servicios Ocultos | Lento | Rápido |
|
||||
|
||||
Lea más: https://geti2p.net/en/comparison/tor
|
||||
|
||||
Este no es instalado por [Bitcoin Standup](https://github.com/BlockchainCommons/Bitcoin-Standup-Scripts) actualmente ya que el soporte i2p fue agregado a Bitcoin Core recientemente. Sin embargo, puede probarlo manualmente siguiendo los pasos mencionados en la [Sección Uno](15_1_Servicio_i2p.md).
|
||||
|
||||
## Objetivos para Este Capítulo
|
||||
|
||||
Después de procesar este capitulo, un desarrollador sera capaz de:
|
||||
|
||||
* Ejecutar Bitcoin Core como un servicio I2P (Proyecto Internet Invisible)
|
||||
|
||||
Los objetivos de apoyo incluyen la habilidad de:
|
||||
|
||||
* Entender la red i2p
|
||||
* Entender las diferencias entre Tor e i2p
|
||||
|
||||
## Tabla de Contenidos
|
||||
|
||||
* [Sección Uno: Bitcoin Core como un Servicio I2P (Proyecto Internet Invisible)](15_1_Servicio_i2p.md)
|
121
es/15_1_Servicio_i2p.md
Normal file
121
es/15_1_Servicio_i2p.md
Normal file
@ -0,0 +1,121 @@
|
||||
# 15.1: Bitcoin Core como servicio I2P (Proyecto de Internet invisible)
|
||||
|
||||
> :information_source: **NOTE:** Esta sección se ha agregado recientemente al curso y es un borrador inicial que aún puede estar pendiente de revisión. Lectura con advertencias.
|
||||
|
||||
En lugar de utilizar el servicio Tor basado en proxy para garantizar la privacidad de sus comunicaciones de Bitcoin, es posible que desee utilizar I2P, que está diseñado para actuar como una red privada dentro de Internet, en lugar de simplemente ofrecer acceso privado a los servicios de Internet.
|
||||
|
||||
## Entender las diferencias
|
||||
|
||||
Tanto Tor como I2P ofrecen acceso privado a servicios en línea, pero con diferentes enrutamiento y bases de datos, y con diferentes arquitecturas para retransmisiones. Dado que los servicios ocultos (como el acceso a Bitcoin) son fundamentales para el diseño de I2P, también se han optimizado mejor:
|
||||
|
||||
| | Tor | i2p |
|
||||
| :--- | :---: | ---: |
|
||||
| Enrutamiento | [Onion](https://www.onion-router.net/) | [Garlic](https://geti2p.net/en/docs/how/garlic-routing) |
|
||||
| Base de Datos de Red | [Servidores Directorio](https://blog.torproject.org/possible-upcoming-attempts-disable-tor-network) de confianza | [Base de Datos de Red Distribuida](https://geti2p.net/en/docs/how/network-database) |
|
||||
| Retransmisión | Conexiones encriptadas **bidireccionales** entre cada Retransmisor | Conexiones **unidireccionales** entre cada servidor con sus túneles |
|
||||
| Servicios Ocultos | Lento | Rápido |
|
||||
|
||||
Puede encontrar una comparación más detallada en [geti2p.net](https://geti2p.net/en/comparison/tor).
|
||||
|
||||
### Comprender las ventajas y desventajas para limitar las conexiones salientes
|
||||
|
||||
Hay [compensaciones](https://bitcoin.stackexchange.com/questions/107060/tor-and-i2p-tradeoffs-in-bitcoin-core) si elige admitir solo I2P, solo Tor o ambos. Estas configuraciones, que limitan las conexiones clearnet salientes, se realizan en Bitcoin Core usando el argumento `onlynet` en su `bitcoin.conf`.
|
||||
|
||||
* `onlynet=onion`, que limita las conexiones salientes a Tor, puede exponer un nodo a los ataques de Sybil y puede crear particiones de red debido a las conexiones limitadas entre Tornet y clearnet.
|
||||
* `onlynet=onion` y `onlynet=i2p` en conjunto, que ejecuta el servicio Onion con el servicio I2P, es experimental por ahora.
|
||||
|
||||
## Instalar I2P
|
||||
|
||||
Para instalar I2P, debe asegurarse de que sus puertos estén configurados correctamente y luego puede continuar con su proceso de configuración.
|
||||
|
||||
### Preparar puertos
|
||||
|
||||
Para usar I2P, deberá abrir los siguientes puertos, que son requeridos por I2P:
|
||||
|
||||
1. **Saliente (Hacia Internet):** Saliente (frente a Internet): se selecciona un puerto aleatorio entre 9000 y 31000. Es mejor si todos estos puertos están abiertos para conexiones salientes, lo que no afecta su seguridad.
|
||||
- Puede verificar el estado del firewall usando `sudo ufw status verbose`, que no debería negar las conexiones salientes de forma predeterminada.
|
||||
2. **Entrante (Desde Internet):** Opcional. Una variedad de puertos entrantes se enumeran en los [documentos I2P](https://geti2p.net/en/faq#ports).
|
||||
- Para obtener la máxima privacidad, es preferible desactivar la aceptación de conexiones entrantes.
|
||||
|
||||
### Ejecute I2P
|
||||
|
||||
Lo siguiente ejecutará los servicios de Bitcoin Core I2P:
|
||||
|
||||
1. Instale `i2pd` en Ubuntu:
|
||||
|
||||
```
|
||||
sudo add-apt-repository ppa:purplei2p/i2pd
|
||||
sudo apt-get update
|
||||
sudo apt-get install i2pd
|
||||
```
|
||||
|
||||
Para instalar en otros sistemas operativos, consulte [estos documentos](https://i2pd.readthedocs.io/en/latest/user-guide/install/)
|
||||
|
||||
2. [Ejecute](https://i2pd.readthedocs.io/en/latest/user-guide/run/) el servicio I2P:
|
||||
|
||||
```
|
||||
$ sudo systemctl start i2pd.service
|
||||
```
|
||||
|
||||
3. Compruebe que I2P se esté ejecutando. Debería verlo en el puerto 7656:
|
||||
|
||||
```
|
||||
$ ss -nlt
|
||||
|
||||
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
|
||||
|
||||
LISTEN 0 4096 127.0.0.1:7656 0.0.0.0:*
|
||||
```
|
||||
|
||||
4. Agregue las siguientes líneas en `bitcoin.conf`:
|
||||
|
||||
```
|
||||
i2psam=127.0.0.1:7656
|
||||
debug=i2p
|
||||
```
|
||||
La opción de registro, `debug=i2p`, se utiliza para registrar información adicional en el registro de depuración sobre la configuración y las conexiones de I2P. La ubicación predeterminada para este archivo de depuración en Linux es `~/.bitcoin/debug.log`:
|
||||
|
||||
5. Reinicie `bitcoind`
|
||||
|
||||
```
|
||||
$ bitcoind
|
||||
```
|
||||
|
||||
6. Revise el archivo `debug.log` para ver si I2P se configuró correctamente o si apareció algún error en los registros.
|
||||
```
|
||||
2021-06-15T20:36:16Z i2paccept thread start
|
||||
2021-06-15T20:36:16Z I2P: Creating SAM session with 127.0.0.1:7656
|
||||
|
||||
2021-06-15T20:36:56Z I2P: SAM session created: session id=3e0f35228b, my address=bmwyyuzyqdc5dcx27s4baltbu6zw7rbqfl2nmclt45i7ng3ul4pa.b32.i2p:18333
|
||||
2021-06-15T20:36:56Z AddLocal(bmwyyuzyqdc5dcx27s4baltbu6zw7rbqfl2nmclt45i7ng3ul4pa.b32.i2p:18333,4)
|
||||
```
|
||||
|
||||
La dirección I2P se menciona en los registros y termina en b32.i2p . Por ejemplo `bmwyyuzyqdc5dcx27s4baltbu6zw7rbqfl2nmclt45i7ng3ul4pa.b32.i2p:18333`.
|
||||
|
||||
7. Confirme que `i2p_private_key` se creó en el directorio de datos de Bitcoin Core. La primera vez que Bitcoin Core se conecta al enrutador I2P, su dirección I2P (y la clave privada correspondiente) se generará automáticamente y se guardará en un archivo llamado *i2p_private_key* :
|
||||
```
|
||||
~/.bitcoin/testnet3$ ls
|
||||
|
||||
anchors.dat chainstate i2p_private_key settings.json
|
||||
banlist.dat debug.log mempool.dat wallets
|
||||
blocks fee_estimates.dat peers.dat
|
||||
```
|
||||
|
||||
8. Compruebe que `bitcoin-cli -netinfo` o `bitcoin-cli getnetworkinfo` retornan la dirección I2P:
|
||||
|
||||
```
|
||||
Local addresses
|
||||
bmwyyuzyqdc5dcx27s4baltbu6zw7rbqfl2nmclt45i7ng3ul4pa.b32.i2p port 18333 score 4
|
||||
```
|
||||
|
||||
Ahora tiene su servidor Bitcoin accesible a través de la red I2P en su nueva dirección local.
|
||||
|
||||
## Resumen: Bitcoin Core como servicio I2P (Proyecto de Internet invisible)
|
||||
|
||||
Siempre es bueno tener alternativas para la privacidad y no depender únicamente de Tor para ejecutar Bitcoin Core como un servicio oculto. Dado que I2P se agregó recientemente en Bitcoin Core, no muchas personas lo usan. Experimente con él e informe de errores si encuentra algún problema.
|
||||
|
||||
> :information_source: **NOTE:** Para la implementación oficial de i2prouter en Java, visite [la página de descarga](https://geti2p.net/en/download) de I2P y siga las instrucciones para su sistema operativo. Una vez instalado, abra una ventana de terminal y escriba `i2prouter start`. Luego, visite `127.0.0.1:7657` en su navegador para habilitar SAM. Para hacerlo, seleccione: "Configurar página de inicio", luego "Clientes", y finalmente seleccione el "Botón Reproducir" junto a la aplicación SAM Bridge. En el lado izquierdo de la página, debería haber una luz verde junto a "Clientes compartidos".
|
||||
|
||||
Continué a "Programando con RPC" con [16.0: Hablando a Bitcoind con C](16_0_Hablando_a_Bitcoind_con_C.md)
|
||||
|
||||
O, si usted no es un programador, puede omitirlo y continuar a [19.0: Entendiendo Su Configuración Lightning](19_0_Entendiendo_Su_Configuracion_Lightning.md) para continuar su educación en la línea de comandos con la red Lightning.
|
25
es/16_0_Hablando_a_Bitcoind_con_C.md
Normal file
25
es/16_0_Hablando_a_Bitcoind_con_C.md
Normal file
@ -0,0 +1,25 @@
|
||||
# Capítulo 16: Hablar con Bitcoind con C
|
||||
|
||||
Mientras trabajamos con Bitcoin Scripts, llegamos a los límites de lo que es posible con bitcoin-cli: actualmente no se puede usar para generar transacciones que contengan scripts inusuales. Los scripts de Shell tampoco son buenos para algunas cosas, como la creación de programas de escucha que sondean constantemente. Afortunadamente, existen otras formas de acceder a la red Bitcoin: API de programación.
|
||||
|
||||
Esta sección se centra en tres bibliotecas diferentes que pueden usarse como base de la programación C sofisticada: una biblioteca RPC y una biblioteca JSON juntas le permiten recrear mucho de lo que hizo en scripts de shell, pero ahora usando C; mientras que una biblioteca ZMQ lo vincula a notificaciones, algo a lo que no ha podido acceder anteriormente. (El próximo capítulo cubrirá una biblioteca aún más sofisticada llamada Libwally, para terminar este vistazo introductorio a la programación de Bitcoin con C.)
|
||||
|
||||
## Objetivos de este capítulo
|
||||
|
||||
Después de trabajar en este capítulo, un desarrollador podrá:
|
||||
|
||||
* Crear programas en C que usen RPC para hablar con Bitcoind
|
||||
* Crear programas en C que usen ZMQ para hablar con Bitcoind
|
||||
|
||||
Los objetivos de apoyo incluyen la capacidad de:
|
||||
|
||||
* Comprender cómo usar una biblioteca RPC
|
||||
* Comprender cómo usar una biblioteca JSON
|
||||
* Comprender las capacidades de ZMQ
|
||||
* Comprender cómo usar una biblioteca ZMQ
|
||||
|
||||
## Tabla de contenido
|
||||
|
||||
* [Sección uno: Acceso a Bitcoind en C con bibliotecas RPC](16_1_Accediendo_a_Bitcoind_en_C_con_las_Bibliotecas_RPC.md)
|
||||
* [Sección dos: Programación de Bitcoind en C con bibliotecas RPC](16_2_Programando_Bitcoind_en_C_con_las_Bibliotecas_RPC.md)
|
||||
* [Sección tres: Recibir notificaciones en C con bibliotecas ZMQ](16_3_Recibiendo_Notificaciones_de_Bitcoind_en_C_con_las_Bibliotecas_ZMQ.md)
|
282
es/16_1_Accediendo_a_Bitcoind_en_C_con_las_Bibliotecas_RPC.md
Normal file
282
es/16_1_Accediendo_a_Bitcoind_en_C_con_las_Bibliotecas_RPC.md
Normal file
@ -0,0 +1,282 @@
|
||||
# 16.1: Acceso a Bitcoind en C con bibliotecas RPC
|
||||
|
||||
> :information_source: **NOTA:** Esta sección se ha agregado recientemente al curso y es un borrador inicial que aún puede estar pendiente de revisión. Lectura con advertencias.
|
||||
|
||||
Ya ha visto una forma alternativa de acceder a los puertos RPC de Bitcoind: `curl` que se cubrió en el [Interludio del Capítulo 4](04_4_Interludio_Usando_Curl.md). Interactuar con `bitcoind` a través de una biblioteca RPC en C no es diferente a eso, solo necesita algunas buenas bibliotecas para ayudarlo. Esta sección presenta un paquete llamado `libbitcoinrpc`, que le permite acceder al puerto JSON-RPC `bitcoind`. Utiliza una biblioteca `curl` para acceder a los datos y usa la biblioteca `jansson` para codificar y decodificar el JSON.
|
||||
|
||||
## Configurar libbitcoinrpc
|
||||
|
||||
Para usar `libbitcoinrpc`, es necesario instalar una configuración básica de C y los paquetes dependientes `libcurl`, `libjansson` y `libuuid`. Lo siguiente lo hará en su servidor Bitcoin Standup (o cualquier otro servidor Ubuntu).
|
||||
```
|
||||
$ sudo apt-get install make gcc libcurl4-openssl-dev libjansson-dev uuid-dev
|
||||
Suggested packages:
|
||||
libcurl4-doc libidn11-dev libkrb5-dev libldap2-dev librtmp-dev libssh2-1-dev
|
||||
The following NEW packages will be installed:
|
||||
libcurl4-openssl-dev libjansson-dev uuid-dev
|
||||
0 upgraded, 3 newly installed, 0 to remove and 4 not upgraded.
|
||||
Need to get 358 kB of archives.
|
||||
After this operation, 1.696 kB of additional disk space will be used.
|
||||
Do you want to continue? [Y/n] y
|
||||
```
|
||||
Puede descargar [libbitcoinrpc de Github](https://github.com/gitmarek/libbitcoinrpc/blob/master/README.md). Clónelo o tome un archivo zip, como prefiera.
|
||||
```
|
||||
$ sudo apt-get install git
|
||||
$ git clone https://github.com/gitmarek/libbitcoinrpc
|
||||
```
|
||||
|
||||
> :warning: **ADVERTENCIA** Un cambio en el RPC de "signrawtransaction" provocó que la firma con `libbitcoinrpc` provocara un segfault para Bitcoin 0.17 o superior. [Se ha enviado un PR](https://github.com/gitmarek/libbitcoinrpc/pull/1/commits) para resolver el problema, pero si aún no se ha fusionado, puede hacer un simple cambio en el código fuente `src/bitcoinrpc_method.c` antes de compilar.
|
||||
|
||||
|
||||
### Compilar libbitcoinrpc
|
||||
|
||||
Antes de que pueda compilar e instalar el paquete, probablemente necesitará ajustar su `$PATH`, para que pueda acceder a `/sbin/ldconfig`:
|
||||
```
|
||||
$ PATH="/sbin:$PATH"
|
||||
```
|
||||
Para un sistema Ubuntu, también querrá ajustar el `INSTALL_LIBPATH` en el fichero `Makefile` de `libbitcoinrpc` para instalar en `/usr/lib` lugar de `/usr/local/lib`:
|
||||
```
|
||||
$ emacs ~/libbitcoinrpc/Makefile
|
||||
...
|
||||
INSTALL_LIBPATH := $(INSTALL_PREFIX)/usr/lib
|
||||
```
|
||||
(Si prefiere no mancillar su `/usr/lib`, la alternativa es cambiar su `etc/ld.so.conf` o sus archivos dependientes de manera apropiada ... pero para una configuración de prueba en una máquina de prueba, esto probablemente esté bien)
|
||||
|
||||
Del mismo modo, también querrá ajustar el `INSTALL_HEADERPATH` en el `libbitcoinrpc` `Makefile` para instalar en `/usr/include` en lugar de `/usr/local/include`:
|
||||
```
|
||||
...
|
||||
INSTALL_HEADERPATH := $(INSTALL_PREFIX)/usr/include
|
||||
```
|
||||
|
||||
Entonces puede compilar:
|
||||
```
|
||||
$ cd libbitcoinrpc
|
||||
~/libbitcoinrpc$ make
|
||||
|
||||
gcc -fPIC -O3 -g -Wall -Werror -Wextra -std=c99 -D VERSION=\"0.2\" -o src/bitcoinrpc_err.o -c src/bitcoinrpc_err.c
|
||||
gcc -fPIC -O3 -g -Wall -Werror -Wextra -std=c99 -D VERSION=\"0.2\" -o src/bitcoinrpc_global.o -c src/bitcoinrpc_global.c
|
||||
gcc -fPIC -O3 -g -Wall -Werror -Wextra -std=c99 -D VERSION=\"0.2\" -o src/bitcoinrpc.o -c src/bitcoinrpc.c
|
||||
gcc -fPIC -O3 -g -Wall -Werror -Wextra -std=c99 -D VERSION=\"0.2\" -o src/bitcoinrpc_resp.o -c src/bitcoinrpc_resp.c
|
||||
gcc -fPIC -O3 -g -Wall -Werror -Wextra -std=c99 -D VERSION=\"0.2\" -o src/bitcoinrpc_cl.o -c src/bitcoinrpc_cl.c
|
||||
gcc -fPIC -O3 -g -Wall -Werror -Wextra -std=c99 -D VERSION=\"0.2\" -o src/bitcoinrpc_method.o -c src/bitcoinrpc_method.c
|
||||
gcc -fPIC -O3 -g -Wall -Werror -Wextra -std=c99 -D VERSION=\"0.2\" -shared -Wl,-soname,libbitcoinrpc.so.0 \
|
||||
src/bitcoinrpc_err.o src/bitcoinrpc_global.o src/bitcoinrpc.o src/bitcoinrpc_resp.o src/bitcoinrpc_cl.o src/bitcoinrpc_method.o \
|
||||
-o .lib/libbitcoinrpc.so.0.2 \
|
||||
-Wl,--copy-dt-needed-entries -luuid -ljansson -lcurl
|
||||
ldconfig -v -n .lib
|
||||
.lib:
|
||||
libbitcoinrpc.so.0 -> libbitcoinrpc.so.0.2 (changed)
|
||||
ln -fs libbitcoinrpc.so.0 .lib/libbitcoinrpc.so
|
||||
```
|
||||
Si eso funciona, puede instalar el paquete:
|
||||
```
|
||||
$ sudo make install
|
||||
Installing to
|
||||
install .lib/libbitcoinrpc.so.0.2 /usr/local/lib
|
||||
ldconfig -n /usr/local/lib
|
||||
ln -fs libbitcoinrpc.so.0 /usr/local/lib/libbitcoinrpc.so
|
||||
install -m 644 src/bitcoinrpc.h /usr/local/include
|
||||
Installing docs to /usr/share/doc/bitcoinrpc
|
||||
mkdir -p /usr/share/doc/bitcoinrpc
|
||||
install -m 644 doc/*.md /usr/share/doc/bitcoinrpc
|
||||
install -m 644 CREDITS /usr/share/doc/bitcoinrpc
|
||||
install -m 644 LICENSE /usr/share/doc/bitcoinrpc
|
||||
install -m 644 Changelog.md /usr/share/doc/bitcoinrpc
|
||||
Installing man pages
|
||||
install -m 644 doc/man3/bitcoinrpc*.gz /usr/local/man/man3
|
||||
```
|
||||
|
||||
## Prepare su código
|
||||
|
||||
`libbitcoinrpc` tiene métodos simples y bien estructurados para conectarse a su `bitcoind`, ejecutar llamadas RPC y decodificar la respuesta.
|
||||
|
||||
Para usar `libbitcoinrpc`, asegúrese de que sus archivos de código incluyan los encabezados adecuados:
|
||||
```
|
||||
#include <jansson.h>
|
||||
#include <bitcoinrpc.h>
|
||||
```
|
||||
También deberá vincular las bibliotecas correspondientes cada vez que compile:
|
||||
```
|
||||
$ cc yourcode.c -lbitcoinrpc -ljansson -o yourcode
|
||||
```
|
||||
|
||||
## Construya su conexión
|
||||
|
||||
Establecer la conexión con su `bitcoind` requiere unos sencillos pasos.
|
||||
|
||||
Primero, inicialice la biblioteca:
|
||||
```
|
||||
bitcoinrpc_global_init();
|
||||
```
|
||||
Luego conéctese a su `bitcoind` con `bitcoinrpc_cl_init_params`. Los cuatro argumentos son `bitcoinrpc_cl_init_params` son nombre de usuario, contraseña, dirección IP y puerto. Ya debería conocer toda esta información de su trabajo con [Curl](04_4_Interludio_Usando_Curl.md). Como recordará, la dirección IP 127.0.0.1 y el puerto 18332 deben ser correctos para la configuración estándar de testnet descrita en estos documentos, mientras que puede extraer el usuario y la contraseña de `~/.bitcoin/bitcoin.conf`.
|
||||
```
|
||||
$ cat bitcoin.conf
|
||||
server=1
|
||||
dbcache=1536
|
||||
par=1
|
||||
maxuploadtarget=137
|
||||
maxconnections=16
|
||||
rpcuser=StandUp
|
||||
rpcpassword=6305f1b2dbb3bc5a16cd0f4aac7e1eba
|
||||
rpcallowip=127.0.0.1
|
||||
debug=tor
|
||||
prune=550
|
||||
testnet=1
|
||||
[test]
|
||||
rpcbind=127.0.0.1
|
||||
rpcport=18332
|
||||
[main]
|
||||
rpcbind=127.0.0.1
|
||||
rpcport=8332
|
||||
[regtest]
|
||||
rpcbind=127.0.0.1
|
||||
rpcport=18443
|
||||
```
|
||||
Que luego coloca en el `bitcoinrpc_cl_init_params`:
|
||||
```
|
||||
bitcoinrpc_cl_t *rpc_client;
|
||||
rpc_client = bitcoinrpc_cl_init_params("StandUp", "6305f1b2dbb3bc5a16cd0f4aac7e1eba", "127.0.0.1", 18332);
|
||||
```
|
||||
|
||||
> **MAINNET VS TESTNET:** El puerto sería 8332 para una configuración de mainnet.
|
||||
|
||||
Si `rpc_client` se inicializa correctamente, podrá enviar comandos RPC.
|
||||
|
||||
Más tarde, cuando haya terminado con su conexión a `bitcoind`, debe cerrarla:
|
||||
```
|
||||
bitcoinrpc_global_cleanup();
|
||||
```
|
||||
|
||||
### Pruebe el código de prueba
|
||||
|
||||
El código de prueba se puede encontrar en el directorio src [16_1_testbitcoin.c](../src/16_1_testbitcoin.c). Descárguelo en su máquina de testnet, luego inserte la contraseña de RPC correcta (y cambie el usuario de RPC si no creó su servidor con StandUp).
|
||||
|
||||
Puede compilar y ejecutar esto de la siguiente manera:
|
||||
```
|
||||
$ cc testbitcoin.c -lbitcoinrpc -ljansson -o testbitcoin
|
||||
$ ./testbitcoin
|
||||
Successfully connected to server!
|
||||
```
|
||||
|
||||
> :warning: **ADVERTENCIA:** Si olvida ingresar su contraseña RPC en este o cualquier otro código de muestra que dependa de RPC, recibirá un mensaje misterioso `ERROR CODE 5`.
|
||||
|
||||
## Realizar una llamada RPC
|
||||
|
||||
Para utilizar un método RPC con `libbitcoinrpc`, debe inicializar una variable de tipo `bitcoinrpc_method_t`. Lo hace con el valor apropiado para el método que desea utilizar, todos los cuales se enumeran en la [referencia bitcoinrpc](https://github.com/gitmarek/libbitcoinrpc/blob/master/doc/reference.md).
|
||||
```
|
||||
bitcoinrpc_method_t *getmininginfo = NULL;
|
||||
getmininginfo = bitcoinrpc_method_init(BITCOINRPC_METHOD_GETMININGINFO);
|
||||
```
|
||||
Por lo general, establecería los parámetros a continuación, pero `getmininginfo` no requiere parámetros, por lo que puede omitir eso por ahora.
|
||||
|
||||
También debe crear otros dos objetos, un "objeto de respuesta" y un "objeto de error". Se pueden inicializar de la siguiente manera:
|
||||
```
|
||||
bitcoinrpc_resp_t *btcresponse = NULL;
|
||||
btcresponse = bitcoinrpc_resp_init();
|
||||
|
||||
bitcoinrpc_err_t btcerror;
|
||||
```
|
||||
Use la variable `rpc_client` sobre la que ya aprendió en la prueba anterior y agregue su método `getmininginfo` y los otros dos objetos:
|
||||
```
|
||||
bitcoinrpc_call(rpc_client, getmininginfo, btcresponse, &btcerror);
|
||||
```
|
||||
### Envíe su respuesta
|
||||
|
||||
Querrá saber qué devolvió la llamada RPC. Para hacerlo, recupere el resultado de su llamada como un objeto JSON `bitcoinrpc_resp_get` y guárdelo en un objeto `jansson`, del tipo `json_t`:
|
||||
```
|
||||
json_t *jsonresponse = NULL;
|
||||
jsonresponse = bitcoinrpc_resp_get(btcresponse);
|
||||
```
|
||||
Si desea generar los resultados JSON completos de la llamada RPC, puede hacerlo con una simple invocación de `json_dumps`, también desde la librería `jansson`:
|
||||
```
|
||||
printf ("%s\n", json_dumps(j, JSON_INDENT(2)));
|
||||
```
|
||||
Sin embargo, dado que ahora está escribiendo programas completos, probablemente desee hacer un trabajo más sutil, como extraer valores JSON individuales para un uso específico. La [referencia jansson](https://jansson.readthedocs.io/en/2.10/apiref.html) detalla cómo hacerlo.
|
||||
|
||||
Al igual que cuando usaba [Curl](04_4_Interludio_Usando_Curl.md), encontrará que RPC devuelve un objeto JSON que contiene un `id`, un `error`, y, lo más importante, un objeto JSON de `result`.
|
||||
|
||||
La función `json_object_get` le permitirá recuperar un valor (como el `result`) de un objeto JSON por clave:
|
||||
```
|
||||
json_t *jsonresult = NULL;
|
||||
jsonresult = json_object_get(jsonresponse,"result");
|
||||
printf ("%s\n", json_dumps (jsonresult, JSON_INDENT(2)));
|
||||
```
|
||||
Sin embargo, probablemente desee profundizar más para obtener una variable específica. Una vez que haya recuperado el valor apropiado, deberá convertirlo en un objeto C estándar usando la función `json_*_value`. Por ejemplo, para acceder a un número entero usa `json_integer_value`:
|
||||
```
|
||||
json_t *jsonblocks = NULL;
|
||||
jsonblocks = json_object_get(jsonresult,"blocks");
|
||||
|
||||
int blocks;
|
||||
blocks = json_integer_value(jsonblocks);
|
||||
printf("Block Count: %d\n",blocks);
|
||||
```
|
||||
|
||||
> :warning: **ADVERTENCIA:** Es extremadamente fácil segmentar su código C cuando se trabaja con objetos `jansson` si se confunde con el tipo de objeto que está recuperando. Haga un uso cuidadoso de `bitcoin-cli help` para saber lo que debe esperar, y si experimenta una falla de segmentación, primero observe sus funciones de recuperación de JSON.
|
||||
|
||||
### Prueba el código de información
|
||||
|
||||
Recupere el código de prueba del [directorio src](../src/16_1_getmininginfo.c).
|
||||
```
|
||||
$ cc getmininginfo.c -lbitcoinrpc -ljansson -o getmininginfo
|
||||
$ ./getmininginfo
|
||||
Full Response: {
|
||||
"result": {
|
||||
"blocks": 1804406,
|
||||
"difficulty": 4194304,
|
||||
"networkhashps": 54842097951591.781,
|
||||
"pooledtx": 127,
|
||||
"chain": "test",
|
||||
"warnings": "Warning: unknown new rules activated (versionbit 28)"
|
||||
},
|
||||
"error": null,
|
||||
"id": "474ccddd-ef8c-4e3f-93f7-fde72fc08154"
|
||||
}
|
||||
|
||||
Just the Result: {
|
||||
"blocks": 1804406,
|
||||
"difficulty": 4194304,
|
||||
"networkhashps": 54842097951591.781,
|
||||
"pooledtx": 127,
|
||||
"chain": "test",
|
||||
"warnings": "Warning: unknown new rules activated (versionbit 28)"
|
||||
}
|
||||
|
||||
Block Count: 1804406
|
||||
```
|
||||
## Realizar una llamada RPC con argumentos
|
||||
|
||||
Pero lo que si su llamada RPC no tiene argumentos?
|
||||
|
||||
### Crear un arreglo JSON
|
||||
|
||||
Para enviar parámetros a su llamada RPC usando `libbitcoinrpc` debe envolverlos en un arreglo JSON. Dado que una matriz es solo una simple lista de valores, todo lo que tiene que hacer es codificar los parámetros como elementos ordenados en la matriz.
|
||||
|
||||
Cree el arreglo JSON usando la función `json_array` de `jansson`:
|
||||
```
|
||||
json_t *params = NULL;
|
||||
params = json_array();
|
||||
```
|
||||
Luego, invertirá el procedimiento que siguió para acceder a los valores JSON: convertirá objetos de tipo C en objetos de tipo JSON utilizando las funciones `json_*`. Luego, los agregará al arreglo:
|
||||
```
|
||||
json_array_append_new(params,json_string(tx_rawhex));
|
||||
```
|
||||
Tenga en cuenta que hay dos variantes del comando append: `json_array_append_new`, que agrega una variable recién creada y `json_array_append`, que agrega una variable existente.
|
||||
|
||||
Esta sencilla metodología `json_array_append_new` servirá para la mayoría de los comandos RPC con parámetros, pero algunos comandos RPC requieren entradas más complejas. En estos casos, es posible que deba crear objetos JSON subsidiarios o matrices JSON, que luego agregará a la matriz de parámetros como de costumbre. La siguiente sección contiene un ejemplo de cómo hacerlo usando `createrawtransaction`, que contiene una matriz JSON de objetos JSON para las entradas, un objeto JSON para las salidas y el parámetro `locktime`.
|
||||
|
||||
### Asignar los parámetros
|
||||
|
||||
Cuando haya creado su matriz JSON de parámetros, simplemente asígnela después de haber inicializado su método RPC, de la siguiente manera:
|
||||
```
|
||||
bitcoinrpc_method_set_params(rpc_method, params)
|
||||
```
|
||||
Esta sección no incluye un ejemplo completo de esta metodología más compleja, pero la veremos en acción varias veces en nuestro primer programa C completo basado en RPC, en la siguiente sección.
|
||||
|
||||
## Resumen: Accediendo a Bitcoind con C
|
||||
|
||||
Al vincular las bibliotecas RPC `bitcoinrpc` y JSON `jansson`, puede acceder fácilmente a `bitcoind` través de llamadas RPC desde una biblioteca C. Para hacerlo, cree una conexión RPC y luego realice llamadas RPC individuales, algunas de ellas con parámetros. `jansson` luego le permite decodificar las respuestas JSON. La siguiente sección demostrará cómo se puede utilizar esto para un programa pragmático del mundo real.
|
||||
|
||||
* :fire: ***Cuál es el poder de C?*** C le permite dar el siguiente paso más allá de las secuencias de comandos de shell, lo que permite la creación de programas más completos y sólidos.
|
||||
|
||||
## Que sigue?
|
||||
|
||||
Obtenga más información sobre "Hablar con Bitcoind con C" en [16.2: Programando Bitcoind en C con las Bibliotecas RPC](16_2_Programando_Bitcoind_en_C_con_las_Bibliotecas_RPC.md).
|
389
es/16_2_Programando_Bitcoind_en_C_con_las_Bibliotecas_RPC.md
Normal file
389
es/16_2_Programando_Bitcoind_en_C_con_las_Bibliotecas_RPC.md
Normal file
@ -0,0 +1,389 @@
|
||||
# 16.2: Programación de Bitcoind en C con bibliotecas RPC
|
||||
|
||||
> :information_source: **NOTA:** Esta sección se agregó recientemente al curso y es un borrador inicial que aún puede estar pendiente de revisión. Lector de advertencias.
|
||||
|
||||
[§16.1](16_1_Accediendo_a_Bitcoind_en_C_con_las_Bibliotecas_RPC.md) presentó la metodología para crear programas en C utilizando bibliotecas RPC y JSON. Ahora vamos a mostrar el potencial de esas bibliotecas C presentando un primer corte simplista de un programa Bitcoin real.
|
||||
|
||||
## Planifique su código
|
||||
|
||||
Esta sección creará una versión simplista de primer corte de `sendtoaddress`, que permitirá al usuario enviar dinero a una dirección siempre que tenga un UTXO suficientemente grande. Esto es lo que debemos hacer:
|
||||
|
||||
1. Solicite una dirección y una cantidad
|
||||
2. Establecer una tarifa arbitraria
|
||||
3. Prepare su RPC
|
||||
4. Encuentre un UTXO que sea lo suficientemente grande para la cantidad + la tarifa
|
||||
5. Cree una dirección de cambio
|
||||
6. Cree una transacción sin procesar que envíe desde la UTXO a la dirección y la dirección de cambio
|
||||
7. Firma la transacción
|
||||
8. Envía la transacción
|
||||
|
||||
### Planifique su futuro
|
||||
|
||||
Dado que este es su primer programa funcional en C, intentaremos mantenerlo simple (KISS). Si estuviéramos creando un programa de producción real, al menos querríamos hacer lo siguiente:
|
||||
|
||||
1. Pruebe y / o revise las entradas
|
||||
2. Calcule una tarifa automáticamente
|
||||
3. Piense lógicamente sobre qué UTXO válido usar
|
||||
4. Combine múltiples UTXO si es necesario
|
||||
5. Esté atento a más errores en los comandos `libbitcoinrpc` o` jansson`
|
||||
6. Esté atento a los errores en las respuestas de RPC
|
||||
|
||||
Si desea continuar expandiendo este ejemplo, abordar las deficiencias de este programa de ejemplo sería un excelente lugar para comenzar.
|
||||
|
||||
## Escriba su software de transacciones
|
||||
|
||||
Ahora esta listo para emprender ese plan paso a paso.
|
||||
|
||||
### Paso 1: Solicite una dirección y una cantidad
|
||||
|
||||
Ingresar la información es bastante fácil a través de argumentos de línea de comando:
|
||||
|
||||
```
|
||||
if (argc != 3) {
|
||||
|
||||
printf("ERROR: Only %i arguments! Correct usage is '%s [recipient] [amount]'\n",argc-1,argv[0]);
|
||||
exit(-1);
|
||||
|
||||
}
|
||||
|
||||
char *tx_recipient = argv[1];
|
||||
float tx_amount = atof(argv[2]);
|
||||
|
||||
printf("Sending %4.8f BTC to %s\n",tx_amount,tx_recipient);
|
||||
```
|
||||
|
||||
> :warning: **ADVERTENCIA:** Un programa real necesitaría una refactorización mucho mejor de estas variables.
|
||||
|
||||
### Paso 2: Establecer una tarifa arbitraria
|
||||
|
||||
En este ejemplo, solo una tarifa arbitraria de 0.0005 BTC para garantizar que las transacciones de prueba se realicen rápidamente:
|
||||
|
||||
```
|
||||
float tx_fee = 0.0005;
|
||||
float tx_total = tx_amount + tx_fee;
|
||||
```
|
||||
|
||||
> :warning: **ADVERTENCIA:** Un programa real calcularía una tarifa que minimiza el costo al tiempo que garantiza que la velocidad sea suficiente para el remitente.
|
||||
|
||||
### Paso 3: Prepare su RPC
|
||||
|
||||
Obviamente, necesitará tener todas sus variables listas nuevamente, como se discutió en [§16.1: Acceso a Bitcoind con C](16_1_Accediendo_a_Bitcoind_en_C_con_las_Bibliotecas_RPC.md). También necesita inicializar su biblioteca, conectar su cliente RPC y preparar su objeto de respuesta:
|
||||
|
||||
```
|
||||
bitcoinrpc_global_init();
|
||||
rpc_client = bitcoinrpc_cl_init_params ("bitcoinrpc", "YOUR-RPC-PASSWD", "127.0.0.1", 18332);
|
||||
btcresponse = bitcoinrpc_resp_init();
|
||||
```
|
||||
|
||||
### Paso 4: Encuentre un UTXO
|
||||
|
||||
Para encontrar un UTXO debe llamar al RPC `listunspent`:
|
||||
|
||||
```
|
||||
rpc_method = bitcoinrpc_method_init(BITCOINRPC_METHOD_LISTUNSPENT);
|
||||
bitcoinrpc_call(rpc_client, rpc_method, btcresponse, &btcerror);
|
||||
```
|
||||
|
||||
Sin embargo, el verdadero trabajo consiste en decodificar la respuesta. La sección anterior señalaba que la biblioteca `jansson` era "algo torpe" y por eso: tiene que crear (y borrar) un conjunto muy grande de objetos `json_t` para buscar lo que quiere.
|
||||
|
||||
Primero, debe recuperar el campo `result` de JSON:
|
||||
|
||||
```
|
||||
json_t *lu_response = NULL;
|
||||
json_t *lu_result = NULL;
|
||||
|
||||
lu_response = bitcoinrpc_resp_get (btcresponse);
|
||||
lu_result = json_object_get(lu_response,"result");
|
||||
```
|
||||
|
||||
> :warning: **ADVERTENCIA:** Solo obtiene un resultado si no hubo un error. Aquí hay otro lugar para una mejor verificación de errores del código de producción.
|
||||
|
||||
|
||||
Luego, ingresa en un ciclo, examinando cada transacción no gastada, que aparece como un elemento en su matriz de resultados JSON:
|
||||
|
||||
```
|
||||
int i;
|
||||
|
||||
const char *tx_id = 0;
|
||||
int tx_vout = 0;
|
||||
double tx_value = 0.0;
|
||||
|
||||
for (i = 0 ; i < json_array_size(lu_result) ; i++) {
|
||||
|
||||
json_t *lu_data = NULL;
|
||||
lu_data = json_array_get(lu_result, i);
|
||||
|
||||
json_t *lu_value = NULL;
|
||||
lu_value = json_object_get(lu_data,"amount");
|
||||
tx_value = json_real_value(lu_value);
|
||||
```
|
||||
|
||||
¿Es el UTXO lo suficientemente grande para pagar su transacción? Si es así, ¡selecciónelo!
|
||||
|
||||
> :warning: **ADVERTENCIA:** Un programa del mundo real pensaría más detenidamente sobre qué UTXO tomar, según el tamaño y otros factores. Probablemente no tomaría lo primero que vio que funcionó.
|
||||
|
||||
```
|
||||
if (tx_value > tx_total) {
|
||||
|
||||
json_t *lu_txid = NULL;
|
||||
lu_txid = json_object_get(lu_data,"txid");
|
||||
tx_id = strdup(json_string_value(lu_txid));
|
||||
|
||||
json_t *lu_vout = NULL;
|
||||
lu_vout = json_object_get(lu_data,"vout");
|
||||
tx_vout = json_integer_value(lu_vout);
|
||||
|
||||
json_decref(lu_value);
|
||||
json_decref(lu_txid);
|
||||
json_decref(lu_vout);
|
||||
json_decref(lu_data);
|
||||
break;
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
También debe borrar sus elementos JSON principales:
|
||||
|
||||
```
|
||||
}
|
||||
|
||||
json_decref(lu_result);
|
||||
json_decref(lu_response);
|
||||
```
|
||||
|
||||
> :warning: **ADVERTENCIA:** Un programa del mundo real también aseguraría que los UTXO fueran "gastables".
|
||||
|
||||
Si no encontró ningun UTXO lo suficientemente grande, tendrá que informar ese triste hecho al usuario ... y tal vez sugerirle que use un programa mejor que combine correctamente las UTXO.
|
||||
|
||||
```
|
||||
if (!tx_id) {
|
||||
|
||||
printf("Very Sad: You don't have any UTXOs larger than %f\n",tx_total);
|
||||
exit(-1);
|
||||
}
|
||||
```
|
||||
|
||||
> **ADVERTENCIA:** Un programa real usaría subrutinas para este tipo de búsqueda, por lo que podría llamar a varias RPC de una biblioteca de funciones C. Simplemente vamos a ponerlo todo en "main" como parte de nuestra filosofía KISS de ejemplos simples.
|
||||
|
||||
|
||||
### Paso 5: Crea una dirección de cambio
|
||||
|
||||
Repita la metodología de búsqueda RPC estándar para obtener una dirección de cambio:
|
||||
|
||||
```
|
||||
rpc_method = bitcoinrpc_method_init(BITCOINRPC_METHOD_GETRAWCHANGEADDRESS);
|
||||
|
||||
if (!rpc_method) {
|
||||
|
||||
printf("ERROR: Unable to initialize listunspent method!\n");
|
||||
exit(-1);
|
||||
|
||||
}
|
||||
|
||||
bitcoinrpc_call(rpc_client, rpc_method, btcresponse, &btcerror);
|
||||
|
||||
if (btcerror.code != BITCOINRPCE_OK) {
|
||||
|
||||
printf("Error: listunspent error code %d [%s]\n", btcerror.code,btcerror.msg);
|
||||
|
||||
exit(-1);
|
||||
|
||||
}
|
||||
|
||||
lu_response = bitcoinrpc_resp_get (btcresponse);
|
||||
lu_result = json_object_get(lu_response,"result");
|
||||
char *changeaddress = strdup(json_string_value(lu_result));
|
||||
```
|
||||
|
||||
La única diferencia es qué información particular se extrae del objeto JSON.
|
||||
|
||||
> :warning: **ADVERTENCIA:** Aquí hay un lugar en el que una subrutina sería realmente agradable: abstraer toda la inicialización y llamada del método RPC.
|
||||
|
||||
|
||||
### Paso 6: Crea una transacción sin procesar
|
||||
|
||||
La creación de la transacción sin procesar real es la otra parte complicada de la programación de su reemplazo de `sendtoaddress`. Eso es porque requiere la creación de un objeto JSON complejo como parámetro.
|
||||
|
||||
Para crear correctamente estos parámetros, deberá revisar lo que espera el RPC `createrawtransaction`. Afortunadamente, esto es fácil de determinar usando la funcionalidad `bitcoin-cli help`:
|
||||
|
||||
```
|
||||
$ bitcoin-cli help createrawtransaction
|
||||
createrawtransaction [{"txid":"id","vout":n},...] {"address":amount,"data":"hex",...} ( locktime )
|
||||
```
|
||||
|
||||
Para revisar, sus entradas serán una matriz JSON que contiene un objeto JSON para cada UTXO. Entonces, todas las salidas estarán en un objeto JSON. Es más fácil crear estos elementos JSON desde adentro hacia afuera, usando comandos `jansson`.
|
||||
|
||||
#### Paso 6.1: Crear los parámetros de entrada
|
||||
|
||||
|
||||
Para crear el objeto de entrada para su UTXO, use `json_object`, luego rellénelo con valores-clave usando `json_object_set_new` (para referencias recién creadas) o `json_object_set` (para referencias existentes):
|
||||
|
||||
```
|
||||
json_t *inputtxid = NULL;
|
||||
inputtxid = json_object();
|
||||
|
||||
json_object_set_new(inputtxid,"txid",json_string(tx_id));
|
||||
json_object_set_new(inputtxid,"vout",json_integer(tx_vout));
|
||||
```
|
||||
|
||||
Notará que nuevamente tiene que traducir cada tipo de variable C en un tipo de variable JSON usando la función apropiada, como `json_string` o `json_integer`.
|
||||
|
||||
Para crear la matriz de entrada general para todos sus UTXO, use `json_array`, luego llénelo con objetos usando `json_array_append`:
|
||||
|
||||
```
|
||||
json_t *inputparams = NULL;
|
||||
inputparams = json_array();
|
||||
json_array_append(inputparams,inputtxid);
|
||||
```
|
||||
|
||||
#### Paso 6.2: Crear los parámetros de salida
|
||||
|
||||
Para crear la matriz de salida para su transacción, siga el mismo formato, cree un objeto JSON con `json_object`, luego llénelo con `json_object_set`:
|
||||
|
||||
```
|
||||
json_t *outputparams = NULL;
|
||||
outputparams = json_object();
|
||||
|
||||
char tx_amount_string[32];
|
||||
sprintf(tx_amount_string,"%.8f",tx_amount);
|
||||
char tx_change_string[32];
|
||||
sprintf(tx_change_string,"%.8f",tx_value - tx_total);
|
||||
|
||||
json_object_set(outputparams, tx_recipient, json_string(tx_amount_string));
|
||||
json_object_set(outputparams, changeaddress, json_string(tx_change_string));
|
||||
```
|
||||
|
||||
> :warning:**ADVERTENCIA:** Puede esperar ingresar sus valores de Bitcoin como números, usando `json_real`. Desafortunadamente, esto expone uno de los principales problemas con la integración de la biblioteca `jansson` y Bitcoin. Bitcoin solo es válido hasta ocho dígitos significativos después del punto decimal. Puede recordar que .00000001 BTC es un satoshi, y esa es la división más pequeña posible de un Bitcoin. Los dobles en C ofrecen dígitos más significativos que eso, aunque a menudo son imprecisos más allá de los ocho decimales. Si intenta convertir directamente de su valor doble en C (o un valor flotante, para el caso) a un valor de Bitcoin, la imprecisión a menudo creará un valor de Bitcoin con más de ocho dígitos significativos. Antes de Bitcoin Core 0.12, esto parece funcionar, y podría usar `json_real`. Pero a partir de Bitcoin Core 0.12, si intenta darle a `createrawtransaction` un valor de Bitcoin con demasiados dígitos significativos, obtendrá un error y la transacción no se creará. Como resultado, si el valor de Bitcoin _ever_ se ha convertido en un doble o flotante, debe reformatearlo a ocho dígitos significativos después del dígito antes de introducirlo como una cadena. Obviamente, esto es una tontería, por lo que debe asegurarse de que continúe funcionando en futuras versiones de Bitcoin Core.
|
||||
|
||||
#### Paso 6.3: Crear la matriz de parámetros
|
||||
|
||||
Para terminar de crear sus parámetros, simplemente agrúpelos todos en una matriz JSON:
|
||||
|
||||
```
|
||||
json_t *params = NULL;
|
||||
params = json_array();
|
||||
json_array_append(params,inputparams);
|
||||
json_array_append(params,outputparams);
|
||||
```
|
||||
|
||||
#### Paso 6.4 Realizar la llamada RPC
|
||||
|
||||
Utilice el método normal para crear su llamada RPC:
|
||||
|
||||
```
|
||||
rpc_method = bitcoinrpc_method_init(BITCOINRPC_METHOD_CREATERAWTRANSACTION);
|
||||
```
|
||||
|
||||
Sin embargo, ahora debe alimentarlo con sus parámetros. Esto simplemente se hace con `bitcoinrpc_method_set_params`:
|
||||
|
||||
```
|
||||
if (bitcoinrpc_method_set_params(rpc_method, params) != BITCOINRPCE_OK) {
|
||||
|
||||
fprintf (stderr, "Error: Could not set params for createrawtransaction");
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
Después, ejecute el RPC y obtenga los resultados como de costumbre:
|
||||
|
||||
```
|
||||
bitcoinrpc_call(rpc_client, rpc_method, btcresponse, &btcerror);
|
||||
|
||||
lu_response = bitcoinrpc_resp_get(btcresponse);
|
||||
lu_result = json_object_get(lu_response,"result");
|
||||
|
||||
char *tx_rawhex = strdup(json_string_value(lu_result));
|
||||
```
|
||||
|
||||
### Paso 7. Firma la transacción
|
||||
|
||||
Es mucho más fácil asignar un parámetro simple a una función. Simplemente crea una matriz JSON y luego asigna el parámetro a la matriz:
|
||||
|
||||
```
|
||||
params = json_array();
|
||||
json_array_append_new(params,json_string(tx_rawhex));
|
||||
```
|
||||
|
||||
Firme la transacción siguiendo el galimatías típico para crear una llamada RPC:
|
||||
|
||||
```
|
||||
rpc_method = bitcoinrpc_method_init(BITCOINRPC_METHOD_SIGNRAWTRANSACTION);
|
||||
if (bitcoinrpc_method_set_params(rpc_method, params) != BITCOINRPCE_OK) {
|
||||
|
||||
fprintf (stderr, "Error: Could not set params for signrawtransaction");
|
||||
|
||||
}
|
||||
|
||||
json_decref(params);
|
||||
|
||||
bitcoinrpc_call(rpc_client, rpc_method, btcresponse, &btcerror);
|
||||
lu_response = bitcoinrpc_resp_get(btcresponse);
|
||||
```
|
||||
|
||||
Nuevamente, usar `jansson` para acceder a la salida puede ser un poco complicado. Aquí debe recordar que `hex` es parte de un objeto JSON, no un resultado independiente, como fue el caso cuando creó la transacción sin procesar. Por supuesto, siempre puede acceder a esta información desde la ayuda de la línea de comandos: `bitcoin-cli help signrawtransaction`:
|
||||
|
||||
```
|
||||
lu_result = json_object_get(lu_response,"result");
|
||||
json_t *lu_signature = json_object_get(lu_result,"hex");
|
||||
char *tx_signrawhex = strdup(json_string_value(lu_signature));
|
||||
json_decref(lu_signature);
|
||||
```
|
||||
|
||||
> :warning: ***ADVERTENCIA:*** Un programa del mundo real obviamente probaría cuidadosamente la respuesta de cada comando RPC para asegurarse de que no haya errores. Eso es especialmente cierto para `signrawtransaction`, porque podría terminar con una transacción parcialmente firmada. Peor aún, si no verifica los errores en el objeto JSON, solo verá el `hex` y no se dará cuenta de que está sin firmar o parcialmente firmado.
|
||||
|
||||
### Paso 8. Envíar la transacción
|
||||
|
||||
Ahora puede enviar su transacción, utilizando todas las técnicas anteriores:
|
||||
|
||||
```
|
||||
params = json_array();
|
||||
json_array_append_new(params,json_string(tx_signrawhex));
|
||||
|
||||
rpc_method = bitcoinrpc_method_init(BITCOINRPC_METHOD_SENDRAWTRANSACTION);
|
||||
|
||||
if (bitcoinrpc_method_set_params(rpc_method, params) != BITCOINRPCE_OK) {
|
||||
|
||||
fprintf (stderr, "Error: Could not set params for sendrawtransaction");
|
||||
|
||||
}
|
||||
|
||||
json_decref(params);
|
||||
|
||||
bitcoinrpc_call(rpc_client, rpc_method, btcresponse, &btcerror);
|
||||
lu_response = bitcoinrpc_resp_get(btcresponse);
|
||||
lu_result = json_object_get(lu_response,"result");
|
||||
|
||||
char *tx_newid = strdup(json_string_value(lu_result));
|
||||
|
||||
printf("Txid: %s\n",tx_newid);
|
||||
```
|
||||
|
||||
El código completo, con un poco más de comprobación de errores, aparece en el Apéndice.
|
||||
|
||||
|
||||
## Pruebe su código
|
||||
|
||||
|
||||
El código completo se puede encontrar en el [directorio src](../src/16_2_sendtoaddress.c).
|
||||
|
||||
Compile esto como de costumbre:
|
||||
|
||||
```
|
||||
$ cc sendtoaddress.c -lbitcoinrpc -ljansson -o sendtoaddress
|
||||
```
|
||||
Luego puede usarlo para enviar fondos a una dirección:
|
||||
|
||||
```
|
||||
./sendtoaddress tb1qynx7f8ulv4sxj3zw5gqpe56wxleh5dp9kts7ns .001
|
||||
Txid: b93b19396f8baa37f5f701c7ca59d3128144c943af5294aeb48e3eb4c30fa9d2
|
||||
```
|
||||
|
||||
Puede ver información sobre esta transacción que enviamos [aquí](https://live.blockcypher.com/btc-testnet/tx/b93b19396f8baa37f5f701c7ca59d3128144c943af5294aeb48e3eb4c30fa9d2/).
|
||||
|
||||
## Resumen: Programación de Bitcoind con C
|
||||
|
||||
Con acceso a una biblioteca C, puede crear programas con muchas más funciones de lo que era razonable hacerlo con scripts de shell. ¡Pero puede requerir mucho trabajo! Incluso con 316 líneas de código, `sendtoaddress.c` no cubre casi todas las complejidades necesarias para realizar transacciones de bitcoins de forma segura e inteligente.
|
||||
|
||||
## ¿Que sigue?
|
||||
|
||||
Obtenga más información sobre "Hablar con Bitcoind con C" en [16.3: Recibir notificaciones en C con bibliotecas ZMQ](16_3_Recibiendo_Notificaciones_de_Bitcoind_en_C_con_las_Bibliotecas_ZMQ.md).
|
@ -0,0 +1,170 @@
|
||||
# 16.3 Recibir notificaciones en C con bibliotecas ZMQ
|
||||
|
||||
> :information_source: **NOTA:** Esta sección se agregó recientemente al curso y es un borrador inicial que aún puede estar pendiente de revisión. Lector de advertencias.
|
||||
|
||||
[§16.1](16_1_Accediendo_a_Bitcoind_en_C_con_las_Bibliotecas_RPC.md) y [§16.2](16_2_Programando_Bitcoind_en_C_con_las_Bibliotecas_RPC.md) introdujeron las bibliotecas RPC y JSON para C, y al hacerlo mostró una de las ventajas de acceder a los comandos RPC de Bitcoin a través de un lenguaje de programación: la capacidad de crear programas mucho más complejos. Este capítulo presenta una tercera biblioteca, para [ZMQ](http://zeromq.org/), y al hacerlo revela otra ventaja: la capacidad de monitorear las notificaciones. Lo usará para codificar un oyente de blockchain.
|
||||
|
||||
> :book: ***¿Qué es ZMQ?*** ZeroMQ (ZMQ) es una biblioteca de mensajería asincrónica de alto rendimiento que proporciona una cola de mensajes. ZeroMQ admite patrones de mensajería comunes (publicación / sub, solicitud / respuesta, cliente / servidor y otros) a través de una variedad de transportes (TCP, en proceso, entre procesos, multidifusión, WebSocket y más), lo que hace que la mensajería entre procesos tan simple como la mensajería entre subprocesos. Puede encontrar más detalles sobre las notificaciones de ZMQ y otros tipos de mensajes en [este repositorio](https://github.com/Actinium-project/ChainTools/blob/master/docs/chainlistener.md).
|
||||
|
||||
## Configurar ZMQ
|
||||
|
||||
Antes de que pueda crear un oyente de blockchain, deberá configurar `bitcoind` para permitir notificaciones ZMQ, y luego deberá instalar una biblioteca ZMQ para aprovechar esas notificaciones.
|
||||
|
||||
### Configurar `bitcoind` para ZMQ
|
||||
|
||||
Bitcoin Core está listo para ZMQ, pero debe especificar puntos finales ZMQ. Los conectores de publicación de ZeroMQ anteponen cada elemento de datos con un tema arbitrario
|
||||
prefijo que permite a los clientes suscriptores solicitar solo aquellos elementos con un prefijo coincidente. Actualmente hay cuatro temas soportados por `bitcoind`:
|
||||
|
||||
```
|
||||
$ bitcoind --help | grep zmq | grep address
|
||||
-zmqpubhashblock=<address>
|
||||
-zmqpubhashtx=<address>
|
||||
-zmqpubrawblock=<address>
|
||||
-zmqpubrawtx=<address>
|
||||
```
|
||||
|
||||
Puede ejecutar `bitcoind` con argumentos de línea de comandos para puntos finales ZMQ, como se muestra arriba, pero también puede hacer que un punto final sea accesible agregando líneas apropiadas a su archivo `~/.bitcoin/bitcoin.conf` y reiniciando su demonio.
|
||||
|
||||
```
|
||||
zmqpubrawblock = tcp: //127.0.0.1: 28332
|
||||
zmqpubrawtx = tcp: //127.0.0.1: 28333
|
||||
```
|
||||
|
||||
Luego puede probar que sus puntos finales están funcionando usando el RPC `getzmqnotifications`:
|
||||
|
||||
```
|
||||
$ bitcoin-cli getzmqnotifications
|
||||
[
|
||||
{
|
||||
"type": "pubrawblock",
|
||||
"address": "tcp://127.0.0.1:28332",
|
||||
"hwm": 1000
|
||||
},
|
||||
{
|
||||
"type": "pubrawtx",
|
||||
"address": "tcp://127.0.0.1:28333",
|
||||
"hwm": 1000
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
Su `bitcoind` ahora emitirá notificaciones ZMQ
|
||||
|
||||
### Instalar ZMQ
|
||||
|
||||
Para aprovechar esas notificaciones, necesita una biblioteca ZMQ que vaya con C; Por lo tanto, usaremos una nueva biblioteca ZMQ en lugar de la biblioteca `libbitcoinrpc` en esta sección, pero cuando experimente en el futuro, por supuesto, podrá combinarlas.
|
||||
|
||||
Afortunadamente, las bibliotecas ZMQ están disponibles a través de paquetes estándar de Debian:
|
||||
|
||||
```
|
||||
$ sudo apt-get install libzmq3-dev
|
||||
$ sudo apt-get install libczmq-dev
|
||||
```
|
||||
|
||||
Ahora esta listo para codificar!
|
||||
|
||||
## Escriba su programa de notificaciones
|
||||
|
||||
El siguiente programa en C es un cliente simple que se suscribe a un punto de conexión ZMQ servido por `bitcoind` y lee los mensajes entrantes.
|
||||
|
||||
El programa requiere dos parámetros: el primer parámetro es el "servidor", que es el punto de conexión TCP expuesto por `bitcoind`; y el segundo es el "tema", que actualmente es `zmqpubhashblock`,` zmqpubhashtx`, `zmqpubrawblock` o `zmqpubrawtx`. El tema debe estar respaldado a través de `bitcoin.conf` y la dirección IP y el puerto del servidor deben coincidir con lo que se define allí.
|
||||
|
||||
``` c
|
||||
#include <czmq.h>
|
||||
int main(int argc, char ** argv) {
|
||||
|
||||
char *zmqserver;
|
||||
char *topic;
|
||||
|
||||
if (argc < 3) {
|
||||
printf("\nUSAGE:\nchainlistener <tcp://localhost:port> <topic>\n\n");
|
||||
return 0;
|
||||
} else {
|
||||
zmqserver = argv[1];
|
||||
topic = argv[2];
|
||||
}
|
||||
```
|
||||
|
||||
Abrirá un socket ZMQ en el servidor definido para el tema definido:
|
||||
|
||||
``` c
|
||||
zsock_t *socket = zsock_new_sub(zmqserver, topic);
|
||||
assert(socket);
|
||||
```
|
||||
|
||||
Después de eso, espera:
|
||||
|
||||
```
|
||||
while(1) {
|
||||
zmsg_t *msg;
|
||||
int rc = zsock_recv(socket, "m", &msg);
|
||||
assert(rc == 0);
|
||||
|
||||
char *header = zmsg_popstr(msg);
|
||||
zframe_t *zdata = zmsg_pop(msg);
|
||||
unsigned int *no = (unsigned int*)zmsg_popstr(msg);
|
||||
|
||||
char *data = zframe_strhex(zdata);
|
||||
int len = zframe_size(zdata);
|
||||
printf("Size: %d\n", len);
|
||||
printf("Data: %s", data);
|
||||
printf("\nNo: %d\n", *no);
|
||||
|
||||
free(header);
|
||||
free(data);
|
||||
free(no);
|
||||
free(zdata);
|
||||
zmsg_destroy(&msg);
|
||||
sleep(1);
|
||||
}
|
||||
```
|
||||
|
||||
Mientras espera, observa los mensajes en el zócalo ZMQ. Siempre que reciba un mensaje, lo "sacará" de la pila e informará su número, su longitud y, lo más importante, los datos.
|
||||
|
||||
¡Eso es!
|
||||
|
||||
Por supuesto, cuando termine, debe limpiar:
|
||||
|
||||
```
|
||||
zsock_destroy(&socket);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
### Pruebe el código de notificación
|
||||
|
||||
El código fuente está en el [directorio src](../src/16_3_chainlistener.c) como de costumbre. Debería compilarlo:
|
||||
|
||||
```
|
||||
$ cc -o chainlistener chainlistener.c -I/usr/local/include -L/usr/local/lib -lzmq -lczmq
|
||||
```
|
||||
|
||||
Luego, puede ejecutarlo con los temas y direcciones que definió en su `bitcoin.conf`:
|
||||
|
||||
```
|
||||
$ ./chainlistener tcp://127.0.0.1:28333 rawtx
|
||||
Size: 250
|
||||
Data: 02000000000101F5BD2032E5A9E6650D4E411AD272E391F26AFC3C9102B7C0C7444F8F74AE86010000000017160014AE9D51ADEEE8F46ED2017F41CD631D210F2ED9C5FEFFFFFF0203A732000000000017A9147231060F1CDF34B522E9DB650F44EDC6C0714E4C8710270000000000001976A914262437B129CF8592AB2EDC59C07D19C57729F72888AC02483045022100AE316D5F21657E3525271DE39EB285D8A0E89A20AB6413824E88CE47DCD0EFE702202F61E10C2A8F4A7125D5EB63AEF883D8E3584A0ECED0D349283AABB6CA5E066D0121035A77FE575A9005E3D3FF0682E189E753E82FA8BFF0A20F8C45F06DC6EBE3421079111B00
|
||||
No: 67
|
||||
Size: 249
|
||||
Data: 0200000000010165C986992F7DAD22BBCE3FCF0BF546EDBC3C599618B04CFA22D9E64EF0CE4C030000000017160014B58E0A5CD68B249F1C407E9AAE9CD0332AAA3067FEFFFFFF02637932000000000017A914CCC47261489036CB6B9AA610857793FF5752E5378710270000000000001976A914262437B129CF8592AB2EDC59C07D19C57729F72888AC0247304402206CCC3F3B4BE01D4E532A01C2DC6BC3B53E4FFB6B494C8B87DD603EFC648A159902201653841E8B16A814DC375129189BB7CF01CFF7D269E91178645B6A97F5C7F4F10121030E20F3D2F172281B8DC747F007DF24B352248AC09E48CA64016942A8F01D317079111B00
|
||||
No: 68
|
||||
Size: 250
|
||||
Data: 02000000000101E889CFC1FFE127BA49F6C1011388606A194109AE1EDAAB9BEE215E123C14A7920000000017160014577B0B3C2BF91B33B5BD70AE9E8BD8144F4B87E7FEFFFFFF02C34B32000000000017A914A9F1440402B46235822639C4FD2F78A31E8D269E8710270000000000001976A914262437B129CF8592AB2EDC59C07D19C57729F72888AC02483045022100B46318F53E1DCE63E7109DB4FA54AF40AADFC2FEB0E08263756BC3B7A6A744CB02200851982AF87DBABDC3DFC3362016ECE96AECFF50E24D9DCF264AE8966A5646FE0121039C90FCB46AEA1530E5667F8FF15CB36169D2AD81247472F236E3A3022F39917079111B00
|
||||
No: 69
|
||||
Size: 250
|
||||
Data: 0200000000010137527957C9AD6CFF0C9A74597E6EFCD7E1EBD53E942AB2FA34A831046CA11488000000001716001429BFF05B3CD79E9CCEFDB5AE82139F72EB3E9DB0FEFFFFFF0210270000000000001976A914262437B129CF8592AB2EDC59C07D19C57729F72888AC231E32000000000017A9146C8D5FE29BFDDABCED0D6F4D8E82DCBFD9D34A8B8702483045022100F259846BAE29EB2C7A4AD711A3BC6109DE69AE91E35B14CA2742157894DD9760022021464E09C00ABA486AEAA0C49FEE12D2850DC03F57F04A1A9E2CC4D0F4F1459C012102899F24A9D60132F4DD1A5BA6DCD1E4E4B6C728927BA482C2C4E511679F60CA5779111B00
|
||||
No: 70
|
||||
.......
|
||||
```
|
||||
|
||||
### Resumen de recepción de notificaciones de Bitcoind con C.md
|
||||
|
||||
Al usar el marco ZMQ, puede recibir notificaciones fácilmente suscribiéndose a un punto de conexión expuesto por `bitcoind` a través de su archivo de configuración.
|
||||
|
||||
> :fire:***¿Cuál es el poder de las notificaciones?*** Con las notificaciones, ya no depende completamente de que los usuarios emitan comandos. En su lugar, puede crear programas que monitoreen la cadena de bloques de Bitcoin y tomar las acciones apropiadas cuando ocurran ciertas cosas. Esto, a su vez, podría combinarse con los comandos RPC que programó en las secciones anteriores. Este también es un gran paso más allá de lo que podría hacer con los scripts de shell: ciertamente, puede crear scripts de shell de escucha de bucle infinito, pero los lenguajes de programación tienden a ser una mejor herramienta para esa tarea.
|
||||
|
||||
|
||||
## ¿Que sigue?
|
||||
|
||||
Obtenga más información sobre "Programación con RPC" en [Capítulo 17: Programación de Bitcoin con Libwally](17_0_Programando_Bitcoin_con_Libwally.md).
|
27
es/17_0_Programando_Bitcoin_con_Libwally.md
Normal file
27
es/17_0_Programando_Bitcoin_con_Libwally.md
Normal file
@ -0,0 +1,27 @@
|
||||
# Capítulo 17: Programación con Libwally
|
||||
|
||||
El capítulo anterior presentó tres Bibliotecas C, para RPC, JSON y ZMQ, todas las cuales están destinadas a interactuar directamente con `bitcoind`, tal como lo ha estado haciendo desde el principio. Pero a veces es posible que desee codificar sin acceso directo a un `bitcoind`. Esto puede ser debido a un cliente fuera de línea, o simplemente porque desea mantener alguna funcionalidad interna en su programa C. También es posible que desee entrar en una funcionalidad de cartera más profunda, como la creación de palabras mnemónicas o la derivación de direcciones. Ahí es donde entra Libwally: es una biblioteca de carteras para C, C++, Java, NodeJS o Python, con envolturas también disponibles para otros idiomas, como Swift.
|
||||
Este capítulo toca la funcionalidad posible dentro de Libwally, la mayoría de los cuales complementan el trabajo que ha hecho a través del acceso RPC a `bitcoind`, pero algunos de los cuales lo replican. También muestra cómo integrar ese trabajo con los clientes RPC con los que está más familiarizado. Sin embargo, tenga en cuenta que esta es sólo la introducción más cruda a Libwally. Varios de sus conjuntos de funciones más importantes están resaltados, pero nunca hacemos más que meter los dedos del pie. Si encuentra sus funciones útiles o intrigantes, entonces tendrá que profundizar mucho más de lo que este curso puede cubrir.
|
||||
|
||||
## Objetivos para este capítulo
|
||||
|
||||
Después de trabajar en este capítulo, un desarrollador podrá:
|
||||
|
||||
* Utilizar funciones de cartera con Libwally
|
||||
* Realizar manipulaciones de PSBTs y transacciones con Libwally
|
||||
* Implementar diseños que mezclen Libwally y trabajo RPC
|
||||
|
||||
Los objetivos de apoyo incluyen la capacidad de:
|
||||
|
||||
* Entender las palabras mnemónicas de BIP39
|
||||
* Conozca más sobre las carteras jerárquicas BIP32
|
||||
* Resumir la profundidad funcional de Libwally
|
||||
|
||||
## Tabla de contenidos
|
||||
* [Sección Uno: Configuración de Libwally](17_1_Configurando_Libwally.md)
|
||||
* [Sección Dos: Usar BIP39 en Libwally](17_2_Usando_BIP39_en_Libwally.md)
|
||||
* [Sección Tres: Usar BIP32 en Libwally](17_3_Usando_BIP32_en_Libwally.md)
|
||||
* [Sección Cuatro: Uso de PSBTs en Libwally](17_4_Usando_PSBTs_en_Libwally.md)
|
||||
* [Sección Cinco: Usar scripts en Libwally](17_5_Usando_Scripts_en_Libwally.md)
|
||||
* [Sección Seis: Usar otras funciones en Libwally](17_6_Usando_Otras_Funciones_en_Libwally.md)
|
||||
* [Sección Siete: Integración de Libwally y Bitcoin-CLI](17_7_Integrando_Libwally_y_Bitcoin-CLI.md)
|
191
es/17_1_Configurando_Libwally.md
Normal file
191
es/17_1_Configurando_Libwally.md
Normal file
@ -0,0 +1,191 @@
|
||||
# 17.1: Configuración de Libwally
|
||||
|
||||
> :information_source: **NOTE:** En esta sección se ha añadido recientemente al curso y es un borrador temprano que todavía puede estar pendiente de revisión. Lectura con advertencias.
|
||||
|
||||
Esta primera sección explicará cómo descargar la Biblioteca Libwally C y hacer que funcione.
|
||||
|
||||
> :book: ***Qué es Libwally?*** Libwally es una biblioteca de primitivos útil para la creación de billeteras que son multiplataforma y multiplataforma, de modo que las mismas funciones se pueden utilizar en todas partes. Hay [documentos en línea](https://wally.readthedocs.io/en/latest/). Libwally está disponible como parte del proyecto [Elements Project](https://github.com/ElementsProject) de Blockstream.
|
||||
|
||||
## Instalar Libwally
|
||||
|
||||
Como siempre, usted necesitará algunos paquetes en su sistema:
|
||||
```
|
||||
$ sudo apt-get install git
|
||||
$ sudo apt-get install dh-autoreconf
|
||||
```
|
||||
A continuación, usted puede descargar Libwally desde su repositorio Git:
|
||||
```
|
||||
$ git clone https://github.com/ElementsProject/libwally-core
|
||||
```
|
||||
Posteriormente, usted puede comenzar el proceso de configuración:
|
||||
```
|
||||
$ ./tools/autogen.sh
|
||||
```
|
||||
Al igual que con `libbitcoinrpc`, es posible que desee instalar esto en `/usr/include` y `/usr/lib` para facilitar su uso. Simplemente modifique la línea apropiada en el programa `configure` :
|
||||
```
|
||||
ac_default_prefix=/usr
|
||||
--
|
||||
> ac_default_prefix=/usr/local
|
||||
```
|
||||
Después puede terminar su preparación:
|
||||
```
|
||||
$ ./configure
|
||||
$ make
|
||||
```
|
||||
Luego, puede verificar que las pruebas están funcionando:
|
||||
```
|
||||
$ make check
|
||||
Making check in src
|
||||
make[1]: Entering directory '/home/standup/libwally-core/src'
|
||||
Making check in secp256k1
|
||||
make[2]: Entering directory '/home/standup/libwally-core/src/secp256k1'
|
||||
make check-TESTS
|
||||
make[3]: Entering directory '/home/standup/libwally-core/src/secp256k1'
|
||||
make[4]: Entering directory '/home/standup/libwally-core/src/secp256k1'
|
||||
============================================================================
|
||||
Testsuite summary for libsecp256k1 0.1
|
||||
============================================================================
|
||||
# TOTAL: 0
|
||||
# PASS: 0
|
||||
# SKIP: 0
|
||||
# XFAIL: 0
|
||||
# FAIL: 0
|
||||
# XPASS: 0
|
||||
# ERROR: 0
|
||||
============================================================================
|
||||
make[4]: Leaving directory '/home/standup/libwally-core/src/secp256k1'
|
||||
make[3]: Leaving directory '/home/standup/libwally-core/src/secp256k1'
|
||||
make[2]: Leaving directory '/home/standup/libwally-core/src/secp256k1'
|
||||
make[2]: Entering directory '/home/standup/libwally-core/src'
|
||||
make check-TESTS check-local
|
||||
make[3]: Entering directory '/home/standup/libwally-core/src'
|
||||
make[4]: Entering directory '/home/standup/libwally-core/src'
|
||||
PASS: test_bech32
|
||||
PASS: test_psbt
|
||||
PASS: test_psbt_limits
|
||||
PASS: test_tx
|
||||
============================================================================
|
||||
Testsuite summary for libwallycore 0.7.8
|
||||
============================================================================
|
||||
# TOTAL: 4
|
||||
# PASS: 4
|
||||
# SKIP: 0
|
||||
# XFAIL: 0
|
||||
# FAIL: 0
|
||||
# XPASS: 0
|
||||
# ERROR: 0
|
||||
============================================================================
|
||||
make[4]: Leaving directory '/home/standup/libwally-core/src'
|
||||
make[3]: Nothing to be done for 'check-local'.
|
||||
make[3]: Leaving directory '/home/standup/libwally-core/src'
|
||||
make[2]: Leaving directory '/home/standup/libwally-core/src'
|
||||
make[1]: Leaving directory '/home/standup/libwally-core/src'
|
||||
make[1]: Entering directory '/home/standup/libwally-core'
|
||||
make[1]: Nothing to be done for 'check-am'.
|
||||
make[1]: Leaving directory '/home/standup/libwally-core'
|
||||
```
|
||||
Por último, puede instalar:
|
||||
```
|
||||
$ sudo make install
|
||||
```
|
||||
|
||||
## Preparación para Libwally
|
||||
|
||||
Entonces, ¿cómo usar Libwally en un programa? Como de costumbre, usted necesitara incluir archivos apropiados y enlazar bibliotecas apropiadas para su código.
|
||||
|
||||
### Incluir los archivos
|
||||
|
||||
Hay un número considerable de archivos de inclusión posibles:
|
||||
```
|
||||
$ ls /usr/include/wally*
|
||||
/usr/include/wally_address.h /usr/include/wally_bip39.h /usr/include/wally_elements.h /usr/include/wally_script.h
|
||||
/usr/include/wally_bip32.h /usr/include/wally_core.h /usr/include/wally.hpp /usr/include/wally_symmetric.h
|
||||
/usr/include/wally_bip38.h /usr/include/wally_crypto.h /usr/include/wally_psbt.h /usr/include/wally_transaction.h
|
||||
```
|
||||
Afortunadamente, los nombres de archivo coinciden en gran medida con las secciones de [docs](https://wally.readthedocs.io/en/latest/), por lo que debería ser capaz de incluir los archivos correctos en función de lo que está haciendo, después de incluir el ubicuo `wally_core.h`.
|
||||
|
||||
### Enlazar las bibliotecas
|
||||
|
||||
También necesitará enlazar las bibliotecas apropiadas:
|
||||
```
|
||||
$ ls /usr/lib/libsecp* /usr/lib/libwally*
|
||||
/usr/lib/libsecp256k1.a /usr/lib/libwallycore.la /usr/lib/libwallycore.so. 0
|
||||
/usr/lib/libsecp256k1.la /usr/lib/libwallycore.so /usr/lib/libwallycore.so. 0.0.0
|
||||
```
|
||||
Mayormente, usted usara `libwallycore`.
|
||||
|
||||
## Configurar un programa Libwally
|
||||
|
||||
En comparación con algunas de las bibliotecas anteriores, Libwally es ridículamente fácil de inicializar:
|
||||
```
|
||||
lw_response = wally_init(0);
|
||||
```
|
||||
Y cuando termine, hay una práctica función para limpiar cualquier memoria asignada:
|
||||
```
|
||||
wally_cleanup(0);
|
||||
```
|
||||
En ambos casos, el argumento es para flags, pero actualmente tiene el valor `0`.
|
||||
|
||||
## Prueba un programa de prueba de Libwally
|
||||
|
||||
El directorio src contiene [testwally.c](../src/17_1_testwally.c), que sólo muestra cómo funcionan las funciones de inicialización y limpieza.
|
||||
|
||||
Puede compilarlo de la siguiente manera:
|
||||
```
|
||||
$ cc testwally.c -lwallycore -o testwally
|
||||
```
|
||||
Después se puede ejecutar:
|
||||
```
|
||||
$ ./testwally
|
||||
Startup: 0
|
||||
```
|
||||
El valor "Startup" es el retorno de `wally_init`. El valor `0` puede parecer inicialmente desalentador, pero es lo que quiere ver:
|
||||
```
|
||||
include/wally_core.h:#define WALLY_OK 0 /** Success */
|
||||
```
|
||||
## Instalar Libsodium
|
||||
|
||||
También debe instalar Libsodium para obtener acceso a un generador de números aleatorios de alta calidad con fines de prueba.
|
||||
> :warning: **WARNING:** La generación de números aleatorios puede ser uno de los mayores puntos de vulnerabilidad en cualquier software de Bitcoin. Si usted lo hace mal, expone a sus usuarios a ataques que podrían terminar como claves de Bitcoin inseguras, y esto no es un [problema teórico](https://github.com/BlockchainCommons/SmartCustodyBook/blob/master/manuscript/03-adversaries.md#adversary-systemic-key-compromise). Blockchain.Info alguna vez generó incorrectamente el 0.0002% de sus claves, lo que dio lugar a la pérdida temporal de 250 Bitcoins. Conclusión: asegúrese de estar totalmente cómodo con su generación de números aleatorios. Podría ser Libsodium, o podría ser un método TRNG aún más robusto.
|
||||
Puede descargar [Libsodium](https://download.libsodium.org/libsodium/releases/) y seguir las instrucciones en [Instalación de Libsodium](https://doc.libsodium.org/installation) para instalar.
|
||||
|
||||
En primer lugar, descomprimir:
|
||||
```
|
||||
$ tar xzfv /tmp/libsodium-1.0.18-stable.tar.gz
|
||||
```
|
||||
Luego, ajuste el archivo `configure` exactamente como tiene las otras bibliotecas hasta la fecha:
|
||||
```
|
||||
< ac_default_prefix=/usr
|
||||
---
|
||||
> ac_default_prefix=/usr/local
|
||||
```
|
||||
Finalmente, `make`, `check`, e `install`
|
||||
```
|
||||
$ make
|
||||
$ make check
|
||||
...
|
||||
============================================================================
|
||||
Testsuite summary for libsodium 1.0.18
|
||||
============================================================================
|
||||
# TOTAL: 77
|
||||
# PASS: 77
|
||||
# SKIP: 0
|
||||
# XFAIL: 0
|
||||
# FAIL: 0
|
||||
# XPASS: 0
|
||||
# ERROR: 0
|
||||
============================================================================
|
||||
...
|
||||
$ sudo make install
|
||||
```
|
||||
Este curso sólo usará `libsodium` para un pequeño (¡pero crucial!) bit de generación de entropía, pero esté atento a ello en la siguiente sección.
|
||||
|
||||
## Resumen: Configuración de Libwally
|
||||
|
||||
Al instalar Libwally (y Libsodium) se incluyen dependencias, bibliotecas y obtiene acceso a una serie de funciones criptográficas y de cartera, que pueden complementar sus bibliotecas RPC y ZMQ (o su línea de comandos `bitcoin-cli`).
|
||||
|
||||
Entonces, ¿qué puede hacer ahora? De eso es lo que se trata en el siguiente capítulo.
|
||||
|
||||
## ¿Qué es lo siguiente?
|
||||
|
||||
Más información sobre "Programar Bitcoin con Libwally" en [17.2: Usar BIP39 en Libwally](17_2_Usando_BIP39_en_Libwally.md).
|
105
es/17_2_Usando_BIP39_en_Libwally.md
Normal file
105
es/17_2_Usando_BIP39_en_Libwally.md
Normal file
@ -0,0 +1,105 @@
|
||||
# 17.2: Uso de BIP39 en Libwally
|
||||
|
||||
> :information_source: **NOTE:** Esta sección se ha añadido recientemente al curso y es un borrador temprano que todavía puede estar pendiente de revisión. Lectura con advertencias.
|
||||
|
||||
Uno de los mayores poderes de Libwally es que puede poner al descubierto el trabajo subyacente de generar semillas, claves privadas y, en última instancia, direcciones. Para empezar, es compatible con [BIP39](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki), que es el BIP que define los códigos mnemónicos para Bitcoin - algo que es totalmente no compatible, hasta la fecha, por Bitcoin Core.
|
||||
> :book: ***Qué es un código mnemónico?*** Las direcciones de Bitcoin (y sus correspondientes claves privadas y semillas subyacentes) son listas largas e ininteligibles de caracteres y números, que no solo son imposibles de recordar, sino también fáciles de escribir mal. Los códigos mnemotécnicos son una solución para esto que permite a los usuarios grabar 12 (o 24) palabras en su idioma, algo que es mucho menos propenso a errores. Estos códigos se pueden utilizar para restaurar completamente una semilla BIP32 que es la base de una cartera HD.
|
||||
|
||||
> :book: ***Que es una semilla?*** Mencionamos brevemente las semillas en [§3.5: Entendiendo el Descriptor](03_5_Entendiendo_El_Descriptor.md). Es el número aleatorio que se utiliza para generar una secuencia completa de claves privadas (y por lo tanto direcciones) en una cartera de jerárquica determinista (HD). Volveremos a las semillas en la siguiente sección, que es todo sobre carteras HD y Libwally. Por ahora, basta saber que un código mnemónico BIP39 corresponde a la semilla de una cartera determinística jerárquica BIP32.
|
||||
|
||||
## Crear códigos mnemotécnicos
|
||||
|
||||
Todas las llaves Bitcoin comienzan con entropía. Este primer uso de Libwally, y su mnemotecnia BIP39, muestra cómo generar entropía y obtener un código mnemotécnico a partir de eso.
|
||||
|
||||
> :book: ***Qué es la entropía?*** Entropía es una forma elegante de decir aleatoriedad, pero es una aleatoriedad cuidadosamente medida que se utiliza como la base de un verdadero número aleatorio generado (TRG). Se mide en "bits", con más bits de entropía resultando en más aleatoriedad (y por lo tanto más protección para lo que se está generando). Para Bitcoin, la entropía es la base de su semilla que en una cartera HD genera todas sus direcciones.
|
||||
Siempre empezará a trabajar con Libwally inicializando la biblioteca y probando los resultados, como se demostró por primera vez en [§17.1](17_1_Configurando_Libwally.md):
|
||||
```
|
||||
int lw_response;
|
||||
|
||||
lw_response = wally_init(0);
|
||||
|
||||
if (lw_response) {
|
||||
|
||||
printf("Error: Wally_init failed: %d\n",lw_response);
|
||||
exit(-1);
|
||||
|
||||
}
|
||||
```
|
||||
Ahora usted esta listo para entropizar.
|
||||
|
||||
### Crear entropía
|
||||
|
||||
Usando `libsodium`, puede crear entropía con el comando `randombytes_buf` :
|
||||
```
|
||||
unsigned char entropy[16];
|
||||
randombytes_buf(entropy, 16);
|
||||
```
|
||||
Este ejemplo, que será la única forma de usar la biblioteca `libsodium`, crea 16 bytes de entropía. En general, para crear un código mnemónico seguro, debe utilizar entre 128 y 256 bits de entropía, que es de 16 a 32 bytes.
|
||||
|
||||
>:warning: **ADVERTENCIA:** De nuevo, tenga la certeza de que usted esta muy cómodo con tu método de generación de entropía antes de usarlo en un programa del mundo real.
|
||||
|
||||
### Traducir a un mnemónico
|
||||
|
||||
16 bytes de entropía es suficiente para crear un código mnemónico de 12 caracteres, que se hace con la función `bip39_mnemonic_from_bytes` de Libwally:
|
||||
```
|
||||
char *mnem = NULL;
|
||||
lw_response = bip39_mnemonic_from_bytes(NULL,entropy,16,&mnem);
|
||||
```
|
||||
Tenga en cuenta que tiene que pasar a lo largo del tamaño del byte, por lo que si fuera a aumentar el tamaño de su entropía, para generar una frase mnemónica más larga, también tendría que aumentar el valor en esta función.
|
||||
|
||||
> **NOTA:** ¡Hay listas de palabras mnemónicas para diferentes idiomas! El valor predeterminado es utilizar la lista en inglés, que es la variable `NULL` en estos comandos mnemotécnicos de Libwally, ¡pero también puede solicitar un idioma diferente!
|
||||
|
||||
¡Eso es! ¡Ha creado una frase mnemónica!
|
||||
|
||||
>:book: ***Cómo se crea la frase mnemónica?*** Usted puede aprender sobre eso en [BIP39](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki), pero si lo prefiere, Greg Walker tiene un [excelente ejemplo](https://learnmeabitcoin.com/technical/mnemonic): básicamente, se añade una suma de comprobación, luego se esconde cada conjunto de 11 bits en una palabra de la lista de palabras. Puede hacer esto con los comandos `bip39_get_wordlist` y `bip39_get_word` si no confía en el comando `bip39_mnemonic_from_bytes`.
|
||||
|
||||
### Traducir en una semilla
|
||||
|
||||
Hay algunas funciones, tales como `bip32_key_from_seed` (que veremos en la siguiente sección) que requieren que usted tenga la semilla en lugar de la mnemónica. Las dos cosas son funcionalmente idénticas: si tiene la semilla, puede generar la mnemónica, y viceversa.
|
||||
|
||||
Si necesita generar la semilla a partir de su mnemónico, sólo tiene que utilizar el comando `bip39_mnemonic_to_seed`:
|
||||
|
||||
```
|
||||
unsigned char seed[BIP39_SEED_LEN_512];
|
||||
size_t seed_len;
|
||||
|
||||
lw_response = bip39_mnemonic_to_seed(mnem,NULL,seed,BIP39_SEED_LEN_512,&seed_len);
|
||||
```
|
||||
Tenga en cuenta que todas las semillas BIP39 son actuales 512 bytes; sin embargo, tiene que establecer el tamaño de su variable apropiadamente, y pasar a lo largo de ese tamaño a `bip39_mnemonic_to_seed`.
|
||||
|
||||
### Imprima su semilla
|
||||
|
||||
Si quiere comprobar cómo se ve su semilla en hexadecimal, puede usar la función `wally_hex_from_bytes` para convertir su semilla en un código hexadecimal legible (pero no para la gente):
|
||||
|
||||
```
|
||||
char *seed_hex;
|
||||
wally_hex_from_bytes(seed,sizeof(seed),&seed_hex);
|
||||
printf("Seed: %s\n",seed_hex);
|
||||
```
|
||||
Si ha hecho todo bien, debería recuperar una semilla de 64 bytes. (Esa es la variable `BIP39_SEED_LEN_512` que usted ha estado lanzando, que define una longitud de semilla predeterminada como 512 bits o 64 bytes.)
|
||||
|
||||
> :warning: **WARNING:** Definitivamente debe probar que su longitud de semilla es de 64 bytes de alguna manera, porque es fácil de estropear, por ejemplo usando el tipo de variable equivocado cuando ejecuta `bip39_mnemonic_to_seed`.
|
||||
|
||||
## Prueba de código mnemónico
|
||||
|
||||
El código completo para generar entropía, generar un mnemónico BIP39, validar el mnemónico y generar una semilla se puede encontrar en el directorio [src](https://github.com/BlockchainCommons/Learning-Bitcoin-from-the-Command-Line/blob/master/src/17_2_genmnemonic.c). Descargar y compilar:
|
||||
```
|
||||
$ cc genmnemonic.c -lwallycore -lsodium -o genmnemonic
|
||||
```
|
||||
Entonces usted puede ejecutar la prueba:
|
||||
```
|
||||
Mnemonic: parent wasp flight sweet miracle inject lemon matter label column canyon trend
|
||||
Mnemonic validated!
|
||||
Seed: 47b04cfb5d8fd43d371497f8555a27a25ca0a04aafeb6859dd4cbf37f6664b0600c4685c1efac29c082b1df29081f7a46f94a26f618fc6fd38d8bc7b6cd344c7
|
||||
```
|
||||
## Resumen: Usando BIP39 en Libwally
|
||||
|
||||
BIP39 le permite generar un conjunto de 12-24 palabras mnemónicas a partir de una semilla (¡y la biblioteca Libwally también le permite validarla!).
|
||||
|
||||
> :fire: ***Cuál es el poder de BIP39?*** Las semillas de bitcoin y las llaves privadas son propensas a todo tipo de pérdidas. Usted escribe mal un solo dígito, y su dinero se ha ido para siempre. Las palabras mnemónicas son una forma mucho más fácil de representar los mismos datos, pero debido a que son palabras en el idioma de elección del usuario, son menos propensas a errores. Asi que el poder de BIP39 es mejorar la accesibilidad, usabilidad y seguridad de Bitcoin.
|
||||
|
||||
> :fire: ***Cuál es el poder del BIP39 en Libwally?*** Bitcoind actualmente no admite palabras mnemónicas, por lo que el uso de Libwally puede permitirle generar palabras mnemotécnicas junto con las direcciones contenidas en `bitcoind` (aunque, como veremos en §17.7, en la actualidad requiere alguna solución alterna para importar sus claves a Bitcoin Core).
|
||||
|
||||
## ¿Qué es lo siguiente?
|
||||
|
||||
Más información sobre "Programar Bitcoin con Libwally" en [17.3: Usar BIP32 en Libwally](17_3_Usando_BIP32_en_Libwally.md).
|
129
es/17_3_Usando_BIP32_en_Libwally.md
Normal file
129
es/17_3_Usando_BIP32_en_Libwally.md
Normal file
@ -0,0 +1,129 @@
|
||||
# 17.3: Uso de BIP32 en Libwally
|
||||
|
||||
> :information_source: **NOTA:** Esta sección se ha añadido recientemente al curso y es un borrador temprano que todavía puede estar pendiente de revisión. Lectura con advertencias.
|
||||
|
||||
En [§17.2](17_2_Usando_BIP39_en_Libwally.md), usted fue capaz de usar entropía para generar una semilla y su mnemónico relacionado. Como usted puede recordar de [§3.5: Entendiendo el Descriptor](03_5_Entendiendo_El_Descriptor.md), una semilla es la base de un Monedero Jerárquico Determinista (HD), donde esa sola semilla puede ser usada para generar muchas direcciones. Entonces, ¿cómo se pasa de la semilla a las direcciones reales? Ahí es donde entra [BIP32](https://en.bitcoin.it/wiki/BIP_0032).
|
||||
|
||||
## Crear una raíz HD
|
||||
|
||||
Para crear una dirección HD se requiere comenzar con una semilla, y luego ir hacía abajo por la jerarquía hasta el punto en el que se crean las direcciones:
|
||||
```c
|
||||
unsigned char entropy[16];
|
||||
randombytes_buf(entropy, 16);
|
||||
|
||||
char *mnem = NULL;#
|
||||
lw_response = bip39_mnemonic_from_bytes(NULL,entropy,16,&mnem);
|
||||
|
||||
unsigned char seed[BIP39_SEED_LEN_512];
|
||||
size_t seed_len;
|
||||
lw_response = bip39_mnemonic_to_seed(mnem,NULL,seed,BIP39_SEED_LEN_512,&seed_len);
|
||||
```
|
||||
Como puede ver, necesitará decirle qué versión de la clave devolver, en este caso `BIP32_VER_TEST_PRIVATE`, una clave de testnet privada.
|
||||
|
||||
> :link: **TESTNET vs MAINNET:** En mainnet, en cambio, se pide `BIP32_VER_MAIN_PRIVATE`.
|
||||
|
||||
### Generar xpub & xprv
|
||||
|
||||
Siempre que tenga una llave en la mano, puede convertirla en claves xpub o xprv para distribución con el comando `bip32_key_to_base58`. Solo tiene que decirle si usted quiere una clave `PRIVATE` (xprv) o `PUBLIC` (xpub):
|
||||
|
||||
```c
|
||||
char *xprv;
|
||||
lw_response = bip32_key_to_base58(key_root, BIP32_FLAG_KEY_PRIVATE, &xprv);
|
||||
|
||||
char *xpub;
|
||||
lw_response = bip32_key_to_base58(key_root, BIP32_FLAG_KEY_PUBLIC, &xpub);
|
||||
```
|
||||
## Entender la jerarquía
|
||||
|
||||
Antes de ir más lejos, es necesario entender cómo funciona la jerarquía de una cartera HD. Como se discute en [§3.5](03_5_Entendiendo_El_Descriptor.md), una ruta de derivación describe el árbol que se sigue para llegar a una clave jerárquica, por lo que `[0/1/0]` es el 0º hijo del 1er hijo del 0º hijo de una clave raíz. A veces parte de esa derivación está marcada con `'`s o `h`s para mostrar derivaciones endurecidas, que aumentan la seguridad: `[0'/1'/0']`.
|
||||
|
||||
Sin embargo, para las carteras HD, cada uno de esos niveles de la jerarquía se utiliza de una manera muy específica. Esto se definió originalmente en [BIP44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki) y más tarde se actualizó para Segwit en [BIP84].
|
||||
|
||||
En conjunto, una ruta de derivación BIP32 se define para tener cinco niveles:
|
||||
1. **Proósito.** Normalmente se establece en `44'` o `84'`, dependiendo del BIP que se esté siguiendo.
|
||||
2. **Moneda.** Para bitcoins en MAINNET, esto es `0'`, para testnet es `1'`.
|
||||
3. **Cuenta.** Una cartera puede contener varias cuentas discretas, empezando por `0'`.
|
||||
4. **Cambio.** Las direcciones externas (para distribución) se establecen en `0`, mientras que las direcciones internas (para cambio) se establecen en `1`.
|
||||
5. **Índice.** La enésima dirección de la jerarquía, comenzando con `0`.
|
||||
|
||||
Así que en testnet, la dirección cero para una dirección externa para la cuenta cero para monedas de testnet usando los estándares BIP84 es `[m/84'/1'/0'/0/0]`. Esa es la dirección que usted estara creando momentáneamente.
|
||||
|
||||
> :link: **TESTNET vs MAINNET:** Para mainnet, eso sería `[m/84'/0'/0'/0'/0]`
|
||||
|
||||
### Entender la jerarquía en el núcleo de Bitcoin
|
||||
|
||||
Usaremos la jerarquía anterior para todas las claves de HD en Libwally, pero tenga en cuenta que este estándar no es utilizado por Bitcoin Core `bitcoin-cli`, que en su lugar utiliza `[m/0'/0'/0']` para la dirección externa 0º y `[m/0'/1'/0']` para la dirección de cambio 0º.
|
||||
|
||||
## Generar una dirección
|
||||
|
||||
Para generar una dirección, tiene que excavar a través de toda la jerarquía.
|
||||
|
||||
### Generar una clave de cuenta
|
||||
|
||||
Una manera de hacer esto es usar la función `bip32_key_from_parent_path_alloc` para desplegar varios niveles de una jerarquía. Incrusta los niveles en una matriz:
|
||||
```c
|
||||
uint32_t path_account[] = {BIP32_INITIAL_HARDENED_CHILD+84, BIP32_INITIAL_HARDENED_CHILD+1, BIP32_INITIAL_HARDENED_CHILD};
|
||||
```
|
||||
Aquí veremos al descendiente endurecido a cero (esa es la cuenta) o al primer descendiente endurecido (eso es monedas de tesnet) del descendiente 84º endurecido (ese es el estándar BIP84): `[m/84'/1'/0']`.
|
||||
|
||||
A continuación, puede utilizar esa ruta para generar una nueva clave a partir de su antigua clave:
|
||||
```c
|
||||
struct ext_key *key_account;
|
||||
lw_response = bip32_key_from_parent_path_alloc(key_root,path_account,sizeof(path_account),BIP32_FLAG_KEY_PRIVATE,&key_account);
|
||||
```
|
||||
Cada vez que tenga una nueva clave,usted puede usarla para generar nuevas claves xprv y xpub, si lo desea:
|
||||
```c
|
||||
lw_response = bip32_key_to_base58(key_account, BIP32_FLAG_KEY_PRIVATE, &a_xprv);
|
||||
lw_response = bip32_key_to_base58(key_account, BIP32_FLAG_KEY_PUBLIC, &a_xpub);
|
||||
```
|
||||
### Generar una clave de dirección
|
||||
|
||||
Alternativamente, puede usar la función `bip32_key_from_parent_alloc`, que simplemente baja un nivel de la jerarquía a la vez. El siguiente ejemplo se reduce al descendiente 0º de la clave de cuenta (que es la dirección externa) y luego al descendiente 0º de la anterior. Esto sería útil porque entonces usted podría seguir generando la primera dirección, la segunda dirección, y así sucesivamente a partir de esa clave externa:
|
||||
```c
|
||||
struct ext_key *key_external;
|
||||
lw_response = bip32_key_from_parent_alloc(key_account,0,BIP32_FLAG_KEY_PRIVATE,&key_external);
|
||||
|
||||
struct ext_key *key_address;
|
||||
lw_response = bip32_key_from_parent_alloc(key_external,0,BIP32_FLAG_KEY_PRIVATE,&key_address);
|
||||
```
|
||||
> :warning: **ADVERTENCIA:** En algún momento de esta jerarquía, puede que decida generar `BIP32_FLAG_KEY_PUBLIC` en lugar de `BIP32_FLAG_KEY_PRIVATE`. Obviamente esta decisión se basará en su seguridad y sus necesidades, pero recuerde que sólo necesita una clave pública para generar la dirección real.
|
||||
|
||||
### Generar una dirección
|
||||
|
||||
Finalmente, usted esta listo para generar una dirección a partir de su clave final. Todo lo que hace es ejecutar `wally_bip32_to_addr_segwit` usando su clave final y una descripción del tipo de dirección que es.
|
||||
```c
|
||||
char *segwit;
|
||||
lw_response = wally_bip32_key_to_addr_segwit(key_address,"tb",0,&segwit);
|
||||
|
||||
printf("[m/84'/1'/0'/0/0]: %s\n",segwit);
|
||||
```
|
||||
> :link: **TESTNET vs MAINNET:** El argumento `tb` define una dirección de testnet. Para mainnet use `bc`.
|
||||
|
||||
También hay una función `wally_bip32_key_to_address` que se puede utilizar para generar una dirección heredada o una dirección Segwit anidada.
|
||||
|
||||
## Prueba de código HD
|
||||
|
||||
El código para este ejemplo de HD se puede encontrar, como de costumbre, en el [src directory](https://github.com/BlockchainCommons/Learning-Bitcoin-from-the-Command-Line/tree/master/src/17_3_genhd.c).
|
||||
|
||||
Puede compilarlo y probarlo:
|
||||
```
|
||||
$ cc genhd.c -lwallycore -lsodium -o genhd
|
||||
$ ./genhd
|
||||
Mnemonic: behind mirror pond finish borrow wood park foam guess mail regular reflect
|
||||
Root xprv key: tprv8ZgxMBicQKsPdLFXmZ6VegTxcmeieNpRUq8J2ahXxSaK2aF7CGqAc14ZADLjdHJdCr8oR2Zng9YH1x1A7EBaajQLVGNtxc4YpFejdE3wyj8
|
||||
Root xpub key: tpubD6NzVbkrYhZ4WoHKfCm64685BoAeoi1L48j5K6jqNiNhs4VspfeknVgRLLiQJ3RkXiA9VxguUjmEwobtmrXNbhXsPHfm9W5HJR9DKRGaGJ2
|
||||
Account xprv key: tprv8yZN7h6SPvJXrhAk56z6cwHQE6qZBRreB9fqqZJ1Xd1nLci3Rw8HTmqNkpFNgf3eZx8hYzhFWafUhHSt3HgF13aHvCE6kveS7gZAyfQwMDi
|
||||
Account xpub key: tpubDWFQG78gYHzCkACXxkeh2LwWo8MVLm3YkTGd85LJwtpBB6xp4KwseGTEvxjeZNhnCNPdfZqRcgcZZAka4tD3xGS2J53WKHPMRhG357VKsqT
|
||||
[m/84'/1'/0'/0/0]: tb1q0knqq26ek59pfl7nukzqr28m2zl5wn2f0ldvwu
|
||||
```
|
||||
## Resumen: Usando BIP32 en Libwally
|
||||
|
||||
Una cartera HD le permite generar un gran número de claves a partir de una sola semilla. Ahora sabe cómo se organizan esas claves bajo BIP44, BIP84 y Bitcoin Core y cómo derivarlas, empezando con una semilla o palabras mnemónicas.
|
||||
|
||||
> :fire: ***Cuál es la potencia de BIP32?*** Las llaves son el elemento más difícil (y más peligroso) de la mayoría de las operaciones criptográficas. Si los pierde, pierde cualquier llave protegida. BIP32 se asegura de que sólo necesita conocer una clave, la semilla, en lugar de un gran número de claves diferentes para diferentes direcciones.
|
||||
|
||||
> :fire: ***Cuál es la potencia del BIP32 en Libwally?*** Bitcoind ya crea direcciones basadas en HD para usted, lo que significa que normalmente no tiene que preocuparse de derivar direcciones de esta manera. Sin embargo, usar las funciones BIP32 de Libwally puede ser muy útil si tiene una máquina fuera de línea donde necesitas derivar direcciones, posiblemente basadas en una semilla pasada de `bitcoind` a su dispositivo fuera de línea (o viceversa).
|
||||
|
||||
## ¿Qué es lo siguiente?
|
||||
|
||||
Más información sobre "Programar Bitcoin con Libwally" en [17.4: Usar PSBTs en Libwally](17_4_Usando_PSBTs_en_Libwally.md).
|
374
es/17_4_Usando_PSBTs_en_Libwally.md
Normal file
374
es/17_4_Usando_PSBTs_en_Libwally.md
Normal file
@ -0,0 +1,374 @@
|
||||
# 17.4: Uso de PSBTs en Libwally
|
||||
|
||||
> :information_source: **NOTA:** Esta sección se ha añadido recientemente al curso y es un borrador temprano que todavía puede estar pendiente de revisión. Lectura con advertencias.
|
||||
|
||||
Aprendió todo sobre las Transacciones de Bitcoin Parcialmente Firmadas (PSBTs) en [§7.1](07_1_Creando_una_Transaccion_Bitcoin_Parcialmente_Firmada.md) y [§7.2](07_2_Usando_una_Transaccion_Bitcoin_Parcialmente_Firmada.md), y como vio en [§7.3: Integración con Wallets de Hardware](07_3_Integrando_con_Hardware_Wallets.md), una de sus principales ventajas es poder integrarse con nodos fuera de línea, como Hardware Wallets. HWI le permitió pasar comandos a una Cartera de Hardware, pero ¿qué utiliza la propia cartera para gestionar los PSBTs? Resulta que puede usar algo como Libwally, como demuestra esta sección.
|
||||
|
||||
Básicamente, Libwally tiene toda la funcionalidad de PSBT, así que si hay algo que puede hacer con `bitcoind`, también puede hacerlo usando Libwally, incluso si su dispositivo está desconectado. Lo que sigue es la más simple introducción a lo que es un tema muy complejo.
|
||||
|
||||
## Convertir un PSBT
|
||||
|
||||
Convertir un PSBT en la estructura interna de Libwally es increíblemente fácil, simplemente ejecuta `wally_psbt_from_base64` con un PSBT base64 - que son las salidas producidas por `bitcoin-cli`, tales como:
|
||||
`cHNidP8BAJoCAAAAAri6BLjKQZGO9Y1iVIYbxlxBJ2kqsTPWnxGaH4HrSjxbAAAAAAD+////leV0hwJ0fO40RmhuFVIYtO16ktic2J4vJFLAsT5TM8cBAAAAAP7///8CYOMWAAAAAAAWABTHctb5VULhHvEejvx8emmDCtOKBU+gBwAAAAAAFgAU9Ojd5ds3CJi1fIRWbj92CYhQgX0AAAAAAAEBH0BCDwAAAAAAFgAUABk8i/Je8Fb41FcaHD9lEj5f54giBgMBaNlILisC1wJ/tKie3FStqhrfcJM09kfQobBTOCiuxRiaHVILVAAAgAEAAIAAAACAAAAAADkCAAAAAQEfQEIPAAAAAAAWABQtTxOfqohTBNFWFqFm0tUVdK9KXSIGAqATz5xLX1aJ2SUwNqPkd8+YaJYm94FMlPCScm8Rt0GrGJodUgtUAACAAQAAgAAAAIAAAAAAAAAAAAAAIgID2UK1nupSfXC81nmB65XZ+pYlJp/W6wNk5FLt5ZCSx6kYmh1SC1QAAIABAACAAAAAgAEAAAABAAAAAA==`
|
||||
|
||||
Sin embargo, es un poco más difícil lidiar con el resultado, porque Libwally lo convierte en una estructura muy compleja `wally_psbt` .
|
||||
|
||||
Así es como se define en `/usr/include/wally_psbt.h`:
|
||||
```c
|
||||
struct wally_psbt {
|
||||
unsigned char magic[5];
|
||||
struct wally_tx *tx;
|
||||
struct wally_psbt_input *inputs;
|
||||
size_t num_inputs;
|
||||
size_t inputs_allocation_len;
|
||||
struct wally_psbt_output *outputs;
|
||||
size_t num_outputs;
|
||||
size_t outputs_allocation_len;
|
||||
struct wally_unknowns_map *unknowns;
|
||||
uint32_t version;
|
||||
};
|
||||
|
||||
struct wally_psbt_input {
|
||||
struct wally_tx *non_witness_utxo;
|
||||
struct wally_tx_output *witness_utxo;
|
||||
unsigned char *redeem_script;
|
||||
size_t redeem_script_len;
|
||||
unsigned char *witness_script;
|
||||
size_t witness_script_len;
|
||||
unsigned char *final_script_sig;
|
||||
size_t final_script_sig_len;
|
||||
struct wally_tx_witness_stack *final_witness;
|
||||
struct wally_keypath_map *keypaths;
|
||||
struct wally_partial_sigs_map *partial_sigs;
|
||||
struct wally_unknowns_map *unknowns;
|
||||
uint32_t sighash_type;
|
||||
};
|
||||
|
||||
struct wally_psbt_output {
|
||||
unsigned char *redeem_script;
|
||||
size_t redeem_script_len;
|
||||
unsigned char *witness_script;
|
||||
size_t witness_script_len;
|
||||
struct wally_keypath_map *keypaths;
|
||||
struct wally_unknowns_map *unknowns;
|
||||
};
|
||||
```
|
||||
Estos a su vez utilizan algunas estructuras de transacción definidas en `/usr/include/wally_transaction.h`:
|
||||
```c
|
||||
struct wally_tx {
|
||||
uint32_t version;
|
||||
uint32_t locktime;
|
||||
struct wally_tx_input *inputs;
|
||||
size_t num_inputs;
|
||||
size_t inputs_allocation_len;
|
||||
struct wally_tx_output *outputs;
|
||||
size_t num_outputs;
|
||||
size_t outputs_allocation_len;
|
||||
};
|
||||
|
||||
struct wally_tx_output {
|
||||
uint64_t satoshi;
|
||||
unsigned char *script;
|
||||
size_t script_len;
|
||||
uint8_t features;
|
||||
};
|
||||
```
|
||||
¡Hay mucho allí! Aunque mucho de esto debería ser familiar de los capítulos penetrantes, es un poco abrumador verlo todo expuesto en las estructuras C.
|
||||
|
||||
## Leer un PSBT convertido
|
||||
|
||||
Obviamente, puede leer cualquier cosa de una estructura PSBT llamando a los elementos individuales de las diversas subestructuras. El siguiente es un breve resumen que muestra cómo tomar algunos de los elementos.
|
||||
|
||||
Aquí hay un ejemplo de la recuperación de los valores y `scriptPubKeys` de las entradas:
|
||||
|
||||
```c
|
||||
int inputs = psbt->num_inputs;
|
||||
printf("TOTAL INPUTS: %i\n",inputs);
|
||||
|
||||
for (int i = 0 ; i < inputs ; i++) {
|
||||
printf("\nINPUT #%i: %i satoshis\n",i, psbt->inputs[i].witness_utxo->satoshi);
|
||||
|
||||
char *script_hex;
|
||||
wally_hex_from_bytes(psbt->inputs[i].witness_utxo->script,psbt->inputs[i].witness_utxo->script_len,&script_hex);
|
||||
printf("scriptPubKey: %s\n",script_hex);
|
||||
wally_free_string(script_hex);
|
||||
|
||||
}
|
||||
```
|
||||
Este patrón de programación se utilizará en muchas partes del PSBT. Se observa el tamaño de la matriz de entradas, luego se pasa a través de él, recuperando lo que desea ver (en este caso, satoshis y scripts).
|
||||
|
||||
Aquí hay un ejemplo similar para las salidas:
|
||||
```c
|
||||
int outputs = psbt->num_outputs;
|
||||
printf("\nTOTAL OUTPUTS: %i\n",outputs);### Pruebe su lector PSBT
|
||||
|
||||
for (int i = 0 ; i < outputs ; i++) {
|
||||
|
||||
char *pubkey_hex;
|
||||
wally_hex_from_bytes(psbt->tx->outputs[i].script,psbt->tx->outputs[i].script_len,&pubkey_hex);
|
||||
printf("\nINPUT #%i\n",i);
|
||||
printf("scriptPubKey: %s\n",pubkey_hex);
|
||||
wally_free_string(pubkey_hex);
|
||||
}
|
||||
```
|
||||
Obviamente, hay mucho más que podría ver en los PSBT. De hecho, observar es el punto principal de un PSBT: puede verificar entradas y salidas desde un ordenador sin conexión.
|
||||
|
||||
> :warning: **ADVERTENCIA:** Estas funciones de lectura son muy rudimentarias y no funcionan correctamente para situaciones extremadamente normales como una entrada o salida que todavía está vacía o que incluye un `non_witness_utxo`. Esto dará un error segfault si no se entrega un PSBT exactamente esperado. Un lector real tendría que ser considerablemente más robusto, para cubrir todas las situaciones posibles, pero eso queda como un ejercicio para el lector.
|
||||
|
||||
### Pruebe su lector PSBT
|
||||
|
||||
De nuevo, el código para este lector PSBT (extremadamente rudimentario y específico) está en el [src directory](../src/17_4_examinepsbt.c).
|
||||
|
||||
Puede compilarlo como siempre:
|
||||
```
|
||||
$ cc examinepsbt.c -lwallycore -o examinepsbt
|
||||
```
|
||||
El siguiente PSBT de [§7.3](07_3_Integrando_con_Hardware_Wallets.md) se puede utilizar para pruebas, ya que coincide con los criterios muy estrechos requeridos por esta implementación limitada:
|
||||
|
||||
```
|
||||
psbt=cHNidP8BAJoCAAAAAri6BLjKQZGO9Y1iVIYbxlxBJ2kqsTPWnxGaH4HrSjxbAAAAAAD+////leV0hwJ0fO40RmhuFVIYtO16ktic2J4vJFLAsT5TM8cBAAAAAP7///8CYOMWAAAAAAAWABTHctb5VULhHvEejvx8emmDCtOKBU+gBwAAAAAAFgAU9Ojd5ds3CJi1fIRWbj92CYhQgX0AAAAAAAEBH0BCDwAAAAAAFgAUABk8i/Je8Fb41FcaHD9lEj5f54giBgMBaNlILisC1wJ/tKie3FStqhrfcJM09kfQobBTOCiuxRiaHVILVAAAgAEAAIAAAACAAAAAADkCAAAAAQEfQEIPAAAAAAAWABQtTxOfqohTBNFWFqFm0tUVdK9KXSIGAqATz5xLX1aJ2SUwNqPkd8+YaJYm94FMlPCScm8Rt0GrGJodUgtUAACAAQAAgAAAAIAAAAAAAAAAAAAAIgID2UK1nupSfXC81nmB65XZ+pYlJp/W6wNk5FLt5ZCSx6kYmh1SC1QAAIABAACAAAAAgAEAAAABAAAAAA==
|
||||
```
|
||||
|
||||
Ejecute `examinepsbt` con ese PSBT, y debería ver los scripts en las entradas y salidas:
|
||||
```
|
||||
$ ./examinepsbt $psbt
|
||||
TOTAL INPUTS: 2
|
||||
|
||||
INPUT #0: 1000000 satoshis
|
||||
scriptPubKey: 001400193c8bf25ef056f8d4571a1c3f65123e5fe788
|
||||
|
||||
INPUT #1: 1000000 satoshis
|
||||
scriptPubKey: 00142d4f139faa885304d15616a166d2d51574af4a5d
|
||||
|
||||
TOTAL OUTPUTS: 2
|
||||
|
||||
INPUT #0
|
||||
scriptPubKey: 0014c772d6f95542e11ef11e8efc7c7a69830ad38a05
|
||||
|
||||
INPUT #1
|
||||
scriptPubKey: 0014f4e8dde5db370898b57c84566e3f76098850817d
|
||||
```
|
||||
Y por supuesto, puede comprobar esto con el comando `decodepsbt` RPC para `bitcoin-cli`:
|
||||
```
|
||||
$ bitcoin-cli decodepsbt $psbt
|
||||
{
|
||||
"tx": {
|
||||
"txid": "45f996d4ff8c9e9ab162f611c5b6ad752479ede9780f9903bdc80cd96619676d",
|
||||
"hash": "45f996d4ff8c9e9ab162f611c5b6ad752479ede9780f9903bdc80cd96619676d",
|
||||
"version": 2,
|
||||
"size": 154,
|
||||
"vsize": 154,
|
||||
"weight": 616,
|
||||
"locktime": 0,
|
||||
"vin": [
|
||||
{
|
||||
"txid": "5b3c4aeb811f9a119fd633b12a6927415cc61b8654628df58e9141cab804bab8",
|
||||
"vout": 0,
|
||||
"scriptSig": {
|
||||
"asm": "",
|
||||
"hex": ""
|
||||
},
|
||||
"sequence": 4294967294
|
||||
},
|
||||
{
|
||||
"txid": "c733533eb1c052242f9ed89cd8927aedb41852156e684634ee7c74028774e595",
|
||||
"vout": 1,
|
||||
"scriptSig": {
|
||||
"asm": "",
|
||||
"hex": ""
|
||||
},
|
||||
"sequence": 4294967294
|
||||
}
|
||||
],
|
||||
"vout": [
|
||||
{
|
||||
"value": 0.01500000,
|
||||
"n": 0,
|
||||
"scriptPubKey": {
|
||||
"asm": "0 c772d6f95542e11ef11e8efc7c7a69830ad38a05",
|
||||
"hex": "0014c772d6f95542e11ef11e8efc7c7a69830ad38a05",
|
||||
"reqSigs": 1,
|
||||
"type": "witness_v0_keyhash",
|
||||
"addresses": [
|
||||
"tb1qcaedd724gts3aug73m78c7nfsv9d8zs9q6h2kd"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"value": 0.00499791,
|
||||
"n": 1,
|
||||
"scriptPubKey": {
|
||||
"asm": "0 f4e8dde5db370898b57c84566e3f76098850817d",
|
||||
"hex": "0014f4e8dde5db370898b57c84566e3f76098850817d",
|
||||
"reqSigs": 1,
|
||||
"type": "witness_v0_keyhash",
|
||||
"addresses": [
|
||||
"tb1q7n5dmewmxuyf3dtus3txu0mkpxy9pqtacuprak"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"unknown": {
|
||||
},
|
||||
"inputs": [
|
||||
{
|
||||
"witness_utxo": {
|
||||
"amount": 0.01000000,
|
||||
"scriptPubKey": {
|
||||
"asm": "0 00193c8bf25ef056f8d4571a1c3f65123e5fe788",
|
||||
"hex": "001400193c8bf25ef056f8d4571a1c3f65123e5fe788",
|
||||
"type": "witness_v0_keyhash",
|
||||
"address": "tb1qqqvnezljtmc9d7x52udpc0m9zgl9leugd2ur7y"
|
||||
}
|
||||
},
|
||||
"bip32_derivs": [
|
||||
{
|
||||
"pubkey": "030168d9482e2b02d7027fb4a89edc54adaa1adf709334f647d0a1b0533828aec5",
|
||||
"master_fingerprint": "9a1d520b",
|
||||
"path": "m/84'/1'/0'/0/569"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"witness_utxo": {
|
||||
"amount": 0.01000000,
|
||||
"scriptPubKey": {
|
||||
"asm": "0 2d4f139faa885304d15616a166d2d51574af4a5d",
|
||||
"hex": "00142d4f139faa885304d15616a166d2d51574af4a5d",
|
||||
"type": "witness_v0_keyhash",
|
||||
"address": "tb1q948388a23pfsf52kz6skd5k4z4627jja2evztr"
|
||||
}
|
||||
},
|
||||
"bip32_derivs": [
|
||||
{
|
||||
"pubkey": "02a013cf9c4b5f5689d9253036a3e477cf98689626f7814c94f092726f11b741ab",
|
||||
"master_fingerprint": "9a1d520b",
|
||||
"path": "m/84'/1'/0'/0/0"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
},
|
||||
{
|
||||
"bip32_derivs": [
|
||||
{
|
||||
"pubkey": "03d942b59eea527d70bcd67981eb95d9fa9625269fd6eb0364e452ede59092c7a9",
|
||||
"master_fingerprint": "9a1d520b",
|
||||
"path": "m/84'/1'/0'/1/1"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"fee": 0.00000209
|
||||
}
|
||||
```
|
||||
Puede ver la entrada en satoshis y el `scriptPubKey` claramente listados en las `inputs` y el nuevo `scriptPubKey`s en el `vout` de la `tx`.
|
||||
|
||||
¡Así que todo está ahí para unirlo!
|
||||
|
||||
## Crear un PSBT
|
||||
|
||||
Como se señaló al principio de esta sección, todas las funciones necesarias para crear y procesar las PSBT están disponibles en Libwally. En realidad, correr a través del proceso de hacerlo es lo suficientemente complejo como para que esté más allá del alcance de esta sección, pero aquí hay una rápida ejecución de las funciones requeridas. Tenga en cuenta que los [documentos](https://wally.readthedocs.io/en/latest/psbt/) están desactualizados para PSBTs, por lo que deberá consultar `/usr/include/wally_psbt.h` para información completa.
|
||||
Como se discute en [§7.1](07_1_Creando_una_Transaccion_Bitcoin_Parcialmente_Firmada.md) hay varios roles involucrados en la creación de PSBTs
|
||||
|
||||
### Tomar el rol de creador
|
||||
|
||||
El rol de creador se encarga de crear un PSBT con al menos una entrada.
|
||||
|
||||
Un PSBT se crea con un uso simple de `wally_psbt_init_alloc`, indicándole cuántas entradas y salidas añadirá finalmente:
|
||||
```c
|
||||
struct wally_psbt *psbt;
|
||||
lw_response = wally_psbt_init_alloc(0,1,1,0,&psbt);
|
||||
```
|
||||
Pero lo que usted tiene todavía no es un PSBT legal, debido a la falta de insumos. Puede crearlos creando una transacción y estableciéndola como la transacción global en el PSBT, que actualiza todas las entradas y salidas:
|
||||
```c
|
||||
struct wally_tx *gtx;
|
||||
lw_response = wally_tx_init_alloc(0,0,1,1,>x);
|
||||
lw_response = wally_psbt_set_global_tx(psbt,gtx);
|
||||
```
|
||||
## Pruebe su creación de PSBT
|
||||
|
||||
En este punto, debería tener un PSBT vacío, pero funcional, que puede ver compilando y ejecutando [el programa](../src/17_4_createemptypsbt.c).
|
||||
```
|
||||
$ cc createemptypsbt.c -lwallycore -o createemptypsbt
|
||||
$ ./createemptypsbt
|
||||
cHNidP8BAAoAAAAAAAAAAAAAAA==
|
||||
```
|
||||
Incluso usted puede usar `bitcoin-cli` para probar el resultado:
|
||||
```
|
||||
$ psbt=$(./createpsbt)
|
||||
$ bitcoin-cli decodepsbt $psbt
|
||||
{
|
||||
"tx": {
|
||||
"txid": "f702453dd03b0f055e5437d76128141803984fb10acb85fc3b2184fae2f3fa78",
|
||||
"hash": "f702453dd03b0f055e5437d76128141803984fb10acb85fc3b2184fae2f3fa78",
|
||||
"version": 0,
|
||||
"size": 10,
|
||||
"vsize": 10,
|
||||
"weight": 40,
|
||||
"locktime": 0,
|
||||
"vin": [
|
||||
],
|
||||
"vout": [
|
||||
]
|
||||
},
|
||||
"unknown": {
|
||||
},
|
||||
"inputs": [
|
||||
],
|
||||
"outputs": [
|
||||
],
|
||||
"fee": 0.00000000
|
||||
}
|
||||
```
|
||||
|
||||
## Asumir el resto de los roles
|
||||
|
||||
Al igual que con la lectura de PSBT, estamos introduciendo el concepto de creación de PSBT, y dejando el resto como un ejercicio para el lector.
|
||||
|
||||
A continuación se presenta una lista aproximada de funciones para cada función; se necesitarán más funciones para crear algunos de los elementos que se añaden a las PSBT.
|
||||
|
||||
**Creador:**
|
||||
|
||||
* wally_psbt_init_alloc
|
||||
* wally_psbt_set_global_tx
|
||||
|
||||
**Actualizador:**
|
||||
* wally_psbt_input_set_non_witness_utxo
|
||||
* wally_psbt_input_set_witness_utxo
|
||||
* wally_psbt_input_set_redeem_script
|
||||
* wally_psbt_input_set_witness_script
|
||||
* wally_psbt_input_set_keypaths
|
||||
* wally_psbt_input_set_unknowns
|
||||
* wally_psbt_output_set_redeem_script
|
||||
* wally_psbt_output_set_witness_script
|
||||
* wally_psbt_output_set_keypaths
|
||||
* wally_psbt_output_set_unknowns
|
||||
|
||||
**Firmante:**
|
||||
* wally_psbt_input_set_partial_sigs
|
||||
* wally_psbt_input_set_sighash_type
|
||||
* wally_psbt_sign
|
||||
|
||||
**Combinador:**
|
||||
* wally_psbt_combine
|
||||
|
||||
**Finalizador:**
|
||||
* wally_psbt_finalize
|
||||
* wally_psbt_input_set_final_script_sig
|
||||
* wally_psbt_input_set_final_witness## Resumen: Usando PSBTs en Libwally
|
||||
|
||||
**Extractor:**
|
||||
* wally_psbt_extract
|
||||
|
||||
## Resumen: Usando PSBTs en Libwally
|
||||
|
||||
Esta sección podría ser un capítulo completo, ya que trabajar con PSBTs a un nivel bajo es un trabajo muy intenso que requiere una manipulación mucho más intensiva de las entradas y salidas que en [Capítulo 7](07_0_Expandiendo_las_Transacciones_Bitcoin_con_PSBTs.md). En su lugar, esta sección muestra lo básico: cómo extraer información de un PSBT, y cómo empezar a crear uno.
|
||||
> :fire: ***Cuál es el poder de los PSBTs en Libwally?*** Obviamente, ya se puede hacer todo esto en `bitcoin-cli`, y es más simple porque Bitcoin Core maneja una gran cantidad de trabajo pesado. La ventaja de usar Libwally es que se puede ejecutar sin conexión, por lo que podría ser Libwally que está sentado en el otro lado de un dispositivo de hardware que su `bitcoin-cli` se está comunicando con HWI. Este es, de hecho, uno de los puntos principales de las PSBT: poder manipular transacciones parcialmente firmadas sin necesidad de un nodo completo. Libwally lo hace posible.
|
||||
|
||||
## ¿Qué es lo siguiente?
|
||||
|
||||
Más información sobre "Programar Bitcoin con Libwally" en [17.5: Usar scripts en Libwally](17_5_Usando_Scripts_en_Libwally.md).
|
177
es/17_5_Usando_Scripts_en_Libwally.md
Normal file
177
es/17_5_Usando_Scripts_en_Libwally.md
Normal file
@ -0,0 +1,177 @@
|
||||
# 17.5: Usando scripts en Libwally
|
||||
|
||||
> :information_source: **NOTA:** Esta sección se ha añadido recientemente al curso y es un borrador temprano que todavía puede estar pendiente de revisión. Lectura con advertencias.
|
||||
|
||||
En la Parte 3, al introducir Scripts, dijimos que era probable que creara transacciones usando scripts con una API y lo marcara como un tema para el futuro. Bueno, el futuro ha llegado.
|
||||
|
||||
## Crear el guión
|
||||
|
||||
Crear el script es la cosa _más fácil_ de hacer en Libwally. Tomemos el siguiente ejemplo, un simple [guión de rompecabezas](13_1_Escribiendo_Puzzle_Scripts.md) que hemos devuelto de vez en cuando:
|
||||
|
||||
```
|
||||
OP_ADD 99 OP_EQUAL
|
||||
```
|
||||
Usando `btcc`, podemos serializar eso.
|
||||
```
|
||||
$ btcc OP_ADD 99 OP_EQUAL
|
||||
warning: ambiguous input 99 is interpreted as a numeric value; use 0x99 to force into hexadecimal interpretation
|
||||
93016387
|
||||
```
|
||||
Anteriormente construimos el script P2SH estándar a mano, pero Libwally puede hacerlo por usted.
|
||||
|
||||
En primer lugar, Libwally tiene que convertir el hex en bytes, ya que los bytes son la mayoría de lo que funciona con:
|
||||
```
|
||||
int script_length = strlen(script)/2;
|
||||
unsigned char bscript[script_length];
|
||||
|
||||
lw_response = wally_hex_to_bytes(script,bscript,script_length,&written);
|
||||
```
|
||||
Luego, ejecuta `wally_scriptpubkey_p2sh_from_bytes` con sus bytes, diciéndole a Libwally que también `HASH160` por usted:
|
||||
```
|
||||
unsigned char p2sh[WALLY_SCRIPTPUBKEY_P2SH_LEN];
|
||||
|
||||
lw_response = wally_scriptpubkey_p2sh_from_bytes(bscript,sizeof(bscript),WALLY_SCRIPT_HASH160,p2sh,WALLY_SCRIPTPUBKEY_P2SH_LEN,&written);
|
||||
```
|
||||
Si usted mirara los resultados de `p2sh`, vería que fue:
|
||||
```
|
||||
a9143f58b4f7b14847a9083694b9b3b52a4cea2569ed87
|
||||
```
|
||||
Lo que [puede recordar](10_2_Construyendo_la_Estructura_de_P2SH.md) se divide en:
|
||||
```
|
||||
a9 / 14 / 3f58b4f7b14847a9083694b9b3b52a4cea2569ed / 87
|
||||
```
|
||||
Ese es nuestro viejo amigo `OP_HASH160 3f58b4f7b14847a9083694b9b3b52a4cea2569ed OP_EQUAL`.
|
||||
|
||||
Básicamente, Libwally tomó su script de canje serializado, lo hasheó para usted con SHA-256 y RIPEMD-160, y aplicó el framing estándar para convertirlo en un P2SH adecuado; Hizo un trabajo similar en [§10.2](10_2_Construyendo_la_Estructura_de_P2SH.md), pero con un exceso de comandos de shell.
|
||||
|
||||
De hecho, puede volver a comprobar su trabajo utilizando los mismos comandos de §10.2:
|
||||
```
|
||||
$ redeemScript="93016387"
|
||||
$ echo -n $redeemScript | xxd -r -p | openssl dgst -sha256 -binary | openssl dgst -rmd160
|
||||
(stdin)= 3f58b4f7b14847a9083694b9b3b52a4cea2569ed
|
||||
```
|
||||
## Crear una transacción
|
||||
|
||||
Con el fin de hacer uso de ese `pubScriptKey` que acaba de crear, es necesario crear una transacción e incrustar el `pubScriptKey` dentro (y este es el gran cambio de `bitcoin-cli`: en realidad se puede crear a mano una transacción con un script P2SH).
|
||||
|
||||
El proceso de crear una transacción en Libwally es muy intenso, al igual que el proceso para crear un PSBT, y por lo que vamos a esbozarlo, tomando un atajo importante, y luego dejar un método sin atajos para la investigación futura.
|
||||
|
||||
Crear una transacción en sí es bastante fácil: sólo tiene que decir `wally_tx_init_alloc` su número de versión, su tiempo de bloqueo, y el número de entradas y salidas:
|
||||
```
|
||||
struct wally_tx *tx;
|
||||
lw_response = wally_tx_init_alloc(2,0,1,1,&tx);
|
||||
```
|
||||
¡Llenar esas entradas y salidas es donde las cosas se ponen complicadas!
|
||||
|
||||
### Crear una salida de transacción
|
||||
|
||||
Para crear una salida, le dice a `wally_tx_output_init_alloc` cuántos satoshis está gastando y le das el script de bloqueo:
|
||||
```
|
||||
struct wally_tx_output *tx_output;
|
||||
lw_response = wally_tx_output_init_alloc(95000,p2sh,sizeof(p2sh),&tx_output);
|
||||
```
|
||||
Esa parte en realidad no era difícil en absoluto y que le permitió a la larga incrustar un P2SH en un `vout`.
|
||||
|
||||
Un comando más lo añade a su transacción:
|
||||
```
|
||||
lw_response = wally_tx_add_output(tx,tx_output);
|
||||
```
|
||||
### Crear una entrada de transacción
|
||||
|
||||
Crear la entrada es mucho más difícil porque usted tiene que acumular información en las rutinas de creación, no todas las cuales son intuitivamente accesibles cuando usa Libwally. Así que, en lugar de ir tan profundo en la maleza, aquí es donde tomamos nuestro atajo. Escribimos nuestro código para que pase el código hexadecimal de una transacción que ya ha sido creada, y luego simplemente reutilizamos la entrada.
|
||||
|
||||
La conversión del código hexadecimal se realiza con `wally_tx_from_hex`:
|
||||
```
|
||||
struct wally_tx *utxo;
|
||||
lw_response = wally_tx_from_hex(utxo_hex,0,&utxo);
|
||||
```
|
||||
A continuación, puede tomar prestadas las entradas de su hexcode para crear una entrada con Libwally:
|
||||
```
|
||||
struct wally_tx_input *tx_input;
|
||||
lw_response = wally_tx_input_init_alloc(utxo->inputs[0].txhash,sizeof(utxo->inputs[0].txhash),utxo->inputs[0].index,0,utxo->inputs[0].script,utxo->inputs[0].script_len,utxo->inputs[0].witness,&tx_input);
|
||||
assert(lw_response == WALLY_OK);
|
||||
```
|
||||
Como es de esperar, a continuación, agregue esa entrada a su transacción:
|
||||
```
|
||||
lw_response = wally_tx_add_input(tx,tx_input);
|
||||
```
|
||||
> **NOTA** Obviamente, querrá poder crear sus propias entradas si está usando Libwally para aplicaciones reales, pero esto es un primer paso. Y en realidad puede ser útil para integrar con `bitcoin-cli`, como veremos en [§17.7](17_7_Integrando_Libwally_y_Bitcoin-CLI.md).
|
||||
|
||||
### Imprimir una transacción
|
||||
|
||||
Teóricamente podría firmar y enviar esta transacción desde su programa C construido en Libwally, pero siguiendo con la idea de que solo estamos usando un simple programa C para sustituir a un P2SH, vamos a imprimir el nuevo hexadecimal. Esto se hace con la ayuda de `wally_tx_to_hex`:
|
||||
```
|
||||
char *tx_hex;
|
||||
lw_response = wally_tx_to_hex(tx,0, &tx_hex);
|
||||
|
||||
printf("%s\n",tx_hex);
|
||||
```
|
||||
Vamos a mostrar cómo hacer uso de eso en §17.7.
|
||||
|
||||
## Pruebe su script de reemplazo
|
||||
|
||||
Puede tomar el código de prueba del [directorio src](https://github.com/BlockchainCommons/Learning-Bitcoin-from-the-Command-Line/tree/master/src/17_5_replacewithscript.c) y compilarlo:
|
||||
```
|
||||
$ cc replacewithscript.c -lwallycore -o replacewithscript
|
||||
```
|
||||
Después, preparar una transacción hexagonal y un script hexadecimal serializado:
|
||||
```
|
||||
hex=020000000001019527cebb072524a7961b1ba1e58fc18dd7c6fc58cd6c1c45d7e1d8fc690b006e0000000017160014cc6e8522f0287b87b7d0a83629049c2f2b0e972dfeffffff026f8460000000000017a914ba421212a629a840492acb2324b497ab95da7d1e87306f0100000000001976a914a2a68c5f9b8e25fdd1213c38d952ab2be2e271be88ac02463043021f757054fa61cfb75b64b17230b041b6d73f25ff9c018457cf95c9490d173fb4022075970f786f24502290e8a5ed0f0a85a9a6776d3730287935fb23aa817791c01701210293fef93f52e6ce8be581db62229baf116714fcb24419042ffccc762acc958294e6921b00
|
||||
|
||||
script=93016387
|
||||
```
|
||||
A continuación, puede ejecutar el programa de reemplazo:
|
||||
```
|
||||
$ ./replacewithscript $hex $script
|
||||
02000000019527cebb072524a7961b1ba1e58fc18dd7c6fc58cd6c1c45d7e1d8fc690b006e0000000017160014cc6e8522f0287b87b7d0a83629049c2f2b0e972d0000000001187301000000000017a9143f58b4f7b14847a9083694b9b3b52a4cea2569ed8700000000
|
||||
```
|
||||
A continuación, puede ver los resultados con `bitcoin-cli`:
|
||||
```
|
||||
$ bitcoin-cli decoderawtransaction $newhex
|
||||
{
|
||||
"txid": "f4e7dbab45e759a7ac6e2fb0f10720cd29d047efad89fe1b569f5f4ba61fd8e6",
|
||||
"hash": "f4e7dbab45e759a7ac6e2fb0f10720cd29d047efad89fe1b569f5f4ba61fd8e6",
|
||||
"version": 2,
|
||||
"size": 106,
|
||||
"vsize": 106,
|
||||
"weight": 424,
|
||||
"locktime": 0,
|
||||
"vin": [
|
||||
{
|
||||
"txid": "6e000b69fcd8e1d7451c6ccd58fcc6d78dc18fe5a11b1b96a7242507bbce2795",
|
||||
"vout": 0,
|
||||
"scriptSig": {
|
||||
"asm": "0014cc6e8522f0287b87b7d0a83629049c2f2b0e972d",
|
||||
"hex": "160014cc6e8522f0287b87b7d0a83629049c2f2b0e972d"
|
||||
},
|
||||
"sequence": 0
|
||||
}
|
||||
],
|
||||
"vout": [
|
||||
{
|
||||
"value": 0.00095000,
|
||||
"n": 0,
|
||||
"scriptPubKey": {
|
||||
"asm": "OP_HASH160 3f58b4f7b14847a9083694b9b3b52a4cea2569ed OP_EQUAL",
|
||||
"hex": "a9143f58b4f7b14847a9083694b9b3b52a4cea2569ed87",
|
||||
"reqSigs": 1,
|
||||
"type": "scripthash",
|
||||
"addresses": [
|
||||
"2My2ApqGcoNXYceZC4d7fipBu4GodkbefHD"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
El `vin` debe coincidir con la entrada que sustituyó en, pero es el `vout` lo que es emocionante: que ha creado una transacción con un `scripthash`!
|
||||
|
||||
## Resumen: Usando scripts en Libwally
|
||||
|
||||
Crear transacciones en Libwally es otro tema que podría ocupar todo un capítulo, pero lo bueno es que una vez que da este salto, puede introducir un script P2SH `PubKey`, y esa parte por sí sola es bastante fácil. Aunque la metodología detallada en este capítulo requiere que tenga una cadena hexadecimal de la transacción ya en la mano (probablemente creado con `bitcoin-cli`) si profundiza en Libwally, puede hacerlo todo usted mismo.
|
||||
|
||||
> :fire: ***Cuál es el poder de los guiones en Libwally?*** Simplemente, puede hacer algo que no podía hacer antes: crear una transacción bloqueada con un P2SH arbitrario.
|
||||
|
||||
## ¿Qué es lo siguiente?
|
||||
|
||||
Más información sobre "Programar Bitcoin con Libwally" en [§17.6: Usar otras funciones en Libwally](17_6_Usando_Otras_Funciones_en_Libwally.md).
|
124
es/17_6_Usando_Otras_Funciones_en_Libwally.md
Normal file
124
es/17_6_Usando_Otras_Funciones_en_Libwally.md
Normal file
@ -0,0 +1,124 @@
|
||||
# 17.6: Uso de otras funciones en Libwally
|
||||
|
||||
> :information_source: **NOTA:** Esta sección se ha añadido recientemente al curso y es un borrador temprano que todavía puede estar pendiente de revisión. Lectura con advertencias.
|
||||
|
||||
Libwally es una extensa biblioteca que proporciona una considerable cantidad de funcionalidad relacionada con la cartera, gran parte de ella no está disponible a través de `bitcoin-cli`. A continuación se ofrece una visión general de algunas funcionalidades no cubiertas anteriormente en este capítulo.
|
||||
|
||||
## Usar funciones criptográficas
|
||||
|
||||
Se puede acceder directamente a varias funciones criptográficas desde Libwally:
|
||||
|
||||
* `wally_aes` - Usar cifrado o descifrado AES
|
||||
* `wally_aes_cbc` - Usar cifrado o descifrado AES en modo CBC
|
||||
* `wally_hash160` - Usar el hash RIPEMD-160(SHA-256)
|
||||
* `wally_scrypt` - Utilizar la derivación de clave Scrypt
|
||||
* `wally_sha256` - utilizar el hash SHA256
|
||||
* `wally_sha256_midstate` - Utilizar SHA256 para hash sólo el primer trozo de datos
|
||||
* `wally_sha256d` - Realizar un doble hash SHA256
|
||||
* `wally_sha512` - utilizar el hash SHA512
|
||||
|
||||
También hay funciones HMAC para los dos hashes SHA, que se utilizan para generar códigos de autenticación de mensajes basados en los hashes. Se utilizan en [BIP32](https://en.bitcoin.it/wiki/BIP_0032), entre otros lugares.
|
||||
|
||||
* `wally_hmac_sha256`
|
||||
* `wally_hmac_sha512`
|
||||
|
||||
Las funciones adicionales cubren la derivación de clave PBKDF2 y la matemática de curva elíptica.
|
||||
|
||||
## Usar funciones de dirección
|
||||
|
||||
Libwally contiene una serie de funciones que se pueden utilizar para importar, exportar y traducir direcciones de Bitcoin.
|
||||
|
||||
Algunos convierten de ida y vuelta entre direcciones y bytes `scriptPubKey`:
|
||||
|
||||
* `wally_addr_segwit_from_bytes` - Convertir un programa testigo (en bytes) en una dirección Segwit
|
||||
* `wally_addr_segwit_to_bytes` - Convertir una dirección Segwit en un `scriptPubKey` (en bytes)
|
||||
* `wally_address_to_scriptpubkey` - Convertir una dirección heredada en un `scriptPubKey`(en bytes)
|
||||
* `wally_scriptpubkey_to_address` - Convertir un scriptPubKey` (en bytes) en una dirección heredada
|
||||
|
||||
Algunos se refieren al formato de importación de la cartera (WIF):
|
||||
|
||||
* `wally_wif_from_bytes` - Convertir una clave privada (en bytes) en una WIF
|
||||
* `wally_wif_is_uncompressed` - Determina si un WIF está descomprimido
|
||||
* `wally_wif_to_address` - Derivar una dirección P2PKH de un WIF
|
||||
* `wally_wif_to_bytes` - Convertir un WIF a una clave privada (en bytes)
|
||||
* `wally_wif_to_public_key` - Derivar una clave pública (en bytes) de un WIF
|
||||
|
||||
## Usar funciones BIP32
|
||||
|
||||
Hay funciones adicionales de la cartera BIP32 HD, más allá de lo que estaba cubierto en [§17.3: Usar BIP32 en Libwally](17_3_Usando_BIP32_en_Libwally.md).
|
||||
|
||||
* `bip32_key_get_fingerprint` - Generar una huella digital BIP32 para una clave extendida
|
||||
* `bip32_key_serialize` - Transformar una clave extendida en bytes seriados
|
||||
* `bip32_key_strip_private_key` - Convertir una clave privada extendida en una clave pública extendida
|
||||
* `bip32_key_unserialize` - Transformar bytes seriados en una clave extendida
|
||||
|
||||
También hay varios numerosos dependiendo de si desea asignar memoria o tener a Libwally haciendo el `_alloc` por usted.
|
||||
|
||||
## Usar funciones BIP38
|
||||
|
||||
[BIP38](https://github.com/bitcoin/bips/blob/master/bip-0038.mediawiki) permite la creación de clave privada protegida con contraseña. No lo enseñamos porque consideremos peligroso insertar este tipo de factor humano en la gestión clave. Véase [#SmartCustody](https://www.smartcustody.com/index.html).
|
||||
|
||||
Las principales funciones son:
|
||||
* `bip38_from_private_key` - Codificar una clave privada usando BIP38
|
||||
* `bip38_to_private_key` - Decodificar una clave privada usando BIP38
|
||||
|
||||
## Usar funciones BIP39
|
||||
|
||||
Algunas funciones de palabras mnemónicas de BIP39 fueron vistas en detalle en [§17.2: Usando BIP39 en Libwally](17_2_Usando_BIP39_en_Libwally.md):
|
||||
|
||||
* `bip39_get_languages` - Ver una lista de idiomas soportados
|
||||
* `bit39_get_word` - Recuperar una palabra específica de la lista de palabras de un idioma
|
||||
* `bip39_get_wordlist` - Ver una lista de palabras para un idioma
|
||||
|
||||
## Usar funciones PSBT
|
||||
|
||||
Los listados de la mayoría de las funciones de PSBT se pueden encontrar en [17.4: Usando PSBTs en Libwally](17_4_Usando_PSBTs_en_Libwally.md).
|
||||
|
||||
## Usar funciones de script
|
||||
|
||||
[§17.5: Usar scripts en Libwally](17_5_Usando_Scripts_en_Libwally.md) apenas tocó las funciones de Scripts de Libwally.
|
||||
|
||||
Hay otra función que le permite determinar el tipo de script que se encuentra en una transacción:
|
||||
|
||||
* `wally_scriptpubkey_get_type` - Determinar el tipo de script de una transacción.
|
||||
|
||||
Luego hay un montón de funciones que crean `scriptPubKey` a partir de bytes, `scriptSig` a partir de firmas, y Testigos a partir de bytes o firmas.
|
||||
|
||||
* `wally_script_push_from_bytes`
|
||||
* `wally_scriptpubkey_csv_2of2_then_1_from_bytes`
|
||||
* `wally_scriptpubkey_csv_2of3_then_2_from_bytes`
|
||||
* `wally_scriptpubkey_multisig_from_bytes`
|
||||
* `wally_scriptpubkey_op_return_from_bytes`
|
||||
* `wally_scriptpubkey_p2pkh_from_bytes`
|
||||
* `wally_scriptpubkey_p2sh_from_bytes`
|
||||
* `wally_scriptsig_multisig_from_bytes`
|
||||
* `wally_scriptsig_p2pkh_from_der`
|
||||
|
||||
* `wally_scriptsig_p2pkh_from_sig`
|
||||
* `wally_witness_multisig_from_bytes`
|
||||
* `wally_witness_p2wpkh_from_der`
|
||||
* `wally_witness_p2wpkh_from_sig`
|
||||
* `wally_witness_program_from_bytes`
|
||||
|
||||
## Usar funciones de transacción
|
||||
|
||||
También apenas tocamos las funciones que se pueden usar para crear y convertir funciones en [§17.5](17_5_Usando_Scripts_en_Libwally.md).
|
||||
|
||||
Hay numerosas funciones informativas, algunas de las más interesantes de las cuales son:
|
||||
|
||||
* `wally_tx_get_length`
|
||||
* `wally_tx_get_total_output_satoshi`
|
||||
* `wally_tx_get_weight`
|
||||
|
||||
También hay funciones que afectan a `wally_tx`, a `wally_tx_input`, a `wally_tx_output`, o a `wally_tx_witness_stack` y que crean firmas.
|
||||
## Usar funciones de elementos
|
||||
|
||||
Libwally se puede compilar para ser utilizado con los elementos de Blockstream, que incluye acceso a sus funciones de activos.
|
||||
|
||||
## Resumen: Uso de otras funciones en Libwally
|
||||
|
||||
Hay mucho más que usted puede hacer con Libwally, más de lo que puede ser cubierto en este capítulo o incluso enumerado en esta sección. Notablemente, puede realizar funciones criptográficas, codificar claves privadas, construir transacciones completas y usar elementos. Los [documentos Libwally](https://wally.readthedocs.io/en/latest/) son el lugar para ir a por más información, aunque a partir de este escrito son a la vez limitados y anticuados. Los archivos de cabecera de Libwally son una copia de seguridad si los documentos están incompletos o mal.
|
||||
|
||||
## ¿Qué es lo siguiente?
|
||||
|
||||
Termine de aprender sobre "Programar Bitcoin con Libwally" en [§17.7: Integrar Libwally y Bitcoin-CLI](17_7_Integrando_Libwally_y_Bitcoin-CLI.md).
|
329
es/17_7_Integrando_Libwally_y_Bitcoin-CLI.md
Normal file
329
es/17_7_Integrando_Libwally_y_Bitcoin-CLI.md
Normal file
@ -0,0 +1,329 @@
|
||||
# 17.7: Integración de Libwally y Bitcoin-CLI
|
||||
|
||||
> :information_source: **NOTA:** Esta sección se ha añadido recientemente al curso y es un borrador temprano que todavía puede estar pendiente de revisión. Lectura con advertencias.
|
||||
|
||||
Libwally es muy limitada. Se trata de manipular semillas, llaves, direcciones y otros elementos de billeteras, con algunas funciones adicionales relacionadas con las transacciones y PSBTs que podrían ser útiles para servicios que no están conectados a nodos completos en Internet. En última instancia, sin embargo, va a necesitar servicios de un nodo completo para tomar ventaja de Libwally.
|
||||
Esta sección final ofrecerá algunos ejemplos de uso de programas de Libwally para complementar un entorno `bitcoin-cli`. Aunque estos ejemplos implican que estos servicios están todos en la misma máquina, pueden volverse aún más poderosos si el servicio `bitcoin-cli` está directamente conectado a Internet y el servicio Libwally no lo está.
|
||||
|
||||
## Compartir una transacción
|
||||
|
||||
[§17.5: Usar scripts en Libwally](17_5_Usando_Scripts_en_Libwally.md) detalló cómo Libwally podría usarse para reescribir una transacción existente, para hacer algo que `bitcoin-cli` no puede: producir una transacción que contenga un P2SH único. Obviamente, este es un bloque de construcción; si decide profundizar más en Libwally creará transacciones completas por su cuenta. Pero esta metodología abreviada también tiene su propio uso: muestra cómo las transacciones se pueden pasar de ida y vuelta entre `bitcoin-cli` y Libwally, demostrando un primer ejemplo de su uso de una manera complementaria.
|
||||
|
||||
Para demostrar completamente esta metodología, creará una transacción con `bitcoin-cli`, usando este UTXO:
|
||||
```
|
||||
{
|
||||
"txid": "c0a110a7a84399b98052c6545018873b13ee3128fa74f7a697779174a36ea33a",
|
||||
"vout": 1,
|
||||
"address": "mvLyH7Rs45c16FG2dfV7uuTKV6pL92kWxo",
|
||||
"label": "",
|
||||
"scriptPubKey": "76a914a2a68c5f9b8e25fdd1213c38d952ab2be2e271be88ac",
|
||||
"amount": 0.00094000,
|
||||
"confirmations": 17375,
|
||||
"spendable": true,
|
||||
"solvable": true,
|
||||
"desc": "pkh([ce0c7e14/0'/0'/5']0368d0fffa651783524f8b934d24d03b32bf8ff2c0808943a556b3d74b2e5c7d65)#qldtsl65",
|
||||
"safe": true
|
||||
}
|
||||
```
|
||||
Por ahora, usted sabe cómo configurar una transacción con `bitcoin-cli`:
|
||||
|
||||
Aunque puso un destinatario y una cantidad en la salida, es irrelevante porque tendrá que reescribirlas. Un código un poco más elegante podría leer la información `vout` existente antes de reescribir, pero estamos manteniendo las cosas muy cerca de nuestro [código original](https://github.com/BlockchainCommons/Learning-Bitcoin-from-the-Command-Line/tree/master/src/17_5_replacewithscript.c).
|
||||
|
||||
Aquí está el cambio necesario, para que pueda especificar el monto de satoshis para la salida `vout`, sin tener que ponerlo a fuego como en el original:
|
||||
```
|
||||
...
|
||||
int satoshis = atoi(argv[3]);
|
||||
...
|
||||
lw_response = wally_tx_output_init_alloc(satoshis,p2sh,sizeof(p2sh),&tx_output);
|
||||
...
|
||||
```
|
||||
Entonces usted ejecuta las cosas como antes:
|
||||
```
|
||||
$ newtxhex=$(./replacewithscript $rawtxhex $script 9000)
|
||||
```
|
||||
Así era la transacción original:
|
||||
```
|
||||
$ bitcoin-cli decoderawtransaction $rawtxhex
|
||||
{
|
||||
"txid": "438d50edd7abeaf656c5abe856a00a20af5ff08939df8fdb9f8bfbfb96234fcb",
|
||||
"hash": "438d50edd7abeaf656c5abe856a00a20af5ff08939df8fdb9f8bfbfb96234fcb",
|
||||
"version": 2,
|
||||
"size": 82,
|
||||
"vsize": 82,
|
||||
"weight": 328,
|
||||
"locktime": 0,
|
||||
"vin": [
|
||||
{
|
||||
"txid": "c0a110a7a84399b98052c6545018873b13ee3128fa74f7a697779174a36ea33a",
|
||||
"vout": 1,
|
||||
"scriptSig": {
|
||||
"asm": "",
|
||||
"hex": ""
|
||||
},
|
||||
"sequence": 4294967295
|
||||
}
|
||||
],
|
||||
"vout": [
|
||||
{
|
||||
"value": 0.00090000,
|
||||
"n": 0,
|
||||
"scriptPubKey": {
|
||||
"asm": "0 2621b0465d851d6ba4e61a667b7ab13e3740e0f7",
|
||||
"hex": "00142621b0465d851d6ba4e61a667b7ab13e3740e0f7",
|
||||
"reqSigs": 1,
|
||||
"type": "witness_v0_keyhash",
|
||||
"addresses": [
|
||||
"tb1qycsmq3jas5wkhf8xrfn8k7438cm5pc8h9ae2k0"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
Y aquí está la transacción reescrita por Libwally para usar un P2SH:
|
||||
```
|
||||
standup@btctest:~/c$ bitcoin-cli decoderawtransaction $newtxhex
|
||||
{
|
||||
"txid": "badb57622ab5fe029fc1a71ace9f7b76c695f933bceb0d38a155c2e5c984f4e9",
|
||||
"hash": "badb57622ab5fe029fc1a71ace9f7b76c695f933bceb0d38a155c2e5c984f4e9",
|
||||
"version": 2,
|
||||
"size": 83,
|
||||
"vsize": 83,
|
||||
"weight": 332,
|
||||
"locktime": 0,
|
||||
"vin": [
|
||||
{
|
||||
"txid": "c0a110a7a84399b98052c6545018873b13ee3128fa74f7a697779174a36ea33a",
|
||||
"vout": 1,
|
||||
"scriptSig": {
|
||||
"asm": "",
|
||||
"hex": ""
|
||||
},
|
||||
"sequence": 0
|
||||
}
|
||||
],
|
||||
"vout": [
|
||||
{
|
||||
"value": 0.00090000,
|
||||
"n": 0,
|
||||
"scriptPubKey": {
|
||||
"asm": "OP_HASH160 3f58b4f7b14847a9083694b9b3b52a4cea2569ed OP_EQUAL",
|
||||
"hex": "a9143f58b4f7b14847a9083694b9b3b52a4cea2569ed87",
|
||||
"reqSigs": 1,
|
||||
"type": "scripthash",
|
||||
"addresses": [
|
||||
"2My2ApqGcoNXYceZC4d7fipBu4GodkbefHD"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
Después puede firmarlo como de costumbre con `bitcoin-cli`:
|
||||
```
|
||||
$ signedtx=$(bitcoin-cli signrawtransactionwithwallet $newtxhex | jq -r '.hex')
|
||||
```
|
||||
Y como puede ver, el resultado es una transacción legítima lista para salir a la red Bitcoin:
|
||||
```
|
||||
$ bitcoin-cli decoderawtransaction $signedtx
|
||||
{
|
||||
"txid": "3061ca8c01d029c0086adbf8b7d4280280c8aee151500bab7c4f783bbc8e75e6",
|
||||
"hash": "3061ca8c01d029c0086adbf8b7d4280280c8aee151500bab7c4f783bbc8e75e6",
|
||||
"version": 2,
|
||||
"size": 189,
|
||||
"vsize": 189,
|
||||
"weight": 756,
|
||||
"locktime": 0,
|
||||
"vin": [
|
||||
{
|
||||
"txid": "c0a110a7a84399b98052c6545018873b13ee3128fa74f7a697779174a36ea33a",
|
||||
"vout": 1,
|
||||
"scriptSig": {
|
||||
"asm": "3044022026c81b6ff4a15135d10c7f4b1ae6e44ac4fdb25c4a3c03161b17b8ab8d04850502200b448d070f418de1ca07e76943d23d447bc95c7c5e0322bcc153cadb5d9befe0[ALL] 0368d0fffa651783524f8b934d24d03b32bf8ff2c0808943a556b3d74b2e5c7d65",
|
||||
"hex": "473044022026c81b6ff4a15135d10c7f4b1ae6e44ac4fdb25c4a3c03161b17b8ab8d04850502200b448d070f418de1ca07e76943d23d447bc95c7c5e0322bcc153cadb5d9befe001210368d0fffa651783524f8b934d24d03b32bf8ff2c0808943a556b3d74b2e5c7d65"
|
||||
},
|
||||
"sequence": 0
|
||||
}
|
||||
],
|
||||
"vout": [
|
||||
{
|
||||
"value": 0.00090000,
|
||||
|
||||
"scriptPubKey": {
|
||||
"asm": "OP_HASH160 3f58b4f7b14847a9083694b9b3b52a4cea2569ed OP_EQUAL",
|
||||
"hex": "a9143f58b4f7b14847a9083694b9b3b52a4cea2569ed87",
|
||||
"reqSigs": 1,
|
||||
"type": "scripthash",
|
||||
"addresses": [
|
||||
"2My2ApqGcoNXYceZC4d7fipBu4GodkbefHD"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
¡Voila! Ese es el poder de Libwally con `bitcoin-cli`.
|
||||
|
||||
Obviamente, también puede pasar un PSBT usando las funciones descritas en [§17.4](17_4_Usando_PSBTs_en_Libwally.md) y esa es una metodología más actualizada para el uso actual de Bitcoin, pero en cualquier caso, el concepto de pasar transacciones desde `bitcoin-cli` a código Libwally y viceversa debe ser similar.
|
||||
|
||||
## Importar y exportar semillas BIP39
|
||||
|
||||
Desafortunadamente, no todas las interacciones entre Libwally y `bitcoin-cli` van tan suavemente. Por ejemplo, sería bueno si pudiera exportar una semilla HD desde `bitcoin-cli`, para generar la frase mnemónica con Libwally, o generar una semilla a partir de una frase mneonímica usando Libwally, y luego importarla a `bitcoin-cli`. Desafortunadamente, ninguno de estos casos es posible en este momento. Una frase mneomínica se traduce en una semilla usando HMAC-SHA512, lo que significa que el resultado es de 512 bits. Sin embargo, `bitcoin-cli` exporta semillas HD (usando `dumpwallet`) e importa semillas HD (usando `sethdseed`) con una longitud de 256 bits. Hasta que eso cambie, nunca se encontrarán.
|
||||
|
||||
> :book: ***Cuál es la diferencia entre entropía y semilla?*** Libwally dice que crea sus frases mnemónicas a partir de la entropía. Eso es esencialmente lo mismo que una semilla: ambos son grandes números aleatorios. Entonces, si `bitcoin-cli` fuera compatible con semillas de frases mnemónicas de 512 bits, podría usar una para generar las frases mneonímicas y obtener los resultados que esperaba.
|
||||
|
||||
> :book: ***Cuál es la diferencia entre entropía y entropía cruda?*** No toda entropía es la misma. Cuando usted ingresa entropía en un comando que crea una semilla mnemónica, tiene una longitud específica y bien comprendida. Cambiar la entropía cruda en entropía requiere masajear la entropía cruda hasta que sea la longitud y el formato correctos, y en ese punto podría reutilizar esa entropía (no cruda) para recrear siempre la misma mnemónica (por lo que la entropía es efectivamente lo mismo que una semilla en ese punto, pero la entropía cruda no lo es).
|
||||
|
||||
## Importar claves privadas
|
||||
|
||||
Afortunadamente puede hacer lo mismo importando una clave privada generada en Libwally. De un vistazo a [genhd-for-import.c](https://github.com/BlockchainCommons/Learning-Bitcoin-from-the-Command-Line/tree/master/src/17_7_genhd_for_import.c), que es una versión simplificada del programa `genhd` de [§17.3](17_3_Usando_BIP32_en_Libwally.md) que también utiliza la biblioteca `jansson` de [§16.1](16_1_Accediendo_a_Bitcoind_en_C_con_las_Bibliotecas_RPC.md) para la salida regularizada.
|
||||
|
||||
El código actualizado también contiene un cambio de nota: solicita una huella dactilar de Libwally para que pueda crear correctamente una ruta de derivación:
|
||||
|
||||
```
|
||||
char account_fingerprint[BIP32_KEY_FINGERPRINT_LEN];
|
||||
lw_response = bip32_key_get_fingerprint(key_account,account_fingerprint,BIP32_KEY_FINGERPRINT_LEN);
|
||||
|
||||
char *fp_hex;
|
||||
lw_response = wally_hex_from_bytes(account_fingerprint,BIP32_KEY_FINGERPRINT_LEN,&fp_hex);
|
||||
```
|
||||
> :warning: **ADVERTENCIA:** Recuerde que la huella dactilar en las rutas de derivación es arbitraria. Dado que Libwally proporciona uno lo estamos usando, pero si no tuviera uno, podría añadir un hexcode arbitrario de 4 bytes como huella digital a su ruta de derivación.
|
||||
|
||||
Asegúrese de compilar el nuevo código con la biblioteca `jansson`, después de instalarlo (si es necesario) por [§16.1](16_1_Accediendo_a_Bitcoind_en_C_con_las_Bibliotecas_RPC.md).
|
||||
|
||||
```
|
||||
$ cc genhd-for-import.c -lwallycore -lsodium -ljansson -o genhd-for-import
|
||||
```
|
||||
|
||||
Cuando ejecute el nuevo programa, le dará una buena lista de salida de todo:
|
||||
|
||||
```
|
||||
$ ./genhd-for-import
|
||||
{
|
||||
"mnemonic": "physical renew say quit enjoy eager topic remind riot concert refuse chair",
|
||||
"account-xprv": "tprv8yxn8iFNgsLktEPkWKQpMqb7bcx5ViFQEbJMtqrGi8LEgvy8es6YeJvyJKrbYEPKMw8JbU3RFhNRQ4F2pataAtTNokS1JXBZVg62xfd5HCn",
|
||||
"address": "tb1q9lhru6k0ymwrtr5w98w35n3lz22upml23h753n",
|
||||
"derivation": "[d1280779/84h/1h/0h]"
|
||||
}
|
||||
```
|
||||
Usted tiene el `mnemonic` del que puede recuperarse un `account-xprv` que puede importar, un `derivation` para usar para la importación, y una muestra de `address` que puede utilizar para probar la importación.
|
||||
|
||||
Ahora puede recurrir a las lecciones aprendidas de [§3.5](03_5_Entendiendo_El_Descriptor.md) sobre cómo convertir ese xprv en un descriptor e importarlo.
|
||||
|
||||
En primer lugar, es necesario averiguar la suma de comprobación:
|
||||
|
||||
```
|
||||
$ xprv=tprv8yxn8iFNgsLktEPkWKQpMqb7bcx5ViFQEbJMtqrGi8LEgvy8es6YeJvyJKrbYEPKMw8JbU3RFhNRQ4F2pataAtTNokS1JXBZVg62xfd5HCn
|
||||
$ dp=[d1280779/84h/1h/0h]
|
||||
$ bitcoin-cli getdescriptorinfo "wpkh($dp$xprv/0/*)"
|
||||
{
|
||||
"descriptor": "wpkh([d1280779/84'/1'/0']tpubDWepH8HcqF2RmhRYPy5QmFFEAeU1f3SJotu9BMta8Q8dXRDuHFv8poYqUUtEiWftBjtKn1aNhi9Qg2P4NdzF66dShYvB92z78WJbYeHTLTz/0/*)#f8rmqc0z",
|
||||
"checksum": "46c00dk5",
|
||||
"isrange": true,
|
||||
"issolvable": true,
|
||||
"hasprivatekeys": true
|
||||
}
|
||||
```
|
||||
Aquí hay tres cosas a tener en cuenta:
|
||||
|
||||
1. Usamos `wpkh` como función en nuestra ruta de derivación. Eso es porque queremos generar direcciones Segwit modernas, no direcciones heredadas. Eso coincide con nuestro uso en Libwally de la función `wally_bip32_key_to_addr_segwit`. Lo más importante, sin embargo, es tener las mismas expectativas con Libwally y `bitcoin-cli` (y su descriptor) sobre qué tipo de dirección está generando, para que todo coincida!
|
||||
|
||||
2. Usamos la ruta `/0/*` porque queríamos las direcciones externas para esta cuenta. Si en cambio queríamos las direcciones de cambio, usaríamos `/1/*`.
|
||||
|
||||
3. No vamos a utilizar la línea `descriptor` devuelta, ya que es para una dirección `xpub`. En su lugar aplicaremos `checksum` devuelta a la `xprv` que ya tenemos.
|
||||
|
||||
```
|
||||
$ cs=$(bitcoin-cli getdescriptorinfo "wpkh($dp$xprv/0/*)" | jq -r ' .checksum')
|
||||
```
|
||||
A continuación, conecte eso a `importmulti` para importar esta clave en `bitcoin-cli`:
|
||||
```
|
||||
$ bitcoin-cli importmulti '''[{ "desc": "wpkh('$dp''$xprv'/0/*)#'$cs'", "timestamp": "now", "range": 10, "watchonly": false, "label": "LibwallyImports", "keypool": false, "rescan": false }]'''
|
||||
[
|
||||
{
|
||||
"success": true
|
||||
}
|
||||
]
|
||||
|
||||
```
|
||||
Aquí, usted importó/generó las primeras diez direcciones para la clave privada.
|
||||
|
||||
Examinando la nueva `LibwallyImported` la etiqueta los muestra:
|
||||
```
|
||||
$ bitcoin-cli getaddressesbylabel "LibwallyImports"
|
||||
{
|
||||
"tb1qzeqrrt77xhvazq5g8sc9th0lzjwstknan8gzq7": {
|
||||
"purpose": "receive"
|
||||
},
|
||||
"tb1q9lhru6k0ymwrtr5w98w35n3lz22upml23h753n": {
|
||||
"purpose": "receive"
|
||||
},
|
||||
"tb1q8fsgxt0z9r9hfl5mst5ylxka2yljjxlxlvaf8j": {
|
||||
"purpose": "receive"
|
||||
},
|
||||
"tb1qg6dayhdk4qc6guutxvdweh6pctc9dpguu6awqc": {
|
||||
"purpose": "receive"
|
||||
},
|
||||
"tb1qdphaj0exvemxhgfpyh4p99wn84e2533u7p96l6": {
|
||||
"purpose": "receive"
|
||||
},
|
||||
"tb1qwv9mdqkpx6trtmvgw3l95npq8gk9pgllucvata": {
|
||||
"purpose": "receive"
|
||||
},
|
||||
"tb1qwh92pkrv6sps62udnmez65vfxe9n5ceuya56xz": {
|
||||
"purpose": "receive"
|
||||
},
|
||||
"tb1q4e98ln8xlym64qjzy3k8zyfyt5q60dgcn39d90": {
|
||||
"purpose": "receive"
|
||||
},
|
||||
"tb1qhzje887fyl65j4mulqv9ysmntwn95zpgmgvtqd": {
|
||||
"purpose": "receive"
|
||||
},
|
||||
"tb1q62xf9ec8zcfkh2qy5qnq4qcxrx8l0jm27dd8ru": {
|
||||
"purpose": "receive"
|
||||
},
|
||||
"tb1qlw85usfk446ssxejm9dmxsfn40kzsqce77aq20": {
|
||||
"purpose": "receive"
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
El segundo en su lista de hecho coincide con su muestra (`tb1q9lhru6k0ymwrtr5w98w35n3lz22upml23h753n`). La importación de esta clave privada y la derivación de diez direcciones fue un éxito.
|
||||
|
||||
Si usted mira hacia atrás en [§7.3](07_3_Integrando_con_Hardware_Wallets.md), verá que esta fue la misma metodología que usamos para importar direcciones desde un Hardware Wallet (aunque esta vez también importamos la clave privada como prueba de concepto). La mayor diferencia es que anteriormente la información fue creada por una caja negra (literalmente: era un dispositivo de Ledger), y esta vez usted mismo creó la información usando Libwally, mostrando cómo puede hacer este tipo de trabajo de modo _airgapped_ u otros dispositivos más remotos y luego llevarlo a `bitcoin-cli`.
|
||||
|
||||
# Importar direcciones
|
||||
|
||||
Obviamente, si puede importar claves privadas, también puede importar direcciones lo que generalmente significa importar direcciones de sólo lectura _sin_ las claves privadas.
|
||||
|
||||
Una forma de hacerlo es utilizar la metodología `importmulti` anterior, pero utilizar la dirección xpub suministrada (`wpkh([d1280779/84'/1'/0']tpubDWepH8HcqF2RmhRYPy5QmFFEAeU1f3SJotu9BMta8Q8dXRDuHv8poYqUUtEiWftBjtKn1aNhi9Qg2P4NdzF66dShYvB92z78WJbYeHTLTz/0/*)#f8rmqc0z`) en lugar de la xprv original. Esa es la mejor manera de importar una secuencia entera de direcciones de sólo lectura.
|
||||
|
||||
Alternativamente, puede importar direcciones individuales. Por ejemplo, considere la dirección de ejemplo individual actualmente devuelta por el programa `genhd-for-import` :
|
||||
```
|
||||
$ ./genhd-for-import
|
||||
{
|
||||
"mnemonic": "finish lady crucial walk illegal ride hamster strategy desert file twin nature",
|
||||
"account-xprv": "tprv8xRujYeVN7CwBHxLoTHRdmzwdW7dKUzDfruSo56GqqfRW9QXtnxnaRG8ke7j65uNjxmCVfcagz5uuaMi2vVJ8jpiGZvLwahmNB8F3SHUSyv",
|
||||
"address": "tb1qtvcchgyklp6cyleth85c7pfr4j72z2vyuwuj3d",
|
||||
"derivation": "[6214ecff/84h/1h/0h]"
|
||||
}
|
||||
```
|
||||
Puede importar eso como una dirección de sólo lectura con `importaddress`:
|
||||
```
|
||||
$ bitcoin-cli -named importaddress address=tb1qtvcchgyklp6cyleth85c7pfr4j72z2vyuwuj3d label=LibwallyWO rescan=false
|
||||
$ bitcoin-cli getaddressesbylabel "LibwallyWO"
|
||||
{
|
||||
"tb1qtvcchgyklp6cyleth85c7pfr4j72z2vyuwuj3d": {
|
||||
"purpose": "receive"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
## Resumen: Integración de Libwally y Bitcoin-CLI
|
||||
|
||||
Con un conocimiento fundamental de Libwally, ahora puede complementar todo el trabajo de sus lecciones anteriores. Transferir direcciones, claves, transacciones y PSBTs son sólo algunas de las formas en las que puede hacer uso de estos dos poderosos métodos de programación Bitcoin juntos. También hay mucha más profundidad potencial si quiere profundizar en la extensa biblioteca de funciones de Libwally.
|
||||
|
||||
> :fire: ***Cuál es el poder de integrar Libwally y Bitcoin-CLI?*** Una de las mayores ventajas de Libwally es que tiene muchas funciones que se pueden usar fuera de línea. En comparación, Bitcoin Core es un programa en red. Esto puede ayudarle a aumentar la seguridad al tener `bitcoin-cli` para pasar claves, direcciones, transacciones o PSBTs a una fuente fuera de línea (que estaría ejecutando programas Libwally). Además de eso, Libwally puede hacer cosas que Bitcoin Core actualmente no puede, como generar una semilla a partir de un BIP39 mnemonic (e incluso si actualmente no se puede importar la semilla a Bitcoin Core, usted _puede_ todavía importar la clave maestra para la cuenta, como se muestra aquí).
|
||||
|
||||
## Que sigue?
|
||||
|
||||
Aprenda sobre otro tipo de programación en [18.0: Hablando a Bitcoind con Otros Lenguajes](18_0_Hablando_a_Bitcoind_con_Otros_Lenguajes.md).
|
24
es/18_0_Hablando_a_Bitcoind_con_Otros_Lenguajes.md
Normal file
24
es/18_0_Hablando_a_Bitcoind_con_Otros_Lenguajes.md
Normal file
@ -0,0 +1,24 @@
|
||||
# Capítulo 18: Hablando con Bitcoind con otros lenguajes
|
||||
|
||||
Ahora debería tener una base sólida para trabajar con Bitcoin en C, no solo usando bibliotecas RPC, JSON y ZMQ para interactuar directamente con `bitcoind`, sino también utilizando las bibliotecas Libwally para complementar ese trabajo. Y C es un gran lenguaje para la creación de prototipos y la abstracción pero probablemente no es en lo que usted esta programando. Este capítulo por lo tanto toma un recorrido de torbellino de otros seis lenguajes de programación, demostrando la funcionalidad de Bitcoin más básica en cada uno y permitiéndole ampliar las lecciones de la línea de comandos y C al lenguaje de programación de su elección.
|
||||
Cada una de las secciones contiene aproximadamente la misma información, centrada en: crear una conexión RPC; examinar la cartera; crear una nueva dirección, y crear una transacción. Sin embargo, hay cierta variedad entre los idiomas, mostrando diferentes aspectos de los comandos RPC de Bitcoin en diferentes ejemplos. En particular, algunos lenguajes utilizan la sencilla metodología de `sendtoaddress` mientras que otros utilizan la dura metodología de crear una transacción en bruto desde cero.
|
||||
|
||||
## Objetivos para este capítulo
|
||||
|
||||
Después de trabajar en este capítulo, un desarrollador podrá:
|
||||
|
||||
* Preparar los entornos de desarrollo de Bitcoin para una variedad de lenguajes
|
||||
* Utilizar las funciones de la cartera en una variedad de lenguajes
|
||||
* Usar funciones de transacción en una variedad de lenguajes
|
||||
|
||||
Los objetivos de apoyo incluyen la capacidad de:
|
||||
|
||||
* Entender más sobre Bitcoin RPC a través de interacciones con una variedad de lenguajes
|
||||
|
||||
## Tabla de contenidos
|
||||
* [Sección Uno: Acceso a Bitcoind con Go](18_1_Accediendo_a_Bitcoind_con_Go.md)
|
||||
* [Sección Dos: Acceso a Bitcoind con Java](18_2_Accediendo_a_Bitcoind_con_Java.md)
|
||||
* [Sección Tres: Acceso a Bitcoind con NodeJS](18_3_Accediendo_a_Bitcoind_con_NodeJS.md)
|
||||
* [Sección Cuatro: Acceder a Bitcoind con Python](18_4_Accediendo_a_Bitcoind_con_Python.md)
|
||||
* [Sección Cinco: Acceso a Bitcoind con Rust](18_5_Accediendo_a_Bitcoind_con_Rust.md)
|
||||
* [Sección Seis: Acceso a Bitcoind con Swift](18_6_Accediendo_a_Bitcoind_con_Swift.md)
|
405
es/18_1_Accediendo_a_Bitcoind_con_Go.md
Normal file
405
es/18_1_Accediendo_a_Bitcoind_con_Go.md
Normal file
@ -0,0 +1,405 @@
|
||||
# 18.1: Acceso a Bitcoind con Go
|
||||
|
||||
> :information_source: **NOTA:** Esta sección se ha añadido recientemente al curso y es un borrador temprano que todavía puede estar pendiente de revisión. Lectura con advertencias.
|
||||
|
||||
Esta sección explica cómo interactuar con `bitcoind` usando el lenguaje de programación Go y el [btcd rpcclient](https://github.com/btcsuite/btcd/tree/master/rpcclient). Tenga en cuenta que tiene algunas peculiaridades y algunas limitaciones.
|
||||
|
||||
## Configurar Go
|
||||
|
||||
Para prepararse para el uso de Go en su máquina UNIX, primero instale curl si aún no lo ha hecho:
|
||||
```
|
||||
$ sudo apt install curl
|
||||
```
|
||||
Luego, mire la página [de descargas Go](https://golang.org/dl/), obtenga el enlace para la última descarga y descarguelo usando `curl`. Para una configuración de Debian, querrá usar la versión `linux-amd64`:
|
||||
|
||||
```
|
||||
$ curl -O https://dl.google.com/go/go1.15.1.linux-amd64.tar.gz
|
||||
```
|
||||
|
||||
Una vez finalizada la descarga, compare el hash de la descarga con el hash en la página [de descargas Go](https://golang.org/dl/):
|
||||
```
|
||||
$ sha256sum go1.15.1.linux-amd64.tar.gz
|
||||
70ac0dbf60a8ee9236f337ed0daa7a4c3b98f6186d4497826f68e97c0c0413f6 go1.15.1.linux-amd64.tar.gz
|
||||
```
|
||||
Los hashes deben coincidir. Si es así, extraiga el archivo e instale Go en su sistema:
|
||||
```
|
||||
$ tar xfv go1.15.1.linux-amd64.tar.gz
|
||||
$ sudo chown -R root:root ./go
|
||||
$ sudo mv go /usr/local
|
||||
```
|
||||
Ahora necesita crear una ruta Go para especificar su entorno. Abra el archivo `~/.profile` con un editor de su elección y añada lo siguiente al final de la misma:
|
||||
|
||||
```
|
||||
export GOPATH=$HOME/work
|
||||
export PATH=$PATH:/usr/local/go/bin:$GOPATH/bin
|
||||
```
|
||||
|
||||
Por último, cree el directorio de su espacio de trabajo Go:
|
||||
|
||||
```
|
||||
$ mkdir $HOME/work
|
||||
```
|
||||
### Configurar `btcd` `rpcclient`
|
||||
|
||||
Usara el `rpcclient` que viene con `btcd,` una implementación de Bitcoin escrita en Go. Aunque `rpcclient` fue originalmente diseñado para trabajar con el nodo completo de Bitcoin `btcd` , también funciona con Bitcoin Core. Tiene algunas peculiaridades que veremos.
|
||||
|
||||
Puede utilizar ```go get``` para descargarlo:
|
||||
```
|
||||
$ go get github.com/btcsuite/btcd/rpcclient
|
||||
```
|
||||
Para probar que funciona, vaya al directorio con los ejemplos de Bitcoin Core:
|
||||
```
|
||||
$ cd $GOPATH/src/github.com/btcsuite/btcd/rpcclient/examples/bitcoincorehttp
|
||||
```
|
||||
Modificar el archivo `main.go` e introduzca los detalles asociados con la configuración del núcleo de Bitcoin, que se pueden encontrar en `~/.bitcoin/bitcoin.conf`:
|
||||
|
||||
```
|
||||
Host: "localhost:18332",
|
||||
User: "StandUp",
|
||||
Pass: "6305f1b2dbb3bc5a16cd0f4aac7e1eba",
|
||||
```
|
||||
> **MAINNET VS TESTNET:** El puerto 8332 sería para una configuración de mainnet.
|
||||
|
||||
Ahora puede realizar una prueba:
|
||||
```
|
||||
$ go run main.go
|
||||
```
|
||||
Deberia ver impreso el conteo de bloques:
|
||||
```
|
||||
2020/09/01 11:41:24 Block count: 1830861
|
||||
```
|
||||
### Crear un proyecto `rpcclient`
|
||||
|
||||
Normalmente estará creando proyectos en su directorio `~/work/src/myproject/bitcoin` :
|
||||
|
||||
```
|
||||
$ mkdir -p ~/work/src/myproject/bitcoin
|
||||
$ cd ~/work/src/myproject/bitcoin
|
||||
```
|
||||
Cada proyecto deberá tener los siguientes `imports`:
|
||||
|
||||
```
|
||||
import (
|
||||
"log"
|
||||
"fmt"
|
||||
"github.com/btcsuite/btcd/rpcclient"
|
||||
)
|
||||
```
|
||||
|
||||
Esta declaración `import` le permite importar bibliotecas relevantes. Para cada ejemplo aquí, necesitará importar `"log", "fmt"` y `"github.com/btcsuite/btcd/rpcclient"`. Es posible que necesite importar bibliotecas adicionales para algunos ejemplos.
|
||||
* `log` se utiliza para imprimir mensajes de error. Después de cada llamada al nodo Bitcoin, una declaración `if` comprobará si hay algún error. Si hay errores, `log` se utiliza para imprimirlos.
|
||||
* `fmt` se utiliza para imprimir la salida.
|
||||
* `rpcclient`; es obviamente la biblioteca `rpcclient`
|
||||
*
|
||||
## Construya su conexión
|
||||
|
||||
Cada función `bitcoind` en Go comienza con la creación de la conexión RPC, usando la función `ConnConfig` :
|
||||
|
||||
```
|
||||
connCfg := &rpcclient.ConnConfig{
|
||||
Host: "localhost:18332",
|
||||
User: "StandUp",
|
||||
Pass: "431451790e3eee1913115b9dd2fbf0ac",
|
||||
HTTPPostMode: true,
|
||||
DisableTLS: true,
|
||||
}
|
||||
client, err := rpcclient.New(connCfg, nil)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer client.Shutdown()
|
||||
```
|
||||
Los parámetros `connCfg` le permiten elegir el puerto RPC de Bitcoin, nombre de usuario, contraseña y si está en testnet o mainnet.
|
||||
|
||||
> **NOTA:** De nuevo, asegúrese de sustituir el `User` y `Pass` con el que se encuentra en su `~/.bitcoin/bitcon.conf`.
|
||||
|
||||
Por tanto la función `rpcclient. New(connCfg, nil)` configura su `client` para conectarse a su nodo Bitcoin.
|
||||
La línea `defer client.Shutdown()` es para desconectar de su nodo Bitcoin, una vez que la función `main()` termina de ejecutarse.
|
||||
Después de la línea `defer client.Shutdown()` es donde va el material emocionante y será bastante fácil de usar.
|
||||
Eso es porque `rpcclient` ayuda a convertir los comandos `bitcoin-cli` en funciones usando PascalCase.
|
||||
Por ejemplo, `bitcoin-cli getblockcount` será `client.GetBlockCount` en Go.
|
||||
|
||||
### Hacer una llamada RPC
|
||||
|
||||
Todo lo que se requiere ahora es hacer una llamada informativa como `GetBlockCount` o `GetBlockHash` usando su `client`:
|
||||
|
||||
```
|
||||
blockCount, err := client.GetBlockCount()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
blockHash, err := client.GetBlockHash(blockCount)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Printf("%d\n", blockCount)
|
||||
fmt.Printf("%s\n", blockHash.String())
|
||||
```
|
||||
### Hacer una llamada RPC con argumentos
|
||||
|
||||
Las funciones `rpcclient` también pueden tomar entradas; por ejemplo `cliente.GetBlockHash(blockCount)` toma el conteo de bloques como una entrada.
|
||||
El cliente `client.GetBlockHash(blockCount)` visto anteriormente se vería como un comando `bitcoin-cli`:
|
||||
|
||||
```
|
||||
$ bitcoin-cli getblockhash 1830868
|
||||
00000000000002d53b6b9bba4d4e7dc44a79cebd1024d1bcfb9b3cc07d6cad9c
|
||||
```
|
||||
Sin embargo, una peculiaridad con hashes en `rpcclient` es que típicamente se imprimirán en una codificación diferente si se va a imprimir normalmente usando `blockHash`.
|
||||
Para imprimirlos como una cadena, es necesario utilizar `blockHash.String()`.
|
||||
|
||||
### Ejecute su código
|
||||
|
||||
Puede descargar el código completo desde el [src directory](../src/18_1_blockinfo.go).
|
||||
|
||||
A continuación, puede ejecutar:
|
||||
```
|
||||
$ go run blockinfo.go
|
||||
1830868
|
||||
00000000000002d53b6b9bba4d4e7dc44a79cebd1024d1bcfb9b3cc07d6cad9c
|
||||
```
|
||||
El último número de bloque junto con su hash debe imprimirse.
|
||||
|
||||
## Buscar fondos
|
||||
|
||||
Debido a las limitaciones de la función `btcd` `rpcclient`, no se puede hacer un uso de la función `getwalletinfo`.
|
||||
Sin embargo, usted puede hacer uso de la llamada RPC `getbalance`:
|
||||
```
|
||||
wallet, err := client.GetBalance("*")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
`client.GetBalance("*")` requiere la entrada `"*"`, debido a una peculiaridad con `btcd`. El asterisco significa que usted quiere conseguir el saldo de todas sus carteras.
|
||||
Si ejecuta [el código src](../src/18_1_getbalance.go), debería obtener una salida similar a esta:
|
||||
```
|
||||
$ go run getbalance.go
|
||||
0.000689 BTC
|
||||
```
|
||||
|
||||
## Crear una dirección
|
||||
|
||||
Puede generar direcciones en Go, pero no puede especificar el tipo de dirección:
|
||||
|
||||
Esto requiere el uso de una función especial `chaincfg`, para especificar para qué red se están creando las direcciones.
|
||||
Esta especificación solo se requiere durante la generación de direcciones, por lo que solo se utiliza en este ejemplo.
|
||||
También puede incluir esto en otros ejemplos, pero no es necesario.
|
||||
|
||||
Asegúrese de importar `"github.com/btcsuite/btcd/chaincfg"`:
|
||||
|
||||
```
|
||||
import (
|
||||
"log"
|
||||
"fmt"
|
||||
"github.com/btcsuite/btcd/rpcclient"
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
)
|
||||
```
|
||||
|
||||
Luego llame a `connCfG` con el parámetro `chaincfg.TestNet3Params.Name` :
|
||||
|
||||
```
|
||||
connCfg := &rpcclient.ConnConfig{
|
||||
Host: "localhost:18332",
|
||||
User: "bitcoinrpc",
|
||||
Pass: "431451790e3eee1913115b9dd2fbf0ac",
|
||||
HTTPPostMode: true,
|
||||
DisableTLS: true,
|
||||
Params: chaincfg.TestNet3Params.Name,
|
||||
}
|
||||
client, err := rpcclient.New(connCfg, nil)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer client.Shutdown()
|
||||
```
|
||||
**MAINNET VS TESTNET:** `Params: chaincfg.TestNet3Params.Name,` debe ser `Parameters: chaincfg.MainNetParams.Name,` en mainnet.
|
||||
|
||||
A continuación, puede crear su dirección:
|
||||
```
|
||||
address, err := client.GetNewAddress("")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fmt.Println(address)
|
||||
```
|
||||
Una peculiaridad con `client.GetNewAddress(")` es que se debe incluir una cadena vacía para que funcione.
|
||||
|
||||
Ejecutando [la fuente](https://github.com/BlockchainCommons/Learning-Bitcoin-from-the-Command-Line/blob/master/src/18_1_getaddress.go) se obtienen los siguientes resultados:
|
||||
|
||||
```
|
||||
$ go run getaddress.go
|
||||
tb1qutkcj34pw0aq7n9wgp3ktmz780szlycwddfmza
|
||||
```
|
||||
### Decodificar una dirección
|
||||
|
||||
La creación de una dirección tomó un trabajo adicional, en especificar la cadena apropiada.
|
||||
Usar una dirección también lo hará porque tendrá que decodificarla antes de usarla.
|
||||
|
||||
Los medios que usted tendrá que importar tanto las librerías `"github.com/btcsuite/btcutil"` como `"github.com/btcsuite/btcd/chaincfg"`.
|
||||
* `btcutil` permite que una dirección de Bitcoin sea decodificada de una manera que el cliente `rpcclient` pueda entender. Esto es necesario cuando se trabaja con direcciones en `rpcclient`.
|
||||
* `chaincfg` se utiliza (de nuevo) para configurar su cadena como la cadena Testnet. Esto es necesario para la decodificación de direcciones ya que las direcciones utilizadas en Mainnet y Testnet son diferentes.
|
||||
```
|
||||
import (
|
||||
"log"
|
||||
"fmt"
|
||||
"github.com/btcsuite/btcd/rpcclient"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
)
|
||||
```
|
||||
La variable defaultNet ahora se utiliza para especificar si su nodo Bitcoin está en testnet o en mainnet. Esa información (y el objeto `btcutil` ) se utiliza para decodificar la dirección.
|
||||
|
||||
> **MAINNET VS TESTNET:** `&chaincfg.TestNet3Params` debe ser `&chaincfg.MainNetParams` en mainnet.
|
||||
```
|
||||
defaultNet := &chaincfg.TestNet3Params
|
||||
addr, err := btcutil.DecodeAddress("mpGpCMX6SuUimDZKiVViuhd7EGyVxkNnha", defaultNet)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
```
|
||||
> **NOTA:** Cambie la dirección (`mpGpCMX6SuUimDZKiVViuhd7EGyVxkNnha`) para una de su billetera actual; puede utilizar `bitcoin-cli listunspent` para encontrar algunas direcciones con fondos para esta prueba. Si quiere ser realmente elegante, modifique el código Go para tomar un argumento, luego escriba un script que ejecute `listunspent`, guarde la información en una variable, y ejecute el código Go con eso.
|
||||
|
||||
Solo después de esto, use la dirección `getreceivedbyaddress` RPC, en su dirección decodificada:
|
||||
```
|
||||
wallet, err := client.GetReceivedByAddress(addr)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println(wallet)
|
||||
```
|
||||
Cuando ejecute [el código](../src/18_1_getamountreceived.go), debería obtener una salida similar a:
|
||||
```
|
||||
$ go run getamountreceived.go
|
||||
0.0085 BTC
|
||||
```
|
||||
## Enviar una transacción
|
||||
|
||||
Ahora tiene todas las piezas del rompecabezas en su lugar para enviar una transacción. Va a querer:
|
||||
|
||||
1. Importar las bibliotecas correctas, incluyendo `chaincfg` para especificar una red y `btcutil` para decodificar una dirección.
|
||||
2. Elija una dirección para enviar.
|
||||
3. Descifre esa dirección.
|
||||
4. Ejecute `sendtoaddress` para enviar los fondos de la manera fácil.
|
||||
|
||||
```
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"fmt"
|
||||
"github.com/btcsuite/btcd/rpcclient"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
)
|
||||
|
||||
func main() {
|
||||
connCfg := &rpcclient.ConnConfig{
|
||||
Host: "localhost:18332",
|
||||
User: "StandUp",
|
||||
Pass: "431451790e3eee1913115b9dd2fbf0ac",
|
||||
HTTPPostMode: true,
|
||||
DisableTLS: true,
|
||||
}
|
||||
client, err := rpcclient.New(connCfg, nil)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer client.Shutdown()
|
||||
|
||||
defaultNet := &chaincfg.TestNet3Params
|
||||
addr, err := btcutil.DecodeAddress("n2eMqTT929pb1RDNuqEnxdaLau1rxy3efi", defaultNet)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
sent, err := client.SendToAddress(addr, btcutil.Amount(1e4))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println(sent)
|
||||
}
|
||||
```
|
||||
Cuando se ejecuta [el código](../src/18_1_sendtransaction.go), el txid de la transacción se emite:
|
||||
```
|
||||
$ go run sendtransaction.go
|
||||
9aa4cd6559e0d69059eae142c35bfe78b71a8084e1fcc2c74e2a9675e9e7489d
|
||||
```
|
||||
### Buscar una transacción
|
||||
|
||||
Para buscar una transacción, como la que acaba de enviar, tendrá que volver a hacer algunas conversiones, esta vez de txid. `"github.com/btcsuite/btcd/chaincfg/chainhash"` se importa para permitir que los hashes se almacenen en el código Go. `chainhash.NewHashFromStr("hash")` convierte un hash en una cadena a un formato que funciona con rpcclient.
|
||||
```
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"fmt"
|
||||
"github.com/btcsuite/btcd/rpcclient"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
)
|
||||
|
||||
func main() {
|
||||
connCfg := &rpcclient.ConnConfig{
|
||||
Host: "localhost:18332",
|
||||
User: "StandUp",
|
||||
Pass: "431451790e3eee1913115b9dd2fbf0ac",
|
||||
HTTPPostMode: true,
|
||||
DisableTLS: true,
|
||||
}
|
||||
client, err := rpcclient.New(connCfg, nil)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer client.Shutdown()
|
||||
|
||||
chash, err := chainhash.NewHashFromStr("1661ce322c128e053b8ea8fcc22d17df680d2052983980e2281d692b9b4ab7df")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
transactions, err := client.GetTransaction(chash)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println(transactions)
|
||||
}
|
||||
```
|
||||
> **NOTA:** De nuevo, querrá cambiar el txid por uno realmente reconocido por su sistema.
|
||||
|
||||
Cuando ejecute [el código](../src/18_1_lookuptransaction.go) imprimirá los detalles asociados con una transacción, como su cantidad y cuántas veces se ha confirmado:
|
||||
```
|
||||
$ go run lookuptransaction.go
|
||||
{
|
||||
"amount": 0.00100000,
|
||||
"confirmations": 4817,
|
||||
"blockhash": "000000006628870b0a8a66abea9cf0d4e815c491f079e3fa9e658a87b5dc863a",
|
||||
"blockindex": 117,
|
||||
"blocktime": 1591857418,
|
||||
"txid": "1661ce322c128e053b8ea8fcc22d17df680d2052983980e2281d692b9b4ab7df",
|
||||
"walletconflicts": [
|
||||
],
|
||||
"time": 1591857343,
|
||||
"timereceived": 1591857343,
|
||||
"bip125-replaceable": "no",
|
||||
"details": [
|
||||
{
|
||||
"address": "mpGpCMX6SuUimDZKiVViuhd7EGyVxkNnha",
|
||||
"category": "receive",
|
||||
"amount": 0.00100000,
|
||||
"label": "",
|
||||
"vout": 0
|
||||
}
|
||||
],
|
||||
"hex": "02000000000101e9e8c3bd057d54e73baadc60c166860163b0e7aa60cab33a03e89fb44321f8d5010000001716001435c2aa3fc09ea53c3e23925c5b2e93b9119b2568feffffff02a0860100000000001976a914600c8c6a4abb0a502ea4de01681fe4fa1ca7800688ac65ec1c000000000017a91425b920efb2fde1a0277d3df11d0fd7249e17cf8587024730440220403a863d312946aae3f3ef0a57206197bc67f71536fb5f4b9ca71a7e226b6dc50220329646cf786cfef79d60de3ef54f702ab1073694022f0618731902d926918c3e012103e6feac9d7a8ad1ac6b36fb4c91c1c9f7fff1e7f63f0340e5253a0e4478b7b13f41fd1a00"
|
||||
}
|
||||
```
|
||||
## Resumen: Acceso a Bitcoind con Go
|
||||
|
||||
Aunque `btcd` y `rpcclient` tienen algunos límites, aún es posible realizar los comandos principales de RPC en Go. La documentación para `rpcclient` está disponible en [Godoc](https://godoc.org/github.com/btcsuite/btcd/rpcclient). Si la documentación no tiene lo que está buscando, consulte también el [repositorio btcd](https://github.com/btcsuite/btcd). Generalmente está bien documentado y es fácil de leer. Sobre la base de estos ejemplos debería ser capaz de incorporar Bitcoin en un proyecto Go y hacer cosas como enviar y recibir monedas.
|
||||
|
||||
## ¿Que sigue?
|
||||
|
||||
Obtenga más información sobre "Hablando con Bitcoin en otros lenguages" en [18.2: Accediendo a Bitcoin con Java](18_2_Accediendo_a_Bitcoind_con_Java.md).
|
315
es/18_2_Accediendo_a_Bitcoind_con_Java.md
Normal file
315
es/18_2_Accediendo_a_Bitcoind_con_Java.md
Normal file
@ -0,0 +1,315 @@
|
||||
# 18.2: Acceso a Bitcoind con Java
|
||||
|
||||
> :information_source: **NOTA:** Esta sección se ha añadido recientemente al curso y es un borrador temprano que todavía puede estar pendiente de revisión. Lectura con advertencias
|
||||
|
||||
Esta sección explica cómo interactuar con `bitcoind` usando el lenguaje de programación Java y el cliente [JavaBitcoindRpcClient](https://githubom/Polve/JavaBitcoindRpcClient).
|
||||
|
||||
## Configuración de Java
|
||||
|
||||
Puede instalar Java en su servidor, usando el comando `apt-get` . También instalará [Apache Maven](http://maven.apache.org/) para administrar las dependencias.
|
||||
```
|
||||
$ sudo apt-get install openjdk-11-jre-headless maven
|
||||
```
|
||||
Puede verificar su instalación de Java:
|
||||
```
|
||||
$ java -version
|
||||
openjdk version "11.0.8" 2020-07-14
|
||||
OpenJDK Runtime Environment (build 11.0.8+10-post-Debian-1deb10u1)
|
||||
OpenJDK 64-Bit Server VM (build 11.0.8+10-post-Debian-1deb10u1, mixed mode, sharing)
|
||||
```
|
||||
### Crear un proyecto Maven
|
||||
|
||||
Para programar con Bitcoin usando java, creará un proyecto Maven:
|
||||
```
|
||||
$ mvn archetype:generate -DgroupId=com.blockchaincommons.lbtc -DartifactId=java-project -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
|
||||
```
|
||||
Esto descargará algunas dependencias
|
||||
```
|
||||
Downloading: https://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-clean-plugin/2.5/maven-clean-plugin-2.5.pom
|
||||
Downloaded: https://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-clean-plugin/2.5/maven-clean-plugin-2.5.pom (4 KB at 4.2 KB/sec)
|
||||
Downloading: https://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-plugins/22/maven-plugins-22.pom
|
||||
Downloaded: https://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-plugins/22/maven-plugins-22.pom (13 KB at 385.9 KB/sec)
|
||||
Downloading: https://repo.maven.apache.org/maven2/org/apache/maven/maven-parent/21/maven-parent-21.pom
|
||||
Downloaded: https://repo.maven.apache.org/maven2/org/apache/maven/maven-parent/21/maven-parent-21.pom (26 KB at 559.6 KB/sec)
|
||||
Downloading: https://repo.maven.apache.org/maven2/org/apache/apache/10/apache-10.pom
|
||||
..............
|
||||
```
|
||||
También creará un archivo de configuración `pom.xml`:
|
||||
|
||||
```
|
||||
$ cd java-project
|
||||
$ ls -lagh
|
||||
total 16K
|
||||
drwxr-xr-x 3 sudo 4.0K Sep 1 13:58 .
|
||||
drwxr-xr-x 15 sudo 4.0K Sep 1 13:58 ..
|
||||
-rw-r--r-- 1 sudo 663 Sep 1 13:58 pom.xml
|
||||
drwxr-xr-x 4 sudo 4.0K Sep 1 13:58 src
|
||||
```
|
||||
Para incluir `JavaBitcoindRpcClient`, debe añadir su dependencia a `dependendencies` en el archivo `pom.xml`
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>wf.bitcoin</groupId>
|
||||
<artifactId>bitcoin-rpc-client</artifactId>
|
||||
<version>1.2.1</version>
|
||||
</dependency>
|
||||
```
|
||||
También necesita agregar propiedades de compilador para indicar qué versión de JDK compilará el código fuente.
|
||||
```xml
|
||||
<properties>
|
||||
<!-- https://maven.apache.org/general.html#encoding-warning -->
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.source>11</maven.compiler.source>
|
||||
<maven.compiler.target>11</maven.compiler.target>
|
||||
</properties>
|
||||
```
|
||||
Siempre que agregue código fuente a sus clases, podrá probarlo con:
|
||||
```
|
||||
$ mvn compile
|
||||
```
|
||||
También puede ejecutar con `exec:java`
|
||||
```
|
||||
$ mvn exec:java -Dexec.mainClass=com.blockchaincommons.lbtc.App
|
||||
```
|
||||
### Crear proyectos alternativos
|
||||
|
||||
Si usa [Gradle](https://gradle.org/releases/), puede ejecutar:
|
||||
|
||||
```groovy
|
||||
compile 'wf.bitcoin:JavaBitcoindRpcClient:1.2.1'
|
||||
```
|
||||
|
||||
Si desea un proyecto de ejemplo y algunas instrucciones sobre cómo ejecutarlo en el servidor que acaba de crear, puede consultar el [Proyecto de Ejemplo](https://github.com/brunocvcunha/bitcoind-java-client-sample/). También puede buscar todo el código fuente para [bitcoin-rpc-client](https://github.com/Polve/bitcoin-rpc-client).
|
||||
|
||||
## Construya su conexión
|
||||
|
||||
Para usar `JavaBitcoindRpcClient`, necesita crear una instancia `BitcoindRpcClient`. Esto se hace creando una URL con argumentos de nombre de usuario, contraseña, dirección IP y puerto. Como recordará, la dirección IP `127.0.0.1` y el puerto `18332` deberían ser correctos para la configuración de testnet estándar descrita en este curso, mientras que puede extraer el usuario y la contraseña de `~/. bitcoin/bitcoin.conf`.
|
||||
|
||||
```java
|
||||
BitcoindRpcClient rpcClient = new BitcoinJSONRPCClient("http://StandUp:6305f1b2dbb3bc5a16cd0f4aac7e1eba@localhost:18332");
|
||||
```
|
||||
|
||||
Tenga en cuenta que también necesitará importar la información adecuada:
|
||||
|
||||
```java
|
||||
import wf.bitcoin.javabitcoindrpcclient.BitcoinJSONRPCClient;
|
||||
import wf.bitcoin.javabitcoindrpcclient.BitcoindRpcClient;
|
||||
```
|
||||
> **MAINNET VS TESTNET:** El puerto sería 8332 para una configuración de mainnet.
|
||||
|
||||
Si `rpcClient` se inicializa correctamente, podrá enviar comandos RPC.
|
||||
|
||||
Más tarde, cuando usted haya terminado con su conexión `bitcoind`, debería cerrarla:
|
||||
|
||||
```java
|
||||
rpcClient.stop();
|
||||
```
|
||||
|
||||
### Hacer una llamada RPC
|
||||
|
||||
Encontrará que `BitcoindRpcClient` proporciona la mayor parte de la funcionalidad a la que se puede acceder a través de `bitcoin-cli` u otros métodos RPC, utilizando los mismos nombres de método, pero en camelCase.
|
||||
|
||||
Por ejemplo, para ejecutar el comando `getmininginfo` para obtener la información de bloque y la dificultad en la red, debe utilizar el método `getMiningInfo()`:
|
||||
|
||||
```java
|
||||
MiningInfo info = rpcClient.getMiningInfo();
|
||||
System.out.println("Mining Information");
|
||||
System.out.println("------------------");
|
||||
System.out.println("Chain......: " + info.chain());
|
||||
System.out.println("Blocks.....: " + info.blocks());
|
||||
System.out.println("Difficulty.: " + info.difficulty());
|
||||
System.out.println("Hash Power.: " + info.networkHashps());
|
||||
```
|
||||
La salida para esta línea debe ser similar a esta:
|
||||
```
|
||||
Mining Information
|
||||
------------------
|
||||
Chain......: test
|
||||
Blocks.....: 1830905
|
||||
Difficulty.: 4194304
|
||||
Hash Power.: 40367401348837.41
|
||||
```
|
||||
### Hacer una llamada RPC con argumentos
|
||||
|
||||
Puede buscar direcciones en su cartera pasando la dirección como argumento a `getAddressInfo`:
|
||||
|
||||
```java
|
||||
String addr1 = "mvLyH7Rs45c16FG2dfV7uuTKV6pL92kWxo";
|
||||
|
||||
AddressInfo addr1Info = rpcClient.getAddressInfo(addr1);
|
||||
System.out.println("Address: " + addr1Info.address());
|
||||
System.out.println("MasterFingerPrint: " + addr1Info.hdMasterFingerprint());
|
||||
System.out.println("HdKeyPath: " + addr1Info.hdKeyPath());
|
||||
System.out.println("PubKey: " + addr1Info.pubKey());
|
||||
```
|
||||
La salida se verá algo así:
|
||||
```
|
||||
Address: mvLyH7Rs45c16FG2dfV7uuTKV6pL92kWxo
|
||||
MasterFingerPrint: ce0c7e14
|
||||
HdKeyPath: m/0'/0'/5'
|
||||
PubKey: 0368d0fffa651783524f8b934d24d03b32bf8ff2c0808943a556b3d74b2e5c7d65
|
||||
```
|
||||
### Ejecute su código
|
||||
|
||||
El código para estos ejemplos se puede encontrar en el [directorio src](../src/18_2_App-getinfo.java) y debe ser instalado en la estructura de directorios estándar creada aquí como `~/java-project/src/main/java/com/blockchaincommons/lbtc/App.java`. Luego se puede compilar y ejecutar.
|
||||
```
|
||||
$ mvn compile
|
||||
$ mvn exec:java -Dexec.mainClass=com.blockchaincommons.lbtc.App
|
||||
Chain......: test
|
||||
Blocks.....: 1831079
|
||||
Difficulty.: 4194304
|
||||
Hash Power.: 38112849943221.16
|
||||
Address: mvLyH7Rs45c16FG2dfV7uuTKV6pL92kWxo
|
||||
MasterFingerPrint: ce0c7e14
|
||||
HdKeyPath: m/0'/0'/5'
|
||||
PubKey: 0368d0fffa651783524f8b934d24d03b32bf8ff2c0808943a556b3d74b2e5c7d65
|
||||
```
|
||||
(También verá mucha más información sobre la compilación, por supuesto.)
|
||||
|
||||
## Buscar fondos
|
||||
|
||||
Recuperar el saldo de una cuenta entera es igualmente fácil:
|
||||
```java
|
||||
System.out.println("Balance: " + rpcClient.getBalance());
|
||||
```
|
||||
## Crear una dirección
|
||||
|
||||
Puede crear una nueva dirección en su cartera, adjuntar una etiqueta específica a ella, e incluso volcar su clave privada.
|
||||
```java
|
||||
String address = rpcClient.getNewAddress("Learning-Bitcoin-from-the-Command-Line");
|
||||
System.out.println("New Address: " + address);
|
||||
|
||||
String privKey = rpcClient.dumpPrivKey(address);
|
||||
System.out.println("Priv Key: " + privKey);
|
||||
```
|
||||
salida:
|
||||
```
|
||||
New Address: mpsFtZ8qTJPRGZy1gaaUw37fHeUSPLkzzs
|
||||
Priv Key: cTy2AnmAALsHokYzJzTdsUBSqBtypmWfmSNYgG6qQH43euUZgqic
|
||||
```
|
||||
## Enviar una transacción
|
||||
|
||||
La biblioteca JavaBitcoindRpcClient tiene algunas buenas herramientas que facilitan la creación de una transacción desde cero.
|
||||
|
||||
### Crear una transacción
|
||||
|
||||
Puede crear una transacción sin procesar usando el método `createRawTransaction`, pasando como argumentos dos objetos ArrayList que contienen las entradas y salidas a utilizar.
|
||||
|
||||
Primero usted establece sus nuevas direcciones, aquí una dirección existente en su sistema y una nueva dirección en su sistema.
|
||||
```java
|
||||
String addr1 = "tb1qdqkc3430rexxlgnma6p7clly33s6jjgay5q8np";
|
||||
System.out.println("Used address addr1: " + addr1);
|
||||
|
||||
String addr2 = rpcClient.getNewAddress();
|
||||
System.out.println("Created address addr2: " + addr2);
|
||||
```
|
||||
Luego, puede usar la lista `RPC para encontrar UTXOs para la dirección existente.
|
||||
```java
|
||||
List<Unspent> utxos = rpcClient.listUnspent(0, Integer.MAX_VALUE, addr1);
|
||||
System.out.println("Found " + utxos.size() + " UTXOs (unspent transaction outputs) belonging to addr1");
|
||||
```
|
||||
Aquí está una salida de toda la información:
|
||||
|
||||
```java
|
||||
System.out.println("Created address addr1: " + addr1);
|
||||
String addr2 = rpcClient.getNewAddress();
|
||||
System.out.println("Created address addr2: " + addr2);
|
||||
List<String> generatedBlocksHashes = rpcClient.generateToAddress(110, addr1);
|
||||
System.out.println("Generated " + generatedBlocksHashes.size() + " blocks for addr1");
|
||||
List<Unspent> utxos = rpcClient.listUnspent(0, Integer.MAX_VALUE, addr1);
|
||||
System.out.println("Found " + utxos.size() + " UTXOs (unspent transaction outputs) belonging to addr1");
|
||||
```
|
||||
Las transacciones se construyen con `BitcoinRawTxBuilder`:
|
||||
```java
|
||||
BitcoinRawTxBuilder txb = new BitcoinRawTxBuilder(rpcClient);
|
||||
```
|
||||
Primero llene las entradas con los UTXOs que está gastando:
|
||||
```java
|
||||
TxInput in = utxos.get(0);
|
||||
txb.in(in);
|
||||
```
|
||||
> :warning: **ADVERTENCIA:** Obviamente, en un programa real, seleccionaría inteligentemente un UTXO; aquí, simplemente tomamos el 0º, una táctica que usaremos a lo largo de este capítulo.
|
||||
|
||||
En segundo lugar, se llena el ouputs cada uno con una cantidad y una dirección:
|
||||
```java
|
||||
BigDecimal estimatedFee = BigDecimal.valueOf(0.00000200);
|
||||
BigDecimal txToAddr2Amount = utxos.get(0).amount().subtract(estimatedFee);
|
||||
txb.out(addr2, txToAddr2Amount);
|
||||
System.out.println("unsignedRawTx in amount: " + utxos.get(0).amount());
|
||||
System.out.println("unsignedRawTx out amount: " + txToAddr2Amount);
|
||||
```
|
||||
Ahora está listo para crear la transacción:
|
||||
```java
|
||||
String unsignedRawTxHex = txb.create();
|
||||
System.out.println("Created unsignedRawTx from addr1 to addr2: " + unsignedRawTxHex);
|
||||
```
|
||||
|
||||
### Firmar una transacción
|
||||
|
||||
Ahora puede firmar la transacción con el método `signRawTransactionWithKey`. Este método recibe como parámetros una transacción de cadena bruta sin firmar, la clave privada de la dirección de envío y el objeto TxInput.
|
||||
```java
|
||||
SignedRawTransaction srTx = rpcClient.signRawTransactionWithKey(
|
||||
unsignedRawTxHex,
|
||||
Arrays.asList(rpcClient.dumpPrivKey(addr1)), //
|
||||
Arrays.asList(in),
|
||||
null);
|
||||
System.out.println("signedRawTx hex: " + srTx.hex());
|
||||
System.out.println("signedRawTx complete: " + srTx.complete());
|
||||
```
|
||||
### Enviar una transacción
|
||||
|
||||
Finalmente enviar requiere el comando `sendRawTransaction` :
|
||||
```java
|
||||
String sentRawTransactionID = rpcClient.sendRawTransaction(srTx.hex());
|
||||
System.out.println("Sent signedRawTx (txID): " + sentRawTransactionID);```
|
||||
```
|
||||
### Ejecute su código
|
||||
|
||||
Ahora puede ejecutar [el código de transacción](../src/18_2_App-sendtx.java) como `~/java-project/src/main/java/com/blockchaincommons/lbtc/App.java`.
|
||||
```
|
||||
$ mvn compile
|
||||
$ mvn exec:java -Dexec.mainClass=com.blockchaincommons.lbtc.App
|
||||
Used address addr1: tb1qdqkc3430rexxlgnma6p7clly33s6jjgay5q8np
|
||||
Created address addr2: tb1q04q2wzlhfqlrnz95ynfj7gp4t3yynrj0542smv
|
||||
Found 1 UTXOs (unspent transaction outputs) belonging to addr1
|
||||
unsignedRawTx in amount: 0.00850000
|
||||
unsignedRawTx out amount: 0.00849800
|
||||
Created unsignedRawTx from addr1 to addr2: 0200000001d2a90fc3b43e8eb4ae9452af43c9448112d359cac701f7f537aa8b6f39193bb90100000000ffffffff0188f70c00000000001600147d40a70bf7483e3988b424d32f20355c48498e4f00000000
|
||||
signedRawTx hex: 02000000000101d2a90fc3b43e8eb4ae9452af43c9448112d359cac701f7f537aa8b6f39193bb90100000000ffffffff0188f70c00000000001600147d40a70bf7483e3988b424d32f20355c48498e4f024730440220495fb64d8cf9dee9daa8535b8867709ac8d3763d693fd8c9111ce610645c76c90220286f39a626a940c3d9f8614524d67dd6594d9ee93818927df4698c1c8b8f622d01210333877967ac52c0d0ec96aca446ceb3f51863de906e702584cc4da2780d360aae00000000
|
||||
signedRawTx complete: true
|
||||
Sent signedRawTx (txID): 82032c07e0ed91780c3369a1943ea8abf49c9e11855ffedd935374ecbc789c45
|
||||
```
|
||||
# Escuchar transacciones o bloques
|
||||
|
||||
Al igual que con [C and its ZMQ libraries](16_3_Recibiendo_Notificaciones_de_Bitcoind_en_C_con_las_Bibliotecas_ZMQ.md), hay maneras fáciles de usar Java para escuchar la cadena de bloques y para ejecutar código específico cuando algo sucede, como una transacción que implica una dirección en su cartera, o incluso la generación de un nuevo bloque en la red.
|
||||
|
||||
Para ello, usa la clase `JavaBitcoindRpcClient` `BitcoinAcceptor`, que le permite conectar oyentes en la red.
|
||||
```java
|
||||
String blockHash = rpcClient.getBestBlockHash();
|
||||
BitcoinAcceptor acceptor = new BitcoinAcceptor(rpcClient, blockHash, 6, new BitcoinPaymentListener() {
|
||||
|
||||
@Override
|
||||
public void transaction(Transaction tx) {
|
||||
System.out.println("Transaction: " + tx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void block(String block) {
|
||||
System.out.println("Block: " + block);
|
||||
}
|
||||
});
|
||||
acceptor.run();
|
||||
```
|
||||
Vea en el [directorio src](../src/18_2_App-listen.java) para el código completo. Cada vez que se envíe una transacción o se genere un nuevo bloque, debería ver la salida en su consola:
|
||||
```
|
||||
Transaction: {account=Tests, address=mhopuJzgmTwhGfpNLCJ9CRknugY691oXp1, category=receive, amount=5.0E-4, label=Tests, vout=1, confirmations=0, trusted=false, txid=361e8fcff243b74ebf396e595a007636654f67c3c7b55fd2860a3d37772155eb, walletconflicts=[], time=1513132887, timereceived=1513132887, bip125-replaceable=unknown}
|
||||
|
||||
Block: 000000004564adfee3738314549f7ca35d96c4da0afc6b232183917086b6d971
|
||||
```
|
||||
### Resumen Acceso a Bitcoind con Java
|
||||
|
||||
Al utilizar la biblioteca javabitcoinrpc, puede acceder fácilmente a bitcoind a través de llamadas RPC desde Java. También tendrá acceso a buenas funciones adicionales, como el servicio de escucha `bitcoinAcceptor` .
|
||||
|
||||
## ¿Qué es lo siguiente?
|
||||
|
||||
Obtenga más información sobre "Cómo hablar con Bitcoin en otros lenguajes" en [18.3: Cómo acceder a Bitcoin con NodeJS](18_3_Accediendo_a_Bitcoind_con_NodeJS.md).
|
242
es/18_3_Accediendo_a_Bitcoind_con_NodeJS.md
Normal file
242
es/18_3_Accediendo_a_Bitcoind_con_NodeJS.md
Normal file
@ -0,0 +1,242 @@
|
||||
# 18.3: Acceso a Bitcoind con NodeJS
|
||||
|
||||
> :information_source: **NOTA:** Esta sección se ha añadido recientemente al curso y es un borrador temprano que todavía puede estar pendiente de revisión. Lectura con advertencias
|
||||
|
||||
Esta sección explica cómo interactuar con `bitcoind` usando el lenguaje de programación NodeJS y el [paquete BCRPC](https://github.com/dgarage/bcrpc).
|
||||
|
||||
## Configurar node.js
|
||||
|
||||
BCRPC está construido en node.js. Por lo tanto, primero necesitará instalar los paquetes `node.js` y `npm` (el administrador de paquetes de nodos) para su sistema.
|
||||
|
||||
Si está usando una máquina de Ubuntu, puede ejecutar los siguientes comandos para obtener una nueva versión de `node.js` (a diferencia de la horriblemente desactualizada versión en el sistema de paquetes de Ubuntu).
|
||||
|
||||
```
|
||||
$ curl -sL https://deb.nodesource.com/setup_14.x | sudo bash -
|
||||
$ sudo apt-get install -y nodejs
|
||||
$ sudo npm install mocha -g
|
||||
|
||||
```
|
||||
### Configuración de BCRPC
|
||||
|
||||
Ahora puede clonar el paquete BCRPC desde GitHub e instalar sus dependencias.
|
||||
```
|
||||
$ git clone https://github.com/dgarage/bcrpc.git
|
||||
$ cd bcrpc
|
||||
$ npm install
|
||||
```
|
||||
|
||||
Para probar el paquete BCRPC, primero debe establecer variables ambientales para rpcuser y rpcpassword. Como de costumbre, estas provienen de `~/. bitcoin/bitcoin.conf`. También debe establecer el puerto RPC en 18332 que debería ser correcto para la configuración estándar de testnet descrita en estos documentos.
|
||||
|
||||
```
|
||||
$ export BITCOIND_USER=StandUp
|
||||
$ export BITCOIND_PASS=d8340efbcd34e312044c8431c59c792c
|
||||
$ export BITCOIND_PORT=18332
|
||||
```
|
||||
> :warning: **ADVERTENCIA:** Obviamente, nunca debería poner su contraseña en una variable ambiental en un entorno de producción.
|
||||
|
||||
> :link: **MAINNET VS TESTNET:** El puerto sería 8332 para una configuración de mainnet.
|
||||
|
||||
Ahora puede verificar que todo funciona correctamente:
|
||||
```
|
||||
$ npm test
|
||||
|
||||
> bcrpc@0.2.2 test /home/user1/bcrpc
|
||||
> mocha tests.js
|
||||
|
||||
BitcoinD
|
||||
✓ is running
|
||||
|
||||
bcrpc
|
||||
✓ can get info
|
||||
|
||||
2 passing (36ms)
|
||||
```
|
||||
Felicitaciones, ahora tiene un envoltorio RPC listo para Bitcoin para Node.js que está trabajando con su configuración de Bitcoin.
|
||||
|
||||
### Crear un proyecto BCRPC
|
||||
|
||||
Ahora puede crear un nuevo proyecto Node.js e instalar BCRPC a través de npm.
|
||||
```
|
||||
$ cd ~
|
||||
$ mkdir myproject
|
||||
$ cd myproject
|
||||
$ npm init
|
||||
[continue with default options]
|
||||
$ npm install bcrpc
|
||||
```
|
||||
# Construya su conexión
|
||||
|
||||
En su directorio `myproject` cree un archivo `.js` donde se ejecutará el código JavaScript.
|
||||
|
||||
Puede iniciar una conexión RPC creando un `RpcAgent`:
|
||||
```
|
||||
const RpcAgent = require('bcrpc');
|
||||
agent = new RpcAgent({port: 18332, user: 'StandUp', pass: 'd8340efbcd34e312044c8431c59c792c'});
|
||||
```
|
||||
Obviamente, su usuario `user` y `pass` deberían coincidir de nuevo con lo que está en su `~/. bitcoin/bitcoin.conf`, y usar `port 18332` si está en testnet.
|
||||
|
||||
### Hacer una llamada RPC
|
||||
|
||||
Usando BCRPC, puede usar los mismos comandos RPC que usaría normalmente a través de `bitcoin-cli` con su `RpcAgent`, excepto que necesitan estar en camelCase. Por ejemplo, `getblockhash` sería `getBlockHash`.
|
||||
|
||||
Para imprimir el nuevo número de bloque, sólo tiene que llamar a `getBlockCount` a través de su `RpcAgent`:
|
||||
```
|
||||
agent.getBlockHash(blockCount.result, function (err, hash) {
|
||||
if (err)
|
||||
throw Error(JSON.stringify(err));
|
||||
console.log(hash.result);
|
||||
})
|
||||
```
|
||||
El resultado de las funciones BCRPC es un objeto JSON que contiene información sobre cualquier error y el id de la solicitud. Al acceder a su resultado, se añade `.result` al final de la misma para especificar que usted está interesado en el resultado real, no información sobre errores.
|
||||
|
||||
### Ejecute su código
|
||||
|
||||
Puede encontrar el código `getinfo` en el [directorio src](https://github.com/BlockchainCommons/Learning-Bitcoin-from-the-Command-Line/blob/master/src/18_3_getinfo.js).
|
||||
```
|
||||
$ node getinfo.js
|
||||
1831094
|
||||
00000000000002bf8b522a830180ad3a93b8eed33121f54b3842d8838580a53c
|
||||
```
|
||||
Esto es lo que la salida del ejemplo anterior se vería si se reemplaza `console.log(blockCount.result);` `console.log(hash.result);` `console.log(blockCount);` y `console.log(hash);`, respectivamente:
|
||||
```
|
||||
{ result: 1774686, error: null, id: null }
|
||||
{
|
||||
result: '00000000000000d980c495a2b7addf09bb0a9c78b5b199c8e965ee54753fa5da',
|
||||
error: null,
|
||||
id: null
|
||||
}
|
||||
```
|
||||
## Buscar fondos
|
||||
|
||||
Es útil al aceptar Bitcoin poder comprobar el bitcoin recibido en una dirección específica en su cartera. Por ejemplo, si estuviera dirigiendo una tienda online aceptando Bitcoin, por cada pago de un cliente, generaría una nueva dirección, mostraría esa dirección al cliente, y luego comprobaría el saldo de la dirección después de algún tiempo, para asegurarse de que se ha recibido la cantidad correcta:
|
||||
```
|
||||
agent.getReceivedByAddress('mpGpCMX6SuUimDZKiVViuhd7EGyVxkNnha', function (err, addressInfo) {
|
||||
if (err)
|
||||
throw Error(JSON.stringify(err));
|
||||
console.log(addressInfo.result);
|
||||
});
|
||||
```
|
||||
> :information_source: **NOTA:** Obviamente, necesitará introducir una dirección reconocida por su máquina.
|
||||
|
||||
Por defecto, esta función comprueba las transacciones que se han confirmado una vez, sin embargo, puede aumentar este a un número más alto, como 6:
|
||||
|
||||
```
|
||||
agent.getReceivedByAddress('mpGpCMX6SuUimDZKiVViuhd7EGyVxkNnha', 6, function (err, addressInfo) {
|
||||
if (err)
|
||||
throw Error(JSON.stringify(err));
|
||||
console.log(addressInfo.result);
|
||||
});
|
||||
```
|
||||
|
||||
### Buscar información de la cartera
|
||||
|
||||
También puede buscar información adicional sobre su cartera y ver su saldo, conteo de transacciones, etc:
|
||||
```
|
||||
agent.getWalletInfo(function (err, walletInfo) {
|
||||
if (err)
|
||||
throw Error(JSON.stringify(err));
|
||||
console.log(walletInfo.result);
|
||||
});
|
||||
```
|
||||
La fuente está disponible como [walletinfo.js](https://github.com/BlockchainCommons/Learning-Bitcoin-from-the-Command-Line/blob/master/src/18_3_walletinfo.js).
|
||||
```
|
||||
$ node walletinfo.js
|
||||
0.008498
|
||||
{
|
||||
walletname: '',
|
||||
walletversion: 169900,
|
||||
balance: 0.010438,
|
||||
unconfirmed_balance: 0,
|
||||
immature_balance: 0,
|
||||
txcount: 4,
|
||||
keypoololdest: 1596567843,
|
||||
keypoolsize: 999,
|
||||
hdseedid: 'da5a1b058deb9e51ecffef1b0ddc069a5dfb2c5f',
|
||||
keypoolsize_hd_internal: 1000,
|
||||
paytxfee: 0,
|
||||
private_keys_enabled: true,
|
||||
avoid_reuse: false,
|
||||
scanning: false
|
||||
}
|
||||
```
|
||||
En lugar de imprimir todos los detalles asociados con su cartera, puede imprimir información específica, como su saldo. Como se está accediendo a un objeto JSON, esto se puede hacer cambiando la línea `console.log(walletInfo.result);`` a `console.log(walletInfo.result.balance);`:
|
||||
|
||||
## Crear una dirección
|
||||
|
||||
También puede pasar argumentos adicionales a los comandos RPC. Por ejemplo, lo siguiente genera una nueva dirección heredada, con la marca `-addresstype`.
|
||||
|
||||
```
|
||||
agent.getNewAddress('-addresstype', 'legacy', function (err, newAddress) {
|
||||
if (err)
|
||||
throw Error(JSON.stringify(err));
|
||||
console.log(newAddress.result);
|
||||
});
|
||||
```
|
||||
Esto es lo mismo que ejecutar lo siguiente desde la línea de comandos:
|
||||
```
|
||||
$ bitcoin-cli getnewaddress -addresstype legacy
|
||||
mtGPcBvRPZFEHo2YX8un9qqPBydhG82uuZ
|
||||
```
|
||||
En BCRPC, generalmente puede utilizar los mismos parámetros que en `bitcoin-cli` en BCRPC. Aunque usa camelCase (`getNewAddress`) para los métodos, las banderas, que normalmente están separadas por espacios en la línea de comandos, se colocan en cadenas y separadas por comas.
|
||||
|
||||
## Enviar una transacción
|
||||
|
||||
Puede enviar monedas a una dirección más fácilmente usando la función `sendToAddress` :
|
||||
```
|
||||
agent.sendToAddress(newAddress.result, 0.00001, function(err, txid) {
|
||||
if (err)
|
||||
throw Error(JSON.stringify(err));
|
||||
console.log(txid.result);
|
||||
});
|
||||
```
|
||||
Esto debe imprimir el txid de la transacción:
|
||||
```
|
||||
1679bee019c61608340b79810377be2798efd4d2ec3ace0f00a1967af70666b9
|
||||
```
|
||||
|
||||
### Buscar una transacción
|
||||
|
||||
Es posible que ahora desee ver una transacción, como la que acaba de enviar.
|
||||
```
|
||||
agent.getTransaction(txid.result, function (err, transaction) {
|
||||
if (err)
|
||||
throw Error(JSON.stringify(err));
|
||||
console.log(transaction.result);
|
||||
});
|
||||
```
|
||||
Debería obtener una salida similar a esta:
|
||||
```
|
||||
{
|
||||
amount: 0.001,
|
||||
confirmations: 4776,
|
||||
blockhash: '000000006628870b0a8a66abea9cf0d4e815c491f079e3fa9e658a87b5dc863a',
|
||||
blockindex: 117,
|
||||
blocktime: 1591857418,
|
||||
txid: '1661ce322c128e053b8ea8fcc22d17df680d2052983980e2281d692b9b4ab7df',
|
||||
walletconflicts: [],
|
||||
time: 1591857343,
|
||||
timereceived: 1591857343,
|
||||
'bip125-replaceable': 'no',
|
||||
details: [
|
||||
{
|
||||
address: 'mpGpCMX6SuUimDZKiVViuhd7EGyVxkNnha',
|
||||
category: 'receive',
|
||||
amount: 0.001,
|
||||
label: '',
|
||||
vout: 0
|
||||
}
|
||||
],
|
||||
hex: '02000000000101e9e8c3bd057d54e73baadc60c166860163b0e7aa60cab33a03e89fb44321f8d5010000001716001435c2aa3fc09ea53c3e23925c5b2e93b9119b2568feffffff02a0860100000000001976a914600c8c6a4abb0a502ea4de01681fe4fa1ca7800688ac65ec1c000000000017a91425b920efb2fde1a0277d3df11d0fd7249e17cf8587024730440220403a863d312946aae3f3ef0a57206197bc67f71536fb5f4b9ca71a7e226b6dc50220329646cf786cfef79d60de3ef54f702ab1073694022f0618731902d926918c3e012103e6feac9d7a8ad1ac6b36fb4c91c1c9f7fff1e7f63f0340e5253a0e4478b7b13f41fd1a00'
|
||||
}
|
||||
```
|
||||
El código completo está disponible como [sendtx.js](https://github.com/BlockchainCommons/Learning-Bitcoin-from-the-Command-Line/blob/master/src/18_3_sendtx.js).
|
||||
|
||||
## Resumen: Acceso a Bitcoind con node.js
|
||||
|
||||
Con BCRPC puede acceder a todos los comandos RPC disponibles a través de `bitcoin-cli`, en JavaScript. El archivo [README de BCRPC](https://github.com/dgarage/bcrpc) tiene algunos ejemplos que usan promesas (los ejemplos en este documento usan callbacks). El [JavaScript detrás de él](https://github.com/dgarage/bcrpc/blob/master/index.js) es corto y legible.
|
||||
|
||||
En base a estos ejemplos debería ser capaz de incorporar Bitcoin en un proyecto Node.js y hacer cosas como enviar y recibir monedas.
|
||||
|
||||
## ¿Qué es lo siguiente?
|
||||
|
||||
Obtenga más información sobre "Cómo hablar con Bitcoin en otros lenguajes" en [18.4: Cómo acceder a Bitcoin con Python](18_4_Accediendo_a_Bitcoind_con_Python.md).
|
464
es/18_4_Accediendo_a_Bitcoind_con_Python.md
Normal file
464
es/18_4_Accediendo_a_Bitcoind_con_Python.md
Normal file
@ -0,0 +1,464 @@
|
||||
# 18.4: Acceso a Bitcoind con Python
|
||||
|
||||
> :information_source: **NOTA:** Esta sección se ha añadido recientemente al curso y es un borrador temprano que todavía puede estar pendiente de revisión. Lectura con advertencias
|
||||
|
||||
Esta sección explica cómo interactuar con `bitcoind` usando el lenguaje de programación Python y el paquete [Python-BitcoinRPC](https://github.com/jgarzik/python-bitcoinrpc).
|
||||
|
||||
## Configuración de Python
|
||||
|
||||
Si usted ya tiene Bitcoin Core instalado, debería tener Python 3 disponible también.
|
||||
Puede comprobar esto corriendo:
|
||||
|
||||
`$ python3 --version`
|
||||
|
||||
Si devuelve un número de versión (por ejemplo, `3.7.3` o `3.8.3`) entonces tiene python3 instalado.
|
||||
|
||||
Sin embargo, si de alguna manera no tiene Python instalado, necesitará construirlo desde el código fuente como sigue. Consulte la variante ["Compilando python desde la fuente"](18_4_Accediendo_a_Bitcoind_con_Python.md#variant-build-python-from-source) antes de continuar.
|
||||
|
||||
### Configurar BitcoinRPC
|
||||
|
||||
Ya sea que haya usado un Python existente o lo haya compilado desde el código fuente, ahora usted esta listo para instalar la biblioteca `python-bitcoinrpc` :
|
||||
```
|
||||
$ pip3 install python-bitcoinrpc
|
||||
```
|
||||
Si no tiene `pip` instalado, necesitará ejecutar lo siguiente:
|
||||
```
|
||||
$ sudo apt install python3-pip
|
||||
```
|
||||
(A continuación, repita las instrucciones `pip3 install python-bitcoinrpc` .)
|
||||
|
||||
### Crear un proyecto BitcoinRPC
|
||||
|
||||
Generalmente necesitara incluir declaraciones apropiadas de `bitcoinrpc` en sus proyectos de Bitcoin en Python. Lo siguiente le dará acceso a los comandos basados en RPC:
|
||||
|
||||
```py
|
||||
from bitcoinrpc.authproxy import AuthServiceProxy, JSONRPCException
|
||||
```
|
||||
También puede encontrar útil lo siguiente:
|
||||
|
||||
```py
|
||||
from pprint import pprint
|
||||
import logging
|
||||
```
|
||||
`pprint` imprimirá amigablemente la respuesta `json` de `bitcoind`.
|
||||
|
||||
`logging` imprimirá la llamada que haga a `bitcoind` y la respuesta de `bitcoind`, lo cual es útil cuando hace un montón de llamadas juntas. Si no quiere que la salida excesiva se muestre en el terminal sólo debe comentar el bloque `logging` .
|
||||
|
||||
## Construya su conexión
|
||||
|
||||
Ahora está listo para empezar a interactuar con `bitcoind` estableciendo una conexión. Cree un archivo llamado `btcrpc.py` y escriba lo siguiente:
|
||||
|
||||
```py
|
||||
logging.basicConfig()
|
||||
logging.getLogger("BitcoinRPC").setLevel(logging.DEBUG)
|
||||
# rpc_user and rpc_password are set in the bitcoin.conf file
|
||||
rpc_user = "StandUp"
|
||||
rpc_pass = "6305f1b2dbb3bc5a16cd0f4aac7e1eba"
|
||||
rpc_host = "127.0.0.1"
|
||||
rpc_client = AuthServiceProxy(f"http://{rpc_user}:{rpc_pass}@{rpc_host}:18332", timeout=120)
|
||||
```
|
||||
|
||||
Los argumentos en la URL son `rpc_username>:rpc_password>@host_IP_address>:port>`. Como de costumbre, el usuario `user` y `pass` se encuentran en su `~/. bitcoin/bitcoin.conf`, mientras que el `host` es su maquina local, y el puerto es `18332` para testnet. El argumento `timeout` se especifica desde _sockets timeout_ bajo carga pesada en la red principal. Si obtiene `socket.timeout: timed out` response, sea paciente y aumente el `timeout`.
|
||||
|
||||
> :link: **MAINNET VS TESTNET:** El puerto sería 8332 para una configuración de mainnet.
|
||||
|
||||
### Hacer una llamada RPC
|
||||
|
||||
Si `rpc_client` se inicializa correctamente, podrá enviar comandos RPC a su nodo bitcoin.
|
||||
|
||||
Para usar un método RPC desde `python-bitcoinrpc`, usará el objeto `rpc_client` que creó, que proporciona la mayor parte de la funcionalidad a la que se puede acceder a través de `bitcoin-cli`, usando los mismos nombres de método.
|
||||
|
||||
Por ejemplo, lo siguiente recuperará el conteo de bloques de su nodo:
|
||||
|
||||
```py
|
||||
block_count = rpc_client.getblockcount()
|
||||
print("---------------------------------------------------------------")
|
||||
print("Block Count:", block_count)
|
||||
print("---------------------------------------------------------------\n")
|
||||
```
|
||||
Debería ver la siguiente salida con `logging` activado:
|
||||
```sh
|
||||
DEBUG:BitcoinRPC:-3-> getblockcount []
|
||||
DEBUG:BitcoinRPC:<-3- 1773020
|
||||
---------------------------------------------------------------
|
||||
Block Count: 1773020
|
||||
---------------------------------------------------------------
|
||||
```
|
||||
### Hacer una llamada RPC con argumentos
|
||||
|
||||
Puede usar ese conteo de bloques como argumento para recuperar el blockhash de un bloque y también para recuperar detalles de ese bloque.
|
||||
|
||||
Esto se hace enviando los comandos objeto `rpc_client` con un argumento:
|
||||
```py
|
||||
blockhash = rpc_client.getblockhash(block_count)
|
||||
block = rpc_client.getblock(blockhash)
|
||||
```
|
||||
El `getblockhash` devolverá un solo valor, mientras que el `getblock` devolverá un array asociativo de información sobre el bloque, que incluye un array bajo `block['tx']` proporcionando detalles sobre cada transacción dentro del bloque:
|
||||
```py
|
||||
nTx = block['nTx']
|
||||
if nTx > 10:
|
||||
it_txs = 10
|
||||
list_tx_heading = "First 10 transactions: "
|
||||
else:
|
||||
it_txs = nTx
|
||||
list_tx_heading = f"All the {it_txs} transactions: "
|
||||
print("---------------------------------------------------------------")
|
||||
print("BLOCK: ", block_count)
|
||||
print("-------------")
|
||||
print("Block Hash...: ", blockhash)
|
||||
print("Merkle Root..: ", block['merkleroot'])
|
||||
print("Block Size...: ", block['size'])
|
||||
print("Block Weight.: ", block['weight'])
|
||||
print("Nonce........: ", block['nonce'])
|
||||
print("Difficulty...: ", block['difficulty'])
|
||||
print("Number of Tx.: ", nTx)
|
||||
print(list_tx_heading)
|
||||
print("---------------------")
|
||||
i = 0
|
||||
while i < it_txs:
|
||||
print(i, ":", block['tx'][i])
|
||||
i += 1
|
||||
print("---------------------------------------------------------------\n")
|
||||
```
|
||||
### Ejecute su código
|
||||
|
||||
Puede recuperar [el código fuente en](https://github.com/BlockchainCommons/Learning-Bitcoin-from-the-Command-Line/blob/master/src/18_4_getinfo.py) y ejecutarlo con `python3`:
|
||||
```
|
||||
$ python3 getinfo.py
|
||||
---------------------------------------------------------------
|
||||
Block Count: 1831106
|
||||
---------------------------------------------------------------
|
||||
---------------------------------------------------------------
|
||||
BLOCK: 1831106
|
||||
-------------
|
||||
Block Hash...: 00000000000003b2ea7c2cdfffd86156ad1f5606ab58e128940a2534d1348b04
|
||||
Merkle Root..: 056a547fe59208167eef86fa694263728fb684119254b340c1f86bdd423a8082
|
||||
Block Size...: 52079
|
||||
Block Weight.: 128594
|
||||
Nonce........: 1775583700
|
||||
Difficulty...: 4194304
|
||||
Number of Tx.: 155
|
||||
First 10 transactions:
|
||||
---------------------
|
||||
0 : d228d55112e3aa26265b0118cfdc98345c229d20fe074b9afb87107c03ce11b5
|
||||
1 : 92822e8e34fafb472b87c99ea3f3e16440452b3f361ed86c6fa62175173fb750
|
||||
2 : fa7c67600c14d4aa350a9674688f1429577954f4a6c5e4639d06c8964824f647
|
||||
3 : 3a91d1527e308e5603dafde7ab17824f441a73a779d2571d073466dc9e8451b2
|
||||
4 : 30fd0e5527b1522e7b26a4818b9edac80fe47c0c39fc34705478a49e684708d0
|
||||
5 : 24c5372b38c78cbaf5b0b305925502a491bc0c1b5758f50c0bd335abb6ae85f5
|
||||
6 : be70e125a5793efc5e32051fecba0668df971bdf371138c8261201c2a46b2d38
|
||||
7 : 41ebf52c847a59ba0aeb4425c74e89a01e91defa86a82785ff53ed4668054561
|
||||
8 : dc8211b4ce122f87692e7c203672e3eb1ffc44c0a307eafcc560323fcc5fae78
|
||||
9 : 59e2d8e11cad287eacf3207e64a373f65059286b803ef0981510193ae29cbc8c
|
||||
---------------------------------------------------------------
|
||||
```
|
||||
## Buscar fondos
|
||||
|
||||
Del mismo modo, puede recuperar la información de su cartera con el `getwalletinfo` RPC:
|
||||
```py
|
||||
wallet_info = rpc_client.getwalletinfo()
|
||||
print("---------------------------------------------------------------")
|
||||
print("Wallet Info:")
|
||||
print("-----------")
|
||||
pprint(wallet_info)
|
||||
print("---------------------------------------------------------------\n")
|
||||
```
|
||||
Debería tener una salida similar a la siguiente con `logging` disabled:
|
||||
```sh
|
||||
---------------------------------------------------------------
|
||||
Wallet Info:
|
||||
-----------
|
||||
{'avoid_reuse': False,
|
||||
'balance': Decimal('0.07160443'),
|
||||
'hdseedid': '6dko666b1cc0d69b7eb0539l89eba7b6390kdj02',
|
||||
'immature_balance': Decimal('0E-8'),
|
||||
'keypoololdest': 1542245729,
|
||||
'keypoolsize': 999,
|
||||
'keypoolsize_hd_internal': 1000,
|
||||
'paytxfee': Decimal('0E-8'),
|
||||
'private_keys_enabled': True,
|
||||
'scanning': False,
|
||||
'txcount': 9,
|
||||
'unconfirmed_balance': Decimal('0E-8'),
|
||||
'walletname': '',
|
||||
'walletversion': 169900}
|
||||
---------------------------------------------------------------
|
||||
```
|
||||
Otros comandos informativos como `getblockchaininfo`, `getnetworkinfo`, `getpeerinfo`, y `getblockchaininfo` funcionarán de manera similar.
|
||||
|
||||
Otros comandos pueden darle información específica sobre determinados elementos dentro de su cartera.
|
||||
|
||||
### Recuperar una matriz
|
||||
|
||||
La llamada RPC `listtransactions` le permite ver las 10 transacciones más recientes en su sistema (o algún conjunto arbitrario de transacciones usando los argumentos `count` y `skip` ). Muestra cómo un comando RPC puede devolver una matriz fácil de manipular:
|
||||
```py
|
||||
tx_list = rpc_client.listtransactions()
|
||||
pprint(tx_list)
|
||||
```
|
||||
### Explorar un UTXO
|
||||
|
||||
Del mismo modo, puede utilizar `listunspent` para obtener una matriz de UTXOs en su sistema:
|
||||
```py
|
||||
print("Exploring UTXOs")
|
||||
## List UTXOs
|
||||
utxos = rpc_client.listunspent()
|
||||
print("Utxos: ")
|
||||
print("-----")
|
||||
pprint(utxos)
|
||||
print("------------------------------------------\n")
|
||||
```
|
||||
Con el fin de manipular un array como el devuelto desde `listtransactions`o `listunpsent`, sólo tiene que tomar el elemento apropiado del elemento apropiado del array:
|
||||
```
|
||||
## Select a UTXO - first one selected here
|
||||
utxo_txid = utxos[0]['txid']
|
||||
```
|
||||
Para `listunspent`, se obtiene un `txid`. Puede recuperar información sobre él con `gettransaction`, luego decodificar eso con `decoderawtransaction`:
|
||||
```
|
||||
utxo_hex = rpc_client.gettransaction(utxo_txid)['hex']
|
||||
|
||||
utxo_tx_details = rpc_client.decoderawtransaction(utxo_hex)
|
||||
|
||||
print("Details of Utxo with txid:", utxo_txid)
|
||||
print("---------------------------------------------------------------")
|
||||
print("UTXO Details:")
|
||||
print("------------")
|
||||
pprint(utxo_tx_details)
|
||||
print("---------------------------------------------------------------\n")
|
||||
```
|
||||
Este código está disponible en [walletinfo.py](https://github.com/BlockchainCommons/Learning-Bitcoin-from-the-Command-Line/blob/master/src/18_4_walletinfo.py).
|
||||
```
|
||||
$ python3 walletinfo.py
|
||||
---------------------------------------------------------------
|
||||
Wallet Info:
|
||||
-----------
|
||||
{'avoid_reuse': False,
|
||||
'balance': Decimal('0.01031734'),
|
||||
'hdseedid': 'da5a1b058deb9e51ecffef1b0ddc069a5dfb2c5f',
|
||||
'immature_balance': Decimal('0E-8'),
|
||||
'keypoololdest': 1596567843,
|
||||
'keypoolsize': 1000,
|
||||
'keypoolsize_hd_internal': 999,
|
||||
'paytxfee': Decimal('0E-8'),
|
||||
'private_keys_enabled': True,
|
||||
'scanning': False,
|
||||
'txcount': 6,
|
||||
'unconfirmed_balance': Decimal('0E-8'),
|
||||
'walletname': '',
|
||||
'walletversion': 169900}
|
||||
---------------------------------------------------------------
|
||||
|
||||
Utxos:
|
||||
-----
|
||||
[{'address': 'mv9cjEnS2o1EygBMdrz99LzhM8KeEMoXDg',
|
||||
'amount': Decimal('0.00001000'),
|
||||
'confirmations': 1180,
|
||||
'desc': "pkh([ce0c7e14/0'/0'/25']02d0541b9211aecd25913f7fdecfc1b469215fa326d52067b1b3f7efbd12316472)#n06pq9q5",
|
||||
'label': '-addresstype',
|
||||
'safe': True,
|
||||
'scriptPubKey': '76a914a080d1a10f5e7a02d0a291f118982ed19e8cfcd788ac',
|
||||
'solvable': True,
|
||||
'spendable': True,
|
||||
'txid': '84207ffec658ae29ad1fdd330d8a13613303c3cf281ce628fadeb7636ffb535e',
|
||||
'vout': 0},
|
||||
{'address': 'tb1qrcf8c29966tvqxhwrtd2se3rj6jeqtll3r46a4',
|
||||
'amount': Decimal('0.01029734'),
|
||||
'confirmations': 1180,
|
||||
'desc': "wpkh([ce0c7e14/0'/1'/26']02c581259ba7e6aef6d7ea23adb08f7c7f10c4c678f2e097a4074639e7685d4805)#j3pctfhf",
|
||||
'safe': True,
|
||||
'scriptPubKey': '00141e127c28a5d696c01aee1adaa8662396a5902fff',
|
||||
'solvable': True,
|
||||
'spendable': True,
|
||||
'txid': '84207ffec658ae29ad1fdd330d8a13613303c3cf281ce628fadeb7636ffb535e',
|
||||
'vout': 1},
|
||||
{'address': 'mzDxbtYY3LBBBJ6HhaBAtnHv6c51BRBTLE',
|
||||
'amount': Decimal('0.00001000'),
|
||||
'confirmations': 1181,
|
||||
'desc': "pkh([ce0c7e14/0'/0'/23']0377bdd176f985b4af2f6bdbb22c2925b6007b6c07ba171f75e65990c002615e98)#3y6ef6vu",
|
||||
'label': '-addresstype',
|
||||
'safe': True,
|
||||
'scriptPubKey': '76a914cd339342b06042bb986a45e73d56db46acc1e01488ac',
|
||||
'solvable': True,
|
||||
'spendable': True,
|
||||
'txid': '1679bee019c61608340b79810377be2798efd4d2ec3ace0f00a1967af70666b9',
|
||||
'vout': 1}]
|
||||
------------------------------------------
|
||||
|
||||
Details of Utxo with txid: 84207ffec658ae29ad1fdd330d8a13613303c3cf281ce628fadeb7636ffb535e
|
||||
---------------------------------------------------------------
|
||||
UTXO Details:
|
||||
------------
|
||||
{'hash': '0c6c27f58f122329bbc53a91f290b35ce23bd2708706b21a04cdc387dc8e2fd9',
|
||||
'locktime': 1831103,
|
||||
'size': 225,
|
||||
'txid': '84207ffec658ae29ad1fdd330d8a13613303c3cf281ce628fadeb7636ffb535e',
|
||||
'version': 2,
|
||||
'vin': [{'scriptSig': {'asm': '', 'hex': ''},
|
||||
'sequence': 4294967294,
|
||||
'txid': '1679bee019c61608340b79810377be2798efd4d2ec3ace0f00a1967af70666b9',
|
||||
'txinwitness': ['3044022014b3e2359fb46d8cbc4cd30fa991b455edfa4b419a4c64a53fcdfc79e3ca89db022010cefc3268bc252d55f1982c426328b709b47d02332def9e2efb3b12de2cf0d301',
|
||||
'0351b470e87b44e8e9607acf09b8d4543c51c93c17dc741176319e60202091f2be'],
|
||||
'vout': 0}],
|
||||
'vout': [{'n': 0,
|
||||
'scriptPubKey': {'addresses': ['mv9cjEnS2o1EygBMdrz99LzhM8KeEMoXDg'],
|
||||
'asm': 'OP_DUP OP_HASH160 '
|
||||
'a080d1a10f5e7a02d0a291f118982ed19e8cfcd7 '
|
||||
'OP_EQUALVERIFY OP_CHECKSIG',
|
||||
'hex': '76a914a080d1a10f5e7a02d0a291f118982ed19e8cfcd788ac',
|
||||
'reqSigs': 1,
|
||||
'type': 'pubkeyhash'},
|
||||
'value': Decimal('0.00001000')},
|
||||
{'n': 1,
|
||||
'scriptPubKey': {'addresses': ['tb1qrcf8c29966tvqxhwrtd2se3rj6jeqtll3r46a4'],
|
||||
'asm': '0 1e127c28a5d696c01aee1adaa8662396a5902fff',
|
||||
'hex': '00141e127c28a5d696c01aee1adaa8662396a5902fff',
|
||||
'reqSigs': 1,
|
||||
'type': 'witness_v0_keyhash'},
|
||||
'value': Decimal('0.01029734')}],
|
||||
'vsize': 144,
|
||||
'weight': 573}
|
||||
---------------------------------------------------------------
|
||||
```
|
||||
## Crear una dirección
|
||||
|
||||
Crear una nueva dirección con Python 3 solo requiere el uso de un RPC como `getnewaddress` o `getrawchangeaddress`.
|
||||
```
|
||||
new_address = rpc_client.getnewaddress("Learning-Bitcoin-from-the-Command-Line")
|
||||
new_change_address = rpc_client.getrawchangeaddress()
|
||||
```
|
||||
En este ejemplo, se da el comando `getnewaddress` un argumento: la etiqueta `Learning-Bitcoin-from-the-Command-Line` .
|
||||
|
||||
## Enviar una transacción
|
||||
|
||||
Crear una transacción en Python 3 requiere combinar algunos de los ejemplos anteriores (de crear direcciones y recuperar UTXOs) con algunos nuevos comandos RPC para crear, firmar y enviar una transacción mucho de lo que ha hecho anteriormente desde la línea de comandos.
|
||||
Hay cinco pasos a seguir:
|
||||
|
||||
0. Crear dos direcciones, una que actuará como receptor y la otra para el cambio.
|
||||
1. Seleccione un UTXO y establezca los detalles de la transacción.
|
||||
2. Crear una transacción en bruto.
|
||||
3. Firmar la transacción en bruto con la clave privada de la UTXO.
|
||||
4. Difundir la transacción en el bitcoin testnet.
|
||||
|
||||
### 1. Seleccione UTXO y definir los detalles de la transacción
|
||||
|
||||
En el siguiente fragmento de código, primero seleccione el UTXO que queremos gastar. Entonces usted consigue su dirección, la identificación de la transacción, y el índice vectorial de la salida.
|
||||
```py
|
||||
utxos = rpc_client.listunspent()
|
||||
selected_utxo = utxos[0] # again, selecting the first utxo here
|
||||
utxo_address = selected_utxo['address']
|
||||
utxo_txid = selected_utxo['txid']
|
||||
utxo_vout = selected_utxo['vout']
|
||||
utxo_amt = float(selected_utxo['amount'])
|
||||
```
|
||||
A continuación, también recupera la dirección del destinatario a la que quiere enviar los bitcoins, calcula la cantidad de bitcoins que quiere enviar, y calcula la tarifa minera y la cantidad de cambio. Aquí, la cantidad se divide arbitrariamente en dos y una cuota de minero se establece arbitrariamente.
|
||||
```py
|
||||
recipient_address = new_address
|
||||
recipient_amt = utxo_amt / 2 # sending half coins to recipient
|
||||
miner_fee = 0.00000300 # choose appropriate fee based on your tx size
|
||||
change_address = new_change_address
|
||||
change_amt = float('%.8f'%((utxo_amt - recipient_amt) - miner_fee))
|
||||
```
|
||||
> :warning: **WARNING:** Obviamente un programa real tomaría decisiones más sofisticadas sobre qué UTXO usar, qué hacer con los fondos, y qué cuota de minero pagar.
|
||||
|
||||
### 2. Crear transacciones sin procesar
|
||||
|
||||
Ahora usted tiene toda la información para enviar una transacción, pero antes de que pueda enviar una, tiene que crear una transacción.
|
||||
```py
|
||||
txids_vouts = [{"txid": utxo_txid, "vout": utxo_vout}]
|
||||
addresses_amts = {f"{recipient_address}": recipient_amt, f"{change_address}": change_amt}
|
||||
unsigned_tx_hex = rpc_client.createrawtransaction(txids_vouts, addresses_amts)
|
||||
```
|
||||
Recuerde que el formato del comando `createrawtransaction` es:
|
||||
|
||||
`$ bitcoin-cli createrawtransaction '[{"txid": <utxo_txid>, "vout": <vector_id>}]' '{"<address>": <amount>}'`
|
||||
|
||||
El `txids_vouts` es así una lista y el `addresses_amts` es un diccionario de python, para que coincida con el formato de `createrawtransaction`.
|
||||
|
||||
Si quiere ver más sobre los detalles de la transacción que ha creado, puede usar `decoderawtransaction`, ya sea en Python 3 o con `bitcoin-cli`.
|
||||
|
||||
### 3. Firma la transacción cruda
|
||||
|
||||
Firmar una transacción es a menudo la parte más complicada de enviar una transacción programáticamente. Aquí usted recupera una clave privada de una dirección con `dumpprivkey` y la coloca en una matriz:
|
||||
```py
|
||||
address_priv_key = [] # list of priv keys of each utxo
|
||||
address_priv_key.append(rpc_client.dumpprivkey(utxo_address))
|
||||
```
|
||||
A continuación, puede utilizar esa matriz (que debe contener las claves privadas de cada UTXO que se está gastando) para firmar su `unsigned_tx_hex`:
|
||||
```py
|
||||
signed_tx = rpc_client.signrawtransactionwithkey(unsigned_tx_hex, address_priv_key)
|
||||
```
|
||||
Esto devuelve un objeto JSON con el hexadecimal de la transacción firmada, y si fue firmado completamente o no:
|
||||
|
||||
### 4. Transacción de transmisión
|
||||
|
||||
Por último, está listo para transmitir la transacción firmada en la red bitcoin:
|
||||
```py
|
||||
send_tx = rpc_client.sendrawtransaction(signed_tx['hex'])
|
||||
```
|
||||
### Ejecute su código
|
||||
|
||||
El [código de ejemplo](https://github.com/BlockchainCommons/Learning-Bitcoin-from-the-Command-Line/blob/master/src/18_4_sendtx.py) está lleno de sentencias `print` para demostrar todos los datos disponibles en cada punto:
|
||||
```
|
||||
$ python3 sendtx.py
|
||||
Creating a Transaction
|
||||
---------------------------------------------------------------
|
||||
Transaction Details:
|
||||
-------------------
|
||||
UTXO Address.......: mv9cjEnS2o1EygBMdrz99LzhM8KeEMoXDg
|
||||
UTXO Txid..........: 84207ffec658ae29ad1fdd330d8a13613303c3cf281ce628fadeb7636ffb535e
|
||||
Vector ID of Output: 0
|
||||
UTXO Amount........: 1e-05
|
||||
Tx Amount..........: 5e-06
|
||||
Recipient Address..: tb1qca0elxxqzw5xc0s3yq5qhapzzj90ka0zartu6y
|
||||
Change Address.....: tb1qrveukqrvqm9h6fua99xvcxgnvdx507dg8e8hrt
|
||||
Miner Fee..........: 3e-06
|
||||
Change Amount......: 2e-06
|
||||
---------------------------------------------------------------
|
||||
|
||||
---------------------------------------------------------------
|
||||
Unsigned Transaction Hex: 02000000015e53fb6f63b7defa28e61c28cfc3033361138a0d33dd1fad29ae58c6fe7f20840000000000ffffffff02f401000000000000160014c75f9f98c013a86c3e1120280bf422148afb75e2c8000000000000001600141b33cb006c06cb7d279d294ccc1913634d47f9a800000000
|
||||
---------------------------------------------------------------
|
||||
|
||||
---------------------------------------------------------------
|
||||
Signed Transaction:
|
||||
----------------------
|
||||
{'complete': True,
|
||||
'hex': '02000000015e53fb6f63b7defa28e61c28cfc3033361138a0d33dd1fad29ae58c6fe7f2084000000006a47304402205da9b2234ea057c9ef3b7794958db6c650c72dedff1a90d2915147a5f6413f2802203756552aba0dd8ebd71b0f28341becc01b28d8b28af063d7c8ce89f9c69167f8012102d0541b9211aecd25913f7fdecfc1b469215fa326d52067b1b3f7efbd12316472ffffffff02f401000000000000160014c75f9f98c013a86c3e1120280bf422148afb75e2c8000000000000001600141b33cb006c06cb7d279d294ccc1913634d47f9a800000000'}
|
||||
---------------------------------------------------------------
|
||||
|
||||
---------------------------------------------------------------
|
||||
TXID of sent transaction: 187f8baa222f9f37841d966b6bad59b8131cfacca861cbe9bfc8656bd16a44cc
|
||||
```
|
||||
## Resumen: Acceso a Bitcoind con Python
|
||||
|
||||
Acceder a Bitcoind con Python es muy fácil mientras usa la biblioteca `python-bitcoinrpc`. Lo primero que hay que hacer siempre es establecer una conexión con su `bitcoind` instancia, a continuación, puede llamar a todas las llamadas a la API de bitcoin como se describe en la documentación de núcleo de bitcoin. Esto hace que sea fácil crear programas pequeños o grandes para administrar su propio nodo, comprobar balances, o crear aplicaciones interesantes en la parte superior dado que tiene acceso a la potencia total de `bitcoin-cli`.
|
||||
|
||||
## ¿Qué es lo siguiente?
|
||||
|
||||
Obtén más información sobre "Cómo hablar con Bitcoin en otros lenguajes" en [18.5: Cómo acceder a Bitcoin con Rust](18_5_Accediendo_a_Bitcoind_con_Rust.md).
|
||||
|
||||
## Variante: Construir Python desde el Origen
|
||||
|
||||
Si necesita instalar Python 3 desde el código fuente, siga estas instrucciones y luego continúe con ["Creando un proyecto BitcoinRPC"](18_4_Accediendo_a_Bitcoind_con_Python.md#creating-a-bitcoinrpc-project).
|
||||
|
||||
### 1. Instalar dependencias
|
||||
```sh
|
||||
$ sudo apt-get install build-essential checkinstall
|
||||
$ sudo apt-get install libreadline-gplv2-dev libncursesw5-dev libssl-dev libsqlite3-dev tk-dev libgdbm-dev libc6-dev libbz2-dev libffi-dev zlib1g-dev
|
||||
```
|
||||
### 2. Descargar y extraer Python
|
||||
```sh
|
||||
$ wget https://www.python.org/ftp/python/3.8.3/Python-3.8.3.tgz
|
||||
$ tar -xzf Python-3.8.3.tgz
|
||||
```
|
||||
### 3. Compilar Python Origen & Comprobar instalación:
|
||||
```sh
|
||||
$ cd Python-3.8.3
|
||||
$ sudo ./configure --enable-optimizations
|
||||
$ sudo make -j 8 # enter the number of cores of your system you want to use to speed up the build process.
|
||||
$ sudo make altinstall
|
||||
$ python3.8 --version
|
||||
```
|
||||
Después de obtener la salida de la versión, elimine el archivo de origen:
|
||||
```sh
|
||||
$ rm Python-3.8.3.tgz
|
||||
```
|
330
es/18_5_Accediendo_a_Bitcoind_con_Rust.md
Normal file
330
es/18_5_Accediendo_a_Bitcoind_con_Rust.md
Normal file
@ -0,0 +1,330 @@
|
||||
# 18.5: Acceso a Bitcoind con Rust
|
||||
|
||||
> :information_source: **NOTA:** Esta sección se ha añadido recientemente al curso y es un borrador temprano que todavía puede estar pendiente
|
||||
de revisión. Lectura con advertencias
|
||||
|
||||
Esta sección explica cómo interactuar con `bitcoind` usando el lenguaje de programación Rust y la [caja `bitcoincore-rpc`](https://github.com/rust-bitcoin/rust-bitcoincore-rpc).
|
||||
|
||||
## Establecer Rust
|
||||
Es necesario instalar tanto Rust como Cargo.
|
||||
|
||||
Se pueden instalar a través de `curl`. Simplemente utilice la instalación "predeterminada"
|
||||
```vim
|
||||
$ curl https://sh.rustup.rs -sSf | sh
|
||||
```
|
||||
Si todo va bien, usted debería ver:
|
||||
```vim
|
||||
Rust is installed now. Great!
|
||||
```
|
||||
A continuación, tendrá que cerrar la sesión y volver a entrar, o bien añadir el directorio binario de Cargo a su ruta a mano:
|
||||
```
|
||||
$ source $HOME/.cargo/env
|
||||
```
|
||||
### Configurar `bitcoincore-rpc`
|
||||
|
||||
Para la mayoría de los lenguajes de programación, necesita instalar una biblioteca RPC de Bitcoin antes de crear su primer proyecto, pero aquí usted lo hara como parte de la creación de su proyecto.
|
||||
|
||||
### Crear un proyecto de bitcoincore-rpc
|
||||
|
||||
Puede crear un nuevo proyecto usando `cargo new btc_test`:
|
||||
```
|
||||
$ cargo new btc_test
|
||||
Created binary (application) `btc_test` package
|
||||
```
|
||||
Esto creará un directorio `btc_test` que contiene un ejemplo de código fuente "hello world" en `src/main.rs` y un archivo `Cargo.toml` .
|
||||
|
||||
Compilará y ejecutará su código con `cargo run`:
|
||||
```
|
||||
$ cd btc_test
|
||||
$ cargo run
|
||||
Compiling btc_test v0.1.0 (/home/standup/btc_test)
|
||||
Finished dev [unoptimized + debuginfo] target(s) in 0.14s
|
||||
Running `target/debug/btc_test`
|
||||
Hello, world!
|
||||
```
|
||||
> :information_source: **NOTA:** si se encuentra con un error `linker Žcc' no encontrado`, tendrá que instalar un
|
||||
Compilador C. Si está en Linux, adelante e instale las [herramientas de desarrollo](https://www.ostechnix.com/install-development-tools-linux/).
|
||||
|
||||
Para acceder a la caja (biblioteca) de `bitcoincore-rpc`, debe añadirla a su `Cargo.toml` en la sección `dependencies`:
|
||||
```rust
|
||||
[dependencies]
|
||||
bitcoincore-rpc = "0.11.0"
|
||||
```
|
||||
Cuando usted `carga ejecutar` de nuevo, se instalará la caja y sus (numerosas) dependencias.
|
||||
```
|
||||
$ cargo run
|
||||
Updating crates.io index
|
||||
...
|
||||
Compiling bitcoin v0.23.0
|
||||
Compiling bitcoincore-rpc-json v0.11.0
|
||||
Compiling bitcoincore-rpc v0.11.0
|
||||
Compiling btc_test v0.1.0 (/home/standup/btc_test)
|
||||
Finished dev [unoptimized + debuginfo] target(s) in 23.56s
|
||||
Running `target/debug/btc_test`
|
||||
Hello, world!
|
||||
```
|
||||
Cuando esté usando `bitcoin-rpc`, normalmente necesitará incluir lo siguiente:
|
||||
```
|
||||
use bitcoincore_rpc::{Auth, Client, RpcApi};
|
||||
```
|
||||
## Construya su conexión
|
||||
|
||||
Para crear un cliente de Bitcoin `RPC`, modifique `src/main.rs`:
|
||||
```rust
|
||||
use bitcoincore_rpc::{Auth, Client, RpcApi};
|
||||
|
||||
fn main() {
|
||||
let rpc = Client::new(
|
||||
"http://localhost:18332".to_string(),
|
||||
Auth::UserPass("StandUp".to_string(), "password".to_string()),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
```
|
||||
Como siempre, asegurese de insertar su nombre de usuario y contraseña desde `~/. bitcoin/bitcoin.conf`. Aquí, se utilizan como argumentos para `Auth::UserPass`.
|
||||
|
||||
> :link: **TESTNET vs MAINNET:** Y, como de costumbre, usar el puerto 8332 para mainnet.
|
||||
|
||||
Cuando termine, también debe cerrar su conexión:
|
||||
```rust
|
||||
let _ = rpc.stop().unwrap();
|
||||
```
|
||||
`cargo run` debe compilar con éxito y ejecutar el ejemplo con una advertencia `warning: variable no utilizada: rpc`
|
||||
|
||||
### Hacer una llamada RPC
|
||||
|
||||
Las llamadas RPC se hacen usando el cliente `rpc` `que usted creó:
|
||||
```rust
|
||||
let mining_info = rpc.get_mining_info().unwrap();
|
||||
println!("{:#?}", mining_info);
|
||||
```
|
||||
Generalmente, las palabras en la llamada RPC están separadas por `_`s. Una lista completa está disponible en [documentos crate](https://crates.io/crates/bitcoincore-rpc).
|
||||
|
||||
### Hacer una llamada RPC con argumentos
|
||||
|
||||
Enviar una llamada RPC con argumentos usando Rust solo requiere saber cómo se presenta la función. Por ejemplo, la función `get_block` se define como sigue en [docs](https://docs.rs/bitcoincore-rpc/0.11.0/bitcoincore_rpc/trait.RpcApi.html#method.get_block):
|
||||
```rust
|
||||
fn get_block(&self, hash: &BlockHash) -> Result<Block>
|
||||
```
|
||||
Sólo tiene que permitir que tome prestado un blockhash, que puede ser recuperado (por ejemplo) por `get_best_block_hash`.
|
||||
|
||||
Aquí está el código completo para recuperar un hash de bloque, convertirlo en un bloque, e imprimirlo.
|
||||
```
|
||||
let hash = rpc.get_best_block_hash().unwrap();
|
||||
let block = rpc.get_block(&hash).unwrap();
|
||||
|
||||
println!("{:?}", block);
|
||||
```
|
||||
> **NOTA:** Otra llamada posible que consideramos para esta sección fue `get_address_info`, pero desafortunadamente en este momento, la función `bitcoincore-rpc` no funciona con las versiones recientes de Bitcoin Core debido a que la caja no aborda los últimos cambios de API en Bitcoin Core. Esperamos que esto se resuelva en el próximo lanzamiento de la caja, pero mientras tanto, _programador con advertencias_.
|
||||
|
||||
### Ejecute su código
|
||||
|
||||
Puede acceder al [código src](https://github.com/BlockchainCommons/Learning-Bitcoin-from-the-Command-Line/blob/master/src/18_5_main-getinfo.rs) y ejecutarlo. Desafortunadamente, la información de "Block" saldrá un poco fea porque este ejemplo no incluye una biblioteca para embellecerla.
|
||||
```
|
||||
$ cargo run
|
||||
Compiling btc_test v0.1.0 (/home/standup/btc_test)
|
||||
Finished dev [unoptimized + debuginfo] target(s) in 1.61s
|
||||
Running `target/debug/btc_test`
|
||||
GetMiningInfoResult {
|
||||
blocks: 1832335,
|
||||
current_block_weight: None,
|
||||
current_block_tx: None,
|
||||
difficulty: 4194304.0,
|
||||
network_hash_ps: 77436285865245.1,
|
||||
pooled_tx: 4,
|
||||
chain: "test",
|
||||
warnings: "Warning: unknown new rules activated (versionbit 28)",
|
||||
}
|
||||
Block { header: BlockHeader { version: 541065216, prev_blockhash: 000000000000027715981d5a3047daf6819ea3b8390b73832587594a2074cbf5, merkle_root: 4b2e2c2754b6ed9cf5c857a66ed4c8642b6f6b33b42a4859423e4c3dca462d0c, time: 1599602277, bits: 436469756, nonce: 218614401 }, txdata: [Transaction { version: 1, lock_time: 0, input: [TxIn { previous_output: OutPoint { txid: 0000000000000000000000000000000000000000000000000000000000000000, vout: 4294967295 }, script_sig: Script(OP_PUSHBYTES_3 8ff51b OP_PUSHBYTES_22 315448617368263538434f494e1d00010320a48db852 OP_PUSHBYTES_32 <push past end>), sequence: 4294967295, witness: [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] }], output: [TxOut { value: 19721777, script_pubkey: Script(OP_HASH160 OP_PUSHBYTES_20 011beb6fb8499e075a57027fb0a58384f2d3f784 OP_EQUAL) }, TxOut { value: 0, script_pubkey: Script(OP_RETURN OP_PUSHBYTES_36 aa21a9ed63363f3620ab5e38b8860a50c84050e5ec31af3636bbd73f01ba9f14103100ee) }] }, Transaction { version: 2, lock_time: 1832282, input: [TxIn { previous_output: OutPoint { txid: cbf880f73d421baf0aa4f0d28e63ba00e5bc6bd934b91eb0641354ce5ca42f7e, vout: 0 }, script_sig: Script(OP_PUSHBYTES_22 00146b8dbd32e5deb90d22934e1513bae6e70156cd50), sequence: 4294967294, witness: [[48, 68, 2, 32, 13, 89, 205, 30, 67, 24, 196, 83, 65, 224, 44, 138, 98, 58, 81, 135, 132, 209, 23, 166, 23, 44, 3, 228, 95, 102, 166, 214, 62, 38, 155, 147, 2, 32, 119, 2, 34, 246, 148, 255, 166, 10, 90, 52, 242, 32, 74, 241, 123, 148, 89, 199, 197, 3, 152, 134, 242, 215, 109, 61, 241, 241, 13, 70, 86, 207, 1], [2, 192, 145, 170, 206, 55, 4, 36, 138, 145, 217, 50, 19, 73, 130, 136, 245, 131, 184, 142, 239, 75, 13, 67, 17, 177, 57, 86, 151, 139, 89, 35, 109]] }], output: [TxOut { value: 1667908, script_pubkey: Script(OP_HASH160 OP_PUSHBYTES_20 908ca2b8b49ccf53efa2226afa85f6cc58dfd7e7 OP_EQUAL) }, TxOut { value: 9093, script_pubkey: Script(OP_DUP OP_HASH160 OP_PUSHBYTES_20 42ee67664ce16edefc68ad0e4c5b7ce2fc2ccc18 OP_EQUALVERIFY OP_CHECKSIG) }] }, ...] }
|
||||
```
|
||||
## Buscar fondos
|
||||
|
||||
Puede buscar fondos sin argumentos opcionales usando la función `get_balance` :
|
||||
```rust
|
||||
let balance = rpc.get_balance(None, None).unwrap();
|
||||
println!("Balance: {:?} BTC", balance.as_btc());
|
||||
```
|
||||
Como se muestra, la función `as_btc()` ayuda a mostrar el balance de forma legible:
|
||||
```
|
||||
Balance: 3433.71692741 BTC
|
||||
```
|
||||
## Crear una dirección
|
||||
|
||||
Crear una dirección demuestra cómo hacer una llamada RPC con múltiples argumentos opcionales especificados (por ejemplo, una etiqueta y un tipo de dirección).
|
||||
```rust
|
||||
// Generate a new address
|
||||
let myaddress = rpc
|
||||
.get_new_address(Option::Some("BlockchainCommons"), Option::Some(json::AddressType::Bech32))
|
||||
.unwrap();
|
||||
println!("address: {:?}", myaddress);
|
||||
```
|
||||
Esto también requerirá que lleve la definición `json` al ámbito:
|
||||
```rust
|
||||
use bitcoincore_rpc::{json, Auth, Client, RpcApi};
|
||||
```
|
||||
## Enviar una transacción
|
||||
|
||||
Ahora tiene todo lo que necesita para crear una transacción, que se hará en cinco partes:
|
||||
|
||||
1. Lista de los UXTOS
|
||||
2. Variables de población
|
||||
3. Crear transacción sin procesar
|
||||
4. Transacción por señas
|
||||
5. Enviar transacción
|
||||
|
||||
### 1. Lista UTXOs
|
||||
|
||||
Para iniciar la creación de una transacción, primero se debe encontrar un UTXO a utilizar. Lo siguiente toma el primer UTXO con al menos 0.01 BTC
|
||||
```rust
|
||||
let unspent = rpc
|
||||
.list_unspent(
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
Option::Some(json::ListUnspentQueryOptions {
|
||||
minimum_amount: Option::Some(Amount::from_btc(0.01).unwrap()),
|
||||
maximum_amount: None,
|
||||
maximum_count: None,
|
||||
minimum_sum_amount: None,
|
||||
}),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let selected_tx = &unspent[0];
|
||||
|
||||
println!("selected unspent transaction: {:#?}", selected_tx);
|
||||
```
|
||||
Para ello será necesario ampliar las estructuras:
|
||||
```rust
|
||||
use bitcoincore_rpc::bitcoin::{Address, Amount};
|
||||
```
|
||||
Tenga en cuenta que está pasando cinco variables a `list_unspent`. Las primeras cuatro (`minconf`, `maxconf`, `addresses`, y `include_unsafe`) no se utilizan aquí. El quinto es `query_options`, que no hemos utilizado antes, pero tiene algunas opciones de filtrado potentes, incluyendo la capacidad de mirar sólo a UTXOs con un cierto valor mínimo (o máximo).
|
||||
|
||||
### 2. Poblar variables
|
||||
|
||||
Para comenzar a poblar las variables que necesitará para crear una nueva transacción, cree la entrada desde el `txid` y el `vout` del UTXO que seleccionó:
|
||||
```rust
|
||||
let selected_utxos = json::CreateRawTransactionInput {
|
||||
txid: selected_tx.txid,
|
||||
vout: selected_tx.vout,
|
||||
sequence: None,
|
||||
};
|
||||
```
|
||||
A continuación, puede calcular la cantidad que va a gastar restando una cuota minera de los fondos de la UTXO:
|
||||
```
|
||||
// send all bitcoin in the UTXO except a minor value which will be paid to miners
|
||||
let unspent_amount = selected_tx.amount;
|
||||
let amount = unspent_amount - Amount::from_btc(0.00001).unwrap();
|
||||
```
|
||||
Finalmente, puede crear un mapa hash de la dirección y la cantidad para formar la salida:
|
||||
```
|
||||
let mut output = HashMap::new();
|
||||
output.insert(
|
||||
myaddress.to_string(),
|
||||
amount,
|
||||
);
|
||||
```
|
||||
Otro rasgo es necesario para la variable de salida: `HashMap`. Le permite almacenar valores por clave, que necesita para representar la información `{dirección : cantidad}`.
|
||||
|
||||
```rust
|
||||
use std::collections::HashMap;
|
||||
```
|
||||
### 3. Crear transacción sin procesar
|
||||
|
||||
Está listo para crear una transacción sin procesar:
|
||||
```rust
|
||||
let unsigned_tx = rpc
|
||||
.create_raw_transaction(&[selected_utxos], &output, None, None)
|
||||
.unwrap();
|
||||
```
|
||||
### 4. Firmar la Transacción
|
||||
|
||||
La firma de su transacción se puede hacer con un simple uso de `sign_raw_transaction_with_wallet`:
|
||||
```rust
|
||||
let signed_tx = rpc
|
||||
.sign_raw_transaction_with_wallet(&unsigned_tx, None, None)
|
||||
.unwrap();
|
||||
|
||||
println!("signed tx {:?}", signed_tx.transaction().unwrap());
|
||||
```
|
||||
### 5. Enviar transacción
|
||||
|
||||
Por último, puede transmitir la transacción:
|
||||
```rust
|
||||
let txid_sent = rpc
|
||||
.send_raw_transaction(&signed_tx.transaction().unwrap())
|
||||
.unwrap();
|
||||
|
||||
println!("{:?}", txid_sent);
|
||||
```
|
||||
### Ejecute su código
|
||||
|
||||
Ahora puede ejecutar el código completo desde [src](https://github.com/BlockchainCommons/Learning-Bitcoin-from-the-Command-Line/blob/master/src/18_5_main-sendtx.rs).
|
||||
```
|
||||
$ cargo run
|
||||
Compiling btc_test v0.1.0 (/home/standup/btc_test)
|
||||
warning: unused variable: `unspent_amount`
|
||||
--> src/main.rs:86:9
|
||||
|
|
||||
86 | let unspent_amount = selected_tx.amount;
|
||||
| ^^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_unspent_amount`
|
||||
|
|
||||
= note: `#[warn(unused_variables)]` on by default
|
||||
|
||||
warning: 1 warning emitted
|
||||
|
||||
Finished dev [unoptimized + debuginfo] target(s) in 2.11s
|
||||
Running `target/debug/btc_test`
|
||||
Balance: 0.01031434 BTC
|
||||
address: tb1qx5jz36xgt9q2rkh4daee8ewfj0g5z05v8qsua2
|
||||
selected unspent transaction: ListUnspentResultEntry {
|
||||
txid: 84207ffec658ae29ad1fdd330d8a13613303c3cf281ce628fadeb7636ffb535e,
|
||||
vout: 1,
|
||||
address: Some(
|
||||
tb1qrcf8c29966tvqxhwrtd2se3rj6jeqtll3r46a4,
|
||||
),
|
||||
label: None,
|
||||
redeem_script: None,
|
||||
witness_script: None,
|
||||
script_pub_key: Script(OP_0 OP_PUSHBYTES_20 1e127c28a5d696c01aee1adaa8662396a5902fff),
|
||||
amount: Amount(1029734 satoshi),
|
||||
confirmations: 1246,
|
||||
spendable: true,
|
||||
solvable: true,
|
||||
descriptor: Some(
|
||||
"wpkh([ce0c7e14/0\'/1\'/26\']02c581259ba7e6aef6d7ea23adb08f7c7f10c4c678f2e097a4074639e7685d4805)#j3pctfhf",
|
||||
),
|
||||
safe: true,
|
||||
}
|
||||
unsigned tx Transaction {
|
||||
version: 2,
|
||||
lock_time: 0,
|
||||
input: [
|
||||
TxIn {
|
||||
previous_output: OutPoint {
|
||||
txid: 84207ffec658ae29ad1fdd330d8a13613303c3cf281ce628fadeb7636ffb535e,
|
||||
vout: 1,
|
||||
},
|
||||
script_sig: Script(),
|
||||
sequence: 4294967295,
|
||||
witness: [],
|
||||
},
|
||||
],
|
||||
output: [
|
||||
TxOut {
|
||||
value: 1028734,
|
||||
script_pubkey: Script(OP_0 OP_PUSHBYTES_20 352428e8c85940a1daf56f7393e5c993d1413e8c),
|
||||
},
|
||||
],
|
||||
}
|
||||
signed tx Transaction { version: 2, lock_time: 0, input: [TxIn { previous_output: OutPoint { txid: 84207ffec658ae29ad1fdd330d8a13613303c3cf281ce628fadeb7636ffb535e, vout: 1 }, script_sig: Script(), sequence: 4294967295, witness: [[48, 68, 2, 32, 98, 230, 199, 113, 156, 242, 158, 42, 148, 229, 239, 44, 9, 226, 127, 219, 72, 51, 26, 135, 44, 212, 179, 200, 213, 63, 56, 167, 0, 55, 236, 235, 2, 32, 41, 43, 30, 109, 60, 162, 124, 67, 20, 126, 4, 107, 124, 95, 9, 200, 132, 246, 147, 235, 176, 55, 59, 45, 190, 18, 211, 201, 143, 62, 163, 36, 1], [2, 197, 129, 37, 155, 167, 230, 174, 246, 215, 234, 35, 173, 176, 143, 124, 127, 16, 196, 198, 120, 242, 224, 151, 164, 7, 70, 57, 231, 104, 93, 72, 5]] }], output: [TxOut { value: 1028734, script_pubkey: Script(OP_0 OP_PUSHBYTES_20 352428e8c85940a1daf56f7393e5c993d1413e8c) }] }
|
||||
b0eda3517e6fac69e58ae315d7fe7a1981e3a858996cc1e3135618cac9b79d1a
|
||||
```
|
||||
## Resumen: Acceso a Bitcoind con Rust
|
||||
|
||||
`bitcoincore-rpc` es una caja simple y robusta que le permitirá interactuar con Bitcoin RPC usando Rust. Sin embargo, a partir de esta escritura se ha quedado atrás Bitcoin Core, lo que podría causar algunos problemas con el uso.
|
||||
|
||||
## ¿Qué es lo siguiente?
|
||||
|
||||
Obtenga más información sobre "Cómo hablar con Bitcoin en otros lenguajes" en [18.6: Cómo acceder a Bitcoin con Swift](18_6_Accediendo_a_Bitcoind_con_Swift.md).
|
458
es/18_6_Accediendo_a_Bitcoind_con_Swift.md
Normal file
458
es/18_6_Accediendo_a_Bitcoind_con_Swift.md
Normal file
@ -0,0 +1,458 @@
|
||||
# 18.6: Acceso a Bitcoind con Swift
|
||||
|
||||
> :information_source: **NOTA:** Esta sección se ha añadido recientemente al curso y es un borrador temprano que todavía puede estar pendiente de revisión. Lectura con advertencias.
|
||||
|
||||
Esta sección explica cómo interactuar con `bitcoind` usando el lenguaje de programación Swift y su propio cliente RPC.
|
||||
|
||||
## Configurar Swift en su Mac
|
||||
|
||||
Hasta la fecha, ha construido todos sus entornos de desarrollo de lenguaje de programación alternativo en su nodo virtual de Debian. Sin embargo, esa no es la mejor plataforma para Swift. Aunque hay una versión de Swift disponible para las plataformas de Ubuntu, no está completamente disponible, y funciona un poco diferente de la Swift nativa de Mac. Una "variante" en la parte inferior de esta sección explica cómo configurarlo, pero tenga en cuenta que estará en un territorio desconocido.
|
||||
|
||||
En su lugar, sugerimos crear un entorno Swift óptimo en una Mac. Hay cuatro pasos importantes para hacerlo.
|
||||
|
||||
### 1. Instalar Xcode
|
||||
|
||||
Vas a necesitar `Xcode`, el entorno de desarrollo integrado para Swift y Objective-C. Eso se puede instalar fácilmente yendo a Mac App Store y consiguiendo `Xcode`.
|
||||
|
||||
#### Alternativa: Instalar a mano
|
||||
|
||||
Algunas personas aconsejan no instalar desde el App Store porque es algo como todo o nada; tampoco funcionará si sigue usando Mojave porque quiere evitar las incompatibilidades de Catalina. En ese caso, puede descargar directamente desde el [area de Developer](https://developer.apple.com/download/more/) en Apple.
|
||||
|
||||
Si usted esta usando Mojave, necesitará el archivo `xip` para Xcode 10.3.1. De lo contrario, obtenga el más reciente.
|
||||
|
||||
Una vez descargado, puede hacer clic en el `xip` para extraerlo, y luego mover la aplicación Xcode a la carpeta Aplicaciones.
|
||||
|
||||
(De cualquier manera, debería tener Xcode instalado en su carpeta Aplicaciones al final de este paso.)
|
||||
|
||||
### 2. Instale el servidor Gordian
|
||||
|
||||
También va a necesitar un nodo Bitcoin en su Mac, para que pueda comunicarse con él. Técnicamente, se puede utilizar un nodo remoto y acceder a él con el inicio de sesión RPC y contraseña a través de la red. Sin embargo, le sugerimos que instale un nodo completo directamente en su Mac, porque es la configuración más segura y limpia, asegurando que ninguna de sus comunicaciones salga de su máquina.
|
||||
|
||||
Para instalar fácilmente un nodo completo en su Mac, utilice el servidor de Blockchain Commons [GordianServer for MacOS](https://github.com/BlockchainCommons/GordianServer-macOS). Vea las [instrucciones de instalación](https://github.com/BlockchainCommons/GordianServer-macOS#installation-instructions) en el README, pero generalmente todo lo que tiene que hacer es descargar el archivo actual `dmg`, abrirlo e instalar esa aplicación en su directorio de Aplicaciones también.
|
||||
|
||||
Después, ejecute la aplicación GordianServer y decirle que inicie `Start` Testnet.
|
||||
|
||||
> :link: **TESTNET vs. MAINNET:** O `Start` Mainnet.
|
||||
|
||||
#### 3. Haga accesible su Gordian bitcoin-cli
|
||||
|
||||
Cuando quiera acceder al `bitcoin-cli` creado por GordianServer en su Mac local, puede encontrarlo en `~/.standup/BitcoinCore/bitcoin-VERSION/bin/bitcoin-cli`, por ejemplo `~/.standup/BitcoinCore/bitcoin-0.20.1/bin/bitcoin-cli`.
|
||||
|
||||
Es posible que desee crear un alias para eso:
|
||||
```
|
||||
alias bitcoin-cli="~/.standup/BitcoinCore/bitcoin-0.20.1/bin/bitcoin-cli -testnet"
|
||||
```
|
||||
|
||||
> :link: **TESTNET vs. MAINNET:** Obviamente, el parámetro `-testnet` solo es necesario si se está ejecutando en testnet.
|
||||
|
||||
### 4. Encuentre su información de GordianServer
|
||||
Finalmente necesitará su información `rpcuser` y `rpcpassword`. Eso está en `~/Library/Application Support/Bitcoin/bitcoin.conf` por defecto en Gordian.
|
||||
|
||||
```
|
||||
$ grep rpc ~/Library/Application\ Support/Bitcoin/bitcoin.conf
|
||||
rpcuser=oIjA53JC2u
|
||||
rpcpassword=ebVCeSyyM0LurvgQyi0exWTqm4oU0rZU
|
||||
...
|
||||
```
|
||||
## Construya su conexión a mano
|
||||
|
||||
En el momento de escribir esto, no hay una Biblioteca RPC de Bitcoin actualizada y fácil de usar que sea específica para Swift, algo que pueda introducir e inmediatamente empezar a usar. Por lo tanto, va a hacer algo que nunca ha hecho antes: construir una conexión RPC a mano.
|
||||
|
||||
### Escriba el transmisor RPC
|
||||
|
||||
Esto solo requiere escribir una función que pase comandos RPC a `bitcoind` en el formato correcto:
|
||||
|
||||
```
|
||||
func makeCommand(method: String, param: Any, completionHandler: @escaping (Any?) -> Void) -> Void {
|
||||
```
|
||||
Las conexiones de PC a `bitcoind` usan el protocolo HTML, lo que significa que necesita hacer tres cosas: crear una URL; hacer una URLRequest; e iniciar una URLSession.
|
||||
|
||||
#### 1. Crear una URL
|
||||
|
||||
Dentro de la función, necesita crear una URL desde su IP, puerto, `rpcuser`, `rpcpassword`, y cartera:
|
||||
```
|
||||
let testnetRpcPort = "18332"
|
||||
let nodeIp = "127.0.0.1:\(testnetRpcPort)"
|
||||
let rpcusername = "oIjA53JC2u"
|
||||
let rpcpassword = "ebVCeSyyM0LurvgQyi0exWTqm4oU0rZU"
|
||||
let walletName = ""
|
||||
```
|
||||
La conexión RPC real a Bitcoin Core se construye utilizando una URL del formato "http://rpcusername:rpcpassword@nodeIp/walletName":
|
||||
```
|
||||
let walletUrl = "http://\(rpcusername):\(rpcpassword)@\(nodeIp)/\(walletName)"
|
||||
|
||||
let url = URL(string: walletUrl)
|
||||
```
|
||||
Esto significa que las variables de muestra resultan en la siguiente URL:
|
||||
```
|
||||
http://oIjA53JC2u:ebVCeSyyM0LurvgQyi0exWTqm4oU0rZU@127.0.0.1:18332/
|
||||
```
|
||||
Que debería parecerse mucho a la URL utilizada en algunas de las secciones anteriores para conexiones RPC.
|
||||
|
||||
#### 2. Crear una URLRequest
|
||||
|
||||
Con esa URL en su mano, ahora puede crear una URLRequest, con el método `POST` y el tipo de contenido `text/plain`. El cuerpo HTTP es entonces el objeto JSON familiar que ha estado enviando cada vez que se conectas directamente a los puertos RPC de Bitcoin Core, como se demostró por primera vez al usar Curl en [§4.4](04_4__Interludio_Usando_Curl.md).
|
||||
|
||||
```
|
||||
var request = URLRequest(url: url!)
|
||||
request.httpMethod = "POST"
|
||||
request.setValue("text/plain", forHTTPHeaderField: "Content-Type")
|
||||
request.httpBody = "{\"jsonrpc\":\"1.0\",\"id\":\"curltest\",\"method\":\"\(method)\",\"params\":[\(param)]}".data(using: .utf8)
|
||||
```
|
||||
#### 3. Crear una URLSession
|
||||
|
||||
Finalmente, está listo para construir una URLSession alrededor de su URLRequest.
|
||||
```
|
||||
let session = URLSession(configuration: .default)
|
||||
let task = session.dataTask(with: request as URLRequest) { data, response, error in
|
||||
```
|
||||
El manejador de completitud para `dataTask` necesita comprobar si hay errores:
|
||||
```
|
||||
do {
|
||||
|
||||
if error != nil {
|
||||
|
||||
//Handle the error
|
||||
|
||||
} else {
|
||||
```
|
||||
Y luego analiza los datos que está recibiendo. Aquí, está leyendo de los resultados de JSON en un `NSDictionary`:
|
||||
```
|
||||
if let urlContent = data {
|
||||
|
||||
do {
|
||||
|
||||
let json = try JSONSerialization.jsonObject(with: urlContent, options: JSONSerialization.ReadingOptions.mutableLeaves) as! NSDictionary
|
||||
```
|
||||
Después de eso, hay más manejo de errores y más manejo de errores y entonces usted puede eventualmente devolver el diccionario `result` usando el `completionHandler` que definió para la nueva función `makeCommand` :
|
||||
```
|
||||
if let errorCheck = json["error"] as? NSDictionary {
|
||||
|
||||
if let errorMessage = errorCheck["message"] as? String {
|
||||
|
||||
print("FAILED")
|
||||
print(errorMessage)
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
let result = json["result"]
|
||||
completionHandler(result)
|
||||
|
||||
}
|
||||
|
||||
} catch {
|
||||
|
||||
//Handle error here
|
||||
|
||||
}
|
||||
```
|
||||
Por supuesto que eventualmente tiene que decirle a la `task` para empezar:
|
||||
```
|
||||
task.resume()
|
||||
```
|
||||
Y eso es "todo" lo que hay que hacer para dicha interacción RPC a mano usando un lenguaje de programación como Swift.
|
||||
|
||||
> :pray: **THANKS:** Gracias a @Fonta1n3 quien facilitó el [código principal](https://github.com/BlockchainCommons/Learning-Bitcoin-from-the-Command-Line/issues/137) para nuestro transmisor RPC.
|
||||
|
||||
### Hacer una llamada RPC
|
||||
|
||||
Después de haber escrito la función `makeCommand` RPC, puede enviar una llamada RPC ejecutándola. Aquí está `getblockchaininfo`:
|
||||
```
|
||||
let method = "getblockchaininfo"
|
||||
let param = ""
|
||||
|
||||
makeCommand(method: method,param: param) { result in
|
||||
|
||||
print(result!)
|
||||
|
||||
}
|
||||
```
|
||||
### Hacer una llamada RPC con argumentos
|
||||
|
||||
De manera similar, podría tomar el conteo de bloques actual de esa información y usarlo para (redundantemente) obtener el hash del bloque actual, usando el parámetro `param` :
|
||||
```
|
||||
let method = "getblockchaininfo"
|
||||
let param = ""
|
||||
|
||||
makeCommand(method: method,param: param) { result in
|
||||
|
||||
let blockinfo = result as! NSDictionary
|
||||
let block = blockinfo["blocks"] as! NSNumber
|
||||
|
||||
let method = "getblockhash"
|
||||
makeCommand(method: method,param: block) { result in
|
||||
print("Blockhash for \(block) is \(result!)")
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
### Ejecute su código
|
||||
|
||||
El código completo está disponible en el [directorio src](https://github.com/BlockchainCommons/Learning-Bitcoin-from-the-Command-Line/blob/master/src/18_6_getinfo.playground). Cárgalo en su entorno Xcode y luego "Editor -> Run Playground" y obtendrá resultados como:
|
||||
```
|
||||
{
|
||||
bestblockhash = 00000000000000069725608ebc5b59e520572a8088cbc57ffa5ba87b7f300ac7;
|
||||
blocks = 1836745;
|
||||
chain = test;
|
||||
chainwork = 0000000000000000000000000000000000000000000001cc3e9f8e0bc6b71196;
|
||||
difficulty = "16508683.81195478";
|
||||
headers = 1836745;
|
||||
initialblockdownload = 0;
|
||||
mediantime = 1601416765;
|
||||
pruned = 0;
|
||||
"size_on_disk" = 28205538354;
|
||||
softforks = {
|
||||
bip34 = {
|
||||
active = 1;
|
||||
height = 21111;
|
||||
type = buried;
|
||||
};
|
||||
bip65 = {
|
||||
active = 1;
|
||||
height = 581885;
|
||||
type = buried;
|
||||
};
|
||||
bip66 = {
|
||||
active = 1;
|
||||
height = 330776;
|
||||
type = buried;
|
||||
};
|
||||
csv = {
|
||||
active = 1;
|
||||
height = 770112;
|
||||
type = buried;
|
||||
};
|
||||
segwit = {
|
||||
active = 1;
|
||||
height = 834624;
|
||||
type = buried;
|
||||
};
|
||||
};
|
||||
verificationprogress = "0.999999907191804";
|
||||
warnings = "Warning: unknown new rules activated (versionbit 28)";
|
||||
}
|
||||
Blockhash for 1836745 is 00000000000000069725608ebc5b59e520572a8088cbc57ffa5ba87b7f300ac7
|
||||
```
|
||||
## Buscar fondos
|
||||
|
||||
Con su nuevo `makeCommand` para funciones RPC, también puede ejecutar un comando como `getwalletinfo` o `getbalance`:
|
||||
```
|
||||
var method = "getwalletinfo"
|
||||
var param = ""
|
||||
|
||||
makeCommand(method: method,param: param) { result in
|
||||
|
||||
print(result!)
|
||||
|
||||
}
|
||||
|
||||
method = "getbalance"
|
||||
makeCommand(method: method,param: param) { result in
|
||||
|
||||
let balance = result as! NSNumber
|
||||
print("Balance is \(balance)")
|
||||
|
||||
}
|
||||
```
|
||||
Lo que nos dice:
|
||||
```
|
||||
Balance is 0.01
|
||||
{
|
||||
"avoid_reuse" = 0;
|
||||
balance = "0.01";
|
||||
hdseedid = bf493318f548df8e25c390d6a7f70758fd6b3668;
|
||||
"immature_balance" = 0;
|
||||
keypoololdest = 1599723938;
|
||||
keypoolsize = 999;
|
||||
"keypoolsize_hd_internal" = 1000;
|
||||
paytxfee = 0;
|
||||
"private_keys_enabled" = 1;
|
||||
scanning = 0;
|
||||
txcount = 1;
|
||||
"unconfirmed_balance" = 0;
|
||||
walletname = "";
|
||||
walletversion = 169900;
|
||||
}
|
||||
```
|
||||
## Crear una dirección
|
||||
|
||||
Crear una dirección es bastante simple, pero ¿qué pasa con crear una dirección heredada con una etiqueta específica? Eso requiere dos parámetros en su llamada RPC.
|
||||
|
||||
Dado que la función simplista `makeCommand` en esta sección simplemente pasa su `param`s como las entrañas de un objeto JSON, todo lo que tiene que hacer es formatear correctamente esas entrañas. Esta es una manera de hacerlo:
|
||||
```
|
||||
method = "getnewaddress"
|
||||
param = "\"learning-bitcoin\", \"legacy\""
|
||||
|
||||
makeCommand(method: method,param: param) { result in
|
||||
|
||||
let address = result as! NSString
|
||||
print(address)
|
||||
}
|
||||
```
|
||||
Ejecutar esto en el entorno de Xcode produce un resultado:
|
||||
```
|
||||
mt3ZRsmXHVMMqYQPJ8M74QjF78bmqrdHZF
|
||||
```
|
||||
Ese resultado es obviamente una dirección Legacy; su etiqueta se puede comprobar desde la línea de comandos:
|
||||
```
|
||||
$ bitcoin-cli getaddressesbylabel "learning-bitcoin"
|
||||
{
|
||||
"mt3ZRsmXHVMMqYQPJ8M74QjF78bmqrdHZF": {
|
||||
"purpose": "receive"
|
||||
}
|
||||
}
|
||||
```
|
||||
Éxito!
|
||||
|
||||
> :information_source: **NOTA:** Como decimos a menudo en estos ejemplos de codificación, un programa del mundo real sería mucho más sofisticado. En particular, querrá ser capaz de enviar un objeto JSON real como parámetro, y luego tener su programa `makeCommand` para analizarlo e introducirlo en la URLSession apropiadamente. Lo que tenemos aquí maximiza la legibilidad y la simplicidad sin centrarse en la facilidad de uso.
|
||||
|
||||
## Enviar una transacción
|
||||
|
||||
Como de costumbre, el envío de una transacción (la forma difícil) es un proceso de varios pasos:
|
||||
0. Generar o recibir una dirección de recepción
|
||||
1. Encontrar una UTXO no utilizada
|
||||
2. Crear una transacción en bruto
|
||||
3. Firmar la transacción en bruto
|
||||
4. Envío de la transacción en bruto
|
||||
|
||||
Usará la `dirección` que generó en el paso anterior como su destinatario.
|
||||
|
||||
### 1. Encuentre un UTXO no gastado
|
||||
|
||||
El RPC `listunspent` le permite encontrar su UTXO:
|
||||
```
|
||||
method = "listunspent"
|
||||
param = ""
|
||||
|
||||
makeCommand(method: method,param: param) { result in
|
||||
|
||||
let unspent = result as! NSArray
|
||||
let utxo = unspent[0] as! NSDictionary
|
||||
|
||||
let txid = utxo["txid"] as! NSString
|
||||
let vout = utxo["vout"] as! NSInteger
|
||||
let amount = utxo["amount"] as! NSNumber
|
||||
let new_amount = amount.floatValue - 0.0001
|
||||
```
|
||||
Como en otros ejemplos, usted va a tomar arbitrariamente el 0º UTXO, y usará las `txid`, `vout`, y `amount` de ella.
|
||||
|
||||
> :information_source **NOTA:** Una vez más, un programa de la vida real sería mucho más sofisticado.
|
||||
|
||||
### 2. Crear una transacción sin procesar
|
||||
|
||||
Crear una transacción en bruto es la cosa más complicada porque necesita obtener todos sus objetos JSON, matrices y comillas correctas. He aquí cómo hacerlo en Swift, usando el formato muy básico `param` del transmisor:
|
||||
```
|
||||
method = "createrawtransaction"
|
||||
param="[ { \"txid\": \"\(txid)\", \"vout\": \(vout) } ], { \"\(address)\": \(new_amount)}"
|
||||
makeCommand(method: method,param: param) { result in
|
||||
|
||||
let hex = result as! NSString
|
||||
```
|
||||
### 3. Firme la transacción cruda
|
||||
|
||||
La firma de su transacción sólo requiere que ejecute la transacción `signrawctionwithwallet` RPC, usando su nuevo `hex`:
|
||||
```
|
||||
method = "signrawtransactionwithwallet"
|
||||
param = "\"\(hex)\""
|
||||
|
||||
makeCommand(method: method,param: param) { result in
|
||||
|
||||
let signedhexinfo = result as! NSDictionary
|
||||
let signedhex = signedhexinfo["hex"] as! NSString
|
||||
```
|
||||
### 4. Enviar la transacción sin procesar
|
||||
|
||||
El envío de su transacción es igualmente simple:
|
||||
```
|
||||
method = "sendrawtransaction"
|
||||
param = "\"\(signedhex)\""
|
||||
|
||||
makeCommand(method: method,param: param) { result in
|
||||
|
||||
let new_txid = result as! NSString
|
||||
print("TXID: \(new_txid)")
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
El código para este remitente de transacción se puede encontrar en el [src directory](https://github.com/BlockchainCommons/Learning-Bitcoin-from-the-Command-Line/blob/master/src/18_6_sendtx.playground).
|
||||
|
||||
## Usar Swift de otras maneras
|
||||
|
||||
Eso cubre nuestras discusiones habituales sobre la programación de Bitcoin RPC en un lenguaje, pero Swift es un lenguaje particularmente importante ya que se puede implementar en dispositivos móviles, uno de los principales lugares para carteras. Como tal, puede considerar otras bibliotecas:
|
||||
|
||||
* El entorno de Blockchain Commons [ios-Bitcoin framework](https://github.com/BlockchainCommons/iOS-Bitcoin) convierte la biblioteca Libbitcoin de C++ a Swift
|
||||
* [Libwally Swift](https://github.com/blockchain/libwally-swift) es una envoltura de Swift para Libwally
|
||||
|
||||
## Resumen: Acceso a Bitcoind con Swift
|
||||
|
||||
Swift es un robusto lenguaje de programación moderno que desafortunadamente aún no tiene bibliotecas RPC fáciles de usar ... lo que nos dio la oportunidad de escribir una función de acceso RPC propia. Con eso en la mano, puede interactuar con `bitcoind` en un Mac o construir aplicaciones complementarias en un iPhone, que es una combinación perfecta para el trabajo Bitcoin desconectado o `airgapped`.
|
||||
|
||||
## ¿Qué es lo siguiente?
|
||||
|
||||
Aprenda acerca de Lightning en [Capítulo 19: Entendiendo su configuración de Lightning](19_0_Entendiendo_Su_Configuracion_Lightning.md).
|
||||
|
||||
## Variante: Implementar Swift en Ubuntu
|
||||
|
||||
Si prefiere implementar Swift en Ubuntu, puede hacerlo, aunque la funcionalidad no es la misma. Parte del código en este capítulo probablemente generará errores que necesitará resolver, y también necesitará hacer más trabajo para enlazar en bibliotecas C.
|
||||
|
||||
Para empezar, instale algunas necesarias bibliotecas Debian :
|
||||
```
|
||||
$ sudo apt-get install clang
|
||||
$ sudo apt-get install libcurl4 libpython2.7 libpython2.7-dev
|
||||
```
|
||||
Si está usando Debian 10 o superior (y realmente debería estarlo), también necesitará poner en una fecha anterior algunas bibliotecas para obtener versiones anteriores:
|
||||
```
|
||||
$ sudo apt-get install libtinfo5 libncurses5
|
||||
```
|
||||
Luego puede descargar e instalar Swift:
|
||||
```
|
||||
$ wget https://swift.org/builds/swift-5.1.3-release/ubuntu1804/swift-5.1.3-RELEASE/swift-5.1.3-RELEASE-ubuntu18.04.tar.gz
|
||||
$ tar xzfv swift-5.1.3-RELEASE-ubuntu18.04.tar.gz
|
||||
$ sudo mv swift-5.1.3-RELEASE-ubuntu18.04 /usr/share/swift
|
||||
```
|
||||
Para poder usar su nueva configuración de Swift, y necesita actualizar su `PATH`en su `.bashrc`:
|
||||
```
|
||||
$ echo "export PATH=/usr/share/swift/usr/bin:$PATH" >> ~/.bashrc
|
||||
$ source ~/.bashrc
|
||||
```
|
||||
Ahora puede probar Swift con el argumento `-versión` :
|
||||
```
|
||||
$ swift --version
|
||||
Swift version 5.1.3 (swift-5.1.3-RELEASE)
|
||||
Target: x86_64-unknown-linux-gnu
|
||||
```
|
||||
### Crear un proyecto
|
||||
Una vez que haya instalado Swift en su máquina Ubuntu, puede crear proyectos con el comando `package init` :
|
||||
```
|
||||
$ mkdir swift-project
|
||||
$ cd swift-project/
|
||||
/swift-project$ swift package init --type executable
|
||||
Creating executable package: swift-project
|
||||
Creating Package.swift
|
||||
Creating README.md
|
||||
Creating .gitignore
|
||||
Creating Sources/
|
||||
Creating Sources/swift-project/main.swift
|
||||
Creating Tests/
|
||||
Creating Tests/LinuxMain.swift
|
||||
Creating Tests/swift-projectTests/
|
||||
Creating Tests/swift-projectTests/swift_projectTests.swift
|
||||
Creating Tests/swift-projectTests/XCTestManifests.swift
|
||||
```
|
||||
Luego editará `Sources/.../main.swift` y cuando esté listo para compilar, puede usar el comando `build` :
|
||||
```
|
||||
$ swift build
|
||||
[4/4] Linking swift-project
|
||||
```
|
||||
Finalmente, podrá ejecutar el programa desde el directorio `.build/debug` :
|
||||
```
|
||||
$ .build/debug/swift-project
|
||||
Hello, world!
|
||||
```
|
||||
Buena suerte!
|
30
es/19_0_Entendiendo_Su_Configuracion_Lightning.md
Normal file
30
es/19_0_Entendiendo_Su_Configuracion_Lightning.md
Normal file
@ -0,0 +1,30 @@
|
||||
# Capítulo 19: Entendiendo la configuración de Lightning
|
||||
|
||||
> :information_source: **NOTA:** Este es un borrador en progreso, por lo que puedo obtener algunos comentarios de los primeros revisores. Todavía no está listo para aprender.
|
||||
|
||||
El capítulo anterior concluyó nuestro trabajo con Bitcoin propiamente dicho, a través de CLI, scripting y lenguajes de programación.
|
||||
Sin embargo, hay muchas otras utilidades dentro del ecosistema de Bitcoin: este capítulo y el siguiente cubren lo que puede ser el más grande e importante: Lightning Network.
|
||||
Aquí comenzará a trabajar con la interfaz de línea de comandos `lightning-cli`, entendiendo la configuración de c-lightning y sus características, incluidos algunos ejemplos y la configuración básica.
|
||||
|
||||
## Objetivos de este capítulo
|
||||
|
||||
Después de trabajar en este capítulo, un desarrollador podrá:
|
||||
|
||||
* Evaluar que un nodo c-lightning está instalado y actualizado
|
||||
* Realizar comandos básicos de billetera Lightning
|
||||
* Crea un canal de Lightning
|
||||
|
||||
Los objetivos de apoyo incluyen la capacidad de:
|
||||
|
||||
* Comprender la configuración básica de Lightning
|
||||
* Comprender la interacción de los nodos Lightning
|
||||
* Entender cómo usasr Lightning
|
||||
|
||||
## Tabla de contenido
|
||||
|
||||
* [Sección uno: Verificación de la configuración de c-lightning](19_1_Verificando_Su_Configuracion_Lightning.md)
|
||||
* [Sección dos: Conozca su configuración de c-lightning](19_2_Conociendo_Su_Configuracion_Lightning.md)
|
||||
* [Interludio: Acceso a un segundo nodo Lightning](19_2_Interludio_Accediendo_a_un_Segundo_Nodo_Lightning.md)
|
||||
* [Sección tres: Creación de un canal Lightning](19_3_Creando_un_Canal_en_Lightning.md)
|
||||
|
||||
|
265
es/19_1_Verificando_Su_Configuracion_Lightning.md
Normal file
265
es/19_1_Verificando_Su_Configuracion_Lightning.md
Normal file
@ -0,0 +1,265 @@
|
||||
# 19.1: Creación de una configuración de c-lightning
|
||||
|
||||
> :information_source: **NOTA :** Esta sección se agregó recientemente al curso y es un borrador inicial que aún puede estar pendiente de revisión. Lectura con advertencias.
|
||||
|
||||
En esta sección, instalará y verificará c-lightning, su utilidad para acceder a Lightning Network.
|
||||
|
||||
> :book: ***¿Qué es Lightning Network?*** Lightning Network es una red descentralizada que utiliza la funcionalidad de contrato inteligente de la cadena de bloques de Bitcoin para permitir pagos instantáneos a través de una red de participantes. Lightning está construido como un protocolo de capa 2 que interactúa con Bitcoin para permitir a los usuarios intercambiar sus bitcoins "fuera de la cadena".
|
||||
|
||||
> :book: ***¿Qué es un protocolo de capa 2?*** La capa 2 se refiere a un protocolo secundario construido sobre el sistema de cadena de bloques de Bitcoin. El objetivo principal de estos protocolos es resolver la velocidad de transacción y las dificultades de escalado que están presentes en Bitcoin: Bitcoin no es capaz de procesar miles de transacciones por segundo (TPS), por lo que se han creado protocolos de capa 2 para resolver el problema de escalabilidad de blockchain. Estas soluciones también se conocen como soluciones de escalado "fuera de la cadena".
|
||||
|
||||
## Instalar C-Lightning
|
||||
|
||||
Si utilizó [Bitcoin Standup Scripts](https://github.com/BlockchainCommons/Bitcoin-Standup-Scripts), es posible que ya haya instalado Lightning al comienzo de este curso. Puede probar esto viendo si `lightningd` se está ejecutando:
|
||||
|
||||
```
|
||||
$ ps auxww | grep -i lightning
|
||||
standup 31213 0.0 0.2 24144 10424 pts/0 S 15:38 0:00 lightningd --testnet
|
||||
standup 31214 0.0 0.1 22716 7444 pts/0 S 15:38 0:00 /usr/local/bin/../libexec/c-lightning/plugins/autoclean
|
||||
standup 31215 0.0 0.2 22992 8248 pts/0 S 15:38 0:00 /usr/local/bin/../libexec/c-lightning/plugins/bcli
|
||||
standup 31216 0.0 0.1 22756 7604 pts/0 S 15:38 0:00 /usr/local/bin/../libexec/c-lightning/plugins/keysend
|
||||
standup 31217 0.0 0.1 22776 7648 pts/0 S 15:38 0:00 /usr/local/bin/../libexec/c-lightning/plugins/pay
|
||||
standup 31218 0.0 0.1 22720 7652 pts/0 S 15:38 0:00 /usr/local/bin/../libexec/c-lightning/plugins/txprepare
|
||||
standup 31219 0.0 0.1 22744 7716 pts/0 S 15:38 0:00 /usr/local/bin/../libexec/c-lightning/plugins/spenderp
|
||||
standup 31227 0.0 0.1 22748 7384 pts/0 SL 15:38 0:00 /usr/local/libexec/c-lightning/lightning_hsmd
|
||||
standup 31228 0.0 0.2 23044 8192 pts/0 S 15:38 0:00 /usr/local/libexec/c-lightning/lightning_connectd
|
||||
standup 31229 0.0 0.1 22860 7556 pts/0 S 15:38 0:00 /usr/local/libexec/c-lightning/lightning_gossipd
|
||||
standup 32072 0.0 0.0 6208 888 pts/0 S+ 15:50 0:00 grep -i lightning
|
||||
```
|
||||
|
||||
Si no es así, deberá instalarlo ahora. Desafortunadamente, si está utilizando Debian, deberá instalarlo a mano, compilando el código fuente, pero aún así debería ser bastante simple si sigue estas instrucciones. Si se encuentra en un sistema Ubuntu estándar, intente [Instalar desde Ubuntu ppa](#variant-install-from-ubuntu-ppa), y siempre puede intentar [Instalar binarios precompilados](#variant-install-binarios precompilados).
|
||||
|
||||
> :book: ***¿Qué es c-lightning?*** Hay tres implementaciones diferentes de Lightning en la actualidad: c-lightning, LND y Eclair. Todos deben ser funcionalmente compatibles, basados en las mismas [RFC de BOLT](https://github.com/lightningnetwork/lightning-rfc/blob/master/00-introduction.md), pero sus detalles de implementación pueden ser diferentes. Hemos elegido c-lightning como base de nuestro curso porque también es parte del mismo [Elements Project](https://github.com/ElementsProject) que también contiene Libwally.
|
||||
|
||||
### Compilar el código fuente de c-lightning
|
||||
|
||||
La instalación de Lightning desde el código fuente debería ser bastante simple si sigue estas instrucciones.
|
||||
|
||||
_Probablemente_ desea hacer esto en un nodo sin podar, ya que trabajar con nodos podados en Lightning puede causar problemas con la instalación y el uso. Si configuró su nodo al principio de este curso para podarlo, es posible que desee reemplazarlo con un nodo sin podar ahora. (Si está usando testnet, debería poder usar el mismo tipo de máquina que usó para su nodo podado).
|
||||
|
||||
> :warning:**ADVERTENCIA:** En realidad, puede ejecutar c-lightning en un nodo podado. Sin embargo, como señala el [repositorio Lightning](https://github.com/ElementsProject/lightning#pruning), puede haber problemas. Para que funcione, debe asegurarse de que su nodo Lightning solo intente actualizar la información de los bloques que su nodo Bitcoin no ha eliminado. Para hacerlo, debe asegurarse de (1) que su nodo Bitcoin esté completamente actualizado antes de iniciar su nodo Lightning por primera vez; y (2) que su nodo Lightning nunca se quede muy atrás de su nodo Bitcoin (para una poda estándar de 550 bloques, nunca se puede apagar durante 4 o más días). Entonces, puede hacerlo, pero presenta cierto peligro, lo cual no es una buena idea si está ejecutando un servicio de producción.
|
||||
|
||||
Con eso, está listo para instalar Lightning:
|
||||
|
||||
Primero, instale las dependencias, incluidos los requisitos de desarrollo.
|
||||
|
||||
```
|
||||
$ sudo apt-get install -y \
|
||||
autoconf automake build-essential git libtool libgmp-dev \
|
||||
libsqlite3-dev python3 python3-mako net-tools zlib1g-dev libsodium-dev \
|
||||
gettext
|
||||
$ sudo apt-get install -y valgrind python3-pip libpq-dev
|
||||
```
|
||||
|
||||
Estos pueden llevar un tiempo, porque hay varios y algunos son grandes.
|
||||
|
||||
En segundo lugar, clona el repositorio de Lightning:
|
||||
|
||||
```
|
||||
$ cd ~
|
||||
$ git clone https://github.com/ElementsProject/lightning.git
|
||||
$ cd lightning
|
||||
```
|
||||
|
||||
Ahora puede usar el `pip3` que instaló para instalar requisitos adicionales para la compilación y configurarlo todo:
|
||||
|
||||
```
|
||||
$ pip3 install -r requirements.txt
|
||||
$ ./configure
|
||||
```
|
||||
|
||||
Ahora compila. Esto también puede llevar algún tiempo dependiendo de su máquina.
|
||||
|
||||
```
|
||||
$ make
|
||||
```
|
||||
|
||||
Luego, todo lo que necesita hacer es instalar:
|
||||
```
|
||||
$ sudo make install
|
||||
```
|
||||
|
||||
## Compruebe su instalacion
|
||||
Puede confirmar que ha instalado lightningd correctamente usando el parámetro `help`:
|
||||
|
||||
|
||||
## Ejecutar lightining
|
||||
|
||||
Comenzará su exploración de la red Lightning con el comando `lightning-cli`. Sin embargo, `lightningd` _ debe_ estar ejecutándose para usar` lightning-cli`, ya que `lightning-cli` envía comandos JSON-RPC al` lightningd` (todo igual que con `bitcoin-cli` y` bitcoind`).
|
||||
|
||||
Si instaló `c-lightning` a mano, ahora deberá iniciarlo:
|
||||
|
||||
```
|
||||
$ nohup lightningd --testnet &
|
||||
```
|
||||
|
||||
### Ejecutar lightningd como servicio
|
||||
|
||||
Si lo prefiere, puede instalar `lightningd` como un servicio que se ejecutará cada vez que reinicie su máquina. Lo siguiente lo hará y comenzará a ejecutarse de inmediato:
|
||||
|
||||
```
|
||||
$ lightningd --help
|
||||
lightningd: WARNING: default network changing in 2020: please set network=testnet in config!
|
||||
Usage: lightningd
|
||||
A bitcoin lightning daemon (default values shown for network: testnet).
|
||||
--conf=<file> Specify configuration file
|
||||
--lightning-dir=<dir> Set base directory: network-specific
|
||||
subdirectory is under here
|
||||
(default: "/home/javier/.lightning")
|
||||
--network <arg> Select the network parameters (bitcoin,
|
||||
testnet, regtest, litecoin or
|
||||
litecoin-testnet) (default: testnet)
|
||||
--testnet Alias for --network=testnet
|
||||
--signet Alias for --network=signet
|
||||
--mainnet Alias for --network=bitcoin
|
||||
|
||||
```
|
||||
|
||||
### Habilitar conexiones remotas
|
||||
|
||||
Si tiene algún tipo de firewall, deberá abrir el puerto 9735 para permitir que otros nodos Lightning se comuniquen con usted.
|
||||
|
||||
Si usa `ufw` de Bitcoin Standup, esto se hace de la siguiente manera:
|
||||
|
||||
```
|
||||
$ sudo ufw allow 9735
|
||||
```
|
||||
|
||||
## Verificar su nodo
|
||||
|
||||
Puede comprobar si su nodo Lightning está listo para funcionar comparando la salida de `bitcoin-cli getblockcount` con el resultado de` blockheight` de `lightning-cli getinfo`.
|
||||
|
||||
|
||||
```
|
||||
$ bitcoin-cli -testnet getblockcount
|
||||
1838587
|
||||
$ lightning-cli --testnet getinfo
|
||||
{
|
||||
"id": "03d4592f1244cd6b5a8bb7fba6a55f8a91591d79d3ea29bf8e3c3a405d15db7bf9",
|
||||
"alias": "HOPPINGNET",
|
||||
"color": "03d459",
|
||||
"num_peers": 0,
|
||||
"num_pending_channels": 0,
|
||||
"num_active_channels": 0,
|
||||
"num_inactive_channels": 0,
|
||||
"address": [
|
||||
{
|
||||
"type": "ipv4",
|
||||
"address": "74.207.240.32",
|
||||
"port": 9735
|
||||
},
|
||||
{
|
||||
"type": "ipv6",
|
||||
"address": "2600:3c01::f03c:92ff:fe48:9ddd",
|
||||
"port": 9735
|
||||
}
|
||||
],
|
||||
"binding": [
|
||||
{
|
||||
"type": "ipv6",
|
||||
"address": "::",
|
||||
"port": 9735
|
||||
},
|
||||
{
|
||||
"type": "ipv4",
|
||||
"address": "0.0.0.0",
|
||||
"port": 9735
|
||||
}
|
||||
],
|
||||
"version": "v0.9.1-96-g6f870df",
|
||||
"blockheight": 1838587,
|
||||
"network": "testnet",
|
||||
"msatoshi_fees_collected": 0,
|
||||
"fees_collected_msat": "0msat",
|
||||
"lightning-dir": "/home/standup/.lightning/testnet"
|
||||
}
|
||||
```
|
||||
|
||||
En este caso, el `blockheight` se muestra como` 1838587` por ambas salidas.
|
||||
|
||||
En su lugar, puede obtener un error, dependiendo de la situación precisa.
|
||||
|
||||
Si el nodo de Bitcoin aún se sincroniza con la red de bitcoin, debería ver un mensaje como este:
|
||||
|
||||
```
|
||||
"warning_bitcoind_sync": "Bitcoind is not up-to-date with network."
|
||||
```
|
||||
|
||||
Si su demonio lightning no está actualizado, debería ver un mensaje como este:
|
||||
|
||||
```
|
||||
"warning_lightningd_sync": "Still loading latest blocks from bitcoind."
|
||||
```
|
||||
|
||||
Si intentó ejecutar en una cadena de bloques podada donde el nodo Bitcoin no estaba actualizado cuando inició el nodo Lightning, obtendrá mensajes de error en su registro como este:
|
||||
|
||||
```
|
||||
bitcoin-cli -testnet getblock 0000000000000559febee77ab6e0be1b8d0bef0f971c7a4bee9785393ecef451 0 exited with status 1
|
||||
```
|
||||
|
||||
## Crear alias
|
||||
|
||||
Sugerimos crear algunos alias para facilitar el uso de c-lightning.
|
||||
|
||||
Puede hacerlo colocándolos en su `.bash_profile`.
|
||||
|
||||
```
|
||||
cat >> ~/.bash_profile <<EOF
|
||||
alias lndir="cd ~/.lightning/" #linux default c-lightning path
|
||||
alias lnc="lightning-cli"
|
||||
alias lnd="lightningd"
|
||||
alias lninfo='lightning-cli getinfo'
|
||||
EOF
|
||||
```
|
||||
|
||||
Después de ingresar estos alias, puede `source ~/.bash_profile` para ingresarlos o simplemente cerrar sesión y volver a ingresar.
|
||||
|
||||
Tenga en cuenta que estos alias incluyen atajos para ejecutar `lightning-cli`, para ejecutar` lightningd` y para ir al directorio c-lightning. Estos alias están destinados principalmente a facilitarle la vida. Le sugerimos que cree otros alias para facilitar el uso de comandos frecuentes (y argumentos) y minimizar los errores. Los alias de este tipo pueden ser aún más útiles si tiene una configuración compleja en la que ejecuta regularmente comandos asociados con Mainnet, con Testnet, _y_ con Regtest, como se explica más adelante.
|
||||
|
||||
Dicho esto, el uso de estos alias en _este_ documento podría oscurecer accidentalmente las lecciones centrales que se enseñan sobre c-lightning, por lo que continuaremos mostrando los comandos completos; ajuste para su propio uso según corresponda.
|
||||
|
||||
## Opcional: Modifique sus tipos de servidor
|
||||
|
||||
> :link: **TESTNET vs MAINNET:** Cuando configura su nodo, elige crearlo como un nodo Mainnet, Testnet o Regtest. Aunque este documento presupone una configuración de testnet, vale la pena comprender cómo puede acceder y utilizar los otros tipos de configuración, ¡incluso todos en la misma máquina! Pero, si es un usuario nuevo, omita esto, ya que no es necesario para una configuración básica.
|
||||
|
||||
Cuando se inicia lightningd, generalmente lee un archivo de configuración cuya ubicación depende de la red que esté utilizando (predeterminado: `~/.lightning/testnet/config`). Esto se puede cambiar con los indicadores `–conf` y` –lightning-dir`.
|
||||
|
||||
```
|
||||
~/.lightning/testnet$ ls -la config
|
||||
-rw-rw-r-- 1 user user 267 jul 12 17:08 config
|
||||
```
|
||||
|
||||
También hay un archivo de configuración general (predeterminado: `~/.lightning/config`). Si desea ejecutar varios tipos diferentes de nodos simultáneamente, debe dejar el indicador testnet (o regtest) fuera de este archivo de configuración. A continuación, debe elegir si está utilizando la red principal, la red de prueba o su registro cada vez que ejecute `lightningd` o` lightning-cli`.
|
||||
|
||||
Es posible que su configuración no tenga ningún archivo de configuración: c-lightning se ejecutará con una buena configuración predeterminada sin ellos.
|
||||
|
||||
## Resumen: Verificación de su configuración Lightning
|
||||
|
||||
Antes de comenzar a jugar con Lightning, debe asegurarse de que sus alias estén configurados, su `lightningd` se esté ejecutando y su nodo esté sincronizado. Es posible que también desee configurar algún acceso a configuraciones alternativas de iluminación en otras redes.
|
||||
|
||||
## ¿Que sigue?
|
||||
|
||||
Continúe "Comprender su configuración Lightning" con [§19.2: Conocer su configuración Lightning](19_2_Conociendo_Su_Configuracion_Lightning.md).
|
||||
|
||||
## Variante: instalar desde Ubuntu ppa
|
||||
|
||||
Si está usando una versión de Ubuntu que no sea Debian, puede instalar c-lightning usando [Ubuntu ppa](https://launchpad.net/~lightningnetwork/+archive/ubuntu/ppa):
|
||||
|
||||
```
|
||||
$ sudo apt-get install -y software-properties-common
|
||||
$ sudo add-apt-repository -u ppa:lightningnetwork/ppa
|
||||
$ sudo apt-get install lightningd
|
||||
```
|
||||
|
||||
## Variante: instalar binarios precompilados
|
||||
|
||||
Otro método para instalar Lightning es utilizar los binarios precompilados en el [repositorio de Github](https://github.com/ElementsProject/lightning/releases). Elija el tarball más reciente, como `clightning-v0.9.1-Ubuntu-20.04.tar.xz`.
|
||||
|
||||
Después de descargarlo, debe moverse al directorio raíz y descomprimirlo:
|
||||
|
||||
```
|
||||
$ cd /
|
||||
$ sudo tar xf ~/clightning-v0.9.1-Ubuntu-20.04.tar.xz
|
||||
```
|
||||
|
||||
Advertencia: esto requerirá que tenga exactamente las mismas bibliotecas que se usaron para crear el binario. A menudo es más fácil simplemente volver a compilar.
|
339
es/19_2_Conociendo_Su_Configuracion_Lightning.md
Normal file
339
es/19_2_Conociendo_Su_Configuracion_Lightning.md
Normal file
@ -0,0 +1,339 @@
|
||||
# 19.2: Conocer la configuración de su nodo c-lightning
|
||||
|
||||
> :information_source: **NOTA:** Esta sección se ha agregado recientemente al curso y es un borrador inicial que aún puede estar pendiente de revisión. Lector de advertencias.
|
||||
|
||||
Antes de comenzar a acceder a Lightning Network, debe comprender mejor su configuración.
|
||||
|
||||
## Conozca su directorio de c-lightning
|
||||
|
||||
Cuando se usa c-lightning, todo se guarda en el directorio `~/.lightning`.
|
||||
|
||||
El directorio principal solo contiene directorios para las redes que estén configuradas, en este caso testnet:
|
||||
```
|
||||
$ ls ~/.lightning
|
||||
testnet
|
||||
```
|
||||
|
||||
El directorio `~/.lightning/testnet` contendrá todas las entrañas de su configuración:
|
||||
```
|
||||
$ ls ~/.lightning/testnet3
|
||||
config gossip_store hsm_secret lightningd.sqlite3 lightningd.sqlite3-journal lightning-rpc
|
||||
```
|
||||
|
||||
> :link: **TESTNET vs MAINNET:** Si está utilizando mainnet, entonces _todo_ se colocará en el directorio `~/.lightning/bitcoin`. Estas diversas configuraciones se hacen elegantemente, por lo que si usted está usando MainNet, testnet y Regtest, usted encontrará que `~/.lightning/bitcoin` contiene el archivo de configuración y sus datos MainNet, el directorio `~/.lightning/testnet` contiene los datos Testnet, y el directorio `~/.lightning/regtest` contiene sus datos regtest.
|
||||
|
||||
## Conozca sus comandos lightning-cli
|
||||
|
||||
La mayor parte de su trabajo inicial se realizará con el comando `lightning-cli`, que ofrece una interfaz fácil contra `lightningd`, tal como lo hace `bitcoin-cli`.
|
||||
|
||||
Ya ha visto que el `help` comando le dará una lista de otros comandos:
|
||||
```
|
||||
$ lightning-cli help
|
||||
lightning-cli: WARNING: default network changing in 2020: please set network=testnet in config!
|
||||
=== bitcoin ===
|
||||
|
||||
feerates style
|
||||
Return feerate estimates, either satoshi-per-kw ({style} perkw) or satoshi-per-kb ({style} perkb).
|
||||
|
||||
newaddr [addresstype]
|
||||
Get a new {bech32, p2sh-segwit} (or all) address to fund a channel (default is bech32)
|
||||
|
||||
reserveinputs outputs [feerate] [minconf] [utxos]
|
||||
Reserve inputs and pass back the resulting psbt
|
||||
|
||||
sendpsbt psbt
|
||||
Finalize, extract and send a PSBT.
|
||||
|
||||
signpsbt psbt
|
||||
Sign this wallet's inputs on a provided PSBT.
|
||||
|
||||
txdiscard txid
|
||||
Abandon a transaction created by txprepare
|
||||
|
||||
txprepare outputs [feerate] [minconf] [utxos]
|
||||
Create a transaction, with option to spend in future (either txsend and txdiscard)
|
||||
|
||||
txsend txid
|
||||
Sign and broadcast a transaction created by txprepare
|
||||
|
||||
unreserveinputs psbt
|
||||
Unreserve inputs, freeing them up to be reused
|
||||
|
||||
withdraw destination satoshi [feerate] [minconf] [utxos]
|
||||
Send to {destination} address {satoshi} (or 'all') amount via Bitcoin transaction, at optional {feerate}
|
||||
|
||||
=== channels ===
|
||||
|
||||
close id [unilateraltimeout] [destination] [fee_negotiation_step]
|
||||
Close the channel with {id} (either peer ID, channel ID, or short channel ID). Force a unilateral close after {unilateraltimeout} seconds (default 48h). If {destination} address is provided, will be used as output address.
|
||||
|
||||
fundchannel_cancel id
|
||||
Cancel inflight channel establishment with peer {id}.
|
||||
|
||||
fundchannel_complete id txid txout
|
||||
Complete channel establishment with peer {id} for funding transactionwith {txid}. Returns true on success, false otherwise.
|
||||
|
||||
fundchannel_start id amount [feerate] [announce] [close_to] [push_msat]
|
||||
Start fund channel with {id} using {amount} satoshis. Returns a bech32 address to use as an output for a funding transaction.
|
||||
|
||||
getroute id msatoshi riskfactor [cltv] [fromid] [fuzzpercent] [exclude] [maxhops]
|
||||
Show route to {id} for {msatoshi}, using {riskfactor} and optional {cltv} (default 9). If specified search from {fromid} otherwise use this node as source. Randomize the route with up to {fuzzpercent} (default 5.0). {exclude} an array of short-channel-id/direction (e.g. [ '564334x877x1/0', '564195x1292x0/1' ]) or node-id from consideration. Set the {maxhops} the route can take (default 20).
|
||||
|
||||
listchannels [short_channel_id] [source]
|
||||
Show channel {short_channel_id} or {source} (or all known channels, if not specified)
|
||||
|
||||
listforwards
|
||||
List all forwarded payments and their information
|
||||
|
||||
setchannelfee id [base] [ppm]
|
||||
Sets specific routing fees for channel with {id} (either peer ID, channel ID, short channel ID or 'all'). Routing fees are defined by a fixed {base} (msat) and a {ppm} (proportional per millionth) value. If values for {base} or {ppm} are left out, defaults will be used. {base} can also be defined in other units, for example '1sat'. If {id} is 'all', the fees will be applied for all channels.
|
||||
|
||||
=== network ===
|
||||
|
||||
connect id [host] [port]
|
||||
Connect to {id} at {host} (which can end in ':port' if not default). {id} can also be of the form id@host
|
||||
|
||||
disconnect id [force]
|
||||
Disconnect from {id} that has previously been connected to using connect; with {force} set, even if it has a current channel
|
||||
|
||||
listnodes [id]
|
||||
Show node {id} (or all, if no {id}), in our local network view
|
||||
|
||||
listpeers [id] [level]
|
||||
Show current peers, if {level} is set, include logs for {id}
|
||||
|
||||
ping id [len] [pongbytes]
|
||||
Send peer {id} a ping of length {len} (default 128) asking for {pongbytes} (default 128)
|
||||
|
||||
=== payment ===
|
||||
|
||||
createonion hops assocdata [session_key]
|
||||
Create an onion going through the provided nodes, each with its own payload
|
||||
|
||||
decodepay bolt11 [description]
|
||||
Decode {bolt11}, using {description} if necessary
|
||||
|
||||
delexpiredinvoice [maxexpirytime]
|
||||
Delete all expired invoices that expired as of given {maxexpirytime} (a UNIX epoch time), or all expired invoices if not specified
|
||||
|
||||
delinvoice label status
|
||||
Delete unpaid invoice {label} with {status}
|
||||
|
||||
invoice msatoshi label description [expiry] [fallbacks] [preimage] [exposeprivatechannels]
|
||||
Create an invoice for {msatoshi} with {label} and {description} with optional {expiry} seconds (default 1 week), optional {fallbacks} address list(default empty list) and optional {preimage} (default autogenerated)
|
||||
|
||||
listinvoices [label]
|
||||
Show invoice {label} (or all, if no {label})
|
||||
|
||||
listsendpays [bolt11] [payment_hash]
|
||||
Show sendpay, old and current, optionally limiting to {bolt11} or {payment_hash}.
|
||||
|
||||
listtransactions
|
||||
List transactions that we stored in the wallet
|
||||
|
||||
sendonion onion first_hop payment_hash [label] [shared_secrets] [partid]
|
||||
Send a payment with a pre-computed onion.
|
||||
|
||||
sendpay route payment_hash [label] [msatoshi] [bolt11] [payment_secret] [partid]
|
||||
Send along {route} in return for preimage of {payment_hash}
|
||||
|
||||
waitanyinvoice [lastpay_index] [timeout]
|
||||
Wait for the next invoice to be paid, after {lastpay_index} (if supplied). If {timeout} seconds is reached while waiting, fail with an error.
|
||||
|
||||
waitinvoice label
|
||||
Wait for an incoming payment matching the invoice with {label}, or if the invoice expires
|
||||
|
||||
waitsendpay payment_hash [timeout] [partid]
|
||||
Wait for payment attempt on {payment_hash} to succeed or fail, but only up to {timeout} seconds.
|
||||
|
||||
=== plugin ===
|
||||
|
||||
autocleaninvoice [cycle_seconds] [expired_by]
|
||||
Set up autoclean of expired invoices.
|
||||
|
||||
estimatefees
|
||||
Get the urgent, normal and slow Bitcoin feerates as sat/kVB.
|
||||
|
||||
fundchannel id amount [feerate] [announce] [minconf] [utxos] [push_msat]
|
||||
Fund channel with {id} using {amount} (or 'all'), at optional {feerate}. Only use outputs that have {minconf} confirmations.
|
||||
|
||||
getchaininfo
|
||||
Get the chain id, the header count, the block count, and whether this is IBD.
|
||||
|
||||
getrawblockbyheight height
|
||||
Get the bitcoin block at a given height
|
||||
|
||||
getutxout txid vout
|
||||
Get informations about an output, identified by a {txid} an a {vout}
|
||||
|
||||
listpays [bolt11]
|
||||
List result of payment {bolt11}, or all
|
||||
|
||||
pay bolt11 [msatoshi] [label] [riskfactor] [maxfeepercent] [retry_for] [maxdelay] [exemptfee]
|
||||
Send payment specified by {bolt11} with {amount}
|
||||
|
||||
paystatus [bolt11]
|
||||
Detail status of attempts to pay {bolt11}, or all
|
||||
|
||||
plugin subcommand=start|stop|startdir|rescan|list
|
||||
Control plugins (start, stop, startdir, rescan, list)
|
||||
|
||||
sendrawtransaction tx
|
||||
Send a raw transaction to the Bitcoin network.
|
||||
|
||||
=== utility ===
|
||||
|
||||
check command_to_check
|
||||
Don't run {command_to_check}, just verify parameters.
|
||||
|
||||
checkmessage message zbase [pubkey]
|
||||
Verify a digital signature {zbase} of {message} signed with {pubkey}
|
||||
|
||||
getinfo
|
||||
Show information about this node
|
||||
|
||||
getlog [level]
|
||||
Show logs, with optional log {level} (info|unusual|debug|io)
|
||||
|
||||
getsharedsecret point
|
||||
Compute the hash of the Elliptic Curve Diffie Hellman shared secret point from this node private key and an input {point}.
|
||||
|
||||
help [command]
|
||||
List available commands, or give verbose help on one {command}.
|
||||
|
||||
listconfigs [config]
|
||||
List all configuration options, or with [config], just that one.
|
||||
|
||||
listfunds
|
||||
Show available funds from the internal wallet
|
||||
|
||||
signmessage message
|
||||
Create a digital signature of {message}
|
||||
|
||||
stop
|
||||
Shut down the lightningd process
|
||||
|
||||
waitblockheight blockheight [timeout]
|
||||
Wait for the blockchain to reach {blockheight}, up to {timeout} seconds.
|
||||
|
||||
=== developer ===
|
||||
|
||||
dev-listaddrs [bip32_max_index]
|
||||
Show addresses list up to derivation {index} (default is the last bip32 index)
|
||||
|
||||
dev-rescan-outputs
|
||||
Synchronize the state of our funds with bitcoind
|
||||
|
||||
---
|
||||
run `lightning-cli help <command>` for more information on a specific command
|
||||
```
|
||||
|
||||
## Conozca la información de lightning
|
||||
|
||||
Una variedad de comandos `lightning-cli` pueden brindarle información adicional sobre su nodo Lightning. Los más generales son:
|
||||
```
|
||||
$ lightning-cli --testnet listconfigs
|
||||
$ lightning-cli --testnet listfunds
|
||||
$ lightning-cli --testnet listtransactions
|
||||
$ lightning-cli --testnet listinvoices
|
||||
$ lightning-cli --testnet listnodes
|
||||
```
|
||||
* listconfigs: El comando RPC `listconfigs` enumera todas las opciones de configuración.
|
||||
* listfunds: El comando RPC `listfunds` muestra todos los fondos disponibles, ya sea en salidas no gastadas (UTXO) en la billetera interna o fondos bloqueados en los canales abiertos actualmente.
|
||||
* listtransactions: El comando RPC `listtransactions` devuelve transacciones rastreadas en la billetera. Esto incluye depósitos, retiros y transacciones relacionadas con los canales.
|
||||
* listinvoices: El comando RPC `listinvoices` recupera el estado de una factura específica, si existe, o el estado de todas las facturas si no se proporciona ningún argumento.
|
||||
* listnodes: El comando RPC `listnodes` devuelve los nodos que su servidor ha aprendido a través de mensajes de gossip, o uno solo si se especificó el ID de nodo.
|
||||
|
||||
Por ejemplo `lightning-cli listconfigs` le brinda una variedad de información sobre su configuración:
|
||||
```
|
||||
c$ lightning-cli --testnet listconfigs
|
||||
{
|
||||
"# version": "v0.8.2-398-g869fa08",
|
||||
"lightning-dir": "/home/standup/.lightning",
|
||||
"network": "testnet",
|
||||
"allow-deprecated-apis": true,
|
||||
"rpc-file": "lightning-rpc",
|
||||
"plugin": "/usr/local/bin/../libexec/c-lightning/plugins/fundchannel",
|
||||
"plugin": "/usr/local/bin/../libexec/c-lightning/plugins/autoclean",
|
||||
"plugin": "/usr/local/bin/../libexec/c-lightning/plugins/bcli",
|
||||
"plugin": "/usr/local/bin/../libexec/c-lightning/plugins/pay",
|
||||
"plugin": "/usr/local/bin/../libexec/c-lightning/plugins/keysend",
|
||||
"plugins": [
|
||||
{
|
||||
"path": "/usr/local/bin/../libexec/c-lightning/plugins/fundchannel",
|
||||
"name": "fundchannel"
|
||||
},
|
||||
{
|
||||
"path": "/usr/local/bin/../libexec/c-lightning/plugins/autoclean",
|
||||
"name": "autoclean",
|
||||
"options": {
|
||||
"autocleaninvoice-cycle": null,
|
||||
"autocleaninvoice-expired-by": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "/usr/local/bin/../libexec/c-lightning/plugins/bcli",
|
||||
"name": "bcli",
|
||||
"options": {
|
||||
"bitcoin-datadir": null,
|
||||
"bitcoin-cli": null,
|
||||
"bitcoin-rpcuser": null,
|
||||
"bitcoin-rpcpassword": null,
|
||||
"bitcoin-rpcconnect": null,
|
||||
"bitcoin-rpcport": null,
|
||||
"bitcoin-retry-timeout": null,
|
||||
"commit-fee": "500"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "/usr/local/bin/../libexec/c-lightning/plugins/pay",
|
||||
"name": "pay"
|
||||
},
|
||||
{
|
||||
"path": "/usr/local/bin/../libexec/c-lightning/plugins/keysend",
|
||||
"name": "keysend"
|
||||
}
|
||||
],
|
||||
"disable-plugin": [],
|
||||
"always-use-proxy": false,
|
||||
"daemon": "false",
|
||||
"wallet": "sqlite3:///home/user/.lightning/testnet/lightningd.sqlite3",
|
||||
"wumbo": false,
|
||||
"wumbo": false,
|
||||
"rgb": "03fce2",
|
||||
"alias": "learningBitcoin",
|
||||
"pid-file": "/home/user/.lightning/lightningd-testnet.pid",
|
||||
"ignore-fee-limits": false,
|
||||
"watchtime-blocks": 144,
|
||||
"max-locktime-blocks": 720,
|
||||
"funding-confirms": 3,
|
||||
"commit-fee-min": 200,
|
||||
"commit-fee-max": 2000,
|
||||
"cltv-delta": 6,
|
||||
"cltv-final": 10,
|
||||
"commit-time": 10,
|
||||
"fee-base": 1,
|
||||
"rescan": 15,
|
||||
"fee-per-satoshi": 10,
|
||||
"max-concurrent-htlcs": 483,
|
||||
"min-capacity-sat": 10000,
|
||||
"offline": "false",
|
||||
"autolisten": true,
|
||||
"disable-dns": "false",
|
||||
"enable-autotor-v2-mode": "false",
|
||||
"encrypted-hsm": false,
|
||||
"rpc-file-mode": "0600",
|
||||
"log-level": "DEBUG",
|
||||
"log-prefix": "lightningd"
|
||||
}
|
||||
```
|
||||
|
||||
## Resumen: Conozca la configuración de su nodo lightning
|
||||
|
||||
El directorio `~/.lightning` contiene todos sus archivos, mientras que el comando `lightning-cli help` se puede usar con una variedad de comandos de ayuda para obtener más información sobre cómo funcionan su configuración y Lightning Network.
|
||||
|
||||
## Que sigue?
|
||||
|
||||
Necesitará tener un segundo nodo Linode para probar el pago real de facturas. Si necesita ayuda para configurar uno, lea [Interludio: Acceso a un segundo nodo Lightning.](19_2_Interludio_Accediendo_a_un_Segundo_Nodo_Lightning.md).
|
||||
|
||||
De lo contrario, continúe "Comprensión de la configuración de Lightning" con [§19.3: Configurando un Canal](19_3_Creando_un_Canal_en_Lightning.md).
|
324
es/19_2_Interludio_Accediendo_a_un_Segundo_Nodo_Lightning.md
Normal file
324
es/19_2_Interludio_Accediendo_a_un_Segundo_Nodo_Lightning.md
Normal file
@ -0,0 +1,324 @@
|
||||
# Interludio: Acceso a un segundo nodo de Lightning
|
||||
|
||||
> :information_source: **NOTA:** Esta sección se ha añadido recientemente al curso y es un borrador temprano que todavía puede estar pendiente de revisión. Lectura con advertencias.
|
||||
|
||||
Cuando jugaba con Bitcoin estaba accediendo a una red existente, y eso hizo que fuera relativamente fácil trabajar con ello: solo fue arrancar `bitcoind` e inmediatamente interactuaba con la red. Así funciona ahora Lightning: es fundamentalmente una red de igual a igual, construida a partir de las conexiones entre dos nodos individuales. En otras palabras, para interactuar con la red Lightning, primero tendrá que encontrar un nodo al cual conectarse.
|
||||
|
||||
Hay cuatro maneras de hacerlo (las tres primeras son posibles para su primera conexión):
|
||||
|
||||
## Solicitar información sobre un nodo
|
||||
|
||||
Si alguien más ya tiene un nodo Lightning en la red de su elección, simplemente pídale su ID.
|
||||
|
||||
Si están ejecutando c-lightning, solo necesitan usar el comando `getinfo`:
|
||||
|
||||
```
|
||||
$ lightning-cli getinfo
|
||||
lightning-cli: WARNING: default network changing in 2020: please set network=testnet in config!
|
||||
"id": "03240a4878a9a64aea6c3921a434e573845267b86e89ab19003b0c910a86d17687",
|
||||
"alias": "VIOLETGLEE",
|
||||
"color": "03240a",
|
||||
"num_peers": 0,
|
||||
"num_pending_channels": 0,
|
||||
"num_active_channels": 0,
|
||||
"num_inactive_channels": 0,
|
||||
"address": [
|
||||
{
|
||||
"type": "ipv4",
|
||||
"address": "74.207.240.32",
|
||||
"port": 9735
|
||||
}
|
||||
],
|
||||
"binding": [
|
||||
{
|
||||
"type": "ipv6",
|
||||
"address": "::",
|
||||
"port": 9735
|
||||
},
|
||||
{
|
||||
"type": "ipv4",
|
||||
"address": "0.0.0.0",
|
||||
"port": 9735
|
||||
}
|
||||
],
|
||||
"version": "v0.9.1-96-g6f870df",
|
||||
"blockheight": 1862854,
|
||||
"network": "testnet",
|
||||
"msatoshi_fees_collected": 0,
|
||||
"fees_collected_msat": "0msat",
|
||||
"lightning-dir": "/home/standup/.lightning/testnet"
|
||||
}
|
||||
```
|
||||
A continuación, pueden decirle su `id` (`03240a4878a9a64aea6c3921a434e573845267b86e89ab19003b0c910a86d17687`). También tendrán que indicarle su dirección IP (`74.207.240.32`) y su puerto (`9735`).
|
||||
|
||||
## Crear un nuevo nodo c-lightning
|
||||
|
||||
Sin embargo, para fines de prueba, es probable que desee tener un segundo nodo bajo su propio control. La forma más fácil de hacerlo es crear un segundo nodo c-lightning en una máquina nueva, usando Bitcoin Standup, por [§2.1](02_1_Configurando_un_Bitcoin-Core_VPS_con_StackScript.md) o compilándolo a mano, por [§19.1](19_1_Verificando_Su_Configuracion_Lightning.md).
|
||||
|
||||
Una vez que tenga su nodo en ejecución, puede ejecutar `getinfo` para recuperar su información, como se muestra arriba.
|
||||
|
||||
## Crear un nuevo nodo LND
|
||||
|
||||
Sin embargo, para nuestros ejemplos en el siguiente capítulo, vamos a crear un nodo LND. Esto nos permitirá demostrar un poco de la profundidad del ecosistema Lightning al mostrar cómo funcionan comandos similares en las dos plataformas diferentes.
|
||||
|
||||
Una forma de crear un nodo LND es ejecutar los Scripts de Bitcoin de nuevo en una máquina nueva, pero esta vez debe elegir LND, en [§2.1](02_1_Configurando_un_Bitcoin-Core_VPS_con_StackScript.md).
|
||||
|
||||
Otra es compilar LND a partir del código fuente en una máquina donde ya está ejecutando un nodo Bitcoin, como sigue.
|
||||
|
||||
### Compilar el código fuente del LND
|
||||
|
||||
Primero, necesita descargar e instalar Go:
|
||||
```
|
||||
$ wget --progress=bar:force https://dl.google.com/go/"go1.14.4"."linux"-"amd64".tar.gz -O ~standup/"go1.14.4"."linux"-"amd64".tar.gz
|
||||
$ /bin/tar xzf ~standup/"go1.14.4"."linux"-"amd64".tar.gz -C ~standup
|
||||
$ sudo mv ~standup/go /usr/local
|
||||
```
|
||||
Asegúrese de que la versión Go es la más actualizada (es `go1.14.4` en el momento actual), y la plataforma y la arquitectura son adecuadas para su máquina. (Lo anterior funcionará para Debian.)
|
||||
|
||||
Actualizar su ruta:
|
||||
```
|
||||
$ export GOPATH=~standup/gocode
|
||||
$ export PATH="$PATH":/usr/local/go/bin:"$GOPATH"/bin
|
||||
```
|
||||
Entonces asegúrese de que `go` funciona:
|
||||
```
|
||||
$ go version
|
||||
go version go1.14.4 linux/amd64
|
||||
```
|
||||
También necesitará `git` y `make`:
|
||||
```
|
||||
$ sudo apt-get install git
|
||||
$ sudo apt-get install build-essential
|
||||
```
|
||||
Ahora está listo para recuperar LND. Asegúrese de obtener el verison actual (actualmente `v0.11.0-beta.rc4`).
|
||||
```
|
||||
$ go get -d github.com/lightningnetwork/lnd
|
||||
```
|
||||
Y ahora puede compilar:
|
||||
```
|
||||
$ cd "$GOPATH"/src/github.com/lightningnetwork/lnd
|
||||
$ git checkout v0.11.0-beta.rc4
|
||||
$ make
|
||||
$ make install
|
||||
```
|
||||
Esto se instalará en `~/gocode/bin`, que es `$GOPATH/bin`.
|
||||
|
||||
Debería moverlo a directorios globales:
|
||||
```
|
||||
$ sudo cp $GOPATH/bin/lnd $GOPATH/bin/lncli /usr/bin
|
||||
```
|
||||
### Crear un archivo de configuración de LND
|
||||
|
||||
A diferencia de c-lightning, necesitará crear un archivo de configuración predeterminado para LND.
|
||||
|
||||
Sin embargo, usted primero necesita habilitar ZMQ en su Bitcoind, si no lo hizo ya en [§16.3](16_3_Recibiendo_Notificaciones_de_Bitcoind_en_C_con_las_Bibliotecas_ZMQ.md).
|
||||
|
||||
Esto requiere agregar lo siguiente a su archivo `~/.bitcoin/bitcoin.conf` si no está ya allí:
|
||||
```
|
||||
zmqpubrawblock=tcp://127.0.0.1:28332
|
||||
zmqpubrawtx=tcp://127.0.0.1:28333
|
||||
```
|
||||
Si usted está usando un archivo de configuración de Bitcoin desde Standup o algún otro `conf` especializado, asegúrese de poner sus nuevos comandos en la sección correcta. Idealmente, deben ir cerca de la parte superior del archivo, de lo contrario en la sección `[test]` (asumiendo, como de costumbre, que está probando en testnet).
|
||||
|
||||
Luego debe reiniciar bitcoin (o simplemente reiniciar su máquina). Puede probar que está funcionando de la siguiente manera:
|
||||
```
|
||||
$ bitcoin-cli getzmqnotifications
|
||||
[
|
||||
{
|
||||
"type": "pubrawblock",
|
||||
"address": "tcp://127.0.0.1:28332",
|
||||
"hwm": 1000
|
||||
},
|
||||
{
|
||||
"type": "pubrawtx",
|
||||
"address": "tcp://127.0.0.1:28333",
|
||||
"hwm": 1000
|
||||
}
|
||||
]
|
||||
```
|
||||
Ahora está listo para crear un archivo de configuración.
|
||||
|
||||
Primero, necesita recuperar su rpcuser y rpcpassword. Esta es una manera automatizada de hacerlo:
|
||||
```
|
||||
$ BITCOINRPC_USER=$(cat ~standup/.bitcoin/bitcoin.conf | grep rpcuser | awk -F = '{print $2}')
|
||||
$ BITCOINRPC_PASS=$(cat ~standup/.bitcoin/bitcoin.conf | grep rpcpassword | awk -F = '{print $2}')
|
||||
```
|
||||
> :warning: **ADVERTENCIA:** Obviamente, nunca almacene su contraseña RPC en una variable de shell en un entorno de producción.
|
||||
|
||||
Luego, puede escribir el archivo:
|
||||
```
|
||||
$ mkdir ~/.lnd
|
||||
$ cat > ~/.lnd/lnd.conf << EOF
|
||||
[Application Options]
|
||||
maxlogfiles=3
|
||||
maxlogfilesize=10
|
||||
#externalip=1.1.1.1 # change to your public IP address if required.
|
||||
alias=StandUp
|
||||
listen=0.0.0.0:9735
|
||||
debuglevel=debug
|
||||
[Bitcoin]
|
||||
bitcoin.active=1
|
||||
bitcoin.node=bitcoind
|
||||
bitcoin.testnet=true
|
||||
[Bitcoind]
|
||||
bitcoind.rpchost=localhost
|
||||
bitcoind.rpcuser=$BITCOINRPC_USER
|
||||
bitcoind.rpcpass=$BITCOINRPC_PASS
|
||||
bitcoind.zmqpubrawblock=tcp://127.0.0.1:28332
|
||||
bitcoind.zmqpubrawtx=tcp://127.0.0.1:28333
|
||||
EOF
|
||||
```
|
||||
|
||||
### Crear un servicio de LND
|
||||
|
||||
Por último, puede crear un servicio LND para ejecutar automáticamente `lnd`:
|
||||
```
|
||||
$ cat > ~/lnd.service << EOF
|
||||
# It is not recommended to modify this file in-place, because it will
|
||||
# be overwritten during package upgrades. If you want to add further
|
||||
# options or overwrite existing ones then use
|
||||
# $ systemctl edit lnd.service
|
||||
# See "man systemd.service" for details.
|
||||
# Note that almost all daemon options could be specified in
|
||||
# /etc/lnd/lnd.conf, except for those explicitly specified as arguments
|
||||
# in ExecStart=
|
||||
[Unit]
|
||||
Description=LND Lightning Network Daemon
|
||||
Requires=bitcoind.service
|
||||
After=bitcoind.service
|
||||
[Service]
|
||||
ExecStart=/usr/bin/lnd
|
||||
ExecStop=/usr/bin/lncli --lnddir /var/lib/lnd stop
|
||||
PIDFile=/run/lnd/lnd.pid
|
||||
User=standup
|
||||
Type=simple
|
||||
KillMode=process
|
||||
TimeoutStartSec=60
|
||||
TimeoutStopSec=60
|
||||
Restart=always
|
||||
RestartSec=60
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
```
|
||||
A continuación, tendrá que instalar eso y poner en marcha las cosas:
|
||||
```
|
||||
$ sudo cp ~/lnd.service /etc/systemd/system
|
||||
$ sudo systemctl enable lnd
|
||||
$ sudo systemctl start lnd
|
||||
```
|
||||
(Espere que esto tome un minuto la primera vez.)
|
||||
|
||||
### Habilitar conexiones remotas
|
||||
|
||||
Al igual que con c-lightning, va a tener que hacer LND accesible a otros nodos. He aquí cómo hacerlo si utiliza `ufw`, según las configuraciones de Bitcoin Standup:
|
||||
```
|
||||
$ sudo ufw allow 9735
|
||||
```
|
||||
### Crear una cartera
|
||||
|
||||
La primera vez que ejecute LND, debe crear una cartera:
|
||||
```
|
||||
$ lncli --network=testnet create
|
||||
```
|
||||
LND le pedirá una contraseña y luego le preguntará si desea ingresar un mnemónico existente (simplemente pulse `n` para el último).
|
||||
|
||||
Ahora debería tener un funcionamiento `lnd`, que puede verificar con `getinfo`:
|
||||
```
|
||||
$ lncli --network=testnet getinfo
|
||||
{
|
||||
"version": "0.11.0-beta.rc4 commit=v0.11.0-beta.rc4",
|
||||
"commit_hash": "fc12656a1a62e5d69430bba6e4feb8cfbaf21542",
|
||||
"identity_pubkey": "032a7572dc013b6382cde391d79f292ced27305aa4162ec3906279fc4334602543",
|
||||
"alias": "StandUp",
|
||||
"color": "#3399ff",
|
||||
"num_pending_channels": 0,
|
||||
"num_active_channels": 0,
|
||||
"num_inactive_channels": 0,
|
||||
"num_peers": 2,
|
||||
"block_height": 1862848,
|
||||
"block_hash": "000000000000000ecb6fd95e1f486283d48683aa3111b6c23144a2056f5a1532",
|
||||
"best_header_timestamp": "1602632294",
|
||||
"synced_to_chain": true,
|
||||
"synced_to_graph": false,
|
||||
"testnet": true,
|
||||
"chains": [
|
||||
{
|
||||
"chain": "bitcoin",
|
||||
"network": "testnet"
|
||||
}
|
||||
],
|
||||
"uris": [
|
||||
],
|
||||
"features": {
|
||||
"0": {
|
||||
"name": "data-loss-protect",
|
||||
"is_required": true,
|
||||
"is_known": true
|
||||
},
|
||||
"5": {
|
||||
"name": "upfront-shutdown-script",
|
||||
"is_required": false,
|
||||
"is_known": true
|
||||
},
|
||||
"7": {
|
||||
"name": "gossip-queries",
|
||||
"is_required": false,
|
||||
"is_known": true
|
||||
},
|
||||
"9": {
|
||||
"name": "tlv-onion",
|
||||
"is_required": false,
|
||||
"is_known": true
|
||||
},
|
||||
"13": {
|
||||
"name": "static-remote-key",
|
||||
"is_required": false,
|
||||
"is_known": true
|
||||
},
|
||||
"15": {
|
||||
"name": "payment-addr",
|
||||
"is_required": false,
|
||||
"is_known": true
|
||||
},
|
||||
"17": {
|
||||
"name": "multi-path-payments",
|
||||
"is_required": false,
|
||||
"is_known": true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
El ID de este nodo es `032a7572dc013b6382cde391d79f292ced27305aa4162ec3906279fc4334602543`. Aunque este comando no le muestra la dirección IP y el puerto, deben ser la dirección IP para su máquina y el puerto `9735`.
|
||||
|
||||
## Escuchando el Gossip
|
||||
|
||||
Si ya estaba conectado a la red lightning, y estaba "chismeando" con nodos compañeros, también podría ser capaz de encontrar información sobre compañeros automáticamente, a través del comando `listpeers`:
|
||||
|
||||
```
|
||||
c$ lightning-cli --network=testnet listpeers
|
||||
{
|
||||
"peers": [
|
||||
{
|
||||
"id": "0302d48972ba7eef8b40696102ad114090fd4c146e381f18c7932a2a1d73566f84",
|
||||
"connected": true,
|
||||
"netaddr": [
|
||||
"127.0.0.1:9736"
|
||||
],
|
||||
"features": "02a2a1",
|
||||
"channels": []
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
Sin embargo, eso definitivamente no será el caso para su primera interacción con la red Lightning.
|
||||
|
||||
## Resumen: Acceso a un segundo nodo de rayos
|
||||
|
||||
Siempre necesitará dos nodos Lightning para formar un canal. Si no tiene a alguien más que esté probando las cosas con usted, va a necesitar crear un segundo nodo, ya sea usando c-lightning o (como haremos en nuestros ejemplos) LND.
|
||||
|
||||
## ¿Qué es lo siguiente?
|
||||
|
||||
Aunque posiblemente haya creado un LND, c-lightning seguirá siendo el corazón de nuestros ejemplos hasta que necesitemos empezar a usar ambos, en el [Capítulo 19](19_0_Entendiendo_Su_Configuracion_Lightning.md).
|
||||
|
||||
Continuar "Comprender la configuración de nodo Lightning" con [§19.3: Creando un Canal en Lightning](19_3_Creando_un_Canal_en_Lightning.md).
|
191
es/19_3_Creando_un_Canal_en_Lightning.md
Normal file
191
es/19_3_Creando_un_Canal_en_Lightning.md
Normal file
@ -0,0 +1,191 @@
|
||||
# 19.3: Creación de un canal lightning
|
||||
|
||||
> :information_source: **NOTA:** Esta sección se agregó recientemente al curso y es un borrador inicial que aún puede estar pendiente de revisión. Lector de advertencias.
|
||||
|
||||
Ahora comprende los conceptos básicos de su configuración Lightning y, con suerte, ha creado o recibido información sobre un segundo nodo Lightning. Está listo para crear su primer canal Lightning Network. Por supuesto, deberá comprender qué es y cómo se crea utilizando c-lightning.
|
||||
|
||||
> :book: ***¿Qué es un canal de lightning?*** Simplemente, un canal de iluminación es un tubo de dinero que permite transferencias de dinero rápidas, baratas y privadas sin enviar transacciones a la cadena de bloques. Más técnicamente, un canal es una transacción de Bitcoin en cadena con firmas múltiples 2 de 2 que establece una relación financiera sin confianza entre dos personas o dos agentes. Se deposita una cierta cantidad de dinero en el canal, cuando luego se mantiene una base de datos local con saldo de bitcoins para ambas partes, haciendo un seguimiento de cuánto dinero tiene cada uno de la cantidad inicial. Los dos usuarios pueden intercambiar bitcoins a través de su canal Lightning sin tener que escribir en la cadena de bloques de Bitcoin. Solo cuando quieren cerrar su canal, liquidan sus bitcoins en la cadena de bloques, en función de la división final de monedas.
|
||||
|
||||
> :book: ***¿Cómo crean los canales Lightning una red Lightning?*** Aunque un canal Lightning solo permite el pago entre dos usuarios, los canales se pueden conectar entre sí para formar una red que permite pagos entre miembros que no tienen canal directo entre ellos. Esto crea una red entre varias personas construida a partir de conexiones por pares.
|
||||
|
||||
En esta sección, continuaremos usando nuestra configuración de c-lightning como nuestro nodo principal.
|
||||
|
||||
## Crear un canal
|
||||
|
||||
La creación de un canal Lightning requiere los siguientes pasos:
|
||||
|
||||
* Financie su billetera c-lightning con algunos satoshis.
|
||||
* Conéctese a un nodo remoto como un par.
|
||||
* Abre un canal.
|
||||
|
||||
### Financiar su billetera c-lightning
|
||||
|
||||
Para mover fondos a un canal Lightning, primero se requiere financiar su billetera c-lightning.
|
||||
|
||||
> :book: ***¿Qué es una billetera c-lightning?*** La implementación estándar de C-lightning viene con una billetera Bitcoin integrada que le permite enviar y recibir transacciones bitcoin en cadena. Esta billetera se utilizará para crear nuevos canales.
|
||||
|
||||
Lo primero que debe hacer es enviar algunos satoshis a su billetera c-lightning. Puede crear una nueva dirección usando el comando `lightning-cli newaddr`. Esto genera una nueva dirección que posteriormente se puede utilizar para financiar canales gestionados por el nodo c-lightning. Puede especificar el tipo de dirección deseada; si no se especifica, la dirección generada será un bech32.
|
||||
|
||||
```
|
||||
$ lightning-cli --testnet newaddr
|
||||
{
|
||||
"address": "tb1qefule33u7ukfuzkmxpz02kwejl8j8dt5jpgtu6",
|
||||
"bech32": "tb1qefule33u7ukfuzkmxpz02kwejl8j8dt5jpgtu6"
|
||||
}
|
||||
```
|
||||
|
||||
Luego puede enviar fondos a esta dirección usando `bitcoin-cli sendtoaddress` (o cualquier otra metodología que prefiera). Para este ejemplo, lo hicimos en la transacción [11094bb9ac29ce5af9f1e5a0e4aac2066ae132f25b72bff90fcddf64bf2feb02](https://blockstream.info/testnet/tx/11094bb9ac29ce5af9f1e5a0e4b2ac2066ae2f25b72bff90fcddf64bf2feb02)
|
||||
|
||||
Esta transacción se denomina [transacción de financiación](https://github.com/lightningnetwork/lightning-rfc/blob/master/03-transactions.md#funding-transaction-output) y debe confirmarse antes de que los fondos puedan ser usado.
|
||||
|
||||
> :book: ***¿Qué es una transacción de financiación?*** Una transacción de financiación es una transacción de Bitcoin que coloca dinero en un canal Lightning. Puede ser de financiación única (por un participante) o de doble financiación (por ambos). A partir de ahí, las transacciones Lightning se tratan de reasignar la propiedad de la transacción de financiación, pero solo se liquidan en la cadena de bloques cuando el canal está cerrado.
|
||||
|
||||
Para verificar su saldo local debe usar el comando `lightning-cli listfunds`:
|
||||
|
||||
```
|
||||
c$ lightning-cli --testnet listfunds
|
||||
{
|
||||
"outputs": [],
|
||||
"channels": []
|
||||
}
|
||||
```
|
||||
|
||||
Dado que los fondos aún no tienen seis confirmaciones, no hay saldo disponible. Después de seis confirmaciones, debería ver un saldo:
|
||||
|
||||
```
|
||||
c$ lightning-cli --testnet listfunds
|
||||
{
|
||||
"outputs": [
|
||||
{
|
||||
"txid": "11094bb9ac29ce5af9f1e5a0e4aac2066ae132f25b72bff90fcddf64bf2feb02",
|
||||
"output": 0,
|
||||
"value": 300000,
|
||||
"amount_msat": "300000000msat",
|
||||
"scriptpubkey": "0014ca79fcc63cf72c9e0adb3044f559d997cf23b574",
|
||||
"address": "tb1qefule33u7ukfuzkmxpz02kwejl8j8dt5jpgtu6",
|
||||
"status": "confirmed",
|
||||
"blockheight": 1780680,
|
||||
"reserved": false
|
||||
}
|
||||
],
|
||||
"channels": []
|
||||
}
|
||||
|
||||
```
|
||||
Tenga en cuenta que el valor aparece en satoshis o microsatoshis, ¡no en Bitcoin!
|
||||
|
||||
> :book: ***¿Qué son los satoshis y msat?*** Ya conoció los satoshis en [§3.4](03_4_Recibiendo_una_Transaccion.md). Un satoshi es la cien millonésima parte de un bitcoin, por lo que 300.000 satoshi = 0,003 BTC. Un satoshi es la unidad monetaria más pequeña de la red Bitcoin. Pero, la red Lightning puede ser más pequeña, por lo que 1000 msat, o milisatoshis, equivalen a un satoshi. Eso significa que 1 msat es la cien mil millonésima parte de un bitcoin y 300.000.000 msat = 0,003 BTC.
|
||||
|
||||
Ahora que ha financiado su billetera c-lightning, necesitará información sobre un nodo remoto para comenzar a crear el proceso de canal.
|
||||
|
||||
### Conectarse a un nodo remoto
|
||||
|
||||
Lo siguiente que debe hacer es conectar su nodo a un par. Esto se hace con el comando `lightning-cli connect`. Recuerde que si desea obtener más información sobre este comando, debe escribir `lightning-cli help connect`.
|
||||
|
||||
Para conectar su nodo a un par remoto, necesita su ID, que representa la clave pública del nodo de destino. Para su comodidad, `id` puede tener el formato `id@host` o `id@host:port`. Es posible que haya recuperado esto con `lightning-cli getinfo` (en c-lightning) o `lncli --network=testnet getinfo` (en LND) como se discutió en el [interludio anterior](19_2_Interludio_Accediendo_a_un_Segundo_Nodo_Lightning.md).
|
||||
|
||||
Hemos seleccionado el nodo LND, `032a7572dc013b6382cde391d79f292ced27305aa4162ec3906279fc4334602543`, que se encuentra en la dirección IP `45.33.35.151`, a la que nos vamos a conectar desde nuestro nodo c-lightning:
|
||||
|
||||
```
|
||||
$ lightning-cli --network=testnet connect 032a7572dc013b6382cde391d79f292ced27305aa4162ec3906279fc4334602543@45.33.35.151
|
||||
{
|
||||
"id": "032a7572dc013b6382cde391d79f292ced27305aa4162ec3906279fc4334602543",
|
||||
"features": "02a2a1"
|
||||
}
|
||||
```
|
||||
|
||||
### Abrir un canal
|
||||
|
||||
El comando fundchannel RPC abre un canal de pago con un par al realizar una transacción de financiación en la cadena de bloques. Debe usar el comando `lightning-cli fundchannel` para hacerlo, con los siguientes parámetros:
|
||||
|
||||
* **id** es el retorno de la identificación del par de connect.
|
||||
* **monto** es el monto en satoshis que se toma de la billetera interna para financiar el canal. El valor no puede ser menor que el límite de polvo, actualmente establecido en 546, ni más de 16.777.215 satoshi (a menos que se hayan negociado grandes canales con el par).
|
||||
* **tarifa** es una tarifa opcional utilizada para la transacción de apertura y como tarifa inicial para transacciones de compromiso y HTLC.
|
||||
* **anuncio** es una bandera opcional que activa si anunciar este canal o no. Por defecto es verdadero. Si desea crear un canal privado no anunciado, configúrelo en falso.
|
||||
* **minconf** especifica el número mínimo de confirmaciones que deben tener las salidas utilizadas en el proceso de apertura del canal. El valor predeterminado es 1.
|
||||
* **utxos** especifica los utxos que se utilizarán para financiar el canal, como una matriz de "txid: vout".
|
||||
|
||||
Ahora puede abrir el canal así:
|
||||
|
||||
```
|
||||
$ lightning-cli --testnet fundchannel 032a7572dc013b6382cde391d79f292ced27305aa4162ec3906279fc4334602543 100000 urgent true 1
|
||||
{
|
||||
"tx": "0200000000010193dc3337837f091718f47b71f2eae8b745ec307231471f6a6aab953c3ea0e3b50100000000fdffffff02a0860100000000002200202e30365fe321a435e5f66962492163302f118c13e215ea8928de88cc46666c1d07860100000000001600142fe02e5be9283e8c5bcb93ae61421baf8cb64f9c024730440220668a7c253c9fd83fc1b45e4a52823fb6bc5fad30da36240d4604f0d6981a6f4502202aeb1da5fbbc8790791ef72b3378005fe98d485d22ffeb35e54a6fbc73178fb2012103b3efe051712e9fa6d90008186e96320491cfe1ef1922d74af5bc6d3307843327c76c1c00",
|
||||
"txid": "66694d23ca15efe379e5f4a71d9be1a2d65e383b89ee3abe126ee36a12f23c1d",
|
||||
"channel_id": "1d3cf2126ae36e12be3aee893b385ed6a2e19b1da7f4e579e3ef15ca234d6966",
|
||||
"outnum": 0
|
||||
}
|
||||
```
|
||||
Para confirmar el estado del canal, use el comando `lightning-cli listfunds`:
|
||||
|
||||
|
||||
```
|
||||
c$ lightning-cli --testnet listfunds
|
||||
{
|
||||
"outputs": [
|
||||
{
|
||||
"txid": "66694d23ca15efe379e5f4a71d9be1a2d65e383b89ee3abe126ee36a12f23c1d",
|
||||
"output": 1,
|
||||
"value": 99847,
|
||||
"amount_msat": "99847000msat",
|
||||
"scriptpubkey": "00142fe02e5be9283e8c5bcb93ae61421baf8cb64f9c",
|
||||
"address": "tb1q9lszuklf9qlgck7tjwhxzssm47xtvnuu4jslf8",
|
||||
"status": "unconfirmed",
|
||||
"reserved": false
|
||||
},
|
||||
{
|
||||
"txid": "b5e3a03e3c95ab6a6a1f47317230ec45b7e8eaf2717bf41817097f833733dc93",
|
||||
"output": 1,
|
||||
"value": 200000,
|
||||
"amount_msat": "200000000msat",
|
||||
"scriptpubkey": "0014ed54b65eae3da99b23a48bf8827c9acd78079469",
|
||||
"address": "tb1qa42tvh4w8k5ekgay30ugyly6e4uq09rfpqf9md",
|
||||
"status": "confirmed",
|
||||
"blockheight": 1862831,
|
||||
"reserved": true
|
||||
}
|
||||
],
|
||||
"channels": [
|
||||
{
|
||||
"peer_id": "032a7572dc013b6382cde391d79f292ced27305aa4162ec3906279fc4334602543",
|
||||
"connected": true,
|
||||
"state": "CHANNELD_AWAITING_LOCKIN",
|
||||
"channel_sat": 100000,
|
||||
"our_amount_msat": "100000000msat",
|
||||
"channel_total_sat": 100000,
|
||||
"amount_msat": "100000000msat",
|
||||
"funding_txid": "66694d23ca15efe379e5f4a71d9be1a2d65e383b89ee3abe126ee36a12f23c1d",
|
||||
"funding_output": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Si bien este nuevo canal con 100.000 satoshis no está confirmado, su estado será `CHANNELD_AWAITING_LOCKIN`. Tenga en cuenta que el cambio no confirmado de satoshis `99847` también se muestra como una nueva transacción en la billetera. Una vez completadas las seis confirmaciones, el canal cambiará al estado `CHANNELD_NORMAL`, que será su estado permanente. En este momento, también aparecerá un `short_channel_id`, como:
|
||||
|
||||
```
|
||||
"short_channel_id": "1862856x29x0",
|
||||
```
|
||||
|
||||
Estos valores indican dónde se puede encontrar la transacción de financiación en la cadena de bloques. Aparece en la forma `block x txid x vout`.
|
||||
|
||||
En este caso, "1862856x29x0" significa:
|
||||
|
||||
* Creado en el bloque 1862856th;
|
||||
* con un `txid` de 29; y
|
||||
* un `vout` de 0.
|
||||
|
||||
Es posible que deba usar este `short_channel_id` para ciertos comandos en Lightning.
|
||||
|
||||
Esta transacción de financiación también se puede encontrar en la cadena en [66694d23ca15efe379e5f4a71d9be1a2d65e383b89ee3abe126ee36a12f23c1d](https://blockstream.info/testnet/tx/66694d23ca15efe379e5f4a71d9be1a2d65e383b89ee3abe126ee36a12f23c1d)
|
||||
|
||||
> :book: ***¿Qué es la capacidad del canal?*** En un canal Lightning, ambos lados del canal poseen una parte de su capacidad. La cantidad de su lado del canal se llama *saldo local* y la cantidad de su lado se llama *saldo remoto*. Ambos saldos se pueden actualizar muchas veces sin cerrar el canal (cuando el saldo final se envía a la cadena de bloques), pero la capacidad del canal no puede cambiar sin cerrarlo o empalmarlo. La capacidad total de un canal es la suma del saldo que tiene cada participante en el canal.
|
||||
|
||||
## Resumen: configuración de un canal
|
||||
|
||||
Necesita crear un canal con un nodo remoto para poder recibir y enviar dinero a través de Lightning Network.
|
||||
|
||||
## ¿Que sigue?
|
||||
|
||||
Usted está listo para continuar! Continúe con el [Capítulo veinte Uso de Lightning](20_0_Usando_Lightning.md).
|
25
es/20_0_Usando_Lightning.md
Normal file
25
es/20_0_Usando_Lightning.md
Normal file
@ -0,0 +1,25 @@
|
||||
# Capítulo Veinte: Usando Lightning
|
||||
|
||||
> :information_source: **NOTA:** Este es un borrador en progreso, por lo que puedo obtener algunos comentarios de los primeros revisores. Todavía no está listo para aprender.
|
||||
|
||||
En este capítulo, continuará trabajando con la interfaz de línea de comandos `lightning-cli`. Creará facturas, realizará pagos y cerrará canales — todas las actividades principales para usar Lightning.
|
||||
|
||||
## Objetivos de Este Capítulo
|
||||
|
||||
Después de trabajar en este capítulo, un desarrollador podrá:
|
||||
|
||||
* Realice pagos en Lightning Network
|
||||
* Aplicar cierre a un canal Lightning.
|
||||
|
||||
Los objetivos de apoyo incluyen la capacidad de:
|
||||
|
||||
* Comprender el formato de las facturas.
|
||||
* Comprender el ciclo de vida de los pagos de Lightning Network.
|
||||
* Sepa cómo expandir la Lightning Network.
|
||||
|
||||
## Tabla de Contenido
|
||||
|
||||
* [Sección Uno: Generación de una Solicitud de Pago](20_1_Generando_una_Solicitud_de_Pago.md)
|
||||
* [Sección Dos: Pagar una Factura](20_2_Pagando_una_Factura.md)
|
||||
* [Sección Tres: Cerrar un Canal Lightning](20_3_Cerrando_un_Canal_Lightning.md)
|
||||
* [Sección Cuatro: Expandiendo la Red Lightning](20_4_Expandiendo_la_Red_Lightning.md)
|
185
es/20_1_Generando_una_Solicitud_de_Pago.md
Normal file
185
es/20_1_Generando_una_Solicitud_de_Pago.md
Normal file
@ -0,0 +1,185 @@
|
||||
|
||||
# 20.1: Generación de una Solicitud de Pago
|
||||
|
||||
> :information_source: **NOTA:** Esta sección se ha agregado recientemente al curso y es un borrador inicial que aún puede estar pendiente de revisión. Lector de advertencias.
|
||||
|
||||
Esta sección describe cómo funcionan los pagos en Lightning Network, cómo crear una solicitud de pago (o _factura_), y, finalmente, cómo entenderla. Le emisión de facturas depende de que tenga un segundo nodo Lightning, como se describe en [Acceso a un Segundo Nodo Lightning](19_2_Interludio_Accediendo_a_un_Segundo_Nodo_Lightning.md). Estos ejemplos usarán un nodo LND como su nodo secundario, para demostrar aún más las posibilidades de Lightning Network. Para diferenciar entre los nodos en estos ejemplos, las solicitudes se mostrarán como `c$` para el nodo c-lightning y `lnd$` como el nodo LND. Si desea reproducir estos pasos, debe [instalar su propio nodo LND secundario](19_2_Interludio_Accediendo_a_un_Segundo_Nodo_Lightning.md#Crear-un-nuevo-nodo-LND).
|
||||
|
||||
> :book: ***¿Qué es una Factura?** Casi todos los pagos realizados en Lightning Network requieren una factura, que no es más que una **solicitud de pago** realizada por el destinatario del dinero y enviada por una variedad de medios al usario que paga. Todas las solicitudes de pago son de un solo uso. Las facturas Lightning utilizan la codificación bech32, que ya utiliza Segregated Witness para Bitcoin.
|
||||
|
||||
## Crear una Factura
|
||||
|
||||
Para crear una nueva factura en c-lightning, usaría el comando `lightning-cli --testnet invoice`.
|
||||
|
||||
Así es como funcionaría con c-lightning, usando argumentos de una cantidad (en millisatoshis), una etiqueta y una descripción.
|
||||
```
|
||||
c$ lightning-cli --testnet invoice 100000 joe-payment "The money you owe me for dinner"
|
||||
{
|
||||
"payment_hash": "07a1c4bd7a38b4dea35f301c173cd8f9aac253b66bd8404d7ad829f226342490",
|
||||
"expires_at": 1603305795,
|
||||
"bolt11": "lntb1u1p0cw3krpp5q7suf0t68z6dag6lxqwpw0xclx4vy5akd0vyqnt6mq5lyf35yjgqdpj235x2grddahx27fq09hh2gr0wajjqmt9ypnx7u3qv35kumn9wgxqyjw5qcqp2sp5r3puay46tffdyzldjv39fw6tzdgu2hnlszamqhnmgjsuxqxavpgs9qy9qsqatawvx44x5qa22m7td84jau5450v7j6sl5224tlv9k5v7wdygq9qr4drz795lfnl52gklvyvnha5e5lx72lzzmgzcfnp942va5thmhsp5sx7c2",
|
||||
"warning_capacity": "No channels",
|
||||
"warning_mpp_capacity": "The total incoming capacity is still insufficient even if the payer had MPP capability."
|
||||
}
|
||||
```
|
||||
Sin embargo, para este ejemplo, vamos a generar una factura en un nodo LND y luego pagarla en el nodo c-lightning. Esto requiere el comando `addinvoice` ligeramente diferente de LND. Puede usar el argumento `--amt` para indicar la cantidad a pagar (en millisatoshis) y agregar una descripción usando el argumento `--memo`.
|
||||
|
||||
```
|
||||
lnd$ lncli -n testnet addinvoice --amt 10000 --memo "First LN Payment - Learning Bitcoin and Lightning from the Command line."
|
||||
{
|
||||
"r_hash": "6cacdedc95b89eec15e5244bd0957b88c0ab58b153eee549735b995344bc16bb",
|
||||
"payment_request": "lntb100u1p0cwnqtpp5djkdahy4hz0wc909y39ap9tm3rq2kk9320hw2jtntwv4x39uz6asdr5ge5hyum5ypxyugzsv9uk6etwwssz6gzvv4shymnfdenjqsnfw33k76twypskuepqf35kw6r5de5kueeqveex7mfqw35x2gzrdakk6ctwvssxc6twv5hqcqzpgsp5a9ryqw7t23myn9psd36ra5alzvp6lzhxua58609teslwqmdljpxs9qy9qsq9ee7h500jazef6c306psr0ncru469zgyr2m2h32c6ser28vrvh5j4q23c073xsvmjwgv9wtk2q7j6pj09fn53v2vkrdkgsjv7njh9aqqtjn3vd",
|
||||
"add_index": "1"
|
||||
}
|
||||
```
|
||||
Tenga en cuenta que estas facturas no hacen referencia directamente al canal que creó: es necesario para el pago, pero no para solicitar el pago.
|
||||
|
||||
## Entender una Factura
|
||||
|
||||
El `bolt11` `payment_request` que ha creado se compone de dos partes: una es legible por humanos y la otra son datos.
|
||||
|
||||
> :book: **Que es un BOLT?** Los BOLTs son las individuales [especificaciones de Lightning Network](https://github.com/lightningnetwork/lightning-rfc).
|
||||
|
||||
### Lea la Parte de la Factura Legible por Humanos
|
||||
|
||||
La parte legible por humanos de sus facturas comienza con un `ln`. Es `lnbc` para Bitcoin mainnet, `lntb` para Bitcoin testnet, o `lnbcrt` para Bitcoin regtest.
|
||||
Luego enumera los fondos solicitados en la factura.
|
||||
|
||||
Por ejemplo, mire su factura desde su nodo LND:
|
||||
```
|
||||
lntb100u1p0cwnqtpp5djkdahy4hz0wc909y39ap9tm3rq2kk9320hw2jtntwv4x39uz6asdr5ge5hyum5ypxyugzsv9uk6etwwssz6gzvv4shymnfdenjqsnfw33k76twypskuepqf35kw6r5de5kueeqveex7mfqw35x2gzrdakk6ctwvssxc6twv5hqcqzpgsp5a9ryqw7t23myn9psd36ra5alzvp6lzhxua58609teslwqmdljpxs9qy9qsq9ee7h500jazef6c306psr0ncru469zgyr2m2h32c6ser28vrvh5j4q23c073xsvmjwgv9wtk2q7j6pj09fn53v2vkrdkgsjv7njh9aqqtjn3vd
|
||||
```
|
||||
La parte legible por humanos `ln` + `tb` + `100u`.
|
||||
|
||||
`lntb` dice que esta es una factura de Lightning Network para los bitcoins de Testnet.
|
||||
|
||||
`100u` dice que es por 100 bitcoins multiplicado por el multiplicador de microsatoshi. Hay cuatro multiplicadores de fondos (opcionales):
|
||||
|
||||
* `m` (milli): multiplicar por 0.001
|
||||
* `u` (micro): multiplicar por 0.000001
|
||||
* `n` (nano): multiplicar por 0.000000001
|
||||
* `p` (pico): multiplicar por 0.000000000001
|
||||
|
||||
100 BTC * .000001 = .0001 BTC, que es lo mismo que 10,000 satoshis.
|
||||
|
||||
### Leer la Parte de la Factura de Datos
|
||||
|
||||
El resto de la factura (`1p0cwnqtpp5djkdahy4hz0wc909y39ap9tm3rq2kk9320hw2jtntwv4x39uz6asdr5ge5hyum5ypxyugzsv9uk6etwwssz6gzvv4shymnfdenjqsnfw33k76twypskuepqf35kw6r5de5kueeqveex7mfqw35x2gzrdakk6ctwvssxc6twv5hqcqzpgsp5a9ryqw7t23myn9psd36ra5alzvp6lzhxua58609teslwqmdljpxs9qy9qsq9ee7h500jazef6c306psr0ncru469zgyr2m2h32c6ser28vrvh5j4q23c073xsvmjwgv9wtk2q7j6pj09fn53v2vkrdkgsjv7njh9aqqtjn3vd`) contiene una marca de tiempo, datos etiquetados específicamente y una firma. Obviamente, no puede leerlo usted mismo, pero puede pedirle a `lightning-cli` de c-lightning que lo haga con el comando `decodepay`:
|
||||
```
|
||||
c$ lightning-cli --testnet decodepay lntb100u1p0cwnqtpp5djkdahy4hz0wc909y39ap9tm3rq2kk9320hw2jtntwv4x39uz6asdr5ge5hyum5ypxyugzsv9uk6etwwssz6gzvv4shymnfdenjqsnfw33k76twypskuepqf35kw6r5de5kueeqveex7mfqw35x2gzrdakk6ctwvssxc6twv5hqcqzpgsp5a9ryqw7t23myn9psd36ra5alzvp6lzhxua58609teslwqmdljpxs9qy9qsq9ee7h500jazef6c306psr0ncru469zgyr2m2h32c6ser28vrvh5j4q23c073xsvmjwgv9wtk2q7j6pj09fn53v2vkrdkgsjv7njh9aqqtjn3vd
|
||||
{
|
||||
"currency": "tb",
|
||||
"created_at": 1602702347,
|
||||
"expiry": 3600,
|
||||
"payee": "032a7572dc013b6382cde391d79f292ced27305aa4162ec3906279fc4334602543",
|
||||
"msatoshi": 10000000,
|
||||
"amount_msat": "10000000msat",
|
||||
"description": "First LN Payment - Learning Bitcoin and Lightning from the Command line.",
|
||||
"min_final_cltv_expiry": 40,
|
||||
"payment_secret": "e946403bcb54764994306c743ed3bf1303af8ae6e7687d3cabcc3ee06dbf904d",
|
||||
"features": "028200",
|
||||
"payment_hash": "6cacdedc95b89eec15e5244bd0957b88c0ab58b153eee549735b995344bc16bb",
|
||||
"signature": "304402202e73ebd1ef974594eb117e8301be781f2ba289041ab6abc558d432351d8365e902202a8151c3fd13419b9390c2b976503d2d064f2a6748b14cb0db64424cf4e572f4"
|
||||
}
|
||||
|
||||
```
|
||||
Esto es lo que significan los elementos más relevantes:
|
||||
|
||||
1. `currency`: La moneda que se paga.
|
||||
2. `created_at`: Hora en que se creó la factura. Esto se mide en tiempo UNIX, que son segundos desde 1970.
|
||||
3. `expiry`: El momento en que su nodo marca la factura como inválida. El valor predeterminado es 1 hora o 3600 segundos.
|
||||
4. `payee`: La clave pública de la persona (nodo) que recibe el pago de Lightning Network.
|
||||
5. `msatoshi` y `amount_msat`: la cantidad de satoshis a pagar.
|
||||
6. `description`: La descripción de entrada del usuario.
|
||||
7. `payment_hash`: El hash de la preimagen que se usa para bloquear el pago. Solo puede canjear un pago bloqueado con la preimagen correspondiente al hash de pago. Esto permite el enrutamiento en Lightning Network, sin confiar en terceros, al crear un **Pago Condicional** para completar.
|
||||
8. `signature`: La firma codificada en DER.
|
||||
|
||||
> :book: ****¿Qué son los Pagos Condicionales?*** Aunque los Canales Lightning se crean entre dos participantes, se pueden conectar múltiples canales entre sí, formando una red de pago que permite pagos entre todos los participantes de la red, incluso aquellos sin un canal directo entre ellos. Esto se hace mediante un contrato intelligente llamado **Hashed Time Locked Contract** o contrato bloqueado por tiempo codificado.
|
||||
|
||||
> :book: ***¿Qué es un Contrato Bloqueado por Tiempo Codificado / Hashed Time Locked Contract (HTLC)?*** Un HTLC es un pago condicional que utiliza bloqueos de codificado y bloqueos de tiempo para garantizar la seguridad del pago. El receptor debe presentar una preimagen de pago o generar un comprobante de pago criptográfico antes de un tiempo determinado, de lo contrario el pagador puede cancelar el contrato gastándolo. Estos contratos se crean como resultados de la **Transacción de Compromiso**.
|
||||
|
||||
> :book: ***¿Qué es una Transacción de Compromiso?*** Una transacción de compromiso es una transacción que gasta la transacción de financiacción original. Cada par tiene la firma del otro par, lo que significa que cualquiera puede gastar su transacción de compromiso cuando quiera. Después de que se crea cada nueva transacción de compromiso, se revoca la anterior. La transacción de compromiso es una forma en que la transacción de financiación se puede desbloquear en la cadena de bloques, como se analiza en [§20.3](20_3_Cerrando_un_Canal_Lightning.md).
|
||||
|
||||
### Verifique su Factura
|
||||
|
||||
Hay dos elementos cruciales para verificar la factura. El primero, obviamente, es el monto del pago, que ya examinó en la parte legible por humanos. El segundo es el valor `payee` (beneficiario) que es la clave pública del destinatario (nodo):
|
||||
```
|
||||
"payee": "032a7572dc013b6382cde391d79f292ced27305aa4162ec3906279fc4334602543",
|
||||
```
|
||||
Debe comprobar que ese es el destinatario esperado.
|
||||
|
||||
Mirando hacia atrás en [§19.3](19_3_Creando_un_Canal_en_Lightning.md#opening-a-channel), puede ver que ese es efectivamente el ID de par que usó cuando creó su canal. También puede verificarlo en el nodo opuesto con el comando `getinfo`.
|
||||
```
|
||||
lnd$ lncli -n testnet getinfo
|
||||
{
|
||||
"version": "0.11.0-beta.rc4 commit=v0.11.0-beta.rc4",
|
||||
"commit_hash": "fc12656a1a62e5d69430bba6e4feb8cfbaf21542",
|
||||
"identity_pubkey": "032a7572dc013b6382cde391d79f292ced27305aa4162ec3906279fc4334602543",
|
||||
"alias": "StandUp",
|
||||
"color": "#3399ff",
|
||||
"num_pending_channels": 0,
|
||||
"num_active_channels": 1,
|
||||
"num_inactive_channels": 0,
|
||||
"num_peers": 3,
|
||||
"block_height": 1862983,
|
||||
"block_hash": "00000000000000c8c2f58f6da2ae2a3884d6e84f55d0e1f585a366f9dfcaa860",
|
||||
"best_header_timestamp": "1602702331",
|
||||
"synced_to_chain": true,
|
||||
"synced_to_graph": true,
|
||||
"testnet": true,
|
||||
"chains": [
|
||||
{
|
||||
"chain": "bitcoin",
|
||||
"network": "testnet"
|
||||
}
|
||||
],
|
||||
"uris": [
|
||||
],
|
||||
"features": {
|
||||
"0": {
|
||||
"name": "data-loss-protect",
|
||||
"is_required": true,
|
||||
"is_known": true
|
||||
},
|
||||
"5": {
|
||||
"name": "upfront-shutdown-script",
|
||||
"is_required": false,
|
||||
"is_known": true
|
||||
},
|
||||
"7": {
|
||||
"name": "gossip-queries",
|
||||
"is_required": false,
|
||||
"is_known": true
|
||||
},
|
||||
"9": {
|
||||
"name": "tlv-onion",
|
||||
"is_required": false,
|
||||
"is_known": true
|
||||
},
|
||||
"13": {
|
||||
"name": "static-remote-key",
|
||||
"is_required": false,
|
||||
"is_known": true
|
||||
},
|
||||
"15": {
|
||||
"name": "payment-addr",
|
||||
"is_required": false,
|
||||
"is_known": true
|
||||
},
|
||||
"17": {
|
||||
"name": "multi-path-payments",
|
||||
"is_required": false,
|
||||
"is_known": true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
Sin embargo, el `payee` (beneficario) también puede ser alguien nuevo, en cuyo caso probablemente deberá consultar con el sitio web o la persona que emitió la factura para asegurarse de que sea correcta.
|
||||
|
||||
## Resumen: Generación de una Solicitud de Pago
|
||||
|
||||
En la mayoría de los casos, debe recibir una factura para utilizar los pagos de Lightning Network. En este ejemplo, creamos uno manualmente, pero si tuviera un entorno de producción, es probable que los sistemas lo hagan automáticamente cada vez que alguien compra productos o servicios. Por supuesto, una vez que haya recibido una factura, debe comprender cómo leerla!
|
||||
|
||||
## Que Sigue?
|
||||
|
||||
Continúe "Usando Lightning" con [§20.2: Pagando una Factura](20_2_Pagando_una_Factura.md).
|
206
es/20_2_Pagando_una_Factura.md
Normal file
206
es/20_2_Pagando_una_Factura.md
Normal file
@ -0,0 +1,206 @@
|
||||
# 20.2: Pagando una Factura
|
||||
|
||||
> :information_source: **NOTA:** Esta sección se ha agregado recientemente al curso y es un borrador inicial que aún puede estar pendiente de revisión. Lector de advertencias.
|
||||
|
||||
En este capitulo aprenderá cómo pagar una factura usando el comando `lightning-cli pay`. Se asume que ya revisó la factura, según [§20.1](20_1_Generando_una_Solicitud_de_Pago.md) y determinó que era válida.
|
||||
|
||||
## Consulta su Saldo
|
||||
|
||||
Obviamente, lo primero que debe hacer es asegurarse de tener fondos suficientes para pagar una factura. En este caso, el canal configurado previamente con `032a7572dc013b6382cde391d79f292ced27305aa4162ec3906279fc4334602543` contiene 100,000 satoshis. Este será el canal utilizado para pagar la factura.
|
||||
|
||||
```
|
||||
c$ lightning-cli --testnet listfunds
|
||||
{
|
||||
"outputs": [
|
||||
{
|
||||
"txid": "66694d23ca15efe379e5f4a71d9be1a2d65e383b89ee3abe126ee36a12f23c1d",
|
||||
"output": 1,
|
||||
"value": 99847,
|
||||
"amount_msat": "99847000msat",
|
||||
"scriptpubkey": "00142fe02e5be9283e8c5bcb93ae61421baf8cb64f9c",
|
||||
"address": "tb1q9lszuklf9qlgck7tjwhxzssm47xtvnuu4jslf8",
|
||||
"status": "confirmed",
|
||||
"blockheight": 1862856,
|
||||
"reserved": false
|
||||
}
|
||||
],
|
||||
"channels": [
|
||||
{
|
||||
"peer_id": "032a7572dc013b6382cde391d79f292ced27305aa4162ec3906279fc4334602543",
|
||||
"connected": true,
|
||||
"state": "CHANNELD_NORMAL",
|
||||
"short_channel_id": "1862856x29x0",
|
||||
"channel_sat": 100000,
|
||||
"our_amount_msat": "100000000msat",
|
||||
"channel_total_sat": 100000,
|
||||
"amount_msat": "100000000msat",
|
||||
"funding_txid": "66694d23ca15efe379e5f4a71d9be1a2d65e383b89ee3abe126ee36a12f23c1d",
|
||||
"funding_output": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
Si no tiene fondos suficientes, debe crear un canal nuevo.
|
||||
|
||||
## Paga su Factura
|
||||
|
||||
Utiliza el comando `lightning-cli pay` para pagar una factura. Intentará encontrar una ruta al destino dado y enviar los fondos solicitados. Aquí eso es muy simple porque hay un canal directo entre el pagador y el destinatario:
|
||||
```
|
||||
c$ lightning-cli --testnet pay lntb100u1p0cwnqtpp5djkdahy4hz0wc909y39ap9tm3rq2kk9320hw2jtntwv4x39uz6asdr5ge5hyum5ypxyugzsv9uk6etwwssz6gzvv4shymnfdenjqsnfw33k76twypskuepqf35kw6r5de5kueeqveex7mfqw35x2gzrdakk6ctwvssxc6twv5hqcqzpgsp5a9ryqw7t23myn9psd36ra5alzvp6lzhxua58609teslwqmdljpxs9qy9qsq9ee7h500jazef6c306psr0ncru469zgyr2m2h32c6ser28vrvh5j4q23c073xsvmjwgv9wtk2q7j6pj09fn53v2vkrdkgsjv7njh9aqqtjn3vd
|
||||
{
|
||||
"destination": "032a7572dc013b6382cde391d79f292ced27305aa4162ec3906279fc4334602543",
|
||||
"payment_hash": "6cacdedc95b89eec15e5244bd0957b88c0ab58b153eee549735b995344bc16bb",
|
||||
"created_at": 1602704828.948,
|
||||
"parts": 1,
|
||||
"msatoshi": 10000000,
|
||||
"amount_msat": "10000000msat",
|
||||
"msatoshi_sent": 10000000,
|
||||
"amount_sent_msat": "10000000msat",
|
||||
"payment_preimage": "1af4a9bb830e49b6bc8f0bef980630e189e3794ad1705f06ad1b9c71571dce0c",
|
||||
"status": "complete"
|
||||
}
|
||||
```
|
||||
¡Tenga en cuenta que aquí todas las cantidades están en `msats`, no en `sats`!
|
||||
|
||||
### Pagar su Factura en Toda la Red
|
||||
|
||||
Sin embargo, _no_ necesita tener un canal con un nodo para poder pagarles. Solo debe haber una ruta razonable a través de Lightning Network.
|
||||
|
||||
Imagine que recibió esta pequeña solicitud de pago por 11,111 msat:
|
||||
```
|
||||
c$ lightning-cli --testnet decodepay lntb111110p1p0cw43ppp5u0ngjytlw6ywec3x784jale4xd7h058g9u4mthcaf9rl2f7g8zxsdp2t9hh2gr0wajjqmt9ypnx7u3qv35kumn9wgs8gmm0yyxqyjw5qcqp2sp5kj4xhrthmfgcgyl84zaqpl9vvdjwm5x368kr09fu5nym74setw4s9qy9qsq8hxjr73ee77vat0ay603e4w9aa8ag9sa2n55xznk5lsfrjffxxdj2k0wznvcfa98l4a57s80j7dhg0cc03vwqdwehkujlzxgm0xyynqqslwhvl
|
||||
{
|
||||
"currency": "tb",
|
||||
"created_at": 1602704929,
|
||||
"expiry": 604800,
|
||||
"payee": "02f3d74746934494fa378235e5bc44cfdbb5b8779d839263fb7f9218be032f6f61",
|
||||
"msatoshi": 11111,
|
||||
"amount_msat": "11111msat",
|
||||
"description": "You owe me for dinner too!",
|
||||
"min_final_cltv_expiry": 10,
|
||||
"payment_secret": "b4aa6b8d77da518413e7a8ba00fcac6364edd0d1d1ec37953ca4c9bf56195bab",
|
||||
"features": "028200",
|
||||
"payment_hash": "e3e689117f7688ece226f1eb2eff35337d77d0e82f2bb5df1d4947f527c8388d",
|
||||
"signature": "304402203dcd21fa39cfbcceadfd269f1cd5c5ef4fd4161d54e9430a76a7e091c929319b02202559ee14d984f4a7fd7b4f40ef979b743f187c58e035d9bdb92f88c8dbcc424c"
|
||||
}
|
||||
```
|
||||
Si intentó pagarlo y no tenía una ruta hacia el destinatario a través de Lightning Network, podría esperar un error como este:
|
||||
```
|
||||
c$ lightning-cli --testnet pay lntb111110p1p0cw43ppp5u0ngjytlw6ywec3x784jale4xd7h058g9u4mthcaf9rl2f7g8zxsdp2t9hh2gr0wajjqmt9ypnx7u3qv35kumn9wgs8gmm0yyxqyjw5qcqp2sp5kj4xhrthmfgcgyl84zaqpl9vvdjwm5x368kr09fu5nym74setw4s9qy9qsq8hxjr73ee77vat0ay603e4w9aa8ag9sa2n55xznk5lsfrjffxxdj2k0wznvcfa98l4a57s80j7dhg0cc03vwqdwehkujlzxgm0xyynqqslwhvl
|
||||
{
|
||||
"code": 210,
|
||||
"message": "Ran out of routes to try after 11 attempts: see `paystatus`",
|
||||
"attempts": [
|
||||
{
|
||||
"status": "failed",
|
||||
"failreason": "Error computing a route to 02f3d74746934494fa378235e5bc44cfdbb5b8779d839263fb7f9218be032f6f61: \"Could not find a route\" (205)",
|
||||
"partid": 1,
|
||||
"amount": "11111msat"
|
||||
},
|
||||
...
|
||||
```
|
||||
Pero, ¿qué pasa si un anfitrión con el que tiene un canal abre un canal con el destinatario previsto?
|
||||
|
||||
En ese caso, cuando vaya a pagar la factura, _funcionará automáticamente_!
|
||||
```
|
||||
c$ lightning-cli --testnet pay lntb111110p1p0cw43ppp5u0ngjytlw6ywec3x784jale4xd7h058g9u4mthcaf9rl2f7g8zxsdp2t9hh2gr0wajjqmt9ypnx7u3qv35kumn9wgs8gmm0yyxqyjw5qcqp2sp5kj4xhrthmfgcgyl84zaqpl9vvdjwm5x368kr09fu5nym74setw4s9qy9qsq8hxjr73ee77vat0ay603e4w9aa8ag9sa2n55xznk5lsfrjffxxdj2k0wznvcfa98l4a57s80j7dhg0cc03vwqdwehkujlzxgm0xyynqqslwhvl
|
||||
{
|
||||
"destination": "02f3d74746934494fa378235e5bc44cfdbb5b8779d839263fb7f9218be032f6f61",
|
||||
"payment_hash": "e3e689117f7688ece226f1eb2eff35337d77d0e82f2bb5df1d4947f527c8388d",
|
||||
"created_at": 1602709081.324,
|
||||
"parts": 1,
|
||||
"msatoshi": 11111,
|
||||
"amount_msat": "11111msat",
|
||||
"msatoshi_sent": 12111,
|
||||
"amount_sent_msat": "12111msat",
|
||||
"payment_preimage": "ec7d1b28a7b877cd92b83be396899e8bfc3ecb0b4f944f65afb4be7d0ee72617",
|
||||
"status": "complete"
|
||||
}
|
||||
```
|
||||
Esa es la verdadera belleza de Lightning Network allí: sin esfuerzo de los participantes igual a igual, sus canales individuales se convierten en una red!
|
||||
|
||||
> :book: ***¿Cómo Funcionan los Pagos en la Red?*** Digamos que el nodo A tiene un canal abierto con el nodo B, el nodo B tiene un canal abierto con el nodo C y el nodo A recibe una factura del nodo C por 11,111 msat. El nodo A paga al nodo B los 11,111 msat, más una pequeña tarifa, y luego el nodo B paga los 11,111 msat al nodo C. Suficientemente fácil. Excepto que recuerde que todos los canales en realidad son solo registros de quién es el propietario de la cantidad de la Transacción de pago. Entonces, lo que realmente sucede es 11,111 msat de la Transacción de pago en el canal A-B cambia de A a B, y luego 11,111 msat de la Transacción de pago en el canal B-C cambia de B a C. Esto significa que se requieren dos cosas para que este pago funcione: primero, cada canal debe tener suficiente capacidad para el pago; y segundo, el pagador en cada canal debe poseer suficiente capacidad para realizar el pago.
|
||||
|
||||
Tenga en cuenta que en este ejemplo, se enviaron 12,111 msat para pagar una factura de 11,111 msat: el extra es una tarifa plana muy pequeña (no un porcentaje) que se pagó al intermediario.
|
||||
|
||||
## Consulta su Saldo
|
||||
|
||||
Después de haber realizado un pago con éxito, debería ver que sus fondos han cambiado en consecuencia.
|
||||
|
||||
Así es como se veían los fondos para el nodo de pago después del pago inicial de 10,000 satoshis:
|
||||
```
|
||||
c$ lightning-cli --testnet listfunds
|
||||
{
|
||||
"outputs": [
|
||||
{
|
||||
"txid": "66694d23ca15efe379e5f4a71d9be1a2d65e383b89ee3abe126ee36a12f23c1d",
|
||||
"output": 1,
|
||||
"value": 99847,
|
||||
"amount_msat": "99847000msat",
|
||||
"scriptpubkey": "00142fe02e5be9283e8c5bcb93ae61421baf8cb64f9c",
|
||||
"address": "tb1q9lszuklf9qlgck7tjwhxzssm47xtvnuu4jslf8",
|
||||
"status": "confirmed",
|
||||
"blockheight": 1862856,
|
||||
"reserved": false
|
||||
}
|
||||
],
|
||||
"channels": [
|
||||
{
|
||||
"peer_id": "032a7572dc013b6382cde391d79f292ced27305aa4162ec3906279fc4334602543",
|
||||
"connected": true,
|
||||
"state": "CHANNELD_NORMAL",
|
||||
"short_channel_id": "1862856x29x0",
|
||||
"channel_sat": 90000,
|
||||
"our_amount_msat": "90000000msat",
|
||||
"channel_total_sat": 100000,
|
||||
"amount_msat": "100000000msat",
|
||||
"funding_txid": "66694d23ca15efe379e5f4a71d9be1a2d65e383b89ee3abe126ee36a12f23c1d",
|
||||
"funding_output": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
Tenga en cuenta que la capacidad del canal permanece en 100,000 satoshis (¡nunca cambia!), pero que `our_amount` (nuestro cantidad) ahora es de solo 90,000 satoshis (o 90,000,000 msat).
|
||||
|
||||
Después de pagar la segunda factura, por 11,111 msat, los fondos cambian nuevamente en consecuencia:
|
||||
```
|
||||
$ lightning-cli --testnet listfunds
|
||||
{
|
||||
"outputs": [
|
||||
{
|
||||
"txid": "66694d23ca15efe379e5f4a71d9be1a2d65e383b89ee3abe126ee36a12f23c1d",
|
||||
"output": 1,
|
||||
"value": 99847,
|
||||
"amount_msat": "99847000msat",
|
||||
"scriptpubkey": "00142fe02e5be9283e8c5bcb93ae61421baf8cb64f9c",
|
||||
"address": "tb1q9lszuklf9qlgck7tjwhxzssm47xtvnuu4jslf8",
|
||||
"status": "confirmed",
|
||||
"blockheight": 1862856,
|
||||
"reserved": false
|
||||
}
|
||||
],
|
||||
"channels": [
|
||||
{
|
||||
"peer_id": "032a7572dc013b6382cde391d79f292ced27305aa4162ec3906279fc4334602543",
|
||||
"connected": true,
|
||||
"state": "CHANNELD_NORMAL",
|
||||
"short_channel_id": "1862856x29x0",
|
||||
"channel_sat": 89987,
|
||||
"our_amount_msat": "89987000msat",
|
||||
"channel_total_sat": 100000,
|
||||
"amount_msat": "100000000msat",
|
||||
"funding_txid": "66694d23ca15efe379e5f4a71d9be1a2d65e383b89ee3abe126ee36a12f23c1d",
|
||||
"funding_output": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
`our_amount` es ahora solo 89,987 satoshis, habiendo pagado 11,111 msat más una tarifa de 1,000 msat.
|
||||
|
||||
## Resumen: Pagando de una Factura
|
||||
|
||||
Una vez que tenga una factura, es bastante fácil pagar con un solo comando en Lightning. Incluso si no tiene un canal para un destinatario, el pago es así de simple, siempre que haya una ruta entre usted y el nodo de destino.
|
||||
|
||||
## ¿Que Sigue?
|
||||
|
||||
Continúe "Usando Lighting" con [§20.3: Cerrando un Canal Lightning](20_3_Cerrando_un_Canal_Lightning.md).
|
259
es/20_3_Cerrando_un_Canal_Lightning.md
Normal file
259
es/20_3_Cerrando_un_Canal_Lightning.md
Normal file
@ -0,0 +1,259 @@
|
||||
# 20.3: Cerrando un Canal
|
||||
|
||||
> :information_source: **NOTA:** Esta sección se ha agregado recientemente al curso y es un borrador inicial que aún puede estar pendiente de revisión. Lector de advertencias.
|
||||
|
||||
En este capítulo aprenderá a cerrar un canal usando la interfaz de línea de comandos `lightning-cli close`. Cerrar un canal significa que usted y su contraparte enviarán el saldo del canal acordado a la blockchain, por lo que debe pagar las tarifas de transacción de la blockchain y esperar a que se mine la transacción. Un cierre puede ser cooperativo o no cooperativo, pero funciona de cualquier manera.
|
||||
|
||||
Para cerrar un canal, primero debe conocer el ID del nodo remoto; puede recuperarlo de dos formas.
|
||||
|
||||
## Encuentra sus Canales por Fondos
|
||||
|
||||
Puede usar el comando `lightning-cli listfunds` para ver sus canales. Este comando RPC muestra todos los fondos disponibles, ya sea en `salidas` (UTXOs) no gastadas en la billetera interna o bloqueados en `canales` abiertos actualmente.
|
||||
```
|
||||
c$ lightning-cli --testnet listfunds
|
||||
{
|
||||
"outputs": [
|
||||
{
|
||||
"txid": "66694d23ca15efe379e5f4a71d9be1a2d65e383b89ee3abe126ee36a12f23c1d",
|
||||
"output": 1,
|
||||
"value": 99847,
|
||||
"amount_msat": "99847000msat",
|
||||
"scriptpubkey": "00142fe02e5be9283e8c5bcb93ae61421baf8cb64f9c",
|
||||
"address": "tb1q9lszuklf9qlgck7tjwhxzssm47xtvnuu4jslf8",
|
||||
"status": "confirmed",
|
||||
"blockheight": 1862856,
|
||||
"reserved": false
|
||||
}
|
||||
],
|
||||
"channels": [
|
||||
{
|
||||
"peer_id": "032a7572dc013b6382cde391d79f292ced27305aa4162ec3906279fc4334602543",
|
||||
"connected": true,
|
||||
"state": "CHANNELD_NORMAL",
|
||||
"short_channel_id": "1862856x29x0",
|
||||
"channel_sat": 89987,
|
||||
"our_amount_msat": "89987000msat",
|
||||
"channel_total_sat": 100000,
|
||||
"amount_msat": "100000000msat",
|
||||
"funding_txid": "66694d23ca15efe379e5f4a71d9be1a2d65e383b89ee3abe126ee36a12f23c1d",
|
||||
"funding_output": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
"message_flags": 1,
|
||||
"channel_flags": 2,
|
||||
"active": true,
|
||||
"last_update": 1595508075,
|
||||
"base_fee_millisatoshi": 1000,
|
||||
"fee_per_millionth": 1,
|
||||
"delay": 40,
|
||||
"htlc_minimum_msat": "1000msat",
|
||||
"htlc_maximum_msat": "280000000msat",
|
||||
"features": ""
|
||||
}
|
||||
```
|
||||
|
||||
Puede recuperar el ID del canal 0 en una variable como esta:
|
||||
```
|
||||
c$ nodeidremote=$(lightning-cli --testnet listfunds | jq '.channels[0] | .peer_id')
|
||||
```
|
||||
|
||||
## Encuentra sus Canales con JQ
|
||||
|
||||
La otra forma de encontrar canales para cerrar es usando el comando `listchannels`. Devuelve datos sobre canales que son conocidos por el nodo. Debido a que los canales pueden ser bidireccionales, se devolverán hasta dos nodos para cada canal (uno para cada dirección).
|
||||
|
||||
Sin embargo, la red de chismes de Lightning es muy efectiva, por lo que en poco tiempo conocerá miles de canales. Eso es excelente para enviar pagos a través de Lightning Network, pero menos útil para descubrir sus propios canales. Hacerlo requiere un poco trabajo `jq`.
|
||||
|
||||
Primero, necesita saber su propia ID de nodo, que puede ser recuperada con `getinfo`:
|
||||
```
|
||||
c$ nodeid=$(lightning-cli --testnet getinfo | jq .id)
|
||||
c$ echo $nodeid
|
||||
"03240a4878a9a64aea6c3921a434e573845267b86e89ab19003b0c910a86d17687"
|
||||
c$
|
||||
```
|
||||
Luego puede usar eso para buscar a través de `listchannels` por cualquier canal donde su nodo sea el origen o el destino:
|
||||
```
|
||||
c$ lightning-cli --testnet listchannels | jq '.channels[] | select(.source == '$nodeid' or .destination == '$nodeid')'
|
||||
{
|
||||
"source": "03240a4878a9a64aea6c3921a434e573845267b86e89ab19003b0c910a86d17687",
|
||||
"destination": "032a7572dc013b6382cde391d79f292ced27305aa4162ec3906279fc4334602543",
|
||||
"short_channel_id": "1862856x29x0",
|
||||
"public": true,
|
||||
"satoshis": 100000,
|
||||
"amount_msat": "100000000msat",
|
||||
"message_flags": 1,
|
||||
"channel_flags": 0,
|
||||
"active": true,
|
||||
"last_update": 1602639570,
|
||||
"base_fee_millisatoshi": 1,
|
||||
"fee_per_millionth": 10,
|
||||
"delay": 6,
|
||||
"htlc_minimum_msat": "1msat",
|
||||
"htlc_maximum_msat": "99000000msat",
|
||||
"features": ""
|
||||
}
|
||||
```
|
||||
Ahí está nuestro viejo favorito `032a7572dc013b6382cde391d79f292ced27305aa4162ec3906279fc4334602543` nuevamente, como destino.
|
||||
|
||||
Una vez que sepa lo que tiene, puede almacenarlo en una variable:
|
||||
```
|
||||
c$ nodeidremote=$(lightning-cli --testnet listchannels | jq '.channels[] | select(.source == '$nodeid' or .destination == '$nodeid') | .destination')
|
||||
```
|
||||
|
||||
## Cerrar un Canal
|
||||
|
||||
Ahora que tiene un ID de nodo remoto, está listo para usar el comando `lightning-cli close` para cerrar un canal. De forma predeterminada, intentará cerrar el canal de forma cooperativa con el par; si desea cerrarlo unilateralmente, establezca el argumento `unilateraltimeout` con el número de segundos de espera. (Si lo establece en 0 y el par está en línea, aún se intenta un cierre mutuo.) Para este ejemplo, intentará un cierre mutuo.
|
||||
|
||||
```
|
||||
c$ lightning-cli --testnet close $nodeidremote 0
|
||||
{
|
||||
"tx": "02000000011d3cf2126ae36e12be3aee893b385ed6a2e19b1da7f4e579e3ef15ca234d69660000000000ffffffff021c27000000000000160014d39feb57a663803da116402d6cb0ac050bf051d9cc5e01000000000016001451c88b44420940c52a384bd8a03888e3676c150900000000",
|
||||
"txid": "f68de52d80a1076e36c677ef640539c50e3d03f77f9f9db4f13048519489593f",
|
||||
"type": "mutual"
|
||||
}
|
||||
```
|
||||
La transacción de cierre en cadena es [f68de52d80a1076e36c677ef640539c50e3d03f77f9f9db4f13048519489593f](https://blockstream.info/testnet/tx/f68de52d80a1076e36c677ef640539c50e3d03f77f9f9db4f13048519489593f).
|
||||
|
||||
Es esta transacción de cierre la que realmente desembolsa los fondos que se intercambiaron de un lado a otro a través de transacciones Lightning. Esto se puede ver examinando la transacción:
|
||||
```
|
||||
$ bitcoin-cli --named getrawtransaction txid=f68de52d80a1076e36c677ef640539c50e3d03f77f9f9db4f13048519489593f verbose=1
|
||||
{
|
||||
"txid": "f68de52d80a1076e36c677ef640539c50e3d03f77f9f9db4f13048519489593f",
|
||||
"hash": "3a6b3994932ae781bab80e159314bad06fc55d3d33453a1d663f9f9415c9719c",
|
||||
"version": 2,
|
||||
"size": 334,
|
||||
"vsize": 169,
|
||||
"weight": 673,
|
||||
"locktime": 0,
|
||||
"vin": [
|
||||
{
|
||||
"txid": "66694d23ca15efe379e5f4a71d9be1a2d65e383b89ee3abe126ee36a12f23c1d",
|
||||
"vout": 0,
|
||||
"scriptSig": {
|
||||
"asm": "",
|
||||
"hex": ""
|
||||
},
|
||||
"txinwitness": [
|
||||
"",
|
||||
"304402207f8048e29192ec86019bc83be8b4cac5d1fc682374538bed0707f58192d41c390220512ebcde122d53747feedd70c09153a40c56d09a5fec02e47642afdbb20aa2ac01",
|
||||
"3045022100d686a16084b60800fa0f6b14c25dca1c13d10a55c5fb7c6a3eb1c5f4a2fb20360220555f5b6e672cf9ef82941f7d46ee03dd52e0e848b9f094a41ff299deb8207cab01",
|
||||
"522102f7589fd8366252cdbb37827dff65e3304abd5d17bbab57460eff71a9e32bc00b210343b980dff4f2723e0db99ac72d0841aad934b51cbe556ce3a1b257b34059a17052ae"
|
||||
],
|
||||
"sequence": 4294967295
|
||||
}
|
||||
],
|
||||
"vout": [
|
||||
{
|
||||
"value": 0.00010012,
|
||||
"n": 0,
|
||||
"scriptPubKey": {
|
||||
"asm": "0 d39feb57a663803da116402d6cb0ac050bf051d9",
|
||||
"hex": "0014d39feb57a663803da116402d6cb0ac050bf051d9",
|
||||
"reqSigs": 1,
|
||||
"type": "witness_v0_keyhash",
|
||||
"addresses": [
|
||||
"tb1q6w07k4axvwqrmggkgqkkev9vq59lq5we5fcrzn"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"value": 0.00089804,
|
||||
"n": 1,
|
||||
"scriptPubKey": {
|
||||
"asm": "0 51c88b44420940c52a384bd8a03888e3676c1509",
|
||||
"hex": "001451c88b44420940c52a384bd8a03888e3676c1509",
|
||||
"reqSigs": 1,
|
||||
"type": "witness_v0_keyhash",
|
||||
"addresses": [
|
||||
"tb1q28ygk3zzp9qv223cf0v2qwygudnkc9gfp30ud4"
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"hex": "020000000001011d3cf2126ae36e12be3aee893b385ed6a2e19b1da7f4e579e3ef15ca234d69660000000000ffffffff021c27000000000000160014d39feb57a663803da116402d6cb0ac050bf051d9cc5e01000000000016001451c88b44420940c52a384bd8a03888e3676c1509040047304402207f8048e29192ec86019bc83be8b4cac5d1fc682374538bed0707f58192d41c390220512ebcde122d53747feedd70c09153a40c56d09a5fec02e47642afdbb20aa2ac01483045022100d686a16084b60800fa0f6b14c25dca1c13d10a55c5fb7c6a3eb1c5f4a2fb20360220555f5b6e672cf9ef82941f7d46ee03dd52e0e848b9f094a41ff299deb8207cab0147522102f7589fd8366252cdbb37827dff65e3304abd5d17bbab57460eff71a9e32bc00b210343b980dff4f2723e0db99ac72d0841aad934b51cbe556ce3a1b257b34059a17052ae00000000",
|
||||
"blockhash": "000000000000002a214b1ffc3a67c64deda838dd24d12154c15d3a6f1137e94d",
|
||||
"confirmations": 1,
|
||||
"time": 1602713519,
|
||||
"blocktime": 1602713519
|
||||
}
|
||||
```
|
||||
La entrada de la transacción es `66694d23ca15efe379e5f4a71d9be1a2d65e383b89ee3abe126ee36a12f23c1d`, que era la transacción de financiación en [§19.3](19_3_Creando_un_Canal_en_Lightning.md). La transacción tiene dos salidas, una para el nodo remoto y la otra para la billetera c-lightning local. La salida en el índice 0 corresponde al nodo remoto con un valor de 0.00010012 BTC; y la salida en el índice 1 corresponde al nodo local con un valor de 0.00089804 BTC.
|
||||
|
||||
Lightning mostrará de manera similar 89804 satoshis devueltos como un nuevo UTXO en su billetera:
|
||||
```
|
||||
$ lightning-cli --network=testnet listfunds
|
||||
{
|
||||
"outputs": [
|
||||
{
|
||||
"txid": "66694d23ca15efe379e5f4a71d9be1a2d65e383b89ee3abe126ee36a12f23c1d",
|
||||
"output": 1,
|
||||
"value": 99847,
|
||||
"amount_msat": "99847000msat",
|
||||
"scriptpubkey": "00142fe02e5be9283e8c5bcb93ae61421baf8cb64f9c",
|
||||
"address": "tb1q9lszuklf9qlgck7tjwhxzssm47xtvnuu4jslf8",
|
||||
"status": "confirmed",
|
||||
"blockheight": 1862856,
|
||||
"reserved": false
|
||||
},
|
||||
{
|
||||
"txid": "f68de52d80a1076e36c677ef640539c50e3d03f77f9f9db4f13048519489593f",
|
||||
"output": 1,
|
||||
"value": 89804,
|
||||
"amount_msat": "89804000msat",
|
||||
"scriptpubkey": "001451c88b44420940c52a384bd8a03888e3676c1509",
|
||||
"address": "tb1q28ygk3zzp9qv223cf0v2qwygudnkc9gfp30ud4",
|
||||
"status": "confirmed",
|
||||
"blockheight": 1863006,
|
||||
"reserved": false
|
||||
}
|
||||
],
|
||||
"channels": [
|
||||
{
|
||||
"peer_id": "032a7572dc013b6382cde391d79f292ced27305aa4162ec3906279fc4334602543",
|
||||
"connected": false,
|
||||
"state": "ONCHAIN",
|
||||
"short_channel_id": "1862856x29x0",
|
||||
"channel_sat": 89987,
|
||||
"our_amount_msat": "89987000msat",
|
||||
"channel_total_sat": 100000,
|
||||
"amount_msat": "100000000msat",
|
||||
"funding_txid": "66694d23ca15efe379e5f4a71d9be1a2d65e383b89ee3abe126ee36a12f23c1d",
|
||||
"funding_output": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### Entender los Tipos de Canales de Cierre
|
||||
|
||||
El comando `close` RPC intenta cerrar un canal de manera cooperativa con su par o unilateralmente después de que expire al argumento `unilateraltimeout`. Esto conlleva una discusión adicional, ya que va al corazón del diseño sin confianza de Lightning:
|
||||
|
||||
Cada participante de un canal puede crear tantos pagos Lightning a su contraparte como lo permitan sus fondos. La mayoría de las veces no habrá desacuerdos entre los participantes, por lo que solo habrá dos transacciones en cadena, una abriendo y la otra cerrando el canal. Sin embargo, puede haber escenarios en los que un par no esté en línea o no esté de acuerdo con el estado final del canal o cuando alguien intente robar fondos de la otra parte. Es por eso que existen cierres tanto cooperativos como forzosos.
|
||||
|
||||
#### Cierre Cooperativo
|
||||
|
||||
En el caso de un cierre cooperativo, ambos participantes del canal acuerdan cerrar el canal y establecer el estado final de la blockchain. Ambos participantes deben estar en línea; El cierre se realiza mediante la transmisíon de un gasto incondicional de la transacción de financiación con una salida a cada par.
|
||||
|
||||
#### Forzar Cierre
|
||||
|
||||
En el caso de un cierre forzado, solo un participante está en línea o los participantes no están de acuerdo con el estado final del canal. En esta situación, un par puede realizar un cierre unilateral del canal sin la cooperación del otro nodo. Se realiza mediante la transmisión de una transacción de compromiso que se compromete con un estado de canal anterior que ambas partes han acordado. Esta transacción de compromiso contiene el estado del canal dividido en dos partes: el saldo de cada participante y todos los pagos pendientes (HTLCs).
|
||||
|
||||
Para realizar este tipo de cierre, debe especificar un argumento `unilateraltimeout`. Si este valor no es cero, el comando de cierre cerrará unilateralmente el canal cuando se alcance ese número de segundos:
|
||||
```
|
||||
c$ lightning-cli --network=testnet close $newidremote 60
|
||||
{
|
||||
"tx": "0200000001a1091f727e6041cc93fead2ea46b8402133f53e6ab89ab106b49638c11f27cba00000000006a40aa8001df85010000000000160014d22818913daf3b4f86e0bcb302a5a812d1ef6b91c6772d20",
|
||||
"txid": "02cc4c647eb3e06f37fcbde39871ebae4333b7581954ea86b27b85ced6a5c4f7",
|
||||
"type": "unilateral"
|
||||
}
|
||||
|
||||
```
|
||||
## Resumen: Cerrando un Canal
|
||||
|
||||
Cuando cierra un canal, realiza una transacción en cadena que pone fin a su relación financiera con el nodo remoto. Para cerrar un canal, debe tener en cuenta su estado y el tipo de cierre que quiere ejecutar.
|
||||
|
||||
## ¿Que Sigue?
|
||||
|
||||
Continúe "Usando Lightning" con [§20.4: Expandiendo la Red Lightning](20_4_Expandiendo_la_Red_Lightning.md).
|
61
es/20_4_Expandiendo_la_Red_Lightning.md
Normal file
61
es/20_4_Expandiendo_la_Red_Lightning.md
Normal file
@ -0,0 +1,61 @@
|
||||
# 20.4: Expandiendo la Red Lightning
|
||||
|
||||
> :information_source: **NOTA:** Esta sección se ha agregado recientemente al curso y es un borrador inicial que aún puede estar pendiente de revisión. Lector de advertencias.
|
||||
|
||||
Estos dos capítulos han cubierto solo algunas de las actividades más importantes con Lightning. Se puede hacer mucho más y es posible una gran variedad. Lo que sigue son algunos consejos a seguir.
|
||||
|
||||
## Usar Complementos de c-lightning
|
||||
|
||||
c-lightning es una implementación ligera, altamente pseronalizable y compatible con el estándar del protocolo de la Red Lightning. Extiende su funcionalidad usando complementos. Principalmente, estos son subprocesos que son inciados por el demonio `lightningd` y pueden interactuar con `lightningd` en una variedad de formas:
|
||||
|
||||
* Las opciones de la línea de comandos permiten que los complementos registren sus propios argumentos de línea de comandos, que luego se exponen a través de `lightningd`.
|
||||
* El paso de comandos JSON-RPC permite que los complementos agreguen sus propios comandos a la interfaz JSON-RPC.
|
||||
* Las suscripciones de flujo de eventos proporcionan complementos con un mecanismo de notificación basado en push para `lightnind`.
|
||||
* Los hooks son una opción primitiva que permite que los complementos sean notificados sobre eventos en el demonio `lightningd` y modifiquen su comportamiento o transmitan comportamientos personalizados.
|
||||
|
||||
Un complemento puede estar escrito en cualquier lenguaje y puede comunicarse con `lightningd` a través de stdin y stdout del complemento. JSON-RPCv2 se utiliza como protocolo en la parte superior de los dos flujos, con el complemento actuando como servidor y `lightningd` actuando como cliente.
|
||||
|
||||
El repositorio de GitHub `lightningd` mantiene una lista actualizada de [complementos](https://github.com/lightningd/plugins) disponibles.
|
||||
|
||||
## Usar Carteras Móviles
|
||||
|
||||
Actualmente conocemos dos billeteras Lightning móviles que admiten la implementación de c-lightning.
|
||||
|
||||
Para dispositivos iOS, FullyNoded es una billetera de Bitcoin para iOS de código abierto que se conecta a través del servicio autenticado Tor V3 a su propio nodo completo. La funcionalidad FullyNoded se encuentra actualmente en desarrolo activo y en la fase de prueba beta inicial.
|
||||
|
||||
* [FullyNoded](https://github.com/Fonta1n3/FullyNoded/blob/master/Docs/Lightning.md)
|
||||
|
||||
SparkWallet es una GUI de billetera minimalista para c-lightning, accesible a través de la web o mediante aplicaciones móviles y de escritorio para Android.
|
||||
|
||||
* [SparkWallet](https://github.com/shesek/spark-wallet)
|
||||
|
||||
## Usar Differentes Implementaciones Lightning
|
||||
|
||||
c-lightning no es su única opción. Hoy en día existen tres implementaciones ampliamente utilizadas de la Red Network. Todos siguen los [documentos Basis of Lightning Technology (BOLT)](https://github.com/lightningnetwork/lightning-rfc), (la base de la tecnología lightning) que describen un protocolo de layer-2 para transferencias de bitcoins fuera de la cadena. Las especificaciones son actualmente un trabajo en progreso que aún se está redactando.
|
||||
|
||||
| Nombre | Descripción | BitcoinStandup | Lenguaje | Repositorio |
|
||||
| ------------- | ------------- | :---: | ------------- | ------------- |
|
||||
| C-lighting | Blockstream | X | C | [Descargar](https://github.com/ElementsProject/lightning) |
|
||||
| LND | Lightning Labs | X | Go | [Descargar](https://github.com/lightningnetwork/lnd) |
|
||||
| Eclair | ACINQ | - | Scala | [Descargar](https://github.com/ACINQ/eclair) |
|
||||
|
||||
## Mantener Copias de Seguridad
|
||||
|
||||
Su nodo Lightning debe estar en línea todo el tiempo; de lo contrario, su contraparte podría enviar un estado de canal anterior y robar sus fondos. Sin embargo, existe otro escenario en el que se pueden perder fondos, y es cuando ocurre una falla de hardware que impide que el nodo establezca un cierre cooperativo con la contraparte. Esto probablemente significará que si no tiene una copia exacta del estado del canal antes de la falla, tendrá un estado no válido que podría hacer que el otro nodo lo asuma como un intento de fraude y use la transacción de penalización. En este caso, se perderán todos los fondos. Para evitar esta situación indeseable existe una solución basada en la alta disponibilidad de [la base de postgresQL](https://github.com/gabridome/docs/blob/master/c-lightning_with_postgresql_reliability.md).
|
||||
|
||||
No hemos probado esta solución.
|
||||
|
||||
## Resumen: Expandiendo la Red Lightning
|
||||
|
||||
Puede usar diferentes implementaciones complementos billeteras móviles o copias de seguridad para expandir su experiencia Lightning.
|
||||
|
||||
## ¿Que Sigue?
|
||||
|
||||
Ha completado Aprender Bitcoin Desde la Línea de Comandos, aunque si nunca visitó los [Apéndices](A0_Apendices.md) de configuraciones alternativas, puede hacerlo ahora.
|
||||
|
||||
De lo contrario, le recomendamos que se una a las comunidades de desarrolladores, programe y ponga en práctica sus nuevos conocimientos.
|
||||
|
||||
También puede ayudarnos aquí en Blockchain Commons con problemas o relaciones públicas para aprender Bitcoin o para cualquiera de nuestros otros repositorios, o inlcuso puede convertirse en [Patrocinador](https://github.com/sponsors/BlockchainCommons). También puede ayudar haciendo correr la voz: informe a las personas en las redes sociales sobre el curso y lo que aprendió de él!
|
||||
|
||||
Ahora salga y haga de la comunidad Blockchain un lugar mejor!
|
||||
|
24
es/A0_Apendices.md
Normal file
24
es/A0_Apendices.md
Normal file
@ -0,0 +1,24 @@
|
||||
# Apéndices
|
||||
|
||||
El cuerpo principal de este curso sugiere una configuración bastante estándar
|
||||
para hacer pruebas con Bitcoin. Lo que sigue en estos apéndices es una mejor
|
||||
explicación de la configuración y otras opciones de alternativas.
|
||||
|
||||
## Objetivos para esta sección
|
||||
|
||||
Después de trabajar en este capítulo, un desarrollador podrá:
|
||||
|
||||
* Decidir entre múltiples métodos para crear una cadena de bloques Bitcoin.
|
||||
|
||||
Los objetivos de apoyo incluyen la capacidad de:
|
||||
|
||||
* Entender la configuración de inicio de Bitcoin
|
||||
* Realizar una compilación de Bitcoin a mano
|
||||
* Entender el poder de Regtest
|
||||
* Utilizar el entorno Regtest
|
||||
|
||||
## Tabla de Contenido
|
||||
|
||||
* [Apéndice Uno: Entendiendo la Configuración Inicial de Bitcoin](A1_0_Entendiendo_Bitcoin_Standup.md)
|
||||
* [Apéndice Dos: Compilando Bitcoin desde la Fuente](A2_0_Compilando_Bitcoin_desde_la_Fuente.md)
|
||||
* [Apéndice Tres: Usando Bitcoin Regtest](A3_0_Usando_Bitcoin_Regtest.md)
|
87
es/A1_0_Entendiendo_Bitcoin_Standup.md
Normal file
87
es/A1_0_Entendiendo_Bitcoin_Standup.md
Normal file
@ -0,0 +1,87 @@
|
||||
# Apéndice I: Entendiendo la Configuración Inicial de Bitcoin
|
||||
|
||||
[§2.1: Configurando un VPS Bitcoin-Core con Bitcoin-Standup](02_1_Configurando_un_Bitcoin-Core_VPS_con_StackScript.md)
|
||||
explica el proceso de crear un nodo Bitcoin usando
|
||||
[Bitcoin-Standup-Scripts](https://github.com/BlockchainCommons/Bitcoin-Standup-Scripts).
|
||||
El siguiente apéndice explica que hacen las principales secciones del programa.
|
||||
Usted puede querer seguir junto con
|
||||
[Linode Standup](https://github.com/BlockchainCommons/Bitcoin-Standup-Scripts/blob/master/Scripts/LinodeStandUp.sh)
|
||||
en otra ventana.
|
||||
|
||||
## Paso 1: Nombre del host
|
||||
|
||||
Su nombre de host es almacenado en `/etc/hostname` y configurado con el comando
|
||||
`hostname`. También aparece en `/etc/hosts`.
|
||||
|
||||
## Paso 2: Zona horaria
|
||||
|
||||
La zona horaria de su host es almacenada en `/etc/timezone`, luego un archivo
|
||||
apropiado es copiado desde `/usr/share/zoneinfo/` a `/etc/localtime`.
|
||||
|
||||
## Paso 3: Actualizando Debian
|
||||
|
||||
El gestor de paquetes `apt-get` es usado para actualizar su maquina e instalar
|
||||
`gnupg`, el generador de números aleatorios `haveged`, y el cortafuegos simple
|
||||
`ufw`.
|
||||
|
||||
Su maquina es configurada automáticamente para estar al día con `echo
|
||||
"unattended-upgrades unattended-upgrades/enable_auto_updates boolean true" |
|
||||
debconf-set-selections`.
|
||||
|
||||
## Paso 4: Configurando un usuario
|
||||
|
||||
Un usuario `standup` es creado, el cual sera usado por sus aplicaciones
|
||||
Bitcoin. Este también tiene permisos `sudo`, permitiéndole tomar acciones
|
||||
privilegiadas con esta cuenta.
|
||||
|
||||
Si usted suministro una llave SSH, esta le permitirá acceder a su cuenta (de
|
||||
otra manera, deberá usar una contraseña creada en la configuración).
|
||||
|
||||
Si usted suministro una dirección IP, el acceso `ssh` estará limitado a esa
|
||||
dirección, según `/etc/hosts.allow`.
|
||||
|
||||
## Paso 5: Configurando Tor
|
||||
|
||||
Tor es instalado para proveer servicios protegidos (ocultos) para acceder a los
|
||||
comandos RPC de Bitcoin a través de su servidor. Vea
|
||||
[§14.1: Verificando Su Configuración Tor](14_1_Verificando_Su_Configuracion_Tor.md)
|
||||
para mas información acerca de su configuración Tor.
|
||||
|
||||
Si usted suministro un cliente autorizado para los servicios ocultos, el acceso
|
||||
estará limitado para esa llave, según
|
||||
`/var/lib/tor/standup/authorized_clients`. Si usted no lo hizo,
|
||||
[§14.2](14_2_Cambiando_Sus_Servicios_Bitcoin_Ocultos.md) explica como hacerlo
|
||||
luego.
|
||||
|
||||
## Paso 6: Instalando Bitcoin
|
||||
|
||||
Bitcoin es instalado en `~standup/.bitcoin`. Su configuración es almacenada en
|
||||
`~standup/.bitcoin/bitcoin.conf`.
|
||||
|
||||
Asegúrese que las sumas de comprobación verifiquen según
|
||||
[§2.1](02_1_Configurando_un_Bitcoin-Core_VPS_con_StackScript.md), de otra
|
||||
manera, podría estar expuesto a ataques de la cadena de suministro.
|
||||
|
||||
## Paso 7: Instalando codificador QR
|
||||
|
||||
Para mantener todo compatible con
|
||||
[GordianSystem](https://github.com/BlockchainCommons/GordianSystem), un código
|
||||
QR es creado en `/qrcode.png`. Esto puede leerse desde un cliente QuickConnect,
|
||||
tal como
|
||||
[GordianWallet](https://github.com/BlockchainCommons/GordianWallet-iOS)
|
||||
|
||||
## Conclusión — Entendiendo la Configuración Inicial de Bitcoin
|
||||
|
||||
Bitcoin Standup usa programas para probar e imitar mucha de las funcionalidades
|
||||
de un [GordianNode](https://github.com/BlockchainCommons/GordianNode-macOS).
|
||||
Este debe proveerlo con un entorno Bitcoin seguro, construido en las bases de
|
||||
Bitcoin Core y Tor para comunicaciones RPC.
|
||||
|
||||
## ¿Que sigue?
|
||||
|
||||
Si usted se encontraba en el proceso de crear un nodo Bitcoin para utilizar en
|
||||
este curso, usted debería volver a
|
||||
[§2.1](02_1_Configurando_un_Bitcoin-Core_VPS_con_StackScript.md).
|
||||
|
||||
Si usted esta leyendo a través de los apéndices, continúe con
|
||||
[Apéndice II: Compilando Bitcoin desde la Fuente](A2_0_Compilando_Bitcoin_desde_la_Fuente.md).
|
182
es/A2_0_Compilando_Bitcoin_desde_la_Fuente.md
Normal file
182
es/A2_0_Compilando_Bitcoin_desde_la_Fuente.md
Normal file
@ -0,0 +1,182 @@
|
||||
# Apéndice II: Compilando Bitcoin desde la Fuente
|
||||
|
||||
Este curso presume que usted usara un programa para crear un entorno Bitcoin,
|
||||
tanto usando Bitcoin Standup para Linode según
|
||||
[§2.1](02_1_Configurando_un_Bitcoin-Core_VPS_con_StackScript.md), o vía alguna
|
||||
otra forma, de acuerdo con [§2.2](02_2_Configurando_Bitcoin_Core_Otros.md). Sin
|
||||
embargo, usted puede preferir compilar Bitcoin a mano.
|
||||
|
||||
Esto tiene los siguientes beneficios:
|
||||
|
||||
1. Usted siempre estará actualizado con el ultimo lanzamiento. Consideración:
|
||||
Estar siempre actualizado no es necesario para Bitcoin Core, ya que el
|
||||
software siempre es retro compatible, esto quiere decir que una versión de
|
||||
Bitcoin Core sera capaz de participar en la red Bitcoin, a pesar de no
|
||||
contar con las ultimas características.
|
||||
2. Usted no necesitara depender de binarios pre compilados de Bitcoin Core.
|
||||
Esto requiere menos confianza. Aun que los mantenedores de Bitcoin Core
|
||||
hacen un gran trabajo manteniendo la integridad del código, un binario pre
|
||||
compilado esta unos pasos por detrás del código fuente. Cuando usted compila
|
||||
desde el código fuente, el código puede ser inspeccionado antes de la
|
||||
compilación.
|
||||
3. Usted puede personalizar la compilación, haciendo cosas tales como
|
||||
deshabilitar los monederos o la interfaz gráfica de usuario.
|
||||
|
||||
## Prepare su Entorno
|
||||
|
||||
Este tutorial utiliza Debian 10.4.kv0 OS en una arquitectura amd64
|
||||
(computadoras de 64-bits), pero usted puede usar este tutorial en cualquier
|
||||
sistema basado en Debian (por ej. Ubuntu, Mint, etc.). Para otros sistemas
|
||||
Linux, puede adaptar los siguientes pasos con el gestor de paquetes para ese
|
||||
sistema.
|
||||
|
||||
Usted puede tener conocimientos básicos o ninguna familiaridad con la línea de
|
||||
comandos, siempre y cuando tenga entusiasmo. La terminal es su mas poderoso
|
||||
aliado, no algo para ser temido. Usted puede simplemente copiar y pegar los
|
||||
siguientes comandos para compilar bitcoin (un comando con un "$" es un comando
|
||||
de un usuario común y uno con un "#" es un comando de un superusuario o
|
||||
administrador).
|
||||
|
||||
Si usted no esta en la lista de superusuario entonces haga lo siguiente:
|
||||
|
||||
```
|
||||
$ su root
|
||||
<enter root passwd>
|
||||
# apt-get install sudo
|
||||
# usermod -aG sudo <username>
|
||||
# reboot
|
||||
```
|
||||
|
||||
## Instale Bitcoin
|
||||
|
||||
### Paso 1: Actualice su sistema
|
||||
|
||||
Primero, actualice el sistema usando:
|
||||
```
|
||||
$ sudo apt-get update
|
||||
```
|
||||
|
||||
### Paso 2: Instale Git y sus dependencias
|
||||
|
||||
Instale `git`, el cual le permitirá descargar el código fuente, y
|
||||
`build-essential`, el cual compila el código:
|
||||
```
|
||||
$ sudo apt-get install git build-essential -y
|
||||
```
|
||||
|
||||
Después, instale las dependencias restantes:
|
||||
```
|
||||
$ sudo apt-get install libtool autotools-dev automake pkg-config bsdmainutils
|
||||
python3 libssl-dev libevent-dev libboost-system-dev libboost-filesystem-dev
|
||||
libboost-chrono-dev libboost-test-dev libboost-thread-dev libminiupnpc-dev
|
||||
libzmq3-dev libqt5gui5 libqt5core5a libqt5dbus5 qttools5-dev qttools5-dev-tools
|
||||
libprotobuf-dev protobuf-compiler ccache -y
|
||||
```
|
||||
|
||||
### Paso 3: Descargue el código fuente
|
||||
|
||||
Una vez que las dependencias están instaladas, descargue el repositorio (repo)
|
||||
conteniendo el código fuente de Bitcoin desde github:
|
||||
```
|
||||
$ git clone https://github.com/bitcoin/bitcoin.git
|
||||
```
|
||||
Verifique el contenido del repo:
|
||||
```
|
||||
$ ls bitcoin
|
||||
````
|
||||
Debería ser aproximadamente similar al siguiente contenido:
|
||||
|
||||

|
||||
|
||||
### Paso 4: Instale la base de datos Berkley v4.8
|
||||
|
||||
1. Ingrese al directorio `contrib`: `$ cd bitcoin/contrib/`
|
||||
2. Ejecute el siguiente comando: ```$ ./install_db4.sh `pwd` ```
|
||||
|
||||
Una vez que ha sido descargado usted vera la siguiente salida. Tome nota de la
|
||||
salida, usted lo usara para configurar bitcoin mientras compila:
|
||||
|
||||

|
||||
|
||||
### Paso 5: Compile Bitcoin Core
|
||||
|
||||
Es recomendado que usted compile desde una rama etiquetada, la cual es mas
|
||||
estable, a menos que usted quiera probar la vanguardia del desarrollo bitcoin.
|
||||
Ejecute el siguiente comando para obtener una lista de etiquetas, ordenadas de
|
||||
acuerdo a la mas reciente:
|
||||
```
|
||||
$ git tag -n | sort -V
|
||||
```
|
||||
Luego elija una etiqueta tal como `v0.20.0`:
|
||||
```
|
||||
$ git checkout <TAG>
|
||||
```
|
||||
|
||||
Una vez que ha seleccionado una rama etiquetada, ejecute lo siguiente desde
|
||||
dentro del directorio `bitcoin`. El `<CAMINO-A>` debe ser la salida del
|
||||
programa `install_db4.sh`.
|
||||
|
||||
```
|
||||
$ ./autogen.sh
|
||||
$ export BDB_PREFIX='<PATH-TO>/db4'
|
||||
$ ./configure BDB_LIBS="-L${BDB_PREFIX}/lib -ldb_cxx-4.8" BDB_CFLAGS="-I${BDB_PREFIX}/include"
|
||||
$ make # build bitcoin core
|
||||
```
|
||||
|
||||
### Paso 6: Pruebe la compilación
|
||||
|
||||
Si usted quiere comprobar su compilación (lo cual es una buena idea), ejecute
|
||||
las siguientes pruebas:
|
||||
|
||||
1. `$ make check` correra las pruebas unitarias, los cuales deberan retornar `PASS`.
|
||||
2. `$ test/functional/test_runner.py --extended` ejecutara las pruebas
|
||||
funcionales extendidas. Omita el indicador `--extended` si usted quiere
|
||||
evitar algunas pruebas. Esto puede tomarle bastante tiempo.
|
||||
|
||||
### Paso 7: Ejecute e instale Bitcoin Core
|
||||
|
||||
Ahora que usted ha compilado Bitcoin Core desde la fuente, usted puede empezar
|
||||
a usarlo e instalarlo para una disponibilidad global.
|
||||
|
||||
#### Ejecute Bitcoin Core sin instalarlo
|
||||
|
||||
Para solo ejecutar Bitcoin Core:
|
||||
|
||||
`$ src/qt/bitcoin-qt` para ejecutar la interfaz grafica de usuario.
|
||||
`$ src/bitcoind` para ejecutar bitcoin en la línea de comandos.
|
||||
|
||||
### Instale Bitcoin Core
|
||||
|
||||
Para instalar:
|
||||
|
||||
`$ sudo make install` instalara bitcoin core globalmente. Una vez instalado
|
||||
usted puede entonces ejecutar bitcoin desde cualquier lugar en la línea de
|
||||
comandos, al igual que con cualquier otro software: `$ bitcoin-qt` para la
|
||||
interfaz grafica de usuario o `bitcoind` y luego `bitcoin-cli` para la línea de
|
||||
comandos.
|
||||
|
||||
## Finalice su sistema
|
||||
|
||||
Compilando Bitcoin desde la fuente, usted disminuye la necesidad de confianza
|
||||
en su configuracion. Sin embargo, usted esta lejos de la seguridad adicional
|
||||
provista por la configuracion de Bitcoin Standup. Para resolver esto, usted
|
||||
puede querer recorrer el programa
|
||||
[Linode Stackscript](https://github.com/BlockchainCommons/Bitcoin-Standup-Scripts/blob/master/Scripts/LinodeStandUp.sh)
|
||||
completo y ejecutar paso a paso todos los comandos. El unico lugar donde
|
||||
necesita ser cuidadoso es en el Paso 6, el cual instala Bitcoin. Omita solo
|
||||
hasta donde verifica sus binarios, y continue desde ahi.
|
||||
|
||||
## Resumen: Compilando Bitcoin desde la Fuente
|
||||
|
||||
Si usted quiere la seguridad incrementada de instalar Bitcoin desde la fuente,
|
||||
usted deberia tenerla ahora. Con un poco de suerte, usted tambien habra
|
||||
recorrido el Linode Stackscript para configurar un servidor mas seguro.
|
||||
|
||||
## ¿Que sigue?
|
||||
|
||||
Si usted estaba en el proceso de crear un nodo Bitcoin para usar en este curso, usted deberia continuar con
|
||||
[Capitulo 3: Entendiendo Su Configuración Bitcoin](03_0_Entendiendo_Su_Configuracion_Bitcoin.md).
|
||||
|
||||
Si usted esta leyendo a través de los apéndices, continúe con
|
||||
[Apéndice III: Usando Bitcoin Regtest](A3_0_Usando_Bitcoin_Regtest.md).
|
||||
|
281
es/A3_0_Usando_Bitcoin_Regtest.md
Normal file
281
es/A3_0_Usando_Bitcoin_Regtest.md
Normal file
@ -0,0 +1,281 @@
|
||||
# Apéndice III: Usando Bitcoin Regtest
|
||||
|
||||
> :information_source: **NOTA:** Esta sección ha sido recientemente agregada al
|
||||
> curso y es un borrador inicial que puede estar esperando aun su revisión.
|
||||
> Lectura con advertencias.
|
||||
|
||||
La mayoría de este curso presume que usted usara o bien Mainnet o bien Testnet.
|
||||
Sin embargo, esas no son las únicas opciones. Mientras desarrolla aplicaciones
|
||||
Bitcoin, usted puede querer mantener sus aplicaciones aisladas de la cadenas de
|
||||
bloques publicas. Para hacerlo, puede crear una cadena de bloques desde cero
|
||||
usando Regtest, la cual tiene una gran ventaja sobre Testnet: usted elige
|
||||
cuando crear nuevos bloques, por lo que tiene un control completo sobre el
|
||||
entorno.
|
||||
|
||||
## Inicie Bitcoind en Regtest
|
||||
|
||||
Luego de
|
||||
[configurar su VPS Bitcoin-Core](02_0_Configurando_un_Bitcoin-Core_VPS.md) o
|
||||
[compilarlo de la fuente](A2_0_Compilando_Bitcoin_desde_la_Fuente.md),
|
||||
usted esta ahora en condiciones de usar regtest. Para iniciar su `bitcoind` en
|
||||
regtest y crear una cadena de bloques privada, use el siguiente comando:
|
||||
```
|
||||
$ bitcoind -regtest -daemon -fallbackfee=1.0 -maxtxfee=1.1
|
||||
```
|
||||
|
||||
Los argumentos `-fallbackfee=1.0 -maxtxfee=1.1` prevendrán el error
|
||||
`Fee estimation failed. Fallbackfee is disabled`.
|
||||
|
||||
En regtest, usualmente no hay suficientes transacciones por lo que bitcoind no
|
||||
puede darle un estimado confiable y, sin eso, el monedero no creara
|
||||
transacciones a menos que se configure explícitamente la tarifa.
|
||||
|
||||
### Reconfigure la cadena de bloques Regtest
|
||||
|
||||
Si usted lo desea, puede mas tarde reiniciar su Regtest con una nueva cadena de
|
||||
bloques.
|
||||
|
||||
Los monederos Regtest y el estado de la cadena de bloques son guardados en el
|
||||
subdirectorio regtest del directorio de configuración de Bitcoin:
|
||||
```
|
||||
user@mybtc:~/.bitcoin# ls
|
||||
bitcoin.conf regtest testnet3
|
||||
```
|
||||
|
||||
Para comenzar una nueva cadena de bloques usando regtest, todo lo que tiene que
|
||||
hacer es eliminar el directorio `regtest` y reiniciar el Bitcoind.
|
||||
```
|
||||
$ rm -rf regtest
|
||||
```
|
||||
## Genere un monedero Regtest
|
||||
|
||||
Antes de generar bloques, es necesario que cargue un monedero usando
|
||||
`loadwallet` o cree uno nuevo con `createwallet`. Desde la versión 0.21,
|
||||
Bitcoin Core no crea nuevos monederos en el inicio.
|
||||
|
||||
El argumento `descriptors=true` crea un monedero con descriptores de forma
|
||||
nativa, que almacena la información de scriptPubKey usando descriptores de
|
||||
salida. Si este es `falso`, creara un monedero de acuerdo al estándar previo,
|
||||
donde las llaves son usadas para generar implícitamente scriptPubKeys y
|
||||
direcciones.
|
||||
```
|
||||
$ bitcoin-cli -regtest -named createwallet wallet_name="regtest_desc_wallet" descriptors=true
|
||||
```
|
||||
|
||||
## Genere Bloques
|
||||
|
||||
Usted puede generar (minar) nuevos bloques en la cadena regtest usando el
|
||||
método RPC `generate` con un argumento para indicar la cantidad de bloques a
|
||||
generar. Solo tiene sentido usar este método en regtest; debido a la alta
|
||||
dificultad es poco probable que genere nuevos bloques en mainnet o testnet:
|
||||
```
|
||||
$ bitcoin-cli -regtest -generate 101
|
||||
[
|
||||
"57f17afccf28b9296048b6370312678b6d8e48dc3a7b4ef7681d18ed3d91c122",
|
||||
"631ff7b8135ce633c774828be3b8505726459eb65c339aab981b10363befe5a7",
|
||||
...
|
||||
"1162dbfe025c7da94ee1128dc26d518a94508f532c19edc0de6bc673a909d02c",
|
||||
"20cb2e815c3d42d6a117a204a0b5e726ab641c826e441b5b3417aca33f2aba48"
|
||||
]
|
||||
```
|
||||
|
||||
> :warning: ADVERTENCIA. Notar que usted debe agregar el indicador `-regtest`
|
||||
> luego de cada comando `bitcoin-cli` para acceder correctamente a su entorno
|
||||
> Regtest. Si lo prefiere, puede incluir un comando `regtest=1` en su archivo
|
||||
> `~/.bitcoin/bitcoin.conf`.
|
||||
|
||||
Debido a que un bloque debe tener 100 confirmaciones antes de que su recompensa
|
||||
pueda ser gastada, usted generara 101 bloques, permitiendo el acceso a la
|
||||
transacción 'coinbase' del bloque #1. Dado que esta es una nueva cadena de
|
||||
bloques usando las reglas por defecto de Bitcoin, el primer bloque recibirá una
|
||||
recompensa de 50 bitcoins. Al contrario que mainnet, en modo regtest, solo los
|
||||
primeros 150 bloques pagan una recompensa de 50 bitcoins. La recompensa se
|
||||
divide luego de 150 bloques, por lo que paga 25, 12.5, etc.
|
||||
|
||||
La salida es el hash de bloque de cada bloque generado.
|
||||
|
||||
> :book: ***¿Que es una transacción 'coinbase'?*** Una transacción 'coinbase'
|
||||
> es la transacción sin entradas creada cuando un nuevo bloque es minado y
|
||||
> otorgado al minero. Es la manera en que nuevos bitcoins entran al ecosistema.
|
||||
> El valor de una transacción 'coinbase' decae con el tiempo. En la mainnet,
|
||||
> esta se divide cada 210,000 transacciones y termina completamente con el
|
||||
> bloque 6.929.999, el cual esta estipulado que ocurra en el siglo 22. A Mayo
|
||||
> del 2020, la recompensa 'coinbase' es de 6.25 BTC.
|
||||
|
||||
### Verifique su balance
|
||||
|
||||
Luego de minar bloques y obtener recompensas, usted puede verificar el balance
|
||||
de su monedero:
|
||||
```
|
||||
$ bitcoin-cli -regtest getbalance
|
||||
50.00000000
|
||||
```
|
||||
|
||||
### Use la Regtest
|
||||
|
||||
Ahora usted debería ser capaz de usar este balance para cualquier tipo de
|
||||
interacción en su cadena de bloques privada, tales como enviar Bitcoins en
|
||||
transacciones de acuerdo a el
|
||||
[Capitulo 4](04_0_Enviando_Transacciones_Bitcoin.md).
|
||||
|
||||
Es importante notar que para que se complete cualquier transacción, usted
|
||||
deberá generar (minar) nuevos bloques, así las transacciones pueden ser
|
||||
incluidas.
|
||||
|
||||
Por ejemplo, para crear una transacción e incluirla en un bloque, usted debe
|
||||
primero usar el comando `sendtoaddress`:
|
||||
```
|
||||
$ bitcoin-cli -regtest sendtoaddress [address] 15.1
|
||||
e834a4ac6ef754164c8e3f0be4f34531b74b768199ffb244ab9f6cb1bbc7465a
|
||||
```
|
||||
|
||||
La salida es el hash de la transacción incluida en la cadena de bloques. Usted
|
||||
puede verificar los detalles usando el comando `gettransaction`:
|
||||
```
|
||||
$ bitcoin-cli -regtest gettransaction e834a4ac6ef754164c8e3f0be4f34531b74b768199ffb244ab9f6cb1bbc7465a
|
||||
{
|
||||
"amount": 0.00000000,
|
||||
"fee": -0.00178800,
|
||||
"confirmations": 0,
|
||||
"trusted": false,
|
||||
"txid": "e834a4ac6ef754164c8e3f0be4f34531b74b768199ffb244ab9f6cb1bbc7465a",
|
||||
"walletconflicts": [
|
||||
],
|
||||
"time": 1513204730,
|
||||
"timereceived": 1513204730,
|
||||
"bip125-replaceable": "unknown",
|
||||
"details": [
|
||||
{
|
||||
"account": "",
|
||||
"address": "mjtN3C97kuWMgeBbxdB7hG1bjz24Grx2vA",
|
||||
"category": "send",
|
||||
"amount": -15.10000000,
|
||||
"label": "",
|
||||
"vout": 1,
|
||||
"fee": -0.00178800,
|
||||
"abandoned": false
|
||||
},
|
||||
{
|
||||
"account": "",
|
||||
"address": "mjtN3C97kuWMgeBbxdB7hG1bjz24Grx2vA",
|
||||
"category": "receive",
|
||||
"amount": 15.10000000,
|
||||
"label": "",
|
||||
"vout": 1
|
||||
}
|
||||
],
|
||||
"hex": "020000000f00fe2c7b70b925d0d40011ce96f8991fee5aba9537bd1b6913b37c37b041a57c00000000494830450221009ad02bfeee2a49196a99811ace20e2e7fefd16d33d525884edbc64bf6e2b1db502200b94f4000556391b0998932edde3033ba2517733c7ddffb87d91f6b756629fe201feffffff06a9301a2b39875b68f8058b8e2ad0b658f505e44a67e1e1d039140ae186ed1f0000000049483045022100c65cd13a85af6fcfba74d2852276a37076c89a7642429aa111b7986eea7fd6c7022012bbcb633d392ed469d5befda8df0a6b96e1acfa342f559877edebc2af7cb93401feffffff434b6f67e5e068401553e89f739a3edc667504597f29feb8edafc2b081cc32d90000000049483045022100b86ecc43e602180c787c36465da7fc8d1e8bfba23d6f49c37190c20889f2dfa0022032c3aec3ceefbb7a33c040ef19090cacbfd6bc9c5cd8e94252eb864891c6f34501feffffff4c65b43f8568ce58fc4c55d24ba0742e9878a031fdfae0fadac7247f42cc1f8e0000000049483045022100d055acfce852259dde051dc61792f94277d094c5da96752f925582b8e739868f02205e69add76e6b001073ad6b7df5f32a681fc8513ee0f6e126ee1c2d45149bd91d01feffffff5a72d60b58300974c5d4731e29b437ea61b87b6733bb3ca6ce5548ef8887d05b0000000049483045022100a7f5b2ee656a5a904fb27f982210de6858dfb165777ec969a77ea1c2c82975a4022001a1a563dbc3714047ec855f7aee901e756b851e255f35435e85c2ba7b0abd8401feffffff60d68e9d5650d55bc9e0b2a65ed27a3b9bceac4955760aa1560408854c3b148d000000004948304502210081a6f0c8232c52f3eaca825965077e88b816e503834989be4afb3f44f87eb98202207ae8becb99efe379fb269f477e7bb70d117dcb83e106c53b7addaa9715029da101feffffff63e2239425aad544f6e1157d5ee245d2500d4e9e9daf8049e0a38add6246da890000000049483045022100e0ab1752e8fbb244b63f7dd5649f2222e0dc42fae293b758e0c28082f77560b60220013f72fbe50acf4af197890b4d18fa89094055ed66f9226a6b461cc4ff560f8e01feffffff6aad4151087f4209ace714193dd64f770305dfb89470b79cca538b88253fbbef0000000049483045022100fee4a5f7ec6e8b55bd6aa0e93b5399af724039171d998b926e8095b70953d5f202203db0d4ef9d1bd57aeff0fe3d47d4358ec0559135dac8107507741eef0638279201feffffff7ddbca5854e25e6a2dfeacfe5828267cd1ef5d86e1da573fe2c2b21b45ecd6ce0000000049483045022100bf45241525592df4625642972dbc940ef74771139dd844bc6a9517197d01488c02203c99ca98892cc2693e8fbb9a600962eec84494fb8596acf0d670822624e497c901feffffff8672949de559e76601684c4ac3731599fd965d0c412e7df9f8ec16038d4420a60000000049483045022100b5a9bd3c6718c6bd2a8300bbd1d9de0ff1c5d02aeb6a659c52bb88958e7e3b0302207f710db1ef975c22edf54e063169aae31bbe470166cc0e5c34fd27b730b8e7d001feffffff8e006b0bb8cef2c5c2a11c8c2aa7d3ba01cb4386c7f780c45bc1014142b425f00000000048473044022046dc9db8daeb09b7c0b9f48013c8af2d0a71f688adaa8d91b40891768c852d4a02204fa15da6d58851191344a56c63bf51a540ec03f73117a3446230bb58a8a4bcce01feffffffbad05b8f86182b9b7c9c5aaa9ce3dc8d08a76848e49a2d9b8dcfb0f764bb26ca000000004847304402200682379dc36cb486309eac4913f41ac19638525677edad45ca8d9a2b0728b12f02203fb44f8a46cbc4c02f5699d7d4d9cd810bdf7e7c981b421218ccbcb7b73845f501feffffffd35228fe9ef0a742eacffc4a13f15ed7ba23854e6cb49d5010810ac11b5bdf690000000048473044022030045b882500808bd707f4654becc63de070818c82716310d39576decdd724e3022034d3b41cb5e939f0011bb5251be7941b6077fde5f4eff59afd8e49a2844288f701fefffffff5ae4cbd4ae8d68b5a34be3231cdc88b660447175f39cf7a86397f37641d4aa70000000049483045022100afe16f0de96a8629d6148f93520d690f30126c37e7f7f05300745a1273d7eb7202200933f6b371c4ea522570f3ec2aee9be2b59730b634e828f543bcdb019cf4749901fefffffff633f61ac61683221cc3d2665cf4bcf193af1c8ffe9d3d756ba83cc5eb7643250000000049483045022100ef0b8853c94d60634eff2fc1d4d75872aacb0a2d3242308b7ee256b24739c614022069fe9be8288bdd635871c263c46be710c001729d43f6fbc1350ed1a693c4646301feffffff0250780000000000001976a91464ed7fb2fe0b06f4cad0d731b122222e3e91088a88ac80c5005a000000001976a9142fed0f02d008f89f6a874168e506e2d4f9bcbfb888acd32b0000"
|
||||
}
|
||||
```
|
||||
|
||||
Sin embargo, usted debe ahora finalizarla creando bloques en la cadena de bloques.
|
||||
|
||||
La mayoría de las aplicaciones requieren seis confirmaciones de bloques para
|
||||
considerar irreversible una transacción. Si ese es su caso, usted puede minar
|
||||
seis bloques adicionales dentro de su cadena regtest:
|
||||
```
|
||||
$ bitcoin-cli -regtest -generate 6
|
||||
[
|
||||
"33549b2aa249f0a814db4a2ba102194881c14a2ac041c23dcc463b9e4e128e9f",
|
||||
"2cc5c2012e2cacf118f9db4cdd79582735257f0ec564418867d6821edb55715e",
|
||||
"128aaa99e7149a520080d90fa989c62caeda11b7d06ed1965e3fa7c76fa1d407",
|
||||
"6037cc562d97eb3984cca50d8c37c7c19bae8d79b8232b92bec6dcc9708104d3",
|
||||
"2cb276f5ed251bf629dd52fd108163703473f57c24eac94e169514ce04899581",
|
||||
"57193ba8fd2761abf4a5ebcb4ed1a9ec2e873d67485a7cb41e75e13c65928bf3"
|
||||
]
|
||||
```
|
||||
|
||||
## Pruebe con NodeJS
|
||||
|
||||
Cuando usted esta en regtest, es capaz de simular casos extremos y ataques que
|
||||
podrían ocurrir en el mundo real, tales como gastos dobles.
|
||||
|
||||
Como se debatió en algún otro lado de este curso, usar librerías de software
|
||||
podría darle acceso a algunos comandos RPC mas sofisticados. En este caso,
|
||||
[bitcointest by dgarage](https://github.com/dgarage/bitcointest) para NodeJS,
|
||||
puede ser usada para simular una transacción de un monedero a otro; usted puede
|
||||
comprobar su [guia](https://www.npmjs.com/package/bitcointest) para
|
||||
simulaciones de ataques mas específicos, tales como gastos dobles.
|
||||
|
||||
Vea [§18.3](18_3_Accediendo_a_Bitcoind_con_NodeJS.md) para la información mas
|
||||
actualizado sobre instalar NodeJS, luego agregue `bitcointest`:
|
||||
```
|
||||
$ npm install -g bitcointest
|
||||
```
|
||||
|
||||
Después de instalar `bitcointest`, usted puede crear un archivo `test.js` con
|
||||
el siguiente contenido:
|
||||
```javascript
|
||||
file: test.js
|
||||
|
||||
const { BitcoinNet, BitcoinGraph } = require('bitcointest');
|
||||
const net = new BitcoinNet('/usr/local/bin', '/tmp/bitcointest/', 22001, 22002);
|
||||
const graph = new BitcoinGraph(net);
|
||||
|
||||
try {
|
||||
|
||||
console.log('Launching nodes...');
|
||||
|
||||
const nodes = net.launchBatchS(4);
|
||||
const [ n1, n2 ] = nodes;
|
||||
net.waitForNodesS(nodes, 20000);
|
||||
|
||||
console.log('Connected!');
|
||||
const blocks = n1.generateBlocksS(110);
|
||||
console.info('Generated 110 blocks');
|
||||
|
||||
console.log(`n2.balance (before) = ${n2.getBalanceS()}`);
|
||||
|
||||
const sometxid = n1.sendToNodeS(n2, 100);
|
||||
console.log(`Generated transaction = ${sometxid}`);
|
||||
n1.generateBlocksS(110);
|
||||
n2.waitForBalanceChangeS(0);
|
||||
|
||||
const sometx = n2.getTransactionS(sometxid);
|
||||
console.log(`n2.balance (after) = ${n2.getBalanceS()}`);
|
||||
|
||||
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
net.shutdownS();
|
||||
throw e;
|
||||
}
|
||||
```
|
||||
|
||||
Como se puede observar, esto generara bloques y una transacción:
|
||||
```
|
||||
$ node test.js
|
||||
Launching nodes...
|
||||
Connected!
|
||||
Generated 110 blocks
|
||||
n2.balance (before) = 0
|
||||
Generated transaction = 91e0040c26fc18312efb80bad6ec3b00202a83465872ecf495c392a0b6afce35
|
||||
n2.after (before) = 100
|
||||
|
||||
```
|
||||
|
||||
## Resumen: Usando Bitcoin Regtest
|
||||
|
||||
Un entorno regtest para Bitcoin funciona tal como cualquier entorno testnet,
|
||||
excepto por el hecho de que usted tiene la capacidad de generar bloques fácil y
|
||||
rápidamente.
|
||||
|
||||
> :fire: ***¿Cual es el poder de regtest?*** El mayor poder de regtest es que
|
||||
> usted puede rápidamente minar bloques, permitiéndole acelerar la cadena de
|
||||
> bloques, para testear transacciones, timelocks y otras características para
|
||||
> las que de otra manera debería sentarse y esperar. Sin embargo, el otro poder
|
||||
> es que usted puede correrlo de forma privada, sin conectarse a una cadena de
|
||||
> bloques publica, permitiéndole probar sus propias ideas antes de liberarlas
|
||||
> dentro del mundo.
|
||||
|
||||
## ¿Que sigue?
|
||||
|
||||
Si usted visito este Apéndice mientras trabajaba en otra parte del curso, usted
|
||||
debería regresar allí.
|
||||
|
||||
Pero, de otra manera, usted ha alcanzado el final! Otras personas que han
|
||||
trabajado su camino a través de este curso se han vuelto desarrolladores e
|
||||
ingenieros Bitcoin profesionales, incluyendo algunos de quienes han contribuido
|
||||
a [Blockchain Commons](https://www.blockchaincommons.com/). Nosotros los
|
||||
incentivamos a hacer lo mismo! Solo salga allí afuera y comience a trabajar en
|
||||
algo de su propio código Bitcoin con lo que ha aprendido.
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user