예제 #1
0
    def _structure_to_kwargs(cls, structure):
        """ Prepare decoded structure data to instance kwargs. """

        kwargs = super()._structure_to_kwargs(structure)

        # Convert data values to verbose.
        # Data will be passed as additional kwarg
        kwargs['data'].update({
            'address':
            MinterHelper.prefix_add(kwargs['data']['address'].hex(),
                                    PREFIX_ADDR),
            'pub_key':
            MinterHelper.prefix_add(kwargs['data']['pub_key'].hex(),
                                    PREFIX_PUBKEY),
            'commission':
            int.from_bytes(kwargs['data']['commission'], 'big'),
            'coin':
            kwargs['data']['coin'],
            'stake':
            MinterHelper.to_bip(int.from_bytes(kwargs['data']['stake'], 'big'))
        })

        # Populate data key values as kwargs
        kwargs.update(kwargs['data'])

        return kwargs
예제 #2
0
    def get_address_from_public_key(cls, public_key):
        """
        Args:
            public_key (str)
        Returns:
            str
        """
        # Create keccak hash
        _keccak = MinterHelper.keccak_hash(
            bytes.fromhex(MinterHelper.prefix_remove(public_key)))

        return MinterHelper.prefix_add(_keccak[-40:], PREFIX_ADDR)
예제 #3
0
    def get_public_from_private(cls, private_key):
        """
        Get public key from private key
        Args:
            private_key (str): hex bytes of private key
        Returns:
            str
        """
        # Get public key from private
        public_key = cls.curve.private_to_public(
            int(private_key, 16).to_bytes(length=32, byteorder='big'))
        public_key = public_key.hex()[2:]

        return MinterHelper.prefix_add(public_key, PREFIX_PUBKEY)
예제 #4
0
    def _structure_to_kwargs(cls, structure):
        """ Prepare decoded structure data to instance kwargs. """

        kwargs = super()._structure_to_kwargs(structure)

        # Convert data values to verbose.
        # Data will be passed as additional kwarg
        kwargs['data'].update({
            'pub_key':
            MinterHelper.prefix_add(kwargs['data']['pub_key'].hex(),
                                    PREFIX_PUBKEY),
            'reward_address':
            MinterHelper.prefix_add(kwargs['data']['reward_address'].hex(),
                                    PREFIX_ADDR),
            'owner_address':
            MinterHelper.prefix_add(kwargs['data']['owner_address'].hex(),
                                    PREFIX_ADDR)
        })

        # Populate data key values as kwargs
        kwargs.update(kwargs['data'])

        return kwargs
예제 #5
0
    def get_hash(self):
        """
        Generate tx hash with prefix
        Returns:
            string
        """
        if not hasattr(self, 'signed_tx') or not self.signed_tx:
            raise AttributeError('You need to sign transaction before')

        # Create SHA256
        sha = hashlib.sha256()
        sha.update(bytes.fromhex(self.signed_tx))

        # Return first 64 symbols with prefix
        return MinterHelper.prefix_add(sha.hexdigest()[:64], PREFIX_TX)
예제 #6
0
    def sign(self, private_key):
        """
        Sign check
        Args:
            private_key (str)
        """
        # Prepare structure
        # It contains nonce, chain_id, due_block, coin, value, gas_coin,
        # lock, v, r, s.
        # lock, v, r, s appended later in code
        structure = [
            int(str(self.nonce).encode().hex(), 16), self.chain_id,
            self.due_block,
            MinterHelper.encode_coin_name(self.coin),
            MinterHelper.to_pip(self.value),
            MinterHelper.encode_coin_name(self.gas_coin)
        ]

        # Create msg hash
        msg_hash = self.__hash(structure)

        # SHA256 from passphrase
        sha = hashlib.sha256()
        sha.update(self.passphrase.encode())
        passphrase = sha.hexdigest()

        # Create lock from signature
        self.lock = self.__lockfromsignature(
            signature=ECDSA.sign(message=msg_hash, private_key=passphrase))

        # Re-create msg hash with adding lock to structure
        structure.append(self.lock)
        msg_hash = self.__hash(structure)

        # Re-create signature, add it to check attrs and to structure
        signature = ECDSA.sign(message=msg_hash, private_key=private_key)
        self.signature = {
            'v': signature[0],
            'r': format(signature[1], 'x'),
            's': format(signature[2], 'x')
        }
        structure += signature

        # Get RLP, which will be the check
        check = rlp.encode(structure).hex()

        return MinterHelper.prefix_add(check, PREFIX_CHECK)
