Bytecode is a low-level, machine-readable representation of code, executed by a virtual machine (VM). Bytecode is a compact binary format consisting of opcodes (operation codes) and data. It acts as an intermediary between high-level source code and the virtual machine, enabling execution of programs.
Developers write source code in high-level programming languages like Solidity, Vyper, Java, and Python which are then compiled into bytecode.
In blockchain development, bytecode is closely linked to smart contracts, which are deployed on blockchains as bytecode.
In Ethereum, Solidity or Vyper source code is compiled into Ethereum bytecode and executed on-chain by the Ethereum Virtual Machine (EVM).
On Solana, Rust source code is compiled into the Solana Bytecode Format (sBPF), a modified version of Berkeley Packet Filter (eBPF) bytecode and is run by Solana's runtime environment.
Other examples include Polkadot, which uses WASM bytecode, executed by its Polkadot Virtual Machine (PVM) and Cosmos, which uses the CosmWasm Virtual Machine (CVM) and WASM bytecode to support modular and scalable smart contract functionality across its ecosystem.
Bytecode ensures cross-platform compatibility, allowing smart contracts to execute identically across all nodes, regardless of the underlying hardware.
Generating bytecode involves compiling high-level source code into a compact, low-level format that virtual machines can interpret and execute.
This process can be broken down into the following steps:
Consider a simple Solidity function:
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;
contract Example {
function add(uint a, uint b) public pure returns (uint) {
return a + b;
}
}
After compilation, it is represented in bytecode like this:
608060405234801561000f575f80fd5b506101a58061001d5f395ff3fe6
08060405234801561000f575f80fd5b5060043610610029575f3560e01c
8063771602f71461002d575b5f80fd5b610047600480360381019061004
291906100a9565b61005d565b60405161005491906100f6565b60405180
910390f35b5f818361006a919061013c565b905092915050565b5f80fd5
b5f819050919050565b61008881610076565b8114610092575f80fd5b50
565b5f813590506100a38161007f565b92915050565b5f8060408385031
2156100bf576100be610072565b5b5f6100cc85828601610095565b9250
5060206100dd85828601610095565b9150509250929050565b6100f0816
10076565b82525050565b5f6020820190506101095f8301846100e7565b
92915050565b7f4e487b710000000000000000000000000000000000000
00000000000000000005f52601160045260245ffd5b5f61014682610076
565b915061015183610076565b925082820190508082111561016957610
16861010f565b5b9291505056fea26469706673582212207c625f8a2583
ea4909fc33bcc9e4218d739a554f4f07971c78b86bdf1fa443a064736f6
c63430008180033
When a user interacts with a smart contract (e.g., submitting a transaction), bytecode stored on the blockchain is executed within the virtual machine sequentially. Execution is deterministic and produces the same result across all nodes in the network.
Execution of bytecode is not free. It consumes computational resources and, thus, gas. Each bytecode instruction has an associated cost reflecting its complexity. Users must pay gas fees to execute smart contracts, and this fee is proportional to the computational work required.
Outside of blockchain, bytecode has been widely used in general programming for decades. Common examples include:
Bytecode is used to ensure portability, platform independence, and efficient execution through virtual machines.