Ejemplo n.º 1
0
    def test_twin(self):
        # Normal twin
        params = ['--raw_tx', self.tx.get_struct().hex()]
        args = self.parser.parse_args(params)

        f = StringIO()
        with capture_logs():
            with redirect_stdout(f):
                execute(args)

        # Transforming prints str in array
        output = f.getvalue().strip().splitlines()

        twin_tx = Transaction.create_from_struct(bytes.fromhex(output[0]))
        # Parents are the same but in different order
        self.assertEqual(twin_tx.parents[0], self.tx.parents[1])
        self.assertEqual(twin_tx.parents[1], self.tx.parents[0])

        # Testing metadata creation from json
        meta_before_conflict = self.tx.get_metadata()
        meta_before_conflict_json = meta_before_conflict.to_json()
        del meta_before_conflict_json['conflict_with']
        del meta_before_conflict_json['voided_by']
        del meta_before_conflict_json['twins']
        new_meta = TransactionMetadata.create_from_json(meta_before_conflict_json)
        self.assertEqual(meta_before_conflict, new_meta)

        self.manager.propagate_tx(twin_tx)

        # Validate they are twins
        meta = self.tx.get_metadata(force_reload=True)
        self.assertEqual(meta.twins, [twin_tx.hash])

        meta2 = twin_tx.get_metadata()
        self.assertFalse(meta == meta2)
Ejemplo n.º 2
0
    def create_from_proto(
            cls,
            tx_proto: protos.BaseTransaction,
            storage: Optional['TransactionStorage'] = None) -> 'Transaction':
        transaction_proto = tx_proto.transaction
        tx = cls(
            version=transaction_proto.version,
            weight=transaction_proto.weight,
            timestamp=transaction_proto.timestamp,
            nonce=transaction_proto.nonce,
            hash=transaction_proto.hash or None,
            parents=list(transaction_proto.parents),
            tokens=list(transaction_proto.tokens),
            inputs=list(
                map(TxInput.create_from_proto, transaction_proto.inputs)),
            outputs=list(
                map(TxOutput.create_from_proto, transaction_proto.outputs)),
            storage=storage,
        )
        if transaction_proto.HasField('metadata'):
            from hathor.transaction import TransactionMetadata

            # make sure hash is not empty
            tx.hash = tx.hash or tx.calculate_hash()
            tx._metadata = TransactionMetadata.create_from_proto(
                tx.hash, transaction_proto.metadata)
        return tx
Ejemplo n.º 3
0
    def _load_from_bytes(self, tx_data: bytes,
                         meta_data: bytes) -> 'BaseTransaction':
        from hathor.transaction.base_transaction import tx_or_block_from_bytes
        from hathor.transaction.transaction_metadata import TransactionMetadata

        tx = tx_or_block_from_bytes(tx_data)
        tx._metadata = TransactionMetadata.create_from_json(
            json_loadb(meta_data))
        tx.storage = self
        return tx
Ejemplo n.º 4
0
 def create_from_proto(cls, tx_proto: protos.BaseTransaction,
                       storage: Optional['TransactionStorage'] = None) -> 'MergeMinedBlock':
     block_proto = tx_proto.block
     tx = cls(
         version=block_proto.version,
         weight=block_proto.weight,
         timestamp=block_proto.timestamp,
         hash=block_proto.hash or None,
         parents=list(block_proto.parents),
         outputs=list(map(TxOutput.create_from_proto, block_proto.outputs)),
         storage=storage,
         data=block_proto.data
     )
     tx.aux_pow = BitcoinAuxPow.create_from_proto(block_proto.aux_pow)
     if block_proto.HasField('metadata'):
         from hathor.transaction import TransactionMetadata
         # make sure hash is not empty
         tx.hash = tx.hash or tx.calculate_hash()
         tx._metadata = TransactionMetadata.create_from_proto(tx.hash, block_proto.metadata)
     return tx
