Problem with WebSocket channel API

Hi,

I’m trying to set up off-chain channel for two accounts in my private Aeternity node using WebSocket.

I run Aeternity as a private node locally. Initially, I send some founds to my 2 accounts:

Responder account:
GET http://node:3013/v2/accounts/ak_tWZrf8ehmY7CyB1JAoBmWJEeThwWnDpU4NadUdzxVSbzDgKjP

Result:

{
   "balance":5451843000000000000000000,
   "id":"ak_tWZrf8ehmY7CyB1JAoBmWJEeThwWnDpU4NadUdzxVSbzDgKjP",
   "kind":"basic",
   "nonce":0
}

Initiator account:
GET http://node:3013/v2/accounts/ak_fUq2NesPXcYZ1CcqBcGC3StpdnQw3iVxMA3YSeCNAwfN4myQk

Result:

{
   "balance":5451843000000000000000000,
   "id":"ak_fUq2NesPXcYZ1CcqBcGC3StpdnQw3iVxMA3YSeCNAwfN4myQk",
   "kind":"basic",
   "nonce":0
}

I followed this tutorial.

  1. Opening WebSocket for responder using this URL:
    ws://node:3014/channel?channel_reserve=2&initiator_amount=3000&initiator_id=any&lock_period=10&port=3333&protocol=json-rpc&push_amount=1&responder_amount=3000&responder_id=ak_tWZrf8ehmY7CyB1JAoBmWJEeThwWnDpU4NadUdzxVSbzDgKjP&role=responder

  2. Opening WebSocket for initiator using this URL:
    ws://node:3014/channel?channel_reserve=2&host=localhost&initiator_amount=3000&initiator_id=ak_fUq2NesPXcYZ1CcqBcGC3StpdnQw3iVxMA3YSeCNAwfN4myQk&lock_period=10&port=3333&protocol=json-rpc&push_amount=1&responder_amount=3000&responder_id=ak_tWZrf8ehmY7CyB1JAoBmWJEeThwWnDpU4NadUdzxVSbzDgKjP&role=initiator

  3. Responder got message:

{
   "jsonrpc":"2.0",
   "method":"channels.info",
   "params":{
      "channel_id":null,
      "data":{
         "event":"channel_open"
      }
   },
   "version":1
}
  1. Initiator got response:
{
   "jsonrpc":"2.0",
   "method":"channels.info",
   "params":{
      "channel_id":null,
      "data":{
         "event":"channel_accept"
      }
   },
   "version":1
}
  1. Initiator got message with transaction to sign:
{
   "jsonrpc":"2.0",
   "method":"channels.sign.initiator_sign",
   "params":{
      "channel_id":null,
      "data":{
         "signed_tx":"tx_+IALAcC4e/h5MgGhAVdfgf+wope3cl3GcdoLF2mx/Fy+RThce1rR/C6vHWCdggu4oQF09Y/rp1KuBCbsvuOjFBTY5rMzXWTsQW8+V04QbH5UEoILuAIKAIYbSOtX4ADAoH/Xn0I4ZH5bOewYl3WluY4D11uLidZ46txRrVUm6XNvAbj/v+Q=",
         "updates":[
         ]
      }
   },
   "version":1
}
  1. Initiator signs transaction using his private key and sends message on his channel:
{
   "jsonrpc":"2.0",
   "method":"channels.initiator_sign",
   "params":{
      "signed_tx":"tx_+MoLAfhCuEB/8CyPkQ3XuAZY+5ArCJUd3JwteDy7W0Rz1U6bYdoCj9kFStB5rNcBIAGBM9183jNl2/g+8nAeMyFM68IsPUABuIL4gAsBwLh7+HkyAaEBV1+B/7Cil7dyXcZx2gsXabH8XL5FOFx7WtH8Lq8dYJ2CC7ihAXT1j+unUq4EJuy+46MUFNjmszNdZOxBbz5XThBsflQSggu4AgoAhhtI61fgAMCgf9efQjhkfls57BiXdaW5jgPXW4uJ1njq3FGtVSbpc28B43JyBg=="
   }
}

Then I expected a message to responder with transaction to sign - but it never happens. After a few seconds I channel closes and in node logs I can see:

