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  }