예제 #1
0
def increment_counter(counter_obj, prev_txid, prev_out_idx, funding_txid,
                      funding_out_idx, unlock_key_priv, miner_fee):
    # Get data from previous counter tx
    r = requests.get('https://api.whatsonchain.com/v1/bsv/main/tx/{}'.format(
        prev_txid)).json()
    prev_locking_script = Script.from_hex(
        r['vout'][prev_out_idx]['scriptPubKey']['hex'])
    prev_counter_bytes = list(prev_locking_script.ops())[-1]
    prev_counter_val = int.from_bytes(prev_counter_bytes, 'little')
    unlocked_satoshis_counter = int(r['vout'][prev_out_idx]['value'] * 10**8)

    # Get data from funding tx
    r = requests.get('https://api.whatsonchain.com/v1/bsv/main/tx/{}'.format(
        funding_txid)).json()
    funding_locking_script = Script.from_hex(
        r['vout'][funding_out_idx]['scriptPubKey']['hex'])
    unlocked_satoshis_funding = int(r['vout'][funding_out_idx]['value'] *
                                    10**8)

    # Set data for next iteration
    counter_obj.set_data_part(
        scryptlib.utils.get_push_int(prev_counter_val + 1))

    ## Construct tx
    n_sequence = 0xffffffff

    # Counter input and output
    prev_tx_hash = hex_str_to_hash(prev_txid)
    counter_in = TxInput(prev_tx_hash, prev_out_idx, None, n_sequence)
    out_satoshis = unlocked_satoshis_counter + unlocked_satoshis_funding - miner_fee
    contract_out = TxOutput(out_satoshis, counter_obj.locking_script)

    # Funding input
    funding_tx_hash = hex_str_to_hash(funding_txid)
    funding_in = TxInput(funding_tx_hash, funding_out_idx, None, n_sequence)

    tx = Tx(2, [counter_in, funding_in], [contract_out], 0x00000000)

    # Set input script to unlock previous counter
    sighash_flag = SigHash(SigHash.ALL | SigHash.FORKID)
    preimage = scryptlib.utils.get_preimage(tx, 0, unlocked_satoshis_counter,
                                            prev_locking_script, sighash_flag)
    increment_func_call = counter_obj.increment(SigHashPreimage(preimage),
                                                Int(out_satoshis))
    tx.inputs[0].script_sig = increment_func_call.script

    # Set input script to unlock funding output
    unlock_key_pub = unlock_key_priv.public_key
    sighash = tx.signature_hash(1, unlocked_satoshis_funding,
                                funding_locking_script, sighash_flag)
    sig = unlock_key_priv.sign(sighash, hasher=None)
    sig = sig + pack_byte(sighash_flag)
    unlock_script = Script() << sig << unlock_key_pub.to_bytes()
    tx.inputs[1].script_sig = unlock_script

    broadcast_tx(tx)
예제 #2
0
    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)
예제 #3
0
    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)
예제 #4
0
    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)
예제 #5
0
    def test_P2MultiSig(self):
        script_hex = ('5221022812701688bc76ef3610b46c8e97f4b385241d5ed6eab6269b8af5f9bfd5a89c210'
                      '3fa0879c543ac97f34daffdaeed808f3500811aa5070e4a1f7e2daed3dd22ef2052ae')
        s = Script.from_hex(script_hex)
        sc = classify_output_script(s, Bitcoin)
        assert isinstance(sc, P2MultiSig_Output)
        assert len(sc.public_keys) == 2
        assert sc.threshold == 2

        # Confirm suffix fails to match
        s = Script.from_hex(script_hex + 'a0')
        assert isinstance(classify_output_script(s, Bitcoin), Unknown_Output)
        # Confirm prefix fails to match
        s = Script.from_hex('a0' + script_hex)
        assert isinstance(classify_output_script(s, Bitcoin), Unknown_Output)
예제 #6
0
    def test_unknown(self):
        # Modified final pubkey byte; not a curve point
        script_hex = '210363f75554e05e05a04551e59d78d78965ec6789f42199f7cbaa9fa4bd2df0a4b3ac'
        s = Script.from_hex(script_hex)
        sc = classify_output_script(s, Bitcoin)
        assert isinstance(sc, Unknown_Output)

        # Truncated script
        script_hex = '210363f7'
        s = Script.from_hex(script_hex)
        sc = classify_output_script(s, Bitcoin)
        assert isinstance(sc, Unknown_Output)

        # Unknown script
        script_hex = pack_byte(OP_1).hex()
        s = Script.from_hex(script_hex)
        sc = classify_output_script(s, Bitcoin)
        assert isinstance(sc, Unknown_Output)
