share slate types

This commit is contained in:
wiesche
2026-09-13 15:07:35 +02:00
parent a3d17030fd
commit 05e1ccb371
8 changed files with 288 additions and 681 deletions
+16 -128
View File
@@ -42,8 +42,8 @@ use crate::slate_versions::v4::{
SlateStateV4, SlateV4, VersionCompatInfoV4, SlateStateV4, SlateV4, VersionCompatInfoV4,
}; };
use crate::slate_versions::v5::{ use crate::slate_versions::v5::{
CommitsV5, KernelFeaturesArgsV5, OutputFeaturesV5, ParticipantDataV5, PaymentInfoV5, KernelFeaturesArgsV5, ParticipantDataV5, PaymentInfoV5, SlateStateV5, SlateV5,
SlateStateV5, SlateV5, VersionCompatInfoV5, VersionCompatInfoV5,
}; };
use crate::slate_versions::VersionedSlate; use crate::slate_versions::VersionedSlate;
use crate::slate_versions::{CURRENT_SLATE_VERSION, GRIN_BLOCK_HEADER_VERSION}; use crate::slate_versions::{CURRENT_SLATE_VERSION, GRIN_BLOCK_HEADER_VERSION};
@@ -1032,72 +1032,6 @@ impl From<&Slate> for SlateV5 {
} }
} }
impl From<&Slate> for Option<Vec<CommitsV5>> {
fn from(slate: &Slate) -> Self {
slate_commitments(slate)
}
}
fn slate_commitments<C>(slate: &Slate) -> Option<Vec<C>>
where
C: for<'a> From<&'a Input> + for<'a> From<&'a Output>,
{
let tx = slate.tx.as_ref()?;
let mut commitments = vec![];
match tx.inputs() {
Inputs::CommitOnly(_) => panic!("commit only inputs unsupported"),
Inputs::FeaturesAndCommit(ref inputs) => {
for input in inputs {
commitments.push(input.into());
}
}
}
for output in tx.outputs() {
commitments.push(output.into());
}
Some(commitments)
}
impl From<&ParticipantData> for ParticipantDataV5 {
fn from(data: &ParticipantData) -> ParticipantDataV5 {
let ParticipantData {
public_blind_excess,
public_nonce,
part_sig,
} = data;
let public_blind_excess = *public_blind_excess;
let public_nonce = *public_nonce;
let part_sig = *part_sig;
ParticipantDataV5 {
xs: public_blind_excess,
nonce: public_nonce,
part: part_sig,
}
}
}
impl From<&SlateState> for SlateStateV5 {
fn from(data: &SlateState) -> SlateStateV5 {
match data {
SlateState::Unknown => SlateStateV5::Unknown,
SlateState::Standard1 => SlateStateV5::Standard1,
SlateState::Standard2 => SlateStateV5::Standard2,
SlateState::Standard3 => SlateStateV5::Standard3,
SlateState::Invoice1 => SlateStateV5::Invoice1,
SlateState::Invoice2 => SlateStateV5::Invoice2,
SlateState::Invoice3 => SlateStateV5::Invoice3,
}
}
}
impl From<&KernelFeaturesArgs> for KernelFeaturesArgsV5 {
fn from(data: &KernelFeaturesArgs) -> KernelFeaturesArgsV5 {
let KernelFeaturesArgs { lock_height } = data;
let lock_hgt = *lock_height;
KernelFeaturesArgsV5 { lock_hgt }
}
}
impl From<&VersionCompatInfo> for VersionCompatInfoV5 { impl From<&VersionCompatInfo> for VersionCompatInfoV5 {
fn from(data: &VersionCompatInfo) -> VersionCompatInfoV5 { fn from(data: &VersionCompatInfo) -> VersionCompatInfoV5 {
let VersionCompatInfo { let VersionCompatInfo {
@@ -1141,16 +1075,6 @@ impl From<&PaymentInfo> for PaymentInfoV5 {
} }
} }
impl From<OutputFeatures> for OutputFeaturesV5 {
fn from(of: OutputFeatures) -> OutputFeaturesV5 {
let index = match of {
OutputFeatures::Plain => 0,
OutputFeatures::Coinbase => 1,
};
OutputFeaturesV5(index)
}
}
///// V5 ///// V5
impl From<SlateV5> for Slate { impl From<SlateV5> for Slate {
fn from(slate: SlateV5) -> Slate { fn from(slate: SlateV5) -> Slate {
@@ -1273,46 +1197,6 @@ impl From<&SlateV5> for Option<Transaction> {
} }
} }
impl From<&ParticipantDataV5> for ParticipantData {
fn from(data: &ParticipantDataV5) -> ParticipantData {
let ParticipantDataV5 {
xs: public_blind_excess,
nonce: public_nonce,
part: part_sig,
} = data;
let public_blind_excess = *public_blind_excess;
let public_nonce = *public_nonce;
let part_sig = *part_sig;
ParticipantData {
public_blind_excess,
public_nonce,
part_sig,
}
}
}
impl From<&KernelFeaturesArgsV5> for KernelFeaturesArgs {
fn from(data: &KernelFeaturesArgsV5) -> KernelFeaturesArgs {
let KernelFeaturesArgsV5 { lock_hgt } = data;
let lock_height = *lock_hgt;
KernelFeaturesArgs { lock_height }
}
}
impl From<&SlateStateV5> for SlateState {
fn from(data: &SlateStateV5) -> SlateState {
match data {
SlateStateV5::Unknown => SlateState::Unknown,
SlateStateV5::Standard1 => SlateState::Standard1,
SlateStateV5::Standard2 => SlateState::Standard2,
SlateStateV5::Standard3 => SlateState::Standard3,
SlateStateV5::Invoice1 => SlateState::Invoice1,
SlateStateV5::Invoice2 => SlateState::Invoice2,
SlateStateV5::Invoice3 => SlateState::Invoice3,
}
}
}
impl From<&VersionCompatInfoV5> for VersionCompatInfo { impl From<&VersionCompatInfoV5> for VersionCompatInfo {
fn from(data: &VersionCompatInfoV5) -> VersionCompatInfo { fn from(data: &VersionCompatInfoV5) -> VersionCompatInfo {
let VersionCompatInfoV5 { let VersionCompatInfoV5 {
@@ -1355,15 +1239,6 @@ impl From<&PaymentInfoV5> for PaymentInfo {
} }
} }
impl From<OutputFeaturesV5> for OutputFeatures {
fn from(of: OutputFeaturesV5) -> OutputFeatures {
match of.0 {
1 => OutputFeatures::Coinbase,
0 | _ => OutputFeatures::Plain,
}
}
}
///////// V4 ///////// V4
impl TryFrom<Slate> for SlateV4 { impl TryFrom<Slate> for SlateV4 {
type Error = Error; type Error = Error;
@@ -1430,7 +1305,20 @@ impl TryFrom<&Slate> for SlateV4 {
impl From<&Slate> for Option<Vec<CommitsV4>> { impl From<&Slate> for Option<Vec<CommitsV4>> {
fn from(slate: &Slate) -> Self { fn from(slate: &Slate) -> Self {
slate_commitments(slate) let tx = slate.tx.as_ref()?;
let mut commitments = vec![];
match tx.inputs() {
Inputs::CommitOnly(_) => panic!("commit only inputs unsupported"),
Inputs::FeaturesAndCommit(ref inputs) => {
for input in inputs {
commitments.push(input.into());
}
}
}
for output in tx.outputs() {
commitments.push(output.into());
}
Some(commitments)
} }
} }
+207
View File
@@ -0,0 +1,207 @@
// Copyright 2026 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.
//! Wire types shared by V4 and V5 slates
use crate::grin_core::core::{Input, Output, TxKernel};
use crate::grin_core::libtx::secp_ser;
use crate::grin_keychain::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_versions::ser, CbData};
/// Slate state definition
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum SlateState {
/// Unknown, coming from earlier versions of the slate
Unknown,
/// Standard flow, freshly init
Standard1,
/// Standard flow, return journey
Standard2,
/// Standard flow, ready for transaction posting
Standard3,
/// Invoice flow, freshly init
Invoice1,
/// Invoice flow, return journey
Invoice2,
/// Invoice flow, ready for tranasction posting
Invoice3,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
/// Kernel features arguments definition
pub struct KernelFeaturesArgs {
/// Lock height, for HeightLocked
pub lock_hgt: u64,
}
/// Participant keys and optional partial signature
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
pub struct ParticipantData {
/// Public key corresponding to private blinding factor
#[serde(with = "secp_ser::pubkey_serde")]
pub xs: PublicKey,
/// Public key corresponding to private nonce
#[serde(with = "secp_ser::pubkey_serde")]
pub nonce: PublicKey,
/// Public partial signature
#[serde(default = "default_part_sig_none")]
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(with = "secp_ser::option_sig_serde")]
pub part: Option<Signature>,
}
fn default_part_sig_none() -> Option<Signature> {
None
}
/// Input commitment or output with its range proof
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
pub struct Commits {
/// Options for an output's structure or use
#[serde(default = "default_output_feature")]
#[serde(skip_serializing_if = "output_feature_is_plain")]
pub f: OutputFeatures,
/// The homomorphic commitment representing the output amount
#[serde(
serialize_with = "secp_ser::as_hex",
deserialize_with = "secp_ser::commitment_from_hex"
)]
pub c: Commitment,
/// A proof that the commitment is in the right range
/// Only applies for transaction outputs
#[serde(with = "ser::option_rangeproof_hex")]
#[serde(default = "default_range_proof")]
#[serde(skip_serializing_if = "Option::is_none")]
pub p: Option<RangeProof>,
}
impl From<&Output> for Commits {
fn from(out: &Output) -> Commits {
Commits {
f: out.features().into(),
c: out.commitment(),
p: Some(out.proof()),
}
}
}
// This will need to be reworked once we no longer support input features with "commit only" inputs.
impl From<&Input> for Commits {
fn from(input: &Input) -> Commits {
Commits {
f: input.features.into(),
c: input.commitment(),
p: None,
}
}
}
fn default_output_feature() -> OutputFeatures {
OutputFeatures(0)
}
fn output_feature_is_plain(o: &OutputFeatures) -> bool {
o.0 == 0
}
/// Output feature byte
#[derive(Serialize, Deserialize, Copy, Debug, Clone, PartialEq, Eq)]
pub struct OutputFeatures(pub u8);
/// Whether all signature bytes are zero
pub fn sig_is_blank(s: &secp::Signature) -> bool {
for b in s.to_raw_data().iter() {
if *b != 0 {
return false;
}
}
true
}
fn default_range_proof() -> Option<RangeProof> {
None
}
/// 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 Coinbase {
/// Output
output: CbOutput,
/// Kernel
kernel: CbKernel,
/// Key Id
key_id: Option<Identifier>,
}
impl From<CbData> for Coinbase {
fn from(cb: CbData) -> Coinbase {
Coinbase {
output: CbOutput::from(&cb.output),
kernel: CbKernel::from(&cb.kernel),
key_id: cb.key_id,
}
}
}
impl From<&Output> for CbOutput {
fn from(output: &Output) -> CbOutput {
CbOutput {
features: CbOutputFeatures::Coinbase,
commit: output.commitment(),
proof: output.proof(),
}
}
}
impl From<&TxKernel> for CbKernel {
fn from(kernel: &TxKernel) -> CbKernel {
CbKernel {
features: CbKernelFeatures::Coinbase,
excess: kernel.excess,
excess_sig: kernel.excess_sig,
}
}
}
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
enum CbOutputFeatures {
Coinbase,
}
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
enum CbKernelFeatures {
Coinbase,
}
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
struct CbOutput {
features: CbOutputFeatures,
#[serde(serialize_with = "secp_ser::as_hex")]
commit: Commitment,
#[serde(serialize_with = "secp_ser::as_hex")]
proof: RangeProof,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
struct CbKernel {
features: CbKernelFeatures,
#[serde(serialize_with = "secp_ser::as_hex")]
excess: Commitment,
#[serde(with = "secp_ser::sig_serde")]
excess_sig: secp::Signature,
}
+35
View File
@@ -26,6 +26,7 @@ use crate::types::CbData;
use crate::Error; use crate::Error;
use std::convert::TryFrom; use std::convert::TryFrom;
mod common;
pub mod ser; pub mod ser;
#[allow(missing_docs)] #[allow(missing_docs)]
@@ -605,6 +606,40 @@ pub mod tests {
Ok(()) Ok(())
} }
#[test]
fn slate_states() {
use crate::grin_core::ser::{deserialize_default, serialize_default};
use crate::slate::SlateState;
use crate::slate_versions::v5::SlateStateV5;
for (state, label, byte) in [
(SlateState::Unknown, "NA", 0),
(SlateState::Standard1, "S1", 1),
(SlateState::Standard2, "S2", 2),
(SlateState::Standard3, "S3", 3),
(SlateState::Invoice1, "I1", 4),
(SlateState::Invoice2, "I2", 5),
(SlateState::Invoice3, "I3", 6),
] {
let mut slate = Slate::blank(2, false);
slate.state = state;
for version in [SlateVersion::V4, SlateVersion::V5] {
let versioned = VersionedSlate::into_version(slate.clone(), version).unwrap();
let json = serde_json::to_value(&versioned).unwrap();
assert_eq!(json["sta"], label);
let recovered: Slate = serde_json::from_value::<VersionedSlate>(json)
.unwrap()
.into();
assert_eq!(recovered.state, slate.state);
}
let mut bytes = vec![];
serialize_default(&mut bytes, &SlateStateV5::from(&slate.state)).unwrap();
assert_eq!(bytes, vec![byte]);
let recovered: SlateStateV5 = deserialize_default(&mut &bytes[..]).unwrap();
assert_eq!(SlateState::from(&recovered), slate.state);
}
}
#[test] #[test]
fn slate_version_numbers() { fn slate_version_numbers() {
for (number, version) in [(4, SlateVersion::V4), (5, SlateVersion::V5)] { for (number, version) in [(4, SlateVersion::V4), (5, SlateVersion::V5)] {
+1 -44
View File
@@ -682,50 +682,7 @@ pub mod slate_state_v4 {
} }
} }
/// Serializes slates 'state' field - V5 pub use slate_state_v4 as slate_state_v5;
pub mod slate_state_v5 {
use serde::de::Error;
use serde::{Deserialize, Deserializer, Serializer};
use crate::slate_versions::v5::SlateStateV5;
///
pub fn serialize<S>(st: &SlateStateV5, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let label = match st {
SlateStateV5::Unknown => "NA",
SlateStateV5::Standard1 => "S1",
SlateStateV5::Standard2 => "S2",
SlateStateV5::Standard3 => "S3",
SlateStateV5::Invoice1 => "I1",
SlateStateV5::Invoice2 => "I2",
SlateStateV5::Invoice3 => "I3",
};
serializer.serialize_str(label)
}
///
pub fn deserialize<'de, D>(deserializer: D) -> Result<SlateStateV5, D::Error>
where
D: Deserializer<'de>,
{
String::deserialize(deserializer).and_then(|s| {
let retval = match s.as_str() {
"NA" => SlateStateV5::Unknown,
"S1" => SlateStateV5::Standard1,
"S2" => SlateStateV5::Standard2,
"S3" => SlateStateV5::Standard3,
"I1" => SlateStateV5::Invoice1,
"I2" => SlateStateV5::Invoice2,
"I3" => SlateStateV5::Invoice3,
_ => return Err(Error::custom("Invalid Slate state")),
};
Ok(retval)
})
}
}
/// Serializes an secp256k1 pubkey to base64 /// Serializes an secp256k1 pubkey to base64
pub mod uuid_base64 { pub mod uuid_base64 {
+8 -186
View File
@@ -54,18 +54,19 @@
//! * `rsig` may be omitted if it has not yet been filled out //! * `rsig` may be omitted if it has not yet been filled out
use crate::grin_core::core::FeeFields; use crate::grin_core::core::FeeFields;
use crate::grin_core::core::{Input, Output, TxKernel};
use crate::grin_core::libtx::secp_ser; use crate::grin_core::libtx::secp_ser;
use crate::grin_keychain::{BlindingFactor, Identifier}; use crate::grin_keychain::BlindingFactor;
use crate::grin_util::secp; use crate::slate_versions::ser;
use crate::grin_util::secp::key::PublicKey;
use crate::grin_util::secp::pedersen::{Commitment, RangeProof};
use crate::grin_util::secp::Signature;
use crate::{slate_versions::ser, CbData};
use ed25519_dalek::Signature as DalekSignature; use ed25519_dalek::Signature as DalekSignature;
use ed25519_dalek::VerifyingKey as DalekPublicKey; use ed25519_dalek::VerifyingKey as DalekPublicKey;
use uuid::Uuid; use uuid::Uuid;
pub use crate::slate_versions::common::{
sig_is_blank, Coinbase as CoinbaseV4, Commits as CommitsV4,
KernelFeaturesArgs as KernelFeaturesArgsV4, OutputFeatures as OutputFeaturesV4,
ParticipantData as ParticipantDataV4, SlateState as SlateStateV4,
};
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Serialize, Deserialize, Debug, Clone)]
pub struct SlateV4 { pub struct SlateV4 {
// Required Fields // Required Fields
@@ -163,32 +164,6 @@ fn default_kernel_features_none() -> Option<KernelFeaturesArgsV4> {
None None
} }
/// Slate state definition
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum SlateStateV4 {
/// Unknown, coming from earlier versions of the slate
Unknown,
/// Standard flow, freshly init
Standard1,
/// Standard flow, return journey
Standard2,
/// Standard flow, ready for transaction posting
Standard3,
/// Invoice flow, freshly init
Invoice1,
///Invoice flow, return journey
Invoice2,
/// Invoice flow, ready for tranasction posting
Invoice3,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
/// Kernel features arguments definition
pub struct KernelFeaturesArgsV4 {
/// Lock height, for HeightLocked
pub lock_hgt: u64,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
pub struct VersionCompatInfoV4 { pub struct VersionCompatInfoV4 {
/// The current version of the slate format /// The current version of the slate format
@@ -197,25 +172,6 @@ pub struct VersionCompatInfoV4 {
pub block_header_version: u16, pub block_header_version: u16,
} }
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
pub struct ParticipantDataV4 {
/// Public key corresponding to private blinding factor
#[serde(with = "secp_ser::pubkey_serde")]
pub xs: PublicKey,
/// Public key corresponding to private nonce
#[serde(with = "secp_ser::pubkey_serde")]
pub nonce: PublicKey,
/// Public partial signature
#[serde(default = "default_part_sig_none")]
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(with = "secp_ser::option_sig_serde")]
pub part: Option<Signature>,
}
fn default_part_sig_none() -> Option<Signature> {
None
}
#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)] #[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
pub struct PaymentInfoV4 { pub struct PaymentInfoV4 {
#[serde(with = "ser::dalek_pubkey_serde")] #[serde(with = "ser::dalek_pubkey_serde")]
@@ -232,71 +188,6 @@ fn default_receiver_signature_none() -> Option<DalekSignature> {
None None
} }
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
pub struct CommitsV4 {
/// Options for an output's structure or use
#[serde(default = "default_output_feature")]
#[serde(skip_serializing_if = "output_feature_is_plain")]
pub f: OutputFeaturesV4,
/// The homomorphic commitment representing the output amount
#[serde(
serialize_with = "secp_ser::as_hex",
deserialize_with = "secp_ser::commitment_from_hex"
)]
pub c: Commitment,
/// A proof that the commitment is in the right range
/// Only applies for transaction outputs
#[serde(with = "ser::option_rangeproof_hex")]
#[serde(default = "default_range_proof")]
#[serde(skip_serializing_if = "Option::is_none")]
pub p: Option<RangeProof>,
}
impl From<&Output> for CommitsV4 {
fn from(out: &Output) -> CommitsV4 {
CommitsV4 {
f: out.features().into(),
c: out.commitment(),
p: Some(out.proof()),
}
}
}
// This will need to be reworked once we no longer support input features with "commit only" inputs.
impl From<&Input> for CommitsV4 {
fn from(input: &Input) -> CommitsV4 {
CommitsV4 {
f: input.features.into(),
c: input.commitment(),
p: None,
}
}
}
fn default_output_feature() -> OutputFeaturesV4 {
OutputFeaturesV4(0)
}
fn output_feature_is_plain(o: &OutputFeaturesV4) -> bool {
o.0 == 0
}
#[derive(Serialize, Deserialize, Copy, Debug, Clone, PartialEq, Eq)]
pub struct OutputFeaturesV4(pub u8);
pub fn sig_is_blank(s: &secp::Signature) -> bool {
for b in s.to_raw_data().iter() {
if *b != 0 {
return false;
}
}
true
}
fn default_range_proof() -> Option<RangeProof> {
None
}
fn u64_is_blank(u: &u64) -> bool { fn u64_is_blank(u: &u64) -> bool {
*u == 0 *u == 0
} }
@@ -316,72 +207,3 @@ fn fee_is_zero(f: &FeeFields) -> bool {
fn default_fee() -> FeeFields { fn default_fee() -> FeeFields {
FeeFields::zero() FeeFields::zero()
} }
/// 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 CoinbaseV4 {
/// Output
output: CbOutputV4,
/// Kernel
kernel: CbKernelV4,
/// Key Id
key_id: Option<Identifier>,
}
impl From<CbData> for CoinbaseV4 {
fn from(cb: CbData) -> CoinbaseV4 {
CoinbaseV4 {
output: CbOutputV4::from(&cb.output),
kernel: CbKernelV4::from(&cb.kernel),
key_id: cb.key_id,
}
}
}
impl From<&Output> for CbOutputV4 {
fn from(output: &Output) -> CbOutputV4 {
CbOutputV4 {
features: CbOutputFeatures::Coinbase,
commit: output.commitment(),
proof: output.proof(),
}
}
}
impl From<&TxKernel> for CbKernelV4 {
fn from(kernel: &TxKernel) -> CbKernelV4 {
CbKernelV4 {
features: CbKernelFeatures::Coinbase,
excess: kernel.excess,
excess_sig: kernel.excess_sig,
}
}
}
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
enum CbOutputFeatures {
Coinbase,
}
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
enum CbKernelFeatures {
Coinbase,
}
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
struct CbOutputV4 {
features: CbOutputFeatures,
#[serde(serialize_with = "secp_ser::as_hex")]
commit: Commitment,
#[serde(serialize_with = "secp_ser::as_hex")]
proof: RangeProof,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
struct CbKernelV4 {
features: CbKernelFeatures,
#[serde(serialize_with = "secp_ser::as_hex")]
excess: Commitment,
#[serde(with = "secp_ser::sig_serde")]
excess_sig: secp::Signature,
}
+4 -4
View File
@@ -175,8 +175,8 @@ impl Readable for SlateOptFields {
} }
} }
struct SigsWrap(Vec<ParticipantDataV4>); pub(super) struct SigsWrap(pub(super) Vec<ParticipantDataV4>);
struct SigsWrapRef<'a>(&'a Vec<ParticipantDataV4>); pub(super) struct SigsWrapRef<'a>(pub(super) &'a Vec<ParticipantDataV4>);
impl<'a> Writeable for SigsWrapRef<'a> { impl<'a> Writeable for SigsWrapRef<'a> {
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), grin_ser::Error> { fn write<W: Writer>(&self, writer: &mut W) -> Result<(), grin_ser::Error> {
@@ -278,8 +278,8 @@ impl Readable for SlateOptStructs {
} }
} }
struct ComsWrap(Vec<CommitsV4>); pub(super) struct ComsWrap(pub(super) Vec<CommitsV4>);
struct ComsWrapRef<'a>(&'a Vec<CommitsV4>); pub(super) struct ComsWrapRef<'a>(pub(super) &'a Vec<CommitsV4>);
impl<'a> Writeable for ComsWrapRef<'a> { impl<'a> Writeable for ComsWrapRef<'a> {
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), grin_ser::Error> { fn write<W: Writer>(&self, writer: &mut W) -> Result<(), grin_ser::Error> {
+9 -186
View File
@@ -28,21 +28,23 @@
//! * `memo` adds optional payment details //! * `memo` adds optional payment details
use crate::grin_core::core::FeeFields; use crate::grin_core::core::FeeFields;
use crate::grin_core::core::{Input, Output, TxKernel};
use crate::grin_core::libtx::secp_ser; use crate::grin_core::libtx::secp_ser;
use crate::grin_keychain::{BlindingFactor, Identifier}; use crate::grin_keychain::BlindingFactor;
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::{PaymentMemo, PaymentProofType}; use crate::slate::{PaymentMemo, PaymentProofType};
use crate::{slate_versions::ser, CbData}; use crate::slate_versions::ser;
use chrono::prelude::{DateTime, Utc}; use chrono::prelude::{DateTime, Utc};
use ed25519_dalek::Signature as DalekSignature; use ed25519_dalek::Signature as DalekSignature;
use ed25519_dalek::VerifyingKey as DalekPublicKey; use ed25519_dalek::VerifyingKey as DalekPublicKey;
use serde_with::TimestampSeconds; use serde_with::TimestampSeconds;
use uuid::Uuid; use uuid::Uuid;
// These fields have the same representation in V4 and V5
pub use crate::slate_versions::common::{
sig_is_blank, Coinbase as CoinbaseV5, Commits as CommitsV5,
KernelFeaturesArgs as KernelFeaturesArgsV5, OutputFeatures as OutputFeaturesV5,
ParticipantData as ParticipantDataV5, SlateState as SlateStateV5,
};
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Serialize, Deserialize, Debug, Clone)]
pub struct SlateV5 { pub struct SlateV5 {
// Required Fields // Required Fields
@@ -140,32 +142,6 @@ fn default_kernel_features_none() -> Option<KernelFeaturesArgsV5> {
None None
} }
/// Slate state definition
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum SlateStateV5 {
/// Unknown, coming from earlier versions of the slate
Unknown,
/// Standard flow, freshly init
Standard1,
/// Standard flow, return journey
Standard2,
/// Standard flow, ready for transaction posting
Standard3,
/// Invoice flow, freshly init
Invoice1,
///Invoice flow, return journey
Invoice2,
/// Invoice flow, ready for tranasction posting
Invoice3,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
/// Kernel features arguments definition
pub struct KernelFeaturesArgsV5 {
/// Lock height, for HeightLocked
pub lock_hgt: u64,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
pub struct VersionCompatInfoV5 { pub struct VersionCompatInfoV5 {
/// The current version of the slate format /// The current version of the slate format
@@ -174,25 +150,6 @@ pub struct VersionCompatInfoV5 {
pub block_header_version: u16, pub block_header_version: u16,
} }
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
pub struct ParticipantDataV5 {
/// Public key corresponding to private blinding factor
#[serde(with = "secp_ser::pubkey_serde")]
pub xs: PublicKey,
/// Public key corresponding to private nonce
#[serde(with = "secp_ser::pubkey_serde")]
pub nonce: PublicKey,
/// Public partial signature
#[serde(default = "default_part_sig_none")]
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(with = "secp_ser::option_sig_serde")]
pub part: Option<Signature>,
}
fn default_part_sig_none() -> Option<Signature> {
None
}
#[serde_as] #[serde_as]
#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)] #[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
pub struct PaymentInfoV5 { pub struct PaymentInfoV5 {
@@ -218,71 +175,6 @@ fn default_promise_signature_none() -> Option<DalekSignature> {
None None
} }
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
pub struct CommitsV5 {
/// Options for an output's structure or use
#[serde(default = "default_output_feature")]
#[serde(skip_serializing_if = "output_feature_is_plain")]
pub f: OutputFeaturesV5,
/// The homomorphic commitment representing the output amount
#[serde(
serialize_with = "secp_ser::as_hex",
deserialize_with = "secp_ser::commitment_from_hex"
)]
pub c: Commitment,
/// A proof that the commitment is in the right range
/// Only applies for transaction outputs
#[serde(with = "ser::option_rangeproof_hex")]
#[serde(default = "default_range_proof")]
#[serde(skip_serializing_if = "Option::is_none")]
pub p: Option<RangeProof>,
}
impl From<&Output> for CommitsV5 {
fn from(out: &Output) -> CommitsV5 {
CommitsV5 {
f: out.features().into(),
c: out.commitment(),
p: Some(out.proof()),
}
}
}
// This will need to be reworked once we no longer support input features with "commit only" inputs.
impl From<&Input> for CommitsV5 {
fn from(input: &Input) -> CommitsV5 {
CommitsV5 {
f: input.features.into(),
c: input.commitment(),
p: None,
}
}
}
fn default_output_feature() -> OutputFeaturesV5 {
OutputFeaturesV5(0)
}
fn output_feature_is_plain(o: &OutputFeaturesV5) -> bool {
o.0 == 0
}
#[derive(Serialize, Deserialize, Copy, Debug, Clone, PartialEq, Eq)]
pub struct OutputFeaturesV5(pub u8);
pub fn sig_is_blank(s: &secp::Signature) -> bool {
for b in s.to_raw_data().iter() {
if *b != 0 {
return false;
}
}
true
}
fn default_range_proof() -> Option<RangeProof> {
None
}
fn u64_is_blank(u: &u64) -> bool { fn u64_is_blank(u: &u64) -> bool {
*u == 0 *u == 0
} }
@@ -302,72 +194,3 @@ fn fee_is_zero(f: &FeeFields) -> bool {
fn default_fee() -> FeeFields { fn default_fee() -> FeeFields {
FeeFields::zero() FeeFields::zero()
} }
/// 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 CoinbaseV5 {
/// Output
output: CbOutputV5,
/// Kernel
kernel: CbKernelV5,
/// Key Id
key_id: Option<Identifier>,
}
impl From<CbData> for CoinbaseV5 {
fn from(cb: CbData) -> CoinbaseV5 {
CoinbaseV5 {
output: CbOutputV5::from(&cb.output),
kernel: CbKernelV5::from(&cb.kernel),
key_id: cb.key_id,
}
}
}
impl From<&Output> for CbOutputV5 {
fn from(output: &Output) -> CbOutputV5 {
CbOutputV5 {
features: CbOutputFeatures::Coinbase,
commit: output.commitment(),
proof: output.proof(),
}
}
}
impl From<&TxKernel> for CbKernelV5 {
fn from(kernel: &TxKernel) -> CbKernelV5 {
CbKernelV5 {
features: CbKernelFeatures::Coinbase,
excess: kernel.excess,
excess_sig: kernel.excess_sig,
}
}
}
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
enum CbOutputFeatures {
Coinbase,
}
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
enum CbKernelFeatures {
Coinbase,
}
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
struct CbOutputV5 {
features: CbOutputFeatures,
#[serde(serialize_with = "secp_ser::as_hex")]
commit: Commitment,
#[serde(serialize_with = "secp_ser::as_hex")]
proof: RangeProof,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
struct CbKernelV5 {
features: CbKernelFeatures,
#[serde(serialize_with = "secp_ser::as_hex")]
excess: Commitment,
#[serde(with = "secp_ser::sig_serde")]
excess_sig: secp::Signature,
}
+8 -133
View File
@@ -14,13 +14,9 @@
//! Wraps a V5 Slate into a V5 Binary slate //! Wraps a V5 Slate into a V5 Binary slate
use crate::grin_core::core::transaction::OutputFeatures;
use crate::grin_core::ser as grin_ser; use crate::grin_core::ser as grin_ser;
use crate::grin_core::ser::{Readable, Reader, Writeable, Writer}; use crate::grin_core::ser::{Readable, Reader, Writeable, Writer};
use crate::grin_keychain::BlindingFactor; use crate::grin_keychain::BlindingFactor;
use crate::grin_util::secp::key::PublicKey;
use crate::grin_util::secp::pedersen::{Commitment, RangeProof};
use crate::grin_util::secp::Signature;
use crate::slate::{PaymentMemo, PaymentProofType}; use crate::slate::{PaymentMemo, PaymentProofType};
use chrono::DateTime; use chrono::DateTime;
use ed25519_dalek::Signature as DalekSignature; use ed25519_dalek::Signature as DalekSignature;
@@ -28,90 +24,12 @@ use ed25519_dalek::VerifyingKey as DalekPublicKey;
use std::convert::TryFrom; use std::convert::TryFrom;
use crate::slate_versions::v5::{ use crate::slate_versions::v5::{
CommitsV5, KernelFeaturesArgsV5, ParticipantDataV5, PaymentInfoV5, SlateStateV5, SlateV5, CommitsV5, KernelFeaturesArgsV5, PaymentInfoV5, SlateStateV5, SlateV5, VersionCompatInfoV5,
VersionCompatInfoV5,
}; };
use crate::slate_versions::v4_bin::{SlateOptFields, UuidWrap}; use crate::slate_versions::v4_bin::{
ComsWrap, ComsWrapRef, SigsWrap, SigsWrapRef, SlateOptFields, UuidWrap,
impl Writeable for SlateStateV5 { };
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), grin_ser::Error> {
let b = match self {
SlateStateV5::Unknown => 0,
SlateStateV5::Standard1 => 1,
SlateStateV5::Standard2 => 2,
SlateStateV5::Standard3 => 3,
SlateStateV5::Invoice1 => 4,
SlateStateV5::Invoice2 => 5,
SlateStateV5::Invoice3 => 6,
};
writer.write_u8(b)
}
}
impl Readable for SlateStateV5 {
fn read<R: Reader>(reader: &mut R) -> Result<SlateStateV5, grin_ser::Error> {
let b = reader.read_u8()?;
let sta = match b {
0 => SlateStateV5::Unknown,
1 => SlateStateV5::Standard1,
2 => SlateStateV5::Standard2,
3 => SlateStateV5::Standard3,
4 => SlateStateV5::Invoice1,
5 => SlateStateV5::Invoice2,
6 => SlateStateV5::Invoice3,
_ => SlateStateV5::Unknown,
};
Ok(sta)
}
}
struct SigsWrap(Vec<ParticipantDataV5>);
struct SigsWrapRef<'a>(&'a Vec<ParticipantDataV5>);
impl<'a> Writeable for SigsWrapRef<'a> {
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), grin_ser::Error> {
writer.write_u8(self.0.len() as u8)?;
for s in self.0.iter() {
//0 means part sig is not yet included
//1 means part sig included
if s.part.is_some() {
writer.write_u8(1)?;
} else {
writer.write_u8(0)?;
}
s.xs.write(writer)?;
s.nonce.write(writer)?;
if let Some(s) = s.part {
s.write(writer)?;
}
}
Ok(())
}
}
impl Readable for SigsWrap {
fn read<R: Reader>(reader: &mut R) -> Result<SigsWrap, grin_ser::Error> {
let sigs_len = reader.read_u8()?;
let sigs = {
let mut ret = vec![];
for _ in 0..sigs_len as usize {
let has_partial = reader.read_u8()?;
let c = ParticipantDataV5 {
xs: PublicKey::read(reader)?,
nonce: PublicKey::read(reader)?,
part: match has_partial {
1 => Some(Signature::read(reader)?),
0 | _ => None,
},
};
ret.push(c);
}
ret
};
Ok(SigsWrap(sigs))
}
}
/// Serialization of optional structs /// Serialization of optional structs
struct SlateOptStructsRef<'a> { struct SlateOptStructsRef<'a> {
@@ -169,53 +87,6 @@ impl Readable for SlateOptStructs {
} }
} }
struct ComsWrap(Vec<CommitsV5>);
struct ComsWrapRef<'a>(&'a Vec<CommitsV5>);
impl<'a> Writeable for ComsWrapRef<'a> {
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), grin_ser::Error> {
writer.write_u16(self.0.len() as u16)?;
for o in self.0.iter() {
//0 means input
//1 means output with proof
if o.p.is_some() {
writer.write_u8(1)?;
} else {
writer.write_u8(0)?;
}
OutputFeatures::from(o.f).write(writer)?;
o.c.write(writer)?;
if let Some(p) = o.p {
p.write(writer)?;
}
}
Ok(())
}
}
impl Readable for ComsWrap {
fn read<R: Reader>(reader: &mut R) -> Result<ComsWrap, grin_ser::Error> {
let coms_len = reader.read_u16()?;
let coms = {
let mut ret = vec![];
for _ in 0..coms_len as usize {
let is_output = reader.read_u8()?;
let c = CommitsV5 {
f: OutputFeatures::read(reader)?.into(),
c: Commitment::read(reader)?,
p: match is_output {
1 => Some(RangeProof::read(reader)?),
0 | _ => None,
},
};
ret.push(c);
}
ret
};
Ok(ComsWrap(coms))
}
}
struct ProofWrap(PaymentInfoV5); struct ProofWrap(PaymentInfoV5);
struct ProofWrapRef<'a>(&'a PaymentInfoV5); struct ProofWrapRef<'a>(&'a PaymentInfoV5);
@@ -485,8 +356,12 @@ impl Readable for SlateV5Bin {
#[test] #[test]
fn slate_v5_serialize_deserialize() { fn slate_v5_serialize_deserialize() {
use crate::grin_core::core::transaction::OutputFeatures;
use crate::grin_util::from_hex; use crate::grin_util::from_hex;
use crate::grin_util::secp::key::PublicKey; use crate::grin_util::secp::key::PublicKey;
use crate::grin_util::secp::pedersen::{Commitment, RangeProof};
use crate::grin_util::secp::Signature;
use crate::slate_versions::v5::ParticipantDataV5;
use crate::Slate; use crate::Slate;
use chrono::Utc; use chrono::Utc;
use grin_core::global::{set_local_chain_type, ChainTypes}; use grin_core::global::{set_local_chain_type, ChainTypes};