github.com/muhammedhassanm/blockchain@v0.0.0-20200120143007-697261defd4d/sawtooth-core-master/validator/src/scheduler/py_scheduler.rs (about) 1 /* 2 * Copyright 2018 Intel Corporation 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * ------------------------------------------------------------------------------ 16 */ 17 18 use std::error::Error; 19 20 use cpython; 21 use cpython::ObjectProtocol; 22 use cpython::PyResult; 23 24 use batch::Batch; 25 26 use protobuf::ProtobufError; 27 28 use scheduler::{BatchResult, TransactionResult}; 29 use scheduler::{ExecutionResults, Scheduler, SchedulerError}; 30 31 impl From<ProtobufError> for SchedulerError { 32 fn from(other: ProtobufError) -> SchedulerError { 33 SchedulerError::Other(other.description().into()) 34 } 35 } 36 37 impl From<cpython::PyErr> for SchedulerError { 38 fn from(other: cpython::PyErr) -> SchedulerError { 39 let gil = cpython::Python::acquire_gil(); 40 let py = gil.python(); 41 SchedulerError::Other(other.get_type(py).name(py).into_owned()) 42 } 43 } 44 45 type CombinedOptionalBatchResult = Vec<(Vec<TransactionResult>, Option<BatchResult>, String)>; 46 47 pub struct PyScheduler { 48 py_scheduler: cpython::PyObject, 49 batch_ids: Vec<String>, 50 } 51 52 impl PyScheduler { 53 pub fn new(py_scheduler: cpython::PyObject) -> PyScheduler { 54 PyScheduler { 55 py_scheduler, 56 batch_ids: vec![], 57 } 58 } 59 60 fn is_complete(&self, block: bool) -> Result<bool, SchedulerError> { 61 let gil = cpython::Python::acquire_gil(); 62 let py = gil.python(); 63 Ok(self.py_scheduler 64 .call_method(py, "complete", (block,), None) 65 .expect("No method complete on python scheduler") 66 .extract::<bool>(py)?) 67 } 68 } 69 70 impl Scheduler for PyScheduler { 71 fn add_batch( 72 &mut self, 73 batch: Batch, 74 expected_state_hash: Option<&str>, 75 required: bool, 76 ) -> Result<(), SchedulerError> { 77 let header_signature = batch.header_signature.clone(); 78 let gil = cpython::Python::acquire_gil(); 79 let py = gil.python(); 80 81 self.py_scheduler 82 .call_method( 83 py, 84 "add_batch", 85 (batch, expected_state_hash, required), 86 None, 87 ) 88 .expect("No method add_batch on python scheduler"); 89 90 self.batch_ids.push(header_signature); 91 Ok(()) 92 } 93 94 fn finalize(&mut self, unschedule_incomplete: bool) -> Result<(), SchedulerError> { 95 let gil = cpython::Python::acquire_gil(); 96 let py = gil.python(); 97 98 if unschedule_incomplete { 99 self.py_scheduler 100 .call_method(py, "unschedule_incomplete_batches", cpython::NoArgs, None) 101 .expect("No method unscheduler_incomplete_batches on python scheduler"); 102 } 103 104 self.py_scheduler 105 .call_method(py, "finalize", cpython::NoArgs, None) 106 .expect("No method finalize on python scheduler"); 107 Ok(()) 108 } 109 110 fn cancel(&mut self) -> Result<(), SchedulerError> { 111 let gil = cpython::Python::acquire_gil(); 112 let py = gil.python(); 113 114 self.py_scheduler 115 .call_method(py, "cancel", cpython::NoArgs, None) 116 .expect("No method cancel on python scheduler"); 117 Ok(()) 118 } 119 120 fn complete(&mut self, block: bool) -> Result<Option<ExecutionResults>, SchedulerError> { 121 if self.is_complete(block)? { 122 let r: PyResult<CombinedOptionalBatchResult> = self.batch_ids 123 .iter() 124 .map(|id| { 125 let gil = cpython::Python::acquire_gil(); 126 let py = gil.python(); 127 let batch_result: cpython::PyObject = self.py_scheduler 128 .call_method(py, "get_batch_execution_result", (id,), None) 129 .expect("No method get_batch_execution_result on python scheduler"); 130 131 if batch_result != cpython::Python::None(py) { 132 let result = batch_result 133 .extract::<BatchResult>(py) 134 .expect("Failed to extract BatchResult"); 135 136 let txn_results: Vec<TransactionResult> = self.py_scheduler 137 .call_method(py, "get_transaction_execution_results", (id,), None) 138 .expect( 139 "No method get_transaction_execution_results on python scheduler", 140 ) 141 .extract::<cpython::PyList>(py)? 142 .iter(py) 143 .map(|r| r.extract::<TransactionResult>(py)) 144 .collect::<Result<Vec<TransactionResult>, cpython::PyErr>>()?; 145 146 Ok((txn_results, Some(result), id.to_owned())) 147 } else { 148 Ok((vec![], None, id.to_owned())) 149 } 150 }) 151 .collect(); 152 153 let results = r?; 154 155 let beginning_state_hash = results 156 .first() 157 .map(|v| v.0.first().map(|r| r.state_hash.clone()).unwrap_or(None)) 158 .unwrap_or(None); 159 160 let ending_state_hash = results 161 .iter() 162 .by_ref() 163 .map(|val| val.1.clone()) 164 .filter(|batch_result| batch_result.is_some()) 165 .find(|batch_result| { 166 batch_result 167 .clone() 168 .expect("Failed to unwrap batch result") 169 .state_hash 170 .is_some() 171 }) 172 .map(|batch_result| { 173 batch_result 174 .expect("Failed to unwrap batch result") 175 .state_hash 176 }) 177 .unwrap_or(None); 178 179 let batch_txn_results = results 180 .into_iter() 181 .map(|val| match val.1 { 182 Some(_) => ( 183 val.2.clone(), 184 Some( 185 val.0 186 .into_iter() 187 .map(|v: TransactionResult| v.into()) 188 .collect(), 189 ), 190 ), 191 None => (val.2.clone(), None), 192 }) 193 .collect(); 194 195 Ok(Some(ExecutionResults { 196 beginning_state_hash: beginning_state_hash, 197 ending_state_hash, 198 batch_results: batch_txn_results, 199 })) 200 } else { 201 Ok(None) 202 } 203 } 204 }