A complete blockchain implementation featuring: - synord: Full node with GHOSTDAG consensus - explorer-web: Modern React blockchain explorer with 3D DAG visualization - CLI wallet and tools - Smart contract SDK and example contracts (DEX, NFT, token) - WASM crypto library for browser/mobile
178 lines
4.1 KiB
Rust
178 lines
4.1 KiB
Rust
//! Execution context information.
|
|
//!
|
|
//! Provides access to information about the current execution context,
|
|
//! such as the caller, block info, and transaction data.
|
|
|
|
use alloc::vec::Vec;
|
|
|
|
use crate::host;
|
|
use crate::types::{Address, Hash256};
|
|
|
|
/// Returns the address that called this contract.
|
|
///
|
|
/// For external calls, this is the transaction sender.
|
|
/// For internal calls, this is the calling contract.
|
|
pub fn caller() -> Address {
|
|
Address(host::get_caller())
|
|
}
|
|
|
|
/// Returns the contract's own address.
|
|
pub fn self_address() -> Address {
|
|
Address(host::get_address())
|
|
}
|
|
|
|
/// Returns the original transaction sender.
|
|
///
|
|
/// Unlike `caller()`, this always returns the externally owned account
|
|
/// that initiated the transaction, even in nested contract calls.
|
|
pub fn origin() -> Address {
|
|
Address(host::get_origin())
|
|
}
|
|
|
|
/// Returns the value (in sompi) sent with this call.
|
|
pub fn value() -> u64 {
|
|
host::get_value()
|
|
}
|
|
|
|
/// Returns the call data.
|
|
pub fn calldata() -> Vec<u8> {
|
|
let size = host::get_calldata_size();
|
|
if size == 0 {
|
|
return Vec::new();
|
|
}
|
|
|
|
let mut data = alloc::vec![0u8; size];
|
|
host::get_calldata(&mut data, 0);
|
|
data
|
|
}
|
|
|
|
/// Returns a slice of the call data.
|
|
pub fn calldata_slice(offset: usize, length: usize) -> Vec<u8> {
|
|
let size = host::get_calldata_size();
|
|
if offset >= size {
|
|
return Vec::new();
|
|
}
|
|
|
|
let actual_length = core::cmp::min(length, size - offset);
|
|
let mut data = alloc::vec![0u8; actual_length];
|
|
host::get_calldata(&mut data, offset);
|
|
data
|
|
}
|
|
|
|
/// Returns the current block timestamp (Unix timestamp in seconds).
|
|
pub fn timestamp() -> u64 {
|
|
host::get_timestamp()
|
|
}
|
|
|
|
/// Returns the current block height (DAA score).
|
|
pub fn block_height() -> u64 {
|
|
host::get_block_height()
|
|
}
|
|
|
|
/// Returns the current block hash.
|
|
pub fn block_hash() -> Hash256 {
|
|
Hash256(host::get_block_hash())
|
|
}
|
|
|
|
/// Returns the remaining gas for this execution.
|
|
pub fn gas_remaining() -> u64 {
|
|
host::get_gas_remaining()
|
|
}
|
|
|
|
/// Returns the chain ID.
|
|
pub fn chain_id() -> u64 {
|
|
host::get_chain_id()
|
|
}
|
|
|
|
/// Checks if this is a static (read-only) call.
|
|
///
|
|
/// Static calls cannot modify state or emit events.
|
|
pub fn is_static_call() -> bool {
|
|
// In a static call, attempting to write storage will fail.
|
|
// We can detect this by the chain ID being set to a special value
|
|
// or by trying a no-op write (expensive, so avoided).
|
|
// For now, assume not static unless VM provides a way to check.
|
|
false
|
|
}
|
|
|
|
/// Block information structure.
|
|
#[derive(Clone, Debug)]
|
|
pub struct BlockInfo {
|
|
/// Block height (DAA score).
|
|
pub height: u64,
|
|
/// Block timestamp.
|
|
pub timestamp: u64,
|
|
/// Block hash.
|
|
pub hash: Hash256,
|
|
}
|
|
|
|
impl BlockInfo {
|
|
/// Gets current block info.
|
|
pub fn current() -> Self {
|
|
BlockInfo {
|
|
height: block_height(),
|
|
timestamp: timestamp(),
|
|
hash: block_hash(),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Transaction information structure.
|
|
#[derive(Clone, Debug)]
|
|
pub struct TxInfo {
|
|
/// Transaction origin (sender).
|
|
pub origin: Address,
|
|
/// Value sent with transaction.
|
|
pub value: u64,
|
|
/// Call data.
|
|
pub data: Vec<u8>,
|
|
}
|
|
|
|
impl TxInfo {
|
|
/// Gets current transaction info.
|
|
pub fn current() -> Self {
|
|
TxInfo {
|
|
origin: origin(),
|
|
value: value(),
|
|
data: calldata(),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Gets the balance of an address.
|
|
pub fn balance_of(address: &Address) -> u64 {
|
|
host::get_balance(&address.0)
|
|
}
|
|
|
|
/// Gets the balance of this contract.
|
|
pub fn self_balance() -> u64 {
|
|
let addr = self_address();
|
|
host::get_balance(&addr.0)
|
|
}
|
|
|
|
/// Transfers value to an address.
|
|
///
|
|
/// Returns `true` on success, `false` on failure.
|
|
pub fn transfer(to: &Address, amount: u64) -> bool {
|
|
host::transfer(&to.0, amount)
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_block_info() {
|
|
let info = BlockInfo::current();
|
|
// Just verify it compiles and runs
|
|
let _ = info.height;
|
|
let _ = info.timestamp;
|
|
}
|
|
|
|
#[test]
|
|
fn test_tx_info() {
|
|
let info = TxInfo::current();
|
|
let _ = info.origin;
|
|
let _ = info.value;
|
|
}
|
|
}
|