From 66790945d793892ebe5293b4e24906b6e79c72a9 Mon Sep 17 00:00:00 2001 From: surangap Date: Wed, 28 Sep 2022 00:34:46 +0530 Subject: [PATCH 01/11] Add SignerListSet struct --- codec/src/field.rs | 6 ++++++ codec/src/transaction.rs | 11 +++++++++++ 2 files changed, 17 insertions(+) diff --git a/codec/src/field.rs b/codec/src/field.rs index d8852eb..0d1a3c3 100644 --- a/codec/src/field.rs +++ b/codec/src/field.rs @@ -43,6 +43,12 @@ pub struct Amount(pub AmountType); #[derive(Field, Debug, Default)] pub struct TxnSignature(pub BlobType); +#[derive(Field, Debug, Default)] +pub struct SignerEntry { + Account: Account, + SignerWeight: u32, +} + impl BinarySerialize for T { fn binary_serialize_to(&self, buf: &mut Vec, for_signing: bool) { if !self.is_serialized() { diff --git a/codec/src/transaction.rs b/codec/src/transaction.rs index 4f55664..cb69565 100644 --- a/codec/src/transaction.rs +++ b/codec/src/transaction.rs @@ -120,6 +120,17 @@ impl Payment { } } +/// An XRP SignerListSet tx +#[derive(Transaction, Debug)] +pub struct SignerListSet { + account: Account, + transaction_type: TransactionType, + fee: Fee, + flags: Flags, + SignerQuorum: u32, + SignerEntries: Vec, +} + #[cfg(test)] mod tests { use super::{CodecToFields, Payment}; From 7831cd38dc01a980934ec610da7803e8410e9ff7 Mon Sep 17 00:00:00 2001 From: surangap Date: Tue, 4 Oct 2022 11:43:00 +0530 Subject: [PATCH 02/11] Add SignerEntryType --- codec/src/types.rs | 62 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/codec/src/types.rs b/codec/src/types.rs index 2b7bda3..c8bfa82 100644 --- a/codec/src/types.rs +++ b/codec/src/types.rs @@ -1,6 +1,10 @@ //! XRPL codec primitive types -use crate::{traits::BinarySerialize, Vec}; +use crate::{ + traits::{ BinarySerialize}, + Vec, +}; +use crate::field::{Account, SignerWeight}; pub const ACCOUNT_ID_TYPE_CODE: u16 = 8; @@ -80,3 +84,59 @@ impl BinarySerialize for AmountType { buf.extend_from_slice((self.0 | 0x4000000000000000).to_be_bytes().as_slice()); } } + +// #[derive(Debug)] +// pub struct STObjectType(pub T); +// impl BinarySerialize for STObjectType { +// fn binary_serialize_to(&self, buf: &mut Vec, _for_signing: bool) { +// // Iterate over the canonical fields and do their serialize +// for f in self.0.to_canonical_fields().iter_mut() { +// f.binary_serialize_to(buf, _for_signing); +// } +// +// // Append the array end here. Ref -> https://xrpl.org/serialization.html#object-fields +// buf.push(0xe1); +// } +// } + +#[derive(Debug)] +pub struct SignerEntryType(pub Account, pub SignerWeight); +impl BinarySerialize for SignerEntryType { + fn binary_serialize_to(&self, buf: &mut Vec, _for_signing: bool) { + // call in canonical order + self.1.binary_serialize_to(buf, _for_signing); + self.0.binary_serialize_to(buf, _for_signing); + + // Append the Object end here. Ref -> https://xrpl.org/serialization.html#object-fields + buf.push(0xe1); + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::field::{SignerEntry, SignerWeight, Account}; + + #[test] + #[allow(non_snake_case)] + fn test_SignerEntryType() { + let signer_entry_type = SignerEntryType(Account(AccountIdType([1_u8; 20])), + SignerWeight(UInt16Type(1_u16))); + let buf = signer_entry_type.binary_serialize(true); + // let signer_entry_field_id: u8 = 0xEB; // Typecode(14) | FieldCode(11) = 0xEB + let account_field_id: u8 = 0x81; // Typecode(8) | Fieldcode(1) = 0x81(129) + let signer_weight_field_id: u8 = 0x13; // Typecode(1) | Fieldcode(3) = 0x13(19) + let account_field_vl: u8 = 0x14; // https://xrpl.org/serialization.html#accountid-fields + let st_object_end: u8 = 0xe1; // https://xrpl.org/serialization.html#object-fields + // construct expected buffer + let mut expected_buf = Vec::::default(); + expected_buf.extend_from_slice(&[signer_weight_field_id]); // SignerWeight comes first in the canonical order + expected_buf.extend_from_slice( &1_u16.to_be_bytes()); + expected_buf.extend_from_slice(&[account_field_id]); + expected_buf.extend_from_slice(&[account_field_vl]); + expected_buf.extend_from_slice( &[1_u8; 20]); + expected_buf.extend_from_slice(&[st_object_end]); + + assert_eq!(buf, expected_buf); + } +} \ No newline at end of file From d28d2292f7760635d53603096ffdf94cd907f1d3 Mon Sep 17 00:00:00 2001 From: surangap Date: Tue, 4 Oct 2022 11:44:14 +0530 Subject: [PATCH 03/11] Add STArrayType --- codec/src/types.rs | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/codec/src/types.rs b/codec/src/types.rs index c8bfa82..70b1b65 100644 --- a/codec/src/types.rs +++ b/codec/src/types.rs @@ -112,6 +112,19 @@ impl BinarySerialize for SignerEntryType { } } +#[derive(Debug)] +pub struct STArrayType(pub Vec); +impl BinarySerialize for STArrayType { + fn binary_serialize_to(&self, buf: &mut Vec, _for_signing: bool) { + // no order, serialize the way it is. Ref -> https://xrpl.org/serialization.html#array-fields + for item in &self.0 { + item.binary_serialize_to(buf, _for_signing); + } + // Append the array end here. Ref -> https://xrpl.org/serialization.html#array-fields + buf.push(0xf1); + } +} + #[cfg(test)] mod tests { use super::*; @@ -137,6 +150,39 @@ mod tests { expected_buf.extend_from_slice( &[1_u8; 20]); expected_buf.extend_from_slice(&[st_object_end]); + assert_eq!(buf, expected_buf); + } + #[test] + #[allow(non_snake_case)] + fn test_STArrayType() { + // use SignerEntry + let mut signer_entries = Vec::::default(); + for i in 1..=2 { + signer_entries.push(SignerEntry(SignerEntryType(Account(AccountIdType([i as u8; 20])), + SignerWeight(UInt16Type(i as u16))))); + } + let st_array_type = STArrayType(signer_entries); + + let buf = st_array_type.binary_serialize(true); + let signer_entry_field_id: u8 = 0xEB; // Typecode(14) | FieldCode(11) = 0xEB + let account_field_id: u8 = 0x81; // Typecode(8) | Fieldcode(1) = 0x81(129) + let signer_weight_field_id: u8 = 0x13; // Typecode(1) | Fieldcode(3) = 0x13(19) + let account_field_vl: u8 = 0x14; // https://xrpl.org/serialization.html#accountid-fields + let st_object_end: u8 = 0xe1; // https://xrpl.org/serialization.html#object-fields + + // let's construct the expected buffer -> https://xrpl.org/serialization.html#array-fields + let mut expected_buf = Vec::::default(); + for i in 1..=2 { + expected_buf.extend_from_slice(&[signer_entry_field_id]); // SignerEntry field ID + expected_buf.extend_from_slice(&[signer_weight_field_id]); // SignerWeight comes first in the canonical order + expected_buf.extend_from_slice(&(i as u16).to_be_bytes()); + expected_buf.extend_from_slice(&[account_field_id]); + expected_buf.extend_from_slice(&[account_field_vl]); + expected_buf.extend_from_slice(&[i as u8; 20]); + expected_buf.extend_from_slice(&[st_object_end]); + } + expected_buf.extend_from_slice(&[0xf1]); // STArray end 0xf1 + assert_eq!(buf, expected_buf); } } \ No newline at end of file From 7342fc7d39490c0b4aae6a2262ed72dcaf4156de Mon Sep 17 00:00:00 2001 From: surangap Date: Tue, 4 Oct 2022 11:48:18 +0530 Subject: [PATCH 04/11] Add SignerQuorum, SignerWeight, SignerEntry, SignerEntries fields --- codec/src/field.rs | 76 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 69 insertions(+), 7 deletions(-) diff --git a/codec/src/field.rs b/codec/src/field.rs index 0d1a3c3..04d6ed7 100644 --- a/codec/src/field.rs +++ b/codec/src/field.rs @@ -5,7 +5,8 @@ use xrpl_codec_utils::Field; use crate::{ traits::{BinarySerialize, CodecField}, - types::{AccountIdType, AmountType, BlobType, UInt16Type, UInt32Type, ACCOUNT_ID_TYPE_CODE}, + types::{AccountIdType, AmountType, BlobType, UInt16Type, UInt32Type, ACCOUNT_ID_TYPE_CODE, + STArrayType, SignerEntryType}, Vec, }; @@ -43,11 +44,17 @@ pub struct Amount(pub AmountType); #[derive(Field, Debug, Default)] pub struct TxnSignature(pub BlobType); -#[derive(Field, Debug, Default)] -pub struct SignerEntry { - Account: Account, - SignerWeight: u32, -} +#[derive(Field, Debug)] +pub struct SignerQuorum(pub UInt32Type); + +#[derive(Field, Debug)] +pub struct SignerWeight(pub UInt16Type); + +#[derive(Field, Debug)] +pub struct SignerEntry(pub SignerEntryType); + +#[derive(Field, Debug)] +pub struct SignerEntries(pub STArrayType); impl BinarySerialize for T { fn binary_serialize_to(&self, buf: &mut Vec, for_signing: bool) { @@ -161,7 +168,6 @@ impl TransactionTypeCode { mod tests { use super::*; use crate::types::BlobType; - use std::prelude::*; #[test] fn serialize_signing_pub_key() { @@ -186,4 +192,60 @@ mod tests { let buf = Destination(AccountIdType(dest)).binary_serialize(true); println!("{:?}", hex::encode(&buf)); } + #[test] + fn serialize_signer_entry() { + let signer_entry = SignerEntry(SignerEntryType(Account(AccountIdType([1_u8; 20])), + SignerWeight(UInt16Type(1_u16)))); + let buf = signer_entry.binary_serialize(true); + // construct the expected buffer manually + let signer_entry_field_id: u8 = 0xEB; // Typecode(14) | FieldCode(11) = 0xEB + let account_field_id: u8 = 0x81; // Typecode(8) | Fieldcode(1) = 0x81(129) + let signer_weight_field_id: u8 = 0x13; // Typecode(1) | Fieldcode(3) = 0x13(19) + let account_field_vl: u8 = 0x14; // https://xrpl.org/serialization.html#accountid-fields + let st_object_end: u8 = 0xe1; // https://xrpl.org/serialization.html#object-fields + + let mut expected_buf = Vec::::default(); + expected_buf.extend_from_slice(&[signer_entry_field_id]); + expected_buf.extend_from_slice(&[signer_weight_field_id]); // SignerWeight comes first in the canonical order + expected_buf.extend_from_slice( &1_u16.to_be_bytes()); + expected_buf.extend_from_slice(&[account_field_id]); + expected_buf.extend_from_slice(&[account_field_vl]); + expected_buf.extend_from_slice( &[1_u8; 20]); + expected_buf.extend_from_slice(&[st_object_end]); + + assert_eq!(buf, expected_buf); + } + #[test] + fn serialize_signer_entries() { + let mut signer_entries_vec = Vec::::default(); + for i in 1..=2 { + signer_entries_vec.push(SignerEntry(SignerEntryType(Account(AccountIdType([i as u8; 20])), + SignerWeight(UInt16Type(i as u16))))); + } + let signer_entries = SignerEntries(STArrayType(signer_entries_vec)); + + let buf = signer_entries.binary_serialize(true); + let signer_entries_field_id: u8 = 0xF4; // Typecode(15) | FieldCode(4) = 0xF4 + let signer_entry_field_id: u8 = 0xEB; // Typecode(14) | FieldCode(11) = 0xEB + let account_field_id: u8 = 0x81; // Typecode(8) | Fieldcode(1) = 0x81(129) + let signer_weight_field_id: u8 = 0x13; // Typecode(1) | Fieldcode(3) = 0x13(19) + let account_field_vl: u8 = 0x14; // https://xrpl.org/serialization.html#accountid-fields + let st_object_end: u8 = 0xe1; // https://xrpl.org/serialization.html#object-fields + + // let's construct the expected buffer -> https://xrpl.org/serialization.html#array-fields + let mut expected_buf = Vec::::default(); + expected_buf.extend_from_slice(&[signer_entries_field_id]); + for i in 1..=2 { + expected_buf.extend_from_slice(&[signer_entry_field_id]); // SignerEntry field ID + expected_buf.extend_from_slice(&[signer_weight_field_id]); // SignerWeight comes first in the canonical order + expected_buf.extend_from_slice(&(i as u16).to_be_bytes()); + expected_buf.extend_from_slice(&[account_field_id]); + expected_buf.extend_from_slice(&[account_field_vl]); + expected_buf.extend_from_slice(&[i as u8; 20]); + expected_buf.extend_from_slice(&[st_object_end]); + } + expected_buf.extend_from_slice(&[0xf1]); // STArray end 0xf1 + + assert_eq!(buf, expected_buf); + } } From 8b629a6f02dc23d8a6d906b8ba5c973b41f3fa91 Mon Sep 17 00:00:00 2001 From: surangap Date: Tue, 4 Oct 2022 11:50:00 +0530 Subject: [PATCH 05/11] Update SignerListSet transaction struct --- codec/src/transaction.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/codec/src/transaction.rs b/codec/src/transaction.rs index cb69565..fa6ee0e 100644 --- a/codec/src/transaction.rs +++ b/codec/src/transaction.rs @@ -123,12 +123,17 @@ impl Payment { /// An XRP SignerListSet tx #[derive(Transaction, Debug)] pub struct SignerListSet { + /// common tx fields account: Account, transaction_type: TransactionType, fee: Fee, flags: Flags, - SignerQuorum: u32, - SignerEntries: Vec, + /// SignerListSet + signer_quorum: SignerQuorum, + signer_entries: SignerEntries, + /// set when signing + signing_pub_key: SigningPubKey, + txn_signature: TxnSignature, } #[cfg(test)] @@ -136,7 +141,8 @@ mod tests { use super::{CodecToFields, Payment}; #[test] - fn canonical_field_order() { + #[allow(non_snake_case)] + fn test_Payment_canonical_field_order() { let account = [1_u8; 20]; let destination = [2_u8; 20]; let amount = 5_000_000_u64; // 5 XRP From f6e8bd9b3be762345dfad0db201992ccb48c727c Mon Sep 17 00:00:00 2001 From: surangap Date: Tue, 4 Oct 2022 13:03:44 +0530 Subject: [PATCH 06/11] implement SignerListSet tx, add tests. --- codec/src/transaction.rs | 77 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-) diff --git a/codec/src/transaction.rs b/codec/src/transaction.rs index fa6ee0e..1d75aa6 100644 --- a/codec/src/transaction.rs +++ b/codec/src/transaction.rs @@ -7,6 +7,7 @@ use crate::{ types::{AccountIdType, AmountType, BlobType, UInt32Type}, Vec, }; +use crate::types::{STArrayType}; /* Tx Common Fields @@ -136,9 +137,49 @@ pub struct SignerListSet { txn_signature: TxnSignature, } +impl SignerListSet { + /// Create a new XRP SignerListSet transaction + /// + /// Applies the global signing flags (see https://xrpl.org/transaction-common-fields.html#global-flags) + /// + /// - `account` the sender's address + /// - `fee` the max XRP fee in drops + /// - `signer_quorum` signer quorum required + /// - `signer_entries` signer entries which can participate in multi signing + /// - `signing_pub_key` public key of `account` + pub fn new( + account: [u8; 20], + fee: u64, + signer_quorum: u32, + signer_entries: Vec::, + signing_pub_key: Option<[u8; 33]>, + ) -> Self { + Self { + account: Account(AccountIdType(account)), + transaction_type: TransactionTypeCode::SignerListSet.into(), + fee: Fee(AmountType(fee)), + // https://xrpl.org/transaction-common-fields.html#global-flags + flags: Flags(UInt32Type(0x8000_0000_u32)), + /// payment only + signer_quorum: SignerQuorum(UInt32Type(signer_quorum)), + signer_entries: SignerEntries(STArrayType(signer_entries)), + signing_pub_key: signing_pub_key + .map(|pk| SigningPubKey(BlobType(pk.to_vec()))) + .unwrap_or_default(), + txn_signature: Default::default(), + } + } + /// Attach a signature to the transaction + pub fn attach_signature(&mut self, signature: [u8; 65]) { + self.txn_signature = TxnSignature(BlobType(signature.to_vec())); + } +} + #[cfg(test)] mod tests { - use super::{CodecToFields, Payment}; + use crate::field::{Account, SignerEntry, SignerWeight}; + use crate::types::{AccountIdType, SignerEntryType, UInt16Type}; + use super::{CodecToFields, Payment, SignerListSet}; #[test] #[allow(non_snake_case)] @@ -171,4 +212,38 @@ mod tests { } } } + #[test] + #[allow(non_snake_case)] + fn test_SignerListSet_canonical_field_order() { + let account = [1_u8; 20]; + let fee = 1_000; // 1000 drops + let signing_pub_key = [1_u8; 33]; + let signer_quorum = 3_u32; + let mut signer_entries = Vec::::default(); + signer_entries.push(SignerEntry(SignerEntryType(Account(AccountIdType([1_u8; 20])), + SignerWeight(UInt16Type(1_u16))))); + signer_entries.push(SignerEntry(SignerEntryType(Account(AccountIdType([2_u8; 20])), + SignerWeight(UInt16Type(2_u16))))); + + let signer_list_set = SignerListSet::new( + account, + fee, + signer_quorum, + signer_entries, + Some(signing_pub_key), + ); + + for chunk in signer_list_set.to_canonical_fields().chunks(2) { + match chunk { + &[f1, f2] => { + assert!( + f1.type_code() < f2.type_code() + || f1.type_code() == f2.type_code() + && f1.field_code() <= f2.field_code() + ); + } + _ => continue, + } + } + } } From 6765c854c1b180e1778e6e9eeabfa663cb18966c Mon Sep 17 00:00:00 2001 From: surangap Date: Tue, 4 Oct 2022 18:05:40 +0530 Subject: [PATCH 07/11] Add SignerListSet txn serialize test --- codec/src/field.rs | 22 ++++++++++----------- codec/src/transaction.rs | 41 +++++++++++++++++++++++++++++++++++++--- codec/src/types.rs | 22 ++++++++++----------- 3 files changed, 60 insertions(+), 25 deletions(-) diff --git a/codec/src/field.rs b/codec/src/field.rs index 04d6ed7..7aadff0 100644 --- a/codec/src/field.rs +++ b/codec/src/field.rs @@ -12,13 +12,13 @@ use crate::{ // TODO: auto-generate the structs from definitions.json -#[derive(Field, Debug)] +#[derive(Field, Debug, Clone)] pub struct Account(pub AccountIdType); -#[derive(Field, Debug)] +#[derive(Field, Debug, Clone)] pub struct Destination(pub AccountIdType); -#[derive(Field, Debug)] +#[derive(Field, Debug, Clone)] pub struct TransactionType(pub UInt16Type); impl From for TransactionType { fn from(v: TransactionTypeCode) -> Self { @@ -26,34 +26,34 @@ impl From for TransactionType { } } -#[derive(Field, Debug)] +#[derive(Field, Debug, Clone)] pub struct Fee(pub AmountType); -#[derive(Field, Debug)] +#[derive(Field, Debug, Clone)] pub struct Flags(pub UInt32Type); -#[derive(Field, Debug)] +#[derive(Field, Debug, Clone)] pub struct Sequence(pub UInt32Type); #[derive(Field, Debug, Default)] pub struct SigningPubKey(pub BlobType); -#[derive(Field, Debug)] +#[derive(Field, Debug, Clone)] pub struct Amount(pub AmountType); #[derive(Field, Debug, Default)] pub struct TxnSignature(pub BlobType); -#[derive(Field, Debug)] +#[derive(Field, Debug, Clone)] pub struct SignerQuorum(pub UInt32Type); -#[derive(Field, Debug)] +#[derive(Field, Debug, Clone)] pub struct SignerWeight(pub UInt16Type); -#[derive(Field, Debug)] +#[derive(Field, Debug, Clone)] pub struct SignerEntry(pub SignerEntryType); -#[derive(Field, Debug)] +#[derive(Field, Debug, Clone)] pub struct SignerEntries(pub STArrayType); impl BinarySerialize for T { diff --git a/codec/src/transaction.rs b/codec/src/transaction.rs index 1d75aa6..1ab8e21 100644 --- a/codec/src/transaction.rs +++ b/codec/src/transaction.rs @@ -151,7 +151,7 @@ impl SignerListSet { account: [u8; 20], fee: u64, signer_quorum: u32, - signer_entries: Vec::, + signer_entries: Vec, signing_pub_key: Option<[u8; 33]>, ) -> Self { Self { @@ -160,7 +160,6 @@ impl SignerListSet { fee: Fee(AmountType(fee)), // https://xrpl.org/transaction-common-fields.html#global-flags flags: Flags(UInt32Type(0x8000_0000_u32)), - /// payment only signer_quorum: SignerQuorum(UInt32Type(signer_quorum)), signer_entries: SignerEntries(STArrayType(signer_entries)), signing_pub_key: signing_pub_key @@ -177,9 +176,10 @@ impl SignerListSet { #[cfg(test)] mod tests { + use alloc::vec::Vec; use crate::field::{Account, SignerEntry, SignerWeight}; use crate::types::{AccountIdType, SignerEntryType, UInt16Type}; - use super::{CodecToFields, Payment, SignerListSet}; + use super::*; #[test] #[allow(non_snake_case)] @@ -246,4 +246,39 @@ mod tests { } } } + #[test] + #[allow(non_snake_case)] + fn test_SignerListSet_serialize() { + let account = [1_u8; 20]; + let fee = 1_000; // 1000 drops + let signing_pub_key = [1_u8; 33]; + let signer_quorum = 3_u32; + let mut signer_entries = Vec::::default(); + signer_entries.push(SignerEntry(SignerEntryType(Account(AccountIdType([1_u8; 20])), + SignerWeight(UInt16Type(1_u16))))); + signer_entries.push(SignerEntry(SignerEntryType(Account(AccountIdType([2_u8; 20])), + SignerWeight(UInt16Type(2_u16))))); + + let signer_list_set = SignerListSet::new( + account, + fee, + signer_quorum, + signer_entries.clone(), + Some(signing_pub_key), + ); + + let buf = signer_list_set.binary_serialize(true); + // Construct the expected buf manually + let mut expected_buf = Vec::::default(); + expected_buf.extend_from_slice(&TransactionType(UInt16Type(TransactionTypeCode::SignerListSet.code())).binary_serialize(true)); // TransactionType + expected_buf.extend_from_slice(&Flags(UInt32Type(0x8000_0000_u32)).binary_serialize(true)); // Flags + expected_buf.extend_from_slice(&SignerQuorum(UInt32Type(signer_quorum)).binary_serialize(true)); // SignerQuorum + expected_buf.extend_from_slice(&Fee(AmountType(fee)).binary_serialize(true)); // Fee + expected_buf.extend_from_slice(&SigningPubKey(BlobType(signing_pub_key.to_vec())).binary_serialize(true)); // SigningPubKey + expected_buf.extend_from_slice(&TxnSignature::default().binary_serialize(true)); // TxnSignature + expected_buf.extend_from_slice(&Account(AccountIdType(account)).binary_serialize(true)); // Account + expected_buf.extend_from_slice(&SignerEntries(STArrayType(signer_entries)).binary_serialize(true)); // SignerEntries + + assert_eq!(buf, expected_buf); + } } diff --git a/codec/src/types.rs b/codec/src/types.rs index 70b1b65..0449a5f 100644 --- a/codec/src/types.rs +++ b/codec/src/types.rs @@ -8,13 +8,13 @@ use crate::field::{Account, SignerWeight}; pub const ACCOUNT_ID_TYPE_CODE: u16 = 8; -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct NotPresentType; impl BinarySerialize for NotPresentType { fn binary_serialize_to(&self, _buf: &mut Vec, _for_signing: bool) {} } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct UInt16Type(pub u16); impl BinarySerialize for UInt16Type { @@ -23,7 +23,7 @@ impl BinarySerialize for UInt16Type { } } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct UInt32Type(pub u32); impl BinarySerialize for UInt32Type { @@ -32,7 +32,7 @@ impl BinarySerialize for UInt32Type { } } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct UInt64Type(pub u64); impl BinarySerialize for UInt64Type { @@ -41,7 +41,7 @@ impl BinarySerialize for UInt64Type { } } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Hash160Type(pub [u8; 20]); impl BinarySerialize for Hash160Type { fn binary_serialize_to(&self, buf: &mut Vec, _for_signing: bool) { @@ -49,7 +49,7 @@ impl BinarySerialize for Hash160Type { } } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Hash256Type(pub [u8; 32]); impl BinarySerialize for Hash256Type { fn binary_serialize_to(&self, buf: &mut Vec, _for_signing: bool) { @@ -57,7 +57,7 @@ impl BinarySerialize for Hash256Type { } } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct AccountIdType(pub [u8; 20]); impl BinarySerialize for AccountIdType { fn binary_serialize_to(&self, buf: &mut Vec, _for_signing: bool) { @@ -65,7 +65,7 @@ impl BinarySerialize for AccountIdType { } } -#[derive(Default, Debug)] +#[derive(Default, Debug, Clone)] pub struct BlobType(pub Vec); impl BinarySerialize for BlobType { @@ -76,7 +76,7 @@ impl BinarySerialize for BlobType { /// Current ///ly supporting native XRP amounts only -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct AmountType(pub u64); impl BinarySerialize for AmountType { fn binary_serialize_to(&self, buf: &mut Vec, _for_signing: bool) { @@ -99,7 +99,7 @@ impl BinarySerialize for AmountType { // } // } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct SignerEntryType(pub Account, pub SignerWeight); impl BinarySerialize for SignerEntryType { fn binary_serialize_to(&self, buf: &mut Vec, _for_signing: bool) { @@ -112,7 +112,7 @@ impl BinarySerialize for SignerEntryType { } } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct STArrayType(pub Vec); impl BinarySerialize for STArrayType { fn binary_serialize_to(&self, buf: &mut Vec, _for_signing: bool) { From c1cfbcf70735acd3f793474ae180230224567c3d Mon Sep 17 00:00:00 2001 From: surangap Date: Wed, 5 Oct 2022 13:50:19 +0530 Subject: [PATCH 08/11] Update SignerListSet::new() signature to take all raw params. --- codec/src/transaction.rs | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/codec/src/transaction.rs b/codec/src/transaction.rs index 1ab8e21..c84e2ea 100644 --- a/codec/src/transaction.rs +++ b/codec/src/transaction.rs @@ -7,7 +7,7 @@ use crate::{ types::{AccountIdType, AmountType, BlobType, UInt32Type}, Vec, }; -use crate::types::{STArrayType}; +use crate::types::{SignerEntryType, STArrayType, UInt16Type}; /* Tx Common Fields @@ -151,7 +151,7 @@ impl SignerListSet { account: [u8; 20], fee: u64, signer_quorum: u32, - signer_entries: Vec, + signer_entries: Vec<([u8; 20], u16)>, signing_pub_key: Option<[u8; 33]>, ) -> Self { Self { @@ -161,7 +161,11 @@ impl SignerListSet { // https://xrpl.org/transaction-common-fields.html#global-flags flags: Flags(UInt32Type(0x8000_0000_u32)), signer_quorum: SignerQuorum(UInt32Type(signer_quorum)), - signer_entries: SignerEntries(STArrayType(signer_entries)), + signer_entries: SignerEntries(STArrayType(signer_entries.into_iter() + .map(|(account, weight)| { + SignerEntry(SignerEntryType( Account(AccountIdType(account)), + SignerWeight(UInt16Type(weight)))) + }).collect())), signing_pub_key: signing_pub_key .map(|pk| SigningPubKey(BlobType(pk.to_vec()))) .unwrap_or_default(), @@ -219,11 +223,10 @@ mod tests { let fee = 1_000; // 1000 drops let signing_pub_key = [1_u8; 33]; let signer_quorum = 3_u32; - let mut signer_entries = Vec::::default(); - signer_entries.push(SignerEntry(SignerEntryType(Account(AccountIdType([1_u8; 20])), - SignerWeight(UInt16Type(1_u16))))); - signer_entries.push(SignerEntry(SignerEntryType(Account(AccountIdType([2_u8; 20])), - SignerWeight(UInt16Type(2_u16))))); + let mut signer_entries = Vec::<([u8; 20], u16)>::default(); + signer_entries.push(([1_u8; 20], 1_u16)); + signer_entries.push(([2_u8; 20], 2_u16)); + let signer_list_set = SignerListSet::new( account, @@ -253,11 +256,9 @@ mod tests { let fee = 1_000; // 1000 drops let signing_pub_key = [1_u8; 33]; let signer_quorum = 3_u32; - let mut signer_entries = Vec::::default(); - signer_entries.push(SignerEntry(SignerEntryType(Account(AccountIdType([1_u8; 20])), - SignerWeight(UInt16Type(1_u16))))); - signer_entries.push(SignerEntry(SignerEntryType(Account(AccountIdType([2_u8; 20])), - SignerWeight(UInt16Type(2_u16))))); + let mut signer_entries = Vec::<([u8; 20], u16)>::default(); + signer_entries.push(([1_u8; 20], 1_u16)); + signer_entries.push(([2_u8; 20], 2_u16)); let signer_list_set = SignerListSet::new( account, @@ -277,6 +278,11 @@ mod tests { expected_buf.extend_from_slice(&SigningPubKey(BlobType(signing_pub_key.to_vec())).binary_serialize(true)); // SigningPubKey expected_buf.extend_from_slice(&TxnSignature::default().binary_serialize(true)); // TxnSignature expected_buf.extend_from_slice(&Account(AccountIdType(account)).binary_serialize(true)); // Account + let signer_entries = signer_entries.into_iter() + .map(|(account, weight)| { + SignerEntry(SignerEntryType( Account(AccountIdType(account)), + SignerWeight(UInt16Type(weight)))) + }).collect(); expected_buf.extend_from_slice(&SignerEntries(STArrayType(signer_entries)).binary_serialize(true)); // SignerEntries assert_eq!(buf, expected_buf); From d16feb4008c61ba73777af6da34ba190bbe5ed96 Mon Sep 17 00:00:00 2001 From: surangap Date: Wed, 5 Oct 2022 21:09:55 +0530 Subject: [PATCH 09/11] Add e2e testing for SignerListSet tx codec --- codec/tests/transaction_decoding.rs | 133 +++++++++++++++++++++++++++- 1 file changed, 130 insertions(+), 3 deletions(-) diff --git a/codec/tests/transaction_decoding.rs b/codec/tests/transaction_decoding.rs index 3e31f65..60a4786 100644 --- a/codec/tests/transaction_decoding.rs +++ b/codec/tests/transaction_decoding.rs @@ -2,12 +2,16 @@ use std::process::Command; -use xrpl_codec::{traits::BinarySerialize, transaction::Payment}; +use xrpl_codec::{ + traits::BinarySerialize, + transaction::{Payment, SignerListSet}, +}; // Assert `encoded` input decodes to `expected` JSON format (whitespace will be removed) fn assert_decodes(encoded: &[u8], expected: &str) { let js_test = format!( - "const xrpl = require(\"xrpl\"); console.log(xrpl.decode('{}'));", + "const util = require('util'); const xrpl = require(\"xrpl\"); \ + console.log(util.inspect(xrpl.decode('{}'), false, null, false));", hex::encode(&encoded) ); let result = Command::new("node") @@ -21,8 +25,9 @@ fn assert_decodes(encoded: &[u8], expected: &str) { core::str::from_utf8(&result.stdout) .expect("valid utf8 only") .replace(" ", "") + .replace("\n", "") .trim(), - expected.replace(" ", "") + expected.replace(" ", "").replace("\n", "") ); } @@ -186,3 +191,125 @@ fn public_key_to_account_id() { assert_eq!(xrpl_js_output, "rLFd1FzHMScFhLsXeaxStzv3UC97QHGAbM"); } + +#[test] +#[allow(non_snake_case)] +fn decode_SignerListSet_tx() { + let account = [1_u8; 20]; + let fee = 1_000; // 1000 drops + let signing_pub_key = [1_u8; 33]; + let signer_quorum = 3_u32; + let mut signer_entries = Vec::<([u8; 20], u16)>::default(); + signer_entries.push(([1_u8; 20], 1_u16)); + signer_entries.push(([2_u8; 20], 2_u16)); + + let mut signer_list_set = SignerListSet::new( + account, + fee, + signer_quorum, + signer_entries.clone(), + Some(signing_pub_key), + ); + + let encoded_no_signature = signer_list_set.binary_serialize(true); + + let expected_signer_list_set_json = r"{ + TransactionType: 'SignerListSet', + Flags: 2147483648, + SignerQuorum: 3, + Fee: '1000', + SigningPubKey: '010101010101010101010101010101010101010101010101010101010101010101', + Account: 'raJ1Aqkhf19P7cyUc33MMVAzgvHPvtNFC', + SignerEntries: [ + { + SignerEntry: { + SignerWeight: 1, + Account: 'raJ1Aqkhf19P7cyUc33MMVAzgvHPvtNFC' + } + }, + { + SignerEntry: { + SignerWeight: 2, + Account: 'rBcktgVfNjHmxNAQDEE66ztz4qZkdngdm' + } + } + ] + }"; + + assert_decodes(encoded_no_signature.as_slice(), expected_signer_list_set_json); + // with signature + signer_list_set.attach_signature([7_u8; 65]); + let expected_signer_list_set_json = r"{ + TransactionType: 'SignerListSet', + Flags: 2147483648, + SignerQuorum: 3, + Fee: '1000', + SigningPubKey: '010101010101010101010101010101010101010101010101010101010101010101', + TxnSignature: '0707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707', + Account: 'raJ1Aqkhf19P7cyUc33MMVAzgvHPvtNFC', + SignerEntries: [ + { + SignerEntry: { + SignerWeight: 1, + Account: 'raJ1Aqkhf19P7cyUc33MMVAzgvHPvtNFC' + } + }, + { + SignerEntry: { + SignerWeight: 2, + Account: 'rBcktgVfNjHmxNAQDEE66ztz4qZkdngdm' + } + } + ] + }"; + let encoded_with_signature = signer_list_set.binary_serialize(false); + assert_decodes(encoded_with_signature.as_slice(), expected_signer_list_set_json); +} + +#[test] +#[allow(non_snake_case)] +fn decode_SignerListSet_tx_empty_signer_entries() { + let account = [1_u8; 20]; + let fee = 1_000; // 1000 drops + let signing_pub_key = [1_u8; 33]; + let signer_quorum = 3_u32; + // let mut signer_entries = Vec::<([u8; 20], u16)>::default(); + // signer_entries.push(([1_u8; 20], 1_u16)); + // signer_entries.push(([2_u8; 20], 2_u16)); + + let mut signer_list_set = SignerListSet::new( + account, + fee, + signer_quorum, + Default::default(), + Some(signing_pub_key), + ); + + let encoded_no_signature = signer_list_set.binary_serialize(true); + + let expected_signer_list_set_json = r"{ + TransactionType: 'SignerListSet', + Flags: 2147483648, + SignerQuorum: 3, + Fee: '1000', + SigningPubKey: '010101010101010101010101010101010101010101010101010101010101010101', + Account: 'raJ1Aqkhf19P7cyUc33MMVAzgvHPvtNFC', + SignerEntries: [] + }"; + + assert_decodes(encoded_no_signature.as_slice(), expected_signer_list_set_json); + // with signature + signer_list_set.attach_signature([7_u8; 65]); + let expected_signer_list_set_json = r"{ + TransactionType: 'SignerListSet', + Flags: 2147483648, + SignerQuorum: 3, + Fee: '1000', + SigningPubKey: '010101010101010101010101010101010101010101010101010101010101010101', + TxnSignature: '0707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707', + Account: 'raJ1Aqkhf19P7cyUc33MMVAzgvHPvtNFC', + SignerEntries: [] + }"; + let encoded_with_signature = signer_list_set.binary_serialize(false); + assert_decodes(encoded_with_signature.as_slice(), expected_signer_list_set_json); +} From d83011753ece1ac91bfb9ba16ace73b1c48ca48a Mon Sep 17 00:00:00 2001 From: surangap Date: Wed, 5 Oct 2022 21:18:41 +0530 Subject: [PATCH 10/11] minor --- codec/src/types.rs | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/codec/src/types.rs b/codec/src/types.rs index 0449a5f..96c3e18 100644 --- a/codec/src/types.rs +++ b/codec/src/types.rs @@ -85,20 +85,7 @@ impl BinarySerialize for AmountType { } } -// #[derive(Debug)] -// pub struct STObjectType(pub T); -// impl BinarySerialize for STObjectType { -// fn binary_serialize_to(&self, buf: &mut Vec, _for_signing: bool) { -// // Iterate over the canonical fields and do their serialize -// for f in self.0.to_canonical_fields().iter_mut() { -// f.binary_serialize_to(buf, _for_signing); -// } -// -// // Append the array end here. Ref -> https://xrpl.org/serialization.html#object-fields -// buf.push(0xe1); -// } -// } - +// TODO(surangap) - https://github.com/futureversecom/xrpl-tx-codec/issues/7 #[derive(Debug, Clone)] pub struct SignerEntryType(pub Account, pub SignerWeight); impl BinarySerialize for SignerEntryType { From 1d2ae9e02f6c3d814f827ddda23dbc967cb0d7d0 Mon Sep 17 00:00:00 2001 From: surangap Date: Wed, 5 Oct 2022 21:25:59 +0530 Subject: [PATCH 11/11] rustfmt --- codec/src/field.rs | 24 ++++++----- codec/src/transaction.rs | 63 +++++++++++++++++++---------- codec/src/types.rs | 28 +++++++------ codec/tests/transaction_decoding.rs | 24 ++++++++--- 4 files changed, 90 insertions(+), 49 deletions(-) diff --git a/codec/src/field.rs b/codec/src/field.rs index 7aadff0..f16ad1b 100644 --- a/codec/src/field.rs +++ b/codec/src/field.rs @@ -5,8 +5,10 @@ use xrpl_codec_utils::Field; use crate::{ traits::{BinarySerialize, CodecField}, - types::{AccountIdType, AmountType, BlobType, UInt16Type, UInt32Type, ACCOUNT_ID_TYPE_CODE, - STArrayType, SignerEntryType}, + types::{ + AccountIdType, AmountType, BlobType, STArrayType, SignerEntryType, UInt16Type, UInt32Type, + ACCOUNT_ID_TYPE_CODE, + }, Vec, }; @@ -194,8 +196,10 @@ mod tests { } #[test] fn serialize_signer_entry() { - let signer_entry = SignerEntry(SignerEntryType(Account(AccountIdType([1_u8; 20])), - SignerWeight(UInt16Type(1_u16)))); + let signer_entry = SignerEntry(SignerEntryType( + Account(AccountIdType([1_u8; 20])), + SignerWeight(UInt16Type(1_u16)), + )); let buf = signer_entry.binary_serialize(true); // construct the expected buffer manually let signer_entry_field_id: u8 = 0xEB; // Typecode(14) | FieldCode(11) = 0xEB @@ -207,20 +211,22 @@ mod tests { let mut expected_buf = Vec::::default(); expected_buf.extend_from_slice(&[signer_entry_field_id]); expected_buf.extend_from_slice(&[signer_weight_field_id]); // SignerWeight comes first in the canonical order - expected_buf.extend_from_slice( &1_u16.to_be_bytes()); + expected_buf.extend_from_slice(&1_u16.to_be_bytes()); expected_buf.extend_from_slice(&[account_field_id]); expected_buf.extend_from_slice(&[account_field_vl]); - expected_buf.extend_from_slice( &[1_u8; 20]); + expected_buf.extend_from_slice(&[1_u8; 20]); expected_buf.extend_from_slice(&[st_object_end]); assert_eq!(buf, expected_buf); } #[test] fn serialize_signer_entries() { - let mut signer_entries_vec = Vec::::default(); + let mut signer_entries_vec = Vec::::default(); for i in 1..=2 { - signer_entries_vec.push(SignerEntry(SignerEntryType(Account(AccountIdType([i as u8; 20])), - SignerWeight(UInt16Type(i as u16))))); + signer_entries_vec.push(SignerEntry(SignerEntryType( + Account(AccountIdType([i as u8; 20])), + SignerWeight(UInt16Type(i as u16)), + ))); } let signer_entries = SignerEntries(STArrayType(signer_entries_vec)); diff --git a/codec/src/transaction.rs b/codec/src/transaction.rs index c84e2ea..8ff7454 100644 --- a/codec/src/transaction.rs +++ b/codec/src/transaction.rs @@ -4,10 +4,11 @@ use xrpl_codec_utils::Transaction; use crate::{ field::*, traits::{BinarySerialize, CodecField, CodecToFields}, - types::{AccountIdType, AmountType, BlobType, UInt32Type}, + types::{ + AccountIdType, AmountType, BlobType, STArrayType, SignerEntryType, UInt16Type, UInt32Type, + }, Vec, }; -use crate::types::{SignerEntryType, STArrayType, UInt16Type}; /* Tx Common Fields @@ -161,11 +162,17 @@ impl SignerListSet { // https://xrpl.org/transaction-common-fields.html#global-flags flags: Flags(UInt32Type(0x8000_0000_u32)), signer_quorum: SignerQuorum(UInt32Type(signer_quorum)), - signer_entries: SignerEntries(STArrayType(signer_entries.into_iter() - .map(|(account, weight)| { - SignerEntry(SignerEntryType( Account(AccountIdType(account)), - SignerWeight(UInt16Type(weight)))) - }).collect())), + signer_entries: SignerEntries(STArrayType( + signer_entries + .into_iter() + .map(|(account, weight)| { + SignerEntry(SignerEntryType( + Account(AccountIdType(account)), + SignerWeight(UInt16Type(weight)), + )) + }) + .collect(), + )), signing_pub_key: signing_pub_key .map(|pk| SigningPubKey(BlobType(pk.to_vec()))) .unwrap_or_default(), @@ -180,10 +187,12 @@ impl SignerListSet { #[cfg(test)] mod tests { - use alloc::vec::Vec; - use crate::field::{Account, SignerEntry, SignerWeight}; - use crate::types::{AccountIdType, SignerEntryType, UInt16Type}; use super::*; + use crate::{ + field::{Account, SignerEntry, SignerWeight}, + types::{AccountIdType, SignerEntryType, UInt16Type}, + }; + use alloc::vec::Vec; #[test] #[allow(non_snake_case)] @@ -222,12 +231,11 @@ mod tests { let account = [1_u8; 20]; let fee = 1_000; // 1000 drops let signing_pub_key = [1_u8; 33]; - let signer_quorum = 3_u32; + let signer_quorum = 3_u32; let mut signer_entries = Vec::<([u8; 20], u16)>::default(); signer_entries.push(([1_u8; 20], 1_u16)); signer_entries.push(([2_u8; 20], 2_u16)); - let signer_list_set = SignerListSet::new( account, fee, @@ -242,7 +250,7 @@ mod tests { assert!( f1.type_code() < f2.type_code() || f1.type_code() == f2.type_code() - && f1.field_code() <= f2.field_code() + && f1.field_code() <= f2.field_code() ); } _ => continue, @@ -255,7 +263,7 @@ mod tests { let account = [1_u8; 20]; let fee = 1_000; // 1000 drops let signing_pub_key = [1_u8; 33]; - let signer_quorum = 3_u32; + let signer_quorum = 3_u32; let mut signer_entries = Vec::<([u8; 20], u16)>::default(); signer_entries.push(([1_u8; 20], 1_u16)); signer_entries.push(([2_u8; 20], 2_u16)); @@ -271,19 +279,30 @@ mod tests { let buf = signer_list_set.binary_serialize(true); // Construct the expected buf manually let mut expected_buf = Vec::::default(); - expected_buf.extend_from_slice(&TransactionType(UInt16Type(TransactionTypeCode::SignerListSet.code())).binary_serialize(true)); // TransactionType + expected_buf.extend_from_slice( + &TransactionType(UInt16Type(TransactionTypeCode::SignerListSet.code())) + .binary_serialize(true), + ); // TransactionType expected_buf.extend_from_slice(&Flags(UInt32Type(0x8000_0000_u32)).binary_serialize(true)); // Flags - expected_buf.extend_from_slice(&SignerQuorum(UInt32Type(signer_quorum)).binary_serialize(true)); // SignerQuorum + expected_buf + .extend_from_slice(&SignerQuorum(UInt32Type(signer_quorum)).binary_serialize(true)); // SignerQuorum expected_buf.extend_from_slice(&Fee(AmountType(fee)).binary_serialize(true)); // Fee - expected_buf.extend_from_slice(&SigningPubKey(BlobType(signing_pub_key.to_vec())).binary_serialize(true)); // SigningPubKey + expected_buf.extend_from_slice( + &SigningPubKey(BlobType(signing_pub_key.to_vec())).binary_serialize(true), + ); // SigningPubKey expected_buf.extend_from_slice(&TxnSignature::default().binary_serialize(true)); // TxnSignature expected_buf.extend_from_slice(&Account(AccountIdType(account)).binary_serialize(true)); // Account - let signer_entries = signer_entries.into_iter() + let signer_entries = signer_entries + .into_iter() .map(|(account, weight)| { - SignerEntry(SignerEntryType( Account(AccountIdType(account)), - SignerWeight(UInt16Type(weight)))) - }).collect(); - expected_buf.extend_from_slice(&SignerEntries(STArrayType(signer_entries)).binary_serialize(true)); // SignerEntries + SignerEntry(SignerEntryType( + Account(AccountIdType(account)), + SignerWeight(UInt16Type(weight)), + )) + }) + .collect(); + expected_buf + .extend_from_slice(&SignerEntries(STArrayType(signer_entries)).binary_serialize(true)); // SignerEntries assert_eq!(buf, expected_buf); } diff --git a/codec/src/types.rs b/codec/src/types.rs index 96c3e18..f500356 100644 --- a/codec/src/types.rs +++ b/codec/src/types.rs @@ -1,10 +1,10 @@ //! XRPL codec primitive types use crate::{ - traits::{ BinarySerialize}, + field::{Account, SignerWeight}, + traits::BinarySerialize, Vec, }; -use crate::field::{Account, SignerWeight}; pub const ACCOUNT_ID_TYPE_CODE: u16 = 8; @@ -115,26 +115,28 @@ impl BinarySerialize for STArrayType { #[cfg(test)] mod tests { use super::*; - use crate::field::{SignerEntry, SignerWeight, Account}; + use crate::field::{Account, SignerEntry, SignerWeight}; #[test] #[allow(non_snake_case)] fn test_SignerEntryType() { - let signer_entry_type = SignerEntryType(Account(AccountIdType([1_u8; 20])), - SignerWeight(UInt16Type(1_u16))); + let signer_entry_type = SignerEntryType( + Account(AccountIdType([1_u8; 20])), + SignerWeight(UInt16Type(1_u16)), + ); let buf = signer_entry_type.binary_serialize(true); // let signer_entry_field_id: u8 = 0xEB; // Typecode(14) | FieldCode(11) = 0xEB let account_field_id: u8 = 0x81; // Typecode(8) | Fieldcode(1) = 0x81(129) let signer_weight_field_id: u8 = 0x13; // Typecode(1) | Fieldcode(3) = 0x13(19) let account_field_vl: u8 = 0x14; // https://xrpl.org/serialization.html#accountid-fields let st_object_end: u8 = 0xe1; // https://xrpl.org/serialization.html#object-fields - // construct expected buffer + // construct expected buffer let mut expected_buf = Vec::::default(); expected_buf.extend_from_slice(&[signer_weight_field_id]); // SignerWeight comes first in the canonical order - expected_buf.extend_from_slice( &1_u16.to_be_bytes()); + expected_buf.extend_from_slice(&1_u16.to_be_bytes()); expected_buf.extend_from_slice(&[account_field_id]); expected_buf.extend_from_slice(&[account_field_vl]); - expected_buf.extend_from_slice( &[1_u8; 20]); + expected_buf.extend_from_slice(&[1_u8; 20]); expected_buf.extend_from_slice(&[st_object_end]); assert_eq!(buf, expected_buf); @@ -143,10 +145,12 @@ mod tests { #[allow(non_snake_case)] fn test_STArrayType() { // use SignerEntry - let mut signer_entries = Vec::::default(); + let mut signer_entries = Vec::::default(); for i in 1..=2 { - signer_entries.push(SignerEntry(SignerEntryType(Account(AccountIdType([i as u8; 20])), - SignerWeight(UInt16Type(i as u16))))); + signer_entries.push(SignerEntry(SignerEntryType( + Account(AccountIdType([i as u8; 20])), + SignerWeight(UInt16Type(i as u16)), + ))); } let st_array_type = STArrayType(signer_entries); @@ -172,4 +176,4 @@ mod tests { assert_eq!(buf, expected_buf); } -} \ No newline at end of file +} diff --git a/codec/tests/transaction_decoding.rs b/codec/tests/transaction_decoding.rs index 60a4786..3483068 100644 --- a/codec/tests/transaction_decoding.rs +++ b/codec/tests/transaction_decoding.rs @@ -198,7 +198,7 @@ fn decode_SignerListSet_tx() { let account = [1_u8; 20]; let fee = 1_000; // 1000 drops let signing_pub_key = [1_u8; 33]; - let signer_quorum = 3_u32; + let signer_quorum = 3_u32; let mut signer_entries = Vec::<([u8; 20], u16)>::default(); signer_entries.push(([1_u8; 20], 1_u16)); signer_entries.push(([2_u8; 20], 2_u16)); @@ -236,7 +236,10 @@ fn decode_SignerListSet_tx() { ] }"; - assert_decodes(encoded_no_signature.as_slice(), expected_signer_list_set_json); + assert_decodes( + encoded_no_signature.as_slice(), + expected_signer_list_set_json, + ); // with signature signer_list_set.attach_signature([7_u8; 65]); let expected_signer_list_set_json = r"{ @@ -263,7 +266,10 @@ fn decode_SignerListSet_tx() { ] }"; let encoded_with_signature = signer_list_set.binary_serialize(false); - assert_decodes(encoded_with_signature.as_slice(), expected_signer_list_set_json); + assert_decodes( + encoded_with_signature.as_slice(), + expected_signer_list_set_json, + ); } #[test] @@ -272,7 +278,7 @@ fn decode_SignerListSet_tx_empty_signer_entries() { let account = [1_u8; 20]; let fee = 1_000; // 1000 drops let signing_pub_key = [1_u8; 33]; - let signer_quorum = 3_u32; + let signer_quorum = 3_u32; // let mut signer_entries = Vec::<([u8; 20], u16)>::default(); // signer_entries.push(([1_u8; 20], 1_u16)); // signer_entries.push(([2_u8; 20], 2_u16)); @@ -297,7 +303,10 @@ fn decode_SignerListSet_tx_empty_signer_entries() { SignerEntries: [] }"; - assert_decodes(encoded_no_signature.as_slice(), expected_signer_list_set_json); + assert_decodes( + encoded_no_signature.as_slice(), + expected_signer_list_set_json, + ); // with signature signer_list_set.attach_signature([7_u8; 65]); let expected_signer_list_set_json = r"{ @@ -311,5 +320,8 @@ fn decode_SignerListSet_tx_empty_signer_entries() { SignerEntries: [] }"; let encoded_with_signature = signer_list_set.binary_serialize(false); - assert_decodes(encoded_with_signature.as_slice(), expected_signer_list_set_json); + assert_decodes( + encoded_with_signature.as_slice(), + expected_signer_list_set_json, + ); }