def newFilter(self, filter_dict): if not isinstance(filter_dict, dict): raise BadRequestError('Filter must be an object') required_keys = set(['fromBlock', 'toBlock']) if not required_keys.issubset(set(filter_dict.keys())): raise BadRequestError('Invalid filter object') b0 = self.json_rpc_server.get_block(block_id_decoder(filter_dict['fromBlock'])) b1 = self.json_rpc_server.get_block(block_id_decoder(filter_dict['toBlock'])) if b1.number < b0.number: raise BadRequestError('fromBlock must be prior or equal to toBlock') address = filter_dict.get('address', None) if is_string(address): addresses = [address_decoder(address)] elif isinstance(address, Iterable): addresses = [address_decoder(addr) for addr in address] elif address is None: addresses = None else: raise JSONRPCInvalidParamsError('Parameter must be address or list of addresses') topics = [data_decoder(topic) for topic in filter_dict.get('topics', [])] blocks = [b1] while blocks[-1] != b1: blocks.append(blocks[-1].get_parent()) filter_ = Filter(self.chain.chain, reversed(blocks), addresses, topics) self.filters[self.next_id] = filter_ self.next_id += 1 return self.next_id - 1
def data_decoder(data): """Decode `data` representing unformatted data.""" if not data.startswith('0x'): data = '0x' + data if len(data) % 2 != 0: raise BadRequestError('Invalid data encoding, must be even length') try: return decode_hex(data[2:]) except TypeError: raise BadRequestError('Invalid data hex encoding', data[2:])
def play_index(self, index): """Start playback of the specified song.""" self.logger.info('[RPC] wotabag.play_index {}'.format(index)) if index >= len(self.playlist) or index < 0: raise BadRequestError('Invalid song index') self.current_track = index self._play()
def set_color(self, color): """Set all LEDs to the specified color or color sequence.""" self.logger.info('[RPC] wotabag.set_color {}'.format(color)) if color == 'Aqours Rainbow': colors = aqours_rainbow elif color in aqours_units: colors = aqours_units[color] elif color == 'Saint Snow': colors = saint_snow elif color in muse_units: colors = muse_units[color] elif color.upper() in BladeColor.__members__: colors = (BladeColor[color.upper()],) else: raise BadRequestError('Unknown color') strip = self.strip if len(colors) == 1: for i in range(strip.numPixels()): strip.setPixelColor(i, colors[0].value) strip.show() elif len(colors) <= 3: if len(colors) == 2: colors = colors + (colors[0],) for x, color in (enumerate(colors)): for y in range(9): strip.setPixelColor(pixel_index(x, y), color.value) strip.show() elif len(colors) == 9: for x in range(3): for y, color in enumerate(colors): strip.setPixelColor(pixel_index(x, y), color.value) strip.show()
def address_decoder(data): """Decode an address from hex with 0x prefix to 20 bytes.""" if not data.startswith('0x'): data = '0x' + data addr = data_decoder(data) if len(addr) not in (20, 0): raise BadRequestError('Addresses must be 20 or 0 bytes long') return addr
def getFilterLogs(self, id_): if id_ not in self.filters: raise BadRequestError('Unknown filter') filter_ = self.filters[id_] if filter_.pending or filter_.latest: return [None] * len(filter_.logs) else: return self.filters[id_].logs
def call(self, data, block_id=None): block = self.json_rpc_server.get_block(block_id) state_root_before = block.state_root # rebuild block state before finalization if block.has_parent(): parent = block.get_parent() test_block = block.init_from_parent(parent, block.coinbase, timestamp=block.timestamp) for tx in block.get_transactions(): success, output = processblock.apply_transaction(test_block, tx) assert success else: original = block.snapshot() original['journal'] = deepcopy(original['journal']) # do not alter original journal test_block = ethereum.blocks.genesis(block.db) test_block.revert(original) # validate transaction if not isinstance(data, dict): raise BadRequestError('Transaction must be an object') to = address_decoder(data['to']) try: startgas = quantity_decoder(data['gas']) except KeyError: startgas = block.gas_limit - block.gas_used try: gasprice = quantity_decoder(data['gasPrice']) except KeyError: gasprice = 0 try: value = quantity_decoder(data['value']) except KeyError: value = 0 try: data_ = data_decoder(data['data']) except KeyError: data_ = b'' try: sender = address_decoder(data['from']) except KeyError: sender = '\x00' * 20 # apply transaction nonce = test_block.get_nonce(sender) tx = Transaction(nonce, gasprice, startgas, to, value, data_) tx.sender = sender try: success, output = processblock.apply_transaction(test_block, tx) except processblock.InvalidTransaction: success = False assert block.state_root == state_root_before if success: return output else: return False
def data_decoder(data): """Decode `data` representing unformatted data.""" if not data.startswith('0x'): data = '0x' + data if len(data) % 2 != 0: success = False # must be even length else: try: return decode_hex(data[2:]) except TypeError: success = False assert not success raise BadRequestError('Invalid data encoding')
def newFilter(self, filter_dict): if not isinstance(filter_dict, dict): raise BadRequestError('Filter must be an object') b0 = self.json_rpc_server.get_block( block_id_decoder(filter_dict.get('fromBlock', 'latest'))) b1 = self.json_rpc_server.get_block( block_id_decoder(filter_dict.get('toBlock', 'latest'))) if b1.number < b0.number: raise BadRequestError( 'fromBlock must be prior or equal to toBlock') address = filter_dict.get('address', None) if is_string(address): addresses = [address_decoder(address)] elif isinstance(address, Iterable): addresses = [address_decoder(addr) for addr in address] elif address is None: addresses = None else: raise JSONRPCInvalidParamsError( 'Parameter must be address or list of addresses') if 'topics' in filter_dict: topics = [] for topic in filter_dict['topics']: if topic is not None: topics.append(big_endian_to_int(data_decoder(topic))) else: topics.append(None) else: topics = None blocks = [b1] while blocks[-1] != b0: blocks.append(blocks[-1].get_parent()) filter_ = Filter(self.chain.chain, reversed(blocks), addresses, topics) self.filters[self.next_id] = filter_ self.next_id += 1 return self.next_id - 1
def getFilterChanges(self, id_): if id_ not in self.filters: raise BadRequestError('Unknown filter') filter_ = self.filters[id_] logger.debug('filter found', filter=filter_) if isinstance(filter_, NewBlockFilter): # For filters created with eth_newBlockFilter the return are block hashes # (DATA, 32 Bytes), e.g. ["0x3454645634534..."]. r = filter_.check() if r: logger.debug('returning newblock', ts=time.time()) return [data_encoder(r.hash)] else: return [] else: return loglist_encoder(filter_.new_logs)
def sendTransaction(self, data): """ extend spec to support v,r,s signed transactions """ if not isinstance(data, dict): raise BadRequestError('Transaction must be an object') def get_data_default(key, decoder, default=None): if key in data: return decoder(data[key]) return default to = get_data_default('to', address_decoder, b'') startgas = get_data_default('gas', quantity_decoder, default_startgas) gasprice = get_data_default('gasPrice', quantity_decoder, default_gasprice) value = get_data_default('value', quantity_decoder, 0) data_ = get_data_default('data', data_decoder, b'') v = signed = get_data_default('v', quantity_decoder, 0) r = get_data_default('r', quantity_decoder, 0) s = get_data_default('s', quantity_decoder, 0) nonce = get_data_default('nonce', quantity_decoder, None) sender = get_data_default('from', address_decoder, self.app.services.accounts.coinbase) # create transaction if signed: assert nonce is not None, 'signed but no nonce provided' assert v and r and s else: nonce = self.app.services.chain.chain.head_candidate.get_nonce( sender) tx = Transaction(nonce, gasprice, startgas, to, value, data_, v, r, s) if not signed: assert sender in self.app.services.accounts, 'no account for sender' self.app.services.accounts.sign_tx(sender, tx) self.app.services.chain.add_transaction(tx, origin=None) log.debug('decoded tx', tx=tx.to_dict()) if to == b'': # create return address_encoder( processblock.mk_contract_address(tx.sender, nonce)) else: return data_encoder(tx.hash)
def quantity_decoder(data): """Decode `data` representing a quantity.""" if not is_string(data): success = False elif not data.startswith('0x'): success = False # must start with 0x prefix elif len(data) > 3 and data[2] == '0': success = False # must not have leading zeros (except `0x0`) else: data = data[2:] # ensure even length if len(data) % 2 == 1: data = '0' + data try: return int(data, 16) except ValueError: success = False assert not success raise BadRequestError('Invalid quantity encoding')
def bool_decoder(data): if not isinstance(data, bool): raise BadRequestError('Parameter must be boolean') return data
def tx_hash_decoder(data): """Decode a transaction hash.""" decoded = data_decoder(data) if len(decoded) != 32: raise BadRequestError('Transaction hashes must be 32 bytes long') return decoded
def block_hash_decoder(data): """Decode a block hash.""" decoded = data_decoder(data) if len(decoded) != 32: raise BadRequestError('Block hashes must be 32 bytes long') return decoded