Ejemplo n.º 1
0
def test_account_transfer_from_address():
    """
    Case: transfer tokens from address to address.
    Expect: account's balances, stored in state, are changed according to transfer amount.
    """
    expected_account_from_balance = ACCOUNT_FROM_BALANCE - TOKENS_AMOUNT_TO_SEND
    expected_account_to_balance = ACCOUNT_TO_BALANCE + TOKENS_AMOUNT_TO_SEND

    transfer_payload = TransferPayload()
    transfer_payload.address_to = ACCOUNT_ADDRESS_TO
    transfer_payload.value = TOKENS_AMOUNT_TO_SEND

    transaction_payload = TransactionPayload()
    transaction_payload.method = AccountMethod.TRANSFER
    transaction_payload.data = transfer_payload.SerializeToString()

    serialized_transaction_payload = transaction_payload.SerializeToString()

    transaction_header = TransactionHeader(
        signer_public_key=RANDOM_NODE_PUBLIC_KEY,
        family_name=TRANSACTION_REQUEST_ACCOUNT_HANDLER_PARAMS.get('family_name'),
        family_version=TRANSACTION_REQUEST_ACCOUNT_HANDLER_PARAMS.get('family_version'),
        inputs=INPUTS,
        outputs=OUTPUTS,
        dependencies=[],
        payload_sha512=hash512(data=serialized_transaction_payload),
        batcher_public_key=RANDOM_NODE_PUBLIC_KEY,
        nonce=time.time().hex().encode(),
    )

    serialized_header = transaction_header.SerializeToString()

    transaction_request = TpProcessRequest(
        header=transaction_header,
        payload=serialized_transaction_payload,
        signature=create_signer(private_key=ACCOUNT_FROM_PRIVATE_KEY).sign(serialized_header),
    )

    mock_context = create_context(account_from_balance=ACCOUNT_FROM_BALANCE, account_to_balance=ACCOUNT_TO_BALANCE)

    AccountHandler().apply(transaction=transaction_request, context=mock_context)

    state_as_list = mock_context.get_state(addresses=[
        ACCOUNT_ADDRESS_FROM, ACCOUNT_ADDRESS_TO,
    ])

    state_as_dict = {}
    for entry in state_as_list:
        acc = Account()
        acc.ParseFromString(entry.data)
        state_as_dict[entry.address] = acc

    assert state_as_dict.get(ACCOUNT_ADDRESS_FROM, Account()).balance == expected_account_from_balance
    assert state_as_dict.get(ACCOUNT_ADDRESS_TO, Account()).balance == expected_account_to_balance
Ejemplo n.º 2
0
 def _genesis(self, context, pub_key, genesis_payload):
     signer_key = self.make_address_from_data(pub_key)
     genesis_status = get_data(context, GenesisStatus, GENESIS_ADDRESS)
     if not genesis_status:
         genesis_status = GenesisStatus()
     elif genesis_status.status:
         raise InvalidTransaction('Genesis is already initialized.')
     genesis_status.status = True
     account = Account()
     account.balance = genesis_payload.total_supply
     LOGGER.info(
         'Generated genesis transaction. Issued {} tokens to address {}'.
         format(genesis_payload.total_supply, signer_key))
     return {signer_key: account, GENESIS_ADDRESS: genesis_status}
Ejemplo n.º 3
0
    def _store_pub_key(self, context, signer_pubkey, transaction_payload):
        address = self.make_address_from_data(transaction_payload.public_key)
        LOGGER.info('Pub key address {}'.format(address))

        account_address = AccountHandler().make_address_from_data(signer_pubkey)
        LOGGER.info('Account address {}'.format(address))
        data, account = get_multiple_data(context, [(address, PubKeyStorage), (account_address, Account)])
        if data:
            raise InvalidTransaction('This pub key is already registered.')

        cert_signer_pubkey = load_pem_public_key(transaction_payload.public_key.encode('utf-8'),
                                                 backend=default_backend())
        try:
            ehs_bytes = binascii.unhexlify(transaction_payload.entity_hash_signature)
            eh_bytes = binascii.unhexlify(transaction_payload.entity_hash)
        except binascii.Error:
            LOGGER.debug(f'entity_hash_signature {transaction_payload.entity_hash_signature}')
            LOGGER.debug(f'entity_hash {transaction_payload.entity_hash}')
            raise InvalidTransaction('Entity hash or signature not a hex format')

        # FIXME: For support PKCS1v15 and PSS
        LOGGER.warn('HAZARD: Detecting padding for verification')
        sigerr = 0
        pkcs = padding.PKCS1v15()
        pss = padding.PSS(mgf=padding.MGF1(hashes.SHA512()), salt_length=padding.PSS.MAX_LENGTH)
        for _padding in (pkcs, pss):
            try:
                cert_signer_pubkey.verify(ehs_bytes, eh_bytes, _padding, hashes.SHA512())
                LOGGER.warn('HAZARD: Padding found: %s', _padding.name)
            except InvalidSignature:
                sigerr += 1

        if sigerr == 2:
            raise InvalidTransaction('Invalid signature')

        valid_from = datetime.fromtimestamp(transaction_payload.valid_from)
        valid_to = datetime.fromtimestamp(transaction_payload.valid_to)

        if valid_to - valid_from > PUB_KEY_MAX_VALIDITY:
            raise InvalidTransaction('The public key validity exceeds the maximum value.')

        data = PubKeyStorage()
        data.owner = signer_pubkey
        data.payload.CopyFrom(transaction_payload)
        data.revoked = False

        if not account:
            account = Account()
        if _get_setting_value(context, 'remme.economy_enabled', 'true').lower() == 'true':
            if account.balance < PUB_KEY_STORE_PRICE:
                raise InvalidTransaction('Not enough tokens to register a new pub key. Current balance: {}'
                                         .format(account.balance))
            account.balance -= PUB_KEY_STORE_PRICE

        if address not in account.pub_keys:
            account.pub_keys.append(address)

        return {address: data,
                account_address: account}
