def test_int_to_little_endian(): n = 1 want = b'\x01\x00\x00\x00' assert util.int_to_little_endian(n, 4) == want n = 10011545 want = b'\x99\xc3\x98\x00\x00\x00\x00\x00' assert util.int_to_little_endian(n, 8) == want
def serialize_txi(txi): result = txi["txid"][::-1] # serialize prev_tx, little endian result += util.int_to_little_endian( txi["idx"], 4) # serialize prev_index, 4 bytes, little endian result += script.serialize(txi["script"]) # serialize the unlock_script result += util.int_to_little_endian( txi["seq.no"], 4) # serialize sequence, 4 bytes, little endian return result
def hash_all_txis(tx): if tx["hash_all"] is None: all_prevouts = b'' all_sequence = b'' for txi in tx["txis"]: all_prevouts += txi["txid"][::-1] + util.int_to_little_endian(txi["idx"], 4) all_sequence += util.int_to_little_endian(txi["seq.no"], 4) tx["hash_all"] = (util.hash256(all_prevouts), util.hash256(all_sequence)) return tx["hash_all"]
def serialize_legacy(tx): result = util.int_to_little_endian(tx["version"], 4) result += util.encode_varint(tx["txi.count"]) for txi in tx["txis"]: result += serialize_txi(txi) result += util.encode_varint(tx["txo.count"]) for txo in tx["txos"]: result += serialize_txo(txo) result += util.int_to_little_endian(tx["locktime"], 4) return result
def serialize_filterload(payload, flag=1): """Return the filterload message""" # start the payload with the size of the filter in bytes result = util.encode_varint(payload['size']) # next add the bit field using self.filter_bytes() result += bloomfilter.bit_field_to_bytes(payload['bit_field']) # function count is 4 bytes little endian result += util.int_to_little_endian(payload['function_count'], 4) # tweak is 4 bytes little endian result += util.int_to_little_endian(payload['tweak'], 4) # flag is 1 byte little endian result += util.int_to_little_endian(flag, 1) return result
def serialize(obj): """ 4: version (LE) 32: prev_block_hash (LE) 32: merkle_root (LE) 4: timestamp (LE) 4: bits 4: nonce """ result = util.int_to_little_endian(obj['version'], 4) result += obj['prev_block_hash'][::-1] result += obj['merkle_root'][::-1] result += util.int_to_little_endian(obj['timestamp'], 4) result += obj['bits'] result += obj['nonce'] return result
def gen_version(version=70015, services=0, timestamp=None, receiver_services=0, receiver_ip=b'\x00\x00\x00\x00', receiver_port=8333, sender_services=0, sender_ip=b'\x00\x00\x00\x00', sender_port=8333, nonce=None, user_agent=b'/bitcoinpy:0.1/', latest_block=0, relay=False): payload = {} payload['version'] = version payload['services'] = services if timestamp is None: payload['timestamp'] = int(time.time()) else: payload['timestamp'] = timestamp payload['receiver_services'] = receiver_services payload['receiver_ip'] = receiver_ip payload['receiver_port'] = receiver_port payload['sender_services'] = sender_services payload['sender_ip'] = sender_ip payload['sender_port'] = sender_port if nonce is None: payload['nonce'] = util.int_to_little_endian(randint(0, 2**64), 8) else: payload['nonce'] = nonce payload['user_agent'] = user_agent payload['latest_block'] = latest_block payload['relay'] = relay return payload
def serialize_segwit(tx): result = util.int_to_little_endian(tx["version"], 4) result += tx["mark"] result += tx["flag"] result += util.encode_varint(tx["txi.count"]) for txi in tx["txis"]: result += serialize_txi(txi) result += util.encode_varint(tx["txo.count"]) for txo in tx["txos"]: result += serialize_txo(txo) for txi in tx["txis"]: result += util.int_to_little_endian(len(txi["wits"]), 1) for item in txi["wits"]: if type(item) == int: result += util.int_to_little_endian(item, 1) else: result += util.encode_varint(len(item)) + item result += util.int_to_little_endian(tx["locktime"], 4) return result
def serialize_getdata(payload): # start with the number of items as a varint result = util.encode_varint(len(payload['data'])) # loop through each tuple (data_type, identifier) in self.data for data_type, identifier in payload['data']: # data type is 4 bytes Little-Endian result += util.int_to_little_endian(data_type, 4) # identifier needs to be in Little-Endian result += identifier[::-1] return result
def serialize_getheaders(payload): """Serialize this message to send over the network""" # protocol version is 4 bytes little-endian result = util.int_to_little_endian(payload['version'], 4) # number of hashes is a varint result += util.encode_varint(payload['num_hashes']) # start block is in little-endian result += payload['start_block'][::-1] # end block is also in little-endian result += payload['end_block'][::-1] return result
def sig_hash_bip143(prev_tx, tx, txi, redeem_script=None, witness_script=None, testnet=False): """ bip143 1:04LE version 2:32 hash prevouts 3:32 hash sequence 4:32+4LE outpoint 5:* script_code of the input 6:08LE value of output spent 7:04LE n_sequence of the input 8:32 hash outputs 9:4LE n_locktime 10:4LE sighash """ s = util.int_to_little_endian(tx["version"], 4) # 1 hash_all_prevouts, hash_all_sequence = hash_all_txis(tx) s += hash_all_prevouts + hash_all_sequence # 2,3 s += txi["txid"][::-1] + util.int_to_little_endian(txi["idx"], 4) # 4 # 5 if witness_script: script_code = script.serialize(witness_script) elif redeem_script: script_code = script.serialize(script.p2pkh_script(redeem_script[1])) else: script_code = script.serialize(script.p2pkh_script(prev_tx["txos"][txi["idx"]]["script"][1])) s += script_code s += util.int_to_little_endian(prev_tx["txos"][txi["idx"]]["amount"], 8) # 6 s += util.int_to_little_endian(txi["seq.no"], 4) # 7 s += hash_all_txos(tx) # 8 s += util.int_to_little_endian(tx["locktime"], 4) # 9 s += util.int_to_little_endian(util.SIGHASH_ALL, 4) # 10 return int.from_bytes(util.hash256(s), 'big')
def serialize_version(payload): """Serialize this message to send over the network""" # version is 4 bytes little endian result = util.int_to_little_endian(payload['version'], 4) # services is 8 bytes little endian result += util.int_to_little_endian(payload['services'], 8) # timestamp is 8 bytes little endian result += util.int_to_little_endian(payload['timestamp'], 8) # receiver services is 8 bytes little endian result += util.int_to_little_endian(payload['receiver_services'], 8) # IPV4 is 10 00 bytes and 2 ff bytes then receiver ip result += b'\x00' * 10 + b'\xff\xff' + payload['receiver_ip'] # receiver port is 2 bytes, big endian result += payload['receiver_port'].to_bytes(2, 'big') # sender services is 8 bytes little endian result += util.int_to_little_endian(payload['sender_services'], 8) # IPV4 is 10 00 bytes and 2 ff bytes then sender ip result += b'\x00' * 10 + b'\xff\xff' + payload['sender_ip'] # sender port is 2 bytes, big endian result += payload['sender_port'].to_bytes(2, 'big') # nonce should be 8 bytes result += payload['nonce'] # useragent is a variable string, so varint first result += util.encode_varint(len(payload['user_agent'])) result += payload['user_agent'] # latest block is 4 bytes little endian result += util.int_to_little_endian(payload['latest_block'], 4) # relay is 00 if false, 01 if true if payload['relay']: result += b'\x01' else: result += b'\x00' return result
def serialize_msg(msg): """Returns the byte serialization of the entire network message""" # add the network magic result = msg['magic'] # command 12 bytes # fill with 0's result += msg['command'] + b'\x00' * (12 - len(msg['command'])) # payload length 4 bytes, little endian result += util.int_to_little_endian(len(msg['payload_bytes']), 4) # checksum 4 bytes, first four of hash256 of payload result += util.hash256(msg['payload_bytes'])[:4] # payload result += msg['payload_bytes'] return result
def sig_hash(tx, idx, lock_script): tx4sig = copy.deepcopy(tx) for i, txi in enumerate(tx4sig['txis']): if i != idx: # script.len is calculated when it is serialized. # txi["script.len"] = 0 txi["script"] = [] else: # script.len is calculated when it is serialized. # script = serialize_script(script_unlock) # txi["script.len"] = len(script) txi["script"] = lock_script s = serialize(tx4sig) s += util.int_to_little_endian(util.SIGHASH_ALL, 4) h256 = util.hash256(s) return int.from_bytes(h256, 'big')
def serialize(script): result = b'' # initialize what we'll send back for token in script: # go through each token if type(token) == int: # if the token is an integer, it's an opcode result += util.int_to_little_endian(token, 1) else: # otherwise, this is an element length = len(token) # get the length in bytes if length < 75: # turn the length into a single byte integer result += util.int_to_little_endian(length, 1) elif 75 < length < 0x100: # 76 is pushdata1 result += util.int_to_little_endian(76, 1) result += util.int_to_little_endian(length, 1) elif 0x100 <= length <= 520: # 77 is pushdata2 result += util.int_to_little_endian(77, 1) result += util.int_to_little_endian(length, 2) else: raise ValueError('too long an token') result += token total = len(result) return util.encode_varint(total) + result
def serialize_txo(txo): result = util.int_to_little_endian(txo["amount"], 8) # serialize amount, 8 bytes, little endian result += script.serialize(txo["script"]) # serialize the script_pubkey return result