Skip to content

Commit

Permalink
Cryptocurrency advanced protobuf [ECR-2296] (#1077)
Browse files Browse the repository at this point in the history
  • Loading branch information
dvush authored and aleksuss committed Dec 4, 2018
1 parent 7023818 commit e804b1b
Show file tree
Hide file tree
Showing 12 changed files with 233 additions and 76 deletions.
5 changes: 5 additions & 0 deletions examples/cryptocurrency-advanced/backend/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,19 @@ circle-ci = { repository = "exonum/exonum" }

[dependencies]
exonum = { version = "0.9.0", path = "../../../exonum" }
exonum_derive = { path = "../../../exonum_derive" }
exonum-configuration = { version = "0.9.0", path = "../../../services/configuration" }
serde = "1.0.0"
serde_derive = "1.0.0"
failure = "0.1.2"
protobuf = "=2.2.0"

[dev-dependencies]
exonum-testkit = { version = "0.9.0", path = "../../../testkit" }
serde_json = "1.0.0"
pretty_assertions = "=0.5.1"
assert_matches = "1.2.0"
hex = "=0.3.2"

[build-dependencies]
exonum_build = { version = "0.9.0", path = "../../../exonum_build" }
13 changes: 13 additions & 0 deletions examples/cryptocurrency-advanced/backend/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
extern crate exonum_build;

use exonum_build::protobuf_generate;
use std::env;

fn main() {
let exonum_protos = env::var("DEP_EXONUM_PROTOBUF_PROTOS").unwrap();
protobuf_generate(
"src/proto",
&["src/proto", &exonum_protos],
"protobuf_mod.rs",
);
}
5 changes: 4 additions & 1 deletion examples/cryptocurrency-advanced/backend/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@
bare_trait_objects
)]

#[macro_use]
extern crate exonum;
#[macro_use]
extern crate exonum_derive;
extern crate protobuf;
#[macro_use]
extern crate failure;
extern crate serde;
#[macro_use]
Expand All @@ -32,6 +34,7 @@ extern crate serde_derive;
pub use schema::Schema;

pub mod api;
pub mod proto;
pub mod schema;
pub mod transactions;
pub mod wallet;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Copyright 2018 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

syntax = "proto3";

package exonum.examples.cryptocurrency_advanced;

import "helpers.proto";

/// Transfer `amount` of the currency from one wallet to another.
message Transfer {
// `PublicKey` of receiver's wallet.
exonum.PublicKey to = 1;
// Amount of currency to transfer.
uint64 amount = 2;
// Auxiliary number to guarantee non-idempotence of transactions.
uint64 seed = 3;
}

// Issue `amount` of the currency to the `wallet`.
message Issue {
// Issued amount of currency.
uint64 amount = 1;
// Auxiliary number to guarantee non-idempotence of transactions.
uint64 seed = 2;
}

// Create wallet with the given `name`.
message CreateWallet {
// Name of the new wallet.
string name = 1;
}

// Wallet information stored in the database.
message Wallet {
// `PublicKey` of the wallet.
exonum.PublicKey pub_key = 1;
// Name of the wallet.
string name = 2;
// Current balance of the wallet.
uint64 balance = 3;
// Length of the transactions history.
uint64 history_len = 4;
// `Hash` of the transactions history.
exonum.Hash history_hash = 5;
}
24 changes: 24 additions & 0 deletions examples/cryptocurrency-advanced/backend/src/proto/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright 2018 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Module of the rust-protobuf generated files.

#![allow(bare_trait_objects)]
#![allow(renamed_and_removed_lints)]

pub use self::cryptocurrency::{CreateWallet, Issue, Transfer, Wallet};

include!(concat!(env!("OUT_DIR"), "/protobuf_mod.rs"));

