From caddd337dacf596a8404dbe51fc45d05cb189602 Mon Sep 17 00:00:00 2001
From: Roman Khlopkov <roman.khlopkov@demlabs.net>
Date: Fri, 11 Mar 2022 17:03:25 +0000
Subject: [PATCH] support-5685

---
 .../include/wrapping_dap_chain_common.h       |   4 +-
 .../common/src/wrapping_dap_chain_datum_tx.c  |   2 +-
 .../net/include/libdap_chain_net_python.h     |   5 +
 .../srv/include/wrapping_dap_chain_net_srv.h  |  18 +-
 .../wrapping_dap_chain_net_srv_client.h       |  60 ++-
 ...wrapping_dap_chain_net_srv_client_remote.h |  85 +++++
 .../net/srv/src/wrapping_dap_chain_net_srv.c  | 300 ++++++---------
 .../src/wrapping_dap_chain_net_srv_client.c   | 350 +++++++++++++++---
 ...wrapping_dap_chain_net_srv_client_remote.c |  50 +++
 .../crypto/include/wrapping_dap_hash.h        |   5 +
 10 files changed, 605 insertions(+), 274 deletions(-)
 create mode 100644 modules/cellframe-sdk/net/srv/include/wrapping_dap_chain_net_srv_client_remote.h
 create mode 100644 modules/cellframe-sdk/net/srv/src/wrapping_dap_chain_net_srv_client_remote.c

diff --git a/modules/cellframe-sdk/common/include/wrapping_dap_chain_common.h b/modules/cellframe-sdk/common/include/wrapping_dap_chain_common.h
index ca4b282b..e6b91b64 100644
--- a/modules/cellframe-sdk/common/include/wrapping_dap_chain_common.h
+++ b/modules/cellframe-sdk/common/include/wrapping_dap_chain_common.h
@@ -278,8 +278,8 @@ static PyTypeObject DapChainNetSrvUIDObject_DapChainNetSrvUIDObjectType = {
     PyType_GenericNew,               /* tp_new */
 };
 
