On-chain
Last updated
Was this helpful?
Last updated
Was this helpful?
Operating a state channel requires, an initial on-chain setup via achannel_create_tx
transaction, that locks up a configurable amount of coins from
each involved party in the channel. This requires a consent, in the form of
either signatures or generalized account authentication call data, from both
participants. More information regarding authentication can be found
In the ideal case, all on-chain transactions get authenticated by both participants, implying that there are no disagreements. These operations can be committed immediately. There are also some unilateral transactions that need to be authenticated just by one of the participants. Those might have a block height timer attached to them for the other party to dispute. The mutually agreed ones will override all conflicting unilateral actions.
Transactions not authenticated by everyone can be disputed viachannel_slash_tx
, channel_snapshot_solo_tx
and channel_force_progress_tx
transactions. During normal operation, these solo transactions can be disputed
indefinitely. If the channel is in the closing state, disputes have to happen
within the pre-negotiated lock_period
, given that closure requires a bounded
finality.
Each channel transaction updating on-chain state provides two fields essential
for future conflict resolution: round
and state_hash
. The state hash is
the root hash of the channel's state tree after the on-chain has been applied
to the local state tree. The round
is the state channel's internal round.
Since the round
is incrementing on every off-chain state change, the channel
transaction both represents the off-chain state of the channel and defines the
point of time when it was valid. This allows us to make educated decisions on
whether or not to update the on-chain persisted channel object. This way we
can solo close a channel according to the last provided on-chain state. All we
have to do is to provide a proof of inclusion having the same state_hash
.
All of the on-chain operations could be submitted by any peer but we assume that
the initiating peer pays for the setup of the channel. Therefore the initiator
MUST pay the channel_create_tx
transaction fees.
channel_create
The channel_create_tx
transaction is used to register a channel on-chain and its
inclusion on-chain causes the specified amounts to be locked up as a guarantee
that participants have a vested interest in the channel. Although it is not a
strict requirement, it is strongly suggested to do so.
e.g.
initiator_id
: account id of the initiating peer
responder_id
: account id of the responding peer
initiator_amount
: unsigned amount of coins the initiator commits to the
channel
responder_amount
: unsigned amount of coins the responder commits to the
channel
lock_period
: period for disputes after solo operations
delegate_ids
, initiator_delegate_ids
and responder_delegate_ids
: lists
of delegate account ids. The delegates play a role in the solo closing
sequence: except for the participants of the channel, they are the only ones
that can provide a snapshot, slash or forced progress transactions. Preiris
there is only a single list of delegates and from iris
on those are
fine grained on a participant level
state_hash
: the root hash of the channel state tree; This is not validated,
just kept in the channel's object as initial value. This come into play if
participants enter a dispute right after opening the channel on-chain.
ttl
: blockheight target until which this transaction can be included
fee
: transaction fee
nonce
: initiator
's account nonce or 0 if one is a generalized account
The length of the lock_period
is a trade-off between responsiveness, e.g. how
fast solo operations can be committed, and security. Choosing a lock_period
that gives participants enough time to react to potential malicious solo
operations is crucial.
The ttl
is in absolute chain height. The involved parties will want to set thettl
to a value quite a bit larger than the present chain height, to avoid
uncertainty. If the fees included are low and transaction pressure is high, then
the transaction might end up being stuck in the mempool for an extended period.ttl
is optional, no ttl
means a transaction that is valid "forever".
The fee
and nonce
refer to the initiator
account, i.e. the fee
MUST be
taken from their balance and the nonce
of their account MUST be incremented.
Account(initiator).balance >= initiator_amount + fee
Account(responder).balance >= responder_amount
initiator_amount >= channel_reserve
responder_amount >= channel_reserve
An update to an open channel requires the authentication of all participants
and a channel identification (channel_id
).
Both channel_deposit_tx
and channel_withdraw_tx
MUST be authenticated by
all involved parties, since changing channel balances might change the
dynamics of code running in a channel.
The channel_id
is computed from the public key of the initiator, the nonce of
the create transaction and the public key of the responder using Blake2b (256
bits digest).
channel_deposit
Depositing funds into a channel after its creation provides the means for a participant to move coins from the participant's balance to the channel's one. This should allow channels to be more long-lived due to the increased ease of balancing them out. The amount of coins sent along with this transaction will get locked up just like the initial deposit.
While it could be desirable to allow anyone to deposit into a channel, we are
going to restrict deposits to the peers of a channel. That means, the from_id
field MUST be an address of one of the participants of the targeted channel and
the standard transaction fee MUST be paid by the from_id
account.
This operation is not mandatory for normal channel operation.
channel_id
: channel id as recorded on-chain
from_id
: sender of the deposit
amount
: amount of coins deposited
state_hash
: the root hash of the channel state tree after the deposit has
been applied to it; This is not validated on-chain, just kept in the
channel's object
round
: the channel's internal round that applies the deposit
ttl
: blockheight target until which this transaction can be included
fee
: transaction fee
nonce
: from_id
's account nonce
Note that the round
SHOULD be incremented on each off-chain update. This
means, in order for an on-chain transaction, referring to off-chain state, to
be considered valid, it MUST include a round
higher than the currently
recorded Channel(channel_id).round
.
If this transaction is valid then it sets:
Channel(channel_id).round := round
Channel(channel_id).solo_round := 0
Channel(channel_id).state_hash := state_hash
Channel(channel_id).total_amount := Channel(channel_id).total_amount + amount
channel_withdraw
Channels should generally not be used to hold significant amounts of coins but being able to withdraw locked coins might still be of use.
channel_id
: channel id as recorded on-chain
to
: receiver of the withdraw
amount
: amount of coins withdrawn
state_hash
: the root hash of the channel state tree after the withdraw had
been applied; This is not validated, just kept in the channel's object
round
: the channel's internal round that applies the withdraw
ttl
: blockheight target until which this transaction can be included
fee
: transaction fee
nonce
: to
's account nonce
The to
account MUST be a participant in the target channel. The amount
MUST be less than or equal to the sum of the channel balance with regard to thechannel_reserve
amounts, i.e. channels cannot create coins out of thin air
but also a minimum of channel_reserve
must remain locked in the channel. The
fee is paid by the to
account and that account should hold enough coins to
pay the fee, i.e., the fee is subtracted before the withdrawn coins arrive.
Note that the round
SHOULD be incremented on each off-chain update. This
means, in order for an on-chain transaction, referring to off-chain state, to
be considered valid, it MUST include a round
higher than or equal to the
currently recorded Channel(channel_id).round
.
If this transaction is valid then it sets:
Channel(channel_id).round := round
Channel(channel_id).solo_round := 0
Channel(channel_id).state_hash := state_hash
Channel(channel_id).total_amount := Channel(channel_id).total_amount - amount
channel_snapshot_solo
In order to make channels both secure and trustless even when one party goes
offline, we provide the functionality of snapshots.
Snapshots provide a recent off-chain state to be recorded on-chain. This state
is represented by a round
and a state_hash
. Those are proven to be correct
at least at some point of time in the past by providing a co-authenticated
off-chain update as a payload
. Note that the payload
can not be an
on-chain transaction.
After channel_snapshot_solo_tx
inclusion the channel can not be closed using an
older state—as indicated by the round
—than the one provided in the snapshot.
channel_id
: channel id as recorded on-chain
from_id
: the account that posts the transaction
payload
: an off-chain transaction of the same channel authenticated
by both parties
ttl
: blockheight target until which this transaction can be included
fee
: transaction fee
nonce
: the from_id
account nonce
The from_id
account MUST be a participant or a delegate in the target
channel. The payload
MUST be an off-chain state. It MUST provide correct
authentication methods for both parties. It MUST be part of the same channel
(containing same channel id) and it MUST have a round
higher than the one
currently recorded on-chain.
This transaction MUST NOT trigger the lock_period
and MUST NOT be used when
the channel is in the closing state. It can be used to overwrite a state produced
by a channel_force_progress_tx
while the channel is in the open state.
If this transaction is valid then it sets:
Channel(channel_id).round := payload.round
Channel(channel_id).solo_round := 0
Channel(channel_id).state_hash := payload.state_hash
channel_set_delegates
In order to make channels both secure and trustless even when one party goes
offline, a participant can delegate the right to produce certain transactions
to other third parties.
Delegates are set initially in the channel_create_tx
and, since the iris
hardfork, can be updated with channel_set_delegates_tx
. It acts similarly tochannel_snapshot_solo_tx
with three notable differences:
While channel_snapshot_solo_tx
can be based only on off-chain state,channel_set_delegates_tx
can be based both on off-chain state or latest
on-chain state. In the latter case the payload
provided is empty.
channel_set_delegates_tx
is mutually agreed upon. If the other participant
does not want to approve such a transaction, this could be a clear sign that
the assumption of cooperation is broken.
channel_set_delegates_tx
not only updates the on-chain channel object
but also sets the list of delegate ids for each participant. The old lists of
delegates are deleted and the new ones provided by the transaction replace
them. There is no option for setting the list just for one participant.
channel_id
: channel id as recorded on-chain
from_id
: the account that posts the transaction
initiator_delegate_ids
: the list of delegates that can provide
transactions on behalf of the initiator
responder_delegate_ids
: the list of delegates that can provide
transactions on behalf of the responder
payload
: an off-chain transaction of the same channel authenticated
by both parties. It could be empty
state_hash
: the hash of the payload, if provided - and if not, the latest
provided on-chain state_hash
round
: the hash of the payload, if provided - and if not, the latest
provided on-chain round
ttl
: blockheight target until which this transaction can be included
fee
: transaction fee
nonce
: the from_id
account nonce
The from_id
account MUST be a participant in the target
channel. The payload
MUST be an off-chain state or empty. It MUST provide correct
authentication methods for both parties. It MUST be part of the same channel
(containing same channel id). If provided, it MUST have a round
higher than
the one currently recorded on-chain. The state_hash
and round
must match
the ones in payload
or the on-chain stored data if the payload
is empty.
This transaction MUST NOT trigger the lock_period
and MUST NOT be used when
the channel is in the closing state. It can be used to overwrite a state produced
by a channel_force_progress_tx
while the channel is in the open state.
If this transaction is valid then it sets:
Channel(channel_id).round := round
Channel(channel_id).solo_round := 0
Channel(channel_id).state_hash := state_hash
Channel(channel_id).initiator_delegate_ids := initiator_delegate_ids
Channel(channel_id).responder_delegate_ids := responder_delegate_ids
We expect channels to be long running but they could be closed. This shall happen when participants have completed their interaction but this includes also the cases of non-cooperation or malicious behaviour. If both parties decide to close the channel, closing is just a matter of issuing one on-chain transaction, authenticated by everyone involved.
In the case of a solo closing, operations are subject to the lock_period
,
during which the closing state can be disputed via a channel_slash_tx
or
even progressed further on-chain via channel_force_progress_tx
transactions.
channel_close_mutual
channel_id
: channel id as recorded on-chain
from_id
: the account that posts the transaction
initiator_amount_final
: final balance for the initiator
responder_amount_final
: final balance for the responder
ttl
: blockheight target until which this transaction can be included
fee
: transaction fee
nonce
: the from_id
account nonce
This transaction MUST have valid authentications of both parties.
This transaction MUST NOT be disputed and any ongoing dispute MUST be considered resolved by this transaction.
After this transaction has been included in a block, the channel MUST be considered closed and allow no further modifications. The on-chain persisted channel object is removed from the on-chain state trees.
channel total >= transaction initiator_amount_final + responder_amount_final + fee
channel_close_solo
In order to close a channel unilaterally, a participant has to send achannel_close_solo
transaction. This is only necessary if one peer stops
responding or cooperating but can also be used by an malicious peer trying to
close a channel with a state that hasn't been agreed on by all participants.
At any point a channel participant can initiate the solo closing sequence.
After the channel_close_solo
is posted and included in the chain alock_period
block height timer is started.
This lock period is required to give the other party an opportunity to dispute
the final state, that the closing sequence is based on. This can be done via
the channel_slash_tx
and channel_force_progress_tx
transactions.
With the inclusion of this transaction on-chain, the channel enters the locked
state, during which the channel_close_solo_tx
can be disputed.
channel_id
: channel id as recorded on-chain
from_id
: participant of the channel that posts the closing transaction
payload
: empty or an authenticated off-chain state proving that the proof
of inclusion is part of the channel
poi
: proof of inclusion
ttl
: blockheight target until which this transaction can be included
fee
: transaction fee
nonce
: according to the from_id
's account
Proof of inclusion represents the channel's internal state. At the bare minimum it has to include all accounts and their balances. It MUST provide enough information to close the channel. Miners are to check balances in it and use this data to update the channel's on-chain representation. This is how the poster initiates the solo closing sequence. If there are any contracts in the channel and those have balances of their own, they are not provided in the proof of inclusion but they are rather could be force-pushed in subsequent transactions. It is up to participants to decide if they want to post them at all. Thus the accumulative balances of the accounts in the solo-close transaction can be lower than the channel balance persisted on-chain.
The payload
can be either empty or an authentication off-chain state
transaction.
If the payload is empty, the last on-chain persisted state_hash
andsolo_round
are used. In this case the proof of inclusion root hash MUST be
equal to the one persisted for the channel on-chain. If that state was
produced unilaterally, i.e. via a channel_force_progress_tx
, makingChannel(channel_id).round != Channel(channel_id).solo_round
, the solo close
is based on the solo_round
and thus can still be disputed.
Channel(channel_id).locked_until := Block.height + Channel(channel_id).lock_period
If the payload is a transaction it MUST be a channel_offchain_tx
. It MUST be
authenticated by both participants.
Payload is a valid transaction that has:
state_hash
equal to the proof of inclusion's root hash. This is a proof
that the PoI is correct
channel_id
being the same as the transaction channel_id
round
greater than Channel(channel_id).round
. IfChannel(channel_id).solo_round > Channel(channel_id).round
, then
this close will invalidate progress produced on-chain
If true, the following changes will be made:
Channel(channel_id).round := payload.round
Channel(channel_id).solo_round := payload.round
Channel(channel_id).state_hash := payload.state_hash
Channel(channel_id).locked_until := Block.height + Channel(channel_id).lock_period
channel_settle
The settlement transaction is the last one in the lifecycle of a channel, but only required if the parties involved did not manage to cooperate when trying to close the channel. It has to be issued after all possible disputes are resolved to then redistribute the locked coins.
The channel_settle_tx
CAN only be included in a block if:
a channel_close_solo_tx
transaction was published and the lock_period
has
expired, i.e. blockheight(top) - blockheight(channel_close_solo_tx) >= lock_period
there are no open disputes, which means that the channel is not currently locked from a prior solo action
channel_id
: channel id as recorded on-chain
from_id
: participant of the channel that posts the settling transaction
initiator_amount_final
: unsigned amount of coins the initiator gets from the
channel
responder_amount_final
: unsigned amount of coins the responder gets from the
channel
ttl
: blockheight target until which this transaction can be included
fee
: transaction fee
nonce
: according to the from_id
's account
After this transaction has been included in a block, the channel MUST be considered closed and allow no further modifications. After the transaction is included, the channel object is removed from on-chain trees.
The transaction MUST be authenticated using the method corresponding to the
account behind from_id
.
Forcing progress is the mechanism to be used when a dispute arises between parties and one of them wants to use the blockchain as an arbiter in a smart contract. The poster provides the off-chain state so that an off-chain contract can be executed on-chain and thus producing the channel's next off-chain state.
This can happen both while a channel is closing or while it is still active. If the channel is not closing, participants can continue using it from the on-chain produced channel state or initiate a closing based on it. If the channel is already closing, the force-progress updates what are the currently expected closing amounts for each participant (according to the contract's execution).
The force progress is based on what is considered to be the latest off-chain
channel state. We have no way of proving that this state is actually the last
one so any progress on chain can always be invalidated by providing an
off-chain channel state, authenticated by both participants, with a higher round
number than the round number that the to-be-disputedchannel_force_progress_tx
transaction used.
If the channel is in the closing state, issuing a channel_force_progress_tx
locks it for lock_period
blocks, during which the update can be disputed. This
lock is necessary to prevent the channel from being closed immediately after
a new round has been produced on chain.
The forcer can be either a participant or, after iris
, a delegate. The
latter can only force from behalf of the participant that had specified her to
do so, ex: initiator
's delegates can only force progress calls made from theinitiator
's account. Delegated forced progress is allowed only when the
channel is already in a closing state.
It is worth mentioning that what is to be disputed is the off-chain state that the force progress had been based on and not the forcing of progress itself. If an older state had been provided by the forcing party, the other party can post a newer authenticated off-chain state (via a snapshot for example). The authenticated by both participants off-chain state with the same or greater round will replace the on-chain produced one.
channel_force_progress_tx
channel_id
: channel id as recorded on-chain
from_id
: a participant or a delegate of the channel that posts the force
progress transaction
payload
: empty or an off-chain state transaction proving that the state trees
represent a mutually agreed-upon channel state
round
: channel's next round
update
: channel off-chain update that contains the contract call with gas
limit and gas prices to be consumed for the on-chain execution of the
off-chain contract. If it is a delegate that provides the force progress,
the the caller
of the off-chain contract MUST be a participant that had
authorized this delegate
state_hash
: channel's expected new root hash of off-chain state trees
offchain_trees
: the full state channel's state trees
ttl
: blockheight target until which this transaction can be included
fee
: transaction fee
nonce
: according to the from_id
's account
The offchain_trees
is the full off-chain state trees set: all accounts and
all contracts. It MUST include both participants' off-chain accounts. It MUST
include the contract to be called. Based on the offchain_trees
, the next
state is going to be computed and its root hash will become the new state'sstate_hash
. The newly produced state trees will be different than the
provided ones at least with the newly added call
object. Thus even if the
contract call fails a new state_hash
is produced.
If this transaction is sent while the channel is in the closing
state, it will
transition the channel into the locked
state for the next lock_period
blocks.
Although while this lasts, the channel can not be settled, new force-
progressed transactions can still be accepted before the timer expires. Those
MUST be based on the previous on-chain produced states but each next one
resets the dispute timer.
The payload can be either empty or an authenticated off-chain state transaction.
If the payload is empty, the last on-chain persisted state and solo_round
are
used. In this case the state trees root hash MUST be equal to the one persisted
for the channel on-chain.
If the contract execution is successful, the channel will be updated with:
Channel(channel_id).solo_round := Channel(channel_id).solo_round + 1
Channel(channel_id).state_hash := state_hash
Additionally, if the channel is in the closing
state:
Channel(channel_id).locked_until := Block.height + Channel(channel_id).lock_period
If the payload is a transaction it MUST be a channel_offchain_tx
. It MUST be
authenticated by both participants.
An off-chain transaction payload is a valid transaction if it has:
state_hash
equal to the state trees' root hash. This is a proof that theoffchain_trees
represent a state both participants had agreed upon at some
point of time
channel_id
being the same as the transaction channel_id
round
greater than Channel(channel_id).round
The update MUST be a call to a contract. The caller of this update MUST be the
poster of the force progress transaction. amount
, gas
and gas_price
are
specified in the update as well. The gas fees are going to be paid by the poster
of the transaction. The gas_price
MUST match protocol expectations for
minimum gas price.
The state_hash
will be the root hash of the updated channel's state trees.
After applying the contract call to the provided offchain_trees
and updating
accounts accordingly, a new channel's state tree is produced. It MUST have the
same value of root hash as the state hash. If those do not match the force
progress fails but since this can only be determined after the call has been
executed, a call object is added on-chain and gas is consumed.
If the contract call succeeded, the channel state will be updated:
Channel(channel_id).round := payload.round
Channel(channel_id).solo_round := payload.round + 1
Channel(channel_id).state_hash := state_hash
Additionally, if the channel is in the closing
state:
Channel(channel_id).locked_until := Block.height + Channel(channel_id).lock_period
Updating channel object
Channel state trees are recreated according to the offchain_trees
being
provided. The update is an off-chain contract call. It is applied on the
channel's state trees and modifies them. The modified trees have a root
hash. It might be:
equal to the state_hash
provided in the force progress transaction.
This hash indeed is the expected result of the contract call and the
blockchain has confirmed it. The on-chain channel object is updated
accordingly:
channel's state hash is updated to be the newly computed one
channel's round is the one in the force progress transaction
if the channel had been in a closing state, closing balances of participants are updated according to the ones in the modified channel state trees
not equal to the state_hash
provided in the force progress transaction. The
hash provided was not confirmed to be the expected one. In this case the force
progress fails and no new state channel state is created. The on-chain channel
object is NOT modified and thus - the round
and state_hash
as stored
on-chain remain unchanged. Gas is still consumed and a call object is created
on-chain.
A special case would be the forcer providing an invalid update call to be forced. Examples for an invalid update calls would be:
A remote call to a missing contract
Spending too much coins in the call so a participants's off-chain balance
goes bellow the channel_reserve
threshold
Contract call being terminated due to a out_of_gas
exception
In this case the contract can not be executed and the forcing of progress
fails to produce a new state. The end result is exactly the same as if there
had been a mismatch of the produced state_hash
and the expected one. It is
worth mentioning that in this case the transaction is still a valid one, the
poster of the transaction is charged for the consumed gas.
Call object
If the channel_force_progress_tx
is valid, the contract call in the update
is executed upon the MPT that had been produced by the offchain_trees
.
The output is a new MPT that will represent the new off-chain channel state.
Participants are to either continue using the channel or close it. If there is
no later off-chain update, they are expected to use this produced MPT in both
cases.
The contract execution consumes gas. The update
itself defines both the gas
limit and the gas price. After the contract call has been executed and the real
gas consumption has been calculated, the balance of the account posting the
transaction is updated to pay the gas fee. Since this is not a mutual
transaction but rather a unilateral one, the initiator of the progress
enforcement pays the fees.
The contract call produces on-chain a new call object in the on-chain state
trees for contract calls. Usually calls have a key that is composed by the
contract's address, the caller's address and the caller's nonce. Since the off-
chain contract is not persisted on-chain, it does not have an address that can
be used in that manner. The calls produced by forcing progress use thechannel_force_progress_tx
's hash instead.
Since the miner is expending resources for the contract's execution, the gas fees are paid and the call object is created for every force progress, no matter if it was successful to update the on-chain channel object or not.
Disputes should be considered anomalies, which only happen whenever one party tries to unilaterally publish an outdated state while:
closing a channel unilaterally
forcing progress
slashing
snapshoting
and can be disputed via channel_slash_tx
, channel_force_progress_tx
,channel_snapshot_solo_tx
transactions.
Since disputes can themselves be challenged, we could end up in situations,
where a malicious party progresses rounds rapidly via channel_force_progress_tx
transactions, depriving the other party of the ability to dispute. To prevent
this situation we can either:
enforce each dispute to always have to wait for the lock_period
to expire
and have only one dispute per period
or not restrict the number consecutive disputes but always have the option of challenging the first element of any chain of disputes, invalidating the full chain.
We choose to use the second strategy because it allows faster progress in the case of a peer that disappeared while still guaranteeing safety. This makes keeping track of the proper states more complex but we assume a peer disappearing has a higher likelihood than them being actively malicious. Therefore we try to optimise for that case.
If the channel is in the closing state, which only happens via achannel_close_solo
, then each dispute triggers an extension of the channel
lock by lock_period
blocks. If a channel is locked, the same rules as above
apply. That is, as many channel_force_progress_tx
or channel_slash_tx
transactions as desired can be submitted—each one extending the lock—but as long
as the channel is locked, the entire chain can be invalidated if a state with a
higher round number can be posted.
Having the lock is necessary here because otherwise a malicious party might post
a channel_force_progress_tx
or channel_slash_tx
containing an outdated state
and then immediately try to have the channel be settled based on the result.
Setup:
Bob and Alice open a channel between each other with lock_period := 100
At chain_height := 1000
Bob posts a channel_force_progress_tx
with a
payload containing round := 23
and produces round := 24
on chain
The channel state will now contain 23 as the latest round
and 24 as
the solo_round
With the selected strategy, Bob does not have to wait for the lock_period
to
expire and can post as many channel_force_progress_tx
as he wants, e.g. atchain_height := 1001
he produces solo_round := 25
and by chain_height := 1011
arrives at solo_round := 31
. The round
is still at 23.
Now if Alice returns at chain_height := 1110
, she can still dispute theinitial update issued by Bob at chain_height := 1000
by providing an
authenticated by both payload with round := 24
or higher via either achannel_force_progress_tx
or a channel_snapshot_solo_tx
.
Setup:
Bob and Alice open a channel between each other with lock_period := 100
At chain_height := 1000
Bob posts a channel_close_solo
with a
payload containing round := 23
. The channel is now locked untilchain_height == 1100
With the selected strategy, Bob has to wait for the lock_period
to expire, if
he wants to settle the channel. But while the channel is locked, he can still
post as many channel_force_progress_tx
as he wants, e.g. atchain_height := 1001
he produces solo_round := 24
and by chain_height := 1011
arrives at solo_round := 31
. Each subsequent operation issued bumps thelock_period
ahead. That is, by chain_height == 1011
the lock_period
is set
to run out at chain_height == 1111
.
Now it is important to note, that at even at chain_height := 1110
Alice can
still dispute the initial update issued by Bob at chain_height := 1000
by
providing an authenticated by both payload with round := 24
or higher but her
dispute would bump the lock by lock_period
too.
If a malicious party sent a channel_close_solo
or channel_force_progress_tx
with an outdated state, the honest party has the opportunity to issue achannel_slash_tx
transaction. This transaction MUST include a state with a higherround
number than the one being disputed, authenticated by all peers for a
successful challenge.
channel_id
: channel id as recorded on-chain
from_id
: channel participant or delegate that posts the slashing transaction
payload
: an off-chain transaction proving that the proof of inclusion is part
of the channel
poi
: proof of inclusion
ttl
: blockheight target until which this transaction can be included
fee
: transaction fee
nonce
: taken from the from_id
's account
The proof of inclusion represents the channel's internal state. It has to include both participants' accounts and their balances. If there are any contracts in the channel and those have balances of their own, they are not provided in the proof of inclusion but they are rather to be force pushed in subsequent transactions. It is up to participants to decide if they want to post them at all. Thus the accumulative balances of the accounts in the slash transaction can be lower than the channel balance persisted on-chain.
The payload is a transaction and it MUST be a channel_offchain_tx
. It
MUST be authenticated by both peers.
Payload is a valid transaction that has:
state_hash
equal to the proof of inclusion's root hash. This is a proof
that the PoI is correct
channel_id
being the same as the transaction channel_id
round
greater than the last on-chain provided co-authenticated channel
state. If the latest on-chain round(s) were produced bychannel_force_progress_tx
transaction(s) that were based on an older channel
state - the whole chain of forced progressed channel states are invalidated
and replaced by the state provided by the slash. Co-authenticated channel
transactions replace unilateral ones with the same round.
If true, the following changes will be made:
Channel(channel_id).round := payload.round
Channel(channel_id).solo_round := payload.round
Channel(channel_id).state_hash := payload.state_hash
Channel(channel_id).locked_until := Block.height + Channel(channel_id).lock_period
MUST be authenticated using the method corresponding to the public key from_id
.
Each block MUST commit to a Merkle Patricia tree of open channels, where thechannel_id
specifies the path.
At a leaf, nodes store information pertaining to the current state of the given
channel.
channel_id
initiator_id
responder_id
delegator_ids
total_amount
initiator_amount
responder_amount
channel_reserve
state_hash
: last published state_hash
round
: last known round
solo_round
: last round produced via a channel_force_progress_tx
lock_period
: agreed upon locking period by peers
locked_until
: on-chain channel height after which the channel can be settled
initiator_auth
: (from Fortuna release) signing/authentication data for initiator
responder_auth
: (from Fortuna release) signing/authentication data for responder
Keeping track of the state_hash
, round
, locked_until
, and lock_period
is
necessary for nodes to be able to assess the validity of channel_slash_tx
andchannel_settle_tx
transactions.
The locked_until
is initialised with 0
and will stay 0
until the channel
enters the closing
state.
Serialization defined
If either of the participants is a the channel create will also create an extra entry in the contract state tree, containing a frozen authentication state that will be used for off-chain authentication and verification in off-chain updates (potentially eventually enforced on-chain) of this particular channel. A more detailed explanation can be found
Serialization defined
Serialization defined
Serialization defined
Serialization defined
Serialization defined
initiator_amount_final
and responder_amount_final
are the agreed upon
distribution of coins out of the channel total balance of coins. The
initiator's and responder's account balances are incremented byinitiator_amount_final
and responder_amount_final
respectively. The
channel MUST have enough total coins to pay for the fee as well as the agreed
upon amounts. The total closing amount of a channel is computed by adding the
amounts of the initiator and responder (before the close) and the fee. If this
total closing amount is lower than the total amount coins already dedicated to
the channel, the excess of coins is .
Serialization defined
Serialization defined
The amounts must correspond to the ones on-chain, provided by the lastchannel_close_solo_tx
, channel_slash_tx
or a channel_force_progress_tx
. The sum
of those final amounts form the total closing amount of the channel. If this
total closing amount is lower than the total amount of coins already dedicated to
the channel, the excess of coins is .
Serialization defined
Serialization defined
Serialization defined