def _del_ccl_state_callback(self, ccl_state, wait): txn = CCL_TransactionPayload() txn.verb = 'delete' dependency = txn.state_update.dependency_list.add() dependency.contract_id = ccl_state.state_update.contract_id dependency.state_hash = ccl_state.state_update.current_state_hash self._send_ccl_transaction(txn, wait)
def execute_json_transaction(self, json_input, address_family, wait, exception_type=None, verbose=False, timeout_exception_type=TimeoutError, transaction_output_list=None, transaction_input_list=None, transaction_dependency_list=None): json_dict = json.loads(json_input) verb = json_dict['verb'] if not verb: if not exception_type: return False raise exception_type("no 'verb' in the json input") if address_family == self.get_enclave_registry_family_name(): txn = PdoContractEnclaveTransaction() txn.verb = verb txn.verifying_key = json_dict.get("verifying_key") if verb == 'register': details = PdoContractEnclaveRegister() proof_data = json_dict.get("proof_data") if proof_data is None or isinstance(proof_data, str): json_format.Parse(json_input, details, ignore_unknown_fields=True) else: if not exception_type: return False raise exception_type("missing or invalid 'proof_data'") elif verb == 'update': details = PdoContractEnclaveUpdate() json_format.Parse(json_input, details, ignore_unknown_fields=True) elif verb == 'delete': details = None else: if not exception_type: return False raise exception_type( "unknown verb in the json input '{}'".format(verb)) if details: txn.transaction_details = txn.transaction_details = details.SerializeToString( ) if verbose: self._dbg_dump.dump_contract_enclave_transaction(txn) self._dbg_dump.dump_enclave_transaction_protobuf_message_to_json( txn) elif address_family == self.get_contract_registry_family_name(): txn = PdoContractTransaction() txn.verb = verb if 'contract_id' in json_dict: txn.contract_id = json_dict.get("contract_id") if verb == 'register': details = PdoContractRegister() elif verb == 'add-enclaves': details = PdoContractAddEnclaves() elif verb == 'remove-enclaves': details = PdoContractRemoveEnclaves() elif verb == 'delete': details = None else: if not exception_type: return False raise exception_type( "unknown verb in the json input '{}'".format(verb)) if details: json_format.Parse(json_input, details, ignore_unknown_fields=True) txn.transaction_details = details.SerializeToString() if verbose: self._dbg_dump.dump_contract_transaction(txn) self._dbg_dump.dump_contract_transaction_protobuf_message_to_json( txn) elif address_family == self.get_ccl_family_name(): if verb not in ['initialize', 'update', 'terminate', 'delete']: if not exception_type: return False raise exception_type( "unknown verb in the json input '{}'".format(verb)) txn = CCL_TransactionPayload() json_format.Parse(json_input, txn, ignore_unknown_fields=True) if verbose: self._dbg_dump.dump_ccl_transaction(txn) self._dbg_dump.dump_ccl_transaction_protobuf_message_to_json( txn) else: if not exception_type: return False raise exception_type( "unknown 'af' (a.k.a. address family) in the json input '{}'". format(address_family)) result, signature = self.send_transaction( txn.SerializeToString(), address_family, wait=wait, exception_type=timeout_exception_type, transaction_output_list=transaction_output_list, transaction_input_list=transaction_input_list, transaction_dependency_list=transaction_dependency_list) if verbose: self._dbg_dump.dump_str("") self._dbg_dump.dump_str(result) self._dbg_dump.dump_str("") self._dbg_dump.dump_str( "Transaction signature: {}".format(signature)) return signature
def _del_ccl_info_callback(self, ccl_info, wait): txn = CCL_TransactionPayload() txn.verb = 'delete' txn.state_update.contract_id = ccl_info.current_state.contract_id self._send_ccl_transaction(txn, wait)
def execute_json_transaction(self, json_input, address_family, wait): if self._verbose: print("\njson_input:") print(json_input) json_dict = json.loads(json_input) if not address_family: try: address_family = json_dict['af'] except: raise PdoCliException( "Family not defined, use 'af'in the json or --enclave, --contract, or --ccl on the command line" ) # set contract id and signature(s) if they are empty in case of contract add and remove enclaves transactions if address_family == self.connect.get_contract_registry_family_name(): if json_dict['verb'] != 'delete': details = None contract = None if json_dict['verb'] != 'register' and not json_dict[ 'contract_id']: contract = self._find_contract_id() if json_dict['verb'] == 'register': # generate pdo_signature and pdo_contract_creator_pem_key in case of contract register details = PdoContractRegister() json_format.Parse(json_input, details, ignore_unknown_fields=True) details.contract_code_hash = self._to_base64( details.contract_code_hash) # normally it would be done using one time transaction signing key # to simplify test automation we are going to reuse the same key was used for contract registration details.pdo_signature = secp256k1_sign( make_contract_register_hash_input( details, self.connect.get_signer_public_key_as_hex()), self.connect.get_signer_private_key_as_hex()) details.pdo_contract_creator_pem_key = self.connect.get_signer_public_key_as_hex( ) contract = PdoContractInfo() if 'contract_id' in json_dict: contract.contract_id = json_dict.get('contract_id') elif json_dict['verb'] == 'remove-enclaves': details = PdoContractRemoveEnclaves() json_format.Parse(json_input, details, ignore_unknown_fields=True) elif json_dict['verb'] == 'add-enclaves': details = PdoContractAddEnclaves() json_format.Parse(json_input, details, ignore_unknown_fields=True) # generate enclave signatures for each enclave info # if signatures are empty in the json input for enclave_info in details.enclaves_info: if not enclave_info.enclave_signature: if not contract: contract = self._get_contract_state( json_dict['contract_id']) if not not contract or not contract.contract_id: raise PdoCliException( "Cannot load contract to generate signature {}" .format(json_dict['contract_id'])) enclave_info.encrypted_contract_state_encryption_key = \ base64.b64encode(enclave_info.encrypted_contract_state_encryption_key.encode()) hash_input = make_add_enclave_to_contract_hash_input( enclave_info, contract) enclave_info.enclave_signature = secp256k1_sign( hash_input, self._enclave_signing_private_key) contract_creator_private_key = self.connect.get_signer_private_key_as_hex( ) self.connect.generate_new_signer_key() details.pdo_signature = secp256k1_sign( make_add_enclave_to_contract_pdo_hash_input( details, contract, self.connect.get_signer_public_key_as_hex()), contract_creator_private_key) if contract: txn = PdoContractTransaction() txn.verb = json_dict['verb'] txn.contract_id = contract.contract_id if details: txn.transaction_details = details.SerializeToString() if self._verbose: print("Updated Contract Transaction:") PdoDbgDump().dump_contract_transaction(txn) PdoDbgDump( ).dump_contract_transaction_protobuf_message_to_json( txn) result = self.connect.send_transaction( txn.SerializeToString(), address_family, wait=wait) if self._verbose: print(result) print("OK") return # set contract id and signature(s) if they are empty in case of CCL transactions if address_family == self.connect.get_ccl_family_name(): if json_dict['verb'] != 'delete': signature = json_dict['contract_enclave_signature'] contract_id = json_dict['state_update']['contract_id'] if not contract_id or not signature: contract_creator_private_key = self.connect.get_signer_private_key_as_hex( ) self.connect.generate_new_signer_key() txn = CCL_TransactionPayload() json_format.Parse(json_input, txn, ignore_unknown_fields=True) # for testing set channel_id to the one time transaction signer key txn.channel_id = self.connect.get_signer_public_key_as_hex( ) if not contract_id: contract = self._find_contract_id() else: contract = self._get_contract_state(contract_id) txn.state_update.contract_id = contract.contract_id for d in txn.state_update.dependency_list: d.contract_id = contract.contract_id d.state_hash = self._to_base64(d.state_hash) txn.state_update.current_state_hash = self._to_base64( txn.state_update.current_state_hash) txn.state_update.previous_state_hash = self._to_base64( txn.state_update.previous_state_hash) txn.state_update.message_hash = self._to_base64( txn.state_update.message_hash) contract.contract_code_hash = self._to_base64( contract.contract_code_hash) if not signature: txn.contract_enclave_signature = sign_ccl_transaction( txn, contract, self._enclave_signing_private_key) if json_dict['verb'] == 'initialize': # generate PDO signature normally done using one time transaction signing key # to simplify test automation assume reuse signing key used to register the contract txn.pdo_signature = secp256k1_sign( make_ccl_transaction_pdo_hash_input(txn, contract), contract_creator_private_key) if self._verbose: print("Updated CCL Transaction:") PdoDbgDump().dump_ccl_transaction(txn) PdoDbgDump( ).dump_ccl_transaction_protobuf_message_to_json(txn) result = self.connect.send_transaction( txn.SerializeToString(), address_family, wait=wait) if self._verbose: print(result) print("OK") return try: if self.connect.execute_json_transaction(json_input, address_family, wait, PdoCliException, self._verbose): print("OK") else: print("Error") except PdoCliException as e: print(e) print("Error") except TypeError as err: print("missing or invalid key:", err) print("Error")
def apply(self, transaction, context): txn_header = transaction.header txn_signer_public_key = txn_header.signer_public_key payload = CCL_TransactionPayload() payload.ParseFromString(transaction.payload) self.dbg_dump.dump_ccl_transaction(payload) if payload.verb == 'initialize': self._verify_initialize(context, payload, txn_signer_public_key) self._complete_action(context, transaction, payload, payload.state_update.contract_id) LOGGER.info("Contract CCL initialized for contract %s", payload.state_update.contract_id) elif payload.verb == 'update': contract_id = self._verify_update(context, payload, txn_signer_public_key) self._complete_action(context, transaction, payload, contract_id) LOGGER.info("Contract CCL updated for contract %s", payload.state_update.contract_id) elif payload.verb == 'terminate': contract_id = self._verify_terminate(context, payload, txn_signer_public_key) self._complete_action(context, transaction, payload, contract_id) LOGGER.info("Contract CCL updated for contract %s", payload.state_update.contract_id) elif payload.verb == 'delete': # 'delete' is useful for development/testing # it should be removed from the production # it is for debug only so no verification # 1) delete states listed in state_update.dependencies_list if not self._debug_on: raise InvalidTransaction( 'Delete is not allowed, debug support is OFF') for d in payload.state_update.dependency_list: state = self._get_ccl_state(context, d.contract_id, d.state_hash) if state.state_update.contract_id != d.contract_id: LOGGER.info("CCL state doesn't exist for '%s':'%s'", d.contract_id, d.state_hash) else: self._delete_ccl_state(context, d.contract_id, d.state_hash) LOGGER.info("CCL state deleted for '%s':'%s'", d.contract_id, d.state_hash) # 2) if payload.state_update.contract_id != "" remove info also if payload.state_update.contract_id: info = self._get_ccl_info(context, payload.state_update.contract_id) if info.current_state.contract_id != \ payload.state_update.contract_id: LOGGER.info("CCL info doesn't exist for '%s'", payload.state_update.contract_id) else: self._delete_ccl_info(context, payload.state_update.contract_id) LOGGER.info("CCL info deleted for %s", payload.state_update.contract_id) else: raise InvalidTransaction('Invalid transaction verb {}'.format( payload.verb))