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
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)
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)
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
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)
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)
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
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
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
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
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
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)
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)