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