State Connector System

Proving the state of any underlying chain for all smart contracts on Flare.

Flare Network is purpose-built for safely interpreting the state of all underlying chains. Other networks either force you to rely on trusted third parties for this, or they force other chains to conform to their standards, in effect changing the independent chain's protocol so they can then begin to communicate. Flare by contrast does not require you to trust anyone but the validators of an underlying chain, and Flare does not require validators from the underlying chains to even be aware that Flare exists.

The state connector system enables Flare to attain the existence, validity and ordering of any transaction from any underlying blockchain. The ability to prove these properties about any transaction from any chain is available freely to all apps on Flare, including the F-asset protocol for representing assets from other networks directly onto Flare.

Design

The high-level premise for how the state connector system operates is best motivated by its threat-model: in order to absorb incorrect state into a Flare Network app from an underlying chain, an attacker would need to compromise:

  1. Your own Flare validator's view of the underlying chain

  2. A majority of other Flare validators' views of the underlying chain

  3. A sustained attack that lasts longer than the number of underlying-chain block confirmations independently required by your app on Flare

This threat model is achieved by requiring each Flare Network validator, no matter how prominently they feature in consensus, to independently observe the ongoing state of all integrated underlying chains. Propositions about the state of an underlying chain are only applied to a validator's local copy of the Ethereum Virtual Machine (EVM) on Flare after the validator independently verifies the proposed underlying-chain state.

In the following sections, the 2-stage mechanism design of the state connector is defined. The first stage enables Flare validators to agree on the span of data from an underlying chain that is currently available, and the second stage involves the actual proof of a transaction from an underlying chain.

Stage 1: Agreement on Data Availability

Before any specific transaction from an underlying chain is proven on Flare, the span of blocks from the underlying chain that are globally available across all Flare validators is first agreed. Anyone is permitted to compete to keep this process alive over time for any underlying chain by submitting data availability proof transactions to Flare. The proof format is simple, and only takes as input:

  • chainId: A numeric identifier for the currently selected underlying chain.

  • ledger: The last ledger index in the series of ledger(s) from the underlying chain currently being proposed as available.

  • dataAvailabilityPeriodHash: The keccak256 hash of the underlying chain's designated hash for ledger.

  • chainTipHash: The keccak256 hash of a newly created ledger which has several confirmations fewer than ledger does. For example, if a chain requires 10 confirmations, and dataAvailabilityPeriodHash pertains to ledger 100; then chainTipHash would pertain to ledger 110.

https://gitlab.com/flarenetwork/flare/-/blob/2cf0ec69603899049c2193dc76fa0e651f2461d2/src/stateco/StateConnector.sol#L128

function proveDataAvailabilityPeriodFinality(
uint32 chainId,
uint64 ledger,
bytes32 dataAvailabilityPeriodHash,
bytes32 chainTipHash
) external isInitialised chainExists(chainId) senderNotBanned returns (
uint32 _chainId,
uint64 _ledger,
uint16 _numConfirmations,
bytes32 _dataAvailabilityPeriodHash
)

Verifying a Data Availability Proof

An initial viability check is performed using a standard EVM state transition call: st.evm.Call(from, to, data, gas, value). However, this call is performed separately and ahead of the actual state transition call that changes the EVM state.

https://gitlab.com/flarenetwork/flare/-/blob/2cf0ec69603899049c2193dc76fa0e651f2461d2/src/coreth/state_transition.go#L326

