예제 #1
0
def parse_header(header: str) -> Header:
    '''
    Parses a header to a dict
    Args:
        header (str): hex formatted 80 byte header
    Returns:
        dict:
            hash        (str): the header hash 0000-first
            version     (int): the block version as an int
            prev_block  (str): the previous block hash 0000-first
            merkle_root (str): the block transaction merkle tree root
            timestamp   (int): the block header timestamp
            nbits       (str): the difficulty bits
            nonce       (str): the nonce
            difficulty  (int): the difficulty as an int
            hex         (str): the full header as hex
            height      (int): the block height (always 0)
    '''
    if len(header) != 160:
        raise ValueError('Invalid header received')
    as_bytes = bytes.fromhex(header)
    nbits = as_bytes[72:76]
    return {
        'hash': rutils.hash256(bytes.fromhex(header))[::-1].hex(),
        'version': rutils.le2i(as_bytes[0:4]),
        'prev_block': as_bytes[4:36][::-1].hex(),
        'merkle_root': as_bytes[36:68].hex(),
        'timestamp': rutils.le2i(as_bytes[68:72]),
        'nbits': nbits.hex(),
        'nonce': as_bytes[76:80].hex(),
        'difficulty': parse_difficulty(nbits),
        'hex': header,
        'height': 0,
        'accumulated_work': 0
    }
예제 #2
0
파일: utils.py 프로젝트: summa-tx/swaps
def get_value_and_lock_time(tx: Tx) -> Tuple[int, int]:
    '''Parses the time lock and first output's value from a txn

    Args:
        tx (riemann.tx.Tx): the transaction
    Returns:
        (int, int): the value and locktime
    '''
    return (rutils.le2i(tx.tx_outs[0].value), rutils.le2i(tx.lock_time))
예제 #3
0
 def calculate_fee(self, input_values):
     '''
     Tx, list(int) -> int
     '''
     total_in = sum(input_values)
     total_out = sum([utils.le2i(tx_out.value) for tx_out in self.tx_outs])
     for js in self.tx_joinsplits:
         total_in += utils.le2i(js.vpub_new)
         total_out += utils.le2i(js.vpub_old)
     return total_in - total_out
예제 #4
0
 def calculate_fee(self, input_values):
     '''
     SaplingTx, list(int) -> int
     '''
     total_in = sum(input_values)
     total_out = sum([utils.le2i(tx_out.value) for tx_out in self.tx_outs])
     shileded_net = utils.le2i(self.value_balance, signed=True)
     for js in self.tx_joinsplits:
         total_in += utils.le2i(js.vpub_new)
         total_out += utils.le2i(js.vpub_old)
     return total_in - total_out + shileded_net
예제 #5
0
    def __init__(self,
                 vpub_old: bytes,
                 vpub_new: bytes,
                 anchor: bytes,
                 nullifiers: bytes,
                 commitments: bytes,
                 ephemeral_key: bytes,
                 random_seed: bytes,
                 vmacs: bytes,
                 zkproof: SproutZkproof,
                 encoded_notes: bytes):
        super().__init__()

        if not isinstance(zkproof, SproutZkproof):
            raise ValueError(
                'Invalid zkproof. '
                'Expected instance of SproutZkproof. Got {}'
                .format(type(zkproof).__name__))
        if (utils.le2i(vpub_old) != 0 and utils.le2i(vpub_new) != 0):
            raise ValueError('vpub_old or vpub_new must be zero')

        self.validate_bytes(vpub_old, 8)
        self.validate_bytes(vpub_new, 8)
        self.validate_bytes(anchor, 32)
        self.validate_bytes(nullifiers, 64)
        self.validate_bytes(commitments, 64)
        self.validate_bytes(ephemeral_key, 32)
        self.validate_bytes(random_seed, 32)
        self.validate_bytes(vmacs, 64)
        self.validate_bytes(encoded_notes, 1202)

        self += vpub_old
        self += vpub_new
        self += anchor
        self += nullifiers
        self += commitments
        self += ephemeral_key
        self += random_seed
        self += vmacs
        self += zkproof
        self += encoded_notes

        self.vpub_old = vpub_old
        self.vpub_new = vpub_new
        self.anchor = anchor
        self.nullifiers = nullifiers
        self.commitments = commitments
        self.ephemeral_key = ephemeral_key
        self.random_seed = random_seed
        self.vmacs = vmacs
        self.zkproof = zkproof
        self.encoded_notes = encoded_notes

        self._make_immutable()
