Skip to content
This repository was archived by the owner on May 20, 2025. It is now read-only.

Commit 9bafb00

Browse files
AlexandcoatsgrtlrAlex6323
authored
fix(inx): fix ledger output rent structure logic (#759)
* Fix ledger output rent structure logic. * Use bee output rent structure impl * clipee * Clippy * Minor improvements to rent structure computation (#761) * Minor improvements to rent structure computation * Further improve (#85) * Further improve * slight refactor Co-authored-by: /alex/ <[email protected]> * Add test case * Improve test * Cleanup test Co-authored-by: Jochen Görtler <[email protected]> Co-authored-by: /alex/ <[email protected]>
1 parent ce584ac commit 9bafb00

File tree

6 files changed

+80
-52
lines changed

6 files changed

+80
-52
lines changed

src/db/collections/outputs/mod.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,6 @@ impl From<&LedgerOutput> for OutputDocument {
8181
fn from(rec: &LedgerOutput) -> Self {
8282
let address = rec.output.owning_address().copied();
8383
let is_trivial_unlock = rec.output.is_trivial_unlock();
84-
let rent_structure = rec.output.rent_structure();
8584

8685
Self {
8786
output_id: rec.output_id,
@@ -94,7 +93,7 @@ impl From<&LedgerOutput> for OutputDocument {
9493
details: OutputDetails {
9594
address,
9695
is_trivial_unlock,
97-
rent_structure,
96+
rent_structure: rec.rent_structure,
9897
},
9998
}
10099
}

src/types/ledger/output_metadata.rs

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ pub struct LedgerOutput {
4343
pub block_id: BlockId,
4444
pub booked: MilestoneIndexTimestamp,
4545
pub output: Output,
46+
pub rent_structure: RentStructureBytes,
4647
}
4748

4849
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
@@ -51,13 +52,36 @@ pub struct LedgerSpent {
5152
pub spent_metadata: SpentMetadata,
5253
}
5354

55+
#[cfg(feature = "inx")]
56+
fn compute_rent_structure(output: &bee_block_stardust::output::Output) -> RentStructureBytes {
57+
use bee_block_stardust::output::{Rent, RentStructureBuilder};
58+
59+
let rent_cost = |byte_cost, data_factor, key_factor| {
60+
output.rent_cost(
61+
&RentStructureBuilder::new()
62+
.byte_cost(byte_cost)
63+
.data_factor(data_factor)
64+
.key_factor(key_factor)
65+
.finish(),
66+
)
67+
};
68+
69+
RentStructureBytes {
70+
num_data_bytes: rent_cost(1, 1, 0),
71+
num_key_bytes: rent_cost(1, 0, 1),
72+
}
73+
}
74+
5475
#[cfg(feature = "inx")]
5576
impl TryFrom<bee_inx::LedgerOutput> for LedgerOutput {
5677
type Error = bee_inx::Error;
5778

5879
fn try_from(value: bee_inx::LedgerOutput) -> Result<Self, Self::Error> {
80+
let bee_output = value.output.inner_unverified()?;
81+
5982
Ok(Self {
60-
output: Into::into(&value.output.inner_unverified()?),
83+
rent_structure: compute_rent_structure(&bee_output),
84+
output: Into::into(&bee_output),
6185
output_id: value.output_id.into(),
6286
block_id: value.block_id.into(),
6387
booked: MilestoneIndexTimestamp {
@@ -76,8 +100,11 @@ impl crate::types::context::TryFromWithContext<bee_inx::LedgerOutput> for Ledger
76100
ctx: &bee_block_stardust::protocol::ProtocolParameters,
77101
value: bee_inx::LedgerOutput,
78102
) -> Result<Self, Self::Error> {
103+
let bee_output = value.output.inner(ctx)?;
104+
79105
Ok(Self {
80-
output: Into::into(&value.output.inner(ctx)?),
106+
rent_structure: compute_rent_structure(&bee_output),
107+
output: Into::into(&bee_output),
81108
output_id: value.output_id.into(),
82109
block_id: value.block_id.into(),
83110
booked: MilestoneIndexTimestamp {
@@ -132,10 +159,40 @@ impl crate::types::context::TryFromWithContext<bee_inx::LedgerSpent> for LedgerS
132159
}
133160

134161
/// The different number of bytes that are used for computing the rent cost.
135-
#[derive(Clone, Debug, Serialize, Deserialize)]
162+
#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
136163
pub struct RentStructureBytes {
137164
/// The number of key bytes in an output.
138165
pub num_key_bytes: u64,
139166
/// The number of data bytes in an output.
140167
pub num_data_bytes: u64,
141168
}
169+
170+
#[cfg(test)]
171+
mod test {
172+
#[cfg(all(feature = "inx", feature = "rand"))]
173+
#[test]
174+
fn test_compute_rent_structure() {
175+
use bee_block_stardust::{output::Rent, rand::output};
176+
177+
use super::compute_rent_structure;
178+
179+
let protocol_params = bee_block_stardust::protocol::protocol_parameters();
180+
181+
let outputs = [
182+
output::rand_basic_output(protocol_params.token_supply()).into(),
183+
output::rand_alias_output(protocol_params.token_supply()).into(),
184+
output::rand_foundry_output(protocol_params.token_supply()).into(),
185+
output::rand_nft_output(protocol_params.token_supply()).into(),
186+
];
187+
188+
for output in outputs {
189+
let rent = compute_rent_structure(&output);
190+
assert_eq!(
191+
(rent.num_data_bytes * protocol_params.rent_structure().v_byte_factor_data as u64
192+
+ rent.num_key_bytes * protocol_params.rent_structure().v_byte_factor_key as u64)
193+
* protocol_params.rent_structure().v_byte_cost as u64,
194+
output.rent_cost(protocol_params.rent_structure())
195+
);
196+
}
197+
}
198+
}

src/types/stardust/block/output/mod.rs

Lines changed: 1 addition & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ pub mod treasury;
1414

1515
use std::{borrow::Borrow, str::FromStr};
1616

17-
use bee_block_stardust::output::{self as bee, Rent};
17+
use bee_block_stardust::output as bee;
1818
use mongodb::bson::{doc, Bson};
1919
use serde::{Deserialize, Serialize};
2020

@@ -30,7 +30,6 @@ pub use self::{
3030
use super::Address;
3131
use crate::types::{
3232
context::{TryFromWithContext, TryIntoWithContext},
33-
ledger::RentStructureBytes,
3433
stardust::block::payload::transaction::TransactionId,
3534
};
3635

@@ -153,48 +152,6 @@ impl Output {
153152
Self::Foundry(_) => true,
154153
}
155154
}
156-
157-
pub fn rent_structure(&self) -> RentStructureBytes {
158-
// Computing the rent structure is independent of the protocol parameters, we just need this for conversion.
159-
let ctx = bee_block_stardust::protocol::protocol_parameters();
160-
match self {
161-
output @ (Self::Basic(_) | Self::Alias(_) | Self::Foundry(_) | Self::Nft(_)) => {
162-
let bee_output = bee::Output::try_from_with_context(&ctx, output.clone())
163-
.expect("`Output` has to be convertible to `bee::Output`");
164-
165-
// The following computations of `data_bytes` and `key_bytes` makec use of the fact that the byte cost
166-
// computation is a linear combination with respect to the type of the fields and their weight.
167-
168-
let num_data_bytes = {
169-
let config = bee::RentStructureBuilder::new()
170-
.byte_cost(1)
171-
.data_factor(1)
172-
.key_factor(0)
173-
.finish();
174-
bee_output.rent_cost(&config)
175-
};
176-
177-
let num_key_bytes = {
178-
let config = bee::RentStructureBuilder::new()
179-
.byte_cost(1)
180-
.data_factor(0)
181-
.key_factor(1)
182-
.finish();
183-
bee_output.rent_cost(&config)
184-
};
185-
186-
RentStructureBytes {
187-
num_data_bytes,
188-
num_key_bytes,
189-
}
190-
}
191-
// The treasury output does not have an associated byte cost.
192-
Self::Treasury(_) => RentStructureBytes {
193-
num_key_bytes: 0,
194-
num_data_bytes: 0,
195-
},
196-
}
197-
}
198155
}
199156

200157
impl<T: Borrow<bee::Output>> From<T> for Output {

tests/blocks.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ mod test_rand {
99
use chronicle::{
1010
db::collections::{BlockCollection, OutputCollection},
1111
types::{
12-
ledger::{BlockMetadata, ConflictReason, LedgerInclusionState, LedgerOutput, MilestoneIndexTimestamp},
12+
ledger::{
13+
BlockMetadata, ConflictReason, LedgerInclusionState, LedgerOutput, MilestoneIndexTimestamp,
14+
RentStructureBytes,
15+
},
1316
stardust::block::{output::OutputId, payload::TransactionEssence, Block, BlockId, Payload},
1417
},
1518
};
@@ -73,6 +76,10 @@ mod test_rand {
7376
milestone_index: 0.into(),
7477
milestone_timestamp: 12345.into(),
7578
},
79+
rent_structure: RentStructureBytes {
80+
num_key_bytes: 0,
81+
num_data_bytes: 100,
82+
},
7683
output,
7784
}))
7885
.await

tests/claiming.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ mod test_rand {
99
use chronicle::{
1010
db::collections::OutputCollection,
1111
types::{
12-
ledger::{LedgerOutput, LedgerSpent, MilestoneIndexTimestamp, SpentMetadata},
12+
ledger::{LedgerOutput, LedgerSpent, MilestoneIndexTimestamp, RentStructureBytes, SpentMetadata},
1313
stardust::block::{
1414
output::{BasicOutput, OutputAmount, OutputId},
1515
payload::TransactionId,
@@ -37,6 +37,10 @@ mod test_rand {
3737
let unspent_outputs = (1..=5)
3838
.map(|i| LedgerOutput {
3939
output_id: OutputId::rand(),
40+
rent_structure: RentStructureBytes {
41+
num_key_bytes: 0,
42+
num_data_bytes: 100,
43+
},
4044
output: rand_output_with_value(i.into()),
4145
block_id: BlockId::rand(),
4246
booked: MilestoneIndexTimestamp {

tests/outputs.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ mod test_rand {
99
use chronicle::{
1010
db::collections::{OutputCollection, OutputMetadataResult, OutputWithMetadataResult},
1111
types::{
12-
ledger::{LedgerOutput, LedgerSpent, MilestoneIndexTimestamp, SpentMetadata},
12+
ledger::{LedgerOutput, LedgerSpent, MilestoneIndexTimestamp, RentStructureBytes, SpentMetadata},
1313
stardust::block::{output::OutputId, payload::TransactionId, BlockId, Output},
1414
},
1515
};
@@ -29,6 +29,10 @@ mod test_rand {
2929
.take(100)
3030
.map(|output| LedgerOutput {
3131
output_id: OutputId::rand(),
32+
rent_structure: RentStructureBytes {
33+
num_key_bytes: 0,
34+
num_data_bytes: 100,
35+
},
3236
output,
3337
block_id: BlockId::rand(),
3438
booked: MilestoneIndexTimestamp {

0 commit comments

Comments
 (0)