Off-chain
Each party keeps a state tree specific for the channel. It represents the
channel state at a certain point of time. It consists of all the channel data:
accounts and contracts. Since it has the same structure as the on-chain state
tree, the names and oracles subtrees are empty as those are not allowed off-chain. Thechannels subtree is empty as well, as it is reserved for future use.
Off-chain transactions update this channel auxiliary tree.
It is the responsibility of the parties to keep this locally. This is the safety guarantee in a case of a dispute: the solo closing path requires a proof of inclusion for subtree instead of posting the whole tree. Being able to provide this proof of inclusion allows a participant to dispute a malicious close by the other party or for basing a forced progress.
Each off-chain update consists of updates being applied on top of channel
state tree as well with an integer value round representing when it
happened. Since round must always be bumped, provided two off-chain
transactions we can reason which was performed earlier than the other.
Messages
Overview
The protocol parties use to run smart contracts is a two-phase commit
protocol, where one party proposes a change, gets it authenticated by the
other and then commits the update locally. These checks are necessary to avoid
parties getting confused if updates are being proposed simultaneously. On a
higher level, to keep off-chain and on-chain state in sync, parties should
refuse to authenticate updates for either without also getting an
authentication for the updates state_hash, e.g. don't authenticate an on-chainchannel_deposit transaction without also updating the channel state trees
as well. Authentication method differences depending on whether the transaction
is on-chain or off-chain one can be found here.
With the consistency of state updates being secured between parties, it is essential that parties make absolutely sure to not lose their local state, since it could potentially lead to them not being able to slash outdated states published on-chain.
Control messages
Framing
Each message is identified by a 1-byte message code. The size of the following message is defined by the type – see the description of each individual message type.
name size (bytes)
---------------------- ----
| msg_type | 1 |
---------------------- ----
| message | .. |
---------------------- ----The following message codes are defined:
type code
-------------------------
| channel_open | 1 |
| channel_accept | 2 |
| channel_reestabl | 3 |
| channel_reest_ack| 4
| funding_created | 5 |
| funding_signed | 6 |
| funding_locked | 7 |
| update | 8 |
| update_ack | 9 |
| update_error | 10 |
| deposit_created | 11 |
| deposit_signed | 12 |
| deposit_locked | 13 |
| deposit_error | 14 |
| withdraw_created | 15 |
| withdraw_signed | 16 |
| withdraw_locked | 17 |
| withdraw_error | 18 |
| leave | 94 |
| leave_ack | 95 |
| inband_message | 96 |
| error | 97 |
| shutdown | 98 |
| shutdown_ack | 99 |
-------------------------error
errorMessage code: 97
Explicitly communicating errors should make debugging easier. In order to avoid complex error handling, which tends to be prone to mistakes, once a channel returns an error, it MUST be considered unusable. As such, errors SHOULD be reserved for unrecoverable failures only.
name size (bytes)
---------------------- ----
| channel_id | 32 |
---------------------- ----
| length | 2 |
---------------------- ----
| data | |
---------------------- ----channel_id: the temporary or final channel idlength: length of data field(optional)
data: relevant information
ping/pong
ping/pongSub-messages
The following serializations can be consistently used below.
Updates list
Progress off-chain is achieved by one participant proposing a set of updates to be applied on top of the last state as well as the next state that is produced. A single off-chain update's serialization has the following structure:
name size (bytes)
---------------------- ----
| length | 2 |
---------------------- ----
| data | N |
---------------------- ----The length is the size of the data field.
A list of updates is a appended list of 0 or more such updates.
Establishing channel off-chain
A (initiator) B
| |
|--- channel_open -->|
|<-- channel_accept ---|
| |
|-- funding_created -->|
|<- funding_signed ---|
| |
|--- funding_locked -->|
|<-- funding_locked ---|
| |In order to establish a channel both parties need to agree on the initial conditions, e.g. funding amounts, minimum reserve and lock time.
By default the initiator of the channel will pay the fee for the opening transaction.
channel_open
channel_openMessage code: 1
This message initiates the opening of a channel and communicates the initiators' intent to a potential future party.
The channel_open message should provide the accepting party all the
information it needs to assess whether or not it should accept the channel.
name size (bytes)
---------------------- ----
| chain_hash | 32 |
---------------------- ----
| temporary_channel_id | 32 |
---------------------- ----
| lock_period | 2 |
---------------------- ----
| push_amount | 8 |
---------------------- ----
| initiator_amount | 8 |
---------------------- ----
| responder_amount | 8 |
---------------------- ----
| channel_reserve | 8 |
---------------------- ----
| initiator_pubkey | 32 |
---------------------- ----
| responder_pubkey | 32 |
---------------------- ----chain_hash: genesis block hash of the chain you want to usetemporary_channel_id: randomly chosen id unique between the involved partieslock_period: time measured in key blocks in which unilateral channel events can be disputedpush_amount: initial deposit in favour of the responder by the initiatorinitiator_amount: amount the initiator is willing to commitresponder_amount: amount the initiator wants the responder to commitchannel_reserve: the minimum amount both parties need to maintain, amount of coins a party is to lose in case of acting maliciouslyinitiator_pubkey: the account that the initiator wants to use to open the channelresponder_pubkey: the account that the initiator expects as a responder on the channel
(TODO: what's the appropriate size for the amounts. Do we want to discourage channels from holding big amounts?)
(TODO: should the initiator send along fee and nonce as well so that the
responder can assemble the channel_create themselves?)
In the future state channels might exist across different chains, at which point
specifying a chain_hash will become meaningful.
The lock_period can be chosen freely. Setting it too high might lock up funds
for too long in the case of non-cooperation and setting it too low could leave
a party without enough time to react to a malicious party trying to unilaterally
close a channel.
Having the ability to include a push_amount, which credits funds to the other
party, simplifies the common case of wanting to open a channel and pay someone
immediately. An exchange might want to send you funds via this mechanism, since
it requires only one on-chain transaction and has the side effect of also
opening a channel.
If push_amount > 0 then the initiator should send along an authenticated
update, assigning that amount to the responder, before sending thefunding_created message.
A channel_reserve ensures that parties have something to lose in the case that
they start acting maliciously. Enforcement of this rule must be done by the
clients, which in practice means they should not authenticate any updates that
end up violating this invariant.
Requirements
Initiator:
chain_hashMUST identify the chain to be usedtemporary_channel_idMUST be unique between the involved partieslock_periodSHOULD be sufficient time to safely publish transactions to the blockchain to stop a cheaterpush_amountMUST be less or equal toinitiator_amountinitiator_pubkeyMUST be a valid ed25519 pubkey
Responder MUST abort if:
chain_hashis unrecognisedinitiator_pubkeynot a valid ed25519 pubkeytemporary_channel_idis not unique between the parties
Responder SHOULD abort if:
initiator_pubkeydoes not have sufficient balance to coverinitiator_amount
Responder MAY abort if:
lock_periodis too smallpush_amountis too smallchannel_reserveis too large or smallresponder_amountis too largeinitiator_amountis too small
channel_accept
channel_acceptMessage code: 2
This message is sent by the responding party. It is used to convey the
conditions under which they are willing to accept the terms proposed by the
initiating party.
name size (bytes)
---------------------- ----
| chain_hash | 32 |
---------------------- ----
| temporary_channel_id | 32 |
---------------------- ----
| minimum_depth | 4 |
---------------------- ----
| initiator_amount | 8 |
---------------------- ----
| responder_amount | 8 |
---------------------- ----
| channel_reserve | 8 |
---------------------- ----
| initiator_pubkey | 32 |
---------------------- ----
| responder_pubkey | 32 |
---------------------- ----chain_hash: genesis block hash of the chain you want to usetemporary_channel_id: randomly chosen id unique between the involved parties,minimum_depth: number of blocks until an opening transaction should be considered final. Theminimum_depthis set by the responding party, since they will typically be the one providing a service. Note that aminimum_depthof 0 (zero) will result in a microblock confirmation (see below).initiator_amount: amount the initiator is willing to commitresponder_amount: amount the initiator wants the responder to commitchannel_reserve: the minimum amount both parties need to maintain. This makes sure that both have to lose something in case they act maliciouslyinitiator_pubkey: the account that the initiator used to open the channelresponder_pubkey: the account that the responder used to open the channel
Requirements
Responder:
chain_hashMUST identify the chain to be usedtemporary_channel_idMUST be unique between the involved partieslock_periodSHOULD be sufficient time to safely publish transactions to the blockchain to stop a cheaterresponder_pubkeyMUST be a valid ed25519 pubkey
Microblock confirmation
As outlined in this Bitcoin-NG blog post, an NG microblock offers strictly stronger guarantees than a 0-confirmation in Bitcoin. In æternity, when the minimum-depth confirmation is set to zero, the system will still wait until the transaction is seen inside a microblock. This will mean that the transaction has been gossiped, picked up from the mempool and accepted by a miner.
Note that high-value transactions should wait for a number of keyblocks in order to guard against forks reorganizing the chain, but a microblock confirmation offers at least a receipt of that the transaction was initially accepted.
channel_reestablish
channel_reestablishMessage code: 3
It is possible to resume a channel which has been terminated either due to client failure or by the participants mutually agreeing to leave.
name size (bytes)
---------------------- ----
| chain_hash | 32 |
---------------------- ----
| channel_id | 32 |
---------------------- ----
| length | 2 |
---------------------- ----
| data | N |
---------------------- ----The payload (data) must be the latest mutually authenticated offchain state,
and the clients must verify that they have the corresponding state trees to
match the state (otherwise, it will not be possible to use the channel later
on.)
In the æternity node implementation, the state trees are cached inside the node. Note that if the node restarts, cached data is not likely to survive (it is not persisted on each update for performance reasons.) The æternity node channel FSM automatically recovers the state trees and verifies that the provided state is in fact the last mutually authenticated state.
Requirements
Responder:
MUST abort if the
chain_iddoesn't match the current chain.MUST abort if the payload does not correspond to the last known mutually authenticated state.
MUST abort if it doesn't have a corresponding state tree (is able to verify proof-of-inclusion) for the provided state.
channel_reestablish_ack
channel_reestablish_ackMessage code: 4
name size (bytes)
---------------------- ----
| chain_hash | 32 |
---------------------- ----
| channel_id | 32 |
---------------------- ----
| length | 2 |
---------------------- ----
| data | N |
---------------------- ----This is a response message to channel_reestablish, expected to contain
identical information.
Requirements
Initiator:
MUST abort if contents do not match exactly, those of the preceding
channel_reestablishMUST abort if the
chain_iddoesn't match the current chain.MUST abort if the payload does not correspond to the last known mutually authenticated state.
MUST abort if it doesn't have a corresponding state tree (is able to verify proof-of-inclusion) for the provided state.
funding_created
funding_createdMessage code: 5
In order to open a channel on chain, parties need to cooperate and mutually
authenticate the channel_create transaction. The funding_created message
is used by the initiator to send an initial state - a channel_create_tx
object, authenticated by the Initiator. The block_hash specifies which
on-chain environment was used to prepare the transaction ensuring both
participants share a common view of the chain.
name size (bytes)
---------------------- ----
| temporary_channel_id | 32 |
---------------------- ----
| block_hash | 32 |
---------------------- ----
| length of create tx | 2 |
---------------------- ----
| channel_create tx | N |
---------------------- ----
| list of updates | |
---------------------- ----Requirements
Responder:
MUST abort if the size of the serialized channel_create transaction does not match
lengthMUST abort if the
datacannot be deserialized into a validchannel_create_txobjectMUST abort if the provided
block_hashis not part of the main chain as the responder sees it or if one considers it too oldMUST abort if the authentication method used is invalid for the provided transaction data on the current top block
MUST abort if disagrees with updates provided
funding_signed
funding_signedMessage code: 6
If the responder was able to validate the initiator's authentication method
sent in the funding_created message, then it should add its own authentication
to the state object. The mutually authenticated object will become the initial
off-chain state of the channel. Responder provides the block_hash to specify
which on-chain environment was used for producing the signature or meta
transaction.
name size (bytes)
---------------------- ----
| temporary_channel_id | 32 |
---------------------- ----
| block_hash | 32 |
---------------------- ----
| length | 2 |
---------------------- ----
| channel_create tx | N |
---------------------- ----Requirements
Initiator:
MUST abort if the size of the channel_create transaction does not match
lengthMUST abort if the
datacannot be deserialized into a validchannel_create_txobjectMUST abort if the
dataobject isn't the offered initial stateMUST abort if the
dataobject isn't mutually authenticated by both parties.MUST abort if the
block_hashis too old
funding_locked
funding_lockedMessage code: 7
Opening a channel requires an on-chain transaction. This transaction needs to be included in a block and, since we only have probabilistic finality, be sufficiently confirmed, so that the probability of a chain re-organisation is negligible.
This message is exchanged by both parties to signal to each other that the above condition has been met from their point of view and only after both of them agree on this, can the channel be considered to be opened.
All subsequent messages must use the included channel_id instead of thetemporary_channel_id.
name size (bytes)
---------------------- ----
| temporary_channel_id | 32 |
---------------------- ----
| channel_id | 32 |
---------------------- ----Requirements
A node MUST NOT send the
funding_lockedmessage unless thechannel_createtransaction hasminimum_depthconfirmations.
State update
State updates require consent of both parties.
Each update MUST have a strictly increasing round, which SHOULD start
at 0 on channel initialisation.
Parameters:
channel_id:balances:state
update
updateMessage code: 8
Once funding_locked messages have been exchanged, the channel enters theopen state. Changes to the off-chain state can be effected by sending anupdate message. It consists of a single-authenticated off-chain transaction
and a list of updates list containing the operations to be performed on the
previous state. The state_hash of the off-chain transaction is the
aggregated root hash of the resulting state trees after the updates had been
applied. The receiver must verify that the state is the correct outcome, then
return it, mutually authenticated, in an update_ack message.
The block_hash is the hash of which on-chain environment was used for
computing the state and either this block or any more recent one could be used
to validate the state. Signatures or Generic Account's meta transactions are
checked according to the latest channel object persisted on-chain. If there are
updates that are contact executions using on-chain data: the block ofblock_hash is being used for building a consistent state on each
participant's side.
name size (bytes)
---------------------- ----
| channel_id | 32 |
---------------------- ----
| block_hash | 32 |
---------------------- ----
| length | 2 |
---------------------- ----
| channel_offchain tx | N |
---------------------- ----
| list of updates | |
---------------------- ----update_ack
update_ackMessage code: 9
In response to an update message, the receiving side validates that the received
updates are indeed desired. Then one verifies that the operations
listed in the updates list, applied to the most recent mutually authenticated
state, results in a state tree corresponding to the state_hash in the
transaction. If so, the state object is mutually authenticated, then returned
as payload in an update_ack message. The block_hash denotes the the
on-chain environment in which the authentication was done. The authentication
method described in the latest channel on-chain persisted object must be used.
name size (bytes)
---------------------- ----
| channel_id | 32 |
---------------------- ----
| block_hash | 32 |
---------------------- ----
| length | 2 |
---------------------- ----
| channel_offchain tx | N |
---------------------- ----update_error
update_errorMessage code: 10
Since both sides may initiate an update request, it is possible that both
may do so at roughly the same time. In particular, in the æternity node system,
if an update request arrives while the FSM is waiting for its client to
authenticate a new state update, it reverts both its own update attempt and the
other participant's update request by sending an update_error message.
The round element signifies the round of the fallback state, which must
be the last mutually authenticated state. The receiver does not reply.
name size (bytes)
---------------------- ----
| channel_id | 32 |
---------------------- ----
| round | 4 |
---------------------- ----deposit_created
deposit_createdMessage code: 11
In order to deposit more funds into the channel, one party can initiate
a deposit_created request. It consists of a single-authenticatedchannel_deposit_tx transaction as well as a list of updates. The transaction
includes the state hash and round of the next off-chain state, after applying
the updates on top of latest state.
Note that it is possible to deposit a zero amount, essentially making the operation an on-chain snapshot.
The receiving side verifies the operation and authenticate the state, returning
it in an deposit_signed message.
The block_hash defines the block used for deposit creation and
depositor's authentication method will be according to the latest on-chain
persisted account and not the on-chain persisted channel object.
name size (bytes)
---------------------- ----
| channel_id | 32 |
---------------------- ----
| block_hash | 32 |
---------------------- ----
| length of deposit tx | 2 |
---------------------- ----
| channel_deposit tx | N |
---------------------- ----
| list of updates | |
---------------------- ----deposit_signed
deposit_signedMessage code: 12
This is an acknowledgement of a preceding deposit_created message (see
above). Upon receipt of a mutually authenticated state, the receiver verifies
that it is indeed the state resulting from the proposed deposit operation. Thechannel_deposit_tx is then pushed to the chain, and the requested number of
confirmations (minimum_depth) are awaited. Once confirmation has been
received, a deposit_locked message is sent, with the hash of thechannel_deposit_tx transaction.
The block_hash defines at which block deposit had been mutually
authenticated and the second authentication will be according to the latest
on-chain persisted account and not the on-chain persisted channel object.
name size (bytes)
---------------------- ----
| channel_id | 32 |
---------------------- ----
| block_hash | 32 |
---------------------- ----
| length of deposit tx | 2 |
---------------------- ----
| channel_deposit tx | N |
---------------------- ----deposit_locked
deposit_lockedMessage code: 13
This message is sent upon receipt of a minimum_depth confirmation for achannel_deposit_tx transaction. The payload is the hash of thechannel_deposit_tx transaction object. Once the message has been sent,
the channel returns to the open state and the new off-chain state is
useable.
name size (bytes)
---------------------- ----
| channel_id | 32 |
---------------------- ----
| tx hash | 32 |
---------------------- ----deposit_error
deposit_errorMessage code: 14
Since both sides may initiate a deposit_created request, it is possible
that both may do so at roughly the same time. In particular, in the æternity node
system, if a deposit_created request arrives while the FSM is waiting for
its client to authenticate a new state update, it reverts both its own update
attempt and the other participant's update request by sending a deposit_error
message. The round element signifies the round of the fallback state, which
must be the last mutually authenticated state. The receiver does not reply.
name size (bytes)
---------------------- ----
| channel_id | 32 |
---------------------- ----
| round | 4 |
---------------------- ----withdraw_created
withdraw_createdMessage code: 15
In order to withdraw coins from the channel, one party can initiate
a withdraw_created request. It consists of a single-authenticatedchannel_withdraw_tx and a list of updates. The transaction includes the state
hash and round of the next off-chain state, after applying the updates.
Note that it is possible to withdraw a zero amount, essentially making the
operation an on-chain snapshot.
The receiving side verifies the operation and mutually authenticated the state,
returning it in an withdraw_signed message.
The block_hash defines on which block the withdrawal had been created and
the withdrawer authentication method will be according to the latest on-chain
persisted account and not the on-chain persisted channel object.
name size (bytes)
---------------------- ----
| channel_id | 32 |
---------------------- ----
| block_hash | 32 |
---------------------- ----
| length of withdrawal | 2 |
---------------------- ----
| channel_withdraw_tx | N |
---------------------- ----
| list of updates | |
---------------------- ----withdraw_signed
withdraw_signedMessage code: 16
This is an acknowledgement of a preceding withdraw_created message (see
above). Upon receipt of a mutually authenticated state, the receiver verifies
that it is indeed the state resulting from the proposed withdrawal operation.
The channel_withdraw_tx is then pushed to the chain, and the requested number
of confirmations (minimum_depth) are awaited. Once confirmation has been
received, a withdraw_locked message is sent, with the hash of thechannel_withdraw_tx transaction.
The block_hash defines on which block the withdrawal had been mutually
authenticated and the second authentication method will be according to the
latest on-chain persisted account and not the on-chain persisted channel object.
name size (bytes)
---------------------- ----
| channel_id | 32 |
---------------------- ----
| block_hash | 32 |
---------------------- ----
| length of withdrawal | 2 |
---------------------- ----
| channel_withdraw_tx | N |
---------------------- ----withdraw_locked
withdraw_lockedMessage code: 17
This message is sent upon receipt of a minimum_depth confirmation for achannel_withdraw_tx transaction. The payload is the hash of thechannel_withdraw_tx transaction object. Once the message has been sent,
the channel returns to the open state and the new off-chain state is
useable.
name size (bytes)
---------------------- ----
| channel_id | 32 |
---------------------- ----
| tx hash | 32 |
---------------------- ----withdraw_error
withdraw_errorMessage code: 18
Since both sides may initiate a withdraw_created request, it is possible
that both may do so at roughly the same time. In particular, in the æternity node
system, if a withdraw_created request arrives while the FSM is waiting for
its client to authentication a new state update, it reverts both its own update
attempt and the other participant's withdraw request by sending awithdraw_error message. The round element signifies the round of the
fallback state, which must be the last mutually authenticated state. The
receiver does not reply.
name size (bytes)
---------------------- ----
| channel_id | 32 |
---------------------- ----
| round | 4 |
---------------------- ----Other interaction
inband_message
inband_messageMessage code: 96
Inband messages are arbitrary messages sent between the channel participants. The payload must be limited to 65,535 bytes. The FSM must deliver an inband message immediately, and the receiver must process it (e.g. conveying it to the client) immediately, preserving the message ordering.
One possible use of inband messages could be to synchronize off-chain state updates, but any application is allowed.
name size (bytes)
---------------------- ----
| channel_id | 32 |
---------------------- ----
| length | 2 |
---------------------- ----
| data | N |
---------------------- ----Channel closing
leave
leaveMessage code: 94
While it is possible to simply drop out of a channel and later reestablish it,
the success of the reestablishing operation depends on the other party keeping
the most recent copy of the state. The polite way to ensure this is to send
a leave request. The receiving side is expected to respond with a leave_ack.
name size (bytes)
---------------------- ----
| channel_id | 32 |
---------------------- ----leave_ack
leave_ackMessage code: 95
This message is sent in response to a leave request. The sender may terminate
its side once the message has been delivered. The receiver should wait for
the leave_ack before it terminates.
name size (bytes)
---------------------- ----
| channel_id | 32 |
---------------------- ----shutdown
shutdownMessage code: 98
In order to close the channel in an orderly fashion, a shutdown message
is sent, passing a singly authenticated channel_close_mutual_tx transaction
object as payload. The sender creates the channel_close_mutual_tx from the
latest mutually authenticated state, including the root hash of the
corresponding state tree. The receiver must verify that the payload corresponds
to its latest mutually authenticated state, and then replies with ashutdown_ack message. The block_hash defines on which block the close
mutual had been created and the closer's authentication method will be according
to the latest on-chain persisted account and not the on-chain persisted channel
object.
name size (bytes)
---------------------- ----
| channel_id | 32 |
---------------------- ----
| block_hash | 32 |
---------------------- ----
| length | 2 |
---------------------- ----
| close mutual tx | N |
---------------------- ----shutdown_ack
shutdown_ackMessage code: 99
This message is sent in response to a verified shutdown message. The sender
may close once the message has been delivered. The receiver must, after
verifying the payload of the shutdown_ack message (which must be the samechannel_close_mutual_tx object, mutually authenticated), push thechannel_close_mutual_tx transaction onto the chain, and then terminate.
The block_hash defines on which block the close mutual had been mutually
authenticated and the second authentication method will be according to the
latest on-chain persisted account and not the on-chain persisted channel object.
name size (bytes)
---------------------- ----
| channel_id | 32 |
---------------------- ----
| block_hash | 32 |
---------------------- ----
| length | 2 |
---------------------- ----
| close mutual tx | N |
---------------------- ----Channel closing
A channel can be closed under three circumstances:
Both parties agree to the close and authenticate the closing transaction together, which then gets broadcasted and included in the blockchain.
One party wants to close the channel: the other party might had been missing for some time or had been trying to cheat. In this case either side can publish the latest state authenticated by both parties and claim their balance after the negotiated timeout.
A malicious party tries to publish an outdated state, which it prefers over a later state. In this case the honest party can publish a state authenticated by both with a higher round and thereby prove that the other one is trying to cheat. A transaction with a higher round overwrites the one with a lower one.
In the case that both parties decide to close the channel, funds are accessible
immediately after the transaction of their agreement is included in a block,
otherwise they have to wait at least lock_period blocks for disputes.
A B
| |
|---- shutdown --->|
|<--- shutdown ----|
| . |
| . |
| resolve pending op |
| . |
| . |
| . |
|<-- closing_created ---|
|--- closing_signed -->|
| |In case of both parties want to close the channel in agreement and there are enough coins left in the channel to pay for the fee, then the the advised distribution of returning the coins left in the channel is as follows:
if initiator_amount + responder_amount < fee
return error
else if initiator_amount >= ceil(fee/2) && responder_amount >= floor(fee/2)
initiator_final := initiator_amount - ceil(fee/2)
responder_final := responder_amount - floor(fee/2)
else if responder_amount >= ceil(fee/2) && initiator_amount >= floor(fee/2)
responder_final := responder_amount - ceil(fee/2)
initiator_final := initiator_amount - floor(fee/2)
else if initiator_amount > responder_amount
initiator_final := initiator_amount - fee + responder_amount
responder_final := 0
else
responder_final := responder_amount - fee + initiator_amount
initiator_final := 0This is an example distribution of the fee. If this is to be accepted as a norm - it means that one of the parties will propose these final amounts in the closing transaction and the other, also following this advise, will happily authenticate it. What ends up on-chain is the fee and the closing amounts of the parties. The process by which they got to agreement is not part of the protocol itself.
shutdown
shutdown name size (bytes)
---------------------- ----
| channel_id | 32 |
---------------------- ----The shutdown message initiates the closing of a channel and can be sent by
either party. After a party sends the shutdown message, it MUST NOT propose any
more update messages.
Requirements
A shutdown cannot be initiated before the on-chain channel opening is authenticated.
The initiator MUST NOT send a shutdown before a funding_created and the
responder MUST NOT send a shutdown before a funding_signed has been sent.
Prior to the respective points parties can still safely abort the procedure
without having committed to anything.
closing_created
closing_createdIf the parties agree to a shutdown then they both need to authenticate thechannel_close_mutual transaction
closing_signed
closing_signedLocal state
Parties need to store local state in order to be able to keep track of state channel operations.
chain_hashinitiator_pubkeyresponder_pubkeyinitiator_amountresponder_amountchannel_activeroundupdated_atclosed[{}]
Contracts
Execution of a contract inside a state channel requires parties to be able to initialise a virtual machine to run their smart contracts in.
Contracts are executed in rounds, which are denoted by round attribute.
Every party executes each smart contract locally and checks if the authenticated state they receive match up with theirs. In the case that state and authentication are valid, they apply the update and then send out their own authentication. If there was an error in either the execution of the contract or the authentication failed, they send a new update with the prior state but an increased round number—to avoid confusion–and their authentication method over it, to signal that something went wrong.
When operating in mutually authenticated mode, contracts might need to be written in a way to avoid the free option problem.
On-chain enforcement
submit code, state, inputs
code should output new distribution of balances?
submit a hash of what is expected to be the root of the new state
parties could choose to continue from there
With on chain enforcement of contracts it becomes possible to unilaterally force progress by publishing contract, state and input on chain. A miner would then execute the contract given the state and inputs to produce a new state. This new state could then either be used for both parties to continue operation from there or leave it at that.
Contracts lifecycle
Contracts are part of the update mechanism: it is different updates that are being used. Serialization of those can be found here.
First one participant initiates an update round containing a channel create contract update. It contains all the information needed for a contract creation. The other participant authenticates the changes and the contract is considered to be created.
After a contract is created it can be called. For this one of the participants
initiates an update round containing a channel call
contract update.
It contains all the information needed for a contract call, including the
contract address. The other participant authenticates the changes and the contract
call is considered to be executed. Its results can be extracted from the calls
tree in the state tree.
Part of the call is the amount a participants commits to the contract. This
is not to be confused with gas consumption - amount are
the coins moved from the caller's off-chain balance to the off-chain balance
of the contract been called.
Contracts referring to on-chain data
Contracts being used in channels off-chain calls have the exact same semantics as those being used on-chain. Because of the different environment however, off-chain calls might have different results as the on-chain ones.
Since there is no single source of truth, each participant considers their current view of the chain to be the correct one. This is essential for the trustless environment. Every off-chain contract call is based on the top of the chain, as it is seen by each participant. This could cause some differences in local contract executions. If those can not be resolved, participants can always rely on the blockchain as an arbiter by using forcing of progress. Then the top is used as it is seen by the Bitcoin-NG leader.
It is worth mentioning that both local contracts' executions and the forced progress ones must be fully deterministic and this implies some restrictions on using on-chain objects in the off-chain contracts. This is especially true for the chain-related primitives (e.g. coinbase, timestamp, block height, difficulty). Please refer to the documentation of the applicable VM version. Registration and updates of names or asking of oracles is impossible in the off-chain contract calls.
Using on-chain contracts in off-chain ones is a tricky task. On-chain contracts reference-count contracts that refer to them. They can be deleted from the blockchain only once they are no longer referenced by any other contract. This can not be enforced for off-chain contracts because there is no knowledge of them on-chain. Also if we were to use an on-chain contract referencing it by a registered name, the name on-chain could be changed to point to another different contract. This opens a security hole especially if one of the participants is in control of the name. For these reasons off-chain contracts are not allowed to use on-chain ones, not even stateless on-chain contracts. Participants can still use well-known contracts that are present on-chain but they have to copy them into their off-chain state. That way participants take care of their own data in a trustless manner - they don't have to rely on other entities keeping contracts on-chain for them.
Gas consumption
While making off-chain updates that both parties authenticate, no gas is being consumed. It is worth mentioning that although contract call updates do include values for the gas limit and the gas price, those are ignored. Assumption is that since both participants are executing the contracts locally, they are equal in their energy consumption.
When a dispute arises and a contract is to be called on-chain, the miner that includes the transaction should be compensated for the energy used. That's why when forcing progress of off-chain contract calls gas is consumed. Gas limit and gas prices are specified in the contract call update itself. Now the values not being used off-chain come into play. Since the force progress is an unilateral act, it is the forcer that specifies them and it is the forcer's on-chain balance that is paying for the consumed gas.
Last updated
Was this helpful?