예제 #7
0
    def hex(self):
        self.bind()

        res_buff = []
        flat_struct = utils.flatten_struct(self, '')
        for elem in flat_struct:
            res_buff.append(elem['value'].hex)

        return Script.from_hex(''.join(res_buff)).to_hex()
예제 #8
0
    def from_dict(cls, data: dict) -> 'Output':
        if 'script' not in data:
            raise Bip270Exception("Missing required 'script' field")
        script_hex = data['script']

        amount = data.get('amount')
        if amount is not None and type(amount) is not int:
            raise Bip270Exception("Invalid 'amount' field")

        description = data.get('description')
        if description is not None and type(description) is not str:
            raise Bip270Exception("Invalid 'description' field")

        return cls(Script.from_hex(script_hex), amount, description)
예제 #9
0
 def encode_pub_function_call(self, contract, name, *args):
     for entity in self.abi:
         if entity['name'] == name:
             if len(entity['params']) != len(args):
                 raise Exception('Wrong number of arguments passed to function call "{}", ' \
                         'expected {}, but got {}.'.format(name, len(entity['params']), len(args)))
             hex_script = self.encode_params(args, entity['params'])
             if len(self.abi) > 2 and 'index' in entity:
                 pub_func_index = entity['index']
                 hex_script += '{}'.format(
                     types.Int(pub_func_index).hex)  # TODO
             unlocking_script = Script.from_hex(hex_script)
             return FunctionCall(name,
                                 args,
                                 contract,
                                 unlocking_script=unlocking_script)
예제 #10
0
def initialize_counter(counter_obj, counter_initial_val, funding_txid, funding_out_idx, \
        unlock_key_priv, miner_fee, contract_out_sats, change_addr):
    counter_obj.set_data_part(
        scryptlib.utils.get_push_int(counter_initial_val))

    # Funding TX
    funding_tx_hash = hex_str_to_hash(funding_txid)
    unlock_key_pub = unlock_key_priv.public_key

    r = requests.get('https://api.whatsonchain.com/v1/bsv/main/tx/{}'.format(
        funding_txid)).json()
    funding_locking_script = Script.from_hex(
        r['vout'][funding_out_idx]['scriptPubKey']['hex'])
    unlocked_satoshis = int(r['vout'][funding_out_idx]['value'] * 10**8)
    n_sequence = 0xffffffff
    tx_input = TxInput(funding_tx_hash, funding_out_idx, None, n_sequence)

    # Output with counter script code
    contract_out = TxOutput(contract_out_sats, counter_obj.locking_script)

    # Change output
    tx_output_script = P2PKH_Address.from_string(change_addr,
                                                 Bitcoin).to_script()
    change_out = TxOutput(unlocked_satoshis - miner_fee - contract_out_sats,
                          tx_output_script)

    tx = Tx(2, [tx_input], [contract_out, change_out], 0x00000000)

    # Create signature for input
    sighash_flag = SigHash(SigHash.ALL | SigHash.FORKID)
    sighash = tx.signature_hash(0, unlocked_satoshis, funding_locking_script,
                                sighash_flag)
    sig = unlock_key_priv.sign(sighash, hasher=None)
    sig = sig + pack_byte(sighash_flag)

    # Set script for input
    unlock_script = Script() << sig << unlock_key_pub.to_bytes()
    tx.inputs[0].script_sig = unlock_script

    broadcast_tx(tx)
예제 #11
0
    "2df53273de1b740e6f566eba00d90366e53afd2c6af896a9488515f8ef5abbd8": [],
    # 5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ (P2PK)
    "7149d82068249701104cd662bfe8ebc0af131ce6e781b124cc6297f45f7f6de5": [
        {
            "height": 50000,
            "value": 1804376,
            "tx_hash":
            "3f5a1badfe1beb42b650f325b20935f09f3ab43a3c473c5be18f58308fc7eff1",
            "tx_pos": 3,
        },
    ],
}