// Check if this transaction pertains to a state connector transaction
if selectProveDataAvailabilityPeriodFinality || selectProvePaymentFinality || selectDisprovePaymentFinality {
// Increment the nonce for the next transaction
st.state.SetNonce(msg.From(), st.state.GetNonce(sender.Address())+1)
// Charge extra gas for state connector transactions beyond EVM gas use due to the additional golang computations
stateConnectorGas := st.gas / GetStateConnectorGasDivisor(st.evm.Context.Time)
// Check basic viability of the data availability proof
checkRet, _, checkVmerr := st.evm.Call(sender, st.to(), st.data, stateConnectorGas, st.value)
if checkVmerr == nil && binary.BigEndian.Uint32(checkRet[28:32]) < GetMaxAllowedChains(st.evm.Context.BlockNumber) {
// Basic viability test passed
// Verify the data availability proof by contacting your underlying chain validator
if StateConnectorCall(msg.From(), st.evm.Context.Time, st.data[0:4], checkRet) {
// Proof was verified
originalCoinbase := st.evm.Context.Coinbase
defer func() {
st.evm.Context.Coinbase = originalCoinbase
}()
// Create signal that proof has been verified
st.evm.Context.Coinbase = st.msg.From()
}
}
// The data availability proof is only permitted to transition EVM state
// in this call if st.evm.Context.Coinbase == st.msg.From()
ret, st.gas, vmerr = st.evm.Call(sender, st.to(), st.data, stateConnectorGas, st.value)
}

After the initial viability check, the values checkRet and checkVmerr are returned at the golang-level from the initial call of proveDataAvailabilityPeriodFinality. checkRet contains the values {_chainId, _ledger, _numConfirmations, _dataAvailabilityPeriodHash}, and checkVmerr is equal to nil if the initial viability test passes. These outputs mirror their correspondingly-named function inputs, with the exception of _numConfirmations, which was retrieved from the state connector contract storage given the inputted chainId. The value of _numConfirmations represents the number of consensus confirmations to judge a block on an underlying chain as being finalised; this primarily applies to proof-of-work based chains and is set to at least 1 for instant-finality chains.

The next step is that your underlying chain validator is directly contacted via a URL endpoint that you provided to your Flare validator on its launch. The values in checkRet are used to determine if dataAvailabilityPeriodHash matches the keccak256 hash of the regularly formatted hash of the ledger from this presently-considered underlying chain. The system for this features complete error-handling to continually request the information until it becomes available on your underlying-chain validator, and it permits multiple chosen underlying-chain validators as backups in case of failed requests. There is no time-limit to this process reaching completion; however, the Flare Network will continue without you once others return from this external call step and transition the EVM state. Your own validator's EVM state will only ever be transitioned once your call to your own underlying chain validator returns an answer about the correctness of dataAvailabilityPeriodHash, meaning that no proof or amount of Flare validators can force you to assume an incorrect state as long as your underlying-chain validator is safe.

Once the prior step returns and if it was successful, the block.coinbase value in the EVM is changed to the value of msg.sender. The value of block.coinbase is typically used on a blockchain to define the rewarded address for successfully being the leader that mines a block. However, the Avalanche consensus protocol is a leaderless protocol, so the value of block.coinbase is disused and normally hard-coded to 0x0100000000000000000000000000000000000000. This step of changing block.coinbase to the successful data-availability proof sender is used to indicate to the state connector contract that the data availability proof transaction is verified.

Stage 2: Proving a Transaction

The process of proving a transaction from an underlying chain is then straightforward and just involves sending a single transaction that provides:

  1. {chainId, dataAvailabilityPeriodIndex, dataAvailabilityPeriodHash} for determining that the payment is contained within a data-available region.

  2. paymentHash: The keccak256 hash of the underlying chain payment's regularly formatted hash, ledger number, source account, destination account, destination tag and amount sent. The pre-image of paymentHash isn't provided at this stage within the EVM transaction.

  3. txId: The regularly formatted hash of the underlying chain payment.

A similar 2-phase mechanism as in the data availability proof system involving the use of a pre-check for basic viability is performed by first checking that the payment exists within a data-available region. If the basic test passes, then the system calls on your underlying chain validator to retrieve the details from the payment using its txId. The system ensures that a retrieved payment exists within the data availability region. The retrieved payment details are then used as the pre-image to construct a keccak256 hash that matches the form of paymentHash, and if the constructed hash matches the value of paymentHash then the payment is deemed to be valid and it's stored in the state connector contract storage for reference by any other contract on Flare that wants to check that the pre-image of paymentHash was finalised to Flare.

