feat: works
This commit is contained in:
72
__crypto/simple_contract/Cargo.lock
generated
72
__crypto/simple_contract/Cargo.lock
generated
@@ -1,5 +1,14 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "ansi_term"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arrayref"
|
||||
version = "0.3.6"
|
||||
@@ -12,6 +21,17 @@ version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "0.1.7"
|
||||
@@ -98,6 +118,21 @@ version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.33.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"atty",
|
||||
"bitflags",
|
||||
"strsim",
|
||||
"textwrap",
|
||||
"unicode-width",
|
||||
"vec_map",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cloudabi"
|
||||
version = "0.0.3"
|
||||
@@ -176,6 +211,15 @@ dependencies = [
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hex"
|
||||
version = "0.4.2"
|
||||
@@ -464,6 +508,7 @@ name = "simple_contract"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bs58",
|
||||
"clap",
|
||||
"digest",
|
||||
"hex",
|
||||
"rand",
|
||||
@@ -475,6 +520,12 @@ dependencies = [
|
||||
"sha2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.56"
|
||||
@@ -507,18 +558,39 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||
dependencies = [
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
|
||||
|
||||
[[package]]
|
||||
name = "vec_map"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.9.0+wasi-snapshot-preview1"
|
||||
|
||||
@@ -17,3 +17,4 @@ sha2 = "0.8.1"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
rust_util = "0.6"
|
||||
clap = "2.33"
|
||||
|
||||
8
__crypto/simple_contract/src/cmd.rs
Normal file
8
__crypto/simple_contract/src/cmd.rs
Normal file
@@ -0,0 +1,8 @@
|
||||
use clap::{ArgMatches, App};
|
||||
use rust_util::XResult;
|
||||
pub type CommandError = XResult<()>;
|
||||
pub trait Command {
|
||||
fn name(&self) -> &str;
|
||||
fn subcommand<'a>(&self) -> App<'a, 'a>;
|
||||
fn run(&self, arg_matches: &ArgMatches, _: &ArgMatches) -> CommandError;
|
||||
}
|
||||
46
__crypto/simple_contract/src/cmd_credit_create.rs
Normal file
46
__crypto/simple_contract/src/cmd_credit_create.rs
Normal file
@@ -0,0 +1,46 @@
|
||||
use std::fs;
|
||||
use clap::{App, Arg, ArgMatches, SubCommand};
|
||||
use rust_util::information;
|
||||
use crate::{cmd::{Command, CommandError}, engine_credit::CreditContractCreateParameters};
|
||||
use crate::engine::ContractEngine;
|
||||
use crate::tx::{Transaction, TransactionBody};
|
||||
use crate::util::JsonKeyPair;
|
||||
|
||||
pub struct CommandImpl;
|
||||
impl Command for CommandImpl {
|
||||
fn name(&self) -> &str { "create" }
|
||||
fn subcommand<'a>(&self) -> App<'a, 'a> {
|
||||
SubCommand::with_name(self.name()).about("Create credit contract subcommand")
|
||||
.arg(Arg::with_name("name").long("name").short("n").required(true).takes_value(true).help("Contract name"))
|
||||
.arg(Arg::with_name("limit").long("limit").short("l").required(true).takes_value(true).help("Contract credit limit"))
|
||||
.arg(Arg::with_name("key").long("key").short("k").required(true).takes_value(true).help("Key pair"))
|
||||
}
|
||||
fn run(&self, _arg_matches: &ArgMatches, sub_arg_matches: &ArgMatches) -> CommandError {
|
||||
let name = sub_arg_matches.value_of("name").unwrap();
|
||||
let limit = sub_arg_matches.value_of("limit").unwrap();
|
||||
let key = sub_arg_matches.value_of("key").unwrap();
|
||||
|
||||
let key_json = fs::read_to_string(key)?;
|
||||
let (pri_key, pub_key) = JsonKeyPair::from_json(&key_json)?.to_key_pair()?;
|
||||
|
||||
let parameters = CreditContractCreateParameters {
|
||||
name: name.into(),
|
||||
credit_limit: limit.parse()?,
|
||||
};
|
||||
let transaction_body = TransactionBody {
|
||||
timestamp: 0,
|
||||
nonce: "".into(),
|
||||
contract: "credit".into(),
|
||||
action: "create".into(),
|
||||
parameters: serde_json::to_string(¶meters)?.into(),
|
||||
};
|
||||
let tx = Transaction::new(&transaction_body, &pri_key, &pub_key)?;
|
||||
|
||||
information!("Create transaction: {:#?}", tx);
|
||||
|
||||
let engine = ContractEngine::new();
|
||||
engine.execute(&tx)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
49
__crypto/simple_contract/src/cmd_credit_issue.rs
Normal file
49
__crypto/simple_contract/src/cmd_credit_issue.rs
Normal file
@@ -0,0 +1,49 @@
|
||||
use std::fs;
|
||||
use clap::{App, Arg, ArgMatches, SubCommand};
|
||||
use rust_util::information;
|
||||
use crate::{cmd::{Command, CommandError}, engine_credit::CreditContractIssueParameters};
|
||||
use crate::engine::ContractEngine;
|
||||
use crate::tx::{Transaction, TransactionBody};
|
||||
use crate::util::JsonKeyPair;
|
||||
|
||||
pub struct CommandImpl;
|
||||
impl Command for CommandImpl {
|
||||
fn name(&self) -> &str { "issue" }
|
||||
fn subcommand<'a>(&self) -> App<'a, 'a> {
|
||||
SubCommand::with_name(self.name()).about("Issue credit contract subcommand")
|
||||
.arg(Arg::with_name("name").long("name").short("n").required(true).takes_value(true).help("Contract name"))
|
||||
.arg(Arg::with_name("receiver").long("receiver").short("r").required(true).takes_value(true).help("Receiver"))
|
||||
.arg(Arg::with_name("credit").long("credit").short("c").required(true).takes_value(true).help("Credit"))
|
||||
.arg(Arg::with_name("key").long("key").short("k").required(true).takes_value(true).help("Key pair"))
|
||||
}
|
||||
fn run(&self, _arg_matches: &ArgMatches, sub_arg_matches: &ArgMatches) -> CommandError {
|
||||
let name = sub_arg_matches.value_of("name").unwrap();
|
||||
let receiver = sub_arg_matches.value_of("receiver").unwrap();
|
||||
let credit: u32 = sub_arg_matches.value_of("credit").unwrap().parse()?;
|
||||
let key = sub_arg_matches.value_of("key").unwrap();
|
||||
|
||||
let key_json = fs::read_to_string(key)?;
|
||||
let (pri_key, pub_key) = JsonKeyPair::from_json(&key_json)?.to_key_pair()?;
|
||||
|
||||
let parameters = CreditContractIssueParameters {
|
||||
name: name.into(),
|
||||
receiver: receiver.into(),
|
||||
credit,
|
||||
};
|
||||
let transaction_body = TransactionBody {
|
||||
timestamp: 0,
|
||||
nonce: "".into(),
|
||||
contract: "credit".into(),
|
||||
action: "issue".into(),
|
||||
parameters: serde_json::to_string(¶meters)?.into(),
|
||||
};
|
||||
let tx = Transaction::new(&transaction_body, &pri_key, &pub_key)?;
|
||||
|
||||
information!("Create transaction: {:#?}", tx);
|
||||
|
||||
let engine = ContractEngine::new();
|
||||
engine.execute(&tx)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
46
__crypto/simple_contract/src/cmd_credit_query.rs
Normal file
46
__crypto/simple_contract/src/cmd_credit_query.rs
Normal file
@@ -0,0 +1,46 @@
|
||||
use std::fs;
|
||||
use clap::{App, Arg, ArgMatches, SubCommand};
|
||||
use rust_util::information;
|
||||
use crate::{cmd::{Command, CommandError}, engine_credit::CreditContractQueryParameters};
|
||||
use crate::engine::ContractEngine;
|
||||
use crate::tx::{Transaction, TransactionBody};
|
||||
use crate::util::JsonKeyPair;
|
||||
|
||||
pub struct CommandImpl;
|
||||
impl Command for CommandImpl {
|
||||
fn name(&self) -> &str { "query" }
|
||||
fn subcommand<'a>(&self) -> App<'a, 'a> {
|
||||
SubCommand::with_name(self.name()).about("Query credit contract subcommand")
|
||||
.arg(Arg::with_name("name").long("name").short("n").required(true).takes_value(true).help("Contract name"))
|
||||
.arg(Arg::with_name("account").long("account").short("a").required(true).takes_value(true).help("Account"))
|
||||
.arg(Arg::with_name("key").long("key").short("k").required(true).takes_value(true).help("Key pair"))
|
||||
}
|
||||
fn run(&self, _arg_matches: &ArgMatches, sub_arg_matches: &ArgMatches) -> CommandError {
|
||||
let name = sub_arg_matches.value_of("name").unwrap();
|
||||
let account = sub_arg_matches.value_of("account").unwrap();
|
||||
let key = sub_arg_matches.value_of("key").unwrap();
|
||||
|
||||
let key_json = fs::read_to_string(key)?;
|
||||
let (pri_key, pub_key) = JsonKeyPair::from_json(&key_json)?.to_key_pair()?;
|
||||
|
||||
let parameters = CreditContractQueryParameters {
|
||||
name: name.into(),
|
||||
account: account.into(),
|
||||
};
|
||||
let transaction_body = TransactionBody {
|
||||
timestamp: 0,
|
||||
nonce: "".into(),
|
||||
contract: "credit".into(),
|
||||
action: "query".into(),
|
||||
parameters: serde_json::to_string(¶meters)?.into(),
|
||||
};
|
||||
let tx = Transaction::new(&transaction_body, &pri_key, &pub_key)?;
|
||||
|
||||
information!("Create transaction: {:#?}", tx);
|
||||
|
||||
let engine = ContractEngine::new();
|
||||
engine.execute(&tx)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
43
__crypto/simple_contract/src/cmd_credit_queryall.rs
Normal file
43
__crypto/simple_contract/src/cmd_credit_queryall.rs
Normal file
@@ -0,0 +1,43 @@
|
||||
use std::fs;
|
||||
use clap::{App, Arg, ArgMatches, SubCommand};
|
||||
use rust_util::information;
|
||||
use crate::{cmd::{Command, CommandError}, engine_credit::CreditContractQueryAllParameters};
|
||||
use crate::engine::ContractEngine;
|
||||
use crate::tx::{Transaction, TransactionBody};
|
||||
use crate::util::JsonKeyPair;
|
||||
|
||||
pub struct CommandImpl;
|
||||
impl Command for CommandImpl {
|
||||
fn name(&self) -> &str { "queryall" }
|
||||
fn subcommand<'a>(&self) -> App<'a, 'a> {
|
||||
SubCommand::with_name(self.name()).about("Queryall credit contract subcommand")
|
||||
.arg(Arg::with_name("name").long("name").short("n").required(true).takes_value(true).help("Contract name"))
|
||||
.arg(Arg::with_name("key").long("key").short("k").required(true).takes_value(true).help("Key pair"))
|
||||
}
|
||||
fn run(&self, _arg_matches: &ArgMatches, sub_arg_matches: &ArgMatches) -> CommandError {
|
||||
let name = sub_arg_matches.value_of("name").unwrap();
|
||||
let key = sub_arg_matches.value_of("key").unwrap();
|
||||
|
||||
let key_json = fs::read_to_string(key)?;
|
||||
let (pri_key, pub_key) = JsonKeyPair::from_json(&key_json)?.to_key_pair()?;
|
||||
|
||||
let parameters = CreditContractQueryAllParameters {
|
||||
name: name.into(),
|
||||
};
|
||||
let transaction_body = TransactionBody {
|
||||
timestamp: 0,
|
||||
nonce: "".into(),
|
||||
contract: "credit".into(),
|
||||
action: "query_all".into(),
|
||||
parameters: serde_json::to_string(¶meters)?.into(),
|
||||
};
|
||||
let tx = Transaction::new(&transaction_body, &pri_key, &pub_key)?;
|
||||
|
||||
information!("Create transaction: {:#?}", tx);
|
||||
|
||||
let engine = ContractEngine::new();
|
||||
engine.execute(&tx)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
49
__crypto/simple_contract/src/cmd_credit_transfer.rs
Normal file
49
__crypto/simple_contract/src/cmd_credit_transfer.rs
Normal file
@@ -0,0 +1,49 @@
|
||||
use std::fs;
|
||||
use clap::{App, Arg, ArgMatches, SubCommand};
|
||||
use rust_util::information;
|
||||
use crate::{cmd::{Command, CommandError}, engine_credit::CreditContractTransferParameters};
|
||||
use crate::engine::ContractEngine;
|
||||
use crate::tx::{Transaction, TransactionBody};
|
||||
use crate::util::JsonKeyPair;
|
||||
|
||||
pub struct CommandImpl;
|
||||
impl Command for CommandImpl {
|
||||
fn name(&self) -> &str { "transfer" }
|
||||
fn subcommand<'a>(&self) -> App<'a, 'a> {
|
||||
SubCommand::with_name(self.name()).about("Transfer credit contract subcommand")
|
||||
.arg(Arg::with_name("name").long("name").short("n").required(true).takes_value(true).help("Contract name"))
|
||||
.arg(Arg::with_name("receiver").long("receiver").short("r").required(true).takes_value(true).help("Receiver"))
|
||||
.arg(Arg::with_name("credit").long("credit").short("c").required(true).takes_value(true).help("Credit"))
|
||||
.arg(Arg::with_name("key").long("key").short("k").required(true).takes_value(true).help("Key pair"))
|
||||
}
|
||||
fn run(&self, _arg_matches: &ArgMatches, sub_arg_matches: &ArgMatches) -> CommandError {
|
||||
let name = sub_arg_matches.value_of("name").unwrap();
|
||||
let receiver = sub_arg_matches.value_of("receiver").unwrap();
|
||||
let credit: u32 = sub_arg_matches.value_of("credit").unwrap().parse()?;
|
||||
let key = sub_arg_matches.value_of("key").unwrap();
|
||||
|
||||
let key_json = fs::read_to_string(key)?;
|
||||
let (pri_key, pub_key) = JsonKeyPair::from_json(&key_json)?.to_key_pair()?;
|
||||
|
||||
let parameters = CreditContractTransferParameters {
|
||||
name: name.into(),
|
||||
receiver: receiver.into(),
|
||||
credit,
|
||||
};
|
||||
let transaction_body = TransactionBody {
|
||||
timestamp: 0,
|
||||
nonce: "".into(),
|
||||
contract: "credit".into(),
|
||||
action: "transfer".into(),
|
||||
parameters: serde_json::to_string(¶meters)?.into(),
|
||||
};
|
||||
let tx = Transaction::new(&transaction_body, &pri_key, &pub_key)?;
|
||||
|
||||
information!("Create transaction: {:#?}", tx);
|
||||
|
||||
let engine = ContractEngine::new();
|
||||
engine.execute(&tx)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
15
__crypto/simple_contract/src/cmd_default.rs
Normal file
15
__crypto/simple_contract/src/cmd_default.rs
Normal file
@@ -0,0 +1,15 @@
|
||||
use clap::{App, Arg, ArgMatches};
|
||||
use rust_util::information;
|
||||
use crate::cmd::CommandError;
|
||||
pub struct CommandImpl;
|
||||
impl CommandImpl {
|
||||
pub fn process_command<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
||||
app.arg(Arg::with_name("verbose").long("verbose").short("v").multiple(true).help("Show verbose info"))
|
||||
}
|
||||
pub fn run(arg_matches: &ArgMatches) -> CommandError {
|
||||
let verbose_count = arg_matches.occurrences_of("verbose");
|
||||
information!("Verbose count: {}", verbose_count);
|
||||
information!("This is default command cli ...");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
24
__crypto/simple_contract/src/cmd_genkey.rs
Normal file
24
__crypto/simple_contract/src/cmd_genkey.rs
Normal file
@@ -0,0 +1,24 @@
|
||||
use std::fs;
|
||||
use std::fs::File;
|
||||
use clap::{App, Arg, ArgMatches, SubCommand};
|
||||
use rust_util::failure;
|
||||
use crate::{cmd::{Command, CommandError}, util::{JsonKeyPair, make_key_pair}};
|
||||
pub struct CommandImpl;
|
||||
impl Command for CommandImpl {
|
||||
fn name(&self) -> &str { "genkey" }
|
||||
fn subcommand<'a>(&self) -> App<'a, 'a> {
|
||||
SubCommand::with_name(self.name()).about("Generate key pair subcommand")
|
||||
.arg(Arg::with_name("output").long("output").short("o").required(true).takes_value(true).help("Key pair output"))
|
||||
}
|
||||
fn run(&self, _arg_matches: &ArgMatches, sub_arg_matches: &ArgMatches) -> CommandError {
|
||||
let output = sub_arg_matches.value_of("output").unwrap();
|
||||
if let Ok(_) = File::open(output) {
|
||||
failure!("Output file exists: {}", output);
|
||||
return Ok(());
|
||||
}
|
||||
let (pri_key, pub_key) = make_key_pair();
|
||||
let json_key_pair = JsonKeyPair::from(pri_key, pub_key);
|
||||
fs::write(output, json_key_pair.to_json()?.as_bytes())?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::{collections::HashMap, fs, fs::File};
|
||||
use rust_util::{SimpleError, XResult, simple_error};
|
||||
use rust_util::{XResult, information, simple_error};
|
||||
use serde::{Serialize, Deserialize};
|
||||
use crate::{tx::Transaction};
|
||||
use crate::tx::Transaction;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct CreditContract {
|
||||
@@ -18,9 +18,10 @@ impl CreditContract {
|
||||
name: name.into(),
|
||||
credit_limit,
|
||||
issue_amount: 0,
|
||||
admin: tx.sender.clone().unwrap(),
|
||||
admin: tx.sender.clone(),
|
||||
credit: HashMap::new(),
|
||||
};
|
||||
save_credit_contract(&c, false)?;
|
||||
Ok(c)
|
||||
}
|
||||
|
||||
@@ -29,23 +30,29 @@ impl CreditContract {
|
||||
}
|
||||
|
||||
pub fn issue(&mut self, tx: &Transaction, receiver: &str, credit: u32) -> XResult<()> {
|
||||
if &self.admin != tx.sender.as_ref().ok_or_else(|| SimpleError::new("Sender is not provided".into()))? {
|
||||
if &self.admin != &tx.sender {
|
||||
return simple_error!("Current user is not admin, {} vs {:?}", self.admin, tx.sender);
|
||||
}
|
||||
if credit == 0 {
|
||||
return simple_error!("Cannot issue 0 credit!");
|
||||
}
|
||||
if self.issue_amount + credit > self.credit_limit {
|
||||
return simple_error!("Issue too much credit, current: {}, issue: {}, limit: {}", self.issue_amount, credit, self.credit_limit);
|
||||
return simple_error!("Issue too much credit, current: {}, issue: {}, limit: {}, left: {}", self.issue_amount, credit, self.credit_limit, self.credit_limit - self.issue_amount);
|
||||
}
|
||||
match self.credit.get_mut(receiver) {
|
||||
None => { self.credit.insert(receiver.to_owned(), credit); },
|
||||
Some(cr) => *cr += credit,
|
||||
}
|
||||
self.issue_amount += credit;
|
||||
save_credit_contract(self)?;
|
||||
save_credit_contract(self, true)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn transfer(&mut self, tx: &Transaction, receiver: &str, credit: u32) -> XResult<()> {
|
||||
match self.credit.get_mut(tx.sender.as_ref().ok_or_else(|| SimpleError::new("Sender is not provided".into()))?) {
|
||||
if credit == 0 {
|
||||
return simple_error!("Cannot transfer 0 credit!");
|
||||
}
|
||||
match self.credit.get_mut(&tx.sender) {
|
||||
None => return simple_error!("Have not enough credit: {:?}", tx.sender),
|
||||
Some(cr) => {
|
||||
if *cr >= credit {
|
||||
@@ -59,7 +66,7 @@ impl CreditContract {
|
||||
}
|
||||
},
|
||||
}
|
||||
save_credit_contract(self)?;
|
||||
save_credit_contract(self, true)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -80,11 +87,14 @@ fn load_credit_contract(name: &str) -> XResult<CreditContract> {
|
||||
serde_json::from_str(&json).map_err(|e| e.into())
|
||||
}
|
||||
|
||||
fn save_credit_contract(c: &CreditContract) -> XResult<()> {
|
||||
fn save_credit_contract(c: &CreditContract, overwrite: bool) -> XResult<()> {
|
||||
let name = &c.name;
|
||||
if let Ok(_) = File::open(name) {
|
||||
return simple_error!("File exists: {}", name);
|
||||
if !overwrite {
|
||||
if let Ok(_) = File::open(name) {
|
||||
return simple_error!("File exists: {}", name);
|
||||
}
|
||||
}
|
||||
information!("Write file: {}", name);
|
||||
fs::write(name, serde_json::to_string(c)?.as_bytes())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
26
__crypto/simple_contract/src/engine.rs
Normal file
26
__crypto/simple_contract/src/engine.rs
Normal file
@@ -0,0 +1,26 @@
|
||||
use rust_util::{XResult, simple_error};
|
||||
use crate::{engine_credit::ContractEngineCredit, tx::Transaction};
|
||||
|
||||
pub struct ContractEngine {
|
||||
}
|
||||
|
||||
impl ContractEngine {
|
||||
pub fn new() -> Self {
|
||||
Self{}
|
||||
}
|
||||
|
||||
pub fn execute(&self, tx: &Transaction) -> XResult<()> {
|
||||
tx.verify()?;
|
||||
|
||||
let tx_body = tx.parse_body()?;
|
||||
|
||||
match tx_body.contract.as_str() {
|
||||
"credit" => {
|
||||
ContractEngineCredit::new().execute(tx, &tx_body)?;
|
||||
},
|
||||
c => return simple_error!("Unknown cotract: {}", c),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
81
__crypto/simple_contract/src/engine_credit.rs
Normal file
81
__crypto/simple_contract/src/engine_credit.rs
Normal file
@@ -0,0 +1,81 @@
|
||||
use serde::{Serialize, Deserialize};
|
||||
use rust_util::{XResult, debugging, information, simple_error};
|
||||
use crate::{credit::CreditContract, tx::{Transaction, TransactionBody}};
|
||||
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct CreditContractCreateParameters {
|
||||
pub name: String,
|
||||
pub credit_limit: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct CreditContractIssueParameters {
|
||||
pub name: String,
|
||||
pub receiver: String,
|
||||
pub credit: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct CreditContractTransferParameters {
|
||||
pub name: String,
|
||||
pub receiver: String,
|
||||
pub credit: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct CreditContractQueryParameters {
|
||||
pub name: String,
|
||||
pub account: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct CreditContractQueryAllParameters {
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
pub struct ContractEngineCredit {
|
||||
}
|
||||
|
||||
impl ContractEngineCredit {
|
||||
pub fn new() -> Self {
|
||||
Self{}
|
||||
}
|
||||
|
||||
pub fn execute(&self, tx: &Transaction, tx_body: &TransactionBody) -> XResult<()> {
|
||||
let action = tx_body.action.as_str();
|
||||
|
||||
debugging!("Creidt contract, action: {}", action);
|
||||
match action {
|
||||
"create" => {
|
||||
let params: CreditContractCreateParameters = serde_json::from_str(&tx_body.parameters)?;
|
||||
CreditContract::new(tx, ¶ms.name, params.credit_limit)?;
|
||||
},
|
||||
"issue" => {
|
||||
let params: CreditContractIssueParameters = serde_json::from_str(&tx_body.parameters)?;
|
||||
let mut c = CreditContract::load(¶ms.name)?;
|
||||
c.issue(tx, ¶ms.receiver, params.credit)?;
|
||||
},
|
||||
"transfer" => {
|
||||
let params: CreditContractTransferParameters = serde_json::from_str(&tx_body.parameters)?;
|
||||
let mut c = CreditContract::load(¶ms.name)?;
|
||||
c.transfer(tx, ¶ms.receiver, params.credit)?;
|
||||
},
|
||||
"query" => {
|
||||
let params: CreditContractQueryParameters = serde_json::from_str(&tx_body.parameters)?;
|
||||
let c = CreditContract::load(¶ms.name)?;
|
||||
information!("Query: {}, credit: {}", ¶ms.account, c.query(tx, ¶ms.account));
|
||||
},
|
||||
"query_all" => {
|
||||
let params: CreditContractQueryAllParameters = serde_json::from_str(&tx_body.parameters)?;
|
||||
let c = CreditContract::load(¶ms.name)?;
|
||||
let map = c.query_all(tx);
|
||||
map.iter().for_each(|(k , v)| {
|
||||
information!("Query: {}, credit: {}", k, v);
|
||||
});
|
||||
},
|
||||
_ => return simple_error!("Unknown action: {}", action),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -1,32 +1,42 @@
|
||||
pub mod util;
|
||||
pub mod tx;
|
||||
pub mod credit;
|
||||
pub mod engine;
|
||||
pub mod engine_credit;
|
||||
|
||||
use std::str::FromStr;
|
||||
use rust_util::XResult;
|
||||
use secp256k1::{Message, Secp256k1, Signature};
|
||||
use util::*;
|
||||
mod cmd;
|
||||
mod cmd_default;
|
||||
mod cmd_genkey;
|
||||
mod cmd_credit_create;
|
||||
mod cmd_credit_issue;
|
||||
mod cmd_credit_transfer;
|
||||
mod cmd_credit_query;
|
||||
mod cmd_credit_queryall;
|
||||
|
||||
fn main() -> XResult<()> {
|
||||
let (pri_key, pub_key) = make_key_pair();
|
||||
println!("{:?}", pri_key);
|
||||
println!("{:?}", pub_key);
|
||||
println!("{:?}", JsonKeyPair::from(pri_key, pub_key).to_json());
|
||||
println!("{:?}", JsonKeyPair::from(pri_key, pub_key).to_key_pair());
|
||||
println!("{}", make_btc_address(&pub_key));
|
||||
use clap::App;
|
||||
use cmd::{Command, CommandError};
|
||||
|
||||
let p256k1 = Secp256k1::new();
|
||||
let s =calc_sha256("hello".as_bytes());
|
||||
let message = Message::from_slice(&s)?;
|
||||
|
||||
let sign = p256k1.sign(&message, &pri_key);
|
||||
let sign_hex = format!("{}", sign);
|
||||
println!("{}", sign_hex);
|
||||
|
||||
let sig = Signature::from_str(&sign_hex)?;
|
||||
|
||||
let result = p256k1.verify(&message, &sig, &pub_key);
|
||||
println!("{:?}", result);
|
||||
|
||||
Ok(())
|
||||
fn main() -> CommandError {
|
||||
let commands: Vec<Box<dyn Command>> = vec![
|
||||
Box::new(cmd_genkey::CommandImpl),
|
||||
Box::new(cmd_credit_create::CommandImpl),
|
||||
Box::new(cmd_credit_issue::CommandImpl),
|
||||
Box::new(cmd_credit_transfer::CommandImpl),
|
||||
Box::new(cmd_credit_query::CommandImpl),
|
||||
Box::new(cmd_credit_queryall::CommandImpl),
|
||||
];
|
||||
let mut app = App::new(env!("CARGO_PKG_NAME"))
|
||||
.version(env!("CARGO_PKG_VERSION"))
|
||||
.about(env!("CARGO_PKG_DESCRIPTION"));
|
||||
app = cmd_default::CommandImpl::process_command(app);
|
||||
for command in &commands {
|
||||
app = app.subcommand(command.subcommand());
|
||||
}
|
||||
let matches = app.get_matches();
|
||||
for command in &commands {
|
||||
if let Some(sub_cmd_matches) = matches.subcommand_matches(command.name()) {
|
||||
return command.run(&matches, sub_cmd_matches);
|
||||
}
|
||||
}
|
||||
cmd_default::CommandImpl::run(&matches)
|
||||
}
|
||||
|
||||
@@ -7,8 +7,9 @@ use crate::util::{calc_sha256, make_btc_address};
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Transaction {
|
||||
pub body: String,
|
||||
pub sender: Option<String>,
|
||||
pub signature: Option<String>,
|
||||
pub sender: String,
|
||||
pub public_key: String,
|
||||
pub signature: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
@@ -21,57 +22,43 @@ pub struct TransactionBody {
|
||||
}
|
||||
|
||||
impl Transaction {
|
||||
pub fn from_json(transaction_json: &str) -> XResult<Self> {
|
||||
serde_json::from_str(transaction_json).map_err(|e| e.into())
|
||||
pub fn new(transaction_body: &TransactionBody, priv_key: &SecretKey, pub_key: &PublicKey) -> XResult<Self> {
|
||||
let body = serde_json::to_string(transaction_body)?;
|
||||
let sender = make_btc_address(&pub_key);
|
||||
let public_key = format!("{}", pub_key);
|
||||
|
||||
let message = get_body_message(&body)?;
|
||||
let sign = Secp256k1::new().sign(&message, priv_key);
|
||||
|
||||
Ok(Self{
|
||||
body,
|
||||
sender,
|
||||
public_key,
|
||||
signature: format!("{}", sign),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn from_transaction_body(transaction_body: &TransactionBody) -> XResult<Self> {
|
||||
Ok(Self {
|
||||
body: serde_json::to_string(transaction_body)?,
|
||||
sender: None,
|
||||
signature: None,
|
||||
})
|
||||
pub fn from_json(transaction_json: &str) -> XResult<Self> {
|
||||
serde_json::from_str(transaction_json).map_err(|e| e.into())
|
||||
}
|
||||
|
||||
pub fn parse_body(&self) -> XResult<TransactionBody> {
|
||||
serde_json::from_str(&self.body).map_err(|e| e.into())
|
||||
}
|
||||
|
||||
pub fn is_signed(&self) -> bool {
|
||||
self.signature.is_some()
|
||||
}
|
||||
|
||||
pub fn sign(&mut self, sender: &str, priv_key: &SecretKey) -> XResult<()> {
|
||||
if self.signature.is_some() {
|
||||
simple_error!("Transaction is signed!")
|
||||
} else {
|
||||
let message = self.get_body_message()?;
|
||||
let sign = Secp256k1::new().sign(&message, priv_key);
|
||||
self.sender = Some(sender.into());
|
||||
self.signature = Some(format!("{}", sign));
|
||||
Ok(())
|
||||
pub fn verify(&self) -> XResult<()> {
|
||||
let public_key = PublicKey::from_str(&self.public_key)?;
|
||||
let address = make_btc_address(&public_key);
|
||||
if &address != &self.sender {
|
||||
return simple_error!("Assress and sender not match!");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn verify(&self, pub_key: &PublicKey) -> XResult<()> {
|
||||
match (&self.sender, &self.signature) {
|
||||
(None, None) | (None, Some(_)) | (Some(_), None) => {
|
||||
simple_error!("Transaction has no sender or not signed!")
|
||||
},
|
||||
(Some(sender), Some(sign_hex)) => {
|
||||
let address = make_btc_address(pub_key);
|
||||
if &address != sender {
|
||||
return simple_error!("Assress and sender not match!");
|
||||
}
|
||||
let message = self.get_body_message()?;
|
||||
let sig = Signature::from_str(sign_hex)?;
|
||||
Secp256k1::new().verify(&message, &sig, pub_key).map_err(|e| e.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_body_message(&self) -> XResult<Message> {
|
||||
let digest= calc_sha256(self.body.as_bytes());
|
||||
Message::from_slice(&digest).map_err(|e| e.into())
|
||||
let message = get_body_message(&self.body)?;
|
||||
let sig = Signature::from_str(&self.signature)?;
|
||||
Secp256k1::new().verify(&message, &sig, &public_key).map_err(|e| e.into())
|
||||
}
|
||||
}
|
||||
|
||||
fn get_body_message(body: &str) -> XResult<Message> {
|
||||
let digest= calc_sha256(body.as_bytes());
|
||||
Message::from_slice(&digest).map_err(|e| e.into())
|
||||
}
|
||||
@@ -10,6 +10,7 @@ use std::str::FromStr;
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct JsonKeyPair {
|
||||
pub identity: String,
|
||||
pub pri_key: String,
|
||||
pub pub_key: String,
|
||||
}
|
||||
@@ -17,13 +18,18 @@ pub struct JsonKeyPair {
|
||||
impl JsonKeyPair {
|
||||
pub fn from(pri_key: SecretKey, pub_key: PublicKey) -> Self {
|
||||
JsonKeyPair {
|
||||
identity: make_btc_address(&pub_key),
|
||||
pri_key: format!("{}", pri_key),
|
||||
pub_key: format!("{}", pub_key),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_json(&self) -> XResult<String> {
|
||||
serde_json::to_string(self).map_err(|e| e.into())
|
||||
serde_json::to_string_pretty(self).map_err(|e| e.into())
|
||||
}
|
||||
|
||||
pub fn from_json(json: &str) -> XResult<Self> {
|
||||
serde_json::from_str(json).map_err(|e| e.into())
|
||||
}
|
||||
|
||||
pub fn to_key_pair(&self) -> XResult<(SecretKey, PublicKey)> {
|
||||
|
||||
Reference in New Issue
Block a user