예제 #7
0
    def from_raw(cls, rawcheck):
        """
        Create check instance from raw check
        Args:
            rawcheck (str)
        Returns:
            MinterCheck
        """

        # Remove check prefix and RLP decode it
        rawcheck = MinterHelper.prefix_remove(rawcheck)
        rawcheck = bytes.fromhex(rawcheck)
        decoded = rlp.decode(rawcheck)

        # Create MinterCheck instance
        kwargs = {
            'nonce': int(decoded[0].decode()),
            'chain_id': int.from_bytes(decoded[1], 'big'),
            'due_block': int.from_bytes(decoded[2], 'big'),
            'coin': MinterHelper.decode_coin_name(decoded[3]),
            'value': MinterHelper.to_bip(int.from_bytes(decoded[4], 'big')),
            'gas_coin': MinterHelper.decode_coin_name(decoded[5]),
            'lock': decoded[6].hex(),
            'signature': {
                'v': int.from_bytes(decoded[7], 'big'),
                'r': decoded[8].hex(),
                's': decoded[9].hex()
            }
        }
        check = MinterCheck(**kwargs)

        # Recover owner address
        msg_hash = cls.__hash(data=[
            int(str(check.nonce).encode().hex(), 16), check.chain_id,
            check.due_block,
            MinterHelper.encode_coin_name(check.coin),
            MinterHelper.to_pip(check.value),
            MinterHelper.encode_coin_name(check.gas_coin),
            bytes.fromhex(check.lock)
        ])
        public_key = ECDSA.recover(msg_hash, tuple(check.signature.values()))
        public_key = MinterHelper.prefix_add(public_key, PREFIX_PUBKEY)

        check.owner = MinterWallet.get_address_from_public_key(public_key)

        return check
예제 #8
0
    def _structure_to_kwargs(cls, structure):
        """ Prepare decoded structure data to instance kwargs. """

        kwargs = super()._structure_to_kwargs(structure)

        # Convert data values to verbose.
        # Data will be passed as additional kwarg
        for index, item in enumerate(kwargs['data']['txs']):
            kwargs['data']['txs'][index] = {
                'coin': item[0],
                'to': MinterHelper.prefix_add(item[1].hex(), PREFIX_ADDR),
                'value': MinterHelper.to_bip(int.from_bytes(item[2], 'big'))
            }

        # Populate data key values as kwargs
        kwargs.update(kwargs['data'])

        return kwargs
예제 #9
0
    def _structure_to_kwargs(cls, structure):
        """ Prepare decoded structure data to instance kwargs. """

        kwargs = super()._structure_to_kwargs(structure)

        # Convert data values to verbose.
        # Data will be passed as additional kwarg
        kwargs['data'].update({
            'check':
            MinterHelper.prefix_add(kwargs['data']['check'].hex(),
                                    PREFIX_CHECK),
            'proof':
            kwargs['data']['proof'].hex()
        })

        # Populate data key values as kwargs
        kwargs.update(kwargs['data'])

        return kwargs
예제 #10
0
    def _structure_to_kwargs(cls, structure):
        """ Prepare decoded structure data to instance kwargs. """

        kwargs = super()._structure_to_kwargs(structure)

        # Convert data values to verbose.
        # Data will be passed as additional kwarg
        kwargs['data'].update({
            'coin':
            MinterHelper.decode_coin_name(kwargs['data']['coin']),
            'to':
            MinterHelper.prefix_add(kwargs['data']['to'].hex(), PREFIX_ADDR),
            'value':
            MinterHelper.to_bip(int.from_bytes(kwargs['data']['value'], 'big'))
        })

        # Populate data key values as kwargs
        kwargs.update(kwargs['data'])

        return kwargs
예제 #11
0
    def _structure_to_kwargs(cls, structure):
        """ Prepare decoded structure data to instance kwargs. """
        kwargs = super()._structure_to_kwargs(structure)

        # Convert data values to verbose.
        # Data will be passed as additional kwarg
        kwargs['data'].update({
            'threshold':
            int.from_bytes(kwargs['data']['threshold'], 'big'),
            'weights':
            [int.from_bytes(w, 'big') for w in kwargs['data']['weights']],
            'addresses': [
                MinterHelper.prefix_add(address.hex(), PREFIX_ADDR)
                for address in kwargs['data']['addresses']
            ]
        })

        # Populate data key values as kwargs
        kwargs.update(kwargs['data'])

        return kwargs
