def get_preimage(tx, input_index, utxo_value, utxo_script, sighash_flag=None): if not sighash_flag: sighash_flag = SigHash(SigHash.ALL | SigHash.FORKID) txin = tx.inputs[input_index] hash_prevouts = hash_sequence = hash_outputs = bitcoinx.consts.ZERO sighash_not_single_none = sighash_flag.base not in (SigHash.SINGLE, SigHash.NONE) if not sighash_flag.anyone_can_pay: hash_prevouts = tx._hash_prevouts() if sighash_not_single_none: hash_sequence = tx._hash_sequence() if sighash_not_single_none: hash_outputs = tx._hash_outputs() elif (sighash_flag.base == SigHash.SINGLE and input_index < len(tx.outputs)): hash_outputs = double_sha256(tx.outputs[input_index].to_bytes()) preimage = b''.join(( pack_le_int32(tx.version), hash_prevouts, hash_sequence, txin.to_bytes_for_signature(utxo_value, utxo_script), hash_outputs, pack_le_uint32(tx.locktime), pack_le_uint32(sighash_flag), )) return preimage
def to_bytes(self): return b''.join(( pack_le_int32(self.version), pack_list(self.inputs, XTxInput.to_bytes), pack_list(self.outputs, XTxOutput.to_bytes), pack_le_uint32(self.locktime), ))
def random_header(prev_hash=None, height=-1, good_bits=None): good_bits = good_bits or some_good_bits raw_header = bytearray(urandom(80)) raw_header[72:76] = pack_le_uint32(random.choice(good_bits)) if prev_hash: raw_header[4:36] = prev_hash return Bitcoin.deserialized_header(bytes(raw_header), height)
def setup_compressed_headers(tmpdir, headers_file, ts_offset, network): with open(os.path.join(data_dir, headers_file), 'rb') as f: raw_data = f.read() all_times = array.array('I') all_bits = array.array('I') read = io.BytesIO(raw_data).read first_height, = unpack_le_uint32(read(4)) header_count, = unpack_le_uint32(read(4)) # Timestamps first_time, = unpack_le_uint32(read(4)) all_times.append(first_time) for n in range(1, header_count): diff, = unpack_le_uint16(read(2)) all_times.append(all_times[-1] + diff - ts_offset) # Bits while True: raw = read(4) if not raw: break bits, = unpack_le_uint32(raw) if bits < 2016 * 2: count = bits bits, = unpack_le_uint32(read(4)) all_bits.extend(array.array('I', [bits]) * count) else: all_bits.append(bits) assert len(all_times) == header_count assert len(all_bits) == header_count raw_header = bytearray(80) raw_header[0] = 1 checkpoint = CheckPoint(raw_header, first_height + header_count - 1, 0) headers = create_headers(tmpdir, checkpoint, network=network) for height, (bits, timestamp) in enumerate(zip(all_bits, all_times), start=first_height): raw_header[68:72] = pack_le_uint32(timestamp) raw_header[72:76] = pack_le_uint32(bits) headers.set_one(height, raw_header) return headers
def get_push_item(item_bytes): ''' Returns script bytes to push item on the stack. ALL data is length prefixed. ''' dlen = len(item_bytes) if dlen < Ops.OP_PUSHDATA1: return pack_byte(dlen) + item_bytes elif dlen <= 0xff: return pack_byte(Ops.OP_PUSHDATA1) + pack_byte(dlen) + item_bytes elif dlen <= 0xffff: return pack_byte(Ops.OP_PUSHDATA2) + pack_le_uint16(dlen) + item_bytes return pack_byte(Ops.OP_PUSHDATA4) + pack_le_uint32(dlen) + item_bytes
def test_mainnet_2016_headers(tmpdir): # Mainnet headers 0, 2015, 2016, 4031, 4032, ... 4249808 headers = setup_headers(tmpdir, 'mainnet-headers-2016') chain = headers.chains()[0] for height in range(0, len(headers), 2016): header = headers.header_at_height(chain, height) assert headers.required_bits(chain, height, None) == header.bits assert headers.required_bits(chain, height + 1, None) == header.bits assert header.difficulty() == 860_221_984_436.2223 bounded_bits = 403011440 # Test // 4 is lower bound for the last one raw_header = bytearray(headers.raw_header_at_height(chain, height - 2016)) timestamp = Bitcoin.header_timestamp(raw_header) # Add 8 weeks and a 14 seconds; the minimum to trigger it raw_header[68:72] = pack_le_uint32(timestamp + 4 * 2016 * 600 + 14) headers.set_one(height - 1, raw_header) assert headers.required_bits(chain, height, ) == bounded_bits
def ref_sighash(script_code, tx, input_index, hash_type): assert input_index < len(tx.inputs) # In case concatenating two scripts ends up with two codeseparators, or an # extra one at the end, this prevents all those possible incompatibilities. script_code = script_code.find_and_delete(Script() << OP_CODESEPARATOR) # Blank out other inputs' signatures empty_script = Script() for tx_in in tx.inputs: tx_in.script_sig = empty_script tx.inputs[input_index].script_sig = script_code # Blank out some of the outputs if (hash_type & 0x1f) == SigHash.NONE: # Wildcard payee tx.outputs.clear() # Let the others update at will: for n, tx_in in enumerate(tx.inputs): if n != input_index: tx_in.sequence = 0 elif (hash_type & 0x1f) == SigHash.SINGLE: if input_index >= len(tx.outputs): return ONE tx_output = tx.outputs[input_index] tx.outputs = [TxOutput.null() for _ in range(input_index)] tx.outputs.append(tx_output) # Let the others update at will: for n, tx_in in enumerate(tx.inputs): if n != input_index: tx_in.sequence = 0 # Blank out other inputs completely; not recommended for open transactions if hash_type & SigHash.ANYONE_CAN_PAY: tx.inputs = [tx.inputs[input_index]] preimage = tx.to_bytes() + pack_le_uint32(hash_type) return double_sha256(preimage)
def test_connect(self, tmpdir): testnet_genesis_checkpoint = CheckPoint(BitcoinTestnet.genesis_header, 0, 0) headers_obj = create_headers(tmpdir, testnet_genesis_checkpoint) header1 = bytes.fromhex( '0100000043497fd7f826957108f4a30fd9cec3aeba79972084e90ead01ea330900000000bac8b0fa' '927c0ac8234287e33c5f74d38d354820e24756ad709d7038fc5f31f020e7494dffff001d03e4b672' ) header2 = bytes.fromhex( '0100000006128e87be8b1b4dea47a7247d5528d2702c96826c7a648497e773b800000000e241352e' '3bec0a95a6217e10c3abb54adfa05abb12c126695595580fb92e222032e7494dffff001d00d23534' ) # Test cache-clearing headers_obj.max_cache_size = 1 # Test they connect headers_obj.connect(header1) headers_obj.connect(header2) # Test re-adding is OK headers_obj.connect(header1) # Test bad bits raises bad_header = bytearray(header1) bad_header[72:76] = pack_le_uint32(472518933) with pytest.raises(IncorrectBits) as e: headers_obj.connect(bad_header) assert str(e.value).endswith('requires bits 0x486604799') # Test insufficient PoW raises bad_header = bytearray(header1) bad_header[0] = 2 with pytest.raises(InsufficientPoW) as e: headers_obj.connect(bad_header) assert 'exceeds its target' in str(e.value)