Misterio del guion
En el artículo anterior , presentamos brevemente la base operativa de los contratos inteligentes de Bitcoin, es decir, el lenguaje de script subyacente Script de la red Bitcoin y el principio operativo de su máquina virtual. Creo que muchos estudiantes que están en contacto por primera vez tendrán cierta confusión después de leerlo: ¿Cómo es que esto no se parece en nada a lenguajes de script como Python y JavaScript con los que todos están familiarizados? ¿Cómo aprender y utilizar el lenguaje de programación de "el esqueleto es tan asombroso"? Con estas preguntas, hablemos más profundamente.
¿Por qué Script?
Como todos sabemos, la red de Bitcoin es esencialmente un conjunto de libros de contabilidad públicos ejecutados y mantenidos por muchos nodos mineros. Todos los nodos deben asegurarse de que los datos de este libro de contabilidad sean legales y precisos. En otras palabras, cualquier transacción puede ser transmitida y verificada por cualquier nodo. El minero realmente necesita ejecutar el script para verificar si la "clave" proporcionada en la nueva transacción puede "abrir" el "candado" en la transacción anterior. para verificar la legalidad de la transacción. En el proceso de verificación, las ventajas de Script se reflejan en estos dos aspectos:
-
No es necesario compilar, ejecutar eficientemente : debido Script El código del script es una cadena de bytes 1 , antes de la necesidad de compilar el proceso de la máquina virtual nuevamente, con el fin de explicar los resultados obtenidos se puede ejecutar la instrucción directamente, asegurando así la eficiencia.
-
Diseñar seguridad y prevenir ataques : una característica muy importante de Script es que no hay instrucciones de salto, lo que puede evitar que alguien escriba maliciosamente (o por negligencia) un bucle sin fin en el script para atacar la red minera. Esto a menudo se critica como lo incompleto de Turing, incapaz de lograr muchas funciones. Pero, de hecho, se trata de un malentendido. La integridad de Turing se puede lograr a través de algunos medios técnicos (seguimiento, planeo escribir otro artículo para hablar sobre esto).
Sin embargo, Script no es tan amigable para los desarrolladores. Existen umbrales muy altos para el aprendizaje, el desarrollo y las pruebas, porque es esencialmente un lenguaje ensamblador.
Lenguaje de alto nivel (sCrypt) vs lenguaje ensamblador (Script)
Creo que la mayoría de los estudiantes que han estudiado lenguaje ensamblador tienen recuerdos similares: ¡recuerde aprenderlo en la escuela! Eso es todo, la mayoría de la gente nunca lo encontrará en proyectos reales. Para los estudiantes que no están familiarizados con el lenguaje ensamblador, es posible que solo necesiten saber que es un lenguaje de programación que nació en los primeros días de la invención de la computadora. Escribir programas en él suele ser muy complicado y requiere mucho tiempo.
El proyecto sCrypt nació debido a la ineficacia del desarrollo del lenguaje Script como el lenguaje ensamblador. Su objetivo es proporcionar a los desarrolladores un lenguaje de desarrollo más avanzado y un entorno de desarrollo familiar, mejorando así la eficiencia general de I + D. En pocas palabras, los desarrolladores usan el lenguaje sCrypt para desarrollar contratos inteligentes y luego usan un compilador para convertir el código fuente en un lenguaje de secuencias de comandos y ponerlos en la transacción para enviarlos a la cadena. Finalmente, los mineros se aseguran de que el código del contrato se ejecute correctamente .
A continuación se presenta formalmente el lenguaje de desarrollo de alto nivel de los contratos inteligentes de Bitcoin: sCrypt (pronunciación en inglés: ess crypt).
Sintaxis y estructura básica de sCrypt
La sintaxis 2 de sCrypt fue diseñada con el objetivo de minimizar el costo de aprendizaje de los desarrolladores, por lo que tiene muchas similitudes con algunos otros lenguajes de alto nivel (como Javascript, Solidity, etc.) en su conjunto, lo cual también es intencional.
Tipo de datos básico
sCrypt es un lenguaje fuertemente tipado. Los tipos de datos básicos incluyen:
-
bool
: Valor booleanotrue
ofalse
; -
int
: Valor entero con signo;
int a1 = 42;
int a2 = -4242424242424242;
int a3 = 55066263022277343669578718895168534326250603453777594175500187360389116729240;
int a4 = 0xFF8C;
bytes
: Representación de matriz de bytes hexadecimal, contenida entre comillas simples y letrasb
como prefijo;
bytes b1 = b'ffee1234';
bytes b2 = b'414136d08c5ed2bf3ba048afe6dcaebafeffffffffffffffffffffffffffffff00';
Para mejorar aún más la seguridad de los tipos, bytes
también se puede convertir a una descripción de subtipo más precisa para que el compilador pueda encontrar o reducir posibles errores de código. Los tipos específicos incluyen:
PubKey
: Tipo de clave pública
PubKey pubKey = PubKey(b'0200112233445566778899aabbccddeeffffeeddccbbaa99887766554433221100');
SigHashType
: Tipo de hash de firma
SigHashType s = SigHashType(b'01');
SigHashType s = SigHash.ALL | SigHash.ANYONECANPAY;
Sig
: Tipo de firma en formato DER , que contiene el valor del tipo de hash de la firma;
Sig sig = Sig(b'3045022100b71be3f1dc001e0a1ad65ed84e7a5a0bfe48325f2146ca1d677cf15e96e8b80302206d74605e8234eae3d4980fcd7b2fdc1c5b9374f0ce71dea38707fccdbd28cf7e41');
Ripemd160
: Tipo hash RIPEMD-160
Ripemd160 r = Ripemd160(b'0011223344556677889999887766554433221100');
Sha1
: Tipo de hash Sha1
Sha1 s = Sha1(b'0011223344556677889999887766554433221100');
Sha256
: Tipo de hash Sha256
Sha256 s = Sha256(b'00112233445566778899aabbccddeeffffeeddccbbaa99887766554433221100');
OpCodeType
: Tipo numérico de código de operación
OpCode.OP_ADD // b'93'
Variable de propiedad (propiedad)
Cada contrato puede constar de varias variables de propiedades (es decir, lenguajes orientados a objetos generalmente variables de instancia), el contrato puede ser una función de la this
clave de acceso. Como:
contract Test {
int x;
bool y;
bytes z;
...
}
Constructor
Cada contrato tiene como máximo 1 constructor (de lo contrario, el compilador generará uno automáticamente), que generalmente se utiliza para inicializar las variables de atributo. Como:
contract Test {
constructor(int x) {
this.x = x;
}
...
}
Funciones integradas
-
require(bool expr)
: Cuando se llama a esta función para comprobar losexpr
resultados del valor booleano de la expresión del parámetro . Sitrue
continúa hacia abajo; de lo contrario, interrumpa inmediatamente el proceso de ejecución, la ejecución del contrato falló. Equivalente a C / C ++, Java y Pythonassert()
. -
exit(bool status)
: Esta función se llama inmediatamente interrumpir el proceso de ejecución, elstatus
valor del parámetro estrue
cuando el contrato se ejecuta con éxito; de lo contrario, la ejecución del contrato falló.
Función pública
La función pública es la interfaz para llamar externamente al contrato. El código lógico principal contenido en el cuerpo de la función se puede considerar como el script de bloqueo; los parámetros de la función se pueden considerar como el script de desbloqueo correspondiente. El minero realmente verifica el resultado de ejecución de este par de combinaciones.
Las particularidades de este tipo de funciones son las siguientes:
- Sin
returns
declaraciones de tipo explícitas y el final de lareturn
declaración de función , que es invisible para devolvertrue
; - El final de la función debe ser una
require()
llamada de función; - Solo cuando la función finaliza, todas las ejecuciones encontradas
require()
han pasado, la secuencia de comandos se considera mediante verificación; de lo contrario, se considerará que la verificación de secuencia de comandos falla, lo que provocará que la transacción falle.
contract Test {
public function equal(int y) {
require(this.valueOf(y) == this.x);
}
...
}
Función no pública (función)
Las funciones no públicas pueden considerarse funciones privadas del contrato, cuyo objetivo principal es encapsular la lógica interna y la reutilización del código. Debe usarse cuando la definición de una palabra clave returns
se describirá con el tipo de retorno, como por ejemplo:
contract Test {
function valueOf(int x) returns(int) {
return x;
}
...
}
Además de parte del contenido presentado brevemente anteriormente, aquí se puede ver la documentación oficial completa que contiene algunas otras características del idioma (en actualización iterativa continua).
Ejemplo de contrato sCrypt
Finalmente, mire este contrato sCrypt completo (debería ser fácil de entender):
contract Test {
// 定义合约
int x; // 属性变量
constructor(int x) {
// 定义构造函数
this.x = x; // 初始化属性变量值
}
public function equal(int y) {
// 定义公共函数,解锁参数 y 为 int 类型
require(this.valueOf(y) == this.x); // 调用 require 函数,只有参数表达式值为 true 时,合约才能执行成功
}
function valueOf(int x) returns (int) {
// 定义内部函数
return x; // 返回值
}
}
En los siguientes artículos, continuaré presentando herramientas de desarrollo relacionadas con sCrypt y algunos diseños e implementación de contratos más complejos. Si está interesado, continúe prestando atención :)