Skip to main content

thruput_xdr/
contract.rs

1// -*-Rust-*-
2// Generated Code: DO NOT CHECK IN
3
4// Generated from xdrc commit: 6ab835b07c234abb4b0b50b61d687904727a4f32
5
6#![allow(non_camel_case_types)]
7#![allow(non_snake_case)]
8#![allow(non_upper_case_globals)]
9#![allow(unused_imports)]
10#![allow(dead_code)]
11#![allow(unused_variables)]
12#![allow(clippy::unnecessary_cast)]
13
14use crate::*;
15use core::option::Option;
16use core::ops::{Deref, DerefMut};
17
18#[cfg(feature = "std")]
19use std::io::{Read, Write};
20#[cfg(feature = "xdrs")]
21use xdrs::*;
22
23
24#[cfg(feature = "serde")]
25use ::serde::{{Serialize, Deserialize}};
26
27
28
29//==============================================================================
30// Contracts and Contract Deployment
31//
32// This module defines the contract abstraction in Thruput. Contracts are
33// code that can be deployed to addresses and invoked to execute logic.
34//
35// Key concepts:
36// - Contracts can be executable blobs, native precompiled code, or test mocks
37// - Contract addresses are deterministically derived from deployment parameters
38// - Contract methods are identified by 8-byte entrypoint IDs
39// - Entrypoint IDs are derived from interface names and versions
40//==============================================================================
41
42//------------------------------------------------------------------------------
43// Contract Types and Code
44//------------------------------------------------------------------------------
45
46/// The largest contract code blob a chain admits when its configuration does
47/// not state `kConfigParamMaxContractSizeBytes`. Includes the artifact header,
48/// code, and initial memory.
49pub const kDefaultMaxContractSizeBytes : u32 = 524288;
50
51/// An opaque blob of executable code.
52///
53/// This is the raw binary that will be executed as an RV32 contract.
54///
55/// Unbounded on the wire: the size a chain admits is a configuration
56/// parameter (`kConfigParamMaxContractSizeBytes`), enforced where a
57/// transaction attaches a contract rather than where one is decoded.
58#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
59#[cfg_attr(feature = "xdrs", derive(ReadXDR, WriteXDR, ConstXDRSize))]
60#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
61#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
62#[repr(C)]
63pub struct ContractBlob {
64    pub data: BytesM,
65}
66
67/// The execution environment for a contract.
68///
69/// Discriminant 0 is retired. It selected an earlier contract runtime, which
70/// was removed once RV32 became the only deployable execution environment.
71/// Do not reuse the value: old encodings that carry it must fail to parse
72/// rather than silently decode as a live contract type.
73#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
74#[cfg_attr(feature = "serde", serde(transparent))]
75#[cfg_attr(feature = "xdrs", derive(ReadXDR, WriteXDR, ConstXDRSize))]
76#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
77#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
78#[derive(Copy)]
79#[repr(transparent)]
80pub struct ContractType(pub i32);
81
82impl ContractType {
83    /// Precompiled native contract implemented natively by the node.
84    ///
85    /// Used for system contracts like the native token.
86    /// Cheaper to invoke than a deployed RV32 contract, but users cannot
87    /// deploy new ones.
88    pub const kNative: Self = Self(1);
89
90    /// Mock contract for local testing.
91    ///
92    /// Never deployed on-chain; exists only in the test harness.
93    pub const kMockTest: Self = Self(2);
94
95    /// RiscV contract executed in the RV32 VM.
96    ///
97    /// This is the standard contract type for user-deployed contracts.
98    pub const kRv32: Self = Self(3);
99}
100impl From<i32> for ContractType {
101    fn from(v: i32) -> Self {
102        Self(v)
103    }
104}
105#[cfg(feature = "std")]
106impl core::fmt::Display for ContractType {
107    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
108        match self.0 {
109            x if x == Self::kNative.0 => {
110                write!(f, "ContractType::kNative")
111            },
112            x if x == Self::kMockTest.0 => {
113                write!(f, "ContractType::kMockTest")
114            },
115            x if x == Self::kRv32.0 => {
116                write!(f, "ContractType::kRv32")
117            },
118            _ => {
119                write!(f, "ContractType({})", self.0)
120            }
121        }
122    }
123}
124
125
126/// A contract that can be deployed to an address and invoked.
127///
128/// Contracts are the fundamental unit of code execution in Thruput.
129/// Once deployed to a `ContractAddress`, they can be invoked by transactions
130/// to execute their methods (entrypoints).
131///
132/// The three contract types serve different purposes:
133/// - `kRv32`: User-deployed contracts (most common)
134/// - `kNative`: System contracts with privileged access
135/// - `kMockTest`: Test contracts for local development
136#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
137#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
138#[cfg_attr(feature = "xdrs", derive(ReadXDR, WriteXDR, ConstXDRSize))]
139#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
140#[repr(i32)]
141#[non_exhaustive]
142pub enum Contract {
143    /// Identifier for which native contract this is.
144    ///
145    /// Native contracts are hard-coded in the runtime.
146    // case kNative:
147    //   HogexecPrecompiledNativeContracts native_contract_id;
148    kNative { native_contract_id: HogexecPrecompiledNativeContracts } = ContractType::kNative.0 as i32,
149    /// Identifier for the mock contract in the test harness.
150    // case kMockTest:
151    //   i32 mock_contract_id;
152    kMockTest { mock_contract_id: i32 } = ContractType::kMockTest.0 as i32,
153    // case kRv32:
154    //   ContractBlob rv32_contract;
155    kRv32 { rv32_contract: ContractBlob } = ContractType::kRv32.0 as i32,
156    
157}
158
159//------------------------------------------------------------------------------
160// Contract Deployment and Address Derivation
161//------------------------------------------------------------------------------
162
163/// Hash preimage for deriving deployed contract addresses.
164///
165/// When a contract deploys another contract, the new contract's address is
166/// deterministically computed as:
167///
168/// ```text
169/// ContractAddress = SHA256(ContractDeploymentHashPreimage)
170/// ```
171///
172/// Under XDR encoding, this struct serializes as the concatenation of its
173/// fields: `deployer_address || nonce || contract_hash`.
174///
175/// This is Thruput's analogue of Ethereum's `CREATE2` opcode, allowing
176/// deterministic address derivation. The deployer controls the nonce to
177/// create addresses at will.
178///
179/// # Example
180///
181/// ```text
182/// Contract A address:  0x1234...
183/// Contract B hash:     0xabcd...   (= SHA256(XDR(Contract B)))
184/// Deployment nonce:    0x5678...
185/// Result: SHA256(0x1234... || 0x5678... || 0xabcd...) = Contract B address
186/// ```
187#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
188#[cfg_attr(feature = "xdrs", derive(ReadXDR, WriteXDR, ConstXDRSize))]
189#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
190#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
191#[repr(C)]
192pub struct ContractDeploymentHashPreimage {
193    /// The address of the contract performing the deployment.
194    pub deployer_address: ContractAddress,
195    /// Arbitrary 32-byte value chosen by the deployer.
196    ///
197    /// Allows creating multiple instances of the same contract code
198    /// at different addresses.
199    pub nonce: SHA256Hash,
200    /// SHA-256 hash of the XDR-encoded `Contract` being deployed.
201    ///
202    /// This hashes the entire union, not the bare code blob:
203    ///
204    /// ```text
205    /// contract_hash = SHA256(XDR(Contract))
206    /// ```
207    ///
208    /// The encoding covers the 4-byte `ContractType` discriminant followed by
209    /// the selected arm, so identical code deployed under a different contract
210    /// type yields a different hash. For `kRv32` the arm is a `ContractBlob`,
211    /// which is itself a 4-byte length prefix followed by the code padded to a
212    /// 4-byte boundary -- hashing the raw code alone does not reproduce this
213    /// value.
214    ///
215    /// Native and mock contracts are hashed the same way, over a union whose
216    /// arm holds a contract identifier instead of a blob. They do not use
217    /// separately predefined hash constants.
218    pub contract_hash: SHA256Hash,
219}
220
221//------------------------------------------------------------------------------
222// Contract Interfaces and Entrypoint Derivation
223//------------------------------------------------------------------------------
224
225/// 8-byte identifier for a contract method (entrypoint).
226///
227/// Entrypoint IDs uniquely identify which method to invoke on a contract.
228/// A contract may use any 8 bytes; the protocol attaches no meaning to them.
229/// By default, the SDK derives them from the interface name, the major
230/// version of the interface, and the method name:
231///
232/// ```text
233/// SHA256(name || "::" || major || "::" || method)[0..8]
234/// ```
235///
236/// `major` is the semver compatibility prefix of the interface version: the
237/// leading components up to and including the first nonzero one (`"1"` for
238/// `"1.4.2"`, `"0.2"` for `"0.2.7"`, `"0.0.3"` for `"0.0.3"`). Versions that
239/// share it therefore share entrypoint IDs, and the `"::"` separators keep
240/// distinct (name, major, method) triples from concatenating to the same
241/// preimage.
242///
243/// # Example
244///
245/// For an `"ERC20"` interface at version `"1.0.0"`, `transfer` is
246/// `SHA256("ERC20::1::transfer")[0..8]`.
247///
248/// Interface IDs use the same prefix under a domain tag,
249/// `SHA256("thruput-interface::" || name || "::" || major)[0..8]`, so they
250/// never coincide with an entrypoint ID.
251// 
252#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
253#[cfg_attr(feature = "xdrs", derive(ReadXDR, WriteXDR, ConstXDRSize))]
254#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
255#[derive(Default, Copy)]
256#[repr(transparent)]
257#[cfg_attr(feature = "serde", serde(transparent))]
258pub struct ContractEntrypointID {
259    #[cfg_attr(feature = "serde", serde(with = "xdr_common::serde_hex"))]
260    inner: [u8; 8 as usize],
261}
262impl From<[u8; 8 as usize]> for ContractEntrypointID {
263    fn from(_inner: [u8; 8 as usize]) -> Self {
264        Self { inner: _inner }
265    }
266}
267impl ContractEntrypointID {
268    pub fn into_inner(self) -> [u8; 8 as usize] {
269        self.inner
270    }
271    pub const fn new(_inner: [u8; 8 as usize]) -> Self {
272        Self { inner: _inner }
273    }
274}
275
276impl Deref for ContractEntrypointID {
277    type Target = [u8; 8 as usize];
278
279    fn deref(&self) -> &Self::Target {
280        &self.inner
281    }
282}
283impl DerefMut for ContractEntrypointID {
284    fn deref_mut(&mut self) -> &mut Self::Target {
285        &mut self.inner
286    }
287}
288impl AsRef<[u8]> for ContractEntrypointID {
289    fn as_ref(&self) -> &[u8] {
290        self.deref().as_slice()
291    }
292}
293impl<'a> From<&'a [u8; 8]> for &'a ContractEntrypointID {
294    fn from(arr: &[u8; 8]) -> Self {
295        let ptr = arr as *const [u8; 8] as *const ContractEntrypointID;
296        unsafe { &*ptr }
297    }
298}
299#[cfg(feature = "xdrs")]
300impl<'r: 'a, 'a> ReadXDR<'r> for &'a ContractEntrypointID {
301  fn read_xdr<R: xdrs::Reader<'r>>(r: &mut R) -> xdrs::ReadResult<Self> {
302      let arr: &[u8; 8] = xdrs::read_xdr(r)?;
303      let val = Self::from(arr);
304      Ok(val)
305  }
306}
307
308#[cfg(feature = "schema")]
309impl schemars::JsonSchema for ContractEntrypointID {
310    fn schema_name() -> ::std::borrow::Cow<'static, str> {
311        "ContractEntrypointID".into()
312    }
313    fn json_schema(_gen: &mut schemars::SchemaGenerator) -> schemars::Schema {
314        schemars::json_schema!({
315            "type": "string",
316            "contentEncoding": "hex",
317            "contentMediaType": "application/binary",
318            "minLength": 16,
319            "maxLength": 16
320        })
321    }
322}
323
324
325
326//------------------------------------------------------------------------------
327// Deployed Contract Metadata
328//------------------------------------------------------------------------------
329
330/// Hash and metadata for a contract deployed at an address.
331///
332/// This allows the system to locate and instantiate the contract code
333/// without loading the full contract from storage.
334#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
335#[cfg_attr(feature = "xdrs", derive(ReadXDR, WriteXDR, ConstXDRSize))]
336#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
337#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
338#[repr(C)]
339pub struct DeployedContractHash {
340    /// SHA-256 hash of the XDR-encoded `Contract` deployed at this address.
341    ///
342    /// Computed as `SHA256(XDR(Contract))`, identically to the `contract_hash`
343    /// field of `ContractDeploymentHashPreimage`.
344    pub hash: SHA256Hash,
345    /// Size of the contract code in bytes.
346    ///
347    /// Always 0 for `kNative` and `kMockTest`, which carry no deployable blob.
348    ///
349    /// Optimization: allows computing and updating storage costs without
350    /// loading the full contract from storage.
351    pub contract_size: u32,
352    /// The type of contract: RV32, native, or mock.
353    ///
354    /// Optimization: allows the executor to determine which runtime to
355    /// instantiate without a database lookup. When the contract module is
356    /// already cached, this avoids loading the contract bytecode entirely.
357    pub contract_type: ContractType,
358}
359
360
361
362//
363// XDR internals below this point
364//
365
366impl Contract {
367    #[allow(clippy::match_single_binding)]
368    pub fn contract_type(&self) -> ContractType {
369        match self {
370            
371            _ => (unsafe { *(self as *const Self as *const i32) }).into(),
372        }
373    }
374}
375
376