def __init__(self, str_signing_key=None): if str_signing_key is None: self._context = Secp256k1Context() self._signing_key = self._context.new_random_private_key() self._verifying_key = self._context.get_public_key( self._signing_key) else: self._context = Secp256k1Context() hexed_string = str_signing_key.encode() self._signing_key = Secp256k1PrivateKey.from_hex(hexed_string) self._verifying_key = self._context.get_public_key( self._signing_key)
def test_store_public_key_for_other_not_der_public_key_format(): """ Case: send transaction request to store certificate public key not in DER format for other. Expect: invalid transaction error is raised with public key is already registered error message. """ not_der_format_public_key_to_store = b'h8ybuhtvrofpckejfhgubicojslmkghvbiuokl' address_from_public_key_to_store = generate_address('pub_key', not_der_format_public_key_to_store) inputs = outputs = [ address_from_public_key_to_store, OWNER_ADDRESS, ZERO_ADDRESS, IS_NODE_ECONOMY_ENABLED_ADDRESS, ] new_public_key_payload = generate_rsa_payload(key=not_der_format_public_key_to_store) serialized_new_public_key_payload = new_public_key_payload.SerializeToString() private_key = Secp256k1PrivateKey.from_hex(OWNER_PRIVATE_KEY) signature_by_owner = Secp256k1Context().sign(serialized_new_public_key_payload, private_key) new_public_key_store_and_pay_payload = NewPubKeyStoreAndPayPayload( pub_key_payload=new_public_key_payload, owner_public_key=bytes.fromhex(OWNER_PUBLIC_KEY), signature_by_owner=bytes.fromhex(signature_by_owner), ) transaction_payload = TransactionPayload() transaction_payload.method = PubKeyMethod.STORE_AND_PAY transaction_payload.data = new_public_key_store_and_pay_payload.SerializeToString() serialized_transaction_payload = transaction_payload.SerializeToString() transaction_header = generate_header( serialized_transaction_payload, inputs, outputs, signer_public_key=PAYER_PUBLIC_KEY, ) serialized_header = transaction_header.SerializeToString() transaction_request = TpProcessRequest( header=transaction_header, payload=serialized_transaction_payload, signature=create_signer(private_key=PAYER_PRIVATE_KEY).sign(serialized_header), ) mock_context = StubContext(inputs=inputs, outputs=outputs, initial_state={}) with pytest.raises(InvalidTransaction) as error: PubKeyHandler().apply(transaction=transaction_request, context=mock_context) assert 'Cannot deserialize the provided public key. Check if it is in DER format.' == str(error.value)
def test_store_public_key_for_other_no_payer_account(): """ Case: send transaction request, to store certificate public key for other, when payer account does not exist. Expect: invalid transaction error is raised with not enough transferable balance error message. """ new_public_key_payload = generate_rsa_payload(key=CERTIFICATE_PUBLIC_KEY) serialized_new_public_key_payload = new_public_key_payload.SerializeToString() private_key = Secp256k1PrivateKey.from_hex(OWNER_PRIVATE_KEY) signature_by_owner = Secp256k1Context().sign(serialized_new_public_key_payload, private_key) new_public_key_store_and_pay_payload = NewPubKeyStoreAndPayPayload( pub_key_payload=new_public_key_payload, owner_public_key=bytes.fromhex(OWNER_PUBLIC_KEY), signature_by_owner=bytes.fromhex(signature_by_owner), ) transaction_payload = TransactionPayload() transaction_payload.method = PubKeyMethod.STORE_AND_PAY transaction_payload.data = new_public_key_store_and_pay_payload.SerializeToString() serialized_transaction_payload = transaction_payload.SerializeToString() transaction_header = generate_header( serialized_transaction_payload, INPUTS, OUTPUTS, signer_public_key=PAYER_PUBLIC_KEY, ) serialized_header = transaction_header.SerializeToString() transaction_request = TpProcessRequest( header=transaction_header, payload=serialized_transaction_payload, signature=create_signer(private_key=PAYER_PRIVATE_KEY).sign(serialized_header), ) owner_account = Account() owner_account.pub_keys.append(RANDOM_ALREADY_STORED_OWNER_PUBLIC_KEY_ADDRESS) serialized_owner_account = owner_account.SerializeToString() zero_account = Account() zero_account.balance = 0 serialized_zero_account = zero_account.SerializeToString() mock_context = StubContext(inputs=INPUTS, outputs=OUTPUTS, initial_state={ OWNER_ADDRESS: serialized_owner_account, ZERO_ADDRESS: serialized_zero_account, }) with pytest.raises(InvalidTransaction) as error: PubKeyHandler().apply(transaction=transaction_request, context=mock_context) assert 'Not enough transferable balance. Sender\'s current balance: 0.' == str(error.value)
def test_store_public_key_for_other_already_registered_public_key(): """ Case: send transaction request to store already registered certificate public key for other. Expect: invalid transaction error is raised with public key is already registered error message. """ new_public_key_payload = generate_rsa_payload(key=CERTIFICATE_PUBLIC_KEY) serialized_new_public_key_payload = new_public_key_payload.SerializeToString() private_key = Secp256k1PrivateKey.from_hex(OWNER_PRIVATE_KEY) signature_by_owner = Secp256k1Context().sign(serialized_new_public_key_payload, private_key) new_public_key_store_and_pay_payload = NewPubKeyStoreAndPayPayload( pub_key_payload=new_public_key_payload, owner_public_key=bytes.fromhex(OWNER_PUBLIC_KEY), signature_by_owner=bytes.fromhex(signature_by_owner), ) transaction_payload = TransactionPayload() transaction_payload.method = PubKeyMethod.STORE_AND_PAY transaction_payload.data = new_public_key_store_and_pay_payload.SerializeToString() serialized_transaction_payload = transaction_payload.SerializeToString() transaction_header = generate_header( serialized_transaction_payload, INPUTS, OUTPUTS, signer_public_key=PAYER_PUBLIC_KEY, ) serialized_header = transaction_header.SerializeToString() transaction_request = TpProcessRequest( header=transaction_header, payload=serialized_transaction_payload, signature=create_signer(private_key=PAYER_PRIVATE_KEY).sign(serialized_header), ) already_registered_public_key = PubKeyStorage() already_registered_public_key.owner = OWNER_PUBLIC_KEY already_registered_public_key.payload.CopyFrom(new_public_key_payload) already_registered_public_key.is_revoked = False serialized_already_registered_public_key = already_registered_public_key.SerializeToString() mock_context = StubContext(inputs=INPUTS, outputs=OUTPUTS, initial_state={ ADDRESS_FROM_CERTIFICATE_PUBLIC_KEY: serialized_already_registered_public_key, }) with pytest.raises(InvalidTransaction) as error: PubKeyHandler().apply(transaction=transaction_request, context=mock_context) assert 'This public key is already registered.' == str(error.value)
def create_context(algorithm_name): """Returns an algorithm instance by name. Args: algorithm_name (str): the algorithm name Returns: (:obj:`Context`): a context instance for the given algorithm Raises: NoSuchAlgorithmError if the algorithm is unknown """ if algorithm_name == 'secp256k1': return Secp256k1Context() raise NoSuchAlgorithmError("no such algorithm: {}".format(algorithm_name))
def test_store_public_key_for_other_invalid_certificate_signature(): """ Case: send transaction request, to store certificate public for other, when certificate signature_by_owner is invalid. Expect: invalid transaction error is raised with public key is already registered error message. """ not_user_certificate_private_key = rsa.generate_private_key( public_exponent=65537, key_size=2048, backend=default_backend(), ) entity_hash_signature = generate_rsa_signature(b'w', not_user_certificate_private_key) new_public_key_payload = generate_rsa_payload( key=CERTIFICATE_PUBLIC_KEY, entity_hash_signature=entity_hash_signature, ) serialized_new_public_key_payload = new_public_key_payload.SerializeToString() private_key = Secp256k1PrivateKey.from_hex(OWNER_PRIVATE_KEY) signature_by_owner = Secp256k1Context().sign(serialized_new_public_key_payload, private_key) new_public_key_store_and_pay_payload = NewPubKeyStoreAndPayPayload( pub_key_payload=new_public_key_payload, owner_public_key=bytes.fromhex(OWNER_PUBLIC_KEY), signature_by_owner=bytes.fromhex(signature_by_owner), ) transaction_payload = TransactionPayload() transaction_payload.method = PubKeyMethod.STORE_AND_PAY transaction_payload.data = new_public_key_store_and_pay_payload.SerializeToString() serialized_transaction_payload = transaction_payload.SerializeToString() transaction_header = generate_header(serialized_transaction_payload, INPUTS, OUTPUTS) serialized_header = transaction_header.SerializeToString() transaction_request = TpProcessRequest( header=transaction_header, payload=serialized_transaction_payload, signature=create_signer(private_key=PAYER_PRIVATE_KEY).sign(serialized_header), ) mock_context = StubContext(inputs=INPUTS, outputs=OUTPUTS, initial_state={}) with pytest.raises(InvalidTransaction) as error: PubKeyHandler().apply(transaction=transaction_request, context=mock_context) assert 'Payed public key has invalid signature.' == str(error.value)
def test_store_public_key_for_other_public_key_exceeded_validity(): """ Case: send transaction request to store certificate public key with exceeded validity for other. Expect: invalid transaction error is raised with validity exceeds the maximum value error message. """ new_public_key_payload = generate_rsa_payload( key=CERTIFICATE_PUBLIC_KEY, valid_to=int(EXCEEDED_PUBLIC_KEY_VALIDITY_TIMESTAMP), ) serialized_new_public_key_payload = new_public_key_payload.SerializeToString() private_key = Secp256k1PrivateKey.from_hex(OWNER_PRIVATE_KEY) signature_by_owner = Secp256k1Context().sign(serialized_new_public_key_payload, private_key) new_public_key_store_and_pay_payload = NewPubKeyStoreAndPayPayload( pub_key_payload=new_public_key_payload, owner_public_key=bytes.fromhex(OWNER_PUBLIC_KEY), signature_by_owner=bytes.fromhex(signature_by_owner), ) transaction_payload = TransactionPayload() transaction_payload.method = PubKeyMethod.STORE_AND_PAY transaction_payload.data = new_public_key_store_and_pay_payload.SerializeToString() serialized_transaction_payload = transaction_payload.SerializeToString() transaction_header = generate_header( serialized_transaction_payload, INPUTS, OUTPUTS, signer_public_key=PAYER_PUBLIC_KEY, ) serialized_header = transaction_header.SerializeToString() transaction_request = TpProcessRequest( header=transaction_header, payload=serialized_transaction_payload, signature=create_signer(private_key=PAYER_PRIVATE_KEY).sign(serialized_header), ) mock_context = StubContext(inputs=INPUTS, outputs=OUTPUTS, initial_state={}) with pytest.raises(InvalidTransaction) as error: PubKeyHandler().apply(transaction=transaction_request, context=mock_context) assert 'The public key validity exceeds the maximum value.' == str(error.value)
def sign(self, data, rsa_signature_padding=None): """ Sign provided data with selected key implementation. Args: data (str): data string which will be signed rsa_signature_padding (RsaSignaturePadding, optional): not used in ECDSA Returns: Hex string of signature. """ if self._private_key is None: raise Exception('Private key is not provided!') if isinstance(data, str): data = utf8_to_bytes(data) sig = Secp256k1Context().sign(message=data, private_key=self._private_key_obj) return sig
def verify(self, data, signature, rsa_signature_padding=None): """ Verify signature for selected key implementation. Args: data (str): data string which will be verified signature (str): hex string of signature rsa_signature_padding (RsaSignaturePadding, optional): not used in ECDSA Returns: Boolean ``True`` if signature is correct, or ``False`` if invalid. """ if isinstance(data, str): data = utf8_to_bytes(data) try: if isinstance(signature, bytes): signature = binascii.hexlify(signature).decode('utf-8') return Secp256k1Context().verify(signature, data, self._public_key_obj) except Exception: return False
def verify(self, product_id, product_name, signature): msg = bytes("{}:{}".format(product_id, product_name), 'utf-8') return Secp256k1Context().verify(signature, msg, self._signer.get_public_key())
def _store_public_key_for_other(self, context, signer_pubkey, transaction_payload): """ Store public key for other account. The transaction for account which want to pay for other account public keys storing. A first account -> send payload -> A second account -> send transaction with first account's public key, but sign and pay for storing on own -> Remme-core. So Remme core charges tokens from a second account, but store a first account's public key. Public key owner here is a first account. Arguments: context (sawtooth_sdk.processor.context): context to store updated state (blockchain data). signer_pubkey: transaction sender public key. transaction_payload (pub_key_pb2.NewPubKeyStoreAndPayPayload): payload for storing public key for other. """ new_public_key_payload = transaction_payload.pub_key_payload owner_public_key_as_bytes = transaction_payload.owner_public_key owner_public_key_as_hex = owner_public_key_as_bytes.hex() owner_secp256k1_public_key = Secp256k1PublicKey.from_hex(owner_public_key_as_hex) is_owner_public_key_payload_signature_valid = Secp256k1Context().verify( signature=transaction_payload.signature_by_owner.hex(), message=new_public_key_payload.SerializeToString(), public_key=owner_secp256k1_public_key, ) if not is_owner_public_key_payload_signature_valid: raise InvalidTransaction('Public key owner\'s signature is invalid.') processor = self._get_public_key_processor(transaction_payload=transaction_payload.pub_key_payload) if not processor.verify(): raise InvalidTransaction('Payed public key has invalid signature.') public_key = processor.get_public_key() public_key_to_store_address = self.make_address_from_data(public_key) public_key_to_store_owner_address = AccountHandler().make_address_from_data(owner_public_key_as_hex) payer_for_storing_address = AccountHandler().make_address_from_data(signer_pubkey) public_key_information, public_key_to_store_owner_account, payer_for_storing_account = get_multiple_data(context, [ (public_key_to_store_address, PubKeyStorage), (public_key_to_store_owner_address, Account), (payer_for_storing_address, Account), ]) if public_key_information: raise InvalidTransaction('This public key is already registered.') if public_key_to_store_owner_account is None: public_key_to_store_owner_account = Account() if payer_for_storing_account is None: payer_for_storing_account = Account() if not self._is_public_key_validity_exceeded( valid_from=new_public_key_payload.valid_from, valid_to=new_public_key_payload.valid_to, ): raise InvalidTransaction('The public key validity exceeds the maximum value.') public_key_information = PubKeyStorage() public_key_information.owner = owner_public_key_as_hex public_key_information.payload.CopyFrom(new_public_key_payload) public_key_information.is_revoked = False state = { public_key_to_store_owner_address: public_key_to_store_owner_account, payer_for_storing_address: payer_for_storing_account, public_key_to_store_address: public_key_information, } charging_state = self._charge_for_storing(context=context, address_from=payer_for_storing_address) if charging_state is not None: state.update(charging_state) public_key_to_store_owner_account = self._store_public_key_to_account( public_key_to_store_address=public_key_to_store_address, public_key_to_store_owner_account=public_key_to_store_owner_account, ) state.update({ public_key_to_store_owner_address: public_key_to_store_owner_account, }) return state
def _store_certificate(self, context, signer_pubkey, transaction_payload): address = self.make_address_from_data(transaction_payload.certificate_raw) data = get_data(context, CertificateStorage, address) if data: raise InvalidTransaction('This certificate is already registered.') certificate = x509.load_der_x509_certificate(bytes.fromhex(transaction_payload.certificate_raw), default_backend()) if transaction_payload.cert_signer_public_key: cert_signer_pubkey = load_pem_public_key(transaction_payload.cert_signer_public_key.encode('utf-8'), backend=default_backend()) else: cert_signer_pubkey = certificate.public_key() try: cert_signer_pubkey.verify(bytes.fromhex(transaction_payload.signature_crt), bytes.fromhex(transaction_payload.signature_rem), padding.PSS(mgf=padding.MGF1(hashes.SHA256()), salt_length=padding.PSS.MAX_LENGTH), hashes.SHA256()) except InvalidSignature: raise InvalidTransaction('signature_crt mismatch') crt_hash = hashlib.sha512(transaction_payload.certificate_raw.encode('utf-8')).hexdigest().encode('utf-8') sawtooth_signing_ctx = Secp256k1Context() sawtooth_signing_pubkey = Secp256k1PublicKey.from_hex(signer_pubkey) sawtooth_signing_check_res = \ sawtooth_signing_ctx.verify(transaction_payload.signature_rem, crt_hash, sawtooth_signing_pubkey) if not sawtooth_signing_check_res: raise InvalidTransaction('signature_rem mismatch with signer key {}'.format(signer_pubkey)) subject = certificate.subject issuer = certificate.issuer organization = issuer.get_attributes_for_oid(NameOID.ORGANIZATION_NAME)[0].value uid = issuer.get_attributes_for_oid(NameOID.USER_ID)[0].value valid_from = certificate.not_valid_before valid_until = certificate.not_valid_after if organization != CERT_ORGANIZATION: raise InvalidTransaction('The organization name should be set to REMME. The actual name is {}' .format(organization)) if uid != signer_pubkey: raise InvalidTransaction('The certificate should be sent by its signer. Certificate signed by {}. ' 'Transaction sent by {}.'.format(uid, signer_pubkey)) if valid_until - valid_from > CERT_MAX_VALIDITY: raise InvalidTransaction('The certificate validity exceeds the maximum value.') fingerprint = certificate.fingerprint(hashes.SHA512()).hex()[:64] data = CertificateStorage() data.hash = fingerprint data.owner = signer_pubkey data.revoked = False account_address, account = TokenHandler.get_account_by_pub_key(context, signer_pubkey) if account.balance < CERT_STORE_PRICE: raise InvalidTransaction('Not enough tokens to register a new certificate. Current balance: {}' .format(account.balance)) account.balance -= CERT_STORE_PRICE LOGGER.info('Registered a new certificate on address {}. Fingerprint: {}'.format(address, fingerprint)) return {address: data, account_address: account}
def test_store_public_key_for_other_economy_is_not_enabled(): """ Case: send transaction request, to store certificate public key for other, when economy isn't enabled. Expect: public key information is stored to blockchain linked to owner address. Owner hasn't paid for storing. """ new_public_key_payload = generate_rsa_payload(key=CERTIFICATE_PUBLIC_KEY) serialized_new_public_key_payload = new_public_key_payload.SerializeToString() private_key = Secp256k1PrivateKey.from_hex(OWNER_PRIVATE_KEY) signature_by_owner = Secp256k1Context().sign(serialized_new_public_key_payload, private_key) new_public_key_store_and_pay_payload = NewPubKeyStoreAndPayPayload( pub_key_payload=new_public_key_payload, owner_public_key=bytes.fromhex(OWNER_PUBLIC_KEY), signature_by_owner=bytes.fromhex(signature_by_owner), ) transaction_payload = TransactionPayload() transaction_payload.method = PubKeyMethod.STORE_AND_PAY transaction_payload.data = new_public_key_store_and_pay_payload.SerializeToString() serialized_transaction_payload = transaction_payload.SerializeToString() transaction_header = generate_header( serialized_transaction_payload, INPUTS, OUTPUTS, signer_public_key=PAYER_PUBLIC_KEY, ) serialized_header = transaction_header.SerializeToString() transaction_request = TpProcessRequest( header=transaction_header, payload=serialized_transaction_payload, signature=create_signer(private_key=PAYER_PRIVATE_KEY).sign(serialized_header), ) payer_account = Account() payer_account.balance = PAYER_INITIAL_BALANCE serialized_payer_account = payer_account.SerializeToString() owner_account = Account() owner_account.pub_keys.append(RANDOM_ALREADY_STORED_OWNER_PUBLIC_KEY_ADDRESS) serialized_owner_account = owner_account.SerializeToString() zero_account = Account() zero_account.balance = 0 serialized_zero_account = zero_account.SerializeToString() is_economy_enabled_setting = Setting() is_economy_enabled_setting.entries.add(key='remme.economy_enabled', value='false') serialized_is_economy_enabled_setting = is_economy_enabled_setting.SerializeToString() mock_context = StubContext(inputs=INPUTS, outputs=OUTPUTS, initial_state={ OWNER_ADDRESS: serialized_owner_account, PAYER_ADDRESS: serialized_payer_account, ZERO_ADDRESS: serialized_zero_account, IS_NODE_ECONOMY_ENABLED_ADDRESS: serialized_is_economy_enabled_setting, }) expected_public_key_storage = PubKeyStorage() expected_public_key_storage.owner = OWNER_PUBLIC_KEY expected_public_key_storage.payload.CopyFrom(new_public_key_payload) expected_public_key_storage.is_revoked = False expected_serialized_public_key_storage = expected_public_key_storage.SerializeToString() expected_payer_account = Account() expected_payer_account.balance = PAYER_INITIAL_BALANCE serialized_expected_payer_account = expected_payer_account.SerializeToString() expected_owner_account = Account() expected_owner_account.pub_keys.append(RANDOM_ALREADY_STORED_OWNER_PUBLIC_KEY_ADDRESS) expected_owner_account.pub_keys.append(ADDRESS_FROM_CERTIFICATE_PUBLIC_KEY) serialized_expected_owner_account = expected_owner_account.SerializeToString() expected_zero_account = Account() expected_zero_account.balance = 0 expected_serialized_zero_account = expected_zero_account.SerializeToString() expected_state = { OWNER_ADDRESS: serialized_expected_owner_account, PAYER_ADDRESS: serialized_expected_payer_account, ADDRESS_FROM_CERTIFICATE_PUBLIC_KEY: expected_serialized_public_key_storage, ZERO_ADDRESS: expected_serialized_zero_account, } PubKeyHandler().apply(transaction=transaction_request, context=mock_context) state_as_list = mock_context.get_state(addresses=[ OWNER_ADDRESS, PAYER_ADDRESS, ADDRESS_FROM_CERTIFICATE_PUBLIC_KEY, ZERO_ADDRESS, ]) state_as_dict = {entry.address: entry.data for entry in state_as_list} assert expected_state == state_as_dict
def test_store_rsa_public_key_no_owner_account(): """ Case: send transaction request, to store certificate public key (RSA) for other, when owner account does not exist. Expect: public key information is stored to blockchain linked to the newly created owner account's address. """ new_public_key_payload = generate_rsa_payload(key=CERTIFICATE_PUBLIC_KEY) serialized_new_public_key_payload = new_public_key_payload.SerializeToString() private_key = Secp256k1PrivateKey.from_hex(OWNER_PRIVATE_KEY) signature_by_owner = Secp256k1Context().sign(serialized_new_public_key_payload, private_key) new_public_key_store_and_pay_payload = NewPubKeyStoreAndPayPayload( pub_key_payload=new_public_key_payload, owner_public_key=bytes.fromhex(OWNER_PUBLIC_KEY), signature_by_owner=bytes.fromhex(signature_by_owner), ) transaction_payload = TransactionPayload() transaction_payload.method = PubKeyMethod.STORE_AND_PAY transaction_payload.data = new_public_key_store_and_pay_payload.SerializeToString() serialized_transaction_payload = transaction_payload.SerializeToString() transaction_header = generate_header( serialized_transaction_payload, INPUTS, OUTPUTS, signer_public_key=PAYER_PUBLIC_KEY, ) serialized_header = transaction_header.SerializeToString() transaction_request = TpProcessRequest( header=transaction_header, payload=serialized_transaction_payload, signature=create_signer(private_key=PAYER_PRIVATE_KEY).sign(serialized_header), ) payer_account = Account() payer_account.balance = PAYER_INITIAL_BALANCE serialized_payer_account = payer_account.SerializeToString() zero_account = Account() zero_account.balance = 0 serialized_zero_account = zero_account.SerializeToString() mock_context = StubContext(inputs=INPUTS, outputs=OUTPUTS, initial_state={ PAYER_ADDRESS: serialized_payer_account, ZERO_ADDRESS: serialized_zero_account, }) expected_public_key_storage = PubKeyStorage() expected_public_key_storage.owner = OWNER_PUBLIC_KEY expected_public_key_storage.payload.CopyFrom(new_public_key_payload) expected_public_key_storage.is_revoked = False expected_serialized_public_key_storage = expected_public_key_storage.SerializeToString() expected_payer_account = Account() expected_payer_account.balance = PAYER_INITIAL_BALANCE - PUB_KEY_STORE_PRICE serialized_expected_payer_account = expected_payer_account.SerializeToString() expected_owner_account = Account() expected_owner_account.pub_keys.append(ADDRESS_FROM_CERTIFICATE_PUBLIC_KEY) serialized_expected_owner_account = expected_owner_account.SerializeToString() expected_zero_account = Account() expected_zero_account.balance = 0 + PUB_KEY_STORE_PRICE expected_serialized_zero_account = expected_zero_account.SerializeToString() expected_state = { OWNER_ADDRESS: serialized_expected_owner_account, PAYER_ADDRESS: serialized_expected_payer_account, ADDRESS_FROM_CERTIFICATE_PUBLIC_KEY: expected_serialized_public_key_storage, ZERO_ADDRESS: expected_serialized_zero_account, } PubKeyHandler().apply(transaction=transaction_request, context=mock_context) state_as_list = mock_context.get_state(addresses=[ OWNER_ADDRESS, PAYER_ADDRESS, ADDRESS_FROM_CERTIFICATE_PUBLIC_KEY, ZERO_ADDRESS, ]) state_as_dict = {entry.address: entry.data for entry in state_as_list} assert expected_state == state_as_dict
def test_store_ecdsa_public_key(): """ Case: send transaction request to store certificate public key (ECDSA) for other. Expect: public key information is stored to blockchain linked to owner address. Transaction sender paid for storing. """ inputs = outputs = [ ADDRESS_FROM_ECDSA_PUBLIC_KEY, OWNER_ADDRESS, PAYER_ADDRESS, ZERO_ADDRESS, IS_NODE_ECONOMY_ENABLED_ADDRESS, ] new_public_key_payload = generate_ecdsa_payload(key=ECDSA_PUBLIC_KEY) serialized_new_public_key_payload = new_public_key_payload.SerializeToString() private_key = Secp256k1PrivateKey.from_hex(OWNER_PRIVATE_KEY) signature_by_owner = Secp256k1Context().sign(serialized_new_public_key_payload, private_key) new_public_key_store_and_pay_payload = NewPubKeyStoreAndPayPayload( pub_key_payload=new_public_key_payload, owner_public_key=bytes.fromhex(OWNER_PUBLIC_KEY), signature_by_owner=bytes.fromhex(signature_by_owner), ) transaction_payload = TransactionPayload() transaction_payload.method = PubKeyMethod.STORE_AND_PAY transaction_payload.data = new_public_key_store_and_pay_payload.SerializeToString() serialized_transaction_payload = transaction_payload.SerializeToString() transaction_header = generate_header( serialized_transaction_payload, inputs, outputs, signer_public_key=PAYER_PUBLIC_KEY, ) serialized_header = transaction_header.SerializeToString() transaction_request = TpProcessRequest( header=transaction_header, payload=serialized_transaction_payload, signature=create_signer(private_key=PAYER_PRIVATE_KEY).sign(serialized_header), ) payer_account = Account() payer_account.balance = PAYER_INITIAL_BALANCE serialized_payer_account = payer_account.SerializeToString() owner_account = Account() owner_account.pub_keys.append(RANDOM_ALREADY_STORED_OWNER_PUBLIC_KEY_ADDRESS) serialized_owner_account = owner_account.SerializeToString() zero_account = Account() zero_account.balance = 0 serialized_zero_account = zero_account.SerializeToString() mock_context = StubContext(inputs=inputs, outputs=outputs, initial_state={ OWNER_ADDRESS: serialized_owner_account, PAYER_ADDRESS: serialized_payer_account, ZERO_ADDRESS: serialized_zero_account, }) expected_public_key_storage = PubKeyStorage() expected_public_key_storage.owner = OWNER_PUBLIC_KEY expected_public_key_storage.payload.CopyFrom(new_public_key_payload) expected_public_key_storage.is_revoked = False expected_serialized_public_key_storage = expected_public_key_storage.SerializeToString() expected_payer_account = Account() expected_payer_account.balance = PAYER_INITIAL_BALANCE - PUB_KEY_STORE_PRICE serialized_expected_payer_account = expected_payer_account.SerializeToString() expected_owner_account = Account() expected_owner_account.pub_keys.append(RANDOM_ALREADY_STORED_OWNER_PUBLIC_KEY_ADDRESS) expected_owner_account.pub_keys.append(ADDRESS_FROM_ECDSA_PUBLIC_KEY) serialized_expected_owner_account = expected_owner_account.SerializeToString() expected_zero_account = Account() expected_zero_account.balance = 0 + PUB_KEY_STORE_PRICE expected_serialized_zero_account = expected_zero_account.SerializeToString() expected_state = { OWNER_ADDRESS: serialized_expected_owner_account, PAYER_ADDRESS: serialized_expected_payer_account, ADDRESS_FROM_ECDSA_PUBLIC_KEY: expected_serialized_public_key_storage, ZERO_ADDRESS: expected_serialized_zero_account, } PubKeyHandler().apply(transaction=transaction_request, context=mock_context) state_as_list = mock_context.get_state(addresses=[ OWNER_ADDRESS, PAYER_ADDRESS, ADDRESS_FROM_ECDSA_PUBLIC_KEY, ZERO_ADDRESS, ]) state_as_dict = {entry.address: entry.data for entry in state_as_list} assert expected_state == state_as_dict