Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Save slate participant messages in database #2441

Merged
merged 12 commits into from
Jan 31, 2019
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,6 @@ chrono = "0.4.4"

grin_keychain = { path = "../keychain", version = "1.0.0" }
grin_util = { path = "../util", version = "1.0.0" }

[dev-dependencies]
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Anyone have any major problems with this dev-dependency? Would rather avoid but seems best way to run serialization tests.

serde_json = "1"
2 changes: 1 addition & 1 deletion core/src/libtx/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ pub mod build;
mod error;
pub mod proof;
pub mod reward;
pub mod serialization;
pub mod secp_ser;
pub mod slate;

use crate::consensus;
Expand Down
55 changes: 55 additions & 0 deletions core/src/libtx/serialization.rs → core/src/libtx/secp_ser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,3 +173,58 @@ where
{
serializer.serialize_str(&to_hex(bytes.as_ref().to_vec()))
}

// Test serialization methods of components that are being used
#[cfg(test)]
mod test {
use super::*;
use crate::libtx::aggsig;
use crate::util::secp::key::{PublicKey, SecretKey};
use crate::util::secp::{Message, Signature};
use crate::util::static_secp_instance;

use serde_json;

use rand::{thread_rng, Rng};

#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone)]
struct SerTest {
#[serde(with = "pubkey_serde")]
pub pub_key: PublicKey,
#[serde(with = "option_sig_serde")]
pub opt_sig: Option<Signature>,
#[serde(with = "sig_serde")]
pub sig: Signature,
}

impl SerTest {
pub fn random() -> SerTest {
let static_secp = static_secp_instance();
let secp = static_secp.lock();
let sk = SecretKey::new(&secp, &mut thread_rng());
let mut msg = [0u8; 32];
thread_rng().fill(&mut msg);
let msg = Message::from_slice(&msg).unwrap();
let sig = aggsig::sign_single(&secp, &msg, &sk, None).unwrap();
SerTest {
pub_key: PublicKey::from_secret_key(&secp, &sk).unwrap(),
opt_sig: Some(sig.clone()),
sig: sig.clone(),
}
}
}

#[test]
fn ser_secp_primitives() {
for _ in 0..10 {
let s = SerTest::random();
println!("Before Serialization: {:?}", s);
let serialized = serde_json::to_string_pretty(&s).unwrap();
println!("JSON: {}", serialized);
let deserialized: SerTest = serde_json::from_str(&serialized).unwrap();
println!("After Serialization: {:?}", deserialized);
println!();
assert_eq!(s, deserialized);
}
}
}
47 changes: 45 additions & 2 deletions core/src/libtx/slate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use crate::core::transaction::{kernel_features, kernel_sig_msg, Transaction, Wei
use crate::core::verifier_cache::LruVerifierCache;
use crate::keychain::{BlindSum, BlindingFactor, Keychain};
use crate::libtx::error::{Error, ErrorKind};
use crate::libtx::{aggsig, build, tx_fee};
use crate::libtx::{aggsig, build, secp_ser, tx_fee};
use crate::util::secp;
use crate::util::secp::key::{PublicKey, SecretKey};
use crate::util::secp::Signature;
Expand Down Expand Up @@ -66,6 +66,33 @@ impl ParticipantData {
}
}

/// Public message data (for serialising and storage)
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ParticipantMessageData {
/// id of the particpant in the tx
pub id: u64,
/// Public key
#[serde(with = "secp_ser::pubkey_serde")]
pub public_key: PublicKey,
/// Message,
pub message: Option<String>,
/// Signature
#[serde(with = "secp_ser::option_sig_serde")]
pub message_sig: Option<Signature>,
}

impl ParticipantMessageData {
/// extract relevant message data from participant data
pub fn from_participant_data(p: &ParticipantData) -> ParticipantMessageData {
ParticipantMessageData {
id: p.id,
public_key: p.public_blind_excess,
message: p.message.clone(),
message_sig: p.message_sig.clone(),
}
}
}

