StellarCN/py-stellar-base

View on GitHub
xdr/Stellar-contract.x

Summary

Maintainability
Test Coverage
// Copyright 2022 Stellar Development Foundation and contributors. Licensed
// under the Apache License, Version 2.0. See the COPYING file at the root
// of this distribution or at http://www.apache.org/licenses/LICENSE-2.0

% #include "xdr/Stellar-types.h"
namespace stellar
{

// We fix a maximum of 128 value types in the system for two reasons: we want to
// keep the codes relatively small (<= 8 bits) when bit-packing values into a
// u64 at the environment interface level, so that we keep many bits for
// payloads (small strings, small numeric values, object handles); and then we
// actually want to go one step further and ensure (for code-size) that our
// codes fit in a single ULEB128-code byte, which means we can only use 7 bits.
//
// We also reserve several type codes from this space because we want to _reuse_
// the SCValType codes at the environment interface level (or at least not
// exceed its number-space) but there are more types at that level, assigned to
// optimizations/special case representations of values abstract at this level.

enum SCValType
{
    SCV_BOOL = 0,
    SCV_VOID = 1,
    SCV_ERROR = 2,

    // 32 bits is the smallest type in WASM or XDR; no need for u8/u16.
    SCV_U32 = 3,
    SCV_I32 = 4,

    // 64 bits is naturally supported by both WASM and XDR also.
    SCV_U64 = 5,
    SCV_I64 = 6,

    // Time-related u64 subtypes with their own functions and formatting.
    SCV_TIMEPOINT = 7,
    SCV_DURATION = 8,

    // 128 bits is naturally supported by Rust and we use it for Soroban
    // fixed-point arithmetic prices / balances / similar "quantities". These
    // are represented in XDR as a pair of 2 u64s.
    SCV_U128 = 9,
    SCV_I128 = 10,

    // 256 bits is the size of sha256 output, ed25519 keys, and the EVM machine
    // word, so for interop use we include this even though it requires a small
    // amount of Rust guest and/or host library code.
    SCV_U256 = 11,
    SCV_I256 = 12,

    // Bytes come in 3 flavors, 2 of which have meaningfully different
    // formatting and validity-checking / domain-restriction.
    SCV_BYTES = 13,
    SCV_STRING = 14,
    SCV_SYMBOL = 15,

    // Vecs and maps are just polymorphic containers of other ScVals.
    SCV_VEC = 16,
    SCV_MAP = 17,

    // Address is the universal identifier for contracts and classic
    // accounts.
    SCV_ADDRESS = 18,

    // The following are the internal SCVal variants that are not
    // exposed to the contracts. 
    SCV_CONTRACT_INSTANCE = 19,

