Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion libwallet/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ pub mod slatepack;
mod types;

pub use crate::error::Error;
pub use crate::slate::{ParticipantData, Slate, SlateState};
pub use crate::slate::{KernelFeaturesArgs, ParticipantData, Slate, SlateState};
pub use crate::slate_versions::v4::sig_is_blank;
pub use crate::slate_versions::{
SlateVersion, VersionedBinSlate, VersionedCoinbase, VersionedSlate, CURRENT_SLATE_VERSION,
Expand Down
49 changes: 38 additions & 11 deletions libwallet/src/slate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,38 @@ impl Slate {
kernel_features_args: None,
}
}

/// Create a new slate with the provided kernel features.
pub fn blank_with_kernel_features(
num_participants: u8,
is_invoice: bool,
kernel_features: KernelFeatures,
) -> Result<Slate, Error> {
let feature = kernel_features.as_u8();
let (fee_fields, kernel_features_args) = match kernel_features {
KernelFeatures::Plain { fee } => (fee, None),
KernelFeatures::Coinbase => return Err(Error::InvalidKernelFeatures(feature)),
KernelFeatures::HeightLocked { fee, lock_height } => {
(fee, Some(KernelFeaturesArgs { lock_height }))
}
KernelFeatures::NoRecentDuplicate {
fee,
relative_height,
} => (
fee,
Some(KernelFeaturesArgs {
lock_height: relative_height.into(),
}),
),
};
let mut slate = Slate::blank(num_participants, is_invoice);
slate.fee_fields = fee_fields;
slate.kernel_features = feature;
slate.kernel_features_args = kernel_features_args;
slate.update_kernel()?;
Ok(slate)
}

/// Removes any signature data that isn't mine, for compacting
/// slates for a return journey
pub fn remove_other_sigdata<K>(
Expand Down Expand Up @@ -954,6 +986,8 @@ pub fn tx_from_slate_v4(slate: &SlateV4) -> Option<Transaction> {
let secp = secp.lock();
let mut calc_slate = Slate::blank(2, false);
calc_slate.fee_fields = slate.fee;
calc_slate.kernel_features = slate.feat;
calc_slate.kernel_features_args = slate.feat_args.as_ref().map(KernelFeaturesArgs::from);
for d in slate.sigs.iter() {
calc_slate.participant_data.push(ParticipantData {
public_blind_excess: d.xs,
Expand All @@ -969,18 +1003,11 @@ pub fn tx_from_slate_v4(slate: &SlateV4) -> Option<Transaction> {
Ok(s) => s,
Err(_) => Signature::from_raw_data(&[0; 64]).unwrap(),
};
let features = calc_slate
.kernel_features()
.unwrap_or(KernelFeatures::Plain { fee: slate.fee });
let kernel = TxKernel {
features: match slate.feat {
0 => KernelFeatures::Plain { fee: slate.fee },
1 => KernelFeatures::HeightLocked {
fee: slate.fee,
lock_height: match slate.feat_args.as_ref() {
Some(a) => a.lock_hgt,
None => 0,
},
},
_ => KernelFeatures::Plain { fee: slate.fee },
},
features,
excess,
excess_sig,
};
Expand Down
6 changes: 3 additions & 3 deletions libwallet/src/slate_versions/v4_bin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -449,8 +449,8 @@ impl Writeable for SlateV4Bin {
proof: &v4.proof,
}
.write(writer)?;
// Write lock height for height locked kernels
if v4.feat == 2 {
// Write the height argument for height locked and NRD kernels
if matches!(v4.feat, 2 | 3) {
let lock_hgt = match &v4.feat_args {
Some(l) => l.lock_hgt,
None => 0,
Expand All @@ -475,7 +475,7 @@ impl Readable for SlateV4Bin {
let sigs = SigsWrap::read(reader)?.0;
let opt_structs = SlateOptStructs::read(reader)?;

let feat_args = if opts.feat == 2 {
let feat_args = if matches!(opts.feat, 2 | 3) {
Some(KernelFeaturesArgsV4 {
lock_hgt: reader.read_u64()?,
})
Expand Down
77 changes: 75 additions & 2 deletions libwallet/tests/slate_versioning.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,81 @@
// See the License for the specific language governing permissions and
// limitations under the License.

//! core::libtx specific tests
//use grin_wallet_libwallet::Slate;
//! Slate versioning tests

use grin_core::core::transaction::{KernelFeatures, NRDRelativeHeight};
use grin_core::core::FeeFields;
use grin_wallet_libwallet::{Slate, SlateVersion, Slatepacker, SlatepackerArgs, VersionedSlate};

#[test]
fn kernel_features_round_trip() {
let fee = FeeFields::new(0, 42).unwrap();
let features = [
KernelFeatures::HeightLocked {
fee,
lock_height: 500_000,
},
KernelFeatures::NoRecentDuplicate {
fee,
relative_height: NRDRelativeHeight::new(10).unwrap(),
},
];
let packer = Slatepacker::new(SlatepackerArgs {
sender: None,
recipients: vec![],
dec_key: None,
});

for expected_features in features {
let slate = Slate::blank_with_kernel_features(2, false, expected_features).unwrap();
let expected_args = slate.kernel_features_args.clone();

let versioned = VersionedSlate::into_version(slate.clone(), SlateVersion::V4).unwrap();
let json = serde_json::to_string(&versioned).unwrap();
let versioned: VersionedSlate = serde_json::from_str(&json).unwrap();
let json_slate: Slate = versioned.into();
assert_eq!(json_slate.kernel_features_args, expected_args);
assert_eq!(
json_slate.tx.unwrap().kernels()[0].features,
expected_features
);

let slatepack = packer.create_slatepack(&slate).unwrap();
let slatepack_slate = packer.get_slate(&slatepack).unwrap();
assert_eq!(slatepack_slate.kernel_features_args, expected_args);
assert_eq!(
slatepack_slate.tx.unwrap().kernels()[0].features,
expected_features
);
}
}

#[test]
fn kernel_features() {
let fee = FeeFields::new(0, 42).unwrap();
let features = [
KernelFeatures::Plain { fee },
KernelFeatures::HeightLocked {
fee,
lock_height: 500_000,
},
KernelFeatures::NoRecentDuplicate {
fee,
relative_height: NRDRelativeHeight::new(10).unwrap(),
},
];

for expected_features in features {
let slate = Slate::blank_with_kernel_features(2, false, expected_features).unwrap();
assert_eq!(slate.kernel_features, expected_features.as_u8());
assert_eq!(slate.tx.unwrap().kernels()[0].features, expected_features);
}

assert!(matches!(
Slate::blank_with_kernel_features(2, false, KernelFeatures::Coinbase),
Err(grin_wallet_libwallet::Error::InvalidKernelFeatures(1))
));
}

// test all slate conversions
/* TODO: Turn back on upon release of new slate version
Expand Down