use exonum::encoding::protobuf::*;
12 changes: 6 additions & 6 deletions examples/cryptocurrency-advanced/backend/src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,27 +84,27 @@ impl<'a> Schema<&'a mut Fork> {
/// Panics if there is no wallet with given public key.
pub fn increase_wallet_balance(&mut self, wallet: Wallet, amount: u64, transaction: &Hash) {
let wallet = {
let mut history = self.wallet_history_mut(wallet.pub_key());
let mut history = self.wallet_history_mut(&wallet.pub_key);
history.push(*transaction);
let history_hash = history.merkle_root();
let balance = wallet.balance();
let balance = wallet.balance;
wallet.set_balance(balance + amount, &history_hash)
};
self.wallets_mut().put(wallet.pub_key(), wallet.clone());
self.wallets_mut().put(&wallet.pub_key, wallet.clone());
}

/// Decrease balance of the wallet and append new record to its history.
///
/// Panics if there is no wallet with given public key.
pub fn decrease_wallet_balance(&mut self, wallet: Wallet, amount: u64, transaction: &Hash) {
let wallet = {
let mut history = self.wallet_history_mut(wallet.pub_key());
let mut history = self.wallet_history_mut(&wallet.pub_key);
history.push(*transaction);
let history_hash = history.merkle_root();
let balance = wallet.balance();
let balance = wallet.balance;
wallet.set_balance(balance - amount, &history_hash)
};
self.wallets_mut().put(wallet.pub_key(), wallet.clone());
self.wallets_mut().put(&wallet.pub_key, wallet.clone());
}

/// Create new wallet and append first record to its history.
Expand Down
95 changes: 57 additions & 38 deletions examples/cryptocurrency-advanced/backend/src/transactions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use exonum::{
messages::{Message, RawTransaction, Signed},
};

use super::proto;
use schema::Schema;
use CRYPTOCURRENCY_SERVICE_ID;

Expand Down Expand Up @@ -65,58 +66,76 @@ impl From<Error> for ExecutionError {
}
}

