fuel_core_chain_config/config/
contract.rs1use 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 pub tx_pointer_block_height: BlockHeight,
36 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}