/// A 'Slate' is passed around to all parties to build up all of the public
/// transaction data needed to create a finalized transaction. Callers can pass
/// the slate around by whatever means they choose, (but we can provide some
Expand Down Expand Up @@ -94,6 +121,13 @@ pub struct Slate {
pub participant_data: Vec<ParticipantData>,
}

/// Helper just to facilitate serialization
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ParticipantMessages {
/// included messages
pub messages: Vec<ParticipantMessageData>,
}

impl Slate {
/// Create a new slate
pub fn blank(num_participants: usize) -> Slate {
Expand Down Expand Up @@ -274,10 +308,19 @@ impl Slate {
message: message,
message_sig: message_sig,
});

Ok(())
}

/// helper to return all participant messages
pub fn participant_messages(&self) -> ParticipantMessages {
let mut ret = ParticipantMessages { messages: vec![] };
for ref m in self.participant_data.iter() {
ret.messages
.push(ParticipantMessageData::from_participant_data(m));
}
ret
}

/// Somebody involved needs to generate an offset with their private key
/// For now, we'll have the transaction initiator be responsible for it
/// Return offset private key for the participant to use later in the
Expand Down
18 changes: 17 additions & 1 deletion src/bin/cmd/wallet_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,16 @@ mod wallet_tests {
let mut bh = 10u64;
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), bh as usize);

let very_long_message = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef\
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef\
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef\
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef\
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef\
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef\
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef\
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef\
This part should all be truncated";