예제 #6
0
    def from_bytes(VarInt, byte_string):
        '''
        byte-like -> VarInt
        accepts arbitrary length input, gets a VarInt off the front
        '''
        num = byte_string
        if num[0] <= 0xfc:
            num = num[0:1]
            non_compact = False
        elif num[0] == 0xfd:
            num = num[1:3]
            non_compact = (num[-1:] == b'\x00')
        elif num[0] == 0xfe:
            num = num[1:5]
            non_compact = (num[-2:] == b'\x00\x00')
        elif num[0] == 0xff:
            num = num[1:9]
            non_compact = (num[-4:] == b'\x00\x00\x00\x00')
        if len(num) not in [1, 2, 4, 8]:
            raise ValueError('Malformed VarInt. Got: {}'.format(
                byte_string.hex()))

        if (non_compact
                and ('overwinter' in riemann.get_current_network_name()
                     or 'sapling' in riemann.get_current_network_name())):
            raise ValueError('VarInt must be compact. Got: {}'.format(
                byte_string.hex()))

        ret = VarInt(utils.le2i(num),
                     length=len(num) + 1 if non_compact else 0)

        return ret
예제 #7
0
 def calculate_fee(self, input_values):
     '''
     Tx, list(int) -> int
     Inputs don't know their value without the whole chain.
     '''
     return \
         sum(input_values) \
         - sum([utils.le2i(o.value) for o in self.tx_outs])
예제 #8
0
def make_target(nbits: bytes) -> int:
    '''
    converts an nbits from a header into the target
    Args:
        nbits (bytes): the 4-byte nbits bytestring
    Returns:
        (int): the target threshold
    '''
    exponent = rutils.be2i(nbits[-1:]) - 3
    return math.floor(rutils.le2i(nbits[:-1]) * 0x100**(exponent))
예제 #9
0
def deserialize(serialized_script: bytes) -> str:
    '''deserialize a script from bytes to human-readable'''
    deserialized = []
    i = 0
    while i < len(serialized_script):
        current_byte = serialized_script[i]
        if current_byte == 0xab:
            raise NotImplementedError('OP_CODESEPARATOR is a bad idea.')
        if current_byte <= 75 and current_byte != 0:

            deserialized.append(serialized_script[i + 1:i + 1 +
                                                  current_byte].hex())

            i += 1 + current_byte
            if i > len(serialized_script):
                raise IndexError(
                    'Push {} caused out of bounds exception.'.format(
                        current_byte))

        elif current_byte == 76:
            # next hex blob length
            blob_len = serialized_script[i + 1]

            deserialized.append(serialized_script[i + 2:i + 2 +
                                                  blob_len].hex())

            i += 2 + blob_len

        elif current_byte == 77:
            # next hex blob length
            blob_len = utils.le2i(serialized_script[i + 1:i + 3])

            deserialized.append(serialized_script[i + 3:i + 3 +
                                                  blob_len].hex())

            i += 3 + blob_len

        elif current_byte == 78:
            raise NotImplementedError('OP_PUSHDATA4 is a bad idea.')

        else:
            if current_byte in riemann.network.INT_TO_CODE_OVERWRITE:
                deserialized.append(
                    riemann.network.INT_TO_CODE_OVERWRITE[current_byte])
            elif current_byte in INT_TO_CODE:
                deserialized.append(INT_TO_CODE[current_byte])
            else:
                raise ValueError('Unsupported opcode. '
                                 'Got 0x%x' % serialized_script[i])
            i += 1

    return ' '.join(deserialized)