예제 #12
0
    def get_sender_address(cls, tx):
        """
        Get sender address from tx.
        Recover public key from tx and then get address from public key,
        if tx has single signature type, or get decoded sender address,
        if tx has multi signature type.
        Args:
            tx (dict): transaction dict
        Returns:
            Minter address (string)
        """

        # Remember signature data and remove it from tx
        signature_data = tx.pop('signature_data')

        # If there is sender address in signature data (multi signature tx),
        # return it
        if signature_data.get('from_mx'):
            return signature_data['from_mx']

        # Otherwise (single signature tx), recover public key and get
        # address from public key
        # Unhexlify hexdigit dict values to bytes
        tx = MinterHelper.hex2bin_recursive(tx)

        # Encode tx data to RLP
        tx['data'] = rlp.encode(list(tx['data'].values()))

        # Message
        tx_rlp = rlp.encode(list(tx.values()))
        _keccak = MinterHelper.keccak_hash(tx_rlp)

        # Recover public key
        public_key = MinterHelper.prefix_add(
            ECDSA.recover(_keccak, tuple(signature_data.values())),
            PREFIX_PUBKEY)

        return MinterWallet.get_address_from_public_key(public_key)
예제 #13
0
    def from_raw(cls, raw_tx):
        """
        Generate tx object from raw tx
        Args:
            raw_tx (string)
        Returns:
            MinterTx child instance
        """

        tx = rlp.decode(bytes.fromhex(raw_tx))

        # Try to decode payload
        try:
            payload = tx[6].decode()
        except UnicodeDecodeError:
            payload = tx[6]

        # Try to decode service data
        try:
            service_data = tx[7].decode()
        except UnicodeDecodeError:
            service_data = tx[7]

        # Populate structure dict with decoded tx data
        struct = copy.copy(cls._STRUCTURE_DICT)
        struct.update({
            'nonce': int.from_bytes(tx[0], 'big'),
            'chain_id': int.from_bytes(tx[1], 'big'),
            'gas_price': int.from_bytes(tx[2], 'big'),
            'gas_coin': int.from_bytes(tx[3], 'big'),
            'type': int.from_bytes(tx[4], 'big'),
            'payload': payload,
            'service_data': service_data,
            'signature_type': int.from_bytes(tx[8], 'big')
        })

        # Get signature data
        signature_data = rlp.decode(tx[9])
        if struct['signature_type'] == cls.SIGNATURE_SINGLE_TYPE:
            signature_data = {
                'v': int.from_bytes(signature_data[0], 'big'),
                'r': signature_data[1].hex(),
                's': signature_data[2].hex()
            }
        else:
            # Decode signatures
            signatures = []
            for signature in signature_data[1]:
                signatures.append({
                    'v': int.from_bytes(signature[0], 'big'),
                    'r': signature[1].hex(),
                    's': signature[2].hex()
                })

            # Create decoded signature data
            signature_data = {
                'from_mx':
                MinterHelper.prefix_add(signature_data[0].hex(), PREFIX_ADDR),
                'signatures':
                signatures
            }
        struct['signature_data'] = signature_data

        # Find out which of tx instance need to create depending on it's type
        data = rlp.decode(tx[5])
        if struct['type'] == MinterDelegateTx.TYPE:
            _class = MinterDelegateTx
        elif struct['type'] == MinterSendCoinTx.TYPE:
            _class = MinterSendCoinTx
        elif struct['type'] == MinterBuyCoinTx.TYPE:
            _class = MinterBuyCoinTx
        elif struct['type'] == MinterCreateCoinTx.TYPE:
            _class = MinterCreateCoinTx
        elif struct['type'] == MinterDeclareCandidacyTx.TYPE:
            _class = MinterDeclareCandidacyTx
        elif struct['type'] == MinterRedeemCheckTx.TYPE:
            _class = MinterRedeemCheckTx
        elif struct['type'] == MinterSellAllCoinTx.TYPE:
            _class = MinterSellAllCoinTx
        elif struct['type'] == MinterSellCoinTx.TYPE:
            _class = MinterSellCoinTx
        elif struct['type'] == MinterSetCandidateOffTx.TYPE:
            _class = MinterSetCandidateOffTx
        elif struct['type'] == MinterSetCandidateOnTx.TYPE:
            _class = MinterSetCandidateOnTx
        elif struct['type'] == MinterUnbondTx.TYPE:
            _class = MinterUnbondTx
        elif struct['type'] == MinterEditCandidateTx.TYPE:
            _class = MinterEditCandidateTx
        elif struct['type'] == MinterMultiSendCoinTx.TYPE:
            _class = MinterMultiSendCoinTx
        elif struct['type'] == MinterCreateMultisigTx.TYPE:
            _class = MinterCreateMultisigTx
        else:
            raise Exception('Undefined tx type.')

        # Set tx data
        struct['data'] = _class._data_from_raw(data)

        # Set sender address and raw tx to minter dict
        # ONLY AFTER tx data was set
        struct.update({
            'from_mx': cls.get_sender_address(tx=copy.copy(struct)),
            'signed_tx': raw_tx
        })

        # Prepare **kwargs for creating _class instance.
        # Pass copy of the struct.
        kwargs = _class._structure_to_kwargs(copy.copy(struct))

        return _class(**kwargs)