Example #1
0
    def decode(cls, data):
        packed = messages.wrap(data)

        if packed is None:
            return None

        # signature must be at the end
        message_type = type(packed)
        signature = message_type.fields_spec[-1]
        assert signature.name == 'signature', 'signature is not the last field'

        message_data = data[:-signature.size_bytes]
        message_signature = data[-signature.size_bytes:]
        message_hash = sha3(message_data)

        data_that_was_signed = pack_signing_data(
            message_type.get_bytes_from(data, 'nonce'),
            message_type.get_bytes_from(data, 'transferred_amount'),
            # Locked amount should get signed when smart contracts change to include it
            # message_type.get_bytes_from(data, 'locked_amount'),
            message_type.get_bytes_from(data, 'channel'),
            message_type.get_bytes_from(data, 'locksroot'),
            message_hash,
        )

        address = signing.recover_address(data_that_was_signed, message_signature)

        if address is None:
            return None

        message = cls.unpack(packed)  # pylint: disable=no-member
        message.sender = address
        return message
Example #2
0
    def decode(cls, data):
        packed = messages.wrap(data)

        if packed is None:
            return None

        # signature must be at the end
        message_type = type(packed)
        signature = message_type.fields_spec[-1]
        assert signature.name == 'signature', 'signature is not the last field'

        message_data = data[:-signature.size_bytes]
        message_signature = data[-signature.size_bytes:]
        message_hash = sha3(message_data)

        data_that_was_signed = pack_signing_data(
            message_type.get_bytes_from(data, 'nonce'),
            message_type.get_bytes_from(data, 'transferred_amount'),
            message_type.get_bytes_from(data, 'channel'),
            message_type.get_bytes_from(data, 'locksroot'),
            message_hash,
        )

        publickey = recover_publickey_safe(data_that_was_signed,
                                           message_signature)

        if publickey is None:
            return None

        message = cls.unpack(packed)  # pylint: disable=no-member
        message.sender = publickey_to_address(publickey)
        return message
Example #3
0
def make_signed_balance_proof(
    nonce,
    transferred_amount,
    locked_amount,
    token_network_address,
    channel_address,
    locksroot,
    extra_hash,
    private_key,
    sender_address,
):

    data_to_sign = balance_proof.signing_data(
        nonce,
        transferred_amount,
        locked_amount,
        channel_address,
        locksroot,
        extra_hash,
    )

    balance_hash = hash_balance_data(
        transferred_amount,
        locked_amount,
        locksroot,
    )
    data_to_sign = balance_proof.pack_signing_data(
        nonce=nonce,
        balance_hash=balance_hash,
        additional_hash=extra_hash,
        channel_identifier=channel_address,
        token_network_identifier=token_network_address,
        chain_id=UNIT_CHAIN_ID,
    )

    signature = signing.sign(data_to_sign, private_key)

    signed_balance_proof = BalanceProofSignedState(
        nonce,
        transferred_amount,
        locked_amount,
        locksroot,
        token_network_address,
        channel_address,
        extra_hash,
        signature,
        sender_address,
        UNIT_CHAIN_ID,
    )

    return signed_balance_proof
Example #4
0
def make_signed_balance_proof(
        nonce,
        transferred_amount,
        locked_amount,
        token_network_address,
        channel_address,
        locksroot,
        extra_hash,
        private_key,
        sender_address,
):

    data_to_sign = balance_proof.signing_data(
        nonce,
        transferred_amount,
        locked_amount,
        channel_address,
        locksroot,
        extra_hash,
    )

    balance_hash = hash_balance_data(
        transferred_amount,
        locked_amount,
        locksroot,
    )
    data_to_sign = balance_proof.pack_signing_data(
        nonce=nonce,
        balance_hash=balance_hash,
        additional_hash=extra_hash,
        channel_identifier=channel_address,
        token_network_identifier=token_network_address,
        chain_id=UNIT_CHAIN_ID,
    )

    signature = signing.sign(data_to_sign, private_key)

    signed_balance_proof = BalanceProofSignedState(
        nonce,
        transferred_amount,
        locked_amount,
        locksroot,
        token_network_address,
        channel_address,
        extra_hash,
        signature,
        sender_address,
        UNIT_CHAIN_ID,
    )

    return signed_balance_proof
Example #5
0
 def _data_to_sign(self) -> bytes:
     balance_hash = hash_balance_data(
         self.transferred_amount,
         self.locked_amount,
         self.locksroot,
     )
     balance_proof_packed = pack_signing_data(
         nonce=self.nonce,
         balance_hash=balance_hash,
         additional_hash=self.message_hash,
         channel_identifier=self.channel_identifier,
         token_network_identifier=self.token_network_address,
         chain_id=self.chain_id,
     )
     return balance_proof_packed
Example #6
0
 def _data_to_sign(self) -> bytes:
     balance_hash = hash_balance_data(
         self.transferred_amount,
         self.locked_amount,
         self.locksroot,
     )
     balance_proof_packed = pack_signing_data(
         nonce=self.nonce,
         balance_hash=balance_hash,
         additional_hash=self.message_hash,
         channel_identifier=self.channel,
         token_network_identifier=self.token_network_address,
         chain_id=self.chain_id,
     )
     return balance_proof_packed
