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 }