fuel_block_executor/refs/
contract.rs1use fuel_chain_config::GenesisCommitment;
2use fuel_core_interfaces::{
3 common::{
4 fuel_storage::{
5 Mappable,
6 MerkleRootStorage,
7 StorageAsMut,
8 StorageAsRef,
9 StorageInspect,
10 },
11 fuel_tx::{
12 Bytes32,
13 ContractId,
14 },
15 prelude::{
16 Hasher,
17 MerkleRoot,
18 },
19 },
20 db::{
21 ContractsAssets,
22 ContractsLatestUtxo,
23 ContractsState,
24 },
25 executor::Error,
26 not_found,
27};
28use std::{
29 borrow::Cow,
30 error::Error as StdError,
31};
32
33pub struct ContractRef<Database> {
35 database: Database,
36 contract_id: ContractId,
37}
38
39impl<Database> ContractRef<Database> {
40 pub fn new(database: Database, contract_id: ContractId) -> Self {
41 Self {
42 database,
43 contract_id,
44 }
45 }
46
47 pub fn contract_id(&self) -> &ContractId {
48 &self.contract_id
49 }
50
51 pub fn database(&self) -> &Database {
52 &self.database
53 }
54
55 pub fn database_mut(&mut self) -> &mut Database {
56 &mut self.database
57 }
58}
59
60impl<Database> ContractRef<Database>
61where
62 Database: StorageInspect<ContractsLatestUtxo>,
63 Error: From<Database::Error>,
64{
65 pub fn utxo(
66 &self,
67 ) -> Result<
68 Option<Cow<'_, <ContractsLatestUtxo as Mappable>::GetValue>>,
69 Database::Error,
70 > {
71 self.database.storage().get(&self.contract_id)
72 }
73}
74
75impl<Database> ContractRef<Database>
76where
77 Database: StorageInspect<ContractsLatestUtxo>,
78 Error: From<Database::Error>,
79{
80 pub fn validated_utxo(
81 &self,
82 utxo_validation: bool,
83 ) -> Result<<ContractsLatestUtxo as Mappable>::GetValue, Error> {
84 let maybe_utxo_id = self.utxo()?.map(|utxo| utxo.into_owned());
85 let expected_utxo_id = if utxo_validation {
86 maybe_utxo_id.ok_or(Error::ContractUtxoMissing(self.contract_id))?
87 } else {
88 maybe_utxo_id.unwrap_or_default()
89 };
90 Result::<_, Error>::Ok(expected_utxo_id)
91 }
92}
93
94impl<Database> ContractRef<Database>
95where
96 for<'b> Database: MerkleRootStorage<ContractId, ContractsAssets<'b>>,
97{
98 pub fn balance_root(
99 &mut self,
100 ) -> Result<Bytes32, <Database as StorageInspect<ContractsAssets<'_>>>::Error> {
101 self.database.root(&self.contract_id).map(Into::into)
102 }
103}
104
105impl<Database> ContractRef<Database>
106where
107 for<'b> Database: MerkleRootStorage<ContractId, ContractsState<'b>>,
108{
109 pub fn state_root(
110 &mut self,
111 ) -> Result<Bytes32, <Database as StorageInspect<ContractsState<'_>>>::Error> {
112 self.database.root(&self.contract_id).map(Into::into)
113 }
114}
115
116pub trait ContractStorageTrait<'a>:
117 StorageInspect<ContractsLatestUtxo, Error = Self::InnerError>
118 + MerkleRootStorage<ContractId, ContractsState<'a>, Error = Self::InnerError>
119 + MerkleRootStorage<ContractId, ContractsAssets<'a>, Error = Self::InnerError>
120{
121 type InnerError: StdError + Send + Sync + 'static;
122}
123
124impl<'a, Database> GenesisCommitment for ContractRef<&'a mut Database>
125where
126 for<'b> Database: ContractStorageTrait<'a>,
127{
128 fn root(&mut self) -> anyhow::Result<MerkleRoot> {
129 let contract_id = *self.contract_id();
130 let utxo = self
131 .database()
132 .storage::<ContractsLatestUtxo>()
133 .get(&contract_id)?
134 .ok_or(not_found!(ContractsLatestUtxo))?
135 .into_owned();
136
137 let state_root = self
138 .database_mut()
139 .storage::<ContractsState>()
140 .root(&contract_id)?;
141
142 let balance_root = self
143 .database_mut()
144 .storage::<ContractsAssets>()
145 .root(&contract_id)?;
146
147 let contract_hash = *Hasher::default()
148 .chain(contract_id.as_ref())
150 .chain(utxo.tx_id().as_ref())
151 .chain([utxo.output_index()])
152 .chain(state_root.as_slice())
153 .chain(balance_root.as_slice())
154 .finalize();
155
156 Ok(contract_hash)
157 }
158}