Ejemplo n.º 4
0
    def test_genesis_success(self):
        TOTAL_SUPPLY = 10000

        self.send_transaction(AccountMethod.GENESIS, AccountClient.get_genesis_payload(TOTAL_SUPPLY),
                              [GENESIS_ADDRESS, self.account_address1])

        self.expect_get({GENESIS_ADDRESS: None})

        genesis_status = GenesisStatus()
        genesis_status.status = True
        account = Account()
        account.balance = TOTAL_SUPPLY

        self.expect_set({
            self.account_address1: account,
            GENESIS_ADDRESS: genesis_status
        })

        self.expect_ok()
Ejemplo n.º 5
0
    def _swap_init(self, context, signer_pubkey, swap_init_payload):
        """
        if SecretLockOptionalBob is provided, Bob uses _swap_init to respond to requested swap
        Otherwise, Alice uses _swap_init to request a swap and thus, Bob can't receive funds until Alice "approves".
        """
        address_swap_info_is_stored_by = self.make_address_from_data(swap_init_payload.swap_id)
        swap_information = get_data(context, AtomicSwapInfo, address_swap_info_is_stored_by)

        if swap_information:
            raise InvalidTransaction('Atomic swap ID has already been taken, please use a different one.')

        block_info = self._get_latest_block_info(context)
        block_time = block_info.timestamp

        swap_information = AtomicSwapInfo()
        swap_information.swap_id = swap_init_payload.swap_id
        swap_information.state = AtomicSwapInfo.OPENED
        swap_information.amount = swap_init_payload.amount
        swap_information.created_at = block_time
        swap_information.secret_lock = swap_init_payload.secret_lock_by_solicitor
        swap_information.email_address_encrypted_optional = swap_init_payload.email_address_encrypted_by_initiator
        swap_information.sender_address = AccountHandler().make_address_from_data(signer_pubkey)
        swap_information.sender_address_non_local = swap_init_payload.sender_address_non_local
        swap_information.receiver_address = swap_init_payload.receiver_address
        swap_information.is_initiator = not swap_init_payload.secret_lock_by_solicitor

        commission_amount = int(_get_setting_value(context, SETTINGS_SWAP_COMMISSION))
        if commission_amount < 0:
            raise InvalidTransaction('Wrong commission address.')

        swap_total_amount = swap_information.amount + commission_amount

        account = get_data(context, Account, swap_information.sender_address)

        if account is None:
            account = Account()

        if account.balance < swap_total_amount:
            raise InvalidTransaction(
                f'Not enough balance to perform the transaction in the amount (with a commission) {swap_total_amount}.'
            )

        transfer_payload = AccountClient.get_transfer_payload(ZERO_ADDRESS, commission_amount)

        transfer_state = AccountHandler()._transfer_from_address(
            context, swap_information.sender_address, transfer_payload,
        )

        sender_account = transfer_state.get(swap_information.sender_address)
        sender_account.balance -= swap_information.amount

        return {
            address_swap_info_is_stored_by: swap_information,
            **transfer_state,
        }
Ejemplo n.º 6
0
    def _transfer_from_address(self, context, address, transfer_payload):
        signer_key = address

        if not transfer_payload.value:
            raise InvalidTransaction("Could not transfer with zero amount")

        if not transfer_payload.address_to.startswith(self._prefix) \
                and transfer_payload.address_to not in [ZERO_ADDRESS]:
            raise InvalidTransaction("Receiver address has to be of an account type")

        if signer_key == transfer_payload.address_to:
            raise InvalidTransaction("Account cannot send tokens to itself.")

        signer_account, receiver_account = get_multiple_data(context, [(signer_key, Account), (transfer_payload.address_to, Account)])

        # TODO transfer from genesis address using SETTINGS_KEY_GENESIS_OWNERS list of allowed addresses(0x0)
        # genesis_members_str = _get_setting_value(context, SETTINGS_KEY_GENESIS_OWNERS)
        # if not genesis_members_str:
        #     raise InvalidTransaction('REMchain is not configured to process genesis transfers.')
        #
        # genesis_members_list = genesis_members_str.split()

        if not receiver_account:
            receiver_account = Account()
        if not signer_account:
            signer_account = Account()

        if signer_account.balance < transfer_payload.value:
            raise InvalidTransaction("Not enough transferable balance. Sender's current balance: {}"
                                     .format(signer_account.balance))

        receiver_account.balance += transfer_payload.value
        signer_account.balance -= transfer_payload.value

        LOGGER.info('Transferred {} tokens from {} to {}'.format(transfer_payload.value,
                                                                 signer_key,
                                                                 transfer_payload.address_to))

        return {
            signer_key: signer_account,
            transfer_payload.address_to: receiver_account
        }
