def _structure_from_instance(self): """ Override parent method. """ struct = super()._structure_from_instance() struct.update({ 'type': self.TYPE, 'data': { 'address': MinterHelper.hex2bin( MinterPrefix.remove_prefix(string=self.address, prefix=MinterPrefix.ADDRESS)), 'pub_key': MinterHelper.hex2bin( MinterPrefix.remove_prefix( string=self.pub_key, prefix=MinterPrefix.PUBLIC_KEY)), 'comission': '' if self.comission == 0 else self.comission, 'coin': MinterConvertor.encode_coin_name(self.coin), 'stake': MinterConvertor.convert_value(value=self.stake, to='pip') }, 'signature_type': self.SIGNATURE_SINGLE_TYPE }) return struct
def _structure_from_instance(self): """ Override parent method to add tx special data. """ struct = super()._structure_from_instance() struct.update({ 'type': self.TYPE, 'data': { 'pub_key': MinterHelper.hex2bin( MinterPrefix.remove_prefix( string=self.pub_key, prefix=MinterPrefix.PUBLIC_KEY)), 'reward_address': MinterHelper.hex2bin( MinterPrefix.remove_prefix(string=self.reward_address, prefix=MinterPrefix.ADDRESS)), 'owner_address': MinterHelper.hex2bin( MinterPrefix.remove_prefix(string=self.owner_address, prefix=MinterPrefix.ADDRESS)) }, 'signature_type': self.SIGNATURE_SINGLE_TYPE }) return struct
def _structure_from_instance(self): """ Override parent method to add tx special data. """ struct = super()._structure_from_instance() struct.update({ 'type': self.TYPE, 'data': { 'check': MinterHelper.hex2bin(MinterPrefix.remove_prefix(self.check, MinterPrefix.CHECK)), 'proof': MinterHelper.hex2bin(self.proof) } }) return struct
def proof(cls, address, passphrase): """ Create proof Args: address (str) passphrase (str) Returns: str """ # Get address hash address = MinterPrefix.remove_prefix( string=address, prefix=MinterPrefix.ADDRESS ) address = MinterHelper.hex2bin(address) address_hash = cls.__hash(data=[address]) # Create SHA256 from passphrase sha = hashlib.sha256() sha.update(passphrase.encode()) passphrase = sha.hexdigest() # Get signature signature = ECDSA.sign(message=address_hash, private_key=passphrase) return binascii.hexlify(cls.__lockfromsignature(signature)).decode()
def _structure_from_instance(self): """ Override parent method to add tx special data. """ struct = super()._structure_from_instance() struct.update({ 'type': self.TYPE, 'data': { 'txs': [] }, 'signature_type': self.SIGNATURE_SINGLE_TYPE }) # Populate multi data from each single tx. for item in self.txs: struct['data']['txs'].append([ MinterConvertor.encode_coin_name(item['coin']), MinterHelper.hex2bin( MinterPrefix.remove_prefix(string=item['to'], prefix=MinterPrefix.ADDRESS)), MinterConvertor.convert_value(value=item['value'], to='pip') ]) return struct
def sign(self, private_key=None, signature=None, ms_address=None): """ Sign transaction. This method can be called only from instances of inherited classes. Args: private_key (string|list[string]): private key to sign transaction with signature (string|list[string]): signature to sign transaction with ms_address (string): Multi signature address to sign tx by """ # Check arguments validity if not private_key and not signature: raise Exception('Please, provide either `private_key(s)` or `signature(s)`') if not ms_address and private_key and type(private_key) is not str: raise Exception('Please, provide a single `private_key` or set `ms_address` argument for multisig tx') if not ms_address and signature and type(signature) is not str: raise Exception('Please, provide a single `signature` or set `ms_address` argument for multisig tx') # Set tx signature type self.signature_type = self.SIGNATURE_SINGLE_TYPE if ms_address: if type(private_key) is str: private_key = [private_key] if type(signature) is str: signature = [signature] self.signature_type = self.SIGNATURE_MULTI_TYPE # Get populated and rlp encoded tx structure tx_struct = self.generate_tx_rlp() # Signature data if self.signature_type == self.SIGNATURE_SINGLE_TYPE: # Only one of private_key or signature can be provided for single signature type tx if private_key and signature: raise Exception('Please, provide one of `private_key` or `signature` for single signature type tx') # Set signature_data signature_data = self.generate_signature(private_key) if private_key else signature signature_data = self.decode_signature(signature_data) else: # Add multisig address to signature signature_data = [ MinterHelper.hex2bin(MinterPrefix.remove_prefix(string=ms_address, prefix=MinterPrefix.ADDRESS)), [] ] # Sign by each private key and add to total signature data if private_key: for pk in private_key: _signature = self.generate_signature(pk) signature_data[1].append(self.decode_signature(_signature)) # Sign by each signature and add to total signature data if signature: for _signature in signature: signature_data[1].append(self.decode_signature(_signature)) tx_struct['signature_data'] = rlp.encode(signature_data) self.signed_tx = self.generate_signed_tx(tx_struct)
def add_signature(cls, signed_tx, private_key): """ Add signature to already signed tx. Method is available only for multisig txs Args: signed_tx (str): signed tx private_key (str): private key Returns: tx object """ # Create tx instance from raw tx tx = cls.from_raw(signed_tx) # Check tx to be multi signature type if tx.signature_type != cls.SIGNATURE_MULTI_TYPE: raise Exception('Signature can be added only to tx with multi signature type') # Convert signature data from verbose dict to needed list of signatures signature_data = [ MinterHelper.hex2bin( MinterPrefix.remove_prefix(string=tx.signature_data['from_mx'], prefix=MinterPrefix.ADDRESS) ), [] ] for item in tx.signature_data['signatures']: # Create raw signature (values as integers) raw = [item['v']] raw.append(int(item['r'], 16)) raw.append(int(item['s'], 16)) # Append raw signature to total signature data signature_data[1].append(raw) # Get tx populated structure and keccak hash from this structure tx_struct = tx.generate_tx_rlp() # Create new signature and update signatures list and signatures attribute of tx signature = cls.decode_signature(signature=tx.generate_signature(private_key)) signature_data[1].append(signature) tx.signature_data['signatures'].append({ 'v': signature[0], 'r': format(signature[1], 'x'), 's': format(signature[2], 'x') }) # Update resulting struct signature data tx_struct['signature_data'] = rlp.encode(signature_data) # Generate new signed tx and update tx object attribute tx.signed_tx = cls.generate_signed_tx(tx_struct) return tx
def from_raw(cls, rawcheck): """ Create check instance from raw check Args: rawcheck (str) Returns: MinterCheck """ # Remove check prefix and RLP decode it rawcheck = MinterPrefix.remove_prefix( string=rawcheck, prefix=MinterPrefix.CHECK ) rawcheck = binascii.unhexlify(rawcheck) decoded = rlp.decode(rawcheck) # Create MinterCheck instance kwargs = { 'nonce': int(decoded[0].decode()), 'chain_id': MinterHelper.bin2int(decoded[1]), 'due_block': MinterHelper.bin2int(decoded[2]), 'coin': MinterConvertor.decode_coin_name(decoded[3]), 'value': MinterConvertor.convert_value( value=MinterHelper.bin2int(decoded[4]), to='bip' ), 'lock': binascii.hexlify(decoded[5]).decode(), 'signature': { 'v': MinterHelper.bin2int(decoded[6]), 'r': MinterHelper.bin2hex(decoded[7]), 's': MinterHelper.bin2hex(decoded[8]) } } check = MinterCheck(**kwargs) # Recover owner address msg_hash = cls.__hash(data=[ int(binascii.hexlify(str(check.nonce).encode()), 16), check.chain_id, check.due_block, MinterConvertor.encode_coin_name(check.coin), MinterConvertor.convert_value(value=check.value, to='pip'), MinterHelper.hex2bin(check.lock) ]) public_key = ECDSA.recover(msg_hash, list(check.signature.values())) public_key = MinterPrefix.PUBLIC_KEY + public_key check.owner = MinterWallet.get_address_from_public_key(public_key) return check
def __lockfromsignature(signature): """ Create lock from signature Args: signature (list): [v, r, s] list Returns: bytes """ v, r, s = signature v = '00' if v == 27 else '01' signature = format(r, 'x').zfill(64) + format(s, 'x').zfill(64) + v return MinterHelper.hex2bin(signature)
def _structure_from_instance(self): """ Override parent method to add tx special data. """ struct = super()._structure_from_instance() struct.update({ 'type': self.TYPE, 'data': { 'pub_key': MinterHelper.hex2bin(MinterPrefix.remove_prefix(self.pub_key, MinterPrefix.PUBLIC_KEY)), 'coin': MinterConvertor.encode_coin_name(self.coin), 'stake': MinterConvertor.convert_value(value=self.stake, to='pip') } }) return struct
def _structure_from_instance(self): """ Override parent method to add tx special data. """ struct = super()._structure_from_instance() struct.update({ 'type': self.TYPE, 'data': { 'pub_key': MinterHelper.hex2bin( MinterPrefix.remove_prefix(string=self.pub_key, prefix=MinterPrefix.PUBLIC_KEY) ) } }) return struct
def _structure_from_instance(self): """ Override parent method to add tx special data. """ struct = super()._structure_from_instance() struct.update({ 'type': self.TYPE, 'data': { 'coin': MinterConvertor.encode_coin_name(self.coin), 'to': MinterHelper.hex2bin(MinterPrefix.remove_prefix(string=self.to, prefix=MinterPrefix.ADDRESS)), 'value': MinterConvertor.convert_value(value=self.value, to='pip') } }) return struct