github.com/muhammedhassanm/blockchain@v0.0.0-20200120143007-697261defd4d/sawtooth-core-master/validator/src/journal/block_wrapper_ffi.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 cpython;
    19  use cpython::{FromPyObject, ObjectProtocol, PyObject, Python, PythonObject, ToPyObject};
    20  use journal::block_wrapper::BlockStatus;
    21  use journal::block_wrapper::BlockWrapper;
    22  
    23  use batch::Batch;
    24  use block::Block;
    25  use transaction::Transaction;
    26  
    27  use protobuf;
    28  use protobuf::Message;
    29  
    30  use proto::batch::Batch as ProtoBatch;
    31  use proto::batch::BatchHeader;
    32  use proto::block::Block as ProtoBlock;
    33  use proto::block::BlockHeader;
    34  use proto::transaction::Transaction as ProtoTxn;
    35  use proto::transaction::TransactionHeader;
    36  use pylogger;
    37  
    38  impl ToPyObject for BlockStatus {
    39      type ObjectType = cpython::PyLong;
    40  
    41      fn to_py_object(&self, py: Python) -> cpython::PyLong {
    42          match self {
    43              &BlockStatus::Unknown => 0i32.to_py_object(py),
    44              &BlockStatus::Invalid => 1i32.to_py_object(py),
    45              &BlockStatus::Valid => 2i32.to_py_object(py),
    46              &BlockStatus::Missing => 3i32.to_py_object(py),
    47          }
    48      }
    49  }
    50  
    51  impl<'source> FromPyObject<'source> for BlockStatus {
    52      fn extract(py: Python, obj: &'source PyObject) -> cpython::PyResult<Self> {
    53          let enum_val: i32 = obj.extract(py)?;
    54          Ok(match enum_val {
    55              1 => BlockStatus::Invalid,
    56              2 => BlockStatus::Valid,
    57              3 => BlockStatus::Missing,
    58              _ => BlockStatus::Unknown,
    59          })
    60      }
    61  }
    62  
    63  impl ToPyObject for BlockWrapper {
    64      type ObjectType = PyObject;
    65  
    66      fn to_py_object(&self, py: Python) -> PyObject {
    67          let block_wrapper_mod = py.import("sawtooth_validator.journal.block_wrapper")
    68              .expect("Unable to import block_wrapper");
    69          let py_block_wrapper = block_wrapper_mod
    70              .get(py, "BlockWrapper")
    71              .expect("Unable to get BlockWrapper");
    72          let block_protobuf_mod = py.import("sawtooth_validator.protobuf.block_pb2")
    73              .expect("Unable to import block_pb2");
    74          let py_block = block_protobuf_mod
    75              .get(py, "Block")
    76              .expect("Unable to get Block");
    77  
    78          let mut proto_block = ProtoBlock::new();
    79          let self_block = self.block.clone();
    80          proto_block.set_header(self_block.header_bytes.clone());
    81          proto_block.set_header_signature(self_block.header_signature.clone());
    82  
    83          let proto_batches = self_block
    84              .batches
    85              .iter()
    86              .map(|batch| {
    87                  let mut proto_batch = ProtoBatch::new();
    88                  proto_batch.set_header(batch.header_bytes.clone());
    89                  proto_batch.set_header_signature(batch.header_signature.clone());
    90  
    91                  let proto_txns = batch
    92                      .transactions
    93                      .iter()
    94                      .map(|txn| {
    95                          let mut proto_txn = ProtoTxn::new();
    96                          proto_txn.set_header(txn.header_bytes.clone());
    97                          proto_txn.set_header_signature(txn.header_signature.clone());
    98                          proto_txn.set_payload(txn.payload.clone());
    99                          proto_txn
   100                      })
   101                      .collect::<Vec<_>>();
   102  
   103                  proto_batch.set_transactions(protobuf::RepeatedField::from_vec(proto_txns));
   104  
   105                  proto_batch
   106              })
   107              .collect::<Vec<_>>();
   108  
   109          proto_block.set_batches(protobuf::RepeatedField::from_vec(proto_batches));
   110  
   111          let block = py_block
   112              .call(py, cpython::NoArgs, None)
   113              .expect("Unable to instantiate Block");
   114          block
   115              .call_method(
   116                  py,
   117                  "ParseFromString",
   118                  (cpython::PyBytes::new(py, &proto_block.write_to_bytes().unwrap()).into_object(),),
   119                  None,
   120              )
   121              .expect("Unable to ParseFromString");
   122  
   123          let wrapper = py_block_wrapper
   124              .call_method(py, "wrap", (block, 0, self.status.clone()), None)
   125              .expect("Unable to call BlockWrapper.wrap");
   126  
   127          wrapper
   128              .setattr(py, "num_transactions", self.num_transactions)
   129              .expect("Unable to set BlockWrapper.num_transactions");
   130  
   131          wrapper
   132      }
   133  }
   134  
   135  impl<'source> FromPyObject<'source> for BlockWrapper {
   136      fn extract(py: Python, obj: &'source PyObject) -> cpython::PyResult<Self> {
   137          let py_block = obj.getattr(py, "block")
   138              .expect("Unable to get block from BlockWrapper");
   139  
   140          let bytes: Vec<u8> = py_block
   141              .call_method(py, "SerializeToString", cpython::NoArgs, None)?
   142              .extract(py)?;
   143  
   144          let mut proto_block: ProtoBlock = protobuf::parse_from_bytes(&bytes)
   145              .expect("Unable to parse protobuf bytes from python protobuf object");
   146  
   147          let mut block_header: BlockHeader = protobuf::parse_from_bytes(proto_block.get_header())
   148              .expect("Unable to parse protobuf bytes from python protobuf object");
   149          let block = Block {
   150              header_signature: proto_block.take_header_signature(),
   151              header_bytes: proto_block.take_header(),
   152              state_root_hash: block_header.take_state_root_hash(),
   153              consensus: block_header.take_consensus(),
   154              batch_ids: block_header.take_batch_ids().into_vec(),
   155              signer_public_key: block_header.take_signer_public_key(),
   156              previous_block_id: block_header.take_previous_block_id(),
   157              block_num: block_header.get_block_num(),
   158  
   159              batches: proto_block
   160                  .take_batches()
   161                  .iter_mut()
   162                  .map(proto_batch_to_batch)
   163                  .collect(),
   164          };
   165  
   166          Ok(BlockWrapper {
   167              block,
   168              execution_results: obj.getattr(py, "execution_results")?.extract(py)?,
   169              num_transactions: obj.getattr(py, "num_transactions")?.extract(py)?,
   170              status: match obj.getattr(py, "status")?.extract(py) {
   171                  Ok(x) => x,
   172                  Err(err) => {
   173                      pylogger::exception(py, "Unable to read status", err);
   174                      BlockStatus::Unknown
   175                  }
   176              },
   177          })
   178      }
   179  }
   180  
   181  fn proto_batch_to_batch(proto_batch: &mut ProtoBatch) -> Batch {
   182      let mut batch_header: BatchHeader = protobuf::parse_from_bytes(proto_batch.get_header())
   183          .expect("Unable to parse protobuf bytes from python protobuf object");
   184      Batch {
   185          header_signature: proto_batch.take_header_signature(),
   186          header_bytes: proto_batch.take_header(),
   187          signer_public_key: batch_header.take_signer_public_key(),
   188          transaction_ids: batch_header.take_transaction_ids().into_vec(),
   189          trace: proto_batch.get_trace(),
   190  
   191          transactions: proto_batch
   192              .take_transactions()
   193              .iter_mut()
   194              .map(proto_txn_to_txn)
   195              .collect(),
   196      }
   197  }
   198  
   199  fn proto_txn_to_txn(proto_txn: &mut ProtoTxn) -> Transaction {
   200      let mut txn_header: TransactionHeader = protobuf::parse_from_bytes(proto_txn.get_header())
   201          .expect("Unable to parse protobuf bytes from python protobuf object");
   202  
   203      Transaction {
   204          header_signature: proto_txn.take_header_signature(),
   205          header_bytes: proto_txn.take_header(),
   206          payload: proto_txn.take_payload(),
   207          batcher_public_key: txn_header.take_batcher_public_key(),
   208          dependencies: txn_header.take_dependencies().into_vec(),
   209          family_name: txn_header.take_family_name(),
   210          family_version: txn_header.take_family_version(),
   211          inputs: txn_header.take_inputs().into_vec(),
   212          outputs: txn_header.take_outputs().into_vec(),
   213          nonce: txn_header.take_nonce(),
   214          payload_sha512: txn_header.take_payload_sha512(),
   215          signer_public_key: txn_header.take_signer_public_key(),
   216      }
   217  }
   218  
   219  #[cfg(test)]
   220  mod tests {
   221      use super::*;
   222      use block::Block;
   223      use cpython::{FromPyObject, PyObject, Python, ToPyObject};
   224      use journal::block_wrapper::{BlockStatus, BlockWrapper};
   225  
   226      #[test]
   227      fn to_from_python() {
   228          let gil_guard = Python::acquire_gil();
   229          let py = gil_guard.python();
   230  
   231          let block_wrapper = BlockWrapper {
   232              block: Block::default(),
   233              status: BlockStatus::Valid,
   234              ..BlockWrapper::default()
   235          };
   236  
   237          let py_block_wrapper = block_wrapper.to_py_object(py);
   238          let round_trip_obj: BlockWrapper = py_block_wrapper.extract(py).unwrap();
   239  
   240          assert_eq!(BlockStatus::Valid, round_trip_obj.status);
   241      }
   242  
   243  }