def _realize_script_sig(self, x_pubkeys, signatures): type_ = self.type() if type_ == 'p2pk': return Script(push_item(signatures[0])) if type_ == 'p2pkh': return Script(push_item(signatures[0]) + push_item(x_pubkeys[0].to_bytes())) if type_ == 'p2sh': parts = [pack_byte(Ops.OP_0)] parts.extend(push_item(signature) for signature in signatures) nested_script = multisig_script(x_pubkeys, self.threshold) parts.append(push_item(nested_script)) return Script(b''.join(parts)) return self.script_sig
def create_script_sig(script_type: ScriptType, threshold: int, x_pubkeys: List[XPublicKey], signatures: List[bytes]) -> Script: if script_type == ScriptType.P2PK: return Script(push_item(signatures[0])) elif script_type == ScriptType.P2PKH: return Script( push_item(signatures[0]) + push_item(x_pubkeys[0].to_bytes())) elif script_type == ScriptType.MULTISIG_P2SH: parts = [pack_byte(Ops.OP_0)] parts.extend(push_item(signature) for signature in signatures) nested_script = multisig_script(x_pubkeys, threshold) parts.append(push_item(nested_script)) return Script(b''.join(parts)) elif script_type == ScriptType.MULTISIG_BARE: parts = [pack_byte(Ops.OP_0)] parts.extend(push_item(signature) for signature in signatures) return Script(b''.join(parts)) elif script_type == ScriptType.MULTISIG_ACCUMULATOR: parts = [] for i, signature in enumerate(signatures): if signature == NO_SIGNATURE: parts.append([pack_byte(Ops.OP_FALSE)]) else: parts.append([ push_item(signature), push_item(x_pubkeys[i].to_bytes()), pack_byte(Ops.OP_TRUE), ]) parts.reverse() return Script(b''.join([value for l in parts for value in l])) raise ValueError(f"unable to realize script {script_type}")
def test_P2PK(self): script_hex = '210363f75554e05e05a04551e59d78d78965ec6789f42199f7cbaa9fa4bd2df0a4b4ac' s = Script.from_hex(script_hex) sc = classify_output_script(s, Bitcoin) assert isinstance(sc, P2PK_Output) assert (sc.public_key.to_hex() == '0363f75554e05e05a04551e59d78d78965ec6789f42199f7cbaa9fa4bd2df0a4b4') suffix = push_item(b'foo') + push_item(b'bar') + pack_byte(OP_2DROP) s2 = Script.from_hex(script_hex + suffix.hex()) sc2 = classify_output_script(s2, Bitcoin) assert sc2.public_key == sc.public_key assert s2 != s assert isinstance(sc2, P2PK_Output)
def test_to_script_bytes(self): pubkey_hex = '0363f75554e05e05a04551e59d78d78965ec6789f42199f7cbaa9fa4bd2df0a4b4' pubkey = PublicKey.from_hex(pubkey_hex) output = P2PK_Output(pubkey, Bitcoin) raw = output.to_script_bytes() assert isinstance(raw, bytes) assert raw == push_item(bytes.fromhex(pubkey_hex)) + pack_byte(OP_CHECKSIG)
def to_script_bytes(self): parts = [ pack_byte(Ops.OP_0), pack_byte(Ops.OP_TOALTSTACK), ] for public_key in self.public_keys: parts.extend([ pack_byte(Ops.OP_IF), pack_byte(Ops.OP_DUP), pack_byte(Ops.OP_HASH160), push_item(public_key.hash160()), pack_byte(Ops.OP_EQUALVERIFY), pack_byte(Ops.OP_CHECKSIGVERIFY), pack_byte(Ops.OP_FROMALTSTACK), pack_byte(Ops.OP_1ADD), pack_byte(Ops.OP_TOALTSTACK), pack_byte(Ops.OP_ENDIF), ]) parts.extend([ # Is this the right order? pack_byte(Ops.OP_FROMALTSTACK), push_int(self.threshold), pack_byte(Ops.OP_GREATERTHANOREQUAL), ]) return b''.join(parts)
def multisig_script(x_pubkeys: List[XPublicKey], threshold: int) -> bytes: '''Returns bytes. x_pubkeys is an array of XPulicKey objects or an array of PublicKey objects. ''' assert 1 <= threshold <= len(x_pubkeys) parts = [push_int(threshold)] parts.extend(push_item(x_pubkey.to_bytes()) for x_pubkey in x_pubkeys) parts.append(push_int(len(x_pubkeys))) parts.append(pack_byte(Ops.OP_CHECKMULTISIG)) return b''.join(parts)
def test_P2SH(self): script_hex = 'a9143e4501f9f212cb6813b3815edbc7013d6a3f0f1087' s = Script.from_hex(script_hex) sc = classify_output_script(s, Bitcoin) assert isinstance(sc, P2SH_Address) suffix = push_item(b'foobar') + pack_byte(OP_DROP) + pack_byte(OP_NOP) s2 = Script.from_hex(script_hex + suffix.hex()) sc2 = classify_output_script(s2, Bitcoin) assert s2 != s assert isinstance(sc2, P2SH_Address)
def test_P2PKH(self): script_hex = '76a914a6dbba870185ab6689f386a40522ae6cb5c7b61a88ac' s = Script.from_hex(script_hex) sc = classify_output_script(s, Bitcoin) assert isinstance(sc, P2PKH_Address) prefix = push_item(b'foobar') + pack_byte(OP_DROP) + pack_byte(OP_NOP) s2 = Script.from_hex(prefix.hex() + script_hex) sc2 = classify_output_script(s2, Bitcoin) assert s2 != s assert isinstance(sc2, P2PKH_Address)
def multisig_script(public_keys, threshold): '''public_keys should be sorted hex strings. P2MultiSig_Ouput is not used as they may be derivation rules and not valid public keys. ''' if sorted(public_keys) != public_keys: logger.warning('public keys are not sorted') assert 1 <= threshold <= len(public_keys) parts = [push_int(threshold)] parts.extend( push_item(bytes.fromhex(public_key)) for public_key in public_keys) parts.append(push_int(len(public_keys))) parts.append(pack_byte(Ops.OP_CHECKMULTISIG)) return b''.join(parts).hex()
def test_OP_RETURN(self): s = Script(pack_byte(OP_RETURN)) sc = classify_output_script(s, Bitcoin) assert isinstance(sc, OP_RETURN_Output) s = Script(pack_byte(OP_RETURN) + push_item(b'BitcoinSV')) sc = classify_output_script(s, Bitcoin) assert isinstance(sc, OP_RETURN_Output) # Truncated OP_RETURN script s = Script(pack_byte(OP_RETURN) + pack_byte(1)) sc = classify_output_script(s, Bitcoin) assert isinstance(sc, OP_RETURN_Output)
def test_to_script_bytes(self, threshold, count): output = P2MultiSig_Output(MS_PUBKEYS[:count], threshold) assert output.public_key_count() == count raw = output.to_script_bytes() assert isinstance(raw, bytes) assert raw == b''.join(( push_int(threshold), b''.join(push_item(public_key.to_bytes()) for public_key in MS_PUBKEYS[:count]), push_int(count), pack_byte(OP_CHECKMULTISIG), )) S = output.to_script() assert isinstance(S, Script) assert S == raw
def _test_op_return(self, old=False): prefix = b'' if old else pack_byte(OP_0) s = Script(prefix + pack_byte(OP_RETURN)) sc = classify_output_script(s, Bitcoin) assert isinstance(sc, OP_RETURN_Output) s = Script(prefix + pack_byte(OP_RETURN) + push_item(b'BitcoinSV')) sc = classify_output_script(s, Bitcoin) assert isinstance(sc, OP_RETURN_Output) # Truncated OP_RETURN script s = Script(prefix + pack_byte(OP_RETURN) + pack_byte(1)) sc = classify_output_script(s, Bitcoin) assert isinstance(sc, OP_RETURN_Output)
def _realize_script_sig(self, x_pubkeys: List[XPublicKey], signatures: List[bytes]) -> Script: if self.script_type == ScriptType.P2PK: return Script(push_item(signatures[0])) elif self.script_type == ScriptType.P2PKH: return Script( push_item(signatures[0]) + push_item(x_pubkeys[0].to_bytes())) elif self.script_type == ScriptType.MULTISIG_P2SH: parts = [pack_byte(Ops.OP_0)] parts.extend(push_item(signature) for signature in signatures) nested_script = multisig_script(x_pubkeys, self.threshold) parts.append(push_item(nested_script)) return Script(b''.join(parts)) elif self.script_type == ScriptType.MULTISIG_BARE: parts = [pack_byte(Ops.OP_0)] parts.extend(push_item(signature) for signature in signatures) return Script(b''.join(parts)) raise ValueError(f"unable to realize script {self.script_type}")