19:03:34.299 [error] CAUGHT exit:{noproc,{gen_server,call,[<0.20569.2>,close]}}, [{gen_server,call,2,[{file,"gen_server.erl"},{line,206}]},{aesc_session_noise,close,1,[{file,"/app/apps/aechannel/src/aesc_session_noise.erl"},{line,103}]},{aesc_fsm,terminate,3,[{file,"/app/apps/aechannel/src/aesc_fsm.erl"},{line,1953}]},{gen_statem,terminate,6,[{file,"gen_statem.erl"},{line,1828}]},{proc_lib,init_p_do_apply,3,[{file,"proc_lib.erl"},{line,247}]}]

What I’m doing wrong?

I’m using Aeternity node v.4.0.0 and WebSocket Test Client (chrome plugin). For signing transaction I’m using Java SDK.

When I intentionally signed transaction with some random private key, I got error message as expected:

{
   "channel_id":null,
   "error":{
      "code":3,
      "data":[
         {
            "code":1010,
            "message":"Broken encoding: transaction"
         }
      ],
      "message":"Rejected",
      "request":{
         "jsonrpc":"2.0",
         "method":"channels.initiator_sign",
         "params":{
            "signed_tx":"tx_+MoLAfhCuEB/8CyPkQ3XuAZY+5ArCJUd3JwteDy7W0Rz1U6bYdoCj9kFStB5rNcBIAGBM9183jNl2/g+8nAeMyFM68IsPUABuIL4gAsBwLh7+HkyAaEBV1+B/7Cil7dyXcZx2gsXabH8XL5FOFx7WtH8Lq8dYJ2CC7ihAXT1j+unUq4EJuy+46MUFNjmszNdZOxBbz5XThBsflQSggu4AgoAhhtI61fgAMCgf9efQjhkfls57BiXdaW5jgPXW4uJ1njq3FGtVSbpc28B43JyBg1=="
         }
      }
   },
   "id":null,
   "jsonrpc":"2.0",
   "version":1
}

Could you please give me some advices how to properly use WebSocket & channel api?

Hi zb0oj,

Could you backtrack a bit from the log message and see if you can find any information on why the fsm related to the noise session <0.20569.2> is terminating? The message you included above basically only says that while the fsm was terminating, it ensured that the noise session would also die (noticing that it was already dead).

@ulf.wiger Thanks for your answer.

There is entire log from my aeternity node:

Exec: /home/aeternity/node/erts-9.3.3/bin/erlexec -boot /home/aeternity/node/releases/4.0.0/aeternity -mode embedded -boot_var ERTS_LIB_DIR /home/aeternity/node/lib -config /home/aeternity/node/releases/4.0.0/sys.config -args_file /home/aeternity/node/releases/4.0.0/vm.args -- console -noshell -noinput -aecore expected_mine_rate 15000
Root: /home/aeternity/node
/home/aeternity/node

=INFO REPORT==== 31-Jul-2019::15:03:52 ===
Setup running ...

=INFO REPORT==== 31-Jul-2019::15:03:52 ===
Directories verified. Res = ok

=INFO REPORT==== 31-Jul-2019::15:03:52 ===
Setup phase 100

=INFO REPORT==== 31-Jul-2019::15:03:52 ===
Reading config file /home/aeternity/aeternity.yaml

=INFO REPORT==== 31-Jul-2019::15:03:52 ===
    validation: "/home/aeternity/aeternity.yaml"
    result: [{ok,#{<<"chain">> => #{<<"persist">> => true},
                   <<"fork_management">> =>
                       #{<<"network_id">> => <<"ae_uat">>},
                   <<"http">> =>
                       #{<<"cors">> => #{<<"allow_domains">> => [<<"*">>]},
                         <<"external">> => #{<<"port">> => 3013},
                         <<"internal">> =>
                             #{<<"debug_endpoints">> => true,
                               <<"listen_address">> => <<"0.0.0.0">>}},
                   <<"keys">> =>
                       #{<<"dir">> => <<"./keys">>,
                         <<"peer_password">> => <<"top secret">>},
                   <<"logging">> => #{<<"level">> => <<"debug">>},
                   <<"mining">> =>
                       #{<<"autostart">> => true,
                         <<"beneficiary">> =>
                             <<"ak_2mwRmUeYmfuW93ti9HMSUJzCk1EYcQEfikVSzgo6k2VghsWhgU">>,
                         <<"beneficiary_reward_delay">> => 2,
                         <<"cuckoo">> =>
                             #{<<"edge_bits">> => 15,
                               <<"miners">> =>
                                   [#{<<"executable">> =>
                                          <<"mean15-generic">>}]},
                         <<"expected_mine_rate">> => 1},
                   <<"peers">> => [],
                   <<"websocket">> =>
                       #{<<"channel">> =>
                             #{<<"listen_address">> => <<"0.0.0.0">>,
                               <<"port">> => 3014}}}}]