예제 #10
0
파일: tx.py 프로젝트: summa-tx/riemann
    def calculate_fee(self, input_values: Sequence[int]) -> int:
        '''
        Calculate the fee associated with a transaction. Caller must provide a
        sequence representing the value (in satoshi) of each input.

        Args:
            input_values: The value of each input in order.
        Returns:
            The total fee paid to miners by this transaction.
        '''
        return \
            sum(input_values) \
            - sum([utils.le2i(o.value) for o in self.tx_outs])
예제 #11
0
    def from_bytes(SproutTx, byte_string):
        '''
        byte-like -> SproutTx
        '''
        version = byte_string[0:4]
        tx_ins = []
        tx_ins_num = shared.VarInt.from_bytes(byte_string[4:])

        current = 4 + len(tx_ins_num)
        for _ in range(tx_ins_num.number):
            tx_in = TxIn.from_bytes(byte_string[current:])
            current += len(tx_in)
            tx_ins.append(tx_in)

        tx_outs = []
        tx_outs_num = shared.VarInt.from_bytes(byte_string[current:])

        current += len(tx_outs_num)
        for _ in range(tx_outs_num.number):
            tx_out = TxOut.from_bytes(byte_string[current:])
            current += len(tx_out)
            tx_outs.append(tx_out)

        lock_time = byte_string[current:current + 4]
        current += 4

        tx_joinsplits = None
        joinsplit_pubkey = None
        joinsplit_sig = None
        if utils.le2i(version) == 2:  # If we expect joinsplits
            tx_joinsplits = []
            tx_joinsplits_num = shared.VarInt.from_bytes(byte_string[current:])
            current += len(tx_joinsplits_num)

            for _ in range(tx_joinsplits_num.number):
                joinsplit = z.SproutJoinsplit.from_bytes(byte_string[current:])
                current += len(joinsplit)
                tx_joinsplits.append(joinsplit)
            joinsplit_pubkey = byte_string[current:current + 32]
            current += 32
            joinsplit_sig = byte_string[current:current + 64]

        return SproutTx(version=version,
                        tx_ins=tx_ins,
                        tx_outs=tx_outs,
                        lock_time=lock_time,
                        tx_joinsplits=tx_joinsplits,
                        joinsplit_pubkey=joinsplit_pubkey,
                        joinsplit_sig=joinsplit_sig)
예제 #12
0
def check_final(t: tx.Tx,
                best_height: int = 0,
                best_timestamp: int = 0) -> bool:
    '''
    Checks absolute locktime of a transaction.
    Pass in the best height and timestamp
    Args:
        t               (tx.Tx): the transaction
        best_height     (int): best known Bitcoin height
        best_timestamp  (int): best known Bitcoin timestamp
    '''
    lock = rutils.le2i(t.lock_time)
    if lock >= 500_000_000:  # timelocked
        return lock <= best_timestamp
    else:  # height-locked
        return lock <= best_height
예제 #13
0
def is_op_return(o: tx.TxOut) -> bool:
    '''
    Checks whether a txout is standard TX_NULL_DATA op_return output
    Args:
        o (tx.TxOut): the output
    Returns:
        (bool): True if standard opreturn, otherwise false
    '''
    script: str = ser.deserialize(o.output_script)
    split_script = script.split()

    # TX_NULL_DATA, up to 83 bytes (80 for safety)
    if (rutils.le2i(o.value) == 0 and split_script[0] == 'OP_RETURN'
            and len(script) < 80):
        return True
    return False
예제 #14
0
def check_is_standard(t: tx.Tx) -> bool:
    '''
    Analog of Bitcoin's IsStandard
    Args:
        t (tx.Tx): the transaction to check
    Returns:
        (bool): True for standard, false for non-standard
    '''
    for o in t.tx_outs:
        # 'scriptpubkey'
        if not is_standard_output_type(o):
            return False

        # 'dust'
        if (rutils.le2i(o.value) < 550 and o.output_script[:2] != b'\x00\x14'):
            return False

    # 'multi-op-return'
    if len([is_op_return(o) for o in t.tx_outs]) > 1:
        return False

    return True