// Update info and check
let arg_vec = vec!["grin", "wallet", "-p", "password", "-a", "mining", "info"];
execute_command(&app, test_dir, "wallet1", &client1, arg_vec)?;
Expand All @@ -273,7 +283,7 @@ mod wallet_tests {
"-d",
&file_name,
"-g",
"Love, Yeast",
very_long_message,
"10",
];
execute_command(&app, test_dir, "wallet1", &client1, arg_vec)?;
Expand Down Expand Up @@ -491,6 +501,12 @@ mod wallet_tests {
let arg_vec = vec!["grin", "wallet", "-p", "password", "-a", "mining", "txs"];
execute_command(&app, test_dir, "wallet1", &client1, arg_vec)?;

// message output (mostly spit out for a visual in test logs)
let arg_vec = vec![
"grin", "wallet", "-p", "password", "-a", "mining", "txs", "-i", "10",
];
execute_command(&app, test_dir, "wallet1", &client1, arg_vec)?;

// txs and outputs (mostly spit out for a visual in test logs)
let arg_vec = vec![
"grin", "wallet", "-p", "password", "-a", "mining", "outputs",
Expand Down
8 changes: 6 additions & 2 deletions wallet/src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -396,15 +396,19 @@ pub fn txs(
&g_args.account,
height,
validated,
txs,
&txs,
include_status,
dark_scheme,
)?;
// if given a particular transaction id, also get and display associated
// inputs/outputs
// inputs/outputs and messages
if args.id.is_some() {
let (_, outputs) = api.retrieve_outputs(true, false, args.id)?;
display::outputs(&g_args.account, height, validated, outputs, dark_scheme)?;
// should only be one here, but just in case
for tx in txs {
display::tx_messages(&tx, dark_scheme)?;
}
};
Ok(())
})?;
Expand Down
76 changes: 75 additions & 1 deletion wallet/src/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ pub fn txs(
account: &str,
cur_height: u64,
validated: bool,
txs: Vec<TxLogEntry>,
txs: &Vec<TxLogEntry>,
include_status: bool,
dark_background_color_scheme: bool,
) -> Result<(), Error> {
Expand Down Expand Up @@ -357,3 +357,77 @@ pub fn accounts(acct_mappings: Vec<AcctPathMapping>) {
table.printstd();
println!();
}

/// Display transaction log messages
pub fn tx_messages(tx: &TxLogEntry, dark_background_color_scheme: bool) -> Result<(), Error> {
let title = format!("Transaction Messages - Transaction '{}'", tx.id,);
println!();
let mut t = term::stdout().unwrap();
t.fg(term::color::MAGENTA).unwrap();
writeln!(t, "{}", title).unwrap();
t.reset().unwrap();

let msgs = match tx.messages.clone() {
None => {
writeln!(t, "{}", "None").unwrap();
t.reset().unwrap();
return Ok(());
}
Some(m) => m.clone(),
};

if msgs.messages.is_empty() {
writeln!(t, "{}", "None").unwrap();
t.reset().unwrap();
return Ok(());
}

let mut table = table!();

table.set_titles(row![
bMG->"Participant Id",
bMG->"Message",
bMG->"Public Key",
bMG->"Signature",
]);

let secp = util::static_secp_instance();
let secp_lock = secp.lock();

for m in msgs.messages {
let id = format!("{}", m.id);
let public_key = format!(
"{}",
util::to_hex(m.public_key.serialize_vec(&secp_lock, true).to_vec())
);
let message = match m.message {
Some(m) => format!("{}", m),
None => "None".to_owned(),
};
let message_sig = match m.message_sig {
Some(s) => format!("{}", util::to_hex(s.serialize_der(&secp_lock))),
None => "None".to_owned(),
};
if dark_background_color_scheme {
table.add_row(row![
bFC->id,
bFC->message,
bFC->public_key,
bFB->message_sig,
]);
} else {
table.add_row(row![
bFD->id,
bFb->message,
bFD->public_key,
bFB->message_sig,
]);
}
}

table.set_format(*prettytable::format::consts::FORMAT_NO_COLSEP);
table.printstd();
println!();

Ok(())
}
24 changes: 22 additions & 2 deletions wallet/src/libwallet/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ use crate::libwallet::{Error, ErrorKind};
use crate::util;
use crate::util::secp::{pedersen, ContextFlag, Secp256k1};

const USER_MESSAGE_MAX_LEN: usize = 256;

/// Functions intended for use by the owner (e.g. master seed holder) of the wallet.
pub struct APIOwner<W: ?Sized, C, K>
where
Expand Down Expand Up @@ -551,7 +553,8 @@ where
/// ParticipantData within the slate. This message will include a signature created with the
/// sender's private keys, and will be publically verifiable. Note this message is for
/// the convenience of the participants during the exchange; it is not included in the final
/// transaction sent to the chain. Validation of this message is optional.
/// transaction sent to the chain. The message will be truncated to 256 characters.
/// Validation of this message is optional.
///
/// # Returns
/// * a result containing:
Expand Down Expand Up @@ -640,6 +643,14 @@ where
None => w.parent_key_id(),
};

let message = match message {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: I'd suggest to introduce SlateMessage type and define semantic (it could be None, if not String has limited length) there, we truncate twice in this pr, could forget to do it introducing some new logic later on

Some(mut m) => {
m.truncate(USER_MESSAGE_MAX_LEN);
Some(m)
}
None => None,
};

let (slate, context, lock_fn) = tx::create_send_tx(
&mut *w,
amount,
Expand Down Expand Up @@ -685,12 +696,12 @@ where
let context = w.get_private_context(slate.id.as_bytes())?;
tx::complete_tx(&mut *w, slate, &context)?;
tx::update_stored_tx(&mut *w, slate)?;
tx::update_message(&mut *w, slate)?;
{
let mut batch = w.batch()?;
batch.delete_private_context(slate.id.as_bytes())?;
batch.commit()?;
}

w.close()?;
Ok(())
}
Expand Down Expand Up @@ -873,6 +884,15 @@ where
return Err(ErrorKind::TransactionAlreadyReceived(slate.id.to_string()).into());
}
}

let message = match message {
Some(mut m) => {
m.truncate(USER_MESSAGE_MAX_LEN);
Some(m)
}
None => None,
};

let res = tx::receive_tx(&mut *w, slate, &parent_key_id, message);
w.close()?;

Expand Down
Loading