Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Redes
Mensajes de red
Todos los mensajes de red se ven como Figura 10-1..
Los primeros 4 bytes son siempre los mismos y se conocen como la magia de la red.
Los bytes mágicos son comunes en la programación de redes, ya que la
comunicación es asíncrona y puede ser intermitente. Los bytes mágicos le dan al
receptor del mensaje un lugar para comenzar si la comunicación se interrumpe (por
ejemplo, por la señal de caída de su teléfono). También son útiles para identificar la
red. No querría que un nodo de Bitcoin se conecte a un nodo de Litecoin, por
ejemplo. Por lo tanto, un nodo Litecoin tiene una magia diferente. El testnet de
Bitcoin también tiene una magia diferente,0b110907, a diferencia de la magia de la
red principal de Bitcoin, f9beb4d9.
177
Figura 10-1. Un mensaje de red: el sobre que contiene la carga útil real
clase NetworkEnvelope:
def __repr__(yo):
regreso '{}: {}'.formato(
yo.mando.descodificar(ascii),
178 El | Capítulo 10: Redes
yo.carga útil.maleficio(),
)
Ejercicio 1
Escribe el analizar gramaticalmente método para NetworkEnvelope.
Ejercicio 2
Determine cuál es este mensaje de red:
f9beb4d976657261636b000000000000000000005df6e0e2
Ejercicio 3
Escribe el publicar por fascículos método para NetworkEnvelope.
Los campos están destinados a proporcionar información suficiente para que dos
nodos puedan comunicarse.
Una vez que finaliza el apretón de manos, A y B pueden comunicarse como quieran.
Tenga en cuenta que aquí no hay autenticación, y depende de los nodos verificar
todos los datos que reciben. Si un nodo envía una transacción o un bloque incorrecto,
puede esperar que lo baneen o deshabilite- conectado.
Conectando a la red
La comunicación de red es complicada debido a su naturaleza asincrónica. Para
experimentar, podemos establecer una conexión a un nodo en la red de forma
síncrona:
> importar enchufe
> desde red importar NetworkEnvelope, VersionMessage
> anfitrión = 'testnet.programmingbitcoin.com'
> Puerto = 18333
> enchufe = enchufe.enchufe(enchufe.AF_INET, enchufe.SOCK_STREAM)
> enchufe.conectar((anfitrión, Puerto))
> corriente = enchufe.makefile('rb', Ninguna)
> versión = VersionMessage()
> sobre = NetworkEnvelope(versión.mando, versión.publicar por
fascículos())
> enchufe.Envia todo(sobre.publicar por fascículos())
> mientras Cierto:
... nuevo mensaje = NetworkEnvelope.analizar
gramaticalmente(corriente)
... impresión(nuevo mensaje)
Este es un servidor que configuré para Testnet. El puerto testnet es 18333 por
defecto.
Creamos una secuencia para poder leer desde el socket. Una secuencia realizada
de esta manera se puede pasar a todos los métodos de análisis.
Esta línea leerá cualquier mensaje que ingrese a través de nuestro socket
conectado.
Conectando de esta manera, no podemos enviar hasta que hayamos recibido y no
podamos responder intelli-suavemente a más de un mensaje a la vez. Una
implementación más robusta usaría una biblioteca asincrónica (como asyncio en
Python 3) para enviar y recibir sin ser bloqueado.
También necesitamos una clase de mensaje verack, que crearemos aquí:
clase VerAckMessage:
mando = si'verack'
@classmethod
def analizar gramaticalmente(cls, s):
regreso cls()
def leer(yo):
'' 'Leer un mensaje del socket' ''
182 El | Capítulo 10: Redes
sobre = NetworkEnvelope.analizar gramaticalmente(yo.corriente,
testnet=yo.testnet)
Si yo.Inicio sesión:
impresión('recibiendo: {}'.formato(sobre))
regreso sobre
los enviarEl método envía un mensaje a través del socket. los mando propiedad
y publicar por fascículos se espera que existan métodos en el mensaje
objeto.
Esperamos recibir un verack para nuestra versión y la versión del otro nodo. Sin
embargo, no sabemos en qué orden llegarán.
Ejercicio 5
Escribe el apretón de manos método para SimpleNode.
Al igual que con la versión, comenzamos con la versión del protocolo, luego el
número de grupos de encabezado de bloque en esta lista (este número puede ser más
de 1 si hay una división de cadena), luego el encabezado de bloque inicial y
finalmente el encabezado de bloque final. Si especificamos que el bloque final
sea000 ... 000, estamos indicando que queremos tantos como el otro nodo nos
dará. El número máximo de encabezados que podemos recuperar es de 2,000, o casi
un solo período de ajuste de dificultad (2,016 bloques).
Así es como se ve la clase:
clase GetHeadersMessage:
mando = si'getheaders'
Para los propósitos de este capítulo, vamos a suponer que el número de grupos
de encabezado de bloque es 1. Una implementación más robusta manejaría más
que un solo grupo de bloque, pero podemos descargar los encabezados de bloque
usando un solo grupo.
El bloque final suponemos que es nulo, o tantos como el servidor nos enviará si
no está definido.
Ejercicio 6
Escribe el publicar por fascículos método para GetHeadersMessage.
Respuesta de encabezados
Ahora podemos crear un nodo, un apretón de manos y luego pedir algunos
encabezados:
> desde io importar BytesIO
> desde bloquear importar Bloquear, GENESIS_BLOCK
> desde red importar SimpleNode, GetHeadersMessage
> nodo = SimpleNode('mainnet.programmingbitcoin.com', testnet=Falso)
> nodo.apretón de manos()
> génesis = Bloquear.analizar
gramaticalmente(BytesIO(GENESIS_BLOCK))
> getheaders =
GetHeadersMessage(bloque_inicio=génesis.picadillo())
> nodo.enviar(getheaders)
Ahora necesitamos una forma de recibir los encabezados del otro nodo. El otro nodo
enviará de vuelta elencabezadosmando. Esta es una lista de encabezados de bloque
(Figura 10-4.), que ya aprendimos a analizar en Capítulo 9. losHeadersMessage La
clase puede aprovechar esto al analizar.
Respuesta de
encabezados El |
185
Figura 10-4. Encabezados analizados
@classmethod
def analizar gramaticalmente(cls, corriente):
num_headers = read_varint(corriente)
bloques = []
para _ _ en rango(num_headers):
bloques.adjuntar(Bloquear.analizar
gramaticalmente(corriente))
num_txs = read_varint(corriente)
Si num_txs ! = 0 0:
aumento Error de tiempo de ejecución('número de txs
no 0')
regreso cls(bloques)
Almacene el primer bloque de la época para calcular los bits al final de la época.
Tenga en cuenta que esto no funcionará en testnet ya que el algoritmo de ajuste de
dificultad es diferente-ent. Para asegurarse de que se puedan encontrar bloques
consistentemente para las pruebas, si no se ha encontrado un bloque en testnet en 20
minutos, la dificultad se reduce a 1, por lo que es muy fácil encontrar un bloque. Esto
se configura de esta manera para permitir que los evaluadores puedan mantener los
bloques de construcción en la red sin costosos equipos de minería. Un ASIC USB de
$ 30 generalmente puede encontrar algunos bloques por minuto en la dificultad
mínima.
Conclusión
Hemos logrado conectarnos a un nodo en la red, apretón de manos, descargar los
encabezados de bloque y verificar que cumplen con las reglas de consenso. En el
próximo capítulo, nos enfocamos en obtener información sobre transacciones que
nos interesan de otro nodo de manera privada pero comprobable.