예제 #15
0
    def __init__(self, tx_ins, tx_outs, lock_time, expiry_height,
                 value_balance, tx_shielded_spends, tx_shielded_outputs,
                 tx_joinsplits, joinsplit_pubkey, joinsplit_sig, binding_sig):
        super().__init__()

        if 'sapling' not in riemann.get_current_network_name():
            raise ValueError(
                'SaplingTx not supported by network {}.'
                .format(riemann.get_current_network_name()))

        self.validate_bytes(lock_time, 4)
        self.validate_bytes(expiry_height, 4)
        self.validate_bytes(value_balance, 8)

        if utils.le2i(expiry_height) > 499999999:
            raise ValueError('Expiry time too high.'
                             'Expected <= 499999999. Got {}'
                             .format(utils.le2i(expiry_height)))

        if (len(tx_shielded_spends) + len(tx_shielded_outputs) == 0
                and value_balance != b'\x00' * 8):
            raise ValueError('If no shielded inputs or outputs, value balance '
                             'must be 8 0-bytes. Got {}'
                             .format(value_balance.hex()))
        elif binding_sig is not None:
            self.validate_bytes(binding_sig, 64)

        for tx_in in tx_ins:
            if not isinstance(tx_in, TxIn):
                raise ValueError(
                    'Invalid TxIn. '
                    'Expected instance of TxOut. Got {}'
                    .format(type(tx_in).__name__))

        for tx_out in tx_outs:
            if not isinstance(tx_out, TxOut):
                raise ValueError(
                    'Invalid TxOut. '
                    'Expected instance of TxOut. Got {}'
                    .format(type(tx_out).__name__))

        if len(tx_joinsplits) > 5:
            raise ValueError('Too many joinsplits. Stop that.')

        for shielded_spend in tx_shielded_spends:
            if not isinstance(shielded_spend, SaplingShieldedSpend):
                raise ValueError(
                    'Invalid shielded spend. '
                    'Expected instance of SaplingShieldedSpend. Got {}'
                    .format(type(shielded_spend).__name__))

        for shielded_output in tx_shielded_outputs:
            if not isinstance(shielded_output, SaplingShieldedOutput):
                raise ValueError(
                    'Invalid shielded output. '
                    'Expected instance of SaplingShieldedOutput. Got {}'
                    .format(type(shielded_output).__name__))

        for tx_joinsplit in tx_joinsplits:
            if not isinstance(tx_joinsplit, SaplingJoinsplit):
                raise ValueError(
                    'Invalid Joinsplit. '
                    'Expected instance of SaplingJoinsplit. Got {}'
                    .format(type(tx_joinsplit).__name__))

        if len(tx_joinsplits) != 0:
            self.validate_bytes(joinsplit_pubkey, 32)
            self.validate_bytes(joinsplit_sig, 64)

        if len(tx_joinsplits) + len(tx_ins) + len(tx_shielded_spends) == 0:
            raise ValueError('Transaction must have some input value.')

        self += b'\x04\x00\x00\x00'  # Sapling is always v4
        self += b'\x85\x20\x2f\x89'  # Sapling version group id
        self += shared.VarInt(len(tx_ins))
        for tx_in in tx_ins:
            self += tx_in
        self += shared.VarInt(len(tx_outs))
        for tx_out in tx_outs:
            self += tx_out
        self += lock_time
        self += expiry_height
        self += value_balance

        self += shared.VarInt(len(tx_shielded_spends))
        if len(tx_shielded_spends) != 0:
            for shielded_spend in tx_shielded_spends:
                self += shielded_spend

        self += shared.VarInt(len(tx_shielded_outputs))
        if len(tx_shielded_outputs) != 0:
            for shielded_output in tx_shielded_outputs:
                self += shielded_output

        self += shared.VarInt(len(tx_joinsplits))
        if len(tx_joinsplits) != 0:
            for tx_joinsplit in tx_joinsplits:
                self += tx_joinsplit
            self += joinsplit_pubkey
            self += joinsplit_sig

        if len(tx_shielded_outputs) + len(tx_shielded_spends) != 0:
            self += binding_sig
            self.binding_sig = binding_sig

        self.header = b'\x04\x00\x00\x80'  # Sapling is always v4
        self.group_id = b'\x85\x20\x2f\x89'  # Sapling version group id
        self.tx_ins = tuple(tx_in for tx_in in tx_ins)
        self.tx_outs = tuple(tx_out for tx_out in tx_outs)
        self.lock_time = lock_time
        self.expiry_height = expiry_height
        self.value_balance = value_balance

        if len(tx_shielded_spends) != 0:
            self.tx_shielded_spends = tuple(ss for ss in tx_shielded_spends)
        else:
            self.tx_shielded_spends = tuple()

        if len(tx_shielded_outputs) != 0:
            self.tx_shielded_outputs = tuple(so for so in tx_shielded_outputs)
        else:
            self.tx_shielded_outputs = tuple()

        if len(tx_joinsplits) != 0:
            self.tx_joinsplits = tuple(js for js in tx_joinsplits)
            self.joinsplit_pubkey = joinsplit_pubkey
            self.joinsplit_sig = joinsplit_sig
            # Zcash spec 5.4.1.4 Hsig hash function
            self.hsigs = (tuple(self._hsig(i)
                          for i in range(len(self.tx_joinsplits))))
            self.primary_inputs = (tuple(self._primary_input(i)
                                   for i in range(len(self.tx_joinsplits))))
        else:
            self.tx_joinsplits = tuple()
            self.joinsplit_pubkey = None
            self.joinsplit_sig = None
            self.hsigs = tuple()
            self.primary_inputs = tuple()

        if len(tx_shielded_outputs) + len(tx_shielded_spends) != 0:
            self.binding_sig = binding_sig
        else:
            self.binding_sig = None

        self.tx_id_le = self.tx_id_le = utils.hash256(self.to_bytes())
        self.tx_id = self.tx_id_le[::-1]

        self._make_immutable()

        if len(self) > 100000:
            raise ValueError(  # pragma: no cover
                'Tx is too large. '
                'Expect less than 100kB. Got: {} bytes'.format(len(self)))
