-
Notifications
You must be signed in to change notification settings - Fork 20
Definitions
This page defines the core data structures and roles that exist in Hyperdrive.
Transaction
A transaction is a user-defined data structure that can be executed over some initial state, and execution plan, to transform it into a new output state. A transaction must be executed in full, or not at all. In this way, we say that transactions are atomic.
execute :: (Tx t, State s, Plan p) => t -> s -> p -> s
An ordered list of transactions can be also be executed over some initial state, and execution plan, to transform it into a new output state. The transactions are executed sequentially, and the output state of one execution is used as the initial state for the next execution. An ordered list of transactions can be executed in concurrently if, and only if, the final output state is equal to the output state that would result from sequential execution.
execute :: (Tx t, State s, Plan p) => [t] -> s -> p -> s
execute txs initState plan = foldr (\tx state -> execute tx state plan) initState txs
It is assumed that a transaction can be serialised to/from bytes as required by the peer-to-peer networking and persistent storage device. No other properties or functionalities are assumed.
class Tx t where
serialise :: t -> [Byte]
deserialise :: [Byte] -> t
Plan
A plan is a user-defined data structure that selects precomputed data for the execution of an ordered list of transactions over an initial state. The precomputed data that must be selected by a plan depends on the ordered list of transactions, the initial state, and the secure multi-party algorithm.
Given some ordered list of transactions and initial state, there exists multiple valid plans. Similarly, one plan can be valid for multiple ordered lists of transactions and initial states. However, the same precomputed data must never be selected by multiple plans, and a plan must never be used for execution more than once.
It is assumed that a plan can be serialised to/from bytes as required by the peer-to-peer networking and persistent storage device. No other properties or functionalities are assumed.
class Plan p where
serialise :: p -> [Byte]
deserialise :: [Byte] -> p
State
A state is a user-defined data structure that represents the application-specific state of the blockchain. Unlike other blockchains, Hyperdrive blocks do not store the application-specific state resulting from the execution of their own transactions. Instead, Hyperdrive blocks store the application-specific state resulting from the execution of the transactions in their parent block. This is because secure multi-party computation execution is interactive, and so consensus on a block is not enough to know the application-specific state resulting from the transactions in that block.
The state at height H refers to the state after executing the transactions at height H on the state at height H-1. This can be confusing, because the state at height H is stored in the block at height H+1.
stateAtHeight :: Height -> State
stateAtHeight 0 = genesis
stateAtHeight height = execute (txsAtHeight (height-1)) (stateAtHeight (height-1)) (planAtHeight (height-1))
It is assumed that a state can be serialised to/from bytes as required by the peer-to-peer networking and persistent storage device. It is also assumed that the genesis state is known and is at height 0.
class State s where
genesis :: s
serialise :: s -> [Byte]
deserialise :: [Byte] -> s
Finality
Finality is defined as the moment at which the application-specific state is known and will not revert. The block at height H
achieves finality when the block at height H+1
is committed. This is also the moment when the state at height H
achieves finality.
Block
Blocks are the unit of consensus. They are used to achieve consensus on application-data such as transactions, plans, and states. Blocks are also used to achieve consensus on consensus-specific data such as the currently active signatories.
class Block b where
hash :: b -> [Byte]
header :: (Header h) => b -> h
txs :: (Tx t) => b -> [t]
plan :: (Plan p) => b -> p
prevState :: (State s) => b -> s
All of the consensus-specific data is stored inside the header
. The block hash
is inferred from the header
, txs
, plan
, and prevState
(encoding bytes using a base64 encoding without padding):
computeHash :: (Header h, Tx t, Plan p, State s) => h -> [t] -> p -> s
computeHash header txs plan prevState =
sha256 (printf "BlockHash(Header=%s,Txs=%s,Plan=%s,State=%s)" (show header) (show txs) (show plan) (show prevState))
Signatory
A signatory is a participant in the consensus algorithm that is authorised to propose, prevote, and precommit to messages that are broadcast throughout the various consensus rounds. It is assumed that the number of adversaries is less than, or equal to, F
when there are 3F+1
signatories. Signatories are identified by a sha256
hash of their ECDSA public key.
Block headers can suggest a set of signatories that is responsible for consensus on all future blocks (until a new set is suggested and committed). This is called rebasing.