edb_engine/analysis/
contract.rs

1// EDB - Ethereum Debugger
2// Copyright (C) 2024 Zhuo Zhang and Wuqi Zhang
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU Affero General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU Affero General Public License for more details.
13//
14// You should have received a copy of the GNU Affero General Public License
15// along with this program. If not, see <https://www.gnu.org/licenses/>.
16
17use std::sync::Arc;
18
19use foundry_compilers::artifacts::ContractDefinition;
20use once_cell::sync::OnceCell;
21use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
22use serde::{Deserialize, Serialize};
23
24use crate::analysis::macros::universal_id;
25
26universal_id! {
27    /// A Universal Contract Identifier (UCID) is a unique identifier for a contract.
28    UCID => 0
29}
30
31/// A reference-counted pointer to a Contract for efficient sharing across multiple contexts.
32#[derive(Debug, Clone)]
33pub struct ContractRef {
34    inner: Arc<RwLock<Contract>>,
35    /* cached readonly fields*/
36    name: OnceCell<String>,
37    definition: OnceCell<ContractDefinition>,
38}
39
40impl From<Contract> for ContractRef {
41    fn from(contract: Contract) -> Self {
42        Self::new(contract)
43    }
44}
45
46impl ContractRef {
47    /// Creates a new ContractRef from a Contract.
48    pub fn new(inner: Contract) -> Self {
49        Self {
50            inner: Arc::new(RwLock::new(inner)),
51            name: OnceCell::new(),
52            definition: OnceCell::new(),
53        }
54    }
55}
56
57impl ContractRef {
58    /// Returns the name of this contract.
59    pub fn name(&self) -> &String {
60        self.name.get_or_init(|| self.inner.read().definition.name.to_string())
61    }
62
63    /// Returns the definition of this contract.
64    pub fn definition(&self) -> &ContractDefinition {
65        self.definition.get_or_init(|| self.inner.read().definition.clone())
66    }
67}
68
69#[allow(unused)]
70impl ContractRef {
71    pub(crate) fn read(&self) -> RwLockReadGuard<'_, Contract> {
72        self.inner.read()
73    }
74
75    pub(crate) fn write(&self) -> RwLockWriteGuard<'_, Contract> {
76        self.inner.write()
77    }
78}
79
80impl Serialize for ContractRef {
81    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
82    where
83        S: serde::Serializer,
84    {
85        self.inner.read().serialize(serializer)
86    }
87}
88
89impl<'de> Deserialize<'de> for ContractRef {
90    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
91    where
92        D: serde::Deserializer<'de>,
93    {
94        let contract = Contract::deserialize(deserializer)?;
95        Ok(Self::new(contract))
96    }
97}
98
99/// Represents a contract in a smart contract with its metadata and type information.
100#[derive(Debug, Clone, Serialize, Deserialize)]
101pub struct Contract {
102    /// The unique contract identifier.
103    pub ucid: UCID,
104    /// The contract definition.
105    pub definition: ContractDefinition,
106}
107
108impl Contract {
109    /// Creates a new Contract with the given definition.
110    pub fn new(definition: ContractDefinition) -> Self {
111        Self { ucid: UCID::next(), definition }
112    }
113}