the Dusk transaction detail I kept getting stuck on is that a contract execution can be reverted without making the transaction itself disappear.
my first instinct was to collapse those into one outcome.
call succeeds = transaction happened.
call reverts = transaction didn't.
Moonlight doesn't work that cleanly.
before acceptance, the network checks that the sender can cover the value, any contract deposit, and maximum gas: gas_limit × gas_price.
it verifies the signature, then checks that the nonce is one above the account's current nonce.
fair enough.
the interesting part comes after execution.
the whitepaper says that if smart contract execution is reverted, the corresponding amount is refunded. unused gas is refunded too.
but the nonce is incremented upon acceptance.
so “the contract kept the state change” and “the network consumed this transaction attempt” are not the same state.
a revert can undo the contract-side effect while the account-side ordering mechanism still moves forward.
gas creates another boundary.
the user has to cover maximum gas before execution, even though they may ultimately pay less because unused gas comes back.
so there are three amounts in play:
what you must be able to cover,
what execution consumes,
what is returned afterward.
easy to miss if gas_limit reads like a fee instead of a spending ceiling.
now imagine an application preparing several Moonlight transactions in sequence.
transaction N calls a contract and reverts.
the contract effect is gone.
but if N was accepted, the sender's nonce has moved.
transaction N+1 cannot reason from “the previous call failed” as if nothing happened.
failure changed something outside the contract.
that's the distinction I like here:
execution rollback is local.
transaction history is not.
and it changes the integration question.
when an app tells a user “this transaction failed,” what exactly failed?
the intended state transition?
or the transaction itself?
on Dusk, those can be two different answers.
@Dusk_Foundation #Dusk $DUSK $GPS $TUT
my first instinct was to collapse those into one outcome.
call succeeds = transaction happened.
call reverts = transaction didn't.
Moonlight doesn't work that cleanly.
before acceptance, the network checks that the sender can cover the value, any contract deposit, and maximum gas: gas_limit × gas_price.
it verifies the signature, then checks that the nonce is one above the account's current nonce.
fair enough.
the interesting part comes after execution.
the whitepaper says that if smart contract execution is reverted, the corresponding amount is refunded. unused gas is refunded too.
but the nonce is incremented upon acceptance.
so “the contract kept the state change” and “the network consumed this transaction attempt” are not the same state.
a revert can undo the contract-side effect while the account-side ordering mechanism still moves forward.
gas creates another boundary.
the user has to cover maximum gas before execution, even though they may ultimately pay less because unused gas comes back.
so there are three amounts in play:
what you must be able to cover,
what execution consumes,
what is returned afterward.
easy to miss if gas_limit reads like a fee instead of a spending ceiling.
now imagine an application preparing several Moonlight transactions in sequence.
transaction N calls a contract and reverts.
the contract effect is gone.
but if N was accepted, the sender's nonce has moved.
transaction N+1 cannot reason from “the previous call failed” as if nothing happened.
failure changed something outside the contract.
that's the distinction I like here:
execution rollback is local.
transaction history is not.
and it changes the integration question.
when an app tells a user “this transaction failed,” what exactly failed?
the intended state transition?
or the transaction itself?
on Dusk, those can be two different answers.
@Dusk_Foundation #Dusk $DUSK $GPS $TUT