Scripts and Smart Contracts
1. Introduction
Scripts execution
UTXO can be owned not only by a public key, but also by more complex scripts written in a stack-based programming language. In this mode, to spend such UTXO, data that satisfies the script must be provided. In fact, the basic public key ownership mechanism is also implemented through scripts: the script takes the elliptic curve signature as input to verify the transaction and the address that owns the UTXO. If the verification is successful, it returns 1; otherwise, it returns 0. More complex scripts are used for other different applications. For example, one can create a script (multi-signature) that requires two of the three private keys to be collected for transaction confirmation. This script is very useful for company accounts, savings accounts, and some commercial agents. Scripts can also be used to send rewards to users who solve computing problems. People can even create scripts like “If you can provide a simplified confirmation payment certificate that you have sent me a certain amount of Dogecoin, this UTXO is yours.” In essence, the UTXO system allows different cryptocurrencies to carry out Decentralized exchange.
Smart contract calls
In the transaction type, you can specify the contract type as EVM, WASM, or MOVE, and in order to be compatible with Ethereum, you can use the following methods: if the payee address is empty, then the contract is created; if the payee address is the contract address, yes Call the contract, and the Data field is a parameter.
WASM is a portable, small-sized, fast-loading virtual machine compatible with various hardware. It was originally a new specification formulated by the W3C community group composed of mainstream browser vendors. In Kinglory, WASM is a small and fast-loading binary format, used for debugging, testing, experimenting, optimization, learning, teaching, or writing smart contract programs, giving full play to hardware capabilities to achieve native execution efficiency.
Since the contract is Turing complete, this can be used for almost all applications.
2. Script UTXO
Validation of transactions rely on scripts. There are two types of scripts, locking scripts and unlocking scripts. Locking scripts are based on a changeable pattern, realized by scripting language, and used for transaction output. In a transaction, the UTXO can only be spent when unlocking script satisfies condition of locking scripts. Scripts run distributively in nodes of blockchain network.
There are two common scripts in Bitcoin. One is Pay-to-Public-Key-Hash, which is hash of payer public key; Recipient can spend the output through signature using its private key. Another one is Pay-to-Script-Hash. It requires M signature of N secret key (M<N) to spend the UTXO.
Pay-to-Public-Key-Hash is like below:
Pubkey script: OP_DUP OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG Signature script:
Pay-to-Script-Hash is like below:
Pubkey script: OP_HASH160 OP_EQUAL Signature script: [sig] [sig...]
Pubkey script stands for locking script, while signature script stands for unlocking script. Words starting with OP_ are predefined script commands setting rules for unlocking scripts.
Scripting mechanism in Bitcoin is relatively simple. It is an engine explaining opcodes based on stack. There are not so much scripting rules to analyze, and it can’t realize complicated logic. It provides a prototype for programmable blockchain, many programmable blockchain projects are developed based on scripts. Ehereum for example strengthens scripting mechanisms, there are not just simply opcodes, but supporting scripting language operable in Virtual machines.
Transaction input is an output UTXO of another transaction happened before. It is marked by previous transaction hash added to corresponding position of the output. Once an UTXO is chosen, wallet will generate unlocking script with signature for each UTXO. In other words, every unlocking script corresponds to an UTXO of an output before.
To verify the signature of an input is valid, CHECKSIG is used. It operates several procedures to generate verifyThisStr, which is based on locking scripts, unlocking scripts and hashtype. Then it is possible for others to verify the transaction with the given public key using ECDSA and check if it matches SHA256(SHA256(verifyThisStr)).
3. Ethereum Virtual Machine
Ethereum Virtual Machine (EVM) is used to handle transactions in blockchain. The process is shown below.
A transaction in input will be converted into a message to be operated by EVM. If it is a normal transaction, update account balance in StateDB. If it is creation or call of a smart contract, the interpreter will load and run the code, during the process StateDB may be inquired or modified.
Intrinsic Gas
For each transaction there’s intrinsic gas fee calculated as below.
If the transaction has no payload, 21000 gas fee will be charged. If the transaction has payload, a zero-byte costs 4 and non-zero-byte costs 68.
Generating Contract
Transactions will be converted into a Message as input to EVM, and EVM will generate a Contract based on Message for later use.
Gas fee calling contract has a limit, which is node’s Block GasLimit.
Sending to interpreter
The code and input from previous steps are sent to interpreter to run. EVM is based on stack, the interpreter will operate four main components:
- PC: pointer to current instruction, similar to PC in CPU.
- Stack: Operation stack with stack width of 256 bits and maximum depth of 1024.
- Memory: RAM space.
- Gas: Using up gas will lead to transaction failure.
Each instruction in EVM is called an Opcode which takes one byte, so the instructions set cannot exceed 256. Below is an example:
First PC will read an Opcode from contract code, then search for corresponding operation from a JumpTable. Then it will calculate cost of the operation, if gas runs out the process is failed and return error message ErrOutOfGas; If not, it calls execute() to proceed. Based on different types of instruction, EVM reads and writes to Stack, memory and StateDB accordingly.
Call contract syntax
Input usually has two parts. The first four bytes are called 4-byte signature, which is first four byte of Keccak hash of a syntax signature. The following part is parameters needed for the syntax.
Contract calling contract
Below is an example of CALL:
The caller stores parameters in memory, then executes CALL command. When the CALL executes it will create new Contract and uses the parameters in memory as input. The interpreter will create new stack and memory for the new contract to not affect the original one. Finishing execution, the new contract will call RETURN command to write results back to original memory, then the original contract continues execution.
Creating contract
If to address of a transaction is nil, it means the transaction is creating a smart contract. First it needs to create contract address, which is calculated from Keccak(RLP(call_addr, nonce))[:12]. The process is RLP encoding call address and nonce, then calculating Keccak hash and take last 12 bits as contract address. Next is creating stateObject according to contract address and storing contract code in transaction. All changes for the contract will be stored into a storage trie, and in StateDB as Key-Value. Code cannot be modified once stored, but content in storage trie can be modified through contract calls, such as SSTORE command.
Four ways calling contracts
In large projects, one smart contract cannot realize all functions. Normally, we will divide codes into different libraries or contracts, with interfaces for calling each other.
In Solidity, we will put common codes into a library for future usage as in C and Java. Storage variables are not allowed to be defined in library, which means library cannot modify contract status. If need to update contract status, we need to create a new contract and call contract from another contract.
There are four ways calling a contract from another contract:
- CALL
- CALLCODE
- DELEGATECALL
- STATICCALL
CALL vs. CALLCODE
The difference between CALL and CALLCODE is that the contest of code is different. CALL modifies callee’s storage, while CALLCODE modifies caller’s storage.
CALLCODE vs. DELEGATECALL
The difference of CALLCODE and DELEGATECALL is that msg.sender are different. DLELGATECALL will keep original caller’s address, but CALLCODE will not.
4. Move VM
Move VM is a stack virtual machine with static type. Move VM regulates Move languages in mixing file formats, verification, and operation. File format structure allows defining modules, types, and functions. Code is shown in Opcode. Opcode can refer to functions and types. File format increases some uncertainty to the language, such as opaque type and private field. According to definition of file format, we know that we can define function, scope of type or namespaces through modules. If all fields are private, then the type is opaque with no functions or methods.
Developing Details
CompiledModule and CompiledScript in libra/language/vm/src/file_format.rs are top structure in Move Module and Transaction Script. The structures provides simple abstraction of file formats. There’s also a group view for easy browsing CompiledModules/CompiledScripts.
Move VM pack provides definition of file format and related programs:
- A simple Rust abstract file format (libra / language / vm / src / file_format.rs) and Opcode
- Sequence and reverse sequence of file format, definition of code binary on-chain represent
- Some print functions
- Proptest basic structure of file format
- Gas cost and foundations
5. WASM smart contract standard
Can execute in interpreter or operate after compiling to machine code.
WASM is an opcode, almost all other languages (C, C++, Rust, Golang, Java, etc.) can be compiled into WASM opcode program.
WASM is basis of distributed system development. It makes smart contract possible to be developed in any language that can be compiled into WASM.
WASM
EOS.IO based blockchain uses Web Assembly (WASM) to operate application code provided by developers. WASM is a standing out web standard, supported by Google, Microsoft, Apple, and other large companies. One of the most used toolsets for building applications with WASM is clang/LLVM and supporting C/C++ compiler.
LLVM
Low Level Virtual Machine (LLVM) is a fundamental structure for building compilers written in C++. The intention of creating the project is that for any programming language, it is possible to build an executor including compiling, linking, and operating. Official LLVM supports C/C++ and Objective-C, while unofficial expansions support ActionScript, Ada, D, Fortran, GLSL, Haskell, Java bytecode, Objective-C, Python, Ruby, Rust, Scala, and C#.