1212# See the License for the specific language governing permissions and
1313# limitations under the License.
1414
15+ import os
1516import argparse
1617import logging
1718import random
3334__all__ = ['command_create' ]
3435
3536## -----------------------------------------------------------------
36- def __add_enclave_secrets (ledger_config , contract_id , client_keys , enclaveclients , provclients ) :
37+ def __add_enclave_secrets__ (ledger_config , contract_id , client_keys , enclaveclients , provclients ) :
3738 """Create and provision the encrypted secrets for each of the
3839 enclaves that will be provisioned for this contract.
3940 """
@@ -76,7 +77,7 @@ def __add_enclave_secrets(ledger_config, contract_id, client_keys, enclaveclient
7677 return encrypted_state_encryption_keys
7778
7879## -----------------------------------------------------------------
79- def __create_contract (ledger_config , client_keys , preferred_eservice_client , eservice_clients , contract ) :
80+ def __create_contract__ (ledger_config , client_keys , preferred_eservice_client , eservice_clients , contract ) :
8081 """Create the initial contract state
8182 """
8283
@@ -106,30 +107,27 @@ def __create_contract(ledger_config, client_keys, preferred_eservice_client, ese
106107
107108## -----------------------------------------------------------------
108109## -----------------------------------------------------------------
109- def command_create (state , bindings , pargs ) :
110- """controller command to create a contract
110+ def create_contract (state , save_file , contract_source , ** kwargs ) :
111+ """Expose the contract creation logic to other client applications
112+
113+ @param save_file: file name for the local contract information
114+ @param contract_source : path to the contract source file
115+ @param contract_class : optional parameter to specific class in the contract source
116+ @param eservice_group : name of the eservice group to provision the contract
117+ @param pservice_group : name of the pservice group to provision the contract
118+ @param interpreter : name of the interpreter that is expected from the eservices
119+ @param state_replicas : number of mandatory copies of state
120+ @param state_duration : minimum duration replicas must be available
121+ @param extra_data : opaque data that can be store in the contract file
111122 """
112- default_interpreter = state .get (['Contract' , 'Interpreter' ])
113- default_replicas = state .get (['Replication' , 'NumProvableReplicas' ], 2 )
114- default_duration = state .get (['Replication' , 'Duration' ], 120 )
115-
116- parser = argparse .ArgumentParser (prog = 'create' )
117- parser .add_argument ('-c' , '--contract-class' , help = 'Name of the contract class' , required = False , type = str )
118- parser .add_argument ('-e' , '--eservice-group' , help = 'Name of the enclave service group to use' , default = "default" )
119- parser .add_argument ('-f' , '--save-file' , help = 'File where contract data is stored' , type = str )
120- parser .add_argument ('-i' , '--interpreter' , help = 'Interpreter used to evaluate the contract' , default = default_interpreter )
121- parser .add_argument ('-p' , '--pservice-group' , help = 'Name of the provisioning service group to use' , default = "default" )
122- parser .add_argument ('-s' , '--contract-source' , help = 'File that contains contract source code' , required = True , type = str )
123-
124- parser .add_argument ('--symbol' , help = 'binding symbol for result' , type = str )
125- parser .add_argument ('--state-replicas' , help = 'Number of authoritative replicas of the state' , default = default_replicas )
126- parser .add_argument ('--state-duration' , help = 'Duration required for state replicas' , default = default_duration )
127- parser .add_argument ('--extra-data' , help = 'Simple string that can save extra data with the contract file' , type = str )
128-
129- options = parser .parse_args (pargs )
130123
131- contract_class = options .contract_class
132- contract_source = options .contract_source
124+ contract_class = kwargs .get ('contract_class' ) or os .path .basename (contract_source )
125+ eservice_group = kwargs .get ('eservice_group' ) or 'default'
126+ pservice_group = kwargs .get ('pservice_group' ) or 'default'
127+ interpreter = kwargs .get ('interpreter' ) or state .get (['Contract' , 'Interpreter' ])
128+ state_replicas = kwargs .get ('state_replicas' ) or state .get (['Replication' , 'NumProvableReplicas' ], 2 )
129+ state_duration = kwargs .get ('state_duration' ) or state .get (['Replication' , 'Duration' ], 120 )
130+ extra_data = kwargs .get ('extra_data' )
133131
134132 # ---------- load the invoker's keys ----------
135133 try :
@@ -143,38 +141,38 @@ def command_create(state, bindings, pargs) :
143141 try :
144142 source_path = state .get (['Contract' , 'SourceSearchPath' ])
145143 contract_code = ContractCode .create_from_file (
146- contract_class , contract_source , source_path , interpreter = options . interpreter )
144+ contract_class , contract_source , source_path , interpreter = interpreter )
147145 except Exception as e :
148146 raise Exception ('unable to load contract source; {0}' .format (str (e )))
149147
150148 logger .debug ('Loaded contract code for %s' , contract_class )
151149
152150 # ---------- set up the enclave clients ----------
153- eservice_clients = get_eservice_list (state , options . eservice_group )
151+ eservice_clients = get_eservice_list (state , eservice_group )
154152 if len (eservice_clients ) == 0 :
155- raise Exception ('unable to locate enclave services in the group %s' , options . eservice_group )
153+ raise Exception ('unable to locate enclave services in the group %s' , eservice_group )
156154
157- preferred_eservice_client = get_eservice (state , eservice_group = options . eservice_group )
158- if preferred_eservice_client .interpreter != options . interpreter :
159- raise Exception ('enclave interpreter does not match requested contract interpreter %s' , options . interpreter )
155+ preferred_eservice_client = get_eservice (state , eservice_group = eservice_group )
156+ if preferred_eservice_client .interpreter != interpreter :
157+ raise Exception ('enclave interpreter does not match requested contract interpreter %s' , interpreter )
160158
161159 # ---------- set up the provisioning service clients ----------
162- pservice_clients = get_pservice_list (state , options . pservice_group )
160+ pservice_clients = get_pservice_list (state , pservice_group )
163161 if len (pservice_clients ) == 0 :
164- raise Exception ('unable to locate provisioning services in the group %s' , options . pservice_group )
162+ raise Exception ('unable to locate provisioning services in the group %s' , pservice_group )
165163
166164 # ---------- register contract ----------
167165 data_directory = state .get (['Contract' , 'DataDirectory' ])
168166 ledger_config = state .get (['Ledger' ])
169167
170168 try :
171169 extra_params = {
172- 'num_provable_replicas' : options . state_replicas ,
173- 'availability_duration' : options . state_duration ,
170+ 'num_provable_replicas' : state_replicas ,
171+ 'availability_duration' : state_duration ,
174172 }
175173
176- if options . extra_data :
177- extra_params ['extra_data' ] = options . extra_data
174+ if extra_data :
175+ extra_params ['extra_data' ] = extra_data
178176
179177 provisioning_service_keys = [pc .identity for pc in pservice_clients ]
180178 contract_id = register_contract (
@@ -188,8 +186,8 @@ def command_create(state, bindings, pargs) :
188186 contract .extra_data ['preferred-enclave' ] = preferred_eservice_client .enclave_id
189187
190188 contract_file = "{0}_{1}.pdo" .format (contract_class , contract .short_id )
191- if options . save_file :
192- contract_file = options . save_file
189+ if save_file :
190+ contract_file = save_file
193191
194192 contract .save_to_file (contract_file , data_dir = data_directory )
195193
@@ -198,7 +196,7 @@ def command_create(state, bindings, pargs) :
198196
199197 # provision the encryption keys to all of the enclaves
200198 try :
201- encrypted_state_encryption_keys = __add_enclave_secrets (
199+ encrypted_state_encryption_keys = __add_enclave_secrets__ (
202200 ledger_config , contract .contract_id , client_keys , eservice_clients , pservice_clients )
203201
204202 for enclave_id in encrypted_state_encryption_keys :
@@ -211,11 +209,35 @@ def command_create(state, bindings, pargs) :
211209
212210 # create the initial contract state
213211 try :
214- __create_contract (ledger_config , client_keys , preferred_eservice_client , eservice_clients , contract )
212+ __create_contract__ (ledger_config , client_keys , preferred_eservice_client , eservice_clients , contract )
215213
216214 contract .save_to_file (contract_file , data_dir = data_directory )
217215 except Exception as e :
218216 raise Exception ('failed to create the initial contract state; {0}' .format (str (e )))
219217
218+ return contract_file
219+
220+ ## -----------------------------------------------------------------
221+ ## -----------------------------------------------------------------
222+ def command_create (state , bindings , pargs ) :
223+ """controller command to create a contract
224+ """
225+
226+ parser = argparse .ArgumentParser (prog = 'create' )
227+ parser .add_argument ('-c' , '--contract-class' , help = 'Name of the contract class' , type = str )
228+ parser .add_argument ('-e' , '--eservice-group' , help = 'Name of the enclave service group to use' , type = str )
229+ parser .add_argument ('-f' , '--save-file' , help = 'File where contract data is stored' , type = str )
230+ parser .add_argument ('-i' , '--interpreter' , help = 'Interpreter used to evaluate the contract' , type = str )
231+ parser .add_argument ('-p' , '--pservice-group' , help = 'Name of the provisioning service group to use' , type = str )
232+ parser .add_argument ('-s' , '--contract-source' , help = 'File that contains contract source code' , required = True , type = str )
233+
234+ parser .add_argument ('--symbol' , help = 'binding symbol for result' , type = str )
235+ parser .add_argument ('--state-replicas' , help = 'Number of authoritative replicas of the state' , type = int )
236+ parser .add_argument ('--state-duration' , help = 'Duration required for state replicas' , type = int )
237+ parser .add_argument ('--extra-data' , help = 'Simple string that can save extra data with the contract file' , type = str )
238+
239+ options = parser .parse_args (pargs )
240+
241+ contract_id = create_contract (state , ** vars (options ))
220242 if contract_id and options .symbol :
221243 bindings .bind (options .symbol , contract_id )
0 commit comments