예제 #16
0
import riemann
from riemann import tx

from riemann import utils

riemann.select_network('zcash_sapling_main')

tx_hex = 'YOUR_TX_HEX_HERE'

# Parse the transaction blob into an object
sapling_tx = tx.SaplingTx.from_hex(tx_hex)

# Interact with it easily
print(utils.le2i(sapling_tx.expiry_height))
print(sapling_tx.tx_shielded_outputs[0].enc_ciphertext.hex())
print(sapling_tx.tx_joinsplits[0].zkproof.pi_sub_c.hex())

# Change some part of it
new_tx = sapling_tx.copy(expiry_height=77)

print(new_tx.hex())

# Calculate the sighash
new_tx.sighash_all(
    joinsplit=False,  # True if you're signing a joinsplit
    script_code=b'\x19\x76\x00\x88\xac',  # the script code to sign
    anyone_can_pay=False,  # Anyone can pay can't be used with JSs
    prevout_value=b'\x00' * 8)  # little-endian 8 byte value in zatoshi
예제 #17
0
txns: List[tx.Tx] = []

# Loop through the txn_bytes, parsing txns off the front
# Riemann parsers all silently handle extra bytes.
# Each time we call from_bytes it returns a tx from the front of the bytearray
for i in range(num_txns.number):
    try:
        txns.append(tx.Tx.from_bytes(txn_bytes[offset:]))
        offset += len(txns[-1])
    except ValueError:
        print()
        print(f'Errored after {len(txns)} txns')
        print('please file an issue')
        print(txn_bytes[offset:].hex())
        break

# list the total output value of each tx
vals_out: List[int] = [
    sum(rutils.le2i(tx_out.value) for tx_out in t.tx_outs)
    for t in txns
]
num_outputs = sum(len(t.tx_outs) for t in txns)