One can also prove that a payment has not occured by a certain block height on the underlying chain: https://gitlab.com/flarenetwork/flare#verify-an-underlying-chain-payment-on-flare

Simple Payment Verification (SPV) Proofs Considered Harmful

A simple payment verification (SPV) proof is a way to prove to a blockchain that a payment has occurred on another blockchain. The proof typically consists of a header that contains a consensus proof such as a proof-of-work, or a signed k-of-n multisignature from a set of validators that are currently believed to be in control of the underlying chain being presently considered. The SPV proof itself then just contains a merkle-tree based set of hashes that proves that a provided payment forms the pre-image to a hash that is contained within the provided merkle tree.

One of the main advantages of a blockchain is that we do not depend on its validators for anything other than being tie-breakers in sequencing transactions. That is, validators on a blockchain cannot insert erroneous transactions into the network that do not conform to the state transition rules that everyone agrees to run. For example, as a miner on a blockchain, one cannot compel the movement of a single coin that does not belong to them, the only way to do so is to sign a valid transaction that can be traced all the way back to the network genesis state as having a valid transfer of ownership history.

However, an SPV proof breaks this separation of powers guarantee -- it permits validators to now submit an isolated merkle tree proof that is self-referential and cannot be tied back to the genesis of the network. For example, if validators collude to manufacture a false SPV proof, they could convince a separate blockchain that a transaction sending them a billion units of an asset has occurred, when they had in fact never owned such an amount.

SPV proofs are also complicated for non-proof-of-work chains by having to keep track of changing validator sets on an underlying chain over time. Consider the scenario where an outgoing set of validators from an underlying chain refuses to sign a proof to Flare that they are now leaving power -- what penalty do they have for refusing to do this? Trying to manage validator sets in this way relies on the enforcement of bad behavior to be conducted by the same set of operators that have performed the bad behavior.

SPV proofs are therefore considered harmful for the purpose of proving the state of an underlying chain to another network. The approach escalates the privilege of underlying chain validators to be able to falsify the ownership of an asset, and the enforcement of bad behavior in the approach must be conducted by the same set of operators that have performed the bad behavior.

State Connector System Advantages

The state connector system is a competitive approach for proving the state of an underlying chain to a smart contract, and it has the following advantages:

  1. Transaction validity references back to an underlying chain's genesis block: Other approaches like the SPV proof do not check the validity of a transaction.

  2. Safety only depends on an underlying chain's validators: There is no trusted third-party service that has its own set of economic incentives and risks. Trust is minimized by leveraging the guarantee that safety can only be lost in the state connector if an underlying chain's validators encounter a Byzantine fault.

  3. No cooperation needed from an underlying chain's validators: Validators from an underlying chain do not need to modify their chain's code base to permit Flare to interpret their network. An underlying chain's validators do not even need to be aware that Flare exists in order for the state connector system to operate.

  4. Can read the state of any blockchain: The state connector can operate on any possible Sybil-resistance technique of an underlying chain. For example: proof-of-work, proof-of-stake and even federated byzantine agreement where there is not global agreement on the set of validators in control of a network.

  5. No encoding of the current validators in control of an underlying chain to a smart contract on Flare: This requirement of other state-relay approaches such as the SPV proof leads to the hazardous scenario where the enforcement of bad behavior in relaying state needs to be conducted by the same set of operators that have performed the bad behavior.

  6. Constant-sized proofs: both the data availability proof and the payment proof are constant-sized, independent of the number of other payments in the data availability period being considered.

  7. Every Flare validator independently verifies an underlying chain's state: If your own Flare validator observes the canonical state of an underlying chain, then you will not lose safety against that chain.