    // SCV_LEDGER_KEY_CONTRACT_INSTANCE and SCV_LEDGER_KEY_NONCE are unique
    // symbolic SCVals used as the key for ledger entries for a contract's
    // instance and an address' nonce, respectively.
    SCV_LEDGER_KEY_CONTRACT_INSTANCE = 20,
    SCV_LEDGER_KEY_NONCE = 21
};

enum SCErrorType
{
    SCE_CONTRACT = 0,          // Contract-specific, user-defined codes.
    SCE_WASM_VM = 1,           // Errors while interpreting WASM bytecode.
    SCE_CONTEXT = 2,           // Errors in the contract's host context.
    SCE_STORAGE = 3,           // Errors accessing host storage.
    SCE_OBJECT = 4,            // Errors working with host objects.
    SCE_CRYPTO = 5,            // Errors in cryptographic operations.
    SCE_EVENTS = 6,            // Errors while emitting events.
    SCE_BUDGET = 7,            // Errors relating to budget limits.
    SCE_VALUE = 8,             // Errors working with host values or SCVals.
    SCE_AUTH = 9               // Errors from the authentication subsystem.
};

enum SCErrorCode
{
    SCEC_ARITH_DOMAIN = 0,      // Some arithmetic was undefined (overflow, divide-by-zero).
    SCEC_INDEX_BOUNDS = 1,      // Something was indexed beyond its bounds.
    SCEC_INVALID_INPUT = 2,     // User provided some otherwise-bad data.
    SCEC_MISSING_VALUE = 3,     // Some value was required but not provided.
    SCEC_EXISTING_VALUE = 4,    // Some value was provided where not allowed.
    SCEC_EXCEEDED_LIMIT = 5,    // Some arbitrary limit -- gas or otherwise -- was hit.
    SCEC_INVALID_ACTION = 6,    // Data was valid but action requested was not.
    SCEC_INTERNAL_ERROR = 7,    // The host detected an error in its own logic.
    SCEC_UNEXPECTED_TYPE = 8,   // Some type wasn't as expected.
    SCEC_UNEXPECTED_SIZE = 9    // Something's size wasn't as expected.
};

// Smart contract errors are split into a type (SCErrorType) and a code. When an
// error is of type SCE_CONTRACT it carries a user-defined uint32 code that
// Soroban assigns no specific meaning to. In all other cases, the type
// specifies a subsystem of the Soroban host where the error originated, and the
// accompanying code is an SCErrorCode, each of which specifies a slightly more
// precise class of errors within that subsystem.
//
// Error types and codes are not maximally precise; there is a tradeoff between
// precision and flexibility in the implementation, and the granularity here is
// chosen to be adequate for most purposes while not placing a burden on future
// system evolution and maintenance. When additional precision is needed for
// debugging, Soroban can be run with diagnostic events enabled.

union SCError switch (SCErrorType type)
{
case SCE_CONTRACT:
    uint32 contractCode;
case SCE_WASM_VM:
case SCE_CONTEXT:
case SCE_STORAGE:
case SCE_OBJECT:
case SCE_CRYPTO:
case SCE_EVENTS:
case SCE_BUDGET:
case SCE_VALUE:
case SCE_AUTH:
    SCErrorCode code;
};

struct UInt128Parts {
    uint64 hi;
    uint64 lo;
};

// A signed int128 has a high sign bit and 127 value bits. We break it into a
// signed high int64 (that carries the sign bit and the high 63 value bits) and
// a low unsigned uint64 that carries the low 64 bits. This will sort in
// generated code in the same order the underlying int128 sorts.
struct Int128Parts {
    int64 hi;
    uint64 lo;
};

struct UInt256Parts {
    uint64 hi_hi;
    uint64 hi_lo;
    uint64 lo_hi;
    uint64 lo_lo;
};

// A signed int256 has a high sign bit and 255 value bits. We break it into a
// signed high int64 (that carries the sign bit and the high 63 value bits) and
// three low unsigned `uint64`s that carry the lower bits. This will sort in
// generated code in the same order the underlying int256 sorts.
struct Int256Parts {
    int64 hi_hi;
    uint64 hi_lo;
    uint64 lo_hi;
    uint64 lo_lo;
};

enum ContractExecutableType
{
    CONTRACT_EXECUTABLE_WASM = 0,
    CONTRACT_EXECUTABLE_STELLAR_ASSET = 1
};

union ContractExecutable switch (ContractExecutableType type)
{
case CONTRACT_EXECUTABLE_WASM:
    Hash wasm_hash;
case CONTRACT_EXECUTABLE_STELLAR_ASSET:
    void;
};

enum SCAddressType
{
    SC_ADDRESS_TYPE_ACCOUNT = 0,
    SC_ADDRESS_TYPE_CONTRACT = 1
};

union SCAddress switch (SCAddressType type)
{
case SC_ADDRESS_TYPE_ACCOUNT:
    AccountID accountId;
case SC_ADDRESS_TYPE_CONTRACT:
    Hash contractId;
};

%struct SCVal;
%struct SCMapEntry;

const SCSYMBOL_LIMIT = 32;

typedef SCVal SCVec<>;
typedef SCMapEntry SCMap<>;

typedef opaque SCBytes<>;
typedef string SCString<>;
typedef string SCSymbol<SCSYMBOL_LIMIT>;

struct SCNonceKey {
    int64 nonce;
};

struct SCContractInstance {
    ContractExecutable executable;
    SCMap* storage;
};

union SCVal switch (SCValType type)
{

case SCV_BOOL:
    bool b;
case SCV_VOID:
    void;
case SCV_ERROR:
    SCError error;

case SCV_U32:
    uint32 u32;
case SCV_I32:
    int32 i32;

case SCV_U64:
    uint64 u64;
case SCV_I64:
    int64 i64;
case SCV_TIMEPOINT:
    TimePoint timepoint;
case SCV_DURATION:
    Duration duration;

case SCV_U128:
    UInt128Parts u128;
case SCV_I128:
    Int128Parts i128;

case SCV_U256:
    UInt256Parts u256;
case SCV_I256:
    Int256Parts i256;

case SCV_BYTES:
    SCBytes bytes;
case SCV_STRING:
    SCString str;
case SCV_SYMBOL:
    SCSymbol sym;

// Vec and Map are recursive so need to live
// behind an option, due to xdrpp limitations.
case SCV_VEC:
    SCVec *vec;
case SCV_MAP:
    SCMap *map;

case SCV_ADDRESS:
    SCAddress address;

// Special SCVals reserved for system-constructed contract-data
// ledger keys, not generally usable elsewhere.
case SCV_LEDGER_KEY_CONTRACT_INSTANCE:
    void;
case SCV_LEDGER_KEY_NONCE:
    SCNonceKey nonce_key;

case SCV_CONTRACT_INSTANCE:
    SCContractInstance instance;
};

struct SCMapEntry
{
    SCVal key;
    SCVal val;
};

}