def create_memo_script(prefix, content): ''' prefix (int): action code content (list of str) ''' prefix_bytes = prefix.to_bytes(2, 'big') if prefix in (MEMO_SET_PROFILE_NAME, MEMO_POST, MEMO_SET_PROFILE_TEXT, MEMO_SET_PROFILE_PICTURE, MEMO_POST_IN_TOPIC, MEMO_FOLLOW_TOPIC, MEMO_UNFOLLOW_TOPIC): return (bytes([OP_RETURN]) + push_data(prefix_bytes) + bytes().join(push_data(d.encode('utf-8')) for d in content)) elif prefix in (MEMO_REPLY, MEMO_LIKE_AND_TIP, MEMO_ADD_POLL_OPTION, MEMO_VOTE_IN_POLL): return ( bytes([OP_RETURN]) + push_data(prefix_bytes) + push_data(bytes.fromhex(content[0])[::-1]) + bytes().join(push_data(d.encode('utf-8')) for d in content[1:])) elif prefix in (MEMO_FOLLOW_USER, MEMO_UNFOLLOW_USER, MEMO_SEND_MONEY): return ( bytes([OP_RETURN]) + push_data(prefix_bytes) + push_data(bytes.fromhex(content[0])) + bytes().join(push_data(d.encode('utf-8')) for d in content[1:])) elif prefix == MEMO_CREATE_POLL: poll_type = op_number(content[0]) option_count = op_number(content[1]) return ( bytes([OP_RETURN]) + push_data(prefix_bytes) + bytes([poll_type, option_count]) + bytes().join(push_data(d.encode('utf-8')) for d in content[2:])) else: raise NullDataError("cannot serialize memo script")
def p2sh_unlocking_script(addr, redeem_script, pubkeys, signatures, var_args=None): assert isinstance(addr, Address) assert addr.kind == Constants.CASH_P2SH assert isinstance(pubkeys[0], PublicKey) assert isinstance(signatures[0], (bytes, bytearray)) assert isinstance(redeem_script, (bytes, bytearray)) assert hash160(redeem_script) == addr.h # TODO: parse script if redeem_script[-1] == OP_CHECKMULTISIG: dummy = var_args[0] # Multisig output to unlock assert redeem_script == multisig_locking_script( pubkeys, len(signatures)) return (multisig_unlocking_script(signatures, dummy) + push_data(redeem_script)) elif (len(redeem_script) in [75, 76, 77, 78, 79, 80]) & ( redeem_script[-38] == OP_CHECKLOCKTIMEVERIFY): # Expiring tip choice = 'refund' print("expiring tip: {} !".format(choice)) return (expiring_tip_unlocking_script('refund', signatures[0]) + push_data(redeem_script)) else: raise ScriptError("cannot parse script")
def locking_script(addr): assert isinstance(addr, Address) if addr.kind == Constants.CASH_P2PKH: return (bytes([OP_DUP, OP_HASH160]) + push_data(addr.h) + bytes([OP_EQUALVERIFY, OP_CHECKSIG])) elif addr.kind == Constants.CASH_P2SH: return (bytes([OP_HASH160]) + push_data(addr.h) + bytes([OP_EQUAL])) return None
def expiring_tip_unlocking_script(choice, sig): assert isinstance(sig, (bytes, bytearray)) if choice == 'claim': return push_data(sig) + bytes([OP_1]) elif choice == 'refund': return push_data(sig) + bytes([OP_0]) else: raise ScriptError("wrong choice")
def multisig_unlocking_script(sigs, dummy=0): ''' Returns m-of-n multisig unlocking script. ''' m = len(sigs) if m > 3: raise ScriptError('Too many signatures ({:d})'.format(m)) dummyb = dummy.to_bytes((dummy.bit_length() + 7) // 8, 'big') return (push_data(dummyb) + b''.join(push_data(sig) for sig in sigs))
def expiring_tip_locking_script(locktime, claim_pubkey, refund_pubkey): assert (locktime < 0x100000000) assert isinstance(claim_pubkey, PublicKey) assert isinstance(refund_pubkey, PublicKey) assert (claim_pubkey.is_compressed() & refund_pubkey.is_compressed()), "public keys must be compressed" return (bytes([OP_IF]) + push_data(claim_pubkey.to_ser()) + bytes([OP_ELSE]) + push_data(script_number(locktime)) + bytes([OP_CHECKLOCKTIMEVERIFY, OP_DROP]) + push_data(refund_pubkey.to_ser()) + bytes([OP_ENDIF, OP_CHECKSIG]))
def nulldata_script(data): ''' Data (temporary: int, bytes and str) ''' script = bytes([OP_RETURN]) for d in data: if isinstance(d, int): script += push_data(script_number(d)) elif isinstance(d, bytes): script += push_data(d) elif isinstance(d, str): script += push_data(d.encode('utf-8')) else: NullDataError("cannot serialize nulldata script") return script
def multisig_locking_script(pubkeys, m): ''' Returns m-of-n multisig locking script (also called redeem script). ''' n = len(pubkeys) if not 1 <= m <= n <= 3: raise ScriptError('{:d}-of-{:d} multisig script not possible'.format( m, n)) OP_m = op_number(m) OP_n = op_number(n) serpubkeys = bytes().join(push_data(pubkey.to_ser()) for pubkey in pubkeys) return (bytes([OP_m]) + serpubkeys + bytes([OP_n, OP_CHECKMULTISIG]))
def nulldata_script(data): ''' Data (temporary: int, bytes and str) ''' for i, d in enumerate(data): if isinstance(d, Address): data[i] = d.h elif isinstance(d, PublicKey): data[i] = d.to_ser(strtype=False) script = bytes([OP_RETURN]) for d in data: if isinstance(d, int): script += push_data(script_number(d)) elif isinstance(d, bytes): script += push_data(d) elif isinstance(d, str): script += push_data(d.encode('utf-8')) else: ScriptError("cannot serialize nulldata script") return script
def p2pkh_unlocking_script(addr, pubkeys, signatures): assert isinstance(addr, Address) assert addr.kind == Constants.CASH_P2PKH assert isinstance(pubkeys[0], PublicKey) assert isinstance(signatures[0], (bytes, bytearray)) return (push_data(signatures[0]) + push_data(pubkeys[0].to_ser()))
def simple_sequence_locking_script(sequence): ''' Simple anyone-can-spend CHECKSEQUENCEVERIFY locking script. ''' assert not (sequence & Constants.SEQUENCE_LOCKTIME_DISABLE_FLAG) return (push_data(script_number(sequence)) + bytes([OP_CHECKSEQUENCEVERIFY, OP_DROP]))
def simple_locktime_locking_script(locktime): ''' Simple anyone-can-spend CHECKLOCKTIMEVERIFY locking script. ''' return (push_data(script_number(locktime)) + bytes([OP_CHECKLOCKTIMEVERIFY, OP_DROP]))
def simple_secret_locking_script(secret): if isinstance(secret, str): secret = secret.encode('utf-8') h = sha256(secret) return bytes([OP_SHA256]) + push_data(h) + bytes([OP_EQUAL])
prevout_txid = "cd7d2d5d6e4cc7c15d35f57273bfe7e361216fc9c3732e26941be468d5553452" prevout_index = 0 prevout_value = 100000 output_address = claim_address fee = 1000 txin = {} txin['address'] = contract_address txin['txid'] = prevout_txid txin['index'] = prevout_index txin['value'] = prevout_value txin['sequence'] = Constants.SEQUENCE_NUMBER txin['pubkeys'] = [] txin['nsigs'] = 0 txin['redeem_script'] = redeemScript txin['unlocking_script'] = anyone_can_spend_unlocking_script() + push_data( redeemScript) output_value = (prevout_value - fee) // 2 txout1 = {} txout1['address'] = output_address txout1['value'] = output_value txout1['type'] = 'p2pkh' # Another output in order to have a txsize > 100 bytes (rule from nov 15th) txout2 = {} txout2['address'] = output_address txout2['value'] = output_value txout2['type'] = 'p2pkh' tx = Transaction(1, [txin], [txout1, txout2], locktime)
def segwit_locking_script(witver, witprog): return bytes([witver]) + push_data(witprog)
def simple_secret_unlocking_script(secret): if isinstance(secret, str): secret = secret.encode('utf-8') return push_data(secret)
def multisig_unlocking_script(sigs): ''' Returns m-of-n multisig unlocking script. ''' return (bytes([OP_0]) + b''.join(push_data(sig) for sig in sigs))