=INFO REPORT==== 31-Jul-2019::15:03:52 ===
Set config (aeutils): '$user_config' = [{<<"chain">>,[{<<"persist">>,true}]},
                                        {<<"fork_management">>,
                                         [{<<"network_id">>,<<"ae_uat">>}]},
                                        {<<"http">>,
                                         [{<<"cors">>,
                                           [{<<"allow_domains">>,[<<"*">>]}]},
                                          {<<"external">>,[{<<"port">>,3013}]},
                                          {<<"internal">>,
                                           [{<<"debug_endpoints">>,true},
                                            {<<"listen_address">>,
                                             <<"0.0.0.0">>}]}]},
                                        {<<"keys">>,
                                         [{<<"dir">>,<<"./keys">>},
                                          {<<"peer_password">>,
                                           <<"top secret">>}]},
                                        {<<"logging">>,
                                         [{<<"level">>,<<"debug">>}]},
                                        {<<"mining">>,
                                         [{<<"autostart">>,true},
                                          {<<"beneficiary">>,
                                           <<"ak_2mwRmUeYmfuW93ti9HMSUJzCk1EYcQEfikVSzgo6k2VghsWhgU">>},
                                          {<<"beneficiary_reward_delay">>,2},
                                          {<<"cuckoo">>,
                                           [{<<"edge_bits">>,15},
                                            {<<"miners">>,
                                             [{<<"executable">>,
                                               <<"mean15-generic">>}]}]},
                                          {<<"expected_mine_rate">>,1}]},
                                        {<<"peers">>,[]},
                                        {<<"websocket">>,
                                         [{<<"channel">>,
                                           [{<<"listen_address">>,
                                             <<"0.0.0.0">>},
                                            {<<"port">>,3014}]}]}]

=INFO REPORT==== 31-Jul-2019::15:03:52 ===
Set config (aeutils): '$user_map' = #{<<"chain">> => #{<<"persist">> => true},
                                      <<"fork_management">> =>
                                          #{<<"network_id">> => <<"ae_uat">>},
                                      <<"http">> =>
                                          #{<<"cors">> =>
                                                #{<<"allow_domains">> =>
                                                      [<<"*">>]},
                                            <<"external">> =>
                                                #{<<"port">> => 3013},
                                            <<"internal">> =>
                                                #{<<"debug_endpoints">> =>
                                                      true,
                                                  <<"listen_address">> =>
                                                      <<"0.0.0.0">>}},
                                      <<"keys">> =>
                                          #{<<"dir">> => <<"./keys">>,
                                            <<"peer_password">> =>
                                                <<"top secret">>},
                                      <<"logging">> =>
                                          #{<<"level">> => <<"debug">>},
                                      <<"mining">> =>
                                          #{<<"autostart">> => true,
                                            <<"beneficiary">> =>
                                                <<"ak_2mwRmUeYmfuW93ti9HMSUJzCk1EYcQEfikVSzgo6k2VghsWhgU">>,
                                            <<"beneficiary_reward_delay">> =>
                                                2,
                                            <<"cuckoo">> =>
                                                #{<<"edge_bits">> => 15,
                                                  <<"miners">> =>
                                                      [#{<<"executable">> =>
                                                             <<"mean15-generic">>}]},
                                            <<"expected_mine_rate">> => 1},
                                      <<"peers">> => [],
                                      <<"websocket">> =>
                                          #{<<"channel">> =>
                                                #{<<"listen_address">> =>
                                                      <<"0.0.0.0">>,
                                                  <<"port">> => 3014}}}

=INFO REPORT==== 31-Jul-2019::15:03:52 ===
aeu_env:read_config()-> ok

