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).

@uwiger 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 aeternity@localhost
15:03:55.205 [info] Application jsx started on node aeternity@localhost
15:03:55.205 [info] Application eblake2 started on node aeternity@localhost
15:03:55.205 [info] Application base58 started on node aeternity@localhost
15:03:55.206 [info] Application aeserialization started on node aeternity@localhost
15:03:55.206 [info] Application getopt started on node aeternity@localhost
15:03:55.207 [info] Application aebytecode started on node aeternity@localhost
15:03:55.207 [info] Application aevm started on node aeternity@localhost
15:03:55.207 [info] Application aetx started on node aeternity@localhost
15:03:55.207 [info] Application aecontract started on node aeternity@localhost
15:03:55.207 [info] Application sext started on node aeternity@localhost
15:03:55.208 [info] Application aechannel started on node aeternity@localhost
15:03:55.208 [info] Application unicode_util_compat started on node aeternity@localhost
15:03:55.208 [info] Application idna started on node aeternity@localhost
15:03:55.208 [info] Application aens started on node aeternity@localhost
15:03:55.208 [info] Application aeoracle started on node aeternity@localhost
15:03:55.208 [info] Application aeprimop started on node aeternity@localhost
15:03:55.208 [info] Application aega started on node aeternity@localhost
15:03:55.208 [info] Application aefate started on node aeternity@localhost
15:03:55.209 [info] Application inets started on node aeternity@localhost
15:03:55.209 [info] Application cowlib started on node aeternity@localhost
15:03:55.209 [info] Application ranch started on node aeternity@localhost
15:03:55.209 [info] Application cowboy started on node aeternity@localhost
15:03:55.209 [info] Application rfc3339 started on node aeternity@localhost
15:03:55.210 [info] Application jesse started on node aeternity@localhost
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 @uwiger 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 @uwiger. 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 @uwiger @marco.chain, 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?

@marco.chain:

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 @uwiger @marco.chain for your help!

3 Likes