transactions! {
/// Transaction group.
pub WalletTransactions {

/// Transfer `amount` of the currency from one wallet to another.
struct Transfer {
/// `PublicKey` of receiver's wallet.
to: &PublicKey,
/// Amount of currency to transfer.
amount: u64,
/// Auxiliary number to guarantee [non-idempotence][idempotence] of transactions.
///
/// [idempotence]: https://en.wikipedia.org/wiki/Idempotence
seed: u64,
}
/// Transfer `amount` of the currency from one wallet to another.
#[derive(Serialize, Deserialize, Clone, Debug, ProtobufConvert)]
#[exonum(pb = "proto::Transfer")]
pub struct Transfer {
/// `PublicKey` of receiver's wallet.
pub to: PublicKey,
/// Amount of currency to transfer.
pub amount: u64,
/// Auxiliary number to guarantee [non-idempotence][idempotence] of transactions.
///
/// [idempotence]: https://en.wikipedia.org/wiki/Idempotence
pub seed: u64,
}

/// Issue `amount` of the currency to the `wallet`.
struct Issue {
/// Issued amount of currency.
amount: u64,
/// Auxiliary number to guarantee [non-idempotence][idempotence] of transactions.
///
/// [idempotence]: https://en.wikipedia.org/wiki/Idempotence
seed: u64,
}
/// Issue `amount` of the currency to the `wallet`.
#[derive(Serialize, Deserialize, Clone, Debug, ProtobufConvert)]
#[exonum(pb = "proto::Issue")]
pub struct Issue {
/// Issued amount of currency.
pub amount: u64,
/// Auxiliary number to guarantee [non-idempotence][idempotence] of transactions.
///
/// [idempotence]: https://en.wikipedia.org/wiki/Idempotence
pub seed: u64,
}

/// Create wallet with the given `name`.
struct CreateWallet {
/// Name of the new wallet.
name: &str,
}
}
/// Create wallet with the given `name`.
#[derive(Serialize, Deserialize, Clone, Debug, ProtobufConvert)]
#[exonum(pb = "proto::CreateWallet")]
pub struct CreateWallet {
/// Name of the new wallet.
pub name: String,
}

/// Transaction group.
#[derive(Serialize, Deserialize, Clone, Debug, TransactionSet)]
pub enum WalletTransactions {
/// Transfer tx.
Transfer(Transfer),
/// Issue tx.
Issue(Issue),
/// CreateWallet tx.
CreateWallet(CreateWallet),
}

impl CreateWallet {
#[doc(hidden)]
pub fn sign(name: &str, pk: &PublicKey, sk: &SecretKey) -> Signed<RawTransaction> {
Message::sign_transaction(CreateWallet::new(name), CRYPTOCURRENCY_SERVICE_ID, *pk, sk)
Message::sign_transaction(
Self {
name: name.to_owned(),
},
CRYPTOCURRENCY_SERVICE_ID,
*pk,
sk,
)
}
}

impl Transfer {
#[doc(hidden)]
pub fn sign(
pk: &PublicKey,
to: &PublicKey,
&to: &PublicKey,
amount: u64,
seed: u64,
sk: &SecretKey,
) -> Signed<RawTransaction> {
Message::sign_transaction(
Transfer::new(to, amount, seed),
Self { to, amount, seed },
CRYPTOCURRENCY_SERVICE_ID,
*pk,
sk,
Expand All @@ -131,8 +150,8 @@ impl Transaction for Transfer {

let mut schema = Schema::new(context.fork());

let to = self.to();
let amount = self.amount();
let to = &self.to;
let amount = self.amount;

if from == to {
return Err(ExecutionError::new(ERROR_SENDER_SAME_AS_RECEIVER));
Expand All @@ -142,7 +161,7 @@ impl Transaction for Transfer {

let receiver = schema.wallet(to).ok_or(Error::ReceiverNotFound)?;

if sender.balance() < amount {
if sender.balance < amount {
Err(Error::InsufficientCurrencyAmount)?
}

Expand All @@ -161,7 +180,7 @@ impl Transaction for Issue {
let mut schema = Schema::new(context.fork());

if let Some(wallet) = schema.wallet(pub_key) {
let amount = self.amount();
let amount = self.amount;
schema.increase_wallet_balance(wallet, amount, &hash);
Ok(())
} else {
Expand All @@ -178,7 +197,7 @@ impl Transaction for CreateWallet {
let mut schema = Schema::new(context.fork());

if schema.wallet(pub_key).is_none() {
let name = self.name();
let name = &self.name;
schema.create_wallet(pub_key, name, &hash);
Ok(())
} else {
Expand Down
52 changes: 35 additions & 17 deletions examples/cryptocurrency-advanced/backend/src/wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,30 +16,48 @@

use exonum::crypto::{Hash, PublicKey};

encoding_struct! {
/// Wallet information stored in the database.
struct Wallet {
/// `PublicKey` of the wallet.
pub_key: &PublicKey,
/// Name of the wallet.
name: &str,
/// Current balance of the wallet.
balance: u64,
/// Length of the transactions history.
history_len: u64,
/// `Hash` of the transactions history.
history_hash: &Hash,
}
use super::proto;

/// Wallet information stored in the database.
#[derive(Serialize, Deserialize, Clone, Debug, ProtobufConvert)]
#[exonum(pb = "proto::Wallet")]
pub struct Wallet {
/// `PublicKey` of the wallet.
pub pub_key: PublicKey,
/// Name of the wallet.
pub name: String,
/// Current balance of the wallet.
pub balance: u64,
/// Length of the transactions history.
pub history_len: u64,
/// `Hash` of the transactions history.
pub history_hash: Hash,
}

impl Wallet {
/// Create new Wallet.
pub fn new(
&pub_key: &PublicKey,
name: &str,
balance: u64,
history_len: u64,
&history_hash: &Hash,
) -> Self {
Self {
pub_key,
name: name.to_owned(),
balance,
history_len,
history_hash,
}
}
/// Returns a copy of this wallet with updated balance.
pub fn set_balance(self, balance: u64, history_hash: &Hash) -> Self {
Self::new(
self.pub_key(),
self.name(),
&self.pub_key,
&self.name,
balance,
self.history_len() + 1,
self.history_len + 1,
history_hash,
)
}
Expand Down

0 comments on commit e804b1b

Please sign in to comment.