mirror of
https://github.com/mimblewimble/grin-wallet.git
synced 2025-02-01 08:51:09 +03:00
V2 Slate Compatibility (#272)
* re-insert v2 slate * reinstate version conversions * rustfmt * add and test versioning checks against 2.0.0 wallets * rustfmt * fix to invoice file output * doctest fix * remove target slate version from command line options
This commit is contained in:
parent
7db55592d0
commit
86e6f511c3
10 changed files with 591 additions and 54 deletions
|
@ -53,7 +53,8 @@ pub trait ForeignRpc {
|
||||||
"Ok": {
|
"Ok": {
|
||||||
"foreign_api_version": 2,
|
"foreign_api_version": 2,
|
||||||
"supported_slate_versions": [
|
"supported_slate_versions": [
|
||||||
"V3"
|
"V3",
|
||||||
|
"V2"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -553,9 +554,10 @@ where
|
||||||
message: Option<String>,
|
message: Option<String>,
|
||||||
) -> Result<VersionedSlate, ErrorKind> {
|
) -> Result<VersionedSlate, ErrorKind> {
|
||||||
let version = in_slate.version();
|
let version = in_slate.version();
|
||||||
|
let slate_from = Slate::from(in_slate);
|
||||||
let out_slate = Foreign::receive_tx(
|
let out_slate = Foreign::receive_tx(
|
||||||
self,
|
self,
|
||||||
&Slate::from(in_slate),
|
&slate_from,
|
||||||
dest_acct_name.as_ref().map(String::as_str),
|
dest_acct_name.as_ref().map(String::as_str),
|
||||||
message,
|
message,
|
||||||
)
|
)
|
||||||
|
|
|
@ -513,9 +513,7 @@ where
|
||||||
{
|
{
|
||||||
controller::owner_single_use(wallet.clone(), keychain_mask, |api, m| {
|
controller::owner_single_use(wallet.clone(), keychain_mask, |api, m| {
|
||||||
let slate = api.issue_invoice_tx(m, args.issue_args)?;
|
let slate = api.issue_invoice_tx(m, args.issue_args)?;
|
||||||
let mut tx_file = File::create(args.dest.clone())?;
|
PathToSlate((&args.dest).into()).put_tx(&slate)?;
|
||||||
tx_file.write_all(json::to_string(&slate).unwrap().as_bytes())?;
|
|
||||||
tx_file.sync_all()?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
})?;
|
})?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -19,7 +19,7 @@ use crate::config::TorConfig;
|
||||||
use crate::keychain::Keychain;
|
use crate::keychain::Keychain;
|
||||||
use crate::libwallet::{
|
use crate::libwallet::{
|
||||||
address, Error, ErrorKind, NodeClient, NodeVersionInfo, Slate, WalletInst, WalletLCProvider,
|
address, Error, ErrorKind, NodeClient, NodeVersionInfo, Slate, WalletInst, WalletLCProvider,
|
||||||
CURRENT_SLATE_VERSION, GRIN_BLOCK_HEADER_VERSION,
|
GRIN_BLOCK_HEADER_VERSION,
|
||||||
};
|
};
|
||||||
use crate::util::secp::key::SecretKey;
|
use crate::util::secp::key::SecretKey;
|
||||||
use crate::util::{from_hex, static_secp_instance, to_base64, Mutex};
|
use crate::util::{from_hex, static_secp_instance, to_base64, Mutex};
|
||||||
|
@ -63,10 +63,7 @@ fn check_middleware(
|
||||||
bhv = n.block_header_version;
|
bhv = n.block_header_version;
|
||||||
}
|
}
|
||||||
if let Some(s) = slate {
|
if let Some(s) = slate {
|
||||||
if s.version_info.version < CURRENT_SLATE_VERSION
|
if bhv > 3 && s.version_info.block_header_version < GRIN_BLOCK_HEADER_VERSION {
|
||||||
// || (bhv == 3 && s.version_info.block_header_version != 3)
|
|
||||||
|| (bhv > 3 && s.version_info.block_header_version < GRIN_BLOCK_HEADER_VERSION)
|
|
||||||
{
|
|
||||||
Err(ErrorKind::Compatibility(
|
Err(ErrorKind::Compatibility(
|
||||||
"Incoming Slate is not compatible with this wallet. \
|
"Incoming Slate is not compatible with this wallet. \
|
||||||
Please upgrade the node or use a different one."
|
Please upgrade the node or use a different one."
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
|
|
||||||
use crate::libwallet::{Error, ErrorKind, Slate};
|
use crate::libwallet::{Error, ErrorKind, Slate, SlateVersion, VersionedSlate};
|
||||||
use crate::{SlateGetter, SlatePutter};
|
use crate::{SlateGetter, SlatePutter};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
@ -26,8 +26,20 @@ pub struct PathToSlate(pub PathBuf);
|
||||||
impl SlatePutter for PathToSlate {
|
impl SlatePutter for PathToSlate {
|
||||||
fn put_tx(&self, slate: &Slate) -> Result<(), Error> {
|
fn put_tx(&self, slate: &Slate) -> Result<(), Error> {
|
||||||
let mut pub_tx = File::create(&self.0)?;
|
let mut pub_tx = File::create(&self.0)?;
|
||||||
|
let out_slate = {
|
||||||
|
if slate.payment_proof.is_some() || slate.ttl_cutoff_height.is_some() {
|
||||||
|
warn!("Transaction contains features that require grin-wallet 3.0.0 or later");
|
||||||
|
warn!("Please ensure the other party is running grin-wallet v3.0.0 or later before sending");
|
||||||
|
VersionedSlate::into_version(slate.clone(), SlateVersion::V3)
|
||||||
|
} else {
|
||||||
|
let mut s = slate.clone();
|
||||||
|
s.version_info.version = 2;
|
||||||
|
s.version_info.orig_version = 2;
|
||||||
|
VersionedSlate::into_version(s, SlateVersion::V2)
|
||||||
|
}
|
||||||
|
};
|
||||||
pub_tx.write_all(
|
pub_tx.write_all(
|
||||||
serde_json::to_string(slate)
|
serde_json::to_string(&out_slate)
|
||||||
.map_err(|_| ErrorKind::SlateSer)?
|
.map_err(|_| ErrorKind::SlateSer)?
|
||||||
.as_bytes(),
|
.as_bytes(),
|
||||||
)?;
|
)?;
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
/// HTTP Wallet 'plugin' implementation
|
/// HTTP Wallet 'plugin' implementation
|
||||||
use crate::client_utils::{Client, ClientError};
|
use crate::client_utils::{Client, ClientError};
|
||||||
|
use crate::libwallet::slate_versions::{SlateVersion, VersionedSlate};
|
||||||
use crate::libwallet::{Error, ErrorKind, Slate};
|
use crate::libwallet::{Error, ErrorKind, Slate};
|
||||||
use crate::SlateSender;
|
use crate::SlateSender;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
@ -64,7 +65,7 @@ impl HttpSlateSender {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check version of the listening wallet
|
/// Check version of the listening wallet
|
||||||
fn check_other_version(&self, url: &str) -> Result<(), Error> {
|
fn check_other_version(&self, url: &str) -> Result<SlateVersion, Error> {
|
||||||
let req = json!({
|
let req = json!({
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"method": "check_version",
|
"method": "check_version",
|
||||||
|
@ -111,13 +112,16 @@ impl HttpSlateSender {
|
||||||
return Err(ErrorKind::ClientCallback(report).into());
|
return Err(ErrorKind::ClientCallback(report).into());
|
||||||
}
|
}
|
||||||
|
|
||||||
if !supported_slate_versions.contains(&"V3".to_owned()) {
|
if supported_slate_versions.contains(&"V3".to_owned()) {
|
||||||
let report = format!("Unable to negotiate slate format with other wallet.");
|
return Ok(SlateVersion::V3);
|
||||||
error!("{}", report);
|
}
|
||||||
return Err(ErrorKind::ClientCallback(report).into());
|
if supported_slate_versions.contains(&"V2".to_owned()) {
|
||||||
|
return Ok(SlateVersion::V2);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
let report = format!("Unable to negotiate slate format with other wallet.");
|
||||||
|
error!("{}", report);
|
||||||
|
Err(ErrorKind::ClientCallback(report).into())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn post<IN>(
|
fn post<IN>(
|
||||||
|
@ -173,15 +177,28 @@ impl SlateSender for HttpSlateSender {
|
||||||
.map_err(|e| ErrorKind::TorProcess(format!("{:?}", e).into()))?;
|
.map_err(|e| ErrorKind::TorProcess(format!("{:?}", e).into()))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.check_other_version(&url_str)?;
|
let slate_send = match self.check_other_version(&url_str)? {
|
||||||
|
SlateVersion::V3 => VersionedSlate::into_version(slate.clone(), SlateVersion::V3),
|
||||||
|
SlateVersion::V2 => {
|
||||||
|
let mut slate = slate.clone();
|
||||||
|
if let Some(_) = slate.payment_proof {
|
||||||
|
return Err(ErrorKind::ClientCallback("Payment proof requested, but other wallet does not support payment proofs. Please urge other user to upgrade, or re-send tx without a payment proof".into()).into());
|
||||||
|
}
|
||||||
|
if let Some(_) = slate.ttl_cutoff_height {
|
||||||
|
warn!("Slate TTL value will be ignored and removed by other wallet, as other wallet does not support this feature. Please urge other user to upgrade");
|
||||||
|
}
|
||||||
|
slate.version_info.version = 2;
|
||||||
|
slate.version_info.orig_version = 2;
|
||||||
|
VersionedSlate::into_version(slate, SlateVersion::V2)
|
||||||
|
}
|
||||||
|
};
|
||||||
// Note: not using easy-jsonrpc as don't want the dependencies in this crate
|
// Note: not using easy-jsonrpc as don't want the dependencies in this crate
|
||||||
let req = json!({
|
let req = json!({
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"method": "receive_tx",
|
"method": "receive_tx",
|
||||||
"id": 1,
|
"id": 1,
|
||||||
"params": [
|
"params": [
|
||||||
slate,
|
slate_send,
|
||||||
null,
|
null,
|
||||||
null
|
null
|
||||||
]
|
]
|
||||||
|
|
|
@ -42,6 +42,7 @@ use std::fmt;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
use crate::slate_versions::v2::SlateV2;
|
||||||
use crate::slate_versions::v3::{
|
use crate::slate_versions::v3::{
|
||||||
CoinbaseV3, InputV3, OutputV3, ParticipantDataV3, PaymentInfoV3, SlateV3, TransactionBodyV3,
|
CoinbaseV3, InputV3, OutputV3, ParticipantDataV3, PaymentInfoV3, SlateV3, TransactionBodyV3,
|
||||||
TransactionV3, TxKernelV3, VersionCompatInfoV3,
|
TransactionV3, TxKernelV3, VersionCompatInfoV3,
|
||||||
|
@ -232,13 +233,11 @@ impl Slate {
|
||||||
let version = Slate::parse_slate_version(slate_json)?;
|
let version = Slate::parse_slate_version(slate_json)?;
|
||||||
let v3: SlateV3 = match version {
|
let v3: SlateV3 = match version {
|
||||||
3 => serde_json::from_str(slate_json).context(ErrorKind::SlateDeser)?,
|
3 => serde_json::from_str(slate_json).context(ErrorKind::SlateDeser)?,
|
||||||
// left as a reminder
|
2 => {
|
||||||
/*0 => {
|
let v2: SlateV2 =
|
||||||
let v0: SlateV0 =
|
|
||||||
serde_json::from_str(slate_json).context(ErrorKind::SlateDeser)?;
|
serde_json::from_str(slate_json).context(ErrorKind::SlateDeser)?;
|
||||||
let v1 = SlateV1::from(v0);
|
SlateV3::from(v2)
|
||||||
SlateV3::from(v1)
|
}
|
||||||
}*/
|
|
||||||
_ => return Err(ErrorKind::SlateVersion(version).into()),
|
_ => return Err(ErrorKind::SlateVersion(version).into()),
|
||||||
};
|
};
|
||||||
Ok(v3.into())
|
Ok(v3.into())
|
||||||
|
@ -728,11 +727,10 @@ impl Serialize for Slate {
|
||||||
match self.version_info.orig_version {
|
match self.version_info.orig_version {
|
||||||
3 => v3.serialize(serializer),
|
3 => v3.serialize(serializer),
|
||||||
// left as a reminder
|
// left as a reminder
|
||||||
/*0 => {
|
2 => {
|
||||||
let v1 = SlateV1::from(v2);
|
let v2 = SlateV2::from(&v3);
|
||||||
let v0 = SlateV0::from(v1);
|
v2.serialize(serializer)
|
||||||
v0.serialize(serializer)
|
}
|
||||||
}*/
|
|
||||||
v => Err(S::Error::custom(format!("Unknown slate version {}", v))),
|
v => Err(S::Error::custom(format!("Unknown slate version {}", v))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,11 +18,14 @@
|
||||||
//! remains for future needs
|
//! remains for future needs
|
||||||
|
|
||||||
use crate::slate::Slate;
|
use crate::slate::Slate;
|
||||||
|
use crate::slate_versions::v2::{CoinbaseV2, SlateV2};
|
||||||
use crate::slate_versions::v3::{CoinbaseV3, SlateV3};
|
use crate::slate_versions::v3::{CoinbaseV3, SlateV3};
|
||||||
use crate::types::CbData;
|
use crate::types::CbData;
|
||||||
|
|
||||||
pub mod ser;
|
pub mod ser;
|
||||||
|
|
||||||
|
#[allow(missing_docs)]
|
||||||
|
pub mod v2;
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
pub mod v3;
|
pub mod v3;
|
||||||
|
|
||||||
|
@ -37,6 +40,8 @@ pub const GRIN_BLOCK_HEADER_VERSION: u16 = 3;
|
||||||
pub enum SlateVersion {
|
pub enum SlateVersion {
|
||||||
/// V3 (most current)
|
/// V3 (most current)
|
||||||
V3,
|
V3,
|
||||||
|
/// V2 (2.0.0 - Onwards)
|
||||||
|
V2,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
@ -46,6 +51,8 @@ pub enum SlateVersion {
|
||||||
pub enum VersionedSlate {
|
pub enum VersionedSlate {
|
||||||
/// Current (3.0.0 Onwards )
|
/// Current (3.0.0 Onwards )
|
||||||
V3(SlateV3),
|
V3(SlateV3),
|
||||||
|
/// V2 (2.0.0 - Onwards)
|
||||||
|
V2(SlateV2),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VersionedSlate {
|
impl VersionedSlate {
|
||||||
|
@ -53,6 +60,7 @@ impl VersionedSlate {
|
||||||
pub fn version(&self) -> SlateVersion {
|
pub fn version(&self) -> SlateVersion {
|
||||||
match *self {
|
match *self {
|
||||||
VersionedSlate::V3(_) => SlateVersion::V3,
|
VersionedSlate::V3(_) => SlateVersion::V3,
|
||||||
|
VersionedSlate::V2(_) => SlateVersion::V2,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,12 +70,11 @@ impl VersionedSlate {
|
||||||
SlateVersion::V3 => VersionedSlate::V3(slate.into()),
|
SlateVersion::V3 => VersionedSlate::V3(slate.into()),
|
||||||
// Left here as a reminder of what needs to be inserted on
|
// Left here as a reminder of what needs to be inserted on
|
||||||
// the release of a new slate
|
// the release of a new slate
|
||||||
/*SlateVersion::V0 => {
|
SlateVersion::V2 => {
|
||||||
let s = SlateV3::from(slate);
|
let s = SlateV3::from(slate);
|
||||||
let s = SlateV1::from(s);
|
let s = SlateV2::from(&s);
|
||||||
let s = SlateV0::from(s);
|
VersionedSlate::V2(s)
|
||||||
VersionedSlate::V0(s)
|
}
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -78,13 +85,11 @@ impl From<VersionedSlate> for Slate {
|
||||||
VersionedSlate::V3(s) => {
|
VersionedSlate::V3(s) => {
|
||||||
let s = SlateV3::from(s);
|
let s = SlateV3::from(s);
|
||||||
Slate::from(s)
|
Slate::from(s)
|
||||||
} // Again, left in as a reminder
|
}
|
||||||
/*VersionedSlate::V0(s) => {
|
VersionedSlate::V2(s) => {
|
||||||
let s = SlateV0::from(s);
|
let s = SlateV3::from(s);
|
||||||
let s = SlateV1::from(s);
|
Slate::from(s)
|
||||||
let s = SlateV2::from(s);
|
}
|
||||||
Slate::from(s)
|
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,6 +101,8 @@ impl From<VersionedSlate> for Slate {
|
||||||
pub enum VersionedCoinbase {
|
pub enum VersionedCoinbase {
|
||||||
/// Current supported coinbase version.
|
/// Current supported coinbase version.
|
||||||
V3(CoinbaseV3),
|
V3(CoinbaseV3),
|
||||||
|
/// Previous
|
||||||
|
V2(CoinbaseV2),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VersionedCoinbase {
|
impl VersionedCoinbase {
|
||||||
|
@ -103,6 +110,7 @@ impl VersionedCoinbase {
|
||||||
pub fn into_version(cb: CbData, version: SlateVersion) -> VersionedCoinbase {
|
pub fn into_version(cb: CbData, version: SlateVersion) -> VersionedCoinbase {
|
||||||
match version {
|
match version {
|
||||||
SlateVersion::V3 => VersionedCoinbase::V3(cb.into()),
|
SlateVersion::V3 => VersionedCoinbase::V3(cb.into()),
|
||||||
|
SlateVersion::V2 => VersionedCoinbase::V2(cb.into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
214
libwallet/src/slate_versions/v2.rs
Normal file
214
libwallet/src/slate_versions/v2.rs
Normal file
|
@ -0,0 +1,214 @@
|
||||||
|
// Copyright 2019 The Grin Developers
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
//! Contains V2 of the slate (grin-wallet 1.1.0)
|
||||||
|
//! Changes from V1:
|
||||||
|
//! * ParticipantData struct fields serialized as hex strings instead of arrays:
|
||||||
|
//! * public_blind_excess
|
||||||
|
//! * public_nonce
|
||||||
|
//! * part_sig
|
||||||
|
//! * message_sig
|
||||||
|
//! * Transaction fields serialized as hex strings instead of arrays:
|
||||||
|
//! * offset
|
||||||
|
//! * Input field serialized as hex strings instead of arrays:
|
||||||
|
//! commit
|
||||||
|
//! * Output fields serialized as hex strings instead of arrays:
|
||||||
|
//! commit
|
||||||
|
//! proof
|
||||||
|
//! * TxKernel fields serialized as hex strings instead of arrays:
|
||||||
|
//! commit
|
||||||
|
//! signature
|
||||||
|
//! * version field removed
|
||||||
|
//! * VersionCompatInfo struct created with fields and added to beginning of struct
|
||||||
|
//! version: u16
|
||||||
|
//! orig_version: u16,
|
||||||
|
//! block_header_version: u16,
|
||||||
|
|
||||||
|
use crate::grin_core::core::transaction::OutputFeatures;
|
||||||
|
use crate::grin_core::libtx::secp_ser;
|
||||||
|
use crate::grin_keychain::{BlindingFactor, Identifier};
|
||||||
|
use crate::grin_util::secp;
|
||||||
|
use crate::grin_util::secp::key::PublicKey;
|
||||||
|
use crate::grin_util::secp::pedersen::{Commitment, RangeProof};
|
||||||
|
use crate::grin_util::secp::Signature;
|
||||||
|
use crate::slate::CompatKernelFeatures;
|
||||||
|
use crate::slate_versions::v3::{OutputV3, TxKernelV3};
|
||||||
|
use crate::types::CbData;
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
pub struct SlateV2 {
|
||||||
|
/// Versioning info
|
||||||
|
pub version_info: VersionCompatInfoV2,
|
||||||
|
/// The number of participants intended to take part in this transaction
|
||||||
|
pub num_participants: usize,
|
||||||
|
/// Unique transaction ID, selected by sender
|
||||||
|
pub id: Uuid,
|
||||||
|
/// The core transaction data:
|
||||||
|
/// inputs, outputs, kernels, kernel offset
|
||||||
|
pub tx: TransactionV2,
|
||||||
|
/// base amount (excluding fee)
|
||||||
|
#[serde(with = "secp_ser::string_or_u64")]
|
||||||
|
pub amount: u64,
|
||||||
|
/// fee amount
|
||||||
|
#[serde(with = "secp_ser::string_or_u64")]
|
||||||
|
pub fee: u64,
|
||||||
|
/// Block height for the transaction
|
||||||
|
#[serde(with = "secp_ser::string_or_u64")]
|
||||||
|
pub height: u64,
|
||||||
|
/// Lock height
|
||||||
|
#[serde(with = "secp_ser::string_or_u64")]
|
||||||
|
pub lock_height: u64,
|
||||||
|
/// Participant data, each participant in the transaction will
|
||||||
|
/// insert their public data here. For now, 0 is sender and 1
|
||||||
|
/// is receiver, though this will change for multi-party
|
||||||
|
pub participant_data: Vec<ParticipantDataV2>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
pub struct VersionCompatInfoV2 {
|
||||||
|
/// The current version of the slate format
|
||||||
|
pub version: u16,
|
||||||
|
/// Original version this slate was converted from
|
||||||
|
pub orig_version: u16,
|
||||||
|
/// Version of grin block header this slate is compatible with
|
||||||
|
pub block_header_version: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
pub struct ParticipantDataV2 {
|
||||||
|
/// Id of participant in the transaction. (For now, 0=sender, 1=rec)
|
||||||
|
#[serde(with = "secp_ser::string_or_u64")]
|
||||||
|
pub id: u64,
|
||||||
|
/// Public key corresponding to private blinding factor
|
||||||
|
#[serde(with = "secp_ser::pubkey_serde")]
|
||||||
|
pub public_blind_excess: PublicKey,
|
||||||
|
/// Public key corresponding to private nonce
|
||||||
|
#[serde(with = "secp_ser::pubkey_serde")]
|
||||||
|
pub public_nonce: PublicKey,
|
||||||
|
/// Public partial signature
|
||||||
|
#[serde(with = "secp_ser::option_sig_serde")]
|
||||||
|
pub part_sig: Option<Signature>,
|
||||||
|
/// A message for other participants
|
||||||
|
pub message: Option<String>,
|
||||||
|
/// Signature, created with private key corresponding to 'public_blind_excess'
|
||||||
|
#[serde(with = "secp_ser::option_sig_serde")]
|
||||||
|
pub message_sig: Option<Signature>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A transaction
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
pub struct TransactionV2 {
|
||||||
|
/// The kernel "offset" k2
|
||||||
|
/// excess is k1G after splitting the key k = k1 + k2
|
||||||
|
#[serde(
|
||||||
|
serialize_with = "secp_ser::as_hex",
|
||||||
|
deserialize_with = "secp_ser::blind_from_hex"
|
||||||
|
)]
|
||||||
|
pub offset: BlindingFactor,
|
||||||
|
/// The transaction body - inputs/outputs/kernels
|
||||||
|
pub body: TransactionBodyV2,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// TransactionBody is a common abstraction for transaction and block
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
pub struct TransactionBodyV2 {
|
||||||
|
/// List of inputs spent by the transaction.
|
||||||
|
pub inputs: Vec<InputV2>,
|
||||||
|
/// List of outputs the transaction produces.
|
||||||
|
pub outputs: Vec<OutputV2>,
|
||||||
|
/// List of kernels that make up this transaction (usually a single kernel).
|
||||||
|
pub kernels: Vec<TxKernelV2>,
|
||||||
|
}
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
pub struct InputV2 {
|
||||||
|
/// The features of the output being spent.
|
||||||
|
/// We will check maturity for coinbase output.
|
||||||
|
pub features: OutputFeatures,
|
||||||
|
/// The commit referencing the output being spent.
|
||||||
|
#[serde(
|
||||||
|
serialize_with = "secp_ser::as_hex",
|
||||||
|
deserialize_with = "secp_ser::commitment_from_hex"
|
||||||
|
)]
|
||||||
|
pub commit: Commitment,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct OutputV2 {
|
||||||
|
/// Options for an output's structure or use
|
||||||
|
pub features: OutputFeatures,
|
||||||
|
/// The homomorphic commitment representing the output amount
|
||||||
|
#[serde(
|
||||||
|
serialize_with = "secp_ser::as_hex",
|
||||||
|
deserialize_with = "secp_ser::commitment_from_hex"
|
||||||
|
)]
|
||||||
|
pub commit: Commitment,
|
||||||
|
/// A proof that the commitment is in the right range
|
||||||
|
#[serde(
|
||||||
|
serialize_with = "secp_ser::as_hex",
|
||||||
|
deserialize_with = "secp_ser::rangeproof_from_hex"
|
||||||
|
)]
|
||||||
|
pub proof: RangeProof,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
pub struct TxKernelV2 {
|
||||||
|
/// Options for a kernel's structure or use
|
||||||
|
pub features: CompatKernelFeatures,
|
||||||
|
/// Fee originally included in the transaction this proof is for.
|
||||||
|
#[serde(with = "secp_ser::string_or_u64")]
|
||||||
|
pub fee: u64,
|
||||||
|
/// This kernel is not valid earlier than lock_height blocks
|
||||||
|
/// The max lock_height of all *inputs* to this transaction
|
||||||
|
#[serde(with = "secp_ser::string_or_u64")]
|
||||||
|
pub lock_height: u64,
|
||||||
|
/// Remainder of the sum of all transaction commitments. If the transaction
|
||||||
|
/// is well formed, amounts components should sum to zero and the excess
|
||||||
|
/// is hence a valid public key.
|
||||||
|
#[serde(
|
||||||
|
serialize_with = "secp_ser::as_hex",
|
||||||
|
deserialize_with = "secp_ser::commitment_from_hex"
|
||||||
|
)]
|
||||||
|
pub excess: Commitment,
|
||||||
|
/// The signature proving the excess is a valid public key, which signs
|
||||||
|
/// the transaction fee.
|
||||||
|
#[serde(with = "secp_ser::sig_serde")]
|
||||||
|
pub excess_sig: secp::Signature,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A mining node requests new coinbase via the foreign api every time a new candidate block is built.
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
pub struct CoinbaseV2 {
|
||||||
|
/// Output
|
||||||
|
pub output: OutputV2,
|
||||||
|
/// Kernel
|
||||||
|
pub kernel: TxKernelV2,
|
||||||
|
/// Key Id
|
||||||
|
pub key_id: Option<Identifier>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Coinbase data to versioned.
|
||||||
|
impl From<CbData> for CoinbaseV2 {
|
||||||
|
fn from(cb: CbData) -> CoinbaseV2 {
|
||||||
|
let output = OutputV3::from(&cb.output);
|
||||||
|
let output = OutputV2::from(&output);
|
||||||
|
let kernel = TxKernelV3::from(&cb.kernel);
|
||||||
|
let kernel = TxKernelV2::from(&kernel);
|
||||||
|
CoinbaseV2 {
|
||||||
|
output,
|
||||||
|
kernel,
|
||||||
|
key_id: cb.key_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
use crate::grin_core::core::transaction::OutputFeatures;
|
use crate::grin_core::core::transaction::OutputFeatures;
|
||||||
use crate::grin_core::libtx::secp_ser;
|
use crate::grin_core::libtx::secp_ser;
|
||||||
|
use crate::grin_core::map_vec;
|
||||||
use crate::grin_keychain::{BlindingFactor, Identifier};
|
use crate::grin_keychain::{BlindingFactor, Identifier};
|
||||||
use crate::grin_util::secp;
|
use crate::grin_util::secp;
|
||||||
use crate::grin_util::secp::key::PublicKey;
|
use crate::grin_util::secp::key::PublicKey;
|
||||||
|
@ -30,6 +31,11 @@ use ed25519_dalek::PublicKey as DalekPublicKey;
|
||||||
use ed25519_dalek::Signature as DalekSignature;
|
use ed25519_dalek::Signature as DalekSignature;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
use crate::slate_versions::v2::{
|
||||||
|
InputV2, OutputV2, ParticipantDataV2, SlateV2, TransactionBodyV2, TransactionV2, TxKernelV2,
|
||||||
|
VersionCompatInfoV2,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
pub struct SlateV3 {
|
pub struct SlateV3 {
|
||||||
/// Versioning info
|
/// Versioning info
|
||||||
|
@ -202,3 +208,298 @@ pub struct CoinbaseV3 {
|
||||||
/// Key Id
|
/// Key Id
|
||||||
pub key_id: Option<Identifier>,
|
pub key_id: Option<Identifier>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// V2 to V3 For Slate
|
||||||
|
impl From<SlateV2> for SlateV3 {
|
||||||
|
fn from(slate: SlateV2) -> SlateV3 {
|
||||||
|
let SlateV2 {
|
||||||
|
num_participants,
|
||||||
|
id,
|
||||||
|
tx,
|
||||||
|
amount,
|
||||||
|
fee,
|
||||||
|
height,
|
||||||
|
lock_height,
|
||||||
|
participant_data,
|
||||||
|
version_info,
|
||||||
|
} = slate;
|
||||||
|
let participant_data = map_vec!(participant_data, |data| ParticipantDataV3::from(data));
|
||||||
|
let version_info = VersionCompatInfoV3::from(&version_info);
|
||||||
|
let tx = TransactionV3::from(tx);
|
||||||
|
SlateV3 {
|
||||||
|
num_participants,
|
||||||
|
id,
|
||||||
|
tx,
|
||||||
|
amount,
|
||||||
|
fee,
|
||||||
|
height,
|
||||||
|
lock_height,
|
||||||
|
ttl_cutoff_height: None,
|
||||||
|
participant_data,
|
||||||
|
version_info,
|
||||||
|
payment_proof: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&ParticipantDataV2> for ParticipantDataV3 {
|
||||||
|
fn from(data: &ParticipantDataV2) -> ParticipantDataV3 {
|
||||||
|
let ParticipantDataV2 {
|
||||||
|
id,
|
||||||
|
public_blind_excess,
|
||||||
|
public_nonce,
|
||||||
|
part_sig,
|
||||||
|
message,
|
||||||
|
message_sig,
|
||||||
|
} = data;
|
||||||
|
let id = *id;
|
||||||
|
let public_blind_excess = *public_blind_excess;
|
||||||
|
let public_nonce = *public_nonce;
|
||||||
|
let part_sig = *part_sig;
|
||||||
|
let message: Option<String> = message.as_ref().map(|t| String::from(&**t));
|
||||||
|
let message_sig = *message_sig;
|
||||||
|
ParticipantDataV3 {
|
||||||
|
id,
|
||||||
|
public_blind_excess,
|
||||||
|
public_nonce,
|
||||||
|
part_sig,
|
||||||
|
message,
|
||||||
|
message_sig,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&VersionCompatInfoV2> for VersionCompatInfoV3 {
|
||||||
|
fn from(data: &VersionCompatInfoV2) -> VersionCompatInfoV3 {
|
||||||
|
let VersionCompatInfoV2 {
|
||||||
|
version,
|
||||||
|
orig_version,
|
||||||
|
block_header_version,
|
||||||
|
} = data;
|
||||||
|
let version = *version;
|
||||||
|
let orig_version = *orig_version;
|
||||||
|
let block_header_version = *block_header_version;
|
||||||
|
VersionCompatInfoV3 {
|
||||||
|
version,
|
||||||
|
orig_version,
|
||||||
|
block_header_version,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<TransactionV2> for TransactionV3 {
|
||||||
|
fn from(tx: TransactionV2) -> TransactionV3 {
|
||||||
|
let TransactionV2 { offset, body } = tx;
|
||||||
|
let body = TransactionBodyV3::from(&body);
|
||||||
|
TransactionV3 { offset, body }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&TransactionBodyV2> for TransactionBodyV3 {
|
||||||
|
fn from(body: &TransactionBodyV2) -> TransactionBodyV3 {
|
||||||
|
let TransactionBodyV2 {
|
||||||
|
inputs,
|
||||||
|
outputs,
|
||||||
|
kernels,
|
||||||
|
} = body;
|
||||||
|
|
||||||
|
let inputs = map_vec!(inputs, |inp| InputV3::from(inp));
|
||||||
|
let outputs = map_vec!(outputs, |out| OutputV3::from(out));
|
||||||
|
let kernels = map_vec!(kernels, |kern| TxKernelV3::from(kern));
|
||||||
|
TransactionBodyV3 {
|
||||||
|
inputs,
|
||||||
|
outputs,
|
||||||
|
kernels,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&InputV2> for InputV3 {
|
||||||
|
fn from(input: &InputV2) -> InputV3 {
|
||||||
|
let InputV2 { features, commit } = *input;
|
||||||
|
InputV3 { features, commit }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&OutputV2> for OutputV3 {
|
||||||
|
fn from(output: &OutputV2) -> OutputV3 {
|
||||||
|
let OutputV2 {
|
||||||
|
features,
|
||||||
|
commit,
|
||||||
|
proof,
|
||||||
|
} = *output;
|
||||||
|
OutputV3 {
|
||||||
|
features,
|
||||||
|
commit,
|
||||||
|
proof,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&TxKernelV2> for TxKernelV3 {
|
||||||
|
fn from(kernel: &TxKernelV2) -> TxKernelV3 {
|
||||||
|
let (fee, lock_height) = (kernel.fee, kernel.lock_height);
|
||||||
|
TxKernelV3 {
|
||||||
|
features: kernel.features,
|
||||||
|
fee,
|
||||||
|
lock_height,
|
||||||
|
excess: kernel.excess,
|
||||||
|
excess_sig: kernel.excess_sig,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// V3 to V2
|
||||||
|
#[allow(unused_variables)]
|
||||||
|
impl From<&SlateV3> for SlateV2 {
|
||||||
|
fn from(slate: &SlateV3) -> SlateV2 {
|
||||||
|
let SlateV3 {
|
||||||
|
num_participants,
|
||||||
|
id,
|
||||||
|
tx,
|
||||||
|
amount,
|
||||||
|
fee,
|
||||||
|
height,
|
||||||
|
lock_height,
|
||||||
|
ttl_cutoff_height,
|
||||||
|
participant_data,
|
||||||
|
version_info,
|
||||||
|
payment_proof,
|
||||||
|
} = slate;
|
||||||
|
let num_participants = *num_participants;
|
||||||
|
let id = *id;
|
||||||
|
let tx = TransactionV2::from(tx);
|
||||||
|
let amount = *amount;
|
||||||
|
let fee = *fee;
|
||||||
|
let height = *height;
|
||||||
|
let lock_height = *lock_height;
|
||||||
|
let participant_data = map_vec!(participant_data, |data| ParticipantDataV2::from(data));
|
||||||
|
let version_info = VersionCompatInfoV2::from(version_info);
|
||||||
|
SlateV2 {
|
||||||
|
num_participants,
|
||||||
|
id,
|
||||||
|
tx,
|
||||||
|
amount,
|
||||||
|
fee,
|
||||||
|
height,
|
||||||
|
lock_height,
|
||||||
|
participant_data,
|
||||||
|
version_info,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&ParticipantDataV3> for ParticipantDataV2 {
|
||||||
|
fn from(data: &ParticipantDataV3) -> ParticipantDataV2 {
|
||||||
|
let ParticipantDataV3 {
|
||||||
|
id,
|
||||||
|
public_blind_excess,
|
||||||
|
public_nonce,
|
||||||
|
part_sig,
|
||||||
|
message,
|
||||||
|
message_sig,
|
||||||
|
} = data;
|
||||||
|
let id = *id;
|
||||||
|
let public_blind_excess = *public_blind_excess;
|
||||||
|
let public_nonce = *public_nonce;
|
||||||
|
let part_sig = *part_sig;
|
||||||
|
let message: Option<String> = message.as_ref().map(|t| String::from(&**t));
|
||||||
|
let message_sig = *message_sig;
|
||||||
|
ParticipantDataV2 {
|
||||||
|
id,
|
||||||
|
public_blind_excess,
|
||||||
|
public_nonce,
|
||||||
|
part_sig,
|
||||||
|
message,
|
||||||
|
message_sig,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&VersionCompatInfoV3> for VersionCompatInfoV2 {
|
||||||
|
fn from(data: &VersionCompatInfoV3) -> VersionCompatInfoV2 {
|
||||||
|
let VersionCompatInfoV3 {
|
||||||
|
version,
|
||||||
|
orig_version,
|
||||||
|
block_header_version,
|
||||||
|
} = data;
|
||||||
|
let version = *version;
|
||||||
|
let orig_version = *orig_version;
|
||||||
|
let block_header_version = *block_header_version;
|
||||||
|
VersionCompatInfoV2 {
|
||||||
|
version,
|
||||||
|
orig_version,
|
||||||
|
block_header_version,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<TransactionV3> for TransactionV2 {
|
||||||
|
fn from(tx: TransactionV3) -> TransactionV2 {
|
||||||
|
let TransactionV3 { offset, body } = tx;
|
||||||
|
let body = TransactionBodyV2::from(&body);
|
||||||
|
TransactionV2 { offset, body }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&TransactionV3> for TransactionV2 {
|
||||||
|
fn from(tx: &TransactionV3) -> TransactionV2 {
|
||||||
|
let TransactionV3 { offset, body } = tx;
|
||||||
|
let offset = offset.clone();
|
||||||
|
let body = TransactionBodyV2::from(body);
|
||||||
|
TransactionV2 { offset, body }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&TransactionBodyV3> for TransactionBodyV2 {
|
||||||
|
fn from(body: &TransactionBodyV3) -> TransactionBodyV2 {
|
||||||
|
let TransactionBodyV3 {
|
||||||
|
inputs,
|
||||||
|
outputs,
|
||||||
|
kernels,
|
||||||
|
} = body;
|
||||||
|
|
||||||
|
let inputs = map_vec!(inputs, |inp| InputV2::from(inp));
|
||||||
|
let outputs = map_vec!(outputs, |out| OutputV2::from(out));
|
||||||
|
let kernels = map_vec!(kernels, |kern| TxKernelV2::from(kern));
|
||||||
|
TransactionBodyV2 {
|
||||||
|
inputs,
|
||||||
|
outputs,
|
||||||
|
kernels,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&InputV3> for InputV2 {
|
||||||
|
fn from(input: &InputV3) -> InputV2 {
|
||||||
|
let InputV3 { features, commit } = *input;
|
||||||
|
InputV2 { features, commit }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&OutputV3> for OutputV2 {
|
||||||
|
fn from(output: &OutputV3) -> OutputV2 {
|
||||||
|
let OutputV3 {
|
||||||
|
features,
|
||||||
|
commit,
|
||||||
|
proof,
|
||||||
|
} = *output;
|
||||||
|
OutputV2 {
|
||||||
|
features,
|
||||||
|
commit,
|
||||||
|
proof,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&TxKernelV3> for TxKernelV2 {
|
||||||
|
fn from(kernel: &TxKernelV3) -> TxKernelV2 {
|
||||||
|
TxKernelV2 {
|
||||||
|
features: kernel.features,
|
||||||
|
fee: kernel.fee,
|
||||||
|
lock_height: kernel.lock_height,
|
||||||
|
excess: kernel.excess,
|
||||||
|
excess_sig: kernel.excess_sig,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -155,11 +155,6 @@ subcommands:
|
||||||
short: t
|
short: t
|
||||||
long: stored_tx
|
long: stored_tx
|
||||||
takes_value: true
|
takes_value: true
|
||||||
- slate_version:
|
|
||||||
help: Target slate version to output/send to receiver
|
|
||||||
short: v
|
|
||||||
long: slate_version
|
|
||||||
takes_value: true
|
|
||||||
- receive:
|
- receive:
|
||||||
about: Processes a transaction file to accept a transfer from a sender
|
about: Processes a transaction file to accept a transfer from a sender
|
||||||
args:
|
args:
|
||||||
|
@ -205,11 +200,6 @@ subcommands:
|
||||||
short: g
|
short: g
|
||||||
long: message
|
long: message
|
||||||
takes_value: true
|
takes_value: true
|
||||||
- slate_version:
|
|
||||||
help: Target slate version to output/send to receiver
|
|
||||||
short: v
|
|
||||||
long: slate_version
|
|
||||||
takes_value: true
|
|
||||||
- dest:
|
- dest:
|
||||||
help: Name of destination slate output file
|
help: Name of destination slate output file
|
||||||
short: d
|
short: d
|
||||||
|
|
Loading…
Reference in a new issue