result_S = ([
    UTXO(value=45318048,
         script_pubkey=Script.from_hex(
             '76a914cb3e86e38ce37d5add87d3da753adc04a04bf60c88ac'),
         tx_hash=
         '9f2c45a12db0144909b5db269415f7319179105982ac70ed80d76ea79d923ebf',
         out_index=0,
         height=437146,
         address=address_from_string('1KXf5PUHNaV42jE9NbJFPKhGGN1fSSGJNK'),
         is_coinbase=False)
], {
    XPublicKey('04e7dd15b4271f8308ff52ad3d3e472b652e78a2c5bc6ed10250a543d28c0128894ae863d086488e6773c4589be93a1793f685dd3f1e8a1f1b390b23470f7d1095'):
    (b'\x98\xe3\x15\xc3%j\x97\x17\xd4\xdd\xea0\xeb*\n-V\xa1d\x93yN\xb0SSf\xea"\xd8i\xa3 ',
     False),
    XPublicKey('03e7dd15b4271f8308ff52ad3d3e472b652e78a2c5bc6ed10250a543d28c012889'):
    (b'\x98\xe3\x15\xc3%j\x97\x17\xd4\xdd\xea0\xeb*\n-V\xa1d\x93yN\xb0SSf\xea"\xd8i\xa3 ',
     True),
    XPublicKey('fd76a914cb3e86e38ce37d5add87d3da753adc04a04bf60c88ac'):
    (b'\x98\xe3\x15\xc3%j\x97\x17\xd4\xdd\xea0\xeb*\n-V\xa1d\x93yN\xb0SSf\xea"\xd8i\xa3 ',
예제 #12
0
prev_txid = 'c1543650beafbf646e75aeeae9b091e4c477362db4a18e740d3f9d2ae250c013'
miner_fee = 120
contract = '../test/res/p2pkh.scrypt'

compiler_result = scryptlib.utils.compile_contract(contract)
desc = compiler_result.to_desc()

P2PKH = scryptlib.contract.build_contract_class(desc)
p2pkh_obj = P2PKH(Ripemd160(addr_dest))

prev_tx_hash = hex_str_to_hash(prev_txid)
prev_out_idx = 0

r = requests.get(
    'https://api.whatsonchain.com/v1/bsv/main/tx/{}'.format(prev_txid)).json()
prev_locking_script = Script.from_hex(
    r['vout'][prev_out_idx]['scriptPubKey']['hex'])
unlocked_satoshis = int(r['vout'][prev_out_idx]['value'] * 10**8)
out_satoshis = unlocked_satoshis - miner_fee
n_sequence = 0xffffffff

tx_input = TxInput(prev_tx_hash, prev_out_idx, None, n_sequence)
tx_output = TxOutput(out_satoshis, p2pkh_obj.locking_script)

tx = Tx(2, [tx_input], [tx_output], 0x00000000)

sighash_flag = SigHash(SigHash.ALL | SigHash.FORKID)
sighash = tx.signature_hash(0, unlocked_satoshis, prev_locking_script,
                            sighash_flag)
sig = unlock_key_priv.sign(sighash, hasher=None)
sig = sig + pack_byte(sighash_flag)
예제 #13
0
def _script_to_address(script_hex):
    result = classify_output_script(Script.from_hex(script_hex))
    assert isinstance(result, Address)
    return result
예제 #14
0
    def get_ls_code_part(self, contract, hex_script, *args):
        abi_constructor = self.abi_constructor()
        c_params = abi_constructor.get('params', [])

        if len(args) != len(c_params):
            raise Exception('Wrong number of arguments passed to constructor. ' \
                    'Expected {}, but got {}.'.format(len(c_params), len(args)))

        _c_params = []
        _args = []
        for idx, param in enumerate(c_params):
            arg = args[idx]
            arg = utils.primitives_to_scrypt_types(arg)
            resolved_type = utils.resolve_type(param['type'], self.aliases)
            is_param_statefull = param['state']
            if utils.is_array_type(resolved_type):
                elem_type, array_sizes = utils.factorize_array_type_str(
                    resolved_type)

                if not utils.check_array(arg, elem_type, array_sizes):
                    raise Exception(
                        'Constructors parameter with index {} should be array of type "{}".'
                        .format(idx, resolved_type))
                flattened_arr = utils.flatten_array(arg, param['name'],
                                                    resolved_type)
                for obj in flattened_arr:
                    _c_params.append({
                        'name': obj['name'],
                        'type': obj['type'],
                        'state': is_param_statefull
                    })
                    _args.append(obj['value'])
            elif utils.is_struct_type(resolved_type):
                if arg.final_type != resolved_type:
                    raise Exception('Constructors parameter with index {} should be struct of type "{}". ' \
                            'Got struct of type "{}" instead.'.format(idx, param['type'], arg.type_str))

                flattened_struct = utils.flatten_struct(arg, param['name'])
                for obj in flattened_struct:
                    _c_params.append({
                        'name': obj['name'],
                        'type': obj['type'],
                        'state': is_param_statefull
                    })
                    _args.append(obj['value'])
            else:
                _c_params.append(param)
                _args.append(arg)

            if is_param_statefull:
                # If a statefull variable, set the passed value as a member of the contract object.
                setattr(contract, param['name'], arg)

        finalized_hex_script = hex_script
        for idx, param in enumerate(_c_params):
            if not '<{}>'.format(param['name']) in hex_script:
                raise Exception(
                    'Missing "{}" contract constructor parameter in passed args.'
                    .format(param['name']))
            param_regex = re.compile(
                escape_str_for_regex('<{}>'.format(param['name'])))
            if param['state']:
                # State variables need only a placeholder value as they will get replaced during script execution.
                #finalized_hex_script = re.sub(param_regex, '0100', finalized_hex_script)
                finalized_hex_script = re.sub(
                    param_regex, self.encode_param(_args[idx], param),
                    finalized_hex_script)
            else:
                finalized_hex_script = re.sub(
                    param_regex, self.encode_param(_args[idx], param),
                    finalized_hex_script)

        finalized_hex_script = re.sub('<__codePart__>', '00',
                                      finalized_hex_script)

        # Replace inline assembly variable placeholders in locking script with the actual arguments.
        # TODO: Check if each value is instance of ScryptType
        if contract.inline_asm_vars:
            for key, val in contract.inline_asm_vars.items():
                param_regex = re.compile(
                    escape_str_for_regex('<{}>'.format(key)))
                finalized_hex_script = re.sub(param_regex, val.hex,
                                              finalized_hex_script)

        return Script.from_hex(finalized_hex_script)
예제 #15
0
    def get_ls_data_part(self,
                         contract,
                         custom_vals_dict=None,
                         first_call=None):
        abi_constructor = self.abi_constructor()
        c_params = abi_constructor.get('params', [])

        state_buff = []

        first_call = first_call if first_call is not None else contract.first_call
        if first_call:
            state_buff.append('01')
        else:
            state_buff.append('00')

        for param in c_params:
            if not param['state']:
                continue

            param_name = param['name']
            resolved_type = utils.resolve_type(param['type'], self.aliases)

            if custom_vals_dict:
                val = custom_vals_dict[param_name]
            else:
                val = getattr(contract, param_name, None)
                if not val:
                    raise Exception(
                        'Statefull variable "{}" has no value.'.format(
                            param_name))

            val = utils.primitives_to_scrypt_types(val)

            # Do type checking.
            if utils.is_array_type(resolved_type):
                elem_type, array_sizes = utils.factorize_array_type_str(
                    resolved_type)
                if not utils.check_array(val, elem_type, array_sizes):
                    raise Exception(
                        'Statefull variable "{}" should be array of type "{}".'
                        .format(param_name, resolved_type))
            elif utils.is_struct_type(resolved_type):
                if val.final_type != resolved_type:
                    raise Exception('Statefull variable "{}" should be struct of type "{}". ' \
                            'Got struct of type "{}" instead.'.format(param_name, param['type'], val.type_str))
            else:
                if val.final_type != resolved_type:
                    raise Exception('Statefull variable "{}" should be of type "{}". ' \
                            'Got object of type "{}" instead.'.format(param_name, param['type'], val.type_str))

            state_buff.append(serializer.serialize(val).hex())

        # State length and state version.
        state_len = 0
        for elem in state_buff:
            state_len += len(elem) // 2
        if state_len > 0:
            size_bytes = state_len.to_bytes(4, 'little')
            state_buff.append(size_bytes.hex())
            state_buff.append(
                CONTRACT_STATE_VERSION.to_bytes(1, 'little').hex())

        return Script.from_hex(''.join(state_buff))