GCULpy es un subconjunto de Python con tipos estáticos estrictos, diseñado para ser seguro, legible y auditable. Su diseño limita de forma intencional ciertas funciones dinámicas de Python para evitar vulnerabilidades comunes de los contratos inteligentes y garantizar que el comportamiento de un contrato siempre sea predecible.
En esta página, se proporciona una referencia para la especificación del lenguaje GCULpy, que abarca los conceptos básicos y el ciclo de vida de un contrato en una red de Universal Ledger.
Conceptos básicos
En el siguiente contrato, se define un token ERC20 de muestra en GCULpy:
import gcul
class ERC20Token(gcul.Contract):
"""Sample ERC20 implementation for the Universal Ledger."""
symbol: str
total_supply: int
balance: gcul.AccountField[int]
def __init__(self, symbol: str):
self.symbol = symbol
self.total_supply = 0
def mint(self, beneficiary: gcul.Account, value: int) -> int:
"""Mints tokens to the given beneficiary."""
assert self.is_owner(gcul.sender), "Only the owner can mint"
assert value >= 0, "Mint amount must be non-negative"
self.total_supply += value
self.balance[beneficiary] += value
return value
def transfer(self, beneficiary: gcul.Account, value: int) -> int:
"""Transfers tokens from the sender to the given beneficiary."""
assert value >= 0, "Transfer amount must be non-negative"
assert (
value <= self.balance[gcul.sender]
), "Sender does not have enough balance"
self.balance[gcul.sender] -= value
self.balance[beneficiary] += value
return value
Un contrato de GCULpy es una clase que hereda de gcul.Contract. Contiene campos (estado de almacenamiento) y métodos (lógica de procesamiento que opera en los campos).
Campos
El estado en un contrato de GCULpy se almacena en campos. Todos los campos se deben declarar con un tipo estático a nivel de la clase. Existen dos tipos de campos:
Los campos de contrato contienen un solo valor almacenado con el contrato. En el ejemplo de
ERC20Token,symbol: strytotal_supply: intson campos de contrato.Los campos de cuenta contienen un valor independiente para cada cuenta que interactúa con el contrato. Se declaran con
gcul.AccountField[T], en el queTes el tipo del valor por cuenta. En el ejemplo deERC20Token,balance: gcul.AccountField[int]es un campo de cuenta. Antes de que un contrato pueda escribir en el espacio de almacenamiento reservado para esa cuenta, el permiso de almacenamiento debe otorgarse de forma explícita al contrato. Una vez que se almacenan los datos, solo la instancia del contrato puede modificarlos, no la cuenta.
Los campos de restricción tienen los siguientes límites de almacenamiento. Una transacción que supere cualquiera de los límites fallará.
- Todos los campos de un contrato comparten una sola entrada de almacenamiento, que puede contener alrededor de 5 MiB de datos serializados en total.
- Todos los campos de cuenta que un contrato almacena para cada cuenta individual pueden contener, como máximo, 1 MiB de datos serializados en total.
Métodos
Los métodos definen la lógica ejecutable de un contrato. Se comportan como métodos de Python y pueden leer o modificar los campos del contrato.
__init__: Se llama al constructor solo una vez cuando se implementa el contrato por primera vez. A cada campo del contrato se le debe asignar un valor en el constructor. El constructor no inicializa los campos de la cuenta; el valor de cada cuenta se crea cuando esa cuenta otorga el permiso de almacenamiento.Métodos privados: Los métodos que comienzan con un guion bajo (por ejemplo,
_internal_logic) son privados y solo los pueden llamar otros métodos dentro del mismo contrato. El intérprete de Universal Ledger aplica esta restricción.Métodos públicos: Cualquier método que no comience con un guion bajo (
_) es público. Cualquier usuario con el rolROLE_CONTRACT_PARTICIPANTpuede llamar a los métodos públicos enviando una transacción InvokeContractMethod.
Restricción Los métodos públicos y todos los métodos @gcul.readonly no pueden usar tipos mutables en sus firmas, por ejemplo, list o dict. En su lugar, usa declaraciones de tipo de solo lectura, como Sequence o Mapping.
Restricción Durante la ejecución, los métodos se limitan a un límite superior de uso de procesamiento en toda la red. Si se supera este límite, se produce un error en la transacción.
Ciclo de vida del contrato
En las siguientes secciones, se explican las operaciones típicas que se realizan en el ciclo de vida de un contrato de GCULpy.
Implementa un contrato
Primero, compila tu código fuente de GCULpy con el compilador
gculpyc. Luego, un usuario con el ROLE_CONTRACT_CREATOR puede enviar una transacción
CreateContract
para implementar el código de bytes compilado en una red de Universal Ledger. Para
obtener instrucciones detalladas, consulta el instructivo
Implementa un contrato programable.
Una transacción de este tipo se vería de la siguiente manera:
client_transaction {
sender_id: "OWNER_ACCOUNT_ID"
create_contract_transaction {
contract_bytes: "COMPILED_BYTECODE"
init_arguments {
key: "symbol"
value: { string_value: "US02079K1079" }
}
}
}
Cuando la red procesa esta transacción, ocurre lo siguiente:
- El constructor, es decir, el método
__init__, se ejecuta con los argumentos proporcionados para crear una nueva instancia de contrato. - El remitente de la transacción se convierte en el propietario del contrato.
- La instancia del contrato se almacena de forma permanente en el libro mayor y se le asigna un ID de contrato único que se devuelve como parte del resultado de la transacción.
Otorga permisos
Antes de que un contrato pueda almacenar datos en un campo de cuenta en nombre de una cuenta, ya sea una cuenta para un usuario o un contrato diferente, se debe otorgar el permiso de almacenamiento al contrato que almacena los datos. Este es un paso de seguridad fundamental.
Otorga permisos para una cuenta de usuario
Un usuario con un ROLE_CONTRACT_PARTICIPANT puede enviar una transacción GrantContractPermissions para un ID de contrato específico:
client_transaction {
sender_id: "PARTICIPANT_ACCOUNT_ID"
grant_contract_permissions_transaction {
contract_id: "CONTRACT_ID"
permissions: CONTRACT_PERMISSION_STORAGE
}
}
Cuando la red procesa esta transacción, ocurre lo siguiente:
- Si el contrato no define ningún campo de cuenta, se rechaza la transacción.
- Si el contrato define campos de cuenta, todos se completan con
valores predeterminados (por ejemplo,
contract.balance[gcul.sender] = 0). Luego, estos valores se almacenan en el estado mundial como parte de los datos de la cuenta.
Otorga permisos para un contrato de delegado
Un usuario con un ROLE_CONTRACT_PARTICIPANT puede enviar una transacción GrantContractPermissions para permitir que un contrato almacene datos en nombre de otro contrato de su propiedad:
client_transaction {
sender_id: "OWNER_ACCOUNT_ID"
grant_contract_permissions_transaction {
contract_id: "TARGET_CONTRACT_ID"
delegate_contract_id: "DELEGATE_CONTRACT_ID"
permissions: CONTRACT_PERMISSION_STORAGE
}
}
Cuando la red procesa esta transacción, ocurre lo siguiente:
- El remitente de la transacción, es decir,
sender_id, debe ser el propietario del contrato identificado pordelegate_contract_id. - Un contrato no puede otorgarse permisos de almacenamiento a sí mismo, por lo que
delegate_contract_iddebe ser diferente decontract_id. - Los permisos de almacenamiento se otorgan exclusivamente al contrato especificado en
delegate_contract_id, en lugar de al remitente de la transacción. - Los campos de cuenta definidos en el contrato de destino,
contract_id, se inicializan para el contrato delegado,delegate_contract_id, lo que permite que los métodos del contrato de destino accedan de forma segura a los campos de cuenta con clave degcul.callerogcul.senderdurante las invocaciones entre contratos.
Invocar métodos de contrato
Una vez que se implementa un contrato y se otorgan los permisos necesarios, los usuarios pueden
interactuar con él llamando a sus métodos públicos. Un usuario con un
ROLE_CONTRACT_PARTICIPANT puede enviar una transacción
InvokeContractMethod
especificando el ID del contrato, el nombre del método y los valores de los argumentos del método.
client_transaction {
sender_id: "PARTICIPANT_ACCOUNT_ID"
invoke_contract_method_transaction {
contract_id: "CONTRACT_ID"
method_name: "mint"
method_arguments {
key: "beneficiary"
value: { account_id: "BENEFICIARY_ID" }
}
method_arguments {
key: "value"
value: { int64_value: 10 }
}
}
}
Cuando la red procesa esta transacción, ocurre lo siguiente:
- Se recupera la instancia de contrato asociada con el
CONTRACT_IDproporcionado. - Se ejecuta el método
mint(beneficiary=Account("BENEFICIARY_ID"), value=10). El entorno de ejecución compila y valida el objetoAccountpara el beneficiario. La lógica del método puede suponer de forma segura que el ID proporcionado es válido y hace referencia a una cuenta existente en el libro mayor. - Si el método falla por cualquier motivo, la transacción fallará y no se realizarán actualizaciones en el estado del contrato.
- Si el método se ejecuta de forma correcta, el estado actualizado del contrato se registra en el estado mundial.
Especificación del lenguaje
GCULpy está diseñado para brindar seguridad y previsibilidad y, por lo tanto, no permite varias funciones de Python; estas se indicarán con la etiqueta Restricción. Estas restricciones están diseñadas para ser funciones de lenguaje permanentes, introducidas para que la lógica del contrato sea más fácil de leer, auditar y analizar de forma estática, lo que limita los comportamientos sorprendentes o no seguros.
Otras funciones se indican con la etiqueta Roadmap. Estas se encuentran en la
hoja de ruta de implementación, pero aún no son compatibles con el compilador gculpyc.
Tipos
GCULpy admite una variedad de tipos de variables comunes con un fuerte énfasis en el tipado estático.
Tipos de valores principales:
- Ya se admiten
int,bool,stryNone. - Hoja de ruta
Decimal,bytes,Enumestán en la hoja de ruta. - Restricción No se permiten
floatnicomplex. - Restricción: Los valores
intson números enteros de 64 bits con firma, de -263 a 263 - 1. Un literal de número entero fuera de este rango generará un error de tiempo de compilación, y una operación cuyo resultado esté fuera de este rango generará un error de tiempo de ejecución. - Restricción: Los valores de
strpueden tener un máximo de 1,000,000 de caracteres. Un literal de cadena más largo generará un error de tiempo de compilación. Si pasas una cadena más larga como argumento de método o produces una como resultado de una operación, se producirá un error de tiempo de ejecución.
Tipos de contenedores:
listydict:list[T]: Es una secuencia mutable. Admite la indexación, por ejemplo,my_list[0], y el métodoappend().dict[K, V]: Es una asignación mutable. Admite la indexación, por ejemplo,my_dict[key], y el métodopop().
collections.abc.Sequenceycollections.abc.Mapping:collections.abc.Sequence[T]: Es una referencia de solo lectura a una secuencia. Admite la lectura de elementos por índice, por ejemplo,my_seq[0], pero los elementos no se pueden modificar ni borrar.list[T]es un subtipo deSequence[T], por lo que puedes pasar, devolver o asignar un valor delist[T]o un literal de lista a un destino con tipoSequence[T], pero no puedes asignar unSequence[T]a unlist[T].collections.abc.Mapping[K, V]: Es una referencia de solo lectura a una asignación. Admite la lectura de entradas por clave, por ejemplo,my_map[key], pero las entradas no se pueden modificar ni borrar.dict[K, V]es un subtipo deMapping[K, V], por lo que puedes pasar, devolver o asignar un valor dedict[K, V]o un literal de diccionario a un destino con el tipoMapping[K, V], pero no puedes asignar unMapping[K, V]a undict[K, V].
- Hoja de ruta
tuple,set,dataclassestán en la hoja de ruta. - Restricción: Se deben especificar tipos concretos para los valores de un contenedor; por ejemplo, se permite
dict[str, int], pero nodictodict[str, Any]simples. - Hoja de ruta: División de listas, por ejemplo,
my_list[1:3]. - Hoja de ruta Otros métodos, como
.get(),.keys(),.values(),.items(),.clear()o.extend().
Restricción Todas las variables, incluidos los campos de contrato y cuenta, los parámetros de función y los tipos de datos que se devuelven, se deben definir y escribir de forma estática. Su tipo no se puede cambiar durante el tiempo de ejecución y solo se admiten tipos concretos. Los tipos no se pueden usar como valores, por ejemplo, no se pueden almacenar en variables ni pasar a funciones como argumentos. Si intentas asignar un valor a un campo no declarado, se producirá un error de tiempo de compilación.
Restricción: Se debe asignar una variable local antes de leerla. Las variables locales no tienen un valor predeterminado, por lo que leer una antes de que se asigne genera un error de tiempo de ejecución.
Clases y herencia
Solo puedes definir clases que sean subclases directas de gcul.Contract o gcul.ContractInterface.
Esta regla estricta evita las complejidades de la herencia completa de Python, que puede introducir errores difíciles de encontrar y dificultar la comprensión del
código. Por motivos de seguridad, si intentas anular una propiedad o un método de una
clase superior, se generará un error, lo que proporciona una protección clara contra comportamientos
inesperados.
Hoja de ruta GCULpy ofrecerá más flexibilidad,
pero mantendrá sus principios fundamentales. La hoja de ruta incluye compatibilidad con la
herencia única en clases definidas por el usuario con anulación de métodos administrada de forma explícita
con un decorador @override. Además, la función integrada super() solo se admitirá en su formato libre argumentos para garantizar operaciones directas y predecibles.
El módulo gcul
GCULpy proporciona un módulo gcul integrado con tipos,
decoradores y variables esenciales para el desarrollo de contratos.
clase gcul.Contract
Es la clase base para todos los contratos. No puedes crear instancias de él directamente;
los contratos solo se crean a través de
transacciones
CreateContract. Los métodos y las propiedades de la clase gcul.Contract base no se pueden
anular en las subclases.
Contract.is_owner(account: Account) -> boolDevuelve
Truesi la cuenta proporcionada es la propietaria del contrato.Contract.call(target: ContractInterface, payment: Amount | None = None) -> ContractMethodsInicia una interacción entre contratos con
target. En lugar de llamar directamente a los métodos en el destino (p.ej.,target.foo()), debes usarself.call()para enrutar de forma explícita la invocación a través del entorno de ejecución del libro mayor. Este mecanismo devuelve un objeto de proxy seguro que se usa para invocar los métodos públicos correspondientes en el contrato de destino, lo que garantiza que los límites de ejecución se apliquen de forma estricta y que cualquierpaymentse entregue de forma segura. Consulta ContractInterface para obtener más detalles.Se debe proporcionar un
paymentcuando se llama a un método decorado con@gcul.payable, y se debe omitir para los métodos no pagaderos.targetdebe ser un contrato diferente. Si se llama al contrato actual a través deself.call(), se genera un error de tiempo de ejecución. Para llamar a otro método en el mismo contrato, llámalo directamente, por ejemplo,self.foo().Contract.native_transfer(beneficiary: Account, amount: Amount) -> NoneTransfiere un importe registrado directamente del saldo del contrato a
beneficiary.Contract.id: strEs el ID de cadena único del contrato.
clase gcul.Account
Es un tipo integrado que representa una cuenta de usuario o de contrato en el libro mayor. No
puedes crear objetos gcul.Account directamente; el entorno de ejecución los crea
por ti y los proporciona como argumentos de función o método. Para pasar una
cuenta como argumento de transacción, proporciona un
AccountValue
que contenga el ID de cuenta. El entorno de ejecución valida el ID y lo convierte en un
objeto de cuenta completo. Si el ID no pertenece a una cuenta registrada, la
transacción falla. Esto garantiza que solo trabajes con cuentas válidas.
La definición de la clase es aproximadamente equivalente a lo siguiente:
@dataclasses.dataclass(frozen=True)
class Account:
"""A valid account on the ledger."""
id: str # The ID of the account as a string.
Account.id: strEs el ID de cadena único de la cuenta.
clase gcul.Amount
Representa un valor monetario denominado en una moneda de libro mayor específica.
Crea una instancia de un importe con
gcul.Amount(value: int, currency: gcul.Currency). La definición de la clase es aproximadamente equivalente a lo siguiente:
@dataclasses.dataclass(frozen=True)
class Amount:
"""Represents an amount denominated in a ledger currency."""
value: int
currency: Currency
clase gcul.Currency
Representa una moneda completamente calificada en el libro mayor. La definición de la clase es aproximadamente equivalente a lo siguiente:
@dataclasses.dataclass(frozen=True)
class Currency:
"""Represents a fully qualified currency on the ledger."""
code: str
operator_id: str
clase gcul.ContractInterface
Es la clase base para declarar la interfaz pública de un contrato.
Los métodos y las propiedades de la clase gcul.ContractInterface base no se pueden
anular en las subclases. Además, los métodos de la declaración de la interfaz no pueden incluir ningún código, solo se permite ....
Para que un contrato llame a métodos en otro contrato implementado en el libro mayor,
declara una clase de interfaz que herede de gcul.ContractInterface. Los resguardos de métodos deben coincidir con su declaración correspondiente en el contrato de destino. Esto
incluye argumentos, tipo de datos que se devuelve y anotaciones de decorador, como
@gcul.readonly o @gcul.payable.
Dentro del código de tu contrato, usa self.call(target, payment) para
invocar un método de otro contrato.
En el siguiente ejemplo, se ilustra cómo interactúa un contrato TokenVendor
con otro contrato que implementa ERC20Interface. Usa self.call() para transferir tokens a un comprador a cambio de un pago en moneda en el libro mayor:
class ERC20Interface(gcul.ContractInterface):
"""Interface for an external ERC20 token contract."""
def transfer(self, beneficiary: gcul.Account, value: int) -> int:
...
class TokenVendor(gcul.Contract):
"""A vendor contract that distributes ERC20 tokens."""
price_per_token: int
def __init__(self, price_per_token: int) -> None:
self.price_per_token = price_per_token
@gcul.payable
def purchase_tokens(self, token: ERC20Interface, quantity: int) -> int:
"""Accepts on-ledger currency for a specific quantity of ERC20 tokens."""
# Enforce positive quantity.
assert quantity > 0, "Quantity must be positive"
# Calculate the required payment.
required_payment = quantity * self.price_per_token
assert gcul.payment.value == required_payment, "Incorrect payment amount"
# Invokes `transfer` on the external ERC20 token contract
# to move tokens from the vendor's own balance to the caller.
return self.call(token).transfer(gcul.caller, quantity)
Los tipos de interfaz también se pueden usar como campos de contrato, no solo como parámetros de método. Almacenar una interfaz en un campo permite que un contrato mantenga una referencia a
otro contrato en todas las transacciones y que reemplace esa referencia más adelante. En el siguiente contrato de ejemplo, se usa el ERC20Interface declarado antes:
class Router(gcul.Contract):
"""Holds a replaceable reference to an ERC20 token contract."""
target: ERC20Interface
def __init__(self, target: ERC20Interface) -> None:
self.target = target
def set_target(self, new_target: ERC20Interface) -> None:
assert self.is_owner(gcul.sender), "Only the owner can set the target"
self.target = new_target
clase gcul.AccountField
Es un tipo genérico integrado para declarar campos de cuenta. gcul.AccountField[T]
contiene un valor independiente de tipo T para cada cuenta que otorgó al
contrato el permiso de almacenamiento. Se comporta como una asignación con claves gcul.Account,
que puedes usar para leer o escribir un valor para cada cuenta específica.
Por ejemplo:
class Token(gcul.Contract):
balance: gcul.AccountField[int]
def deposit(self, account: gcul.Account, value: int) -> None:
self.balance[account] = value # Writes the value for one account.
def get_balance(self, account: gcul.Account) -> int:
return self.balance[account] # Reads the value for one account.
T debe ser un tipo que tenga un valor predeterminado, por lo que gcul.Account, gcul.Amount,
gcul.Currency y los tipos de interfaz no se pueden usar como valores de campo de
cuenta. Cuando una cuenta otorga el permiso de almacenamiento a un contrato, cada
campo de la cuenta se propaga con el valor predeterminado de su tipo para esa
cuenta.
Restricción: La indexación con una cuenta es la única operación que admite un campo de cuenta. El campo en sí no se puede asignar a una variable, pasar como un argumento, devolver desde una función ni iterar.
Restricción: No se pueden borrar las entradas del campo Cuenta. Se puede reemplazar un valor almacenado, pero la entrada en sí es permanente.
Los campos de cuenta de restricción para gcul.sender, gcul.caller y cualquier
gcul.Account que se pase como argumento de método (incluidas las listas internas o cualquier otro
contenedor) se cargan antes de la ejecución del método. En el caso de otras cuentas, una sola
transacción puede cargar de forma diferida los campos de la cuenta para un máximo de 15 pares
(contract, account) distintos. El acceso a un campo de la cuenta para el mismo par
varias veces en una transacción se cuenta solo una vez. Una transacción que supera
este límite falla.
@gcul.readonly
Anota un método de contrato como de solo lectura. Las declaraciones de métodos con este decorador no pueden mutar el estado del contrato ni realizar transferencias de moneda en el libro mayor. Tampoco
pueden usar tipos de contenedores mutables en sus firmas, por ejemplo, list
o dict; en su lugar, deben usar declaraciones de tipo de solo lectura, como Sequence o
Mapping.
@gcul.payable
Anota un método de contrato que requiere que se ejecute un pago. Si un método
espera recibir un pago en moneda registrada con gcul.payment, debe
marcarse con este decorador; de lo contrario, la transacción fallará.
gcul.sender: gcul.Account
Contiene una referencia a la cuenta que firmó y envió la transacción
InvokeContractMethod
actual. El valor de gcul.sender no cambia durante la ejecución de la transacción,
incluso si implica llamadas entre contratos, a diferencia de gcul.caller,
que hace referencia al emisor inmediato.
gcul.caller: gcul.Account
Contiene una referencia al llamador inmediato del método actual. Para las transacciones directas de los usuarios, gcul.caller coincide con gcul.sender, que apunta a quien envió la transacción. Para las llamadas entre contratos, gcul.caller corresponde al
ID de cuenta del contrato que realiza la llamada. Las llamadas internas dentro de un contrato no cambian
el valor de gcul.caller.
gcul.payment: gcul.Amount
Contiene el pago transferido a un método decorado con @gcul.payable.
Si se accede a gcul.payment dentro de un método no pagadero, se genera un error de tiempo de compilación.
Operadores
La mayoría de los operadores disponibles en Python son compatibles con GCULpy y funcionan como se espera.
- Suma (
+) y resta (-), incluidas las formas unarias y binarias - Multiplicación (
*), división de piso (//) y módulo (%). - Exponenciación (
**) para exponentes positivos. - Comparaciones (
<,<=,>,>=,==,!=) - AND (
&), OR (|), XOR (^), desplazamiento a la izquierda (<<), desplazamiento a la derecha (>>) y negación (~) a nivel de bits. - Operaciones booleanas (
and,or,not) - Hoja de ruta Identidad de objeto (
is). - Restricción: No se permiten los exponentes negativos y generan un error de tiempo de ejecución.
- Restricción No se permite la división verdadera (
/), ya que tiene un tipo de datos que se devuelvefloat, y genera un error de tiempo de compilación.
Flujo de control
La mayoría de las declaraciones de flujo de control de Python funcionan en GCULpy con la misma semántica:
pass.- llamadas a funciones internas (mismo contrato, no recursivas).
assert.if ... then .. else ....for VAR in CONTAINER.- llamadas a funciones externas (a cualquier otro contrato, no recursivas)
- Declaraciones
breakycontinue raise.- Declaraciones de hoja de ruta
try ... except. - Declaraciones de hoja de ruta
match. - Hoja de ruta Declaraciones
generatorsyyield. - Administradores de contexto de hoja de ruta y sentencias
with.
Restricción: GCULpy es intencionalmente Turing-incompleto para evitar bucles infinitos y facilitar el análisis estático. A continuación, se muestra cómo aplica esta política:
- Sin bucles infinitos: Solo se permite la iteración con bucles
foren contenedores finitos o secuencias limitadas conrange(...); no se permiten los bucleswhile. No se permiten algunas actualizaciones de contenedores, por ejemplo, agregar o quitar elementos de una lista o claves de un diccionario, mientras se iteran. - Sin recursión: Una función no puede llamarse a sí misma, ya sea de forma directa o indirecta. El entorno de ejecución realiza verificaciones estáticas y de ejecución para detectar y rechazar el uso de la recursión.
- No hay flujo de control asíncrono: No se permite el uso de primitivas
asyncpara mantener los principios de diseño fundamentales de previsibilidad, seguridad y ejecución determinística. Las operaciones asíncronas dificultan el razonamiento sobre el flujo de control de un programa, lo que suele generar vulnerabilidades y condiciones de carrera.
Funciones integradas
GCULpy admite las siguientes funciones integradas:
abs(x)Devuelve el valor absoluto de un número entero
x. Los argumentos deben ser del tipoint.len(s)Devuelve la longitud, es decir, la cantidad de elementos, de una cadena o un contenedor finito.
max(iterable)
max(arg1, arg2, *args)Devuelve el elemento más grande de un iterable o el más grande de dos o más argumentos. Llamar a
max()en un iterable vacío genera un error de tiempo de ejecución.min(iterable)
min(arg1, arg2, *args)Devuelve el elemento más pequeño de un iterable o el más pequeño de dos o más argumentos. Llamar a
min()en un iterable vacío genera un error de tiempo de ejecución.range(stop)
range(start, stop[, step=1])Genera una secuencia aritmética de números enteros con un
stepentero distinto de cero.Restricción: Solo se puede usar intercalado con bucles
for, por ejemplo,for i in range(10): .... Los objetos de rango no se pueden asignar a variables ni almacenar en campos, pasar como argumentos a funciones ni consultar conlen().
Hoja de ruta Las siguientes funciones integradas se encuentran en la hoja de ruta de implementación:
|
A
B
C
D |
E
F
H
I
L |
O
P
R |
S
T
Z |
Notas de la versión
3 de noviembre de 2026. Se lanzó la versión de DG del compilador de
gculpyc(v0.2.0), que incluye compatibilidad con llamadas entre contratos, transferencias y pagos de monedas en el libro mayor, métodos@gcul.readonly,list, declaraciones de flujo de control adicionales y funciones integradas.28 de enero de 2026 Se puso a disposición de los participantes de la versión preliminar privada de Universal Ledger una versión inicial del compilador de
gculpyc. Para ver un instructivo sobre cómo usar el compilador, consulta Implementa un contrato programable.