fuel_core_chain_config/config/
contract.rs

1use crate::serialization::HexIfHumanReadable;
2use fuel_core_types::{
3    fuel_tx::{
4        AssetId,
5        Contract,
6        ContractId,
7        StorageSlot,
8        TxPointer,
9        UtxoId,
10    },
11    fuel_types::{
12        BlockHeight,
13        Bytes32,
14        Salt,
15    },
16};
17use itertools::Itertools;
18use serde::{
19    Deserialize,
20    Serialize,
21};
22use serde_with::serde_as;
23
24#[serde_as]
25#[derive(Default, Clone, Debug, Deserialize, Serialize, Eq, PartialEq)]
26pub struct ContractConfig {
27    pub contract_id: ContractId,
28    #[serde_as(as = "HexIfHumanReadable")]
29    pub code: Vec<u8>,
30    pub tx_id: Bytes32,
31    pub output_index: u16,
32    /// TxPointer: auto-generated if None
33    /// used if contract is forked from another chain to preserve id & tx_pointer
34    /// The block height that the contract was last used in
35    pub tx_pointer_block_height: BlockHeight,
36    /// TxPointer: auto-generated if None
37    /// used if contract is forked from another chain to preserve id & tx_pointer
38    /// The index of the originating tx within `tx_pointer_block_height`
39    pub tx_pointer_tx_idx: u16,
40    pub states: Vec<ContractStateConfig>,
41    pub balances: Vec<ContractBalanceConfig>,
42}
43
44#[serde_as]
45#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq, PartialOrd, Ord)]
46pub struct ContractStateConfig {
47    pub key: Bytes32,
48    #[serde_as(as = "HexIfHumanReadable")]
49    pub value: Vec<u8>,
50}
51
52impl TryFrom<ContractStateConfig> for StorageSlot {
53    type Error = anyhow::Error;
54
55    fn try_from(value: ContractStateConfig) -> Result<Self, Self::Error> {
56        let key = value.key;
57        let value = Bytes32::try_from(value.value.as_slice())?;
58        Ok(Self::new(key, value))
59    }
60}
61
62#[cfg(feature = "test-helpers")]
63impl crate::Randomize for ContractStateConfig {
64    fn randomize(mut rng: impl ::rand::Rng) -> Self {
65        Self {
66            key: crate::Randomize::randomize(&mut rng),
67            value: Bytes32::randomize(&mut rng).to_vec(),
68        }
69    }
70}
71
72#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)]
73pub struct ContractBalanceConfig {
74    pub asset_id: AssetId,
75    pub amount: u64,
76}
77
78#[cfg(feature = "test-helpers")]
79impl crate::Randomize for ContractBalanceConfig {
80    fn randomize(mut rng: impl ::rand::Rng) -> Self {
81        Self {
82            asset_id: crate::Randomize::randomize(&mut rng),
83            amount: crate::Randomize::randomize(&mut rng),
84        }
85    }
86}
87
88impl ContractConfig {
89    pub fn utxo_id(&self) -> UtxoId {
90        UtxoId::new(self.tx_id, self.output_index)
91    }
92
93    pub fn tx_pointer(&self) -> TxPointer {
94        TxPointer::new(self.tx_pointer_block_height, self.tx_pointer_tx_idx)
95    }
96}
97
98#[cfg(feature = "test-helpers")]
99impl crate::Randomize for ContractConfig {
100    fn randomize(mut rng: impl ::rand::Rng) -> Self {
101        let code = Bytes32::randomize(&mut rng).to_vec();
102        let states = vec![ContractStateConfig {
103            key: Bytes32::randomize(&mut rng),
104            value: Bytes32::randomize(&mut rng).to_vec(),
105        }];
106
107        let contract = Contract::from(code.clone());
108        let state_root = {
109            let states = states
110                .iter()
111                .cloned()
112                .map(|state| StorageSlot::try_from(state).expect("32 bytes"))
113                .collect_vec();
114            Contract::initial_state_root(states.iter())
115        };
116        let salt = Salt::zeroed();
117        let contract_id = contract.id(&salt, &contract.root(), &state_root);
118
119        Self {
120            contract_id,
121            code,
122            tx_id: crate::Randomize::randomize(&mut rng),
123            output_index: rng.gen(),
124            tx_pointer_block_height: crate::Randomize::randomize(&mut rng),
125            tx_pointer_tx_idx: rng.gen(),
126            states,
127            balances: vec![ContractBalanceConfig {
128                asset_id: crate::Randomize::randomize(&mut rng),
129                amount: rng.gen(),
130            }],
131        }
132    }
133}
134
135impl ContractConfig {
136    pub fn update_contract_id(&mut self, salt: Salt) {
137        let slots: Vec<_> = self
138            .states
139            .iter()
140            .cloned()
141            .map(StorageSlot::try_from)
142            .try_collect()
143            .unwrap();
144        let state_root = Contract::initial_state_root(slots.iter());
145
146        let contract = Contract::from(self.code.clone());
147        let root = contract.root();
148        let contract_id = contract.id(&salt, &root, &state_root);
149        self.contract_id = contract_id;
150    }
151}