ckb_gen_types/extension/
capacity.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
use ckb_occupied_capacity::{Capacity, Result as CapacityResult};

use crate::{packed, prelude::*};

impl packed::Script {
    /// Calculates the occupied capacity of [`Script`].
    ///
    /// Includes [`code_hash`] (32), [`hash_type`] (1) and [`args`] (calculated).
    ///
    /// [`Script`]: https://github.com/nervosnetwork/ckb/blob/v0.36.0/util/types/schemas/blockchain.mol#L30-L34
    /// [`code_hash`]: #method.code_hash
    /// [`hash_type`]: #method.hash_type
    /// [`args`]: #method.args
    pub fn occupied_capacity(&self) -> CapacityResult<Capacity> {
        Capacity::bytes(self.args().raw_data().len() + 32 + 1)
    }
}

impl packed::CellOutput {
    /// Calculates the occupied capacity of [`CellOutput`].
    ///
    /// Includes [`output_data`] (provided), [`capacity`] (8), [`lock`] (calculated) and [`type`] (calculated).
    ///
    /// [`CellOutput`]: https://github.com/nervosnetwork/ckb/blob/v0.36.0/util/types/schemas/blockchain.mol#L46-L50
    /// [`output_data`]: https://github.com/nervosnetwork/ckb/blob/v0.36.0/util/types/schemas/blockchain.mol#L63
    /// [`capacity`]: #method.capacity
    /// [`lock`]: #method.lock
    /// [`type`]: #method.type_
    pub fn occupied_capacity(&self, data_capacity: Capacity) -> CapacityResult<Capacity> {
        Capacity::bytes(8)
            .and_then(|x| x.safe_add(data_capacity))
            .and_then(|x| self.lock().occupied_capacity().and_then(|y| y.safe_add(x)))
            .and_then(|x| {
                self.type_()
                    .to_opt()
                    .as_ref()
                    .map(packed::Script::occupied_capacity)
                    .transpose()
                    .and_then(|y| y.unwrap_or_else(Capacity::zero).safe_add(x))
            })
    }

    /// Returns if the [`capacity`] in `CellOutput` is smaller than the [`occupied capacity`].
    ///
    /// [`capacity`]: #method.capacity
    /// [`occupied capacity`]: #method.occupied_capacity
    pub fn is_lack_of_capacity(&self, data_capacity: Capacity) -> CapacityResult<bool> {
        self.occupied_capacity(data_capacity)
            .map(|cap| cap > self.capacity().unpack())
    }
}

impl packed::CellOutputBuilder {
    /// Build a [`CellOutput`] and sets its [`capacity`] equal to its [`occupied capacity`] exactly.
    ///
    /// [`CellOutput`]: struct.CellOutput.html
    /// [`capacity`]: #method.capacity
    /// [`occupied capacity`]: struct.CellOutput.html#method.occupied_capacity
    pub fn build_exact_capacity(
        self,
        data_capacity: Capacity,
    ) -> CapacityResult<packed::CellOutput> {
        Capacity::bytes(8)
            .and_then(|x| x.safe_add(data_capacity))
            .and_then(|x| self.lock.occupied_capacity().and_then(|y| y.safe_add(x)))
            .and_then(|x| {
                self.type_
                    .to_opt()
                    .as_ref()
                    .map(packed::Script::occupied_capacity)
                    .transpose()
                    .and_then(|y| y.unwrap_or_else(Capacity::zero).safe_add(x))
            })
            .map(|x| self.capacity(x.pack()).build())
    }
}

impl packed::CellOutputVec {
    /// Sums the capacities of all [`CellOutput`]s in the vector.
    ///
    /// [`CellOutput`]: struct.CellOutput.html#method.occupied_capacity
    pub fn total_capacity(&self) -> CapacityResult<Capacity> {
        self.as_reader()
            .iter()
            .map(|output| {
                let cap: Capacity = output.capacity().unpack();
                cap
            })
            .try_fold(Capacity::zero(), Capacity::safe_add)
    }
}