Ejemplo n.º 7
0
def test_public_key_handler_non_existing_sender_account():
    """
    Case: send transaction request, to store certificate public key, from non-existing account.
    Expect: invalid transaction error is raised with not enough transferable balance error message.
    """
    new_public_key_payload = generate_rsa_payload()

    transaction_payload = TransactionPayload()
    transaction_payload.method = PubKeyMethod.STORE
    transaction_payload.data = new_public_key_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=SENDER_PRIVATE_KEY).sign(serialized_header),
    )

    zero_account = Account()
    zero_account.balance = 0
    serialized_zero_account = zero_account.SerializeToString()

    mock_context = StubContext(inputs=INPUTS,
                               outputs=OUTPUTS,
                               initial_state={
                                   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)
Ejemplo n.º 8
0
    def _transfer_from_address(self, context, address, transfer_payload):
        signer_key = address

        if not transfer_payload.value:
            raise InvalidTransaction("Could not transfer with zero amount")

        if not transfer_payload.address_to.startswith(self._prefix) \
                and transfer_payload.address_to not in [ZERO_ADDRESS]:
            raise InvalidTransaction(
                "Receiver address has to be of an account type")

        if signer_key == transfer_payload.address_to:
            raise InvalidTransaction("Account cannot send tokens to itself.")

        signer_account, receiver_account = get_multiple_data(
            context, [(signer_key, Account),
                      (transfer_payload.address_to, Account)])

        if not receiver_account:
            receiver_account = Account()
        if not signer_account:
            signer_account = Account()

        if signer_account.balance < transfer_payload.value:
            raise InvalidTransaction(
                "Not enough transferable balance. Sender's current balance: "
                f"{signer_account.balance}")

        receiver_account.balance += transfer_payload.value
        signer_account.balance -= transfer_payload.value

        LOGGER.info(f'Transferred {transfer_payload.value} tokens from '
                    f'{signer_key} to {transfer_payload.address_to}')

        return {
            signer_key: signer_account,
            transfer_payload.address_to: receiver_account
        }
Ejemplo n.º 9
0
    def _transfer_from_address(self, context, address_from, transfer_payload):
        if not transfer_payload.value:
            raise InvalidTransaction('Could not transfer with zero amount.')

        if not transfer_payload.address_to.startswith(self._prefix) \
                and transfer_payload.address_to != ZERO_ADDRESS:
            raise InvalidTransaction('Receiver address has to be of an account type.')

        if address_from == transfer_payload.address_to:
            raise InvalidTransaction('Account cannot send tokens to itself.')

        signer_account, receiver_account = get_multiple_data(context, [
            (address_from, Account),
            (transfer_payload.address_to, Account),
        ])

        if signer_account is None:
            signer_account = Account()

        if receiver_account is None:
            receiver_account = Account()

        if signer_account.balance < transfer_payload.value:
            raise InvalidTransaction(
                f'Not enough transferable balance. Sender\'s current balance: {signer_account.balance}.',
            )

        receiver_account.balance += transfer_payload.value
        signer_account.balance -= transfer_payload.value

        LOGGER.info(
            f'Transferred {transfer_payload.value} tokens from {address_from} to {transfer_payload.address_to}.',
        )

        return {
            address_from: signer_account,
            transfer_payload.address_to: receiver_account,
        }
Ejemplo n.º 10
0
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)
Ejemplo n.º 11
0
    def _swap_expire(self, context, signer_pubkey, swap_expire_payload):
        """
        Transaction initiator (Alice) decides to withdraw deposit in 24 hours, or Bob in 48 hours.
        """
        swap_identifier = swap_expire_payload.swap_id

        address_swap_info_is_stored_by = self.make_address_from_data(swap_identifier)
        swap_information = get_data(context, AtomicSwapInfo, address_swap_info_is_stored_by)

        if not swap_information:
            raise InvalidTransaction(f'Atomic swap was not initiated for identifier {swap_identifier}!')

        if swap_information.state in NOT_PERMITTED_TO_CHANGE_SWAP_STATUSES:
            raise InvalidTransaction(
                f'No operations can be done upon the swap: {swap_identifier} as it is already closed or expired.',
            )

        signer_address = AccountHandler().make_address_from_data(signer_pubkey)

        if signer_address != swap_information.sender_address:
            raise InvalidTransaction('Signer is not the one who opened the swap.')

        block = self._get_latest_block_info(context)
        block_time = self.get_datetime_from_timestamp(block.timestamp)
        created_at = self.get_datetime_from_timestamp(swap_information.created_at)

        time_delta = INITIATOR_TIME_DELTA_LOCK if swap_information.is_initiator else NON_INITIATOR_TIME_DELTA_LOCK

        if (created_at + time_delta) > block_time:
            initiator_name = 'initiator' if swap_information.is_initiator else 'non initiator'
            initiator_time_lock = INTIATOR_TIME_LOCK if swap_information.is_initiator else NON_INTIATOR_TIME_LOCK

            raise InvalidTransaction(
                f'Swap {initiator_name} needs to wait {initiator_time_lock} hours since '
                f'timestamp {swap_information.created_at} to withdraw.'
            )

        account = get_data(context, Account, swap_information.sender_address)
        if account is None:
            account = Account()
        account.balance += swap_information.amount

        swap_information.state = AtomicSwapInfo.EXPIRED

        return {
            address_swap_info_is_stored_by: swap_information,
            swap_information.sender_address: account,
        }
Ejemplo n.º 12
0
    def _swap_close(self, context, signer_pubkey, swap_close_payload):
        """
        Close atomic swap.

        Any party (Bob or Alice) can close atomic swap by providing secret key. If hash from secret key matches
        secret lock, secret key is valid. Closing atomic swap means participant (not initiator)
        get REMchain tokens instead ERC20 tokens.

        Closing requires atomic swap to be approved.
        """
        swap_identifier = swap_close_payload.swap_id

        address_swap_info_is_stored_by = self.make_address_from_data(swap_identifier)
        swap_information = get_data(context, AtomicSwapInfo, address_swap_info_is_stored_by)

        if not swap_information:
            raise InvalidTransaction(f'Atomic swap was not initiated for identifier {swap_identifier}!')

        if swap_information.state in NOT_PERMITTED_TO_CHANGE_SWAP_STATUSES:
            raise InvalidTransaction(
                f'No operations can be done upon the swap: {swap_identifier} as it is already closed or expired.',
            )

        if not swap_information.secret_lock:
            raise InvalidTransaction('Secret lock is required to close the swap.')

        if web3_hash(swap_close_payload.secret_key) != swap_information.secret_lock:
            raise InvalidTransaction('Secret key doesn\'t match specified secret lock.')

        if swap_information.is_initiator and swap_information.state != AtomicSwapInfo.APPROVED:
            raise InvalidTransaction('Transaction cannot be closed before it\'s approved.')

        account = get_data(context, Account, swap_information.receiver_address)
        if account is None:
            account = Account()
        account.balance += swap_information.amount

        swap_information.secret_key = swap_close_payload.secret_key
        swap_information.state = AtomicSwapInfo.CLOSED

        return {
            address_swap_info_is_stored_by: swap_information,
            swap_information.receiver_address: account,
        }
Ejemplo n.º 13
0
def create_context(account_from_balance, account_to_balance):
    """
    Create stub context with initial data.

    Stub context is an interface around Sawtooth state, consider as database.
    State is key-value storage that contains address with its data (i.e. account balance).

    References:
        - https://github.com/Remmeauth/remme-core/blob/dev/testing/mocks/stub.py
    """
    account_protobuf = Account()

    account_protobuf.balance = account_from_balance
    serialized_account_from_balance = account_protobuf.SerializeToString()

    account_protobuf.balance = account_to_balance
    serialized_account_to_balance = account_protobuf.SerializeToString()

    initial_state = {
        ACCOUNT_ADDRESS_FROM: serialized_account_from_balance,
        ACCOUNT_ADDRESS_TO: serialized_account_to_balance,
    }

    return StubContext(inputs=INPUTS, outputs=OUTPUTS, initial_state=initial_state)
