def decode_transfer(transfer_encoded): if transfer_encoded[0] == DIRECTTRANSFER: return DirectTransfer.decode(transfer_encoded) elif transfer_encoded[0] == MEDIATEDTRANSFER: return MediatedTransfer.decode(transfer_encoded) elif transfer_encoded[0] == CANCELTRANSFER: return CancelTransfer.decode(transfer_encoded) # convinience for testing only (LockedTransfer are not exchanged between nodes) elif transfer_encoded[0] == LOCKEDTRANSFER: return LockedTransfer.decode(transfer_encoded) else: raise ValueError('invalid transfer type {}'.format(type(transfer_encoded[0])))
def decode_transfer(transfer_encoded): if transfer_encoded[0] == DIRECTTRANSFER: return DirectTransfer.decode(transfer_encoded) elif transfer_encoded[0] == MEDIATEDTRANSFER: return MediatedTransfer.decode(transfer_encoded) elif transfer_encoded[0] == REFUNDTRANSFER: return RefundTransfer.decode(transfer_encoded) # convinience for testing only (LockedTransfer are not exchanged between nodes) elif transfer_encoded[0] == LOCKEDTRANSFER: return LockedTransfer.decode(transfer_encoded) else: raise ValueError('invalid transfer type {}'.format(type(transfer_encoded[0])))
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']