Example #7
0
    def data_to_sign(self):
        """ Returns an encoded subset of the fields to sign """
        packed = self.packed()
        klass = type(packed)

        field = klass.fields_spec[-1]
        assert field.name == 'signature', 'signature is not the last field'

        data = packed.data
        return pack_signing_data(
            klass.get_bytes_from(data, 'nonce'),
            klass.get_bytes_from(data, 'transferred_amount'),
            klass.get_bytes_from(data, 'locked_amount'),
            klass.get_bytes_from(data, 'channel'),
            klass.get_bytes_from(data, 'locksroot'),
            self.message_hash,
        )
Example #8
0
    def sign(self, private_key, node_address):
        packed = self.packed()
        klass = type(packed)

        field = klass.fields_spec[-1]
        assert field.name == 'signature', 'signature is not the last field'

        data = packed.data
        data_to_sign = pack_signing_data(
            klass.get_bytes_from(data, 'nonce'),
            klass.get_bytes_from(data, 'transferred_amount'),
            klass.get_bytes_from(data, 'channel'),
            klass.get_bytes_from(data, 'locksroot'),
            self.message_hash,
        )
        signature = signing.sign(data_to_sign, private_key)

        packed.signature = signature

        self.sender = node_address
        self.signature = signature
Example #9
0
def find_max_pending_transfers(gas_limit):
    """Measure gas consumption of TokenNetwork.unlock() depending on number of
    pending transfers and find the maximum number of pending transfers so
    gas_limit is not exceeded."""

    tester = ContractTester(generate_keys=2)

    tester.deploy_contract('SecretRegistry')

    tester.deploy_contract(
        'HumanStandardToken',
        _initialAmount=100000,
        _decimalUnits=3,
        _tokenName='SomeToken',
        _tokenSymbol='SMT',
    )

    tester.deploy_contract(
        'TokenNetwork',
        _token_address=tester.contract_address('HumanStandardToken'),
        _secret_registry=tester.contract_address('SecretRegistry'),
        _chain_id=1,
        _settlement_timeout_min=100,
        _settlement_timeout_max=200,
    )

    tester.call_transaction(
        'HumanStandardToken',
        'transfer',
        _to=tester.accounts[1],
        _value=10000,
    )

    receipt = tester.call_transaction(
        'TokenNetwork',
        'openChannel',
        participant1=tester.accounts[0],
        participant2=tester.accounts[1],
        settle_timeout=150,
    )

    channel_identifier = receipt['logs'][0]['topics'][1]

    tester.call_transaction(
        'HumanStandardToken',
        'approve',
        sender=tester.accounts[0],
        _spender=tester.contract_address('TokenNetwork'),
        _value=10000,
    )

    tester.call_transaction(
        'HumanStandardToken',
        'approve',
        sender=tester.accounts[1],
        _spender=tester.contract_address('TokenNetwork'),
        _value=5000,
    )

    tester.call_transaction(
        'TokenNetwork',
        'setTotalDeposit',
        participant=tester.accounts[0],
        total_deposit=5000,
        partner=tester.accounts[1],
    )

    tester.call_transaction(
        'TokenNetwork',
        'setTotalDeposit',
        participant=tester.accounts[1],
        total_deposit=2000,
        partner=tester.accounts[0],
    )

    print(
        "Measuring unlock()'s gas cost for different Merkle tree widths, can take a while..."
    )

    before_closing = tester.tester.take_snapshot()
    enough = 0
    too_much = 1024

    nonce = 10
    additional_hash = urandom(32)
    token_network_identifier = tester.contract_address('TokenNetwork')

    while enough + 1 < too_much:
        tree_size = (enough + too_much) // 2
        tester.tester.revert_to_snapshot(before_closing)

        pending_transfers_tree = get_pending_transfers_tree(
            tester.web3,
            unlockable_amounts=[1] * tree_size,
        )

        balance_hash = hash_balance_data(3000, 2000,
                                         pending_transfers_tree.merkle_root)
        data_to_sign = pack_signing_data(
            nonce,
            balance_hash,
            additional_hash,
            channel_identifier,
            token_network_identifier,
            1,
        )
        signature = sign(data_to_sign, tester.private_keys[1])

        tester.call_transaction(
            'TokenNetwork',
            'closeChannel',
            partner=tester.accounts[1],
            balance_hash=balance_hash,
            nonce=nonce,
            additional_hash=additional_hash,
            signature=signature,
        )

        tester.tester.mine_blocks(160)  # close settlement window

        tester.call_transaction(
            'TokenNetwork',
            'settleChannel',
            participant1=tester.accounts[0],
            participant1_transferred_amount=0,
            participant1_locked_amount=0,
            participant1_locksroot=b'\x00' * 32,
            participant2=tester.accounts[1],
            participant2_transferred_amount=3000,
            participant2_locked_amount=2000,
            participant2_locksroot=pending_transfers_tree.merkle_root,
        )

        receipt = tester.call_transaction(
            'TokenNetwork',
            'unlock',
            participant=tester.accounts[0],
            partner=tester.accounts[1],
            merkle_tree_leaves=pending_transfers_tree.packed_transfers,
        )
        gas_used = receipt['gasUsed']

        if gas_used <= gas_limit:
            enough = tree_size
            print(
                f'{tree_size} pending transfers work ({gas_used} gas needed to unlock)'
            )
        else:
            too_much = tree_size
            print(
                f'{tree_size} pending transfers are too much ({gas_used} gas needed to unlock)'
            )