# Calculate and output some basic stats
print()
print(f'block produced {num_outputs} new TXOs')
print(f'total output value of block is {as_btc(sum(vals_out))}')
print(f'mean output value is {as_btc(sum(vals_out) / num_outputs)}')
print(f'average tx output value is {as_btc(sum(vals_out) / len(vals_out))}')
print()
예제 #18
0
    def __init__(self, version, tx_ins, tx_outs, lock_time, tx_joinsplits,
                 joinsplit_pubkey, joinsplit_sig):

        super().__init__()

        if 'sprout' not in riemann.get_current_network_name():
            raise ValueError('SproutTx not supported by network {}.'.format(
                riemann.get_current_network_name()))

        self.validate_bytes(version, 4)
        self.validate_bytes(lock_time, 4)

        for tx_in in tx_ins:
            if not isinstance(tx_in, TxIn):
                raise ValueError('Invalid TxIn. '
                                 'Expected instance of TxOut. Got {}'.format(
                                     type(tx_in).__name__))

        for tx_out in tx_outs:
            if not isinstance(tx_out, TxOut):
                raise ValueError('Invalid TxOut. '
                                 'Expected instance of TxOut. Got {}'.format(
                                     type(tx_out).__name__))

        if utils.le2i(version) == 1:
            if tx_joinsplits is not None and len(tx_joinsplits) != 0:
                raise ValueError('Joinsplits not allowed in version 1 txns.')
            if tx_ins is None or len(tx_ins) == 0:
                raise ValueError('Version 1 txns must have at least 1 input.')

        if utils.le2i(version) == 2:
            if len(tx_joinsplits) > 5:
                raise ValueError('Too many joinsplits. Stop that.')
            for tx_joinsplit in tx_joinsplits:
                if not isinstance(tx_joinsplit, z.SproutJoinsplit):
                    raise ValueError(
                        'Invalid Joinsplit. '
                        'Expected instance of SproutJoinsplit. Got {}'.format(
                            type(tx_joinsplit).__name__))
            self.validate_bytes(joinsplit_pubkey, 32)
            if joinsplit_sig is not None and joinsplit_sig != b'':
                self.validate_bytes(joinsplit_sig, 64)

        if utils.le2i(version) not in [1, 2]:
            raise ValueError('Version must be 1 or 2. '
                             'Got: {}'.format(utils.le2i(version)))

        self += version
        self += shared.VarInt(len(tx_ins))
        for tx_in in tx_ins:
            self += tx_in
        self += shared.VarInt(len(tx_outs))
        for tx_out in tx_outs:
            self += tx_out
        self += lock_time

        if version == utils.i2le_padded(2, 4):
            self += shared.VarInt(len(tx_joinsplits))
            for tx_joinsplit in tx_joinsplits:
                self += tx_joinsplit
            self += joinsplit_pubkey
            self += joinsplit_sig

        self.version = version
        self.tx_ins = tuple(tx_in for tx_in in tx_ins)
        self.tx_outs = tuple(tx_out for tx_out in tx_outs)
        self.tx_joinsplits = tuple(js for js in tx_joinsplits)
        self.lock_time = lock_time

        if version == utils.i2le_padded(2, 4):
            self.joinsplit_pubkey = joinsplit_pubkey
            self.joinsplit_sig = joinsplit_sig
            # Zcash spec 5.4.1.4 Hsig hash function
            self.hsigs = (tuple(
                self._hsig(i) for i in range(len(self.tx_joinsplits))))
            self.primary_inputs = (tuple(
                self._primary_input(i)
                for i in range(len(self.tx_joinsplits))))
        else:
            self.joinsplit_pubkey = None
            self.joinsplit_sig = None
            self.hsigs = None
            self.primary_inputs = None

        self.tx_id_le = utils.hash256(self.to_bytes()).hex()
        self.tx_id = utils.hash256(self.to_bytes())[::-1].hex()

        self._make_immutable()

        if len(self) > 100000:
            raise ValueError(  # pragma: no cover
                'Tx is too large. '
                'Expect less than 100kB. Got: {} bytes'.format(len(self)))
