def unlock(self, ctx, locked_encoded, merkleproof_encoded, secret): if self.settled is not 0: raise RuntimeError('Contract is settled.') if self.closed is 0: raise RuntimeError('Contract is open.') if ctx['msg.sender'] not in self.participants: raise ValueError('Unknow address.') partner = self.partner(ctx['msg.sender']) state = self.participants[partner] transfer = state.transfer # if partner haven't made a single transfer if transfer is None: return merkle_proof = tuple32(merkleproof_encoded) lock = Lock.from_bytes(locked_encoded) hashlock = lock.hashlock if hashlock != sha3(secret): raise ValueError('Invalid secret') is_valid_proof = check_proof( merkle_proof, transfer.locksroot, sha3(lock.as_bytes), ) if not is_valid_proof: raise ValueError('Invalid merkle proof') transfer.append(lock)
def unlock(self, ctx, locked_encoded, merkleproof_encoded, secret): if self.settled is not None: raise RuntimeError('Contract is settled.') if self.closed is None: raise RuntimeError('Contract is open.') if ctx['msg.sender'] not in self.participants: raise ValueError('Unknow address.') partner = self.partner(ctx['msg.sender']) state = self.participants[partner] transfer = state.transfer # if partner haven't made a single transfer if transfer is None: return merkle_proof = tuple32(merkleproof_encoded) lock = Lock.from_bytes(locked_encoded) hashlock = lock.hashlock if hashlock != sha3(secret): raise ValueError('Invalid secret') is_valid_proof = check_proof( merkle_proof, transfer.locksroot, sha3(transfer.lock.as_bytes), ) if not is_valid_proof: raise ValueError('Invalid merkle proof') transfer.append(lock)
def handle_contract_send_channelunlock( raiden: RaidenService, channel_unlock_event: ContractSendChannelBatchUnlock, ): channel = raiden.chain.netting_channel(channel_unlock_event.channel_identifier) block_number = raiden.get_block_number() for unlock_proof in channel_unlock_event.unlock_proofs: lock = Lock.from_bytes(unlock_proof.lock_encoded) if lock.expiration < block_number: log.error('Lock has expired!', lock=lock) else: channel.unlock(unlock_proof)
def handle_contract_channelwithdraw( raiden: 'RaidenService', channel_withdraw_event: ContractSendChannelWithdraw): channel = raiden.chain.netting_channel( channel_withdraw_event.channel_identifier) block_number = raiden.get_block_number() for unlock_proof in channel_withdraw_event.unlock_proofs: lock = Lock.from_bytes(unlock_proof.lock_encoded) if lock.expiration < block_number: log.error('Lock has expired!', lock=lock) else: channel.withdraw(unlock_proof)
def close( self, ctx, sender, transfers_encoded, locked_encoded, # noqa merkleproof_encoded, secret): """" Request the closing of the channel. Can be called multiple times. lock period starts with first valid call. Args: sender (address): The sender address. transfers_encoded (List[transfer]): A list of maximum length of 2 containing the transfer encoded using the fixed length format, may be empty. ctx: Block chain state used for mocking. locked_encoded (bin): The Lock to be unlocked. merkleproof_encoded (bin): A proof that the given lock is contained in the latest transfer. The binary data is composed of a single hash at every 4bytes. secret (bin): The secret that unlocks the lock `hashlock = sha3(secret)`. Todo: if challenged, keep track of who provided the last valid answer, punish the wrongdoer here, check that participants only updates their own balance are counted, because they could sign something for the other party to blame it. """ # pylint: disable=too-many-arguments,too-many-locals,too-many-branches # if len(transfers_encoded): # raise ValueError('transfers_encoded needs at least 1 item.') if len(transfers_encoded) > 2: raise ValueError( 'transfers_encoded cannot have more than 2 items.') if self.settled: raise RuntimeError('contract is settled') # the merkleproof can be empty, if there is only one haslock has_oneofunlocked = locked_encoded or secret has_allofunlocked = locked_encoded and secret if has_oneofunlocked and not has_allofunlocked: raise ValueError( 'all arguments `merkle_proof`, `locked`, and `secret` must be provided' ) last_sent_transfers = [] for data in transfers_encoded: if data[0] == DIRECTTRANSFER: last_sent_transfers.append(DirectTransfer.decode(data)) elif data[0] == MEDIATEDTRANSFER: last_sent_transfers.append(MediatedTransfer.decode(data)) elif data[0] == CANCELTRANSFER: last_sent_transfers.append(CancelTransfer.decode(data)) # convinience for testing only (LockedTransfer are not exchanged between nodes) elif data[0] == LOCKEDTRANSFER: last_sent_transfers.append(LockedTransfer.decode(data)) else: raise ValueError('invalid transfer type {}'.format( type(data[0]))) # keep the latest claim for transfer in last_sent_transfers: if transfer.sender not in self.participants: raise ValueError( 'Invalid tansfer, sender is not a participant') sender_state = self.participants[transfer.sender] if is_newer_transfer(transfer, sender_state): sender_state['last_sent_transfer'] = transfer partner = self.partner(sender) partner_state = self.participants[partner] if last_sent_transfers: transfer = last_sent_transfers[-1] # XXX: check me # register un-locked if merkleproof_encoded: merkle_proof = tuple32(merkleproof_encoded) lock = Lock.from_bytes(locked_encoded) hashlock = lock.hashlock if hashlock != sha3(secret): raise ValueError('invalid secret') # the partner might not have made a transfer if partner_state['last_sent_transfer'] is not None: assert check_proof( merkle_proof, partner_state['last_sent_transfer'].locksroot, sha3(transfer.lock.as_bytes), ) partner_state['unlocked'].append(lock) if self.closed is None: log.debug('closing contract', netcontract_address=pex(self.netcontract_address)) self.closed = ctx['block_number']
def close(self, ctx, sender, transfers_encoded, locked_encoded, # noqa merkleproof_encoded, secret): """" Request the closing of the channel. Can be called multiple times. lock period starts with first valid call. Args: sender (address): The sender address. transfers_encoded (List[transfer]): A list of maximum length of 2 containing the transfer encoded using the fixed length format, may be empty. ctx: Block chain state used for mocking. locked_encoded (bin): The Lock to be unlocked. merkleproof_encoded (bin): A proof that the given lock is contained in the latest transfer. The binary data is composed of a single hash at every 4bytes. secret (bin): The secret that unlocks the lock `hashlock = sha3(secret)`. Todo: if challenged, keep track of who provided the last valid answer, punish the wrongdoer here, check that participants only updates their own balance are counted, because they could sign something for the other party to blame it. """ # pylint: disable=too-many-arguments,too-many-locals,too-many-branches # if len(transfers_encoded): # raise ValueError('transfers_encoded needs at least 1 item.') if len(transfers_encoded) > 2: raise ValueError('transfers_encoded cannot have more than 2 items.') if self.settled: raise RuntimeError('contract is settled') # the merkleproof can be empty, if there is only one haslock has_oneofunlocked = locked_encoded or secret has_allofunlocked = locked_encoded and secret if has_oneofunlocked and not has_allofunlocked: raise ValueError( 'all arguments `merkle_proof`, `locked`, and `secret` must be provided' ) last_sent_transfers = [] for data in transfers_encoded: if data[0] == DIRECTTRANSFER: last_sent_transfers.append( DirectTransfer.decode(data) ) elif data[0] == MEDIATEDTRANSFER: last_sent_transfers.append( MediatedTransfer.decode(data) ) elif data[0] == CANCELTRANSFER: last_sent_transfers.append( CancelTransfer.decode(data) ) # convinience for testing only (LockedTransfer are not exchanged between nodes) elif data[0] == LOCKEDTRANSFER: last_sent_transfers.append( LockedTransfer.decode(data) ) else: raise ValueError('invalid transfer type {}'.format(type(data[0]))) # keep the latest claim for transfer in last_sent_transfers: if transfer.sender not in self.participants: raise ValueError('Invalid tansfer, sender is not a participant') sender_state = self.participants[transfer.sender] if is_newer_transfer(transfer, sender_state): sender_state['last_sent_transfer'] = transfer partner = self.partner(sender) partner_state = self.participants[partner] if last_sent_transfers: transfer = last_sent_transfers[-1] # XXX: check me # register un-locked if merkleproof_encoded: merkle_proof = tuple32(merkleproof_encoded) lock = Lock.from_bytes(locked_encoded) hashlock = lock.hashlock if hashlock != sha3(secret): raise ValueError('invalid secret') # the partner might not have made a transfer if partner_state['last_sent_transfer'] is not None: assert check_proof( merkle_proof, partner_state['last_sent_transfer'].locksroot, sha3(transfer.lock.as_bytes), ) partner_state['unlocked'].append(lock) if self.closed is None: log.debug('closing contract', netcontract_address=pex(self.netcontract_address)) self.closed = ctx['block_number']