extern crate exonum;
#[macro_use]
extern crate exonum_testkit;
extern crate serde_json;
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate exonum_derive;
extern crate failure;
extern crate protobuf;
use exonum::{
api::node::public::explorer::{BlocksQuery, BlocksRange, TransactionQuery},
blockchain::{
ExecutionResult, Schema, Service, Transaction, TransactionContext, TransactionSet,
},
crypto::{gen_keypair, Hash, PublicKey, SecretKey},
messages::{Message, RawTransaction, Signed},
storage::Snapshot,
};
use exonum_testkit::{ApiKind, TestKitBuilder};
mod proto;
const SERVICE_ID: u16 = 512;
#[derive(Serialize, Deserialize, Clone, Debug, ProtobufConvert)]
#[exonum(pb = "proto::TxTimestamp")]
struct TxTimestamp {
message: String,
}
#[derive(Serialize, Deserialize, Clone, Debug, TransactionSet)]
enum TimestampingServiceTransactions {
TxTimestamp(TxTimestamp),
}
impl TxTimestamp {
fn sign(author: &PublicKey, message: &str, key: &SecretKey) -> Signed<RawTransaction> {
Message::sign_transaction(
Self {
message: message.to_owned(),
},
SERVICE_ID,
*author,
key,
)
}
}
struct TimestampingService;
impl Transaction for TxTimestamp {
fn execute(&self, _context: TransactionContext) -> ExecutionResult {
Ok(())
}
}
impl Service for TimestampingService {
fn service_name(&self) -> &str {
"timestamping"
}
fn state_hash(&self, _: &Snapshot) -> Vec<Hash> {
Vec::new()
}
fn service_id(&self) -> u16 {
SERVICE_ID
}
fn tx_from_raw(&self, raw: RawTransaction) -> Result<Box<Transaction>, failure::Error> {
let tx = TimestampingServiceTransactions::tx_from_raw(raw)?;
Ok(tx.into())
}
}
fn main() {
let mut testkit = TestKitBuilder::validator()
.with_validators(4)
.with_service(TimestampingService)
.create();
let keypair = gen_keypair();
let tx1 = TxTimestamp::sign(&keypair.0, "Down To Earth", &keypair.1);
let tx2 = TxTimestamp::sign(&keypair.0, "Cry Over Spilt Milk", &keypair.1);
let tx3 = TxTimestamp::sign(&keypair.0, "Dropping Like Flies", &keypair.1);
let block =
testkit.create_block_with_transactions(txvec![tx1.clone(), tx2.clone(), tx3.clone(),]);
assert_eq!(block.len(), 3);
assert!(block.iter().all(|transaction| transaction.status().is_ok()));
let snapshot = testkit.snapshot();
let schema = Schema::new(&snapshot);
assert!(schema.transactions().contains(&tx1.hash()));
assert!(schema.transactions().contains(&tx2.hash()));
assert!(schema.transactions().contains(&tx3.hash()));
let api = testkit.api();
let blocks_range: BlocksRange = api
.public(ApiKind::Explorer)
.query(&BlocksQuery {
count: 10,
..Default::default()
})
.get("v1/blocks")
.unwrap();
assert_eq!(blocks_range.blocks.len(), 2);
api.public(ApiKind::Explorer)
.query(&TransactionQuery { hash: tx1.hash() })
.get::<serde_json::Value>("v1/transactions")
.unwrap();
}