-static bool PyDapChainNetSrvUid_Check(PyObject *a_obj){
-    return PyObject_TypeCheck(a_obj, &DapChainNetSrvUIDObject_DapChainNetSrvUIDObjectType);
+static bool PyDapChainNetSrvUid_Check(PyDapChainNetSrvUIDObject *a_obj){
+    return !PyObject_TypeCheck(a_obj, &DapChainNetSrvUIDObject_DapChainNetSrvUIDObjectType);
 }
 
 /*=================*/
diff --git a/modules/cellframe-sdk/common/src/wrapping_dap_chain_datum_tx.c b/modules/cellframe-sdk/common/src/wrapping_dap_chain_datum_tx.c
index 79d2ed0d..eb80c92e 100644
--- a/modules/cellframe-sdk/common/src/wrapping_dap_chain_datum_tx.c
+++ b/modules/cellframe-sdk/common/src/wrapping_dap_chain_datum_tx.c
@@ -112,7 +112,7 @@ PyObject *dap_chain_datum_tx_add_out_cond_item_py(PyObject *self, PyObject *args
         return NULL;
     void *cond = (void*)PyBytes_AsString(obj_cond_bytes);
     int res = dap_chain_datum_tx_add_out_cond_item(&(((PyDapChainDatumTxObject*)self)->datum_tx),
-                                                   ((PyCryptoKeyObject*)obj_key)->key,
+                                                   ((PyDapPkeyObject*)obj_key)->pkey,
                                                    ((PyDapChainNetSrvUIDObject*)obj_srv_uid)->net_srv_uid,
                                                    value, value_max_per_unit,
                                                    ((PyDapChainNetSrvPriceUnitUIDObject*)obj_srv_price_unit_uid)->price_unit_uid,
diff --git a/modules/cellframe-sdk/net/include/libdap_chain_net_python.h b/modules/cellframe-sdk/net/include/libdap_chain_net_python.h
index d23c6bfc..d3045eaa 100644
--- a/modules/cellframe-sdk/net/include/libdap_chain_net_python.h
+++ b/modules/cellframe-sdk/net/include/libdap_chain_net_python.h
@@ -152,6 +152,11 @@ static PyTypeObject DapChainNetObject_DapChainNetObjectType = {
     PyType_GenericNew,               /* tp_new */
 };
 
+static bool PyDapChainNet_Check(PyDapChainNetObject *pyNet)
+{
+    return !PyObject_TypeCheck(pyNet, &DapChainNetObject_DapChainNetObjectType);
+}
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/modules/cellframe-sdk/net/srv/include/wrapping_dap_chain_net_srv.h b/modules/cellframe-sdk/net/srv/include/wrapping_dap_chain_net_srv.h
index 6a597a9c..a1364fe4 100644
--- a/modules/cellframe-sdk/net/srv/include/wrapping_dap_chain_net_srv.h
+++ b/modules/cellframe-sdk/net/srv/include/wrapping_dap_chain_net_srv.h
@@ -2,15 +2,19 @@
 
 #include "Python.h"
 #include "dap_chain_net_srv.h"
+#include "dap_chain_net_srv_stream_session.h"
 #include "uthash.h"
-#include "wrapping_dap_chain_net_srv_client.h"
 #include "wrapping_dap_chain_common.h"
-//#include "wrapping_dap_chain_net_srv_common.h"
+#include "wrapping_dap_chain_net_srv_client_remote.h"
 
 typedef struct PyDapChainNetSrv{
     PyObject_HEAD
     dap_chain_net_srv_t *srv;
-    bool original;
+    PyObject *callbackRequested;
+    PyObject *callbackSuccess;
+    PyObject *callbackError;
+    PyObject *callbackReceiptNext;
+    PyObject *callbackReadWithOutData;
 }PyDapChainNetSrvObject;
 
 int PyDapChainNetSrv_init(PyDapChainNetSrvObject* self, PyObject *args, PyObject *kwds);
@@ -22,6 +26,10 @@ PyObject *wrapping_dap_chain_net_srv_get_price_list(PyObject *self, void *closur
 PyObject *wrapping_dap_chain_net_srv_get_ban_list(PyObject *self, void *closure);
 PyObject *wrapping_dap_chain_net_srv_get_grace_period(PyObject *self, void *closure);
 
+//Function
+PyObject *wrapping_dap_chain_net_srv_set_callback_channel(PyObject *self, PyObject *args);
+//PyObject *wrapping_dap_chain_net_srv_issue_receipt(PyObject *self, PyObject *args);
+
 static PyMethodDef DapChainNetSrvMethods[]={
         {NULL, NULL, 0, NULL}
 };
@@ -37,7 +45,7 @@ static PyTypeObject DapChainNetSrvObject_DapChainNetSrvObjectType = {
         "CellFrame.ChainNetSrv",        /* tp_name */
         sizeof(PyDapChainNetSrvObject), /* tp_basicsize */
         0,                                /* tp_itemsize */
-        (destructor)PyDapChainNetSrv_dealloc,                                /* tp_dealloc */
+        0,                                /* tp_dealloc */
         0,                                /* tp_print */
         0,                                /* tp_getattr */
         0,                                /* tp_setattr */
@@ -54,7 +62,7 @@ static PyTypeObject DapChainNetSrvObject_DapChainNetSrvObjectType = {
         0,                                /* tp_as_buffer */
         Py_TPFLAGS_DEFAULT |
         Py_TPFLAGS_BASETYPE,          /* tp_flags */
-        "Chain net srv object",               /* tp_doc */
+        "Chain net service object",               /* tp_doc */
         0,		                          /* tp_traverse */
         0,		                          /* tp_clear */
         0,		                          /* tp_richcompare */
diff --git a/modules/cellframe-sdk/net/srv/include/wrapping_dap_chain_net_srv_client.h b/modules/cellframe-sdk/net/srv/include/wrapping_dap_chain_net_srv_client.h
index e14297d9..2051f1b9 100644
--- a/modules/cellframe-sdk/net/srv/include/wrapping_dap_chain_net_srv_client.h
+++ b/modules/cellframe-sdk/net/srv/include/wrapping_dap_chain_net_srv_client.h
@@ -1,44 +1,34 @@
-//
-// Created by blus on 05.02.2022.
-//
+#pragma once
 
 #include "Python.h"
-#include "datetime.h"
-#include "dap_chain_net_srv.h"
-
-#ifndef WRAPPING_DAP_CHAIN_NET_SRV_CLIENT_H
-#define WRAPPING_DAP_CHAIN_NET_SRV_CLIENT_H
+#include "dap_chain_net_srv_client.h"
+#include "libdap_chain_net_python.h"
 
 typedef struct PyDapChainNetSrvClient{
     PyObject_HEAD
-    dap_chain_net_srv_client_remote_t *srv_client;
+    dap_chain_net_srv_client_t *srv_client;
+    PyObject *callback_connected;
+    PyObject *callback_disconnected;
+    PyObject *callback_deleted;
+    PyObject *callback_check;
+    PyObject *callback_sign;
+    PyObject *callback_success;
+    PyObject *callback_error;
+    PyObject *callback_data;
 }PyDapChainNetSrvClientObject;
 
-PyObject *wrapping_dap_chain_net_srv_client_get_ch(PyObject *self, void *closure);
-PyObject *wrapping_dap_chain_net_srv_client_get_ts_created(PyObject *self, void *closure);
-PyObject *wrapping_dap_chain_net_srv_client_get_created(PyObject *self, void *closure);
-PyObject *wrapping_dap_chain_net_srv_client_get_stream_worker(PyObject *self, void *closure);
-PyObject *wrapping_dap_chain_net_srv_client_get_session_id(PyObject *self, void *closure);
-PyObject *wrapping_dap_chain_net_srv_client_get_bytes_received(PyObject *self, void *closure);
-PyObject *wrapping_dap_chain_net_srv_client_get_bytes_send(PyObject *self, void *closure);
-//PyObject *wrapping_dap_chain_net_srv_client_get_bytes_prev(PyObject *self, void *closure);
-//PyObject *wrapping_dap_chain_net_srv_client_get_bytes_next(PyObject *self, void *closure);
+int PyDapChainNetSrvClient_init(PyDapChainNetSrvClientObject* self, PyObject *args, PyObject *kwds);
+PyObject *wrapping_dap_chain_net_srv_client_check(PyObject *self, PyObject *args);
+PyObject *wrapping_dap_chain_net_srv_client_request(PyObject *self, PyObject *args);
+PyObject *wrapping_dap_chain_net_srv_client_write(PyObject *self, PyObject *args);
 
 static PyMethodDef DapChainNetSrvClientMethods[]={
+        {"check", (PyCFunction)wrapping_dap_chain_net_srv_client_check, METH_VARARGS, ""},
+        {"request", (PyCFunction)wrapping_dap_chain_net_srv_client_request, METH_VARARGS, ""},
+        {"write", (PyCFunction)wrapping_dap_chain_net_srv_client_write, METH_VARARGS, ""},
         {NULL, NULL, 0, NULL}
 };
 
-static PyGetSetDef DapChaiNetSrvClientGetsSets[] = {
-        {"ch", (getter)wrapping_dap_chain_net_srv_client_get_ch, NULL, NULL, NULL},
-        {"tsCreated", (getter)wrapping_dap_chain_net_srv_client_get_ts_created, NULL, NULL, NULL},
-        {"created", (getter)wrapping_dap_chain_net_srv_client_get_created, NULL, NULL, NULL},
-        {"streamWorker", (getter)wrapping_dap_chain_net_srv_client_get_stream_worker, NULL, NULL, NULL},
-        {"sessionId", (getter)wrapping_dap_chain_net_srv_client_get_session_id, NULL, NULL, NULL},
-        {"bytesReceived", (getter)wrapping_dap_chain_net_srv_client_get_bytes_received, NULL, NULL, NULL},
-        {"bytesSend", (getter)wrapping_dap_chain_net_srv_client_get_bytes_send, NULL, NULL, NULL},
-        {NULL}
-};
-
 static PyTypeObject DapChainNetSrvClientObject_DapChainNetSrvClientObjectType = {
         PyVarObject_HEAD_INIT(NULL, 0)
         "CellFrame.ChainNetSrvClient",        /* tp_name */
@@ -60,25 +50,23 @@ static PyTypeObject DapChainNetSrvClientObject_DapChainNetSrvClientObjectType =
         0,                                /* tp_setattro */
         0,                                /* tp_as_buffer */
         Py_TPFLAGS_DEFAULT |
-        Py_TPFLAGS_BASETYPE,          /* tp_flags */
-        "Chain net srv client object",               /* tp_doc */
+        Py_TPFLAGS_BASETYPE,              /* tp_flags */
+        "Chain net service client object",/* tp_doc */
         0,		                          /* tp_traverse */
         0,		                          /* tp_clear */
         0,		                          /* tp_richcompare */
         0,                                /* tp_weaklistoffset */
         0,		                          /* tp_iter */
         0,		                          /* tp_iternext */
-        DapChainNetSrvClientMethods,        /* tp_methods */
+        DapChainNetSrvClientMethods,      /* tp_methods */
         0,                                /* tp_members */
-        DapChaiNetSrvClientGetsSets,        /* tp_getset */
+        0,                                /* tp_getset */
         0,                                /* tp_base */
         0,                                /* tp_dict */
         0,                                /* tp_descr_get */
         0,                                /* tp_descr_set */
         0,                                /* tp_dictoffset */
-        0,                                /* tp_init */
+        (initproc)PyDapChainNetSrvClient_init,      /* tp_init */
         0,                                /* tp_alloc */
         PyType_GenericNew,                /* tp_new */
 };
-
-#endif //WRAPPING_DAP_CHAIN_NET_SRV_CLIENT_H
diff --git a/modules/cellframe-sdk/net/srv/include/wrapping_dap_chain_net_srv_client_remote.h b/modules/cellframe-sdk/net/srv/include/wrapping_dap_chain_net_srv_client_remote.h
new file mode 100644
index 00000000..d8b8d19a
--- /dev/null
+++ b/modules/cellframe-sdk/net/srv/include/wrapping_dap_chain_net_srv_client_remote.h
@@ -0,0 +1,85 @@
+//
+// Created by blus on 05.02.2022.
+//
+
+#include "Python.h"
+#include "datetime.h"
+#include "dap_chain_net_srv.h"
+
+#ifndef WRAPPING_DAP_CHAIN_NET_SRV_CLIENT_REMOTE_H
+#define WRAPPING_DAP_CHAIN_NET_SRV_CLIENT_REMOTE_H
+
+typedef struct PyDapChainNetSrvClientRemote{
+    PyObject_HEAD
+    dap_chain_net_srv_client_remote_t *srv_client_remote;
+}PyDapChainNetSrvClientRemoteObject;
+
+PyObject *wrapping_dap_chain_net_srv_client_remote_get_ch(PyObject *self, void *closure);
+PyObject *wrapping_dap_chain_net_srv_client_remote_get_ts_created(PyObject *self, void *closure);
+PyObject *wrapping_dap_chain_net_srv_client_remote_get_created(PyObject *self, void *closure);
+PyObject *wrapping_dap_chain_net_srv_client_remote_get_stream_worker(PyObject *self, void *closure);
+PyObject *wrapping_dap_chain_net_srv_client_remote_get_session_id(PyObject *self, void *closure);
+PyObject *wrapping_dap_chain_net_srv_client_remote_get_bytes_received(PyObject *self, void *closure);
+PyObject *wrapping_dap_chain_net_srv_client_remote_get_bytes_send(PyObject *self, void *closure);
+//PyObject *wrapping_dap_chain_net_srv_client_remote_get_bytes_prev(PyObject *self, void *closure);
+//PyObject *wrapping_dap_chain_net_srv_client_remote_get_bytes_next(PyObject *self, void *closure);
+
+static PyMethodDef DapChainNetSrvClientRemoteMethods[]={
+        {NULL, NULL, 0, NULL}
+};
+
+static PyGetSetDef DapChaiNetSrvClientRemoteGetsSets[] = {
+        {"ch", (getter)wrapping_dap_chain_net_srv_client_remote_get_ch, NULL, NULL, NULL},
+        {"tsCreated", (getter)wrapping_dap_chain_net_srv_client_remote_get_ts_created, NULL, NULL, NULL},
+        {"created", (getter)wrapping_dap_chain_net_srv_client_remote_get_created, NULL, NULL, NULL},
+        {"streamWorker", (getter)wrapping_dap_chain_net_srv_client_remote_get_stream_worker, NULL, NULL, NULL},
+        {"sessionId", (getter)wrapping_dap_chain_net_srv_client_remote_get_session_id, NULL, NULL, NULL},
+        {"bytesReceived", (getter)wrapping_dap_chain_net_srv_client_remote_get_bytes_received, NULL, NULL, NULL},
+        {"bytesSend", (getter)wrapping_dap_chain_net_srv_client_remote_get_bytes_send, NULL, NULL, NULL},
+        {NULL}
+};
+
+static PyTypeObject DapChainNetSrvClientRemoteObject_DapChainNetSrvClientRemoteObjectType = {
+        PyVarObject_HEAD_INIT(NULL, 0)
+        "CellFrame.ChainNetSrvClientRemote",        /* tp_name */
+        sizeof(PyDapChainNetSrvClientRemoteObject), /* tp_basicsize */
+        0,                                /* tp_itemsize */
+        0,                                /* tp_dealloc */
+        0,                                /* tp_print */
+        0,                                /* tp_getattr */
+        0,                                /* tp_setattr */
+        0,                                /* tp_reserved */
+        0,                                /* tp_repr */
+        0,                                /* tp_as_number */
+        0,                                /* tp_as_sequence */
+        0,                                /* tp_as_mapping */
+        0,                                /* tp_hash  */
+        0,                                /* tp_call */
+        0,                                /* tp_str */
+        0,                                /* tp_getattro */
+        0,                                /* tp_setattro */
+        0,                                /* tp_as_buffer */
+        Py_TPFLAGS_DEFAULT |
+        Py_TPFLAGS_BASETYPE,          /* tp_flags */
+        "Chain net service client remote object",               /* tp_doc */
+        0,		                          /* tp_traverse */
+        0,		                          /* tp_clear */
+        0,		                          /* tp_richcompare */
+        0,                                /* tp_weaklistoffset */
+        0,		                          /* tp_iter */
+        0,		                          /* tp_iternext */
+        DapChainNetSrvClientRemoteMethods,        /* tp_methods */
+        0,                                /* tp_members */
+        DapChaiNetSrvClientRemoteGetsSets,        /* tp_getset */
+        0,                                /* tp_base */
+        0,                                /* tp_dict */
+        0,                                /* tp_descr_get */
+        0,                                /* tp_descr_set */
+        0,                                /* tp_dictoffset */
+        0,                                /* tp_init */
+        0,                                /* tp_alloc */
+        PyType_GenericNew,                /* tp_new */
+};
+
+#endif //WRAPPING_DAP_CHAIN_NET_SRV_CLIENT_REMOTE_H
+
diff --git a/modules/cellframe-sdk/net/srv/src/wrapping_dap_chain_net_srv.c b/modules/cellframe-sdk/net/srv/src/wrapping_dap_chain_net_srv.c
index 9fd904d0..eda94181 100644
--- a/modules/cellframe-sdk/net/srv/src/wrapping_dap_chain_net_srv.c
+++ b/modules/cellframe-sdk/net/srv/src/wrapping_dap_chain_net_srv.c
@@ -1,91 +1,29 @@
 #include "wrapping_dap_chain_net_srv.h"
 
-enum _wrapping_dap_chain_net_srv_type_callbacks{
-    WRAPPING_DAP_CHAIN_NET_SERV_CALLBACK_DATA_REQUESTED,
-    WRAPPING_DAP_CHAIN_NET_SERV_CALLBACK_DATA_RESPONSE_SUCCESS,
-    WRAPPING_DAP_CHAIN_NET_SERV_CALLBACK_DATA_RESPONSE_ERROR,
-    WRAPPING_DAP_CHAIN_NET_SERV_CALLBACK_DATA_RECEIPT_NEXT_SUCCESS,
-    WRAPPING_DAP_CHAIN_NET_SERV_CALLBACK_DATA_STREAM_CH_READ,
-    WRAPPING_DAP_CHAIN_NET_SERV_CALLBACK_DATA_CLIENT_SUCCESS
-};
-
-typedef struct _wrapping_dap_chain_net_srv_callbacks_key{
-    enum _wrapping_dap_chain_net_srv_type_callbacks type;
-    dap_chain_net_srv_t  *srv;
-}_wrapping_dap_chain_net_srv_callbacks_key_t;
-
-typedef struct _wrapping_dap_chain_net_srv_callbacks{
-    _wrapping_dap_chain_net_srv_callbacks_key_t *key;
-    dap_chain_net_srv_uid_t uid;
-    PyObject *func;
-    UT_hash_handle hh;
-}_wrapping_dap_chain_net_srv_callbacks_t;
-
-static _wrapping_dap_chain_net_srv_callbacks_t *_s_callbacks = NULL;
-
-void _wrapping_dap_chain_net_srv_del(_wrapping_dap_chain_net_srv_callbacks_t *a_callback){
-    HASH_DEL(_s_callbacks, a_callback);
-    Py_XINCREF(a_callback->func);
-}
-
-PyObject* _wrapping_dap_chain_net_srv_search(_wrapping_dap_chain_net_srv_callbacks_key_t *a_key){
-    _wrapping_dap_chain_net_srv_callbacks_t *callbacks = NULL;
-    HASH_FIND(hh, _s_callbacks, a_key, sizeof(_wrapping_dap_chain_net_srv_callbacks_key_t), callbacks);
-    if (callbacks == NULL){
-        return Py_None;
-    } else {
-        return callbacks->func;
-    }
-}
-
-_wrapping_dap_chain_net_srv_callbacks_t* _wrapping_dap_chain_net_srv_search_el(_wrapping_dap_chain_net_srv_callbacks_key_t *a_key){
-    _wrapping_dap_chain_net_srv_callbacks_t *callbacks = NULL;
-    HASH_FIND(hh, _s_callbacks, a_key, sizeof(_wrapping_dap_chain_net_srv_callbacks_key_t), callbacks);
-    return callbacks;
-}
-
-int _wrapping_dap_chain_net_srv_add(
-                enum _wrapping_dap_chain_net_srv_type_callbacks a_type,
-                dap_chain_net_srv_t *a_srv,
-                dap_chain_net_srv_uid_t a_uid,
-                PyObject *a_obj_func){
-    if (PyCallable_Check(a_obj_func)){
-        _wrapping_dap_chain_net_srv_callbacks_t *callbacks = DAP_NEW(_wrapping_dap_chain_net_srv_callbacks_t);
-        _wrapping_dap_chain_net_srv_callbacks_key_t *l_key = DAP_NEW(_wrapping_dap_chain_net_srv_callbacks_key_t);
-        l_key->type = a_type;
-        l_key->srv = a_srv;
-        callbacks->key = l_key;
-        callbacks->uid = a_uid;
-        callbacks->func = a_obj_func;
-        Py_XINCREF(a_obj_func);
-        HASH_ADD(hh, _s_callbacks, key, sizeof(_wrapping_dap_chain_net_srv_callbacks_key_t), callbacks);
-        return 0;
-    }
-    return -1;
-}
+#define LOG_TAG "wrapping_dap_chain_net_srv"
 
 PyObject *_wrapping_dac_chain_callback_data_t_get_tuple(
-        dap_chain_net_srv_t *a_srv, //NOT USAGE
+        dap_chain_net_srv_t *a_srv,
         uint32_t a_usage_id,
         dap_chain_net_srv_client_remote_t * a_srv_client,
         const void *a_custom_data,
         size_t a_custom_data_size){
-    PyDapChainNetSrvClientObject *l_obj_srv_client = NULL;
+    PyDapChainNetSrvObject *pyNetSrvObj = (PyDapChainNetSrvObject *)a_srv->_inheritor;
+    PyDapChainNetSrvClientRemoteObject *l_obj_srv_client = NULL;
     if (a_srv_client == NULL){
-        l_obj_srv_client = (PyDapChainNetSrvClientObject *)Py_None;
+        l_obj_srv_client = (PyDapChainNetSrvClientRemoteObject *)Py_None;
     } else {
-        l_obj_srv_client = PyObject_New(PyDapChainNetSrvClientObject,
-                                        &DapChainNetSrvClientObject_DapChainNetSrvClientObjectType);
-        PyObject_Dir((PyObject *) l_obj_srv_client);
-        l_obj_srv_client->srv_client = a_srv_client;
+        l_obj_srv_client = PyObject_New(PyDapChainNetSrvClientRemoteObject,
+                                        &DapChainNetSrvClientRemoteObject_DapChainNetSrvClientRemoteObjectType);
+        l_obj_srv_client->srv_client_remote = a_srv_client;
     }
     PyObject *l_obj_custom_data = NULL;
     if (a_custom_data == NULL || a_custom_data_size == 0){
         l_obj_custom_data = Py_None;
     }else{
-        l_obj_custom_data = PyBytes_FromStringAndSize((char*)a_custom_data_size, (Py_ssize_t)a_custom_data_size);
+        l_obj_custom_data = PyBytes_FromStringAndSize((char*)a_custom_data, (Py_ssize_t)a_custom_data_size);
     }
-    return Py_BuildValue("iOO", l_obj_srv_client, l_obj_custom_data);
+    return Py_BuildValue("OiOO", pyNetSrvObj, a_usage_id, l_obj_srv_client, l_obj_custom_data);
 }
 
 int _w_dap_chain_callback_data_t_requested(
@@ -94,19 +32,20 @@ int _w_dap_chain_callback_data_t_requested(
         dap_chain_net_srv_client_remote_t * a_srv_client,
         const void *a_custom_data,
         size_t a_custom_data_size){
-    _wrapping_dap_chain_net_srv_callbacks_key_t  *l_key = DAP_NEW(_wrapping_dap_chain_net_srv_callbacks_key_t);
-    l_key->srv = a_srv;
-    l_key->type = WRAPPING_DAP_CHAIN_NET_SERV_CALLBACK_DATA_REQUESTED;
-    PyObject *l_func = _wrapping_dap_chain_net_srv_search(l_key);
-    Py_INCREF(l_func);
+    PyDapChainNetSrvObject *pyNetSrvObj = (PyDapChainNetSrvObject *)a_srv->_inheritor;
+    PyObject *l_func = pyNetSrvObj->callbackRequested;
+    if (!PyCallable_Check(l_func)){
+        log_it(L_ERROR, "Python function is not callable");
+        return -1;
+    }
     PyObject *l_arg = _wrapping_dac_chain_callback_data_t_get_tuple(a_srv, a_usage_id, a_srv_client, a_custom_data, a_custom_data_size);
+    PyGILState_STATE state = PyGILState_Ensure();
     PyObject *result = PyObject_CallObject(l_func, l_arg);
+    PyGILState_Release(state);
     if(result == NULL){
         PyErr_Print();
         return -1;
     }
-    Py_XINCREF(l_func);
-    Py_XINCREF(l_arg);
     if (!PyLong_Check(result)){
         return -1;
     }
@@ -116,22 +55,23 @@ int _w_dap_chain_callback_data_t_requested(
 int _w_dap_chain_callback_data_t_response_success(
         dap_chain_net_srv_t *a_srv,
         uint32_t a_usage_id,
-        dap_chain_net_srv_client_remote_t * a_srv_client,
+        dap_chain_net_srv_client_remote_t *a_srv_client,
         const void *a_custom_data,
         size_t a_custom_data_size){
-    _wrapping_dap_chain_net_srv_callbacks_key_t  *l_key = DAP_NEW(_wrapping_dap_chain_net_srv_callbacks_key_t);
-    l_key->srv = a_srv;
-    l_key->type = WRAPPING_DAP_CHAIN_NET_SERV_CALLBACK_DATA_RESPONSE_SUCCESS;
-    PyObject *l_func = _wrapping_dap_chain_net_srv_search(l_key);
-    Py_INCREF(l_func);
+    PyDapChainNetSrvObject *pyNetSrvObj = (PyDapChainNetSrvObject *)a_srv->_inheritor;
+    PyObject *l_func = pyNetSrvObj->callbackSuccess;
+    if (!PyCallable_Check(l_func)){
+        log_it(L_ERROR, "Python function is not callable");
+        return -1;
+    }
     PyObject *l_arg = _wrapping_dac_chain_callback_data_t_get_tuple(a_srv, a_usage_id, a_srv_client, a_custom_data, a_custom_data_size);
+    PyGILState_STATE state = PyGILState_Ensure();
     PyObject *result = PyObject_CallObject(l_func, l_arg);
+    PyGILState_Release(state);
     if(result == NULL){
         PyErr_Print();
         return -1;
     }
-    Py_XINCREF(l_func);
-    Py_XINCREF(l_arg);
     if (!PyLong_Check(result)){
         return -1;
     }
@@ -142,22 +82,23 @@ int _w_dap_chain_callback_data_t_response_success(
 int _w_dap_chain_callback_data_t_response_error(
         dap_chain_net_srv_t *a_srv,
         uint32_t a_usage_id,
-        dap_chain_net_srv_client_remote_t * a_srv_client,
+        dap_chain_net_srv_client_remote_t *a_srv_client,
         const void *a_custom_data,
         size_t a_custom_data_size){
-    _wrapping_dap_chain_net_srv_callbacks_key_t  *l_key = DAP_NEW(_wrapping_dap_chain_net_srv_callbacks_key_t);
-    l_key->srv = a_srv;
-    l_key->type = WRAPPING_DAP_CHAIN_NET_SERV_CALLBACK_DATA_RESPONSE_ERROR;
-    PyObject *l_func = _wrapping_dap_chain_net_srv_search(l_key);
-    Py_INCREF(l_func);
+    PyDapChainNetSrvObject *pyNetSrvObj = (PyDapChainNetSrvObject *)a_srv->_inheritor;
+    PyObject *l_func = pyNetSrvObj->callbackError;
+    if (!PyCallable_Check(l_func)){
+        log_it(L_ERROR, "Python function is not callable");
+        return -1;
+    }
     PyObject *l_arg = _wrapping_dac_chain_callback_data_t_get_tuple(a_srv, a_usage_id, a_srv_client, a_custom_data, a_custom_data_size);
+    PyGILState_STATE state = PyGILState_Ensure();
     PyObject *result = PyObject_CallObject(l_func, l_arg);
+    PyGILState_Release(state);
     if(result == NULL){
         PyErr_Print();
         return -1;
     }
-    Py_XINCREF(l_func);
-    Py_XINCREF(l_arg);
     if (!PyLong_Check(result)){
         return -1;
     }
@@ -168,22 +109,23 @@ int _w_dap_chain_callback_data_t_response_error(
 int _w_dap_chain_callback_data_t_receipt_next_success(
         dap_chain_net_srv_t *a_srv,
         uint32_t a_usage_id,
-        dap_chain_net_srv_client_remote_t * a_srv_client,
+        dap_chain_net_srv_client_remote_t *a_srv_client,
         const void *a_custom_data,
         size_t a_custom_data_size){
-    _wrapping_dap_chain_net_srv_callbacks_key_t  *l_key = DAP_NEW(_wrapping_dap_chain_net_srv_callbacks_key_t);
-    l_key->srv = a_srv;
-    l_key->type = WRAPPING_DAP_CHAIN_NET_SERV_CALLBACK_DATA_RECEIPT_NEXT_SUCCESS;
-    PyObject *l_func = _wrapping_dap_chain_net_srv_search(l_key);
-    Py_INCREF(l_func);
+    PyDapChainNetSrvObject *pyNetSrvObj = (PyDapChainNetSrvObject *)a_srv->_inheritor;
+    PyObject *l_func = pyNetSrvObj->callbackReceiptNext;
+    if (!PyCallable_Check(l_func)){
+        log_it(L_ERROR, "Python function is not callable");
+        return -1;
+    }
     PyObject *l_arg = _wrapping_dac_chain_callback_data_t_get_tuple(a_srv, a_usage_id, a_srv_client, a_custom_data, a_custom_data_size);
+    PyGILState_STATE state = PyGILState_Ensure();
     PyObject *result = PyObject_CallObject(l_func, l_arg);
+    PyGILState_Release(state);
     if(result == NULL){
         PyErr_Print();
         return -1;
     }
-    Py_XINCREF(l_func);
-    Py_XINCREF(l_arg);
     if (!PyLong_Check(result)){
         return -1;
     }
@@ -191,14 +133,37 @@ int _w_dap_chain_callback_data_t_receipt_next_success(
     return res_int;
     return 0;
 }
-int _w_dap_chain_callback_data_t_stream_ch_read(
-        dap_chain_net_srv_t *a_srv,
-        uint32_t a_usage_id,
-        dap_chain_net_srv_client_remote_t * a_srv_client,
-        const void *a_custom_data,
-        size_t a_custom_data_size){
-    return 0;
+
+void *_w_dap_chain_callback_data_t_custom_data(dap_chain_net_srv_t *a_srv,
+                                               dap_chain_net_srv_usage_t *a_usage,
+                                               const void *a_custom_data,
+                                               size_t a_custom_data_size,
+                                               size_t *a_out_data_size){
+    PyDapChainNetSrvObject *pyNetSrvObj = (PyDapChainNetSrvObject *)a_srv->_inheritor;
+    PyObject *l_func = pyNetSrvObj->callbackReadWithOutData;
+    if (!PyCallable_Check(l_func)){
+        log_it(L_ERROR, "Python function is not callable");
+        return NULL;
+    }
+    PyObject *l_arg = _wrapping_dac_chain_callback_data_t_get_tuple(a_srv, a_usage ? a_usage->id : 0,
+                                                                    a_usage ? a_usage->client : NULL,
+                                                                    a_custom_data, a_custom_data_size);
+    PyGILState_STATE state = PyGILState_Ensure();
+    PyObject *result = PyObject_CallObject(l_func, l_arg);
+    PyGILState_Release(state);
+    if(result == NULL){
+        PyErr_Print();
+        return NULL;
+    }
+    if (!PyBytes_Check(result)){
+        return NULL;
+    }
+    void *l_data = PyBytes_AsString(result);
+    if (a_out_data_size)
+        *a_out_data_size = (size_t)PyBytes_Size(result);
+    return l_data;
 }
+
 int _w_dap_chain_callback_data_t_client_success(
         dap_chain_net_srv_t *a_srv,
         uint32_t a_usage_id,
@@ -208,110 +173,63 @@ int _w_dap_chain_callback_data_t_client_success(
     return 0;
 }
 
-//Conructor
+//Constructor
 int PyDapChainNetSrv_init(PyDapChainNetSrvObject* self, PyObject *args, PyObject *kwds){
     const char *kwlist[] = {
             "uid",
+            "section",
             "callbackRequested",
             "callbackResponseSuccess",
             "callbackResponseError",
             "callbackReceiptNextSuccess",
+            "callbackCustomData",
             NULL};
-    PyObject *obj_uid;
-    PyObject *obj_callback_requested;
-    PyObject *obj_callback_response_success;
-    PyObject *obj_callback_response_error;
-    PyObject *obj_callback_receipt_next_success;
-    if(!PyArg_ParseTupleAndKeywords(args, kwds, "OOOOO", (char **)kwlist,
+    PyDapChainNetSrvUIDObject *obj_uid;
+    const char *l_section;
+    if(!PyArg_ParseTupleAndKeywords(args, kwds, "OsOOOOO", (char **)kwlist,
                                     &obj_uid,
-                                    &obj_callback_requested,
-                                    &obj_callback_response_success,
-                                    &obj_callback_response_error,
-                                    &obj_callback_receipt_next_success)) {
+                                    &l_section,
+                                    &self->callbackRequested,
+                                    &self->callbackSuccess,
+                                    &self->callbackError,
+                                    &self->callbackReceiptNext,
+                                    &self->callbackReadWithOutData)) {
         return -1;
     }
-    if (
-            PyDapChainNetSrvUid_Check(obj_uid)||
-            PyCallable_Check(obj_callback_requested)||
-            PyCallable_Check(obj_callback_response_success)||
-            PyCallable_Check(obj_callback_response_error)||
-            PyCallable_Check(obj_callback_receipt_next_success)) {
+    if (PyDapChainNetSrvUid_Check(obj_uid) &&
+            PyCallable_Check(self->callbackRequested) &&
+            PyCallable_Check(self->callbackSuccess) &&
+            PyCallable_Check(self->callbackError) &&
+            PyCallable_Check(self->callbackReceiptNext) &&
+            PyCallable_Check(self->callbackReadWithOutData)) {
         self->srv = dap_chain_net_srv_add(
-                ((PyDapChainNetSrvUIDObject*)obj_uid)->net_srv_uid,
+                obj_uid->net_srv_uid,
+                l_section,
                 _w_dap_chain_callback_data_t_requested,
                 _w_dap_chain_callback_data_t_response_success,
                 _w_dap_chain_callback_data_t_response_error,
-                _w_dap_chain_callback_data_t_receipt_next_success
+                _w_dap_chain_callback_data_t_receipt_next_success,
+                _w_dap_chain_callback_data_t_custom_data
                 );
         if (self->srv == NULL){
             return -3;
         }
-        _wrapping_dap_chain_net_srv_add(
-                WRAPPING_DAP_CHAIN_NET_SERV_CALLBACK_DATA_REQUESTED,
-                self->srv,
-                ((PyDapChainNetSrvUIDObject*)self)->net_srv_uid,
-                obj_callback_requested);
-        _wrapping_dap_chain_net_srv_add(
-                WRAPPING_DAP_CHAIN_NET_SERV_CALLBACK_DATA_RESPONSE_SUCCESS,
-                self->srv,
-                ((PyDapChainNetSrvUIDObject*)self)->net_srv_uid,
-                obj_callback_response_success);
-        _wrapping_dap_chain_net_srv_add(
-                WRAPPING_DAP_CHAIN_NET_SERV_CALLBACK_DATA_RESPONSE_ERROR,
-                self->srv,
-                ((PyDapChainNetSrvUIDObject*)self)->net_srv_uid,
-                obj_callback_response_error);
-        _wrapping_dap_chain_net_srv_add(
-                WRAPPING_DAP_CHAIN_NET_SERV_CALLBACK_DATA_RECEIPT_NEXT_SUCCESS,
-                self->srv,
-                ((PyDapChainNetSrvUIDObject*)self)->net_srv_uid,
-                obj_callback_receipt_next_success);
-        self->original = true;
+        self->srv->_inheritor = self;
+        Py_INCREF(self);
         return 0;
     }
     return -2;
 }
 
 void PyDapChainNetSrv_dealloc(PyDapChainNetSrvObject* self){
-    if(self->original == true){
-        _wrapping_dap_chain_net_srv_callbacks_t *callback = NULL;
-        _wrapping_dap_chain_net_srv_callbacks_key_t *l_key_requested = DAP_NEW(_wrapping_dap_chain_net_srv_callbacks_key_t);
-        l_key_requested->type = WRAPPING_DAP_CHAIN_NET_SERV_CALLBACK_DATA_REQUESTED;
-        l_key_requested->srv = self->srv;
-        callback = _wrapping_dap_chain_net_srv_search_el(l_key_requested);
-        _wrapping_dap_chain_net_srv_del(callback);
-        DAP_FREE(callback);
-        DAP_FREE(l_key_requested);
-        _wrapping_dap_chain_net_srv_callbacks_key_t *l_key_success = DAP_NEW(_wrapping_dap_chain_net_srv_callbacks_key_t);;
-        l_key_success->type = WRAPPING_DAP_CHAIN_NET_SERV_CALLBACK_DATA_RESPONSE_SUCCESS;
-        l_key_success->srv = self->srv;
-        callback = _wrapping_dap_chain_net_srv_search_el(l_key_success);
-        _wrapping_dap_chain_net_srv_del(callback);
-        DAP_FREE(callback);
-        DAP_FREE(l_key_requested);
-        _wrapping_dap_chain_net_srv_callbacks_key_t *l_key_error = DAP_NEW(_wrapping_dap_chain_net_srv_callbacks_key_t);;
-        l_key_error->type = WRAPPING_DAP_CHAIN_NET_SERV_CALLBACK_DATA_RESPONSE_ERROR;
-        l_key_error->srv = self->srv;
-        callback = _wrapping_dap_chain_net_srv_search_el(l_key_error);
-        _wrapping_dap_chain_net_srv_del(callback);
-        DAP_FREE(callback);
-        DAP_FREE(l_key_error);
-        _wrapping_dap_chain_net_srv_callbacks_key_t *l_key_receipt_new_success = DAP_NEW(_wrapping_dap_chain_net_srv_callbacks_key_t);;
-        l_key_receipt_new_success->type = WRAPPING_DAP_CHAIN_NET_SERV_CALLBACK_DATA_RECEIPT_NEXT_SUCCESS;
-        l_key_error->srv = self->srv;
-        callback = _wrapping_dap_chain_net_srv_search_el(l_key_receipt_new_success);
-        _wrapping_dap_chain_net_srv_del(callback);
-        DAP_FREE(callback);
-        DAP_FREE(l_key_receipt_new_success);
-        dap_chain_net_srv_del(self->srv);
-    }
+    dap_chain_net_srv_del(self->srv);
+    Py_XDECREF(self);
     Py_TYPE(self)->tp_free((PyObject*)self);
 }
 
 PyObject *wrapping_dap_chain_net_srv_get_uid(PyObject *self, void *closure){
     (void)closure;
     PyDapChainNetSrvUIDObject *l_obj_srv_uid = PyObject_New(PyDapChainNetSrvUIDObject, &DapChainNetSrvUIDObject_DapChainNetSrvUIDObjectType);
-    PyObject_Dir((PyObject*)l_obj_srv_uid);
     l_obj_srv_uid->net_srv_uid = ((PyDapChainNetSrvObject *)self)->srv->uid;
     return (PyObject*)l_obj_srv_uid;
 }
@@ -320,3 +238,19 @@ PyObject *wrapping_dap_chain_net_srv_get_grace_period(PyObject *self, void *clos
     (void)closure;
     return Py_BuildValue("I", ((PyDapChainNetSrvObject*)self)->srv->grace_period);
 }
+
+/* callbacks stream ch */
+
+PyObject *wrapping_dap_chain_net_srv_set_callback_channel(PyObject *self, PyObject *args){
+    PyObject *obj_ch_open, *obj_ch_write, *obj_ch_closed;
+    if (!PyArg_ParseTuple(args, "OOO", &obj_ch_open, &obj_ch_write, &obj_ch_closed))
+        return Py_None;
+    if (
+            !PyCallable_Check(obj_ch_open) ||
+            !PyCallable_Check(obj_ch_write) ||
+            !PyCallable_Check(obj_ch_closed)){
+        // TODO wrap channel callbacks
+        return Py_None;
+    }
+    return Py_None;
+}
diff --git a/modules/cellframe-sdk/net/srv/src/wrapping_dap_chain_net_srv_client.c b/modules/cellframe-sdk/net/srv/src/wrapping_dap_chain_net_srv_client.c
index 1ac0eb1a..88623a34 100644
--- a/modules/cellframe-sdk/net/srv/src/wrapping_dap_chain_net_srv_client.c
+++ b/modules/cellframe-sdk/net/srv/src/wrapping_dap_chain_net_srv_client.c
@@ -1,49 +1,305 @@
-//#include "wrapping_dap_chain_net_"
 #include "wrapping_dap_chain_net_srv_client.h"
 
-#define WRAPPING_DAP_CHAIN_NET_SRV_CLIENT(a) ((dap_chain_net_srv_client_remote_t*)((PyDapPyDapChainNetSrvClientObject*)a)->srv_client)
-#define _PyDapChainNetSrvClient(a) ((PyDapChainNetSrvClient*)a)
-
-PyObject *wrapping_dap_chain_net_srv_client_get_ch(PyObject *self, void *closure){
-    (void)closure;
-    //TODO
-    return Py_None;
-}
-PyObject *wrapping_dap_chain_net_srv_client_get_ts_created(PyObject *self, void *closure){
-    (void)closure;
-    return Py_BuildValue("k", ((PyDapChainNetSrvClientObject*)self)->srv_client->ts_created);
-}
-PyObject *wrapping_dap_chain_net_srv_client_get_created(PyObject *self, void *closure){
-    (void)closure;
-    PyDateTime_IMPORT;
-    PyObject *l_obj_long_ts = PyLong_FromDouble(((PyDapChainNetSrvClientObject*)self)->srv_client->ts_created);
-    PyObject *l_obj_tuple = Py_BuildValue("(O)", l_obj_long_ts);
-    PyObject *l_obj_dateTime = PyDateTime_FromTimestamp(l_obj_tuple);
-    return l_obj_dateTime;
-}
-PyObject *wrapping_dap_chain_net_srv_client_get_stream_worker(PyObject *self, void *closure){
-    (void)closure;
-    //TODO
-    return Py_None;
-}
-PyObject *wrapping_dap_chain_net_srv_client_get_session_id(PyObject *self, void *closure){
-    (void)closure;
-    return Py_BuildValue("i", ((PyDapChainNetSrvClientObject*)self)->srv_client->session_id);
-}
-PyObject *wrapping_dap_chain_net_srv_client_get_bytes_received(PyObject *self, void *closure){
-    (void)closure;
-    dap_chain_net_srv_client_remote_t *l_client = ((PyDapChainNetSrvClientObject*)self)->srv_client;
-    return Py_BuildValue("k", l_client->bytes_received);
-}
-PyObject *wrapping_dap_chain_net_srv_client_get_bytes_send(PyObject *self, void *closure){
-    (void)closure;
-    dap_chain_net_srv_client_remote_t *l_client = ((PyDapChainNetSrvClientObject*)self)->srv_client;
-    return Py_BuildValue("k", l_client->bytes_sent);
-}
-//PyObject *wrapping_dap_chain_net_srv_client_get_bytes_prev(PyObject *self, void *closure){
-//    (void)closure;
-//}
-//PyObject *wrapping_dap_chain_net_srv_client_get_bytes_next(PyObject *self, void *closure){
-//    (void)closure;
-//    PyDapChain
-//}
+#define LOG_TAG "wrapping_dap_chain_net_srv_client"
+
+static void _wrapping_dap_chain_net_srv_client_callback_connected(dap_chain_net_srv_client_t* a_client, void *a_arg){
+    PyDapChainNetSrvClientObject *py_client = (PyDapChainNetSrvClientObject *)a_client->_inheritor;
+    PyObject *l_call = py_client->callback_connected;
+    if (PyCallable_Check(l_call)) {
+        PyObject *l_args = Py_BuildValue("OO", py_client, a_arg);
+        PyGILState_STATE state = PyGILState_Ensure();
+        PyEval_CallObject(l_call, l_args);
+        Py_DECREF(l_args);
+        PyGILState_Release(state);
+    } else {
+        log_it(L_ERROR, "Can't call a python handler on connected event");
+    }
+}
+
+static void _wrapping_dap_chain_net_srv_client_callback_disconnected(dap_chain_net_srv_client_t* a_client, void *a_arg){
+    UNUSED(a_client);
+    PyDapChainNetSrvClientObject *py_client = (PyDapChainNetSrvClientObject *)a_client->_inheritor;
+    PyObject *l_call = py_client->callback_disconnected;
+    if (PyCallable_Check(l_call)) {
+        PyObject *l_args = Py_BuildValue("OO", py_client, a_arg);
+        PyGILState_STATE state = PyGILState_Ensure();
+        PyEval_CallObject(l_call, l_args);
+        Py_DECREF(l_args);
+        PyGILState_Release(state);
+    } else {
+        log_it(L_ERROR, "Can't call a python handler on disconnected event");
+    }
+}
+
+static void _wrapping_dap_chain_net_srv_client_callback_deleted(dap_chain_net_srv_client_t* a_client, void *a_arg){
+    UNUSED(a_client);
+    PyDapChainNetSrvClientObject *py_client = (PyDapChainNetSrvClientObject *)a_client->_inheritor;
+    PyObject *l_call = py_client->callback_deleted;
+    if (PyCallable_Check(l_call)) {
+        PyObject *l_args = Py_BuildValue("OO", py_client, a_arg);
+        PyGILState_STATE state = PyGILState_Ensure();
+        PyEval_CallObject(l_call, l_args);
+        Py_DECREF(l_args);
+        PyGILState_Release(state);
+    } else {
+        log_it(L_ERROR, "Can't call a python handler on delete event");
+    }
+}
+
+
+static void _wrapping_dap_chain_net_srv_client_callback_check(dap_chain_net_srv_client_t *a_srv_client,
+                                                              dap_stream_ch_chain_net_srv_pkt_test_t *a_pkt,
+                                                              void *a_arg) {
+    UNUSED(a_pkt);
+    PyDapChainNetSrvClientObject *py_client = (PyDapChainNetSrvClientObject *)a_srv_client->_inheritor;
+    PyObject *l_call = py_client->callback_check;
+    if (PyCallable_Check(l_call)) {
+        PyObject *l_args = Py_BuildValue("OO", py_client, (PyObject *)a_arg);
+        PyGILState_STATE state = PyGILState_Ensure();
+        PyEval_CallObject(l_call, l_args);
+        Py_DECREF(l_args);
+        PyGILState_Release(state);
+    } else {
+        log_it(L_ERROR, "Can't call a python handler on check response event");
+    }
+}
+
+static dap_chain_datum_tx_receipt_t * _wrapping_dap_chain_net_srv_client_callback_sign(
+                                                             dap_chain_net_srv_client_t *a_srv_client,
+                                                             dap_chain_datum_tx_receipt_t *a_receipt,
+                                                             void *a_arg) {
+    PyDapChainNetSrvClientObject *py_client = (PyDapChainNetSrvClientObject *)a_srv_client->_inheritor;
+    PyObject *l_call = py_client->callback_sign;
+    PyDapChainTXReceiptObject *py_ret = NULL;
+    if (PyCallable_Check(l_call)) {
+        PyDapChainTXReceiptObject *py_receipt = PyObject_New(PyDapChainTXReceiptObject,
+                                                             &DapChainTxReceiptObject_DapChainTxReceiptTypeObjectType);
+        py_receipt->tx_receipt = a_receipt;
+        PyObject *l_args = Py_BuildValue("OOO", py_client, py_receipt, (PyObject *)a_arg);
+        PyGILState_STATE state = PyGILState_Ensure();
+        py_ret = (PyDapChainTXReceiptObject *)PyEval_CallObject(l_call, l_args);
+        Py_DECREF(l_args);
+        PyGILState_Release(state);
+    } else {
+        log_it(L_ERROR, "Can't call handler Python in callback sign");
+    }
+    if (!py_ret || (PyObject *)py_ret == Py_None || !py_ret->tx_receipt)
+        return NULL;
+    return DAP_DUP_SIZE(py_ret->tx_receipt, py_ret->tx_receipt->size);
+}
+
+static void _wrapping_dap_chain_net_srv_client_callback_success(dap_chain_net_srv_client_t *a_srv_client,
+                                                                dap_stream_ch_chain_net_srv_pkt_success_t *a_pkt,
+                                                                size_t a_pkt_size,
+                                                                void *a_arg) {
+    PyDapChainNetSrvClientObject *py_client = (PyDapChainNetSrvClientObject *)a_srv_client->_inheritor;
+    PyObject *l_call = py_client->callback_success;
+    if (PyCallable_Check(l_call)) {
+        PyDapHashFastObject *py_cond_hash = PyObject_New(PyDapHashFastObject,
+                                                         &DapHashTypeObject_DapChainHashTypeObjectType);
+        if (a_pkt_size == sizeof(dap_stream_ch_chain_net_srv_pkt_success_t) + sizeof(dap_chain_hash_fast_t)) {
+            py_cond_hash->hash_fast = DAP_NEW(dap_chain_hash_fast_t);
+            memcpy(py_cond_hash->hash_fast, a_pkt->custom_data, sizeof(dap_chain_hash_fast_t));
+        } else
+            py_cond_hash->hash_fast = NULL;
+        PyObject *l_args = Py_BuildValue("OOO", py_client, py_cond_hash, (PyObject *)a_arg);
+        PyGILState_STATE state = PyGILState_Ensure();
+        PyEval_CallObject(l_call, l_args);
+        Py_DECREF(l_args);
+        PyGILState_Release(state);
+    } else {
+        log_it(L_ERROR, "Can't call handler Python in callback success");
+    }
+}
+
+static void _wrapping_dap_chain_net_srv_client_callback_error(dap_chain_net_srv_client_t *a_srv_client,
+                                                              int a_error_code,
+                                                              void *a_arg) {
+    PyDapChainNetSrvClientObject *py_client = (PyDapChainNetSrvClientObject *)a_srv_client->_inheritor;
+    PyObject *l_call = py_client->callback_error;
+    if (PyCallable_Check(l_call)) {
+        PyObject *l_args = Py_BuildValue("OiO", py_client, a_error_code, (PyObject *)a_arg);
+        PyGILState_STATE state = PyGILState_Ensure();
+        PyEval_CallObject(l_call, l_args);
+        Py_DECREF(l_args);
+        PyGILState_Release(state);
+    } else {
+        log_it(L_ERROR, "Can't call handler Python in callback error");
+    }
+}
+
+static void _wrapping_dap_chain_net_srv_client_callback_data(dap_chain_net_srv_client_t *a_srv_client,
+                                                             uint8_t *a_data,
+                                                             size_t a_data_size,
+                                                             void *a_arg) {
+    PyDapChainNetSrvClientObject *py_client = (PyDapChainNetSrvClientObject *)a_srv_client->_inheritor;
+    PyObject *l_call = py_client->callback_data;
+    if (PyCallable_Check(l_call)) {
+        PyObject *l_data = PyBytes_FromStringAndSize((char *)a_data, a_data_size);
+        PyObject *l_args = Py_BuildValue("OOO", py_client, l_data, (PyObject *)a_arg);
+        PyGILState_STATE state = PyGILState_Ensure();
+        PyEval_CallObject(l_call, l_args);
+        Py_DECREF(l_args);
+        PyGILState_Release(state);
+    } else {
+        log_it(L_ERROR, "Can't call handler Python in callback data");
+    }
+}
+
+int PyDapChainNetSrvClient_init(PyDapChainNetSrvClientObject* self, PyObject *args, PyObject *kwds) {
+    const char *kwlist[] = {
+            "net",
+            "addr",
+            "port",
+            "callback_connected",
+            "callback_disconnected",
+            "callback_deleted",
+            "callback_check",
+            "callback_sign",
+            "callback_success",
+            "callback_error",
+            "callback_data",
+            "callback_arg",
+            NULL
+    };
+    PyDapChainNetObject *py_net;
+    PyObject *py_cb_conn, *py_cb_disc, *py_cb_del, *py_cb_check, *py_cb_sign;
+    PyObject *py_cb_success, *py_cb_error, *py_cb_data, *py_cb_arg;
+    const char *addr;
+    uint16_t port;
+    if (!PyArg_ParseTupleAndKeywords(
+                args, kwds, "OsHOOOOOOOOO", (char **)kwlist,
+                &py_net, &addr, &port, &py_cb_conn,
+                &py_cb_disc, &py_cb_del, &py_cb_check,
+                &py_cb_sign, &py_cb_success, &py_cb_error,
+                &py_cb_data, &py_cb_arg
+                )){
+        return -1;
+    }
+    if (!PyDapChainNet_Check(py_net))
+       return -2;
+    if (!PyCallable_Check(py_cb_conn) ||
+            !PyCallable_Check(py_cb_disc) ||
+            !PyCallable_Check(py_cb_del) ||
+            !PyCallable_Check(py_cb_check) ||
+            !PyCallable_Check(py_cb_sign) ||
+            !PyCallable_Check(py_cb_success) ||
+            !PyCallable_Check(py_cb_error) ||
+            !PyCallable_Check(py_cb_data)) {
+        return -3;
+    }
+    dap_chain_net_srv_client_callbacks_t callbacks = {0};
+    callbacks.connected = _wrapping_dap_chain_net_srv_client_callback_connected;
+    callbacks.disconnected = _wrapping_dap_chain_net_srv_client_callback_disconnected;
+    callbacks.deleted = _wrapping_dap_chain_net_srv_client_callback_deleted;
+    callbacks.check = _wrapping_dap_chain_net_srv_client_callback_check;
+    callbacks.sign = _wrapping_dap_chain_net_srv_client_callback_sign;
+    callbacks.success = _wrapping_dap_chain_net_srv_client_callback_success;
+    callbacks.error = _wrapping_dap_chain_net_srv_client_callback_error;
+    callbacks.data = _wrapping_dap_chain_net_srv_client_callback_data;
+    dap_chain_net_srv_client_t *l_client =
+            dap_chain_net_srv_client_create_n_connect(py_net->chain_net,
+                                                      (char *)addr, port, &callbacks, py_cb_arg);
+    self->srv_client = l_client;
+    self->callback_connected = py_cb_conn;
+    self->callback_disconnected = py_cb_disc;
+    self->callback_deleted = py_cb_del;
+    self->callback_check = py_cb_check;
+    self->callback_sign = py_cb_sign;
+    self->callback_success = py_cb_success;
+    self->callback_error = py_cb_error;
+    self->callback_data = py_cb_data;
+    Py_INCREF(self);
+    l_client->_inheritor = self;
+    return 0;
+}
+
+
+PyObject *wrapping_dap_chain_net_srv_client_check(PyObject *self, PyObject *args) {
+    PyDapChainNetIdObject *obj_net_id;
+    PyDapChainNetSrvUIDObject *obj_srv_uid;
+    PyObject *obj_bytes;
+    if (!PyArg_ParseTuple(args, "OOO", &obj_net_id, &obj_srv_uid, &obj_bytes)) {
+        return Py_None;
+    }
+    if (!PyDapChainNetSrvUid_Check(obj_srv_uid))
+        return Py_None;
+    if (PyObject_TypeCheck(obj_net_id, &DapChainNetIdObject_DapChainNetIdObjectType))
+        return Py_None;
+    if (!PyBytes_Check(obj_bytes)) {
+        return Py_None;
+    }
+    //Generate packet
+    size_t l_bytes_size = PyBytes_Size(obj_bytes);
+    void *l_bytes = PyBytes_AsString(obj_bytes);
+    size_t l_request_size = sizeof(dap_stream_ch_chain_net_srv_pkt_test_t) + l_bytes_size;
+    dap_stream_ch_chain_net_srv_pkt_test_t *l_request = DAP_NEW_S_SIZE(dap_stream_ch_chain_net_srv_pkt_test_t,
+                                                                       l_request_size);
+    memset(l_request, 0, sizeof(dap_stream_ch_chain_net_srv_pkt_test_t));
+    l_request->net_id.uint64 = obj_net_id->net_id.uint64;
+    l_request->srv_uid.uint64 = obj_srv_uid->net_srv_uid.uint64;
+    l_request->data_size_send = l_request->data_size_recv = l_bytes_size;
+    l_request->data_size = l_bytes_size;
+    gettimeofday(&l_request->send_time1, NULL);
+    memcpy(l_request->data, l_bytes, l_bytes_size);
+    dap_hash_fast(l_request->data, l_request->data_size, &l_request->data_hash);
+    ssize_t l_res = dap_chain_net_srv_client_write(
+                        ((PyDapChainNetSrvClientObject*)self)->srv_client,
+                        DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_CHECK_REQUEST,
+                        l_request, l_request_size);
+    return Py_BuildValue("L", l_res);
+}
+
+PyObject *wrapping_dap_chain_net_srv_client_request(PyObject *self, PyObject *args) {
+    PyDapChainNetObject *obj_net;
+    PyDapChainNetSrvUIDObject *obj_srv_uid;
+    PyDapHashFastObject *obj_tx_cond_hash;
+    if (!PyArg_ParseTuple(args, "OOO", &obj_net, &obj_srv_uid, &obj_tx_cond_hash))
+        return Py_None;
+    if (!PyDapChainNetSrvUid_Check(obj_srv_uid))
+        return Py_None;
+    if (!PyDapChainNet_Check(obj_net))
+        return Py_None;
+    if (!PyDapHashFast_Check(obj_tx_cond_hash)) {
+        return Py_None;
+    }
+    //Generate packet
+    dap_stream_ch_chain_net_srv_pkt_request_hdr_t l_hdr = {};
+    l_hdr.net_id = obj_net->chain_net->pub.id;
+    l_hdr.srv_uid = obj_srv_uid->net_srv_uid;
+    memcpy(&l_hdr.tx_cond, obj_tx_cond_hash->hash_fast, sizeof(dap_chain_hash_fast_t));
+    ssize_t l_res = dap_chain_net_srv_client_write(
+                        ((PyDapChainNetSrvClientObject*)self)->srv_client,
+                        DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_REQUEST,
+                        &l_hdr, sizeof(l_hdr));
+    return Py_BuildValue("L", l_res);
+}
+
+PyObject *wrapping_dap_chain_net_srv_client_write(PyObject *self, PyObject *args) {
+    PyDapChainNetSrvUIDObject *obj_srv_uid;
+    PyObject *obj_bytes;
+    if (!PyArg_ParseTuple(args, "OO", &obj_srv_uid, &obj_bytes)) {
+        return Py_None;
+    }
+    if (!PyDapChainNetSrvUid_Check(obj_srv_uid)) {
+        return Py_None;
+    }
+    if (!PyBytes_Check(obj_bytes)) {
+        return Py_None;
+    }
+    //Generate packet
+    size_t l_bytes_size = PyBytes_Size(obj_bytes);
+    void *l_bytes = PyBytes_AsString(obj_bytes);
+    dap_stream_ch_chain_net_srv_pkt_data_t *l_data = DAP_NEW_S_SIZE(void,
+                                                        sizeof(dap_stream_ch_chain_net_srv_pkt_data_t) + l_bytes_size);
+    l_data->hdr.version = 1;
+    l_data->hdr.data_size = (uint16_t)l_bytes_size;
+    l_data->hdr.usage_id = 0;
+    l_data->hdr.srv_uid = obj_srv_uid->net_srv_uid;
+    memcpy(l_data->data, l_bytes, l_bytes_size);
+    ssize_t l_res = dap_chain_net_srv_client_write(
+                        ((PyDapChainNetSrvClientObject*)self)->srv_client,
+                        DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_DATA,
+                        l_data, sizeof(*l_data) + l_bytes_size);
+    return Py_BuildValue("L", l_res);
+}
diff --git a/modules/cellframe-sdk/net/srv/src/wrapping_dap_chain_net_srv_client_remote.c b/modules/cellframe-sdk/net/srv/src/wrapping_dap_chain_net_srv_client_remote.c
new file mode 100644
index 00000000..d57b3a0f
--- /dev/null
+++ b/modules/cellframe-sdk/net/srv/src/wrapping_dap_chain_net_srv_client_remote.c
@@ -0,0 +1,50 @@
+//#include "wrapping_dap_chain_net_"
+#include "wrapping_dap_chain_net_srv_client_remote.h"
+
+#define WRAPPING_DAP_CHAIN_NET_SRV_CLIENT(a) ((dap_chain_net_srv_client_remote_t*)((PyDapPyDapChainNetSrvClientObject*)a)->srv_client)
+#define _PyDapChainNetSrvClient(a) ((PyDapChainNetSrvClient*)a)
+
+PyObject *wrapping_dap_chain_net_srv_client_remote_get_ch(PyObject *self, void *closure){
+    (void)closure;
+    //TODO
+    return Py_None;
+}
+PyObject *wrapping_dap_chain_net_srv_client_remote_get_ts_created(PyObject *self, void *closure){
+    (void)closure;
+    return Py_BuildValue("k", ((PyDapChainNetSrvClientRemoteObject*)self)->srv_client_remote->ts_created);
+}
+PyObject *wrapping_dap_chain_net_srv_client_remote_get_created(PyObject *self, void *closure){
+    (void)closure;
+    PyDateTime_IMPORT;
+    PyObject *l_obj_long_ts = PyLong_FromDouble(((PyDapChainNetSrvClientRemoteObject*)self)->srv_client_remote->ts_created);
+    PyObject *l_obj_tuple = Py_BuildValue("(O)", l_obj_long_ts);
+    PyObject *l_obj_dateTime = PyDateTime_FromTimestamp(l_obj_tuple);
+    return l_obj_dateTime;
+}
+PyObject *wrapping_dap_chain_net_srv_client_remote_get_stream_worker(PyObject *self, void *closure){
+    (void)closure;
+    //TODO
+    return Py_None;
+}
+PyObject *wrapping_dap_chain_net_srv_client_remote_get_session_id(PyObject *self, void *closure){
+    (void)closure;
+    return Py_BuildValue("i", ((PyDapChainNetSrvClientRemoteObject*)self)->srv_client_remote->session_id);
+}
+PyObject *wrapping_dap_chain_net_srv_client_remote_get_bytes_received(PyObject *self, void *closure){
+    (void)closure;
+    dap_chain_net_srv_client_remote_t *l_client = ((PyDapChainNetSrvClientRemoteObject*)self)->srv_client_remote;
+    return Py_BuildValue("k", l_client->bytes_received);
+}
+PyObject *wrapping_dap_chain_net_srv_client_remote_get_bytes_send(PyObject *self, void *closure){
+    (void)closure;
+    dap_chain_net_srv_client_remote_t *l_client = ((PyDapChainNetSrvClientRemoteObject*)self)->srv_client_remote;
+    return Py_BuildValue("k", l_client->bytes_sent);
+}
+//PyObject *wrapping_dap_chain_net_srv_client_remote_get_bytes_prev(PyObject *self, void *closure){
+//    (void)closure;
+//}
+//PyObject *wrapping_dap_chain_net_srv_client_remote_get_bytes_next(PyObject *self, void *closure){
+//    (void)closure;
+//    PyDapChain
+//}
+
diff --git a/modules/dap-sdk/crypto/include/wrapping_dap_hash.h b/modules/dap-sdk/crypto/include/wrapping_dap_hash.h
index 2cc38398..e4e4508f 100644
--- a/modules/dap-sdk/crypto/include/wrapping_dap_hash.h
+++ b/modules/dap-sdk/crypto/include/wrapping_dap_hash.h
@@ -156,6 +156,11 @@ static PyTypeObject DapHashFastObject_DapHashFastObjectType = {
     PyType_GenericNew,               /* tp_new */
 };
 
+static bool PyDapHashFast_Check(PyDapHashFastObject *pyHash)
+{
+    return !PyObject_TypeCheck(pyHash, &DapHashFastObject_DapHashFastObjectType);
+}
+
 #ifdef __cplusplus
 }
 #endif
-- 
GitLab