def parsear(cls, s, testnet=False): '''Toma un stream y crea un NetworkEnvelope''' # comprueba la magia de red magia = s.read(4) if magia == b'': raise RuntimeError('Conexión reseteada!') if testnet: magia_esperada = MAGIA_RED_TESTNET else: magia_esperada = MAGIA_RED if magia != magia_esperada: raise RuntimeError('magia no es correcta {} vs {}'.format( magia.hex(), magia_esperada.hex())) # comando 12 bytes comando = s.read(12) # quita los 0's arrastrados comando = comando.strip(b'\x00') # longitud de carga 4 bytes, little endian longitud_carga = little_endian_a_int(s.read(4)) # checksum es 4 bytes, los primeros cuatro del doble_sha256 de carga checksum = s.read(4) # carga es de longitud longitud_carga carga = s.read(longitud_carga) # verificar checksum checksum_calculada = doble_sha256(carga)[:4] if checksum_calculada != checksum: raise RuntimeError('checksum no es correcta') return cls(comando, carga, testnet=testnet)
def sig_hash(self, indice_input, tipo_hash): '''Devuelve la representación entera del hash que necesitas firmar para el índice indice_input''' # crea una nueva serie de tx_ins (alt_tx_ins) alt_tx_ins = [] # itera sobre self.tx_ins for tx_in in self.tx_ins: # crea un nuevo TxIn que tenga un script_sig (b'') en blanco y añáde a alt_tx_ins alt_tx_ins.append( TxIn( tx_previa=tx_in.tx_previa, indice_previo=tx_in.indice_previo, script_sig=Script([]), sequence=tx_in.sequence, )) # obtén el input en el indice_input input_firmante = alt_tx_ins[indice_input] # obtén el script_pubkey del input script_pubkey = input_firmante.script_pubkey(self.testnet) # el script_sig del input_firmante debería ser script_pubkey input_firmante.script_sig = script_pubkey # crea una transacción alternativa con las tx_ins modificadas alt_tx = self.__class__(versión=self.versión, tx_ins=alt_tx_ins, tx_outs=self.tx_outs, locktime=self.locktime) # añade el tipo_hash entero 4 bytes, little endian res = alt_tx.serializar() + int_a_little_endian(tipo_hash, 4) # obtén el doble_sha256 de la serialización de la tx s256 = doble_sha256(res) # convierte esto a un entero big-endian usando int.from_bytes(x, 'big') return int.from_bytes(s256, 'big')
def sig_hash(self, índice_input, tipo_hash): '''Devuelve la representación entera del hash que debe ser firmado para índice índice_input''' # crea una nueva serie de tx_ins (alt_tx_ins) alt_tx_ins = [] # itera sobre self.tx_ins for tx_in in self.tx_ins: # crea una nueva TxIn que tenga un script_sig en blanco (b'') y añádela a alt_tx_ins alt_tx_ins.append(TxIn( tx_previa=tx_in.tx_previa, índice_previo=tx_in.índice_previo, script_sig=Script([]), sequence=tx_in.sequence, )) # grab the input at the índice_input firmaring_input = alt_tx_ins[índice_input] # grab the script_pubkey of the input script_pubkey = firmaring_input.script_pubkey(self.testnet) # the script_sig of the firmaring_input should be script_pubkey firmaring_input.script_sig = script_pubkey # create an alternate transaction with the modified tx_ins alt_tx = self.__class__( versión=self.versión, tx_ins=alt_tx_ins, tx_outs=self.tx_outs, locktime=self.locktime) # añade el tipo_hash int 4 bytes, little endian res = alt_tx.serializar() + int_a_little_endian(tipo_hash, 4) # obtén el doble_sha256 de la serializacón de la tx s256 = doble_sha256(res) # convierte esto a big-endian entero usando int.from_bytes(x, 'big') return int.from_bytes(s256, 'big')
def hash(self): '''Devuelve el doble-sha256 interpretado little endian del bloque''' # serializar s = self.serializar() # doble-sha256 sha = doble_sha256(s) # dar la vuelta return sha[::-1]
def comprobar_pow(self): '''Devuelve si este bloque satisface la prueba de trabajo''' # obtén el doble_sha256 de la serialización de este bloque sha = doble_sha256(self.serializar()) # interpreta este hash como un número little-endian prueba = little_endian_a_int(sha) # devuelve si este entero es menos que el target return prueba < self.target()
def comprobar_pow(self): '''Devuelve si este Bloque satisface la prueba de trabajo''' # obtén el doble_sha256 de la serialización de este Bloque sha = doble_sha256(self.serializar()) # interpreta este hash como un número little-endian prueba = little_endian_a_int(sha) # return whether this integer is less than the target return prueba < self.target()
def serializar(self): '''Devuelve la serialización en bytes del mensaje de red completo''' # añade la magia de red res = self.magia # comando 12 bytes # rellénalo con 0's res += self.comando + b'\x00' * (12 - len(self.comando)) # la longitud de carga son 4 bytes, little endian res += int_a_little_endian(len(self.carga), 4) # checksum 4 bytes, los primeros cuatro de doble_sha256 de carga res += doble_sha256(self.carga)[:4] # carga res += self.carga return res
def dire(self, comprimido=True, testnet=False): '''Devuelve la cadena dirección''' # obtén el sec sec = self.sec(comprimido) # hash160 the sec h160 = hash160(sec) # bruto es el hash 160 antepuesto por b'\x00' para mainnet, b'\x6f' para testnet if testnet: prefijo = b'\x6f' else: prefijo = b'\x00' bruto = prefijo + h160 # checksum son los primeros 4 bytes del doble_sha256 de bruto checksum = doble_sha256(bruto)[:4] # haz encode_base58 a bruto + checksum dire = encode_base58(bruto+checksum) # devuelve como cadena, puedes usar .decode('ascii') para hacerlo return dire.decode('ascii')
def hash(self): return doble_sha256(self.serializar())[::-1]