예제 #19
0
    def __init__(self, tx_ins, tx_outs, lock_time, expiry_height,
                 tx_joinsplits, joinsplit_pubkey, joinsplit_sig):
        super().__init__()

        if 'overwinter' not in riemann.get_current_network_name():
            raise ValueError(
                'OverwinterTx not supported by network {}.'
                .format(riemann.get_current_network_name()))

        self.validate_bytes(lock_time, 4)
        self.validate_bytes(expiry_height, 4)

        if utils.le2i(expiry_height) > 499999999:
            raise ValueError('Expiry time too high.'
                             'Expected <= 499999999. Got {}'
                             .format(utils.le2i(expiry_height)))

        for tx_in in tx_ins:
            if not isinstance(tx_in, TxIn):
                raise ValueError(
                    'Invalid TxIn. '
                    'Expected instance of TxIn. Got {}'
                    .format(type(tx_in).__name__))

        for tx_out in tx_outs:
            if not isinstance(tx_out, TxOut):
                raise ValueError(
                    'Invalid TxOut. '
                    'Expected instance of TxOut. Got {}'
                    .format(type(tx_out).__name__))

        if len(tx_joinsplits) > 5:
            raise ValueError('Too many joinsplits. Stop that.')

        for tx_joinsplit in tx_joinsplits:
            if not isinstance(tx_joinsplit, z.SproutJoinsplit):
                raise ValueError(
                    'Invalid Joinsplit. '
                    'Expected instance of SproutJoinsplit. Got {}'
                    .format(type(tx_joinsplit).__name__))
        if len(tx_joinsplits) != 0:
            self.validate_bytes(joinsplit_pubkey, 32)
            self.validate_bytes(joinsplit_sig, 64)

        if len(tx_joinsplits) == 0 and len(tx_ins) == 0:
            raise ValueError('Transaction must have tx_ins or joinsplits.')

        self += b'\x03\x00\x00\x80'  # Version 3 + fOverwintered
        self += b'\x70\x82\xc4\x03'  # Overwinter Group ID
        self += shared.VarInt(len(tx_ins))
        for tx_in in tx_ins:
            self += tx_in
        self += shared.VarInt(len(tx_outs))
        for tx_out in tx_outs:
            self += tx_out
        self += lock_time
        self += expiry_height

        self += shared.VarInt(len(tx_joinsplits))
        if len(tx_joinsplits) != 0:
            for tx_joinsplit in tx_joinsplits:
                self += tx_joinsplit
            self += joinsplit_pubkey
            self += joinsplit_sig

        self.header = b'\x03\x00\x00\x80'
        self.group_id = b'\x70\x82\xc4\x03'
        self.version = b'\x03\x00'
        self.tx_ins = tuple(tx_in for tx_in in tx_ins)
        self.tx_outs = tuple(tx_out for tx_out in tx_outs)
        self.lock_time = lock_time
        self.expiry_height = expiry_height

        if len(tx_joinsplits) != 0:
            self.tx_joinsplits = tuple(js for js in tx_joinsplits)
            self.joinsplit_pubkey = joinsplit_pubkey
            self.joinsplit_sig = joinsplit_sig
            # Zcash spec 5.4.1.4 Hsig hash function
            self.hsigs = (tuple(self._hsig(i)
                          for i in range(len(self.tx_joinsplits))))
            self.primary_inputs = (tuple(self._primary_input(i)
                                   for i in range(len(self.tx_joinsplits))))
        else:
            self.tx_joinsplits = tuple()
            self.joinsplit_pubkey = None
            self.joinsplit_sig = None
            self.hsigs = tuple()
            self.primary_inputs = tuple()

        self.tx_id_le = self.tx_id_le = utils.hash256(self.to_bytes())
        self.tx_id = self.tx_id_le[::-1]

        self._make_immutable()

        if len(self) > 100000:
            raise ValueError(  # pragma: no cover
                'Tx is too large. '
                'Expect less than 100kB. Got: {} bytes'.format(len(self)))
예제 #20
0
def parse_nbits(nbits_hex):
    nbits_bytes = bytes.fromhex(nbits_hex)
    exponent = rutils.be2i(nbits_bytes[-1:])
    return rutils.le2i(nbits_bytes[:-1]) * 0xff**(exponent - 3)
예제 #21
0
 def calculate_fee(self):
     return \
         sum([utils.le2i(w.value) for w in self.tx_witnesses]) \
         - sum([utils.le2i(o.value) for o in self.tx_outs])