=INFO REPORT==== 31-Jul-2019::15:03:52 ===
Setup phase 110
setenv K=autostart, V=true
setenv K=persist, V=true

=INFO REPORT==== 31-Jul-2019::15:03:52 ===
aecore_app:check_env()-> ok

=INFO REPORT==== 31-Jul-2019::15:03:52 ===
aec_dev_reward:ensure_env()-> ok

=INFO REPORT==== 31-Jul-2019::15:03:52 ===
aehttp_app:check_env()-> ok

=INFO REPORT==== 31-Jul-2019::15:03:52 ===
aec_hard_forks:check_env()-> ok

=INFO REPORT==== 31-Jul-2019::15:03:52 ===
aec_mining:check_env()-> ok

=INFO REPORT==== 31-Jul-2019::15:03:52 ===
Setup phase 200

=INFO REPORT==== 31-Jul-2019::15:03:55 ===
aec_db:check_db()-> ok

=INFO REPORT==== 31-Jul-2019::15:03:55 ===
Setup finished processing hooks (Mode=normal)...
15:03:55.203 [info] Application lager started on node [email protected]
15:03:55.205 [info] Application jsx started on node [email protected]
15:03:55.205 [info] Application eblake2 started on node [email protected]
15:03:55.205 [info] Application base58 started on node [email protected]
15:03:55.206 [info] Application aeserialization started on node [email protected]
15:03:55.206 [info] Application getopt started on node [email protected]
15:03:55.207 [info] Application aebytecode started on node [email protected]
15:03:55.207 [info] Application aevm started on node [email protected]
15:03:55.207 [info] Application aetx started on node [email protected]
15:03:55.207 [info] Application aecontract started on node [email protected]
15:03:55.207 [info] Application sext started on node [email protected]
15:03:55.208 [info] Application aechannel started on node [email protected]
15:03:55.208 [info] Application unicode_util_compat started on node [email protected]
15:03:55.208 [info] Application idna started on node [email protected]
15:03:55.208 [info] Application aens started on node [email protected]
15:03:55.208 [info] Application aeoracle started on node [email protected]
15:03:55.208 [info] Application aeprimop started on node [email protected]
15:03:55.208 [info] Application aega started on node [email protected]
15:03:55.208 [info] Application aefate started on node [email protected]
15:03:55.209 [info] Application inets started on node [email protected]
15:03:55.209 [info] Application cowlib started on node [email protected]
15:03:55.209 [info] Application ranch started on node [email protected]
15:03:55.209 [info] Application cowboy started on node [email protected]
15:03:55.209 [info] Application rfc3339 started on node [email protected]
15:03:55.210 [info] Application jesse started on node [email protected]
15:03:55.210 [info] Starting aecore node
15:03:55.224 [info] Loaded empty persisted chain
15:03:55.225 [info] Initializing keys manager
15:03:55.265 [info] aec_peers started for "pp_HdcpgTX...EcSyF7X"
15:03:56.039 [warning] lager_error_logger_h dropped 169 messages in the last second that exceeded the limit of 50 messages/sec
15:08:48.341 [error] CAUGHT exit:{noproc,{gen_server,call,[<0.32271.0>,close]}}, [{gen_server,call,2,[{file,"gen_server.erl"},{line,206}]},{aesc_session_noise,close,1,[{file,"/app/apps/aechannel/src/aesc_session_noise.erl"},{line,103}]},{aesc_fsm,terminate,3,[{file,"/app/apps/aechannel/src/aesc_fsm.erl"},{line,1953}]},{gen_statem,terminate,6,[{file,"gen_statem.erl"},{line,1828}]},{proc_lib,init_p_do_apply,3,[{file,"proc_lib.erl"},{line,247}]}]

My aeternity.yaml config file:

---
peers: []
http:
  external:
    port: 3013
  internal:
    listen_address: 0.0.0.0
    debug_endpoints: true
  cors:
    allow_domains: ["*"]

logging:
  level: debug

websocket:
  channel:
    listen_address: 0.0.0.0
    port: 3014

keys:
  peer_password: "top secret"
  dir: ./keys

chain:
  persist: true