Ejemplo n.º 14
0
def get_account_by_address(context, address):
    account = get_data(context, Account, address)
    if account is None:
        return Account()
    return account
Ejemplo n.º 15
0
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
Ejemplo n.º 16
0
 async def get_account(self, address):
     account = Account()
     raw_account = await self.get_value(address)
     account.ParseFromString(raw_account)
     return account
Ejemplo n.º 17
0
    def get_account_model(self, balance):
        account = Account()
        account.balance = int(balance)

        return account
Ejemplo n.º 18
0
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
Ejemplo n.º 19
0
def test_public_key_handler_rsa_store():
    """
    Case: send transaction request to store certificate public key.
    Expect: public key information is stored to blockchain linked to owner address. Owner paid tokens for storing.
    """
    new_public_key_payload = generate_rsa_payload()

    transaction_payload = TransactionPayload()
    transaction_payload.method = PubKeyMethod.STORE
    transaction_payload.data = new_public_key_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=SENDER_PRIVATE_KEY).sign(serialized_header),
    )

    sender_account = Account()
    sender_account.balance = SENDER_INITIAL_BALANCE
    sender_account.pub_keys.append(RANDOM_ALREADY_STORED_SENDER_PUBLIC_KEY)
    serialized_sender_account = sender_account.SerializeToString()

    zero_account = Account()
    zero_account.balance = 0
    serialized_zero_account = zero_account.SerializeToString()

    mock_context = StubContext(inputs=INPUTS,
                               outputs=OUTPUTS,
                               initial_state={
                                   SENDER_ADDRESS: serialized_sender_account,
                                   ZERO_ADDRESS: serialized_zero_account,
                               })

    expected_public_key_storage = PubKeyStorage()
    expected_public_key_storage.owner = SENDER_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_sender_account = Account()
    expected_sender_account.balance = SENDER_INITIAL_BALANCE - PUB_KEY_STORE_PRICE
    expected_sender_account.pub_keys.append(
        RANDOM_ALREADY_STORED_SENDER_PUBLIC_KEY)
    expected_sender_account.pub_keys.append(
        ADDRESS_FROM_CERTIFICATE_PUBLIC_KEY)
    expected_serialized_sender_account = expected_sender_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 = {
        SENDER_ADDRESS: expected_serialized_sender_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=[
        SENDER_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
Ejemplo n.º 20
0
def test_public_key_handler_store_sender_is_node():
    """
    Case: send transaction request, to store certificate public key, when sender is node (same addresses).
    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()

    transaction_payload = TransactionPayload()
    transaction_payload.method = PubKeyMethod.STORE
    transaction_payload.data = new_public_key_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=SENDER_PRIVATE_KEY).sign(serialized_header),
    )

    sender_account = Account()
    sender_account.pub_keys.append(RANDOM_ALREADY_STORED_SENDER_PUBLIC_KEY)
    serialized_sender_account = sender_account.SerializeToString()

    zero_account = Account()
    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={
                                   SENDER_ADDRESS: serialized_sender_account,
                                   IS_NODE_ECONOMY_ENABLED_ADDRESS:
                                   serialized_is_economy_enabled_setting,
                                   ZERO_ADDRESS: serialized_zero_account,
                               })

    expected_public_key_storage = PubKeyStorage()
    expected_public_key_storage.owner = SENDER_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_sender_account = Account()
    expected_sender_account.pub_keys.append(
        RANDOM_ALREADY_STORED_SENDER_PUBLIC_KEY)
    expected_sender_account.pub_keys.append(
        ADDRESS_FROM_CERTIFICATE_PUBLIC_KEY)
    expected_serialized_sender_account = expected_sender_account.SerializeToString(
    )

    expected_zero_account = Account()
    expected_serialized_zero_account = expected_zero_account.SerializeToString(
    )

    expected_state = {
        SENDER_ADDRESS: expected_serialized_sender_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=[
        SENDER_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
Ejemplo n.º 21
0
class RpcApiTestCase(AioHTTPTestCase, HelperTestCase):
    @staticmethod
    def create_raw_transaction_send_token_payload(pub_key_to, amount=1):
        client = AccountClient()
        signer = client._signer
        address = client.make_address_from_data(pub_key_to)
        node_address = client.get_user_address()

        transfer = TransferPayload()
        transfer.address_to = address
        transfer.value = amount

        tr = TransactionPayload()
        tr.method = AccountMethod.TRANSFER
        tr.data = transfer.SerializeToString()

        payload = tr.SerializeToString()

        header = TransactionHeader(
            signer_public_key=signer.get_public_key().as_hex(),
            family_name=client._family_handler.family_name,
            family_version=client._family_handler.family_versions[-1],
            inputs=[node_address, address],
            outputs=[node_address, address],
            dependencies=[],
            payload_sha512=hash512(payload),
            batcher_public_key=signer.get_public_key().as_hex(),
            nonce=time.time().hex().encode()).SerializeToString()

        signature = signer.sign(header)

        transaction = Transaction(header=header,
                                  payload=payload,
                                  header_signature=signature)
        return transaction

    async def get_application(self):
        app = web.Application()
        rpc = JsonRpc(loop=self.loop, max_workers=1)
        rpc.add_methods(
            ('', get_node_config),
            ('', send_raw_transaction),
            ('', get_balance),
            ('', get_batch_status),
        )
        app.router.add_route('POST', '/', rpc)
        return app

    async def create_rpc_request(self, method, params=None):
        if params is None:
            params = {}
        data = encode_request(method, id=int(time.time()), params=params)
        LOGGER.info(f'JSON RPC request payload: {data}')
        return await self.client.request(
            'POST',
            '/',
            data=data,
            headers={'Content-Type': 'application/json'})

    @mock.patch(
        'remme.clients.basic.BasicClient.fetch_state',
        return_value={
            'data':
            base64.b64encode(
                Setting(entries=[
                    Setting.Entry(
                        key=_make_settings_key(SETTINGS_STORAGE_PUB_KEY),
                        value=
                        '03823c7a9e285246985089824f3aaa51fb8675d08d84b151833ca5febce37ad61e'
                    )
                ]).SerializeToString())
        })
    @mock.patch('remme.clients.basic.BasicClient._head_to_root',
                return_value=(None, 'some_root'))
    @unittest_run_loop
    @test
    async def test_node_key_retrieve_info_and_it_ok(self, root_mock,
                                                    fetch_state_mock):
        resp = await self.create_rpc_request('get_node_config')
        self.assertEqual(resp.status, 200)
        data = await resp.json()

        pub_key = PubKeyClient().get_public_key()
        self.assertEqual(data['result']['node_public_key'], pub_key)

    @mock.patch(
        'remme.clients.basic.BasicClient.submit_batches',
        return_value={
            'data':
            'c6bcb01255c1870a5d42fe2dde5e91fb0c5992ec0b49932cdab901539bf977f75bb7699c053cea16668ba732a7d597dd0c2b80f157f1a2514932078bb761de4b'
        })
    @unittest_run_loop
    @test
    async def test_valid_raw_transaction_send_to_the_node(self, req_mock):
        payload = self.create_raw_transaction_send_token_payload(
            '03823c7a9e285246985089824f3aaa51fb8675d08d84b151833ca5febce37ad61e',
            1)
        resp = await self.create_rpc_request('send_raw_transaction', {
            'data':
            base64.b64encode(payload.SerializeToString()).decode('utf-8')
        })
        self.assertEqual(resp.status, 200)
        data = await resp.json()
        self.assertEqual(
            data['result'],
            'c6bcb01255c1870a5d42fe2dde5e91fb0c5992ec0b49932cdab901539bf977f75bb7699c053cea16668ba732a7d597dd0c2b80f157f1a2514932078bb761de4b'
        )

    @mock.patch('remme.clients.basic.BasicClient.fetch_state',
                return_value={
                    'data':
                    base64.b64encode(Account(balance=100).SerializeToString())
                })
    @mock.patch('remme.clients.basic.BasicClient._head_to_root',
                return_value=(None, 'some_root'))
    @unittest_run_loop
    @test
    async def test_get_token_balance(self, root_mock, fetch_state_mock):
        address = AccountClient().make_address_from_data(
            '03823c7a9e285246985089824f3aaa51fb8675d08d84b151833ca5febce37ad61a'
        )
        resp = await self.create_rpc_request('get_balance',
                                             {'public_key_address': address})
        self.assertEqual(resp.status, 200)
        data = await resp.json()
        self.assertEqual(data['result'], 100)

    @mock.patch('remme.clients.basic.BasicClient.list_statuses',
                return_value={'data': [{
                    'status': 'COMMITTED'
                }]})
    @unittest_run_loop
    @test
    async def test_check_batch_status(self, batch_status_mock):
        resp = await self.create_rpc_request(
            'get_batch_status', {
                'id':
                '3936f0fa13d008c2b00d04013dfa5e5359fccc117e4c47b1416ee24e115ac08b08707be3b3ce6956ca3d789d245ff0dddf7a39bc2b2f4210ffe81ebd0244c014'
            })
        self.assertEqual(resp.status, 200)
        data = await resp.json()
        self.assertEqual(data['result'], 'COMMITTED')
Ejemplo n.º 22
0
 def get_account(self, address):
     account = Account()
     account.ParseFromString(self.get_value(address))
     return account
Ejemplo n.º 23
0
def test_account_handler_genesis_apply():
    """
    Case: send transaction request, to send tokens from genesis address, to the account handler.
    Expect:
    """
    account = Account()
    account.balance = TOKENS_AMOUNT_TO_SUPPLY
    expected_serialized_account_to_balance = account.SerializeToString()

    genesis_payload = GenesisPayload()
    genesis_payload.total_supply = TOKENS_AMOUNT_TO_SUPPLY

    transaction_payload = TransactionPayload()
    transaction_payload.method = AccountMethod.GENESIS
    transaction_payload.data = genesis_payload.SerializeToString()

    serialized_transaction_payload = transaction_payload.SerializeToString()

    transaction_header = TransactionHeader(
        signer_public_key=NODE_PUBLIC_KEY,
        family_name=TRANSACTION_REQUEST_ACCOUNT_HANDLER_PARAMS.get(
            'family_name'),
        family_version=TRANSACTION_REQUEST_ACCOUNT_HANDLER_PARAMS.get(
            'family_version'),
        inputs=INPUTS,
        outputs=OUTPUTS,
        dependencies=[],
        payload_sha512=hash512(data=serialized_transaction_payload),
        batcher_public_key=NODE_PUBLIC_KEY,
        nonce=time.time().hex().encode(),
    )

    serialized_header = transaction_header.SerializeToString()

    transaction_request = TpProcessRequest(
        header=transaction_header,
        payload=serialized_transaction_payload,
        signature=create_signer(
            private_key=NODE_PRIVATE_KEY).sign(serialized_header),
    )

    genesis_status = GenesisStatus()
    genesis_status.status = True

    expected_state = {
        GENESIS_ADDRESS: genesis_status.SerializeToString(),
        ACCOUNT_ADDRESS_TO: expected_serialized_account_to_balance,
    }

    mock_context = StubContext(inputs=INPUTS,
                               outputs=OUTPUTS,
                               initial_state={})

    AccountHandler().apply(transaction=transaction_request,
                           context=mock_context)

    state_as_list = mock_context.get_state(
        addresses=[GENESIS_ADDRESS, ACCOUNT_ADDRESS_TO])
    state_as_dict = {entry.address: entry.data for entry in state_as_list}

    assert expected_state == state_as_dict
Ejemplo n.º 24
0
def test_close_atomic_swap():
    """
    Case: close atomic swap.
    Expect: increase Alice account address by swap amount.
    """
    atomic_swap_close_payload = AtomicSwapClosePayload(
        swap_id=SWAP_ID,
        secret_key=SECRET_KEY,
    )

    transaction_payload = TransactionPayload()
    transaction_payload.method = AtomicSwapMethod.CLOSE
    transaction_payload.data = atomic_swap_close_payload.SerializeToString()

    serialized_transaction_payload = transaction_payload.SerializeToString()

    transaction_header = TransactionHeader(
        signer_public_key=BOT_PUBLIC_KEY,
        family_name=TRANSACTION_REQUEST_ACCOUNT_HANDLER_PARAMS.get(
            'family_name'),
        family_version=TRANSACTION_REQUEST_ACCOUNT_HANDLER_PARAMS.get(
            'family_version'),
        inputs=INPUTS,
        outputs=OUTPUTS,
        dependencies=[],
        payload_sha512=hash512(data=serialized_transaction_payload),
        batcher_public_key=RANDOM_NODE_PUBLIC_KEY,
        nonce=time.time().hex().encode(),
    )

    serialized_header = transaction_header.SerializeToString()

    transaction_request = TpProcessRequest(
        header=transaction_header,
        payload=serialized_transaction_payload,
        signature=create_signer(
            private_key=BOT_PRIVATE_KEY).sign(serialized_header),
    )

    alice_account = Account()
    alice_account.balance = 0
    serialized_alice_account = alice_account.SerializeToString()

    existing_swap_info_to_close = AtomicSwapInfo()
    existing_swap_info_to_close.swap_id = SWAP_ID
    existing_swap_info_to_close.amount = 200
    existing_swap_info_to_close.state = AtomicSwapInfo.APPROVED
    existing_swap_info_to_close.secret_lock = SECRET_LOCK
    existing_swap_info_to_close.is_initiator = True
    existing_swap_info_to_close.sender_address = BOT_ADDRESS
    existing_swap_info_to_close.receiver_address = ALICE_ADDRESS
    serialized_existing_swap_info_to_lock = existing_swap_info_to_close.SerializeToString(
    )

    genesis_members_setting = Setting()
    genesis_members_setting.entries.add(key=SETTINGS_KEY_ZERO_ADDRESS_OWNERS,
                                        value=f'{BOT_PUBLIC_KEY},')
    serialized_genesis_members_setting = genesis_members_setting.SerializeToString(
    )

    mock_context = StubContext(inputs=INPUTS,
                               outputs=OUTPUTS,
                               initial_state={
                                   ADDRESS_TO_GET_GENESIS_MEMBERS_AS_STRING_BY:
                                   serialized_genesis_members_setting,
                                   ADDRESS_TO_STORE_SWAP_INFO_BY:
                                   serialized_existing_swap_info_to_lock,
                                   ALICE_ADDRESS: serialized_alice_account,
                               })

    expected_alice_account = Account()
    expected_alice_account.balance = TOKENS_AMOUNT_TO_SWAP
    serialized_expected_alice_account = expected_alice_account.SerializeToString(
    )

    expected_closed_swap_info = AtomicSwapInfo()
    expected_closed_swap_info.swap_id = SWAP_ID
    expected_closed_swap_info.amount = 200
    expected_closed_swap_info.state = AtomicSwapInfo.CLOSED
    expected_closed_swap_info.secret_lock = SECRET_LOCK
    expected_closed_swap_info.secret_key = SECRET_KEY
    expected_closed_swap_info.is_initiator = True
    expected_closed_swap_info.sender_address = BOT_ADDRESS
    expected_closed_swap_info.receiver_address = ALICE_ADDRESS
    serialized_expected_closed_swap_info = expected_closed_swap_info.SerializeToString(
    )

    expected_state = {
        ADDRESS_TO_STORE_SWAP_INFO_BY: serialized_expected_closed_swap_info,
        ALICE_ADDRESS: serialized_expected_alice_account,
    }

    AtomicSwapHandler().apply(transaction=transaction_request,
                              context=mock_context)

    state_as_list = mock_context.get_state(
        addresses=[ADDRESS_TO_STORE_SWAP_INFO_BY, ALICE_ADDRESS])
    state_as_dict = {entry.address: entry.data for entry in state_as_list}

    assert expected_state == state_as_dict
Ejemplo n.º 25
0
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
Ejemplo n.º 26
0
def test_expire_atomic_swap():
    """
    Case: to expire atomic swap.
    Expect: increase bot address balance by swap amount. Leave commission on zero address.
    """
    atomic_swap_expire_payload = AtomicSwapExpirePayload(swap_id=SWAP_ID, )

    transaction_payload = TransactionPayload()
    transaction_payload.method = AtomicSwapMethod.EXPIRE
    transaction_payload.data = atomic_swap_expire_payload.SerializeToString()

    serialized_transaction_payload = transaction_payload.SerializeToString()

    transaction_header = TransactionHeader(
        signer_public_key=BOT_PUBLIC_KEY,
        family_name=TRANSACTION_REQUEST_ACCOUNT_HANDLER_PARAMS.get(
            'family_name'),
        family_version=TRANSACTION_REQUEST_ACCOUNT_HANDLER_PARAMS.get(
            'family_version'),
        inputs=INPUTS,
        outputs=OUTPUTS,
        dependencies=[],
        payload_sha512=hash512(data=serialized_transaction_payload),
        batcher_public_key=RANDOM_NODE_PUBLIC_KEY,
        nonce=time.time().hex().encode(),
    )

    serialized_header = transaction_header.SerializeToString()

    transaction_request = TpProcessRequest(
        header=transaction_header,
        payload=serialized_transaction_payload,
        signature=create_signer(
            private_key=BOT_PRIVATE_KEY).sign(serialized_header),
    )

    bot_account = Account()
    bot_account.balance = 4700
    serialized_bot_account = bot_account.SerializeToString()

    genesis_members_setting = Setting()
    genesis_members_setting.entries.add(key=SETTINGS_KEY_ZERO_ADDRESS_OWNERS,
                                        value=f'{BOT_PUBLIC_KEY},')
    serialized_genesis_members_setting = genesis_members_setting.SerializeToString(
    )

    existing_swap_info = AtomicSwapInfo()
    existing_swap_info.swap_id = SWAP_ID
    existing_swap_info.state = AtomicSwapInfo.OPENED
    existing_swap_info.amount = TOKENS_AMOUNT_TO_SWAP
    existing_swap_info.created_at = CURRENT_TIMESTAMP // 2
    existing_swap_info.sender_address = BOT_ADDRESS
    existing_swap_info.receiver_address = ALICE_ADDRESS
    existing_swap_info.is_initiator = True
    serialized_existing_swap_info = existing_swap_info.SerializeToString()

    mock_context = StubContext(inputs=INPUTS,
                               outputs=OUTPUTS,
                               initial_state={
                                   BLOCK_INFO_CONFIG_ADDRESS:
                                   SERIALIZED_BLOCK_INFO_CONFIG,
                                   BLOCK_INFO_ADDRESS:
                                   SERIALIZED_BLOCK_INFO,
                                   BOT_ADDRESS:
                                   serialized_bot_account,
                                   ADDRESS_TO_STORE_SWAP_INFO_BY:
                                   serialized_existing_swap_info,
                                   ADDRESS_TO_GET_GENESIS_MEMBERS_AS_STRING_BY:
                                   serialized_genesis_members_setting,
                               })

    expected_bot_account = Account()
    expected_bot_account.balance = 4700 + TOKENS_AMOUNT_TO_SWAP
    serialized_expected_bot_account = expected_bot_account.SerializeToString()

    expected_swap_info = AtomicSwapInfo()
    expected_swap_info.swap_id = SWAP_ID
    expected_swap_info.state = AtomicSwapInfo.EXPIRED
    expected_swap_info.amount = TOKENS_AMOUNT_TO_SWAP
    expected_swap_info.created_at = CURRENT_TIMESTAMP // 2
    expected_swap_info.sender_address = BOT_ADDRESS
    expected_swap_info.receiver_address = ALICE_ADDRESS
    expected_swap_info.is_initiator = True
    serialized_expected_swap_info = expected_swap_info.SerializeToString()

    expected_state = {
        BOT_ADDRESS: serialized_expected_bot_account,
        ADDRESS_TO_STORE_SWAP_INFO_BY: serialized_expected_swap_info,
    }

    AtomicSwapHandler().apply(transaction=transaction_request,
                              context=mock_context)

    state_as_list = mock_context.get_state(addresses=[
        ADDRESS_TO_STORE_SWAP_INFO_BY,
        BOT_ADDRESS,
    ])
    state_as_dict = {entry.address: entry.data for entry in state_as_list}

    assert expected_state == state_as_dict
Ejemplo n.º 27
0
    def _store_pub_key(self, context, signer_pubkey, transaction_payload):
        """
        Store public key to the blockchain.

        Flow on client:
        1. Create private and public key (for instance, RSA).
        2. Create random data and sign it with private key to allows node verify signature,
            so ensure the address sent transaction is a real owner of public key.
        3. Send public key, signature, and other information to the node.

        Node does checks: if public key already exists in the blockchain, try to deserialize public key,
        try to verify signature, if validity exceeds.

        If transaction successfully passed checks, node charges fixed tokens price for storing
        public keys (if node economy is enabled) and link public key to the account (address).

        References:
            - https://docs.remme.io/remme-core/docs/family-pub-key.html
            - https://github.com/Remmeauth/remme-client-python/blob/develop/remme/remme_public_key_storage.py
        """
        processor = self._get_public_key_processor(transaction_payload=transaction_payload)

        if not processor.verify():
            raise InvalidTransaction('Invalid signature')

        public_key = processor.get_public_key()

        public_key_to_store_address = self.make_address_from_data(public_key)
        sender_account_address = AccountHandler().make_address_from_data(signer_pubkey)

        public_key_information, sender_account = get_multiple_data(context, [
            (public_key_to_store_address, PubKeyStorage),
            (sender_account_address, Account),
        ])
        if public_key_information:
            raise InvalidTransaction('This public key is already registered.')

        if not sender_account:
            sender_account = Account()

        if not self._is_public_key_validity_exceeded(
            valid_from=transaction_payload.valid_from,
            valid_to=transaction_payload.valid_to,
        ):
            raise InvalidTransaction('The public key validity exceeds the maximum value.')

        public_key_information = PubKeyStorage()
        public_key_information.owner = signer_pubkey
        public_key_information.payload.CopyFrom(transaction_payload)
        public_key_information.is_revoked = False

        state = {
            sender_account_address: sender_account,
            public_key_to_store_address: public_key_information,
        }

        charging_state = self._charge_for_storing(context=context, address_from=sender_account_address)
        if charging_state is not None:
            state.update(charging_state)
            sender_account = state.get(sender_account_address)

        sender_account = self._store_public_key_to_account(
            public_key_to_store_address=public_key_to_store_address,
            public_key_to_store_owner_account=sender_account,
        )

        state.update({
            sender_account_address: sender_account,
        })

        return state
Ejemplo n.º 28
0
    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
Ejemplo n.º 29
0
class RestApiTestCase(HelperTestCase):
    @classmethod
    def setUpClass(cls):
        super().setUpClass(AccountHandler, AccountClient)
        flask_app = connexion.FlaskApp('remme.rest_api')
        flask_app.add_api(
            resource_filename('remme.rest_api', 'openapi.yml'),
            resolver=RestMethodsSwitcherResolver('remme.rest_api'))
        cls.client = flask_app.app.test_client()

    @staticmethod
    def create_raw_transaction_send_token_payload(pub_key_to, amount=1):
        client = AccountClient()
        signer = client._signer
        address = client.make_address_from_data(pub_key_to)
        node_address = client.get_user_address()

        transfer = TransferPayload()
        transfer.address_to = address
        transfer.value = amount

        tr = TransactionPayload()
        tr.method = AccountMethod.TRANSFER
        tr.data = transfer.SerializeToString()

        payload = tr.SerializeToString()

        header = TransactionHeader(
            signer_public_key=signer.get_public_key().as_hex(),
            family_name=client._family_handler.family_name,
            family_version=client._family_handler.family_versions[-1],
            inputs=[node_address, address],
            outputs=[node_address, address],
            dependencies=[],
            payload_sha512=hash512(payload),
            batcher_public_key=signer.get_public_key().as_hex(),
            nonce=time.time().hex().encode()).SerializeToString()

        signature = signer.sign(header)

        transaction = Transaction(header=header,
                                  payload=payload,
                                  header_signature=signature)
        return transaction

    @test
    def test_node_key_retrieve_info_and_it_ok(self):
        response = self.client.get('/api/v1/node_key')
        self.assertEqual(response.status_code, 200)
        self.assertTrue('pubkey' in response.get_json())

    @test
    @mock.patch(
        'remme.clients.basic.BasicClient.submit_batches',
        return_value={
            'link':
            'http://rest-api:8080/batch_statuses?id=c6bcb01255c1870a5d42fe2dde5e91fb0c5992ec0b49932cdab901539bf977f75bb7699c053cea16668ba732a7d597dd0c2b80f157f1a2514932078bb761de4b'
        })
    def test_valid_raw_transaction_send_to_the_node(self, req_mock):
        payload = self.create_raw_transaction_send_token_payload(
            '03823c7a9e285246985089824f3aaa51fb8675d08d84b151833ca5febce37ad61e',
            1)
        response = self.client.post(
            '/api/v1/transaction',
            data=json.dumps({
                'transaction':
                base64.b64encode(payload.SerializeToString()).decode('utf-8')
            }),
            content_type='application/json')
        self.assertEqual(response.status_code, 200,
                         'Error: %s' % response.get_data())
        self.assertTrue('batch_id' in response.get_json())

    @test
    @mock.patch(
        'remme.clients.basic.BasicClient.submit_batches',
        return_value={
            'link':
            'http://rest-api:8080/batch_statuses?id=c6bcb01255c1870a5d42fe2dde5e91fb0c5992ec0b49932cdab901539bf977f75bb7699c053cea16668ba732a7d597dd0c2b80f157f1a2514932078bb761de4b'
        })
    def test_token_send(self, req_mock):
        response = self.client.post(
            '/api/v1/token',
            data=json.dumps({
                "pub_key_to":
                "03823c7a9e285246985089824f3aaa51fb8675d08d84b151833ca5febce37ad61e",
                "amount": 1
            }),
            content_type='application/json')
        self.assertEqual(response.status_code, 200,
                         'Error: %s' % response.get_data())
        self.assertTrue('batch_id' in response.get_json())

    @test
    @mock.patch('remme.clients.basic.BasicClient.fetch_state',
                return_value={
                    'data':
                    base64.b64encode(Account(balance=100).SerializeToString())
                })
    @mock.patch('remme.clients.basic.BasicClient.get_root_block',
                return_value=(None, 'some_root'))
    def test_get_token_balance(self, root_mock, fetch_state_mock):
        pubkey = '03823c7a9e285246985089824f3aaa51fb8675d08d84b151833ca5febce37ad61a'
        response = self.client.get(f'/api/v1/token/{pubkey}')
        self.assertEqual(response.status_code, 200,
                         'Error: %s' % response.get_data())
        self.assertEqual(response.get_json()['balance'], 100)

    @test
    @mock.patch('remme.clients.basic.BasicClient.get_batch_statuses',
                return_value={'data': [{
                    'status': 'COMMITTED'
                }]})
    def test_check_batch_status(self, batch_status_mock):
        batch_id = '3936f0fa13d008c2b00d04013dfa5e5359fccc117e4c47b1416ee24e115ac08b08707be3b3ce6956ca3d789d245ff0dddf7a39bc2b2f4210ffe81ebd0244c014'
        response = self.client.get(f'/api/v1/batch_status/{batch_id}')
        self.assertEqual(response.status_code, 200,
                         'Error: %s' % response.get_data())
        resp = response.get_json()
        self.assertEqual(resp['batch_id'], batch_id)
        self.assertEqual(resp['status'], 'COMMITTED')
Ejemplo n.º 30
0
def test_atomic_swap_init_swap_not_enough_balance():
    """
    Case: initialize swap of bot's Remme node tokens to Alice's ERC20 Remme tokens with not enough bot address balance.
    Expect: invalid transaction error is raised with not enough balance error message.
    """

    atomic_swap_init_payload = AtomicSwapInitPayload(
        receiver_address=ALICE_ADDRESS,
        sender_address_non_local=BOT_ETHEREUM_ADDRESS,
        amount=TOKENS_AMOUNT_TO_SWAP,
        swap_id=SWAP_ID,
        secret_lock_by_solicitor=BOT_IT_IS_INITIATOR_MARK,
        email_address_encrypted_by_initiator=ALICE_EMAIL_ADDRESS_ENCRYPTED_BY_INITIATOR,
        created_at=CURRENT_TIMESTAMP,
    )

    transaction_payload = TransactionPayload()
    transaction_payload.method = AtomicSwapMethod.INIT
    transaction_payload.data = atomic_swap_init_payload.SerializeToString()

    serialized_transaction_payload = transaction_payload.SerializeToString()

    transaction_header = TransactionHeader(
        signer_public_key=BOT_PUBLIC_KEY,
        family_name=TRANSACTION_REQUEST_ACCOUNT_HANDLER_PARAMS.get('family_name'),
        family_version=TRANSACTION_REQUEST_ACCOUNT_HANDLER_PARAMS.get('family_version'),
        inputs=INPUTS,
        outputs=OUTPUTS,
        dependencies=[],
        payload_sha512=hash512(data=serialized_transaction_payload),
        batcher_public_key=RANDOM_NODE_PUBLIC_KEY,
        nonce=time.time().hex().encode(),
    )

    serialized_header = transaction_header.SerializeToString()

    transaction_request = TpProcessRequest(
        header=transaction_header,
        payload=serialized_transaction_payload,
        signature=create_signer(private_key=BOT_PRIVATE_KEY).sign(serialized_header),
    )

    bot_account = Account()
    bot_account.balance = 0
    serialized_bot_account_balance = bot_account.SerializeToString()

    swap_commission_setting = Setting()
    swap_commission_setting.entries.add(key=SETTINGS_SWAP_COMMISSION, value=str(SWAP_COMMISSION_AMOUNT))
    serialized_swap_commission_setting = swap_commission_setting.SerializeToString()

    mock_context = StubContext(inputs=INPUTS, outputs=OUTPUTS, initial_state={
        BLOCK_INFO_CONFIG_ADDRESS: SERIALIZED_BLOCK_INFO_CONFIG,
        BLOCK_INFO_ADDRESS: SERIALIZED_BLOCK_INFO,
        BOT_ADDRESS: serialized_bot_account_balance,
        ADDRESS_TO_GET_SWAP_COMMISSION_AMOUNT_BY: serialized_swap_commission_setting,
    })

    with pytest.raises(InvalidTransaction) as error:
        AtomicSwapHandler().apply(transaction=transaction_request, context=mock_context)

    total_amount = TOKENS_AMOUNT_TO_SWAP + SWAP_COMMISSION_AMOUNT

    assert f'Not enough balance to perform the transaction in the amount (with a commission) {total_amount}.' \
           == str(error.value)