Ejemplo n.º 5
0
    def generate_mining_block(
        self,
        rng: Random,
        merge_mined: bool = False,
        address: Optional[bytes] = None,
        timestamp: Optional[int] = None,
        data: Optional[bytes] = None,
        storage: Optional[TransactionStorage] = None,
        include_metadata: bool = False,
    ) -> Union[Block, MergeMinedBlock]:
        """ Generates a block by filling the template with the given options and random parents (if multiple choices).

        Note that if a timestamp is given it will be coerced into the [timestamp_min, timestamp_max] range.
        """
        # XXX: importing these here to try to contain hathor dependencies as much as possible
        from hathor.transaction import TransactionMetadata, TxOutput
        from hathor.transaction.scripts import create_output_script

        parents = list(self.get_random_parents(rng))
        output_script = create_output_script(
            address) if address is not None else b''
        base_timestamp = timestamp if timestamp is not None else self.timestamp_now
        block_timestamp = min(max(base_timestamp, self.timestamp_min),
                              self.timestamp_max)
        tx_outputs = [TxOutput(self.reward, output_script)]
        cls: Union[
            Type['Block'],
            Type['MergeMinedBlock']] = MergeMinedBlock if merge_mined else Block
        block = cls(outputs=tx_outputs,
                    parents=parents,
                    timestamp=block_timestamp,
                    data=data or b'',
                    storage=storage,
                    weight=self.weight)
        if include_metadata:
            block._metadata = TransactionMetadata(height=self.height,
                                                  score=self.score)
        block.get_metadata(use_storage=False)
        return block
Ejemplo n.º 6
0
def create_tx_from_dict(data: Dict[str, Any], update_hash: bool = False,
                        storage: Optional[TransactionStorage] = None) -> BaseTransaction:
    import base64

    from hathor.transaction.aux_pow import BitcoinAuxPow
    from hathor.transaction.base_transaction import TxInput, TxOutput, TxVersion

    hash_bytes = bytes.fromhex(data['hash']) if 'hash' in data else None
    if 'data' in data:
        data['data'] = base64.b64decode(data['data'])

    parents = []
    for parent in data['parents']:
        parents.append(bytes.fromhex(parent))
    data['parents'] = parents

    inputs = []
    for input_tx in data.get('inputs', []):
        tx_id = bytes.fromhex(input_tx['tx_id'])
        index = input_tx['index']
        input_data = base64.b64decode(input_tx['data'])
        inputs.append(TxInput(tx_id, index, input_data))
    if len(inputs) > 0:
        data['inputs'] = inputs
    else:
        data.pop('inputs', [])

    outputs = []
    for output in data['outputs']:
        value = output['value']
        script = base64.b64decode(output['script'])
        token_data = output['token_data']
        outputs.append(TxOutput(value, script, token_data))
    if len(outputs) > 0:
        data['outputs'] = outputs

    tokens = [bytes.fromhex(uid) for uid in data['tokens']]
    if len(tokens) > 0:
        data['tokens'] = tokens
    else:
        del data['tokens']

    if 'aux_pow' in data:
        data['aux_pow'] = BitcoinAuxPow.from_bytes(bytes.fromhex(data['aux_pow']))

    if storage:
        data['storage'] = storage

    cls = TxVersion(data['version']).get_cls()
    metadata = data.pop('metadata', None)
    tx = cls(**data)
    if update_hash:
        tx.update_hash()
        assert tx.hash is not None
    if hash_bytes:
        assert tx.hash == hash_bytes, f'Hashes differ: {tx.hash!r} != {hash_bytes!r}'
    if metadata:
        tx._metadata = TransactionMetadata.create_from_json(metadata)
        if tx._metadata.hash and hash_bytes:
            assert tx._metadata.hash == hash_bytes
    return tx
 def _get_new_tx(self, nonce):
     tx = Transaction(nonce=nonce, storage=self.cache_storage)
     tx.update_hash()
     meta = TransactionMetadata(hash=tx.hash)
     tx._metadata = meta
     return tx