I tried understanding code of update
channel flow. Would be like some one to verify it. TIA
Code Snippet for channel update
at FSM 1 Side
Expose channel.update.new
rpc first
process_request(#{<<"method">> := <<"channels.update.new">> = M,
<<"params">> := #{<<"from">> := FromB,
<<"to">> := ToB,
<<"amount">> := Amount} = Params}, FsmPid) ->
assert_integer(Amount),
case {aeser_api_encoder:safe_decode(account_pubkey, FromB),
aeser_api_encoder:safe_decode(account_pubkey, ToB)} of
{{ok, From}, {ok, To}} ->
apply_with_optional_params(
M, Params,
fun(XParams) ->
aesc_fsm:upd_transfer(FsmPid, From, To, Amount, XParams)
end);
_ -> {error, {broken_encoding, [account]}}
end;
Handle the RPC call in handle_upd_transfer
method
Currently in open
state
handle_upd_transfer(FromPub, ToPub, Amount, From, UOpts, #data{ state = State
, opts = Opts
, on_chain_id = ChannelId
} = D) ->
%% Get the current block_hash
{BlockHash, OnChainEnv, OnChainTrees} = pick_onchain_env(UOpts, D),
ActiveProtocol = aetx_env:consensus_version(OnChainEnv),
try
%% Form the update object with from, to and amount params
Updates = [aesc_offchain_update:op_transfer(aeser_id:create(account, FromPub),
aeser_id:create(account, ToPub), Amount)
| meta_updates(UOpts)],
lager:debug("TODO_IM: handle_upd_transfer: Updates = ~p", [Updates]),
%% Prepare the transaction to be signed
Tx1 = aesc_offchain_state:make_update_tx(Updates, State, ChannelId, ActiveProtocol,
OnChainTrees, OnChainEnv,
channel_reserve(Opts)),
%% Request to sdk for signing
case request_signing(?UPDATE, Tx1, Updates, BlockHash, D, defer) of
{ok, Send, D1, Actions} ->
%% reply before sending sig request
gen_statem:reply(From, ok),
Send(),
%% Move to awaiting_signature state
next_state(awaiting_signature, D1, Actions);
{error, _} = Error ->
gen_statem:reply(From, Error),
keep_state(D)
end
...
...
Set the half signed state before sending this halfSgined Tx to FSM 1
check_signed_update_ack_tx(SignedTx, Msg,
#data{ state = State
, opts = Opts
, op = #op_ack{tag = ?UPDATE} = Op} = D) ->
...
...
{ok, D#data{ state = aesc_offchain_state:set_signed_tx(
SignedTx, Updates, State, OnChainTrees, OnChainEnv, Opts)
, log = log_msg(rcv, ?UPDATE_ACK, Msg, D#data.log)}};
...
...
Now send the halfSignedTx to FSM 2
send_update_msg(SignedTx, Updates,
#data{ on_chain_id = OnChainId
, session = Sn
, op = #op_ack{ tag = ?UPDATE
, data = OpData}} = Data) ->
...
...
aesc_session_noise:update(Sn, Msg);
...
...
And you go back to the awaiting_update_ask
state after checking the signature
awaiting_signature(cast, {?SIGNED, ?UPDATE = OpTag, SignedTx} = Msg,
#data{ state = State
, op = #op_sign{ tag = OpTag
, data = OpData0 } = OpSign} = D) ->
%% Check the signature
maybe_check_auth(SignedTx, OpSign, not_offchain_tx, me,
...
...
%% Go to awaiting_update_ack state
next_state(awaiting_update_ack, D3)
...
...
Code Snippet for channel update
at FSM 2 Side
Receive the transaction, check for message authenticity and request the sdk to sign the message
open(cast, {?UPDATE, Msg}, D) ->
%% Check the message first which came from FSM1
case check_update_msg(Msg, D) of
{ok, SignedTx, Updates, BlockHash, D1} ->
D2 = report(info, update, D1),
%% Request SDK2 to sign
case request_signing_(?UPDATE_ACK, SignedTx, Updates, BlockHash, D2) of
{ok, D3, Actions} ->
%% Let's wait for SDK2 sign back. Moved to `awaiting_signature` state
next_state(awaiting_signature, set_ongoing(?UPDATE, D3), Actions); %% next_state(st, D, opts)
{error, _Error} ->
handle_update_conflict(?UPDATE, D2)
end;
...
...
After it gets the signed message (full signed), he moves stores the state and goes into open
state
awaiting_signature(cast, {?SIGNED, ?UPDATE_ACK = OpTag, SignedTx} = Msg,
#data{ op = #op_sign{ tag = OpTag
, data = OpData0 } = OpSign
, opts = Opts
, state = State } = D) ->
...
...
%% Check the signautres
maybe_check_auth(SignedTx, OpSign, not_offchain_tx, both,
fun() ->
D1 = log(rcv, ?SIGNED, Msg, D),
%% Respond to FSM1 about this fullSigned message
D2 = send_update_ack_msg(SignedTx, D1),
{OnChainEnv, OnChainTrees} = load_pinned_env(BlockHash),
%% Stores the full signed state
State1 = aesc_offchain_state:set_signed_tx(SignedTx, Updates, State,
OnChainTrees, OnChainEnv, Opts),
D3 = D2#data{ state = State1
, op = ?NO_OP },
%% Goes back to open state
next_state(open, D3)
end, D);
Sends the fullSignedtx to FSM 1
send_update_ack_msg(SignedTx, #data{ on_chain_id = OnChainId
, session = Sn } = Data) ->
%% serialize before sending via Noise to FSM1
TxBin = aetx_sign:serialize_to_binary(SignedTx),
Msg = #{ channel_id => OnChainId
, data => #{tx => TxBin} },
%% Send it now!
aesc_session_noise:update_ack(Sn, Msg),
Code Snippet for channel update
at FSM 1 Side
Currently in awaiting_update_ack
state
Receives the message, check the validity, responds to SDK 1, stores the state, goes back to open
state
awaiting_update_ack(cast, {?UPDATE_ACK, Msg}, #data{} = D) ->
%% Check for the incomming message
case check_update_ack_msg(Msg, D) of
{ok, D1} ->
next_state(open, D1);
...
...
Deserialize and check the validity
check_update_ack_msg_(#{ channel_id := ChanId
, data := #{tx := TxBin} } = Msg,
#data{on_chain_id = ChanId} = D) ->
try aetx_sign:deserialize_from_binary(TxBin) of
SignedTx ->
check_signed_update_ack_tx(SignedTx, Msg, D)
...
..
Stores the state
check_signed_update_ack_tx(SignedTx, Msg,
#data{ state = State
, opts = Opts
, op = #op_ack{tag = ?UPDATE} = Op} = D) ->
...
...
{ok, D#data{ state = aesc_offchain_state:set_signed_tx(
SignedTx, Updates, State, OnChainTrees, OnChainEnv, Opts)
, log = log_msg(rcv, ?UPDATE_ACK, Msg, D#data.log)}};
...
...