def __cache_data_block__(cls, contract_id, raw_data, data_dir="./data"): """ save a data block into the local cache :param contract_id str: contract identifier, base64 encoded :param raw_data str: base64 encoded string """ contract_id = ContractState.safe_filename(contract_id) state_hash = ContractState.compute_hash(raw_data, encoding='b64') state_hash = ContractState.safe_filename(state_hash) cache_dir = os.path.join(data_dir, cls.__path__, contract_id) filename = putils.build_file_name(state_hash, cache_dir, '.ctx') if not os.path.exists(os.path.dirname(filename)): os.makedirs(os.path.dirname(filename)) try: logger.debug('save state block to file %s', filename) with open(filename, 'w') as statefile: statefile.write(raw_data) # json.dump(, statefile) except Exception as e: logger.info('failed to save state; %s', str(e)) raise Exception('unable to cache state {}'.format(filename))
def __read_data_block_from_cache__(cls, contract_id, state_hash, data_dir="./data"): """ read a data block from the local cache :param contract_id str: contract identifier, base64 encoded :param state_hash str: b64 encoded string """ contract_id = ContractState.safe_filename(contract_id) state_hash = ContractState.safe_filename(state_hash) cache_dir = os.path.join(data_dir, cls.__path__, contract_id) filename = putils.build_file_name(state_hash, cache_dir, cls.__extension__) try: logger.debug('read state block from file %s', filename) with open(filename, "r") as statefile: raw_data = statefile.read() except FileNotFoundError as fe: logger.error('file not found; %s', filename) return None except Exception as e: logger.info('error reading state; %s', str(e)) raise Exception( 'failed to read state from cache; {}'.format(contract_id)) return raw_data
def __cache_block_from_eservice__(cls, eservice, contract_id, state_hash, data_dir = None) : """ ensure that a block is cached locally :param eservice EnclaveServiceClient object: :param contract_id str: contract identifier :param state_hash string: base64 encoded hash of the block """ # check to see if the eservice already has the block logger.debug('ensure block %s is stored in the local cache', state_hash) # first see if the block is already in the cache safe_contract_id = ContractState.safe_filename(contract_id) safe_state_hash = ContractState.safe_filename(state_hash) filename = putils.build_file_name(safe_state_hash, data_dir, cls.__path__, cls.__extension__) if os.path.isfile(filename) : return # it is not in the cache so grab it from the eservice raw_data = eservice.block_store_get(state_hash) if raw_data : # since we don't really trust the eservice, make sure that the # block it sent us is really the one that we were supposed to get if ContractState.compute_hash(raw_data, encoding='b64') != state_hash : raise Exception('invalid block returned from eservice') ContractState.__cache_data_block__(contract_id, raw_data, data_dir) logger.debug('sent block %s to eservice', state_hash)
def read_from_file(cls, ledger_config, basename, data_dir='./data'): filename = putils.build_file_name(basename, data_dir, '.pdo') logger.debug('load contract information from %s', filename) if os.path.exists(filename) is not True: raise FileNotFoundError(errno.ENOENT, "contract data file does not exist", filename) try: with open(filename, "r") as contract_file: contract_info = json.load(contract_file) except Exception as e: logger.warn('load contract information file failed; %s', str(e)) raise Exception("invalid contract file; {}".format(filename)) try: code_info = contract_info['contract_code'] code = ContractCode(code_info['Code'], code_info['Name'], code_info['Nonce']) except KeyError as ke: logger.error('invalid contract data file; missing %s', str(ke)) raise Exception("invalid contract file; {}".format(filename)) except Exception as e: logger.error('error occurred retreiving contract code; %s', str(e)) raise Exception("invalid contract file; {}".format(filename)) ## need to handle the case where the contract has been registered ## but the initial state has not been committed try: contract_id = contract_info['contract_id'] current_state_hash = ContractState.get_current_state_hash( ledger_config, contract_id) except Exception as e: logger.error('error occurred retreiving contract state hash; %s', str(e)) raise Exception('invalid contract file; {}'.format(filename)) try: state = ContractState.read_from_cache(contract_id, current_state_hash, data_dir=data_dir) if state is None: state = ContractState.get_from_ledger(ledger_config, contract_id, current_state_hash) state.save_to_cache(data_dir=data_dir) except Exception as e: logger.error('error occurred retreiving contract state; %s', str(e)) raise Exception("invalid contract file; {}".format(filename)) obj = cls(code, state, contract_info['contract_id'], contract_info['creator_id']) for enclave in contract_info['enclaves_info']: obj.set_state_encryption_key( enclave['contract_enclave_id'], enclave['encrypted_contract_state_encryption_key']) return obj
def save_to_file(self, basename, data_dir="./data"): serialized = dict() serialized['contract_id'] = self.contract_id serialized['creator_id'] = self.creator_id serialized['contract_code'] = self.contract_code.serialize() # this encoding is rather verbose, but mirrors the one that the ledger # currently uses enclaves_info = [] for (enclave_id, encrypted_key) in self.enclave_map.items(): enclave_info = {} enclave_info['contract_enclave_id'] = enclave_id enclave_info[ 'encrypted_contract_state_encryption_key'] = encrypted_key enclaves_info.append(enclave_info) serialized['enclaves_info'] = enclaves_info filename = putils.build_file_name(basename, data_dir, '.pdo') try: with open(filename, "w") as contract_file: json.dump(serialized, contract_file) except Exception as e: logger.warn('failed to save contract information; %s', str(e)) raise Exception( 'unable to write contract data file {}'.format(filename))
def read_from_file(cls, basename, data_dir=None, txn_keys=None, block_store=None): """read_from_file -- read enclave data from a file and initialize a new Enclave object with the resulting data. :param file_name: string, name of the file :param search_path: list of strings, directories to search for the data file :param txn_keys: object of type TransactionKeys """ if txn_keys is None: txn_keys = keys.TransactionKeys() filename = putils.build_file_name(basename, data_dir=data_dir, extension='.enc') if os.path.exists(filename) is not True: raise FileNotFoundError(errno.ENOENT, "enclave information file does not exist", filename) logger.debug('load enclave information from %s', filename) with open(filename, "r") as enclave_file: enclave_info = json.load(enclave_file) try: assert 'nonce' in enclave_info assert 'sealed_data' in enclave_info assert 'interpreter' in enclave_info assert 'verifying_key' in enclave_info assert 'encryption_key' in enclave_info assert 'proof_data' in enclave_info assert 'enclave_id' in enclave_info except KeyError as ke: raise Exception('enclave data missing key {0}'.format(str(ke))) except: raise Exception('invalid enclave data file {0}'.format(filename)) try: public_enclave_data = pdo_enclave.get_enclave_public_info( enclave_info['sealed_data']) assert public_enclave_data and len(public_enclave_data) == 2 assert enclave_info['verifying_key'] == public_enclave_data[ 'verifying_key'] assert enclave_info['encryption_key'] == public_enclave_data[ 'encryption_key'] except: raise Exception( 'sealed storage does not match enclave data file; {}'.format( filename)) return cls(enclave_info, txn_keys, block_store)
def __cache_filename__(cls, contract_id, state_hash, data_dir): """ state_hash = base64 encoded """ contract_id = ContractState.safe_filename(contract_id) state_hash = ContractState.safe_filename(state_hash) subdirectory = os.path.join(cls.__path__, contract_id, state_hash[0:2]) return putils.build_file_name(state_hash, data_dir, subdirectory, cls.__extension__)
def save_to_file(self, basename, data_dir = None) : enclave_info = dict() enclave_info['nonce'] = self.nonce enclave_info['sealed_data'] = self.sealed_data enclave_info['verifying_key'] = self.verifying_key enclave_info['encryption_key'] = self.encryption_key enclave_info['proof_data'] = self.proof_data enclave_info['enclave_id'] = self.enclave_id filename = putils.build_file_name(basename, data_dir=data_dir, extension='.enc') logger.debug('save enclave data to %s', filename) with open(filename, "w") as file : json.dump(enclave_info, file)
def save_to_cache(self, data_dir="./data"): contract_id = ContractState.safe_filename(self.contract_id) state_hash = ContractState.compute_hash(self.encrypted_state, encoding='hex') cache_dir = os.path.join(data_dir, self.__path__, contract_id) filename = putils.build_file_name(state_hash, cache_dir, '.ctx') if not os.path.exists(os.path.dirname(filename)): os.makedirs(os.path.dirname(filename)) try: logger.debug('save contract state to file %s', filename) with open(filename, 'w') as statefile: json.dump(self.serialize(), statefile) except Exception as e: logger.info('failed to save state; %s', str(e)) raise Exception('unable to cache state {}'.format(filename))
def create_from_scheme_file(cls, name, source_name=None, search_path=['.', '..', './contracts']): """Create a code object from a Gipsy source file :param name str: the name of the scheme contract class :param source_name str: the name of the source file :param search_path list of str: directories to search for the source file """ if source_name is None: source_name = name basename = putils.build_file_name(source_name, extension='.scm') filename = putils.find_file_in_path(basename, search_path) with open(filename, "r") as cfile: code = cfile.read() return cls(code, name)
def read_from_cache(cls, contract_id, state_hash, data_dir="./data"): contract_id = ContractState.safe_filename(contract_id) state_hash = ContractState.safe_filename(state_hash) cache_dir = os.path.join(data_dir, cls.__path__, contract_id) filename = putils.build_file_name(state_hash, cache_dir, cls.__extension__) try: logger.debug('load contract state from file %s', filename) with open(filename, "r") as statefile: state_info = json.load(statefile) except FileNotFoundError as fe: return None except Exception as e: logger.info('error reading state; %s', str(e)) raise Exception( 'failed to read state from cache; {}'.format(contract_id)) return cls(state_info['ContractID'], state_info.get('EncryptedState'))
def save_to_file(self, basename, data_dir=None): serialized = dict() serialized['extra_data'] = self.extra_data serialized['contract_id'] = self.contract_id serialized['creator_id'] = self.creator_id serialized['contract_code'] = self.contract_code.serialize() # this encoding is rather verbose, but mirrors the one that the ledger # currently uses enclaves_info = [] for (enclave_id, encrypted_key) in self.enclave_map.items(): enclave_info = {} enclave_info['contract_enclave_id'] = enclave_id enclave_info[ 'encrypted_contract_state_encryption_key'] = encrypted_key enclaves_info.append(enclave_info) serialized['enclaves_info'] = enclaves_info # add replication params serialized['num_provable_replicas'] = self.replication_params[ 'num_provable_replicas'] serialized['availability_duration'] = self.replication_params[ 'availability_duration'] filename = putils.build_file_name(basename, data_dir, self.__path__, self.__extension__) try: if not os.path.exists(os.path.dirname(filename)): os.makedirs(os.path.dirname(filename)) with open(filename, "w") as contract_file: json.dump(serialized, contract_file) except Exception as e: logger.warn('failed to save contract information; %s', str(e)) raise Exception( 'unable to write contract data file {}'.format(filename))
def read_from_file(cls, ledger_config, basename, data_dir=None): filename = putils.build_file_name(basename, data_dir, cls.__path__, cls.__extension__) logger.debug('load contract information from %s', filename) if os.path.exists(filename) is not True: raise FileNotFoundError(errno.ENOENT, "contract data file does not exist", filename) try: with open(filename, "r") as contract_file: contract_info = json.load(contract_file) except Exception as e: logger.warn('load contract information file failed; %s', str(e)) raise Exception("invalid contract file; {}".format(filename)) try: code_info = contract_info['contract_code'] comp_report = None if not code_info['CompilationReport'].get( 'CompilerVerifyingKey') is None: comp_report = ContractCompilationReport.init_from_dict( code_info['CompilationReport']) code = ContractCode(code_info['Code'], code_info['Name'], code_info['Nonce'], compilation_report=comp_report) except KeyError as ke: logger.error('invalid contract data file; missing %s', str(ke)) raise Exception("invalid contract file; {}".format(filename)) except Exception as e: logger.error('error occurred retreiving contract code; %s', str(e)) raise Exception("invalid contract file; {}".format(filename)) ## need to handle the case where the contract has been registered ## but the initial state has not been committed try: contract_id = contract_info['contract_id'] current_state_hash = ContractState.get_current_state_hash( ledger_config, contract_id) except Exception as e: logger.error('error occurred retreiving contract state hash; %s', str(e)) raise Exception('invalid contract file; {}'.format(filename)) try: state = ContractState.read_from_cache(contract_id, current_state_hash, data_dir=data_dir) if state is None: state = ContractState.get_from_ledger(ledger_config, contract_id, current_state_hash) state.save_to_cache(data_dir=data_dir) except Exception as e: logger.error('error occurred retreiving contract state; %s', str(e)) raise Exception("invalid contract file; {}".format(filename)) extra_data = contract_info.get('extra_data', {}) obj = cls(code, state, contract_info['contract_id'], contract_info['creator_id'], extra_data=extra_data) for enclave in contract_info['enclaves_info']: obj.set_state_encryption_key( enclave['contract_enclave_id'], enclave['encrypted_contract_state_encryption_key']) obj.set_replication_parameters(contract_info['num_provable_replicas'], contract_info['availability_duration']) return obj