POX Virtual Machine(PVM)
PVM (Pollux Virtual Machine) is the runtime environment for smart contracts on the Pollux network, and each node in the network maintains a PVM entity. The Pollux protocol ensures the continuous, uninterrupted, and immutable operation of this state machine. At any given block in the chain, Pollux has one and only one 'canonical' state, and the PVM is what defines the rules for computing a new valid state from block to block.
From Ledger To State Machine
The concept of a 'distributed ledger' is frequently employed to characterize blockchains like Bitcoin, designed to facilitate decentralized currencies through cryptographic tools. In this context, a cryptocurrency behaves akin to a traditional currency, governed by specific rules that dictate modifications to the ledger. For instance, in Bitcoin, an address cannot spend more cryptocurrency than it has previously received, establishing the foundational rules for all transactions.
While Pollux operates with its native cryptocurrency, POX, adhering closely to the intuitive rules seen in traditional currencies, it goes a step further by introducing a more robust capability—smart contracts. Unlike a straightforward distributed ledger, Pollux functions as a distributed state machine. The state of Pollux is a comprehensive data structure that encompasses not only account information but also a machine state. This machine state can undergo changes from block to block, following a predefined set of rules and executing arbitrary machine code, introducing a level of complexity beyond a simple ledger.
The State Transition Function
The PVM operates similarly to a mathematical function, behaving deterministically by producing a consistent output when given a specific input. To provide a more formal description, we can consider Pollux as having a state transition function:
Given an old valid state (S) and a new set of valid transactions (P), the POLLUX state transition function Y(S, T) produces a new valid output state S'.
State
Within the Pollux network, the state is managed through a substantial data structure known as the Merkle Trie. This intricate structure organizes all accounts by utilizing linked hashes, ultimately converging to a singular root hash stored on the blockchain.
Transaction
Transactions are instructions cryptographically signed by accounts, falling into two distinct categories: system contract transactions and smart contract transactions. The latter encompasses transactions leading to contract message calls and those resulting in contract creation.
Contract creation initiates the establishment of a new contract account, housing compiled smart contract bytecode. When another account initiates a message call to this contract, it executes its bytecode within the PVM.
PVM Instructions
The PVM operates as a stack machine with a depth of 1024 items, where each item is a 256-bit word. This choice of a 256-bit word aligns with the convenience of compatibility with 256-bit cryptography, such as Keccak-256 hashes or secp256k1 signatures.
Compiled smart contract bytecode runs as a series of PVM opcodes, executing standard stack operations like XOR, AND, ADD, SUB, among others. Additionally, the PVM incorporates various blockchain-specific stack operations, including ADDRESS, BALANCE, BLOCKHASH, and more. For a comprehensive list of opcodes, please refer to Pollux opcodes.
The below flowchart shows how PVM works:
The compiler transforms the smart contract into bytecode, which is both readable and executable on the PVM. The PVM processes data using opcodes. The PVM interacts with blockchain data and calls external data interfaces through the Interoperation layer. Upon completion of PVM execution, the status is recorded in the block, and users can inquire about the execution results and status through the API.
Difference from EVM
PVM is compatible with EVM with some differences in details
PVM utilizes energy as opposed to gas, and the current energy price is 420 sun. GASPRICE and BASEFEE provide the energy unit price in PVM.
In PVM, DIFFICULTY and GASLIMIT return zero.
Most opcodes in PVM have comparable energy consumption to EVM, with some being lower (e.g., SLOAD, CALL).
The contract address prefix generated by CREATE2 differs from EVM. PVM adopts 0x37 as the prefix, following the formula keccak256( 0x41 ++ address ++ salt ++ keccak256(init_code))[12:].
For the pre-compiled contract Ripemd160(0x03) in PVM, SHA-256 is computed twice on the input. A new pre-compiled contract will be introduced to implement the standard Ripemd160.
Pre-compiled contract 0x09 in PVM, which corresponds to Blake2F in EVM, is replaced by BatchValidateSign. Refer to TIP-43 for details.
There are two methods to send POX to contracts: Transfer and TriggerSmartContract with a callValue. Transfer does not invoke fallback functions in the contracts.
PVM has new features bases on Pollux characteristics
PVM include CALLTOKEN(0xd0), TOKENBALANCE(0xd1), CALLTOKENVALUE(0d2), and CALLTOKENID(0xd3).
To determine whether an address belongs to a contract, PVM introduces the ISCONTRACT(0xd4) opcode as per TIP-44.
For batch validations involving normal and multiple signatures, PVM incorporates BatchValidateSign(0x09) as outlined in TIP-43 and ValidateMultiSign(0x0a) under TIP-60.
Anonymous contract and Librustzcash-related pre-compiled contracts in PVM include verifyMintProof(0x1000001), verifyMintProof(0x1000002), verifyMintProof(0x1000003), and merkleHash(0x1000004), with details available in TIP-135, TIP-137, and TIP-138.
Freeze/Unfreeze functions in PVM involve FREEZE(0xd5), UNFREEZE(0xd6), and FREEZEEXPIRETIME(0xd7) per TIP-157..
Contract voting-related opcodes and pre-compiled contracts in PVM encompass VOTEWITNESS(0xd8), WITHDRAWREWARD(0xd9), RewardBalance(0x1000006), IsSrCandidate(0x1000006), VoteCount(0x1000007), UsedVoteCount(0x1000008), ReceivedVoteCount(0x1000009), and TotalVoteCount(0x100000a) under TIP-271.
Stake 2.0 related Freeze/Unfreeze/Delegate/UnDelegate functions in PVM include FREEZEBALANCEV2(0xda), UNFREEZEBALANCEV2(0xdb), CANCELALLUNFREEZEV2(0xdc), WITHDRAWEXPIREUNFREEZE(0xdd), DELEGATERESOURCE(0xde), UNDELEGATERESOURCE(0xdf), GetChainParameter(0x100000b), AvailableUnfreezeV2Size(0x100000c), UnfreezableBalanceV2(0x100000d), ExpireUnfreezeBalanceV2(0x100000e), DelegatableResource(0x100000f), ResourceV2(0x1000010), CheckUnDelegateResource(0x1000011), ResourceUsage(0x1000012), TotalResource(0x1000013), TotalDelegatedResource(0x1000014), and TotalAcquiredResource(0x1000015) per TIP-467.
Please note that compatible solutions are currently under discussion. If you are interested, you can participate in the discussion on GitHub ISSUE.
Last updated