mining:
  beneficiary: "ak_2mwRmUeYmfuW93ti9HMSUJzCk1EYcQEfikVSzgo6k2VghsWhgU"
  beneficiary_reward_delay: 2
  expected_mine_rate: 1
  autostart: true
  cuckoo:
    edge_bits: 15
    miners:
      - executable: mean15-generic

fork_management:
  network_id: ae_uat

Unfortunetly, I don’t see any usefull informations in log. Maybe I miss something?

Since you have "logging": {"level": "debug"}, there should be more detailed log info available in ${AETERNITY_TOP}/log/aeternity.log* (the file aeternity.log contains the latest info; any files named aeternity.log.N where N is a number e.g. between 0 and 13 or so contain earlier output.)

Thanks @ulf.wiger for your advice, I found in logs following line:

2019-08-01 15:07:49.503 [debug] <0.1779.3>@sc_ws_api_jsonrpc:process_incoming:256 CAUGHT E=function_clause / Req = #{<<"jsonrpc">> => <<"2.0">>,<<"method">> => <<"channels.initiator_sign">>,<<"params">> => #{<<"signed_tx">> => <<"tx_+MoLAfhCuEC36UM8tSNncYCV+WySszA6oATjuemTbB9TRXfYQQQ8js0WPjqfsg37090E6MtbQnwFF+U2WFoU+MD1aMIqo9gOuIL4gAsBwLh7+HkyAaEBV1+B/7Cil7dyXcZx2gsXabH8XL5FOFx7WtH8Lq8dYJ2CC7ihAXT1j+unUq4EJuy+46MUFNjmszNdZOxBbz5XThBsflQSggu4AAAAhhtI61fgAMCgbdDgIT4JdWTw9g3mvZu+ql7meENF965Hhf52kwz5A3QB19sGPQ==">>}} / [{aetx,type_to_cb,[signed_tx],[{file,"/app/apps/aetx/src/aetx.erl"},{line,491}]},{aetx,deserialize_from_binary,1,[{file,"/app/apps/aetx/src/aetx.erl"},{line,486}]},{aetx_sign,deserialize_from_binary,1,[{file,"/app/apps/aetx/src/aetx_sign.erl"},{line,187}]},{sc_ws_api_jsonrpc,process_request,2,[{file,"/app/apps/aehttp/src/sc_ws_api_jsonrpc.erl"},{line,532}]},{sc_ws_api_jsonrpc,'-process_incoming/2-fun-2-',3,[{file,"/app/apps/aehttp/src/sc_ws_api_jsonrpc.erl"},{line,248}]},{lists,foldl,3,[{file,"lists.erl"},{line,1263}]},{sc_ws_api_jsonrpc,process_incoming,2,[{file,"/app/apps/aehttp/src/sc_ws_api_jsonrpc.erl"},{line,245}]},{sc_ws_api,process_incoming,1,[{file,"/app/apps/aehttp/src/sc_ws_api.erl"},{line,137}]}]

But I still don’t understand what it means. :frowning:

It indicates why you get “Broken encoding”. The [{aetx,type_to_cb,[signed_tx],[{file,"/app/apps/aetx/src/aetx.erl"},{line,491}] indicates that the type of the encoded transaction is signed_tx where in fact, channel_create_tx is expected. What it looks like is that rather than adding a signature to the signed_tx envelope, you are wrapping it inside another signed_tx envelope.

Could you ensure that you have an up-to-date version of the SDK?

2 Likes

Thanks @ulf.wiger. I very appreciate your help.

I’m using Java SDK version 1.2.0, but it doesn’t support websocket api at this moment. I wrongly assumed, that method sign will solve all my problems :slight_smile:

With your help I made some changes in my code and now I’m getting following error:

2019-08-05 20:35:29.260 [debug] <0.884.14>@sc_ws_api_jsonrpc:process_incoming:256 CAUGHT E={trailing,<<185,157,18,227,46,150,67,37,224,144,242,139,209,58,153,141,204,27,120,48,22,236,15,138,39,54,164,39,197,202,43,93,132,115,172,179,93,192,186,10,123,200,89,91,105,14,196,74,89,77>>,<<178,185,157,18,227,46,150,67,37,224,144,242,139,209,58,153,141,204,27,120,48,22,236,15,138,39,54,164,39,197,202,43,93,132,115,172,179,93,192,186,10,123,200,89,91,105,14,196,74,89,77,129,192,94,44,215,39,252,102,130,156,184,55,0>>,<<129,192,94,44,215,39,252,102,130,156,184,55,0>>} / Req = #{<<"jsonrpc">> => <<"2.0">>,<<"method">> => <<"channels.initiator_sign">>,<<"params">> => #{<<"signed_tx">> => <<"tx_srmdEuMulkMl4JDyi9E6mY3MG3gwFuwPiic2pCfFyitdhHOss13Augp7yFlbaQ7ESllNgcBeLNcn/GaCnLg3ACmp/V8=">>}} / [{aeser_rlp,decode,1,[{file,"/app/_build/default/lib/aeserialization/src/aeser_rlp.erl"},{line,60}]},{aeserialization,deserialize,5,[{file,"/app/_build/default/lib/aeserialization/src/aeserialization.erl"},{line,56}]},{aetx_sign,deserialize_from_binary,1,[{file,"/app/apps/aetx/src/aetx_sign.erl"},{line,181}]},{sc_ws_api_jsonrpc,process_request,2,[{file,"/app/apps/aehttp/src/sc_ws_api_jsonrpc.erl"},{line,532}]},{sc_ws_api_jsonrpc,'-process_incoming/2-fun-2-',3,[{file,"/app/apps/aehttp/src/sc_ws_api_jsonrpc.erl"},{line,248}]},{lists,foldl,3,[{file,"lists.erl"},{line,1263}]},{sc_ws_api_jsonrpc,process_incoming,2,[{file,"/app/apps/aehttp/src/sc_ws_api_jsonrpc.erl"},{line,245}]},{sc_ws_api,process_incoming,1,[{file,"/app/apps/aehttp/src/sc_ws_api.erl"},{line,137}]}]

I decoded transaction using Java RLP* and it contains 4 fields:

tag: 11 # Signed transaction	
version: 1
signatures: [] # empty array
transaction: # object

In transaction object I found:

tag: 50 # Channel create transaction
version: 1
initiator:  # initiator address
initiator_amount: 3000
responder: # responder address
responder_amount: 3000
channel_reserve: 0x00
lock_period: 0x00
ttl: 0x00
fee: 0x0FE139190800
delegate_ids: [] # empty array
state_hash: 0x6DD0E0213E097564F0F60DE6BD9BBEAA5EE6784345F7AE4785FE76930CF90374
nonce: 0

Which one should be signed? I have to put any data into signatures field in 1st transaction?

It’s a little bit closer to working solution, I’ll try to debug it tomorrow. Much thanks for your effort.

I am very sorry to tell you that state channel support currently isn’t fully implemented in the Java SDK. the tx type for the creation of a channel is already present. but we haven’t implemented the websocket-client that enables the off-chain communication which is required.

you can follow the progress here:

it will probably take some time until we finish this. will let you know when its done. until then you need to stick with another SDK that already supports state channels and off-chain communication.

edit:

  • if you are interested in contributing to the SDK and help us implementing state channel support let me know :wink:
1 Like

@zb0oj, not having checked the Java SDK code, what you should do is sign the serialized Channel create transaction object, and add that signature to the signatures array in the Signed transaction object.

Code examples in other languages can be found here:

1 Like

Thanks @ulf.wiger @marc0olo, I finally handled this error.

Now I have next problem with state hash. I signed transaction properly (I hope :slight_smile: ), but after signing transaction by responder I’m getting message for both responder/initiator:

{"jsonrpc":"2.0","method":"channels.info","params":{"channel_id":null,"data":{"event":"died"}},"version":1}

Logs says:

2019-08-07 16:58:03.676 [debug] <0.9025.1>@aesc_fsm:report_info:2402 report_info(true, Client = <0.9020.1>, Msg = #{info => bad_state_hash,tag => info,type => report})

I think that I didn’t touched state hash value - it should be changed durning transaction sign?

@marc0olo:

When I finish my first aepp application I will be able to help you with implementation. I integrated your SDK with SpringBoot and prepared some code for state channels, maybe I will find some time for contribution.

EDIT:

After channel params change (I got error when channel_reserve, push_amount, lock_period was 0) I finally opened channel! Thanks @ulf.wiger @marc0olo for your help!

3 Likes