def serialize_segwit(self): '''Returns the byte serialization of the transaction''' # serialize version (4 bytes, little endian) result = int_to_little_endian(self.version, 4) # segwit marker '0001' result += b'\x00\x01' # encode_varint on the number of inputs result += encode_varint(len(self.tx_ins)) # iterate inputs for tx_in in self.tx_ins: # serialize each input result += tx_in.serialize() # encode_varint on the number of inputs result += encode_varint(len(self.tx_outs)) # iterate outputs for tx_out in self.tx_outs: # serialize each output result += tx_out.serialize() # add the witness data for tx_in in self.tx_ins: result += tx_in.witness_program # serialize locktime (4 bytes, little endian) result += int_to_little_endian(self.locktime, 4) return result
def test_exercise_3(self): hex_tx = '0100000001868278ed6ddfb6c1ed3ad5f8181eb0c7a385aa0836f01d5e4789e6bd304d87221a000000db00483045022100dc92655fe37036f47756db8102e0d7d5e28b3beb83a8fef4f5dc0559bddfb94e02205a36d4e4e6c7fcd16658c50783e00c341609977aed3ad00937bf4ee942a8993701483045022100da6bee3c93766232079a01639d07fa869598749729ae323eab8eef53577d611b02207bef15429dcadce2121ea07f233115c6f09034c0be68db99980b9a6c5e75402201475221022626e955ea6ea6d98850c994f9107b036b1334f18ca8830bfff1295d21cfdb702103b287eaf122eea69030a0e9feed096bed8045c8b98bec453e1ffac7fbdbd4bb7152aeffffffff04d3b11400000000001976a914904a49878c0adfc3aa05de7afad2cc15f483a56a88ac7f400900000000001976a914418327e3f3dda4cf5b9089325a4b95abdfa0334088ac722c0c00000000001976a914ba35042cfe9fc66fd35ac2224eebdafd1028ad2788acdc4ace020000000017a91474d691da1574e6b3c192ecfb52cc8984ee7b6c568700000000' hex_sec = '03b287eaf122eea69030a0e9feed096bed8045c8b98bec453e1ffac7fbdbd4bb71' hex_der = '3045022100da6bee3c93766232079a01639d07fa869598749729ae323eab8eef53577d611b02207bef15429dcadce2121ea07f233115c6f09034c0be68db99980b9a6c5e754022' hex_redeem_script = '475221022626e955ea6ea6d98850c994f9107b036b1334f18ca8830bfff1295d21cfdb702103b287eaf122eea69030a0e9feed096bed8045c8b98bec453e1ffac7fbdbd4bb7152ae' sec = bytes.fromhex(hex_sec) der = bytes.fromhex(hex_der) redeem_script = Script.parse(BytesIO(bytes.fromhex(hex_redeem_script))) stream = BytesIO(bytes.fromhex(hex_tx)) tx_obj = Tx.parse(stream) s = int_to_little_endian(tx_obj.version, 4) s += encode_varint(len(tx_obj.tx_ins)) i = tx_obj.tx_ins[0] s += TxIn(i.prev_tx, i.prev_index, redeem_script, i.sequence).serialize() s += encode_varint(len(tx_obj.tx_outs)) for tx_out in tx_obj.tx_outs: s += tx_out.serialize() s += int_to_little_endian(tx_obj.locktime, 4) s += int_to_little_endian(SIGHASH_ALL, 4) z = int.from_bytes(hash256(s), 'big') point = S256Point.parse(sec) sig = Signature.parse(der) self.assertTrue(point.verify(z, sig))
def filterload(self, flag=1): '''Return the filterload message''' # start the payload with the size of the filter in bytes payload = encode_varint(self.size) # next add the bit field using self.filter_bytes() payload += self.filter_bytes() # function count is 4 bytes little endian payload += int_to_little_endian(self.function_count, 4) # tweak is 4 bytes little endian payload += int_to_little_endian(self.tweak, 4) # flag is 1 byte little endian payload += int_to_little_endian(flag, 1) # return a GenericMessage whose command is b'filterload' # and payload is what we've calculated return GenericMessage(b'filterload', payload)
def sig_hash(self, input_index): s = int_to_little_endian(self.version, 4) s += encode_varint(len(self.tx_ins)) for i, tx_in in enumerate(self.tx_ins): if i == input_index: s += TxIn( prev_tx=tx_in.prev_tx, prev_index=tx_in.prev_index, script_sig=tx_in.script_pubkey(self.testnet), sequence=tx_in.sequence, ).serialize() else: s += TxIn( prev_tx=tx_in.prev_tx, prev_index=tx_in.prev_index, sequence=tx_in.sequence, ).serialize() s += encode_varint(len(self.tx_outs)) for tx_out in self.tx_outs: s += tx_out.serialize() s += int_to_little_endian(self.locktime, 4) s += int_to_little_endian(SIGHASH_ALL, 4) h256 = hash256(s) return int.from_bytes(h256, 'big')
def sig_hash(self, input_index): '''Returns the integer representation of the hash that needs to get signed for index input_index''' # start the serialization with version # use int_to_little_endian in 4 bytes s = int_to_little_endian(self.version, 4) # add how many inputs there are using encode_varint s += encode_varint(len(self.tx_ins)) # loop through each input using enumerate, so we have the input index # if the input index is the one we're signing # the previous tx's ScriptPubkey is the ScriptSig # Otherwise, the ScriptSig is empty # add the serialization of the input with the ScriptSig we want for i, tx_in in enumerate(self.tx_ins): if i == input_index: s += TxIn(prev_tx=tx_in.prev_tx, prev_index=tx_in.prev_index, script_sig=tx_in.script_pubkey(self.testnet), sequence=tx_in.sequence).serialize() else: s += TxIn(prev_tx=tx_in.prev_tx, prev_index=tx_in.prev_index, sequence=tx_in.sequence).serialize() # add how many outputs there are using encode_varint s += encode_varint(len(self.tx_outs)) # add the serialization of each output for tx_out in self.tx_outs: s += tx_out.serialize() # add the locktime using int_to_little_endian in 4 bytes s += int_to_little_endian(self.locktime, 4) # add SIGHASH_ALL using int_to_little_endian in 4 bytes s += int_to_little_endian(SIGHASH_ALL, 4) # hash256 the serialization h256 = hash256(s) # convert the result to an integer using int.from_bytes(x, 'big') return int.from_bytes(h256, 'big')
def test_varint(self): tests = [ (0x01, unhexlify('01')), (0xfd, unhexlify('fdfd00')), (0xfe, unhexlify('fdfe00')), (0xff, unhexlify('fdff00')), (0x1234, unhexlify('fd3412')), (0x123456, unhexlify('fe56341200')), (0x123456789a01, unhexlify('ff019a785634120000')), ] for num, encoded in tests: self.assertEqual(encode_varint(num), encoded) s = BytesIO(encoded) self.assertEqual(read_varint(s), num) self.assertRaises(ValueError, encode_varint, 2**65)
def serialize(self): '''Returns the byte serialization of the transaction input''' # serialize prev_tx, little endian result = self.prev_tx[::-1] # serialize prev_index, 4 bytes, little endian result += int_to_little_endian(self.prev_index, 4) # get the scriptSig ready (use self.script_sig.serialize()) raw_script_sig = self.script_sig.serialize() # encode_varint on the length of the scriptSig result += encode_varint(len(raw_script_sig)) # add the scriptSig result += raw_script_sig # serialize sequence, 4 bytes, little endian result += int_to_little_endian(self.sequence, 4) return result
def script_pubkey(self, testnet=False): '''Get the ScriptPubKey by looking up the tx hash Returns a Script object ''' # use self.fetch_tx to get the transaction #tx = self.fetch_tx(testnet=testnet)#ORIGINAL # get the output at self.prev_index # return the script_pubkey property #return tx.tx_outs[self.prev_index].script_pubkey if testnet: coin_sym = "btc-testnet" else: coin_sym = "btc" pretx = get_transaction_details(self.prev_tx.hex(),coin_symbol=coin_sym) ser_script = pretx["outputs"][self.prev_index]["script"] length = hex(int.from_bytes(encode_varint(len(ser_script)//2),"big"))[2:] script_pubkey = Script.parse(BytesIO(bytes.fromhex(length+ser_script))) return script_pubkey
def serialize(self): '''Returns the byte serialization of the transaction input''' # serialize prev_tx, little endian result = self.prev_tx[::-1] # serialize prev_index, 4 bytes, little endian result += int_to_little_endian(self.prev_index, 4) # serialize the script_sig if self.script_sig is None: result += b'\x00' else: #result += self.script_sig.serialize() result += encode_varint(len(self.script_sig)) result += self.script_sig # serialize sequence, 4 bytes, little endian result += int_to_little_endian(self.sequence, 4) return result
def sign_input(self, input_index, private_key): # added for signing p2sh script tx_in = self.tx_ins[input_index] script_lock = tx_in.get_script_lock(testnet=self.testnet) if script_lock.is_p2sh_script_pubkey(): cmd = tx_in.script_sig.cmds[ -1] # last element in script_sig of p2sh is redeem script redeem_for_parsing = encode_varint(len(cmd)) + cmd # for parsing redeem_script = script.parse(BytesIO(redeem_for_parsing)) else: redeem_script = None z = self.sig_hash(input_index, redeem_script) der = private_key.sign(z).der() sig = der + SIGHASH_ALL.to_bytes(1, 'big') sec = private_key.pubPoint.sec() script_sig = Script([sig, sec]) self.tx_ins[input_index].script_sig = script_sig return self.verify_input(input_index)
def serialize(self): s = int_to_little_endian(self.version, 4) s += int_to_little_endian(self.services, 8) s += int_to_little_endian(self.timestamp, 8) s += int_to_little_endian(self.receiver_services, 8) s += (b'\x00' * 10) + (b'\xff' * 2) + self.receiver_ip s += int_to_little_endian(self.receiver_port, 2) s += int_to_little_endian(self.sender_services, 8) s += (b'\x00' * 10) + (b'\xff' * 2) + self.sender_ip s += int_to_little_endian(self.sender_port, 2) s += self.nonce s += encode_varint(len(self.user_agent)) s += self.user_agent s += int_to_little_endian(self.latest_block, 4) if self.relay: s += b'\x01' else: s += b'\x00' return s
def serialize(self): result = int_to_little_endian(self.version, 4) result += int_to_little_endian(self.services, 8) result += int_to_little_endian(self.timestamp, 8) result += int_to_little_endian(self.receiver_services, 8) result += b'\x00' * 10 + b'\xff\xff' + self.receiver_ip result += self.receiver_port.to_bytes(2, 'big') result += int_to_little_endian(self.sender_services, 8) result += b'\x00' * 10 + b'\xff\xff' + self.sender_ip result += self.sender_port.to_bytes(2, 'big') result += self.nonce result += encode_varint(len(self.user_agent)) result += self.user_agent result += int_to_little_endian(self.latest_block, 4) if self.relay: result += b'\x01' else: result += b'\x00' return result
async def process_queue(self): print("start processing") start = time.time() while self.keep_looping: envelope = await self.q.get() command = envelope.command.strip(b'\x00').decode('ascii') if command == 'version': self.send(b'verack', b'') elif command == 'sendheaders': self.send(b'headers', encode_varint(0)) elif command == 'ping': self.send(b'pong', envelope.payload) if not self._sent: # tell them we have a tx self.send(b'inv', self.inv_payload) elif not self._accepted: self.send(b'tx', self.raw_tx) self.send(b'mempool', b'') elif command == 'getdata': if envelope.payload == self.inv_payload: self.send(b'tx', self.raw_tx) self._sent = True elif self._sent: print('TX rejected') self.keep_looping = False elif command == 'feefilter': minimum = little_endian_to_int(envelope.payload) print('TX requires fee: {} minimum'.format(minimum)) elif command == 'inv': stream = BytesIO(envelope.payload) num_inv = read_varint(stream) for _ in range(num_inv): inv_type = little_endian_to_int(stream.read(4)) inv_hash = stream.read(32) if inv_type == 1 and inv_hash == self.tx_hash: print('TX successfully sent') self.keep_looping = False self.send(b'inv', self.inv_payload) else: print(envelope) if time.time() - start < self.timeout: self.keep_looping = False
def encode_address(_script_pubkey, testnet=True): address = "" addr_type = "" length = encode_varint(len(_script_pubkey)) stream = BytesIO(length + _script_pubkey) #stream = BytesIO(_script_pubkey) try: script_pubkey = Script.parse(stream) if script_pubkey.is_p2pkh_script_pubkey(): address = h160_to_p2pkh_address(script_pubkey.cmds[2], testnet) addr_type = "P2PKH" elif script_pubkey.is_p2sh_script_pubkey(): address = h160_to_p2sh_address(script_pubkey.cmds[1], testnet) addr_type = "P2SH" elif script_pubkey.is_p2wpkh_script_pubkey( ) or script_pubkey.is_p2wsh_script_pubkey(): if testnet: address = segwit_addr.encode("tb", 0, script_pubkey.cmds[1]) else: address = segwit_addr.encode("bc", 0, script_pubkey.cmds[1]) if script_pubkey.is_p2wpkh_script_pubkey(): addr_type = "P2WPKH" else: addr_type = "P2WSH" elif len(script_pubkey.cmds ) == 2 and script_pubkey.cmds[1] == 0xac: try: address = script_pubkey.cmds[0].hex() addr_type = "P2PK" except: app_log.info( f"P2PK failed {script_pubkey.cmds[0]} from tx: {output['t.id']}" ) except: app_log.info(f"script parsing failed.") return address, addr_type
def save(self): store_height = self.store_height() if exists(self.filename): with open(self.filename, 'rb') as f: file_height = read_varint(f) if store_height == file_height: # no need to save as we're synced return rest = f.read() else: file_height = -1 rest = b'' with open(self.filename, 'wb') as f: f.write(encode_varint(store_height)) for height in range(store_height, file_height, -1): h = self.header_by_height(height) f.write(h.serialize()) f.write(h.cfheader) f.write(h.cfhash) f.write(rest)
def serialize(self): '''Serialize this message to send over the network''' result = int_to_little_endian(self.version, 4) result += int_to_little_endian(self.services, 8) result += int_to_little_endian(self.timestamp, 8) result += int_to_little_endian(self.receiver_services, 8) result += 10 * b'\x00' + 2 * b'\xff' + self.receiver_ip result += self.receiver_port.to_bytes(2, byteorder='big') result += int_to_little_endian(self.sender_services, 8) result += 10 * b'\x01' + 2 * b'\xff' + self.sender_ip result += self.sender_port.to_bytes(2, byteorder='big') result += self.nonce result += encode_varint(len(self.user_agent)) result += self.user_agent result += int_to_little_endian(self.latest_block, 4) if self.relay: result += b'\x01' else: result += b'\x00' return result
def serialize(self): # initialize what we'll send back result = b'' # go through each item for item in self.items: # if the item is an integer, it's an op code if type(item) == int: # turn the item into a single byte integer using int_to_little_endian result += int_to_little_endian(item, 1) else: # otherwise, this is an element # get the length in bytes length = len(item) # turn the length into a single byte integer using int_to_little_endian prefix = int_to_little_endian(length, 1) # append to the result both the length and the item result += prefix + item # get the length of the whole thing total = len(result) # encode_varint the total length of the result and prepend return encode_varint(total) + result
def serialize(self): '''Serialize this message to send over the network''' # version is 4 bytes little endian s = int_to_little_endian(self.version, 4) # services is 8 bytes little endian s += int_to_little_endian(self.services, 8) # timestamp is 8 bytes little endian s += int_to_little_endian(self.timestamp, 8) # receiver services is 8 bytes little endian s += int_to_little_endian(self.receiver_services, 8) # IPV4 is 10 00 bytes and 2 ff bytes then receiver ip if len(self.receiver_ip) == 4: s += b'\x00' * 10 + b'\xff' * 2 + self.receiver_ip else: s += self.receiver_ip # receiver port is 2 bytes, big endian s += self.receiver_port.to_bytes(2, 'big') # sender services is 8 bytes little endian s += int_to_little_endian(self.sender_services, 8) # IPV4 is 10 00 bytes and 2 ff bytes then sender ip if len(self.sender_ip) == 4: s += b'\x00' * 10 + b'\xff' * 2 + self.sender_ip else: s += self.sender_ip # sender port is 2 bytes, big endian s += self.sender_port.to_bytes(2, 'big') # nonce should be 8 bytes s += self.nonce # useragent is a variable string, so varint first s += encode_varint(len(self.user_agent)) s += self.user_agent # latest block is 4 bytes little endian s += int_to_little_endian(self.latest_block, 4) # relay is 00 if false, 01 if true if self.relay: s += b'\x01' else: s += b'\x00' return s
def save(self): with open(self.filename, 'wb') as f: f.write(self.encrypted_private.serialize()) f.write(self.public.serialize()) f.write(encode_varint(self.next_external)) f.write(encode_varint(self.next_internal)) f.write(encode_varint(self.creation_height)) f.write(encode_varint(self.sync_height)) utxos = [u for u in self.utxo_lookup.values()] f.write(encode_varint(len(utxos))) for utxo in utxos: f.write(utxo.serialize()) stxos = [s for s in self.stxo_lookup.values()] f.write(encode_varint(len(stxos))) for stxo in stxos: f.write(stxo.serialize())
def serialize(self): '''Serialize this message to send over the network''' result = b'' result += self.version.to_bytes(4, byteorder='little') result += self.services.to_bytes(8, byteorder='little') result += self.timestamp.to_bytes(8, byteorder='little') result += self.receiver_services.to_bytes(8, byteorder='little') result += bytes.fromhex('00000000000000000000ffff') result += self.receiver_ip result += self.receiver_port.to_bytes(2, byteorder='big') result += self.sender_services.to_bytes(8, byteorder='little') result += bytes.fromhex('00000000000000000000ffff') result += self.sender_ip result += self.sender_port.to_bytes(2, byteorder='big') result += self.nonce result += encode_varint(len(self.user_agent)) result += self.user_agent result += int_to_little_endian(self.latest_block, 4) if self.relay: result += b'\x01' else: result += b'\x00' return result
def verify_input(self, input_index): # get the relevant input tx_in = self.tx_ins[input_index] # grab the previous ScriptPubKey script_pubkey = tx_in.script_pubkey(testnet=self.testnet) # check to see if the ScriptPubkey is a p2sh using # Script.is_p2sh_script_pubkey() if script_pubkey.is_p2sh_script_pubkey(): # the last cmd in a p2sh is the RedeemScript cmd = tx_in.script_sig.cmds[-1] # prepend the length of the RedeemScript using encode_varint raw_redeem = encode_varint(len(cmd)) + cmd # parse the RedeemScript redeem_script = Script.parse(BytesIO(raw_redeem)) # otherwise RedeemScript is None else: redeem_script = None # get the signature hash (z) # pass the RedeemScript to the sig_hash method z = self.sig_hash(input_index, redeem_script) # combine the current ScriptSig and the previous ScriptPubKey combined = tx_in.script_sig + script_pubkey # evaluate the combined script return combined.evaluate(z)
def serialize(self): result = encode_varint(len(self.data)) for data_type, identifier in self.data: result += int_to_little_endian(data_type, 4) result += identifier[::-1] return result
def serialize(self): result = int_to_little_endian(self.version, 4) result += encode_varint(self.num_hashes) result += self.start_block[::-1] result += self.end_block[::-1] return result
def evaluate(self, z, witness): # create a copy as we may need to add to this list if we have a # RedeemScript cmds = self.cmds[:] stack = [] altstack = [] while len(cmds) > 0: cmd = cmds.pop(0) if type(cmd) == int: # do what the opcode says operation = OP_CODE_FUNCTIONS[cmd] if cmd in (99, 100): # op_if/op_notif require the cmds array if not operation(stack, cmds): LOGGER.info('bad op: {}'.format(OP_CODE_NAMES[cmd])) return False elif cmd in (107, 108): # op_toaltstack/op_fromaltstack require the altstack if not operation(stack, altstack): LOGGER.info('bad op: {}'.format(OP_CODE_NAMES[cmd])) return False elif cmd in (172, 173, 174, 175): # these are signing operations, they need a sig_hash # to check against if not operation(stack, z): LOGGER.info('bad op: {}'.format(OP_CODE_NAMES[cmd])) return False else: if not operation(stack): LOGGER.info('bad op: {}'.format(OP_CODE_NAMES[cmd])) return False else: # add the cmd to the stack stack.append(cmd) # p2sh rule. if the next three cmds are: # OP_HASH160 <20 byte hash> OP_EQUAL this is the RedeemScript # OP_HASH160 == 0xa9 and OP_EQUAL == 0x87 if len(cmds) == 3 and cmds[0] == 0xa9 \ and type(cmds[1]) == bytes and len(cmds[1]) == 20 \ and cmds[2] == 0x87: redeem_script = encode_varint(len(cmd)) + cmd # we execute the next three opcodes cmds.pop() h160 = cmds.pop() cmds.pop() if not op_hash160(stack): return False stack.append(h160) if not op_equal(stack): return False # final result should be a 1 if not op_verify(stack): LOGGER.info('bad p2sh h160') return False # hashes match! now add the RedeemScript redeem_script = encode_varint(len(cmd)) + cmd stream = BytesIO(redeem_script) cmds.extend(Script.parse(stream).cmds) # witness program version 0 rule. if stack cmds are: # 0 <20 byte hash> this is p2wpkh # tag::source3[] if len(stack) == 2 and stack[0] == b'' and len(stack[1]) == 20: # <1> h160 = stack.pop() stack.pop() cmds.extend(witness) cmds.extend(p2pkh_script(h160).cmds) # end::source3[] # witness program version 0 rule. if stack cmds are: # 0 <32 byte hash> this is p2wsh # tag::source6[] if len(stack) == 2 and stack[0] == b'' and len(stack[1]) == 32: s256 = stack.pop() # <1> stack.pop() # <2> cmds.extend(witness[:-1]) # <3> witness_script = witness[-1] # <4> if s256 != sha256(witness_script): # <5> print('bad sha256 {} vs {}'.format (s256.hex(), sha256(witness_script).hex())) return False stream = BytesIO(encode_varint(len(witness_script)) + witness_script) witness_script_cmds = Script.parse(stream).cmds # <6> cmds.extend(witness_script_cmds) # end::source6[] if len(stack) == 0: return False if stack.pop() == b'': return False return True
def evaluate(self, z, witness): # create a copy as we may need to add to this list if we have a # RedeemScript instructions = self.instructions[:] stack = [] altstack = [] while len(instructions) > 0: instruction = instructions.pop(0) if type(instruction) == int: # do what the opcode says operation = OP_CODE_FUNCTIONS[instruction] if instruction in (99, 100): # op_if/op_notif require the instructions array if not operation(stack, instructions): LOGGER.info('bad op: {}'.format( OP_CODE_NAMES[instruction])) return False elif instruction in (107, 108): # op_toaltstack/op_fromaltstack require the altstack if not operation(stack, altstack): LOGGER.info('bad op: {}'.format( OP_CODE_NAMES[instruction])) return False elif instruction in (172, 173, 174, 175): # these are signing operations, they need a sig_hash # to check against if not operation(stack, z): LOGGER.info('bad op: {}'.format( OP_CODE_NAMES[instruction])) return False else: if not operation(stack): LOGGER.info('bad op: {}'.format( OP_CODE_NAMES[instruction])) return False else: # add the instruction to the stack stack.append(instruction) # p2sh rule. if the next three instructions are: # OP_HASH160 <20 byte hash> OP_EQUAL this is the RedeemScript # OP_HASH160 == 0xa9 and OP_EQUAL == 0x87 if len(instructions) == 3 and instructions[0] == 0xa9 \ and type(instructions[1]) == bytes and len(instructions[1]) == 20 \ and instructions[2] == 0x87: redeem_script = encode_varint( len(instruction)) + instruction # we execute the next three opcodes instructions.pop() h160 = instructions.pop() instructions.pop() if not op_hash160(stack): return False stack.append(h160) if not op_equal(stack): return False # final result should be a 1 if not op_verify(stack): LOGGER.info('bad p2sh h160') return False # hashes match! now add the RedeemScript redeem_script = encode_varint( len(instruction)) + instruction stream = BytesIO(redeem_script) instructions.extend(Script.parse(stream).instructions) # witness program version 0 rule. if stack instructions are: # 0 <20 byte hash> this is p2wpkh if len(stack) == 2 and stack[0] == b'' and len(stack[1]) == 20: h160 = stack.pop() stack.pop() instructions.extend(witness) instructions.extend(p2pkh_script(h160).instructions) # witness program version 0 rule. if stack instructions are: # 0 <32 byte hash> this is p2wsh if len(stack) == 2 and stack[0] == b'' and len(stack[1]) == 32: h256 = stack.pop() stack.pop() instructions.extend(witness[:-1]) witness_script = witness[-1] if h256 != sha256(witness_script): LOGGER.info('bad sha256 {} vs {}'.format( h256.hex(), sha256(witness_script).hex())) return False # hashes match! now add the Witness Script stream = BytesIO( encode_varint(len(witness_script)) + witness_script) witness_script_instructions = Script.parse( stream).instructions instructions.extend(witness_script_instructions) if len(stack) == 0: return False if stack.pop() == b'': return False return True
def _create_addresses(tx, batch, testnet=True): """ testnet is TRUE always. Change this for mainnet later. """ batch_size = 5 app_log.info( f" batch size {batch_size}. Represents the amount of blocks whose outputs are being encoded to addresses." ) for height in range(batch * batch_size, batch_size * (batch + 1)): result = tx.run( "MATCH (b:block {height:$height}) " "MATCH (x)<-[:CREATES]-(t:transaction)<-[:CONTAINS]-(b) " "RETURN x.script_pubkey, x.index, t.id", height=height) addresses = [] for output in result.data(): address = None addr_type = None raw_script_pubkey = output["x.script_pubkey"] b_sp = bytes.fromhex(raw_script_pubkey) length = encode_varint(len(b_sp)) stream = BytesIO(length + b_sp) try: script_pubkey = Script.parse(stream) if script_pubkey.is_p2pkh_script_pubkey(): address = h160_to_p2pkh_address( script_pubkey.cmds[2], testnet) addr_type = "P2PKH" elif script_pubkey.is_p2sh_script_pubkey(): address = h160_to_p2sh_address(script_pubkey.cmds[1], testnet) addr_type = "P2SH" elif script_pubkey.is_p2wpkh_script_pubkey( ) or script_pubkey.is_p2wsh_script_pubkey(): if testnet: address = segwit_addr.encode( "tb", 0, script_pubkey.cmds[1]) else: address = segwit_addr.encode( "bc", 0, script_pubkey.cmds[1]) if script_pubkey.is_p2wpkh_script_pubkey(): addr_type = "P2WPKH" else: addr_type = "P2WSH" elif len(script_pubkey.cmds ) == 2 and script_pubkey.cmds[1] == 0xac: try: address = script_pubkey.cmds[0].hex() addr_type = "P2PK" except: app_log.info( f"P2PK failed {script_pubkey.cmds[0]} from tx: {output['t.id']}" ) except: app_log.info( f"script parsing failed in tx {output['t.id']} index {output['x.index']} " ) if address is not None: address_dict = { "address": address, "type": addr_type, "tx_id": output["t.id"], "index": output["x.index"] } addresses.append(address_dict) if len(addresses) > 0: result = tx.run( "FOREACH (address in $addresses | \n" "MERGE (o:output {index:address.index})<-[:CREATES]-(:transaction {id:address.tx_id}) \n" "MERGE (a:address {address:address.address}) SET a.type=address.type \n" "MERGE (a)-[:HAS]->(o) )", addresses=addresses) return
def evaluate(self, z): # create a copy as we may need to add to this list if we have a # RedeemScript cmds = self.cmds[:] stack = [] altstack = [] while len(cmds) > 0: cmd = cmds.pop(0) if type(cmd) == int: # do what the opcode says operation = OP_CODE_FUNCTIONS[cmd] if cmd in (99, 100): # op_if/op_notif require the cmds array if not operation(stack, cmds): LOGGER.info('bad op: {}'.format(OP_CODE_NAMES[cmd])) return False elif cmd in (107, 108): # op_toaltstack/op_fromaltstack require the altstack if not operation(stack, altstack): LOGGER.info('bad op: {}'.format(OP_CODE_NAMES[cmd])) return False elif cmd in (172, 173, 174, 175): # these are signing operations, they need a sig_hash # to check against if not operation(stack, z): LOGGER.info('bad op: {}'.format(OP_CODE_NAMES[cmd])) return False else: if not operation(stack): LOGGER.info('bad op: {}'.format(OP_CODE_NAMES[cmd])) return False # tag::source1[] else: #리딤 스크립트를 스택에 올린다. stack.append(cmd) #그리고 다음명령이 op_hash160, 리딤스크립트의 hash값, op_euqal이면, if len(cmds) == 3 and cmds[0] == 0xa9 \ and type(cmds[1]) == bytes and len(cmds[1]) == 20 \ and cmds[2] == 0x87: # <1> cmds.pop() # <2> h160 = cmds.pop() cmds.pop() #리딤 스크립트를 해시 if not op_hash160(stack): # <3> return False #리딤 스크립트의 해시 값을 추가 stack.append(h160) #두 값이 같은지 비교 if not op_equal(stack): return False if not op_verify(stack): # <4> LOGGER.info('bad p2sh h160') return False #리딤 스크립트의 길이를 구해 리딤 스크립트의 앞에 위치시킨다. redeem_script = encode_varint(len(cmd)) + cmd # <5> stream = BytesIO(redeem_script) #리딤 스크립트를 파싱해서 명령어 집합에 추가 cmds.extend(Script.parse(stream).cmds) # <6> # end::source1[] if len(stack) == 0: return False if stack.pop() == b'': return False return True
1574e6b3c192ecfb52cc8984ee7b6c568700000000' hex_sec = '03b287eaf122eea69030a0e9feed096bed8045c8b98bec453e1ffac7fbdbd4b\ b71' hex_der = '3045022100da6bee3c93766232079a01639d07fa869598749729ae323eab8ee\ f53577d611b02207bef15429dcadce2121ea07f233115c6f09034c0be68db99980b9a6c5e75402\ 2' hex_redeem_script = '475221022626e955ea6ea6d98850c994f9107b036b1334f18ca88\ 30bfff1295d21cfdb702103b287eaf122eea69030a0e9feed096bed8045c8b98bec453e1ffac7f\ bdbd4bb7152ae' sec = bytes.fromhex(hex_sec) der = bytes.fromhex(hex_der) redeem_script = Script.parse(BytesIO(bytes.fromhex(hex_redeem_script))) stream = BytesIO(bytes.fromhex(hex_tx)) tx_obj = Tx.parse(stream) s = int_to_little_endian(tx_obj.version, 4) s += encode_varint(len(tx_obj.tx_ins)) i = tx_obj.tx_ins[0] s += TxIn(i.prev_tx, i.prev_index, redeem_script, i.sequence).serialize() s += encode_varint(len(tx_obj.tx_outs)) for tx_out in tx_obj.tx_outs: s += tx_out.serialize() s += int_to_little_endian(tx_obj.locktime, 4) s += int_to_little_endian(SIGHASH_ALL, 4) z = int.from_bytes(hash256(s), 'big') point = S256Point.parse(sec) sig = Signature.parse(der) print(point.verify(z, sig))
def serialize_pair(key, value): kv_bytes = encode_varint(len(key)) + key kv_bytes += encode_varint(len(value)) + value return kv_bytes
def evaluate(self, z): # create a copy as we may need to add to this list if we have a # RedeemScript instructions = self.instructions[:] stack = [] altstack = [] while len(instructions) > 0: instruction = instructions.pop(0) if type(instruction) == int: # do what the opcode says operation = OP_CODE_FUNCTIONS[instruction] if instruction in (99, 100): # op_if/op_notif require the instructions array if not operation(stack, instructions): LOGGER.info('bad op: {}'.format( OP_CODE_NAMES[instruction])) return False elif instruction in (107, 108): # op_toaltstack/op_fromaltstack require the altstack if not operation(stack, altstack): LOGGER.info('bad op: {}'.format( OP_CODE_NAMES[instruction])) return False elif instruction in (172, 173, 174, 175): # these are signing operations, they need a sig_hash # to check against if not operation(stack, z): LOGGER.info('bad op: {}'.format( OP_CODE_NAMES[instruction])) return False else: if not operation(stack): LOGGER.info('bad op: {}'.format( OP_CODE_NAMES[instruction])) return False else: # add the instruction to the stack stack.append(instruction) if len(instructions) == 3 and instructions[0] == 0xa9 \ and type(instructions[1]) == bytes and len(instructions[1]) == 20 \ and instructions[2] == 0x87: # we execute the next three opcodes instructions.pop() h160 = instructions.pop() instructions.pop() if not op_hash160(stack): return False stack.append(h160) if not op_equal(stack): return False # final result should be a 1 if not op_verify(stack): LOGGER.info('bad p2sh h160') return False # hashes match! now add the RedeemScript redeem_script = encode_varint( len(instruction)) + instruction stream = BytesIO(redeem_script) instructions.extend(Script.parse(stream).instructions) if len(stack) == 0: return False if stack.pop() == b'': return False return True