تطوير Blockchain للصناعة باستخدام Go. الجزء 1

منذ أربعة أشهر وأنا أعمل على مشروع يسمى "تطوير أدوات حماية وإدارة البيانات في القطاعين الحكومي والصناعي على أساس blockchain".
الآن أود أن أخبركم كيف بدأت هذا المشروع، والآن سأصف رمز البرنامج بالتفصيل.

تطوير Blockchain للصناعة باستخدام Go. الجزء 1

هذه هي المقالة الأولى في سلسلة مقالات. هنا أصف الخادم والبروتوكول. في الواقع، يمكن للقارئ أيضًا كتابة نسخته الخاصة من عناصر blockchain هذه.

وهنا الجزء الثاني — حول blockchain وهياكل بيانات المعاملات، وكذلك حول الحزمة التي تنفذ التفاعل مع قاعدة البيانات.

في العام الماضي، في هاكاثون الاختراق الرقمي، توصلوا إلى فكرة لإنشاء نظام مفيد للصناعة والاقتصاد الرقمي باستخدام تكنولوجيا دفتر الأستاذ الموزع؛ كما تم إصدار منحة للتطوير من قبل صندوق مساعدة الابتكار (يجب أن أكتب مقالة منفصلة) مقالة عن المنحة، لأولئك الذين بدأوا للتو شركاتهم الناشئة)، والآن بالترتيب.

يتم التطوير بلغة Go، وقاعدة البيانات التي يتم تخزين الكتل فيها هي LevelDB.
الأجزاء الرئيسية هي البروتوكول، والخادم (الذي يقوم بتشغيل TCP وWebSocket - الأول لمزامنة blockchain، والثاني لربط العملاء وإرسال المعاملات والأوامر من JavaScript، على سبيل المثال.

كما ذكرنا سابقًا، هناك حاجة إلى تقنية blockchain هذه في المقام الأول لأتمتة وحماية تبادل المنتجات بين الموردين والعملاء، أو كليهما في شخص واحد. هؤلاء الناس ليسوا في عجلة من أمرهم للثقة ببعضهم البعض. لكن المهمة لا تقتصر فقط على إنشاء "دفتر شيكات" باستخدام آلة حاسبة مدمجة، بل نظام يعمل على أتمتة معظم المهام الروتينية التي تنشأ عند العمل مع دورة حياة المنتج. يتم تخزين الرمز الثانوي المسؤول عن هذه المسألة، كما هو معتاد في blockchain، في مدخلات ومخرجات المعاملات (يتم تخزين المعاملات نفسها في كتل، ويتم تشفير الكتل في LevelDB مسبقًا بتنسيق GOB). أولاً، دعونا نتحدث عن البروتوكول والخادم (المعروف أيضًا باسم العقدة).

البروتوكول ليس معقدًا، والهدف الأساسي منه هو التبديل إلى وضع تحميل بعض البيانات، عادةً كتلة أو معاملة، استجابةً لسطر أوامر خاص، وهو ضروري أيضًا لتبادل المخزون، حتى تعرف العقدة من هي يتم الاتصال بها وكيفية القيام بأعمالها (تسمى العقد المتصلة لجلسة المزامنة أيضًا "المجاورة" لأن عنوان IP الخاص بها معروف ويتم تخزين بيانات حالتها في الذاكرة).

تسمى المجلدات (الأدلة كما يسميها Linux) في فهم مبرمجي Go الحزم، لذلك في بداية كل ملف به كود Go من هذا الدليل يكتبون الحزمة Folder_name_where_this_file. وإلا فلن تتمكن من تغذية الحزمة إلى المترجم. حسنًا، هذا ليس سرًا لمن يعرف هذه اللغة. هذه هي الحزم:

  • اتصالات الشبكة (الخادم، العميل، البروتوكول)
  • هياكل البيانات المخزنة والمرسلة (الكتلة، المعاملة)
  • قاعدة البيانات (البلوكشين)
  • إجماع
  • آلة افتراضية مكدسة (xvm)
  • المساعدة (التشفير، الأنواع) هذا كل ما في الوقت الحالي.

هنا هو الرابط إلى جيثب

هذه نسخة تعليمية، فهي تفتقر إلى التفاعل بين العمليات والعديد من المكونات التجريبية، ولكن الهيكل يتوافق مع الهيكل الذي يتم تنفيذ التطوير عليه. إذا كان لديك أي شيء تقترحه في التعليقات، سأكون سعيدًا بأخذه بعين الاعتبار في مزيد من التطوير. والآن للحصول على شرح الخادم و بروتوكول.

دعونا نلقي نظرة على الخادم أولا.

يعمل الروتين الفرعي للخادم كخادم بيانات يعمل أعلى بروتوكول TCP باستخدام هياكل البيانات من حزمة البروتوكول.

يستخدم الروتين الحزم التالية: الخادم, بروتوكول, أنواع. في الحزمة نفسها tcp_server.go يحتوي على بنية البيانات خدمة.

type Serve struct {
	Port string
	BufSize int
	ST *types.Settings
}

يمكنه قبول المعلمات التالية:

  • منفذ الشبكة الذي سيتم من خلاله تبادل البيانات
  • ملف تكوين الخادم بتنسيق JSON
  • علامة للتشغيل في وضع التصحيح (Blockchain الخاص)

تقدم:

  • يقرأ التكوين من ملف JSON
  • تم تحديد علامة وضع التصحيح: إذا تم تعيينها، فلن يتم تشغيل برنامج جدولة مزامنة الشبكة ولن يتم تحميل blockchain
  • تهيئة بنية بيانات التكوين وبدء تشغيل الخادم

المخدم

  • ينفذ إطلاق خادم TCP وتفاعل الشبكة وفقًا للبروتوكول.
  • يحتوي على بنية بيانات خدمة تتكون من رقم المنفذ وحجم المخزن المؤقت ومؤشر للهيكل الأنواع.الإعدادات
  • تبدأ طريقة التشغيل تفاعل الشبكة (الاستماع للاتصالات الواردة على منفذ معين، عند تلقي اتصال جديد، يتم نقل معالجته إلى طريقة المقبض الخاص في سلسلة رسائل جديدة)
  • В مقبض تتم قراءة البيانات من الاتصال إلى مخزن مؤقت، وتحويلها إلى تمثيل سلسلة وتمريرها إلى البروتوكول.الاختيار
  • البروتوكول.الاختيار عائدات نتيجة أو يسبب خطأ نتيجة ثم نقل الى بروتوكول.تفسيرالذي يعود com.interpr - كائن من النوع InterpreteDataأو يتسبب في حدوث خطأ في معالجة نتيجة التحديد
  • ثم يتم تنفيذ التبديل إنتربر.الأوامر[0] الذي يتحقق واحدًا من: النتيجة، الفاتورة، خطأ وهناك قسم الافتراضي
  • في القسم نتيجة تم العثور على التبديل من حيث القيمة إنتربر.الأوامر[1] الذي يتحقق من القيم طول المخزن المؤقت и الإصدار (في كل حالة يتم استدعاء الوظيفة المقابلة)

وظائف GetVersion и الطول موجودة في الملف srvlib.go حزمة الخادم

GetVersion(conn net.Conn, version string)

فهو ببساطة يطبع على وحدة التحكم ويرسل الإصدار الذي تم تمريره في المعلمة إلى العميل:

conn.Write([]byte("result:" + version))

.
وظيفة

BufferLength(conn net.Conn, intrpr *protocol.InterpreteData)

يقوم بتحميل كتلة أو معاملة أو بيانات محددة أخرى على النحو التالي:

  • يطبع إلى وحدة التحكم نوع البيانات المحددة في البروتوكول الذي يجب قبوله:
    fmt.Println("DataType:", intrpr.Commands[2])
  • يقرأ القيمة intrpr.Body إلى متغير رقمي buf_len
  • يخلق المخزن المؤقت com.newbuf الحجم المحدد:
    make([]byte, buf_len)
  • يرسل ردا طيبا:
    conn.Write([]byte("result:ok"))
  • يملأ المخزن المؤقت بالكامل من دفق القراءة:
    io.ReadFull(conn, newbuf)

    .

  • طباعة محتويات المخزن المؤقت إلى وحدة التحكم
    fmt.Println(string(newbuf))

    وعدد البايتات المقروءة

    fmt.Println("Bytes length:", n)
  • يرسل ردا طيبا:
    conn.Write([]byte("result:ok"))

يتم تكوين الأساليب من حزمة الخادم لمعالجة البيانات المستلمة باستخدام وظائف من الحزمة بروتوكول.

بروتوكول

يعمل البروتوكول كوسيلة لتمثيل البيانات في تبادل الشبكة.

الاختيار (سلسلة سلسلة) (سلسلة، خطأ) ينفذ المعالجة الأولية للبيانات التي يتلقاها الخادم، ويتلقى تمثيل سلسلة من البيانات كمدخلات ويعيد سلسلة تم إعدادها لها مترجم:

  • يتم تقسيم سلسلة الإدخال إلى رأس وجسم باستخدام ReqParseN2(شارع)
  • يتم تقسيم الرأس إلى عناصر ووضعه في شريحة الأوامر باستخدام ReqParseHead(head)
  • В التبديل (الأوامر[0]) حدد الأمر المستلم (كمد، مفتاح، عنوان أو يتم تشغيل القسم الافتراضي)
  • تم فحص أمرين في cmd التبديل (الأوامر [1]) - الطول и com.getversion.
  • الطول يتحقق من نوع البيانات في الأوامر[2] ويحفظه فيها نوع البيانات
  • يتحقق من ذلك الجسدي يحتوي على قيمة سلسلة
    len(body) < 1
  • إرجاع سلسلة الاستجابة:
    "result:bufferlength:" + datatype + "/" + body
  • com.getversion ترجع سلسلة
    return "result:version/auto"

مترجم

يحتوي على بنية InterpreteData ويقوم بمعالجة ثانوية للبيانات التي يتم إرجاعها منها الاختيار السلاسل وتشكيل الكائنات InterpreteData.

type InterpreteData struct {
	Head string
	Commands []string
	Body string
	IsErr bool
	ErrCode int 
	ErrMessage string
}

وظيفة

Interprete(str string) (*InterpreteData, error)

يقبل سلسلة نتيجة ويقوم بإنشاء وإرجاع مرجع إلى الكائن InterpreteData.

تقدم:

  • وبالمثل الاختيار يتم استخراج الرأس والجسم باستخدام ReqParseN2(شارع)
  • يتم تقسيم الرأس إلى عناصر باستخدام ريكبارسيهيد (الرأس)
  • تتم تهيئة الكائن InterpreteData ويتم إرجاع المؤشر إليه:

res := &InterpreteData{
	Head: head,
	Commands: commands,
	Body: body,
}
return res, nil

يستخدم هذا الكائن في server.go الحزمة الرئيسية.

العميل

تحتوي حزمة العميل على الوظائف TCPConnect и TCPResponseData.

وظيفة

TCPConnect(s *types.Settings, data []byte, payload []byte)

يعمل على النحو التالي:

  • يتم إجراء اتصال بالاتصال المحدد في كائن الإعدادات الذي تم تمريره
    net.Dial("tcp", s.Host + ":" + s.Port)
  • يتم إرسال البيانات التي تم تمريرها في معلمة البيانات:
    conn.Write(data)
  • الجواب قراءة
    resp, n, _ := TCPResponseData(conn, s.BufSize)

    وطباعتها على وحدة التحكم

    fmt.Println(string(resp[:n]))
  • إذا تم نقله الحمولة ثم يمررها
    conn.Write(payload)

    ويقرأ أيضًا استجابة الخادم، ويطبعها على وحدة التحكم

وظيفة

 TCPResponseData(conn net.Conn, bufsiz int) ([]byte, int, error)

يقوم بإنشاء مخزن مؤقت بالحجم المحدد، ويقرأ استجابة الخادم هناك ويعيد هذا المخزن المؤقت وعدد البايتات المقروءة، بالإضافة إلى كائن خطأ.

روتين فرعي للعميل

يعمل على إرسال الأوامر إلى خوادم العقدة، وكذلك الحصول على إحصائيات مختصرة واختبارات.

يمكن قبول المعلمات التالية: ملف التكوين بتنسيق JSON، والبيانات التي سيتم إرسالها إلى الخادم كسلسلة، والمسار إلى الملف الذي سيتم إرساله إلى الحمولة، وعلامة مضاهاة جدولة العقدة، ونوع البيانات المنقولة كقيمة رقمية.

  • الحصول على التكوين
    st := types.ParseConfig(*config)
  • إذا تم تمرير علم الاتحاد الاقتصادي والنقدي، فإنه يبدأ com.sheduler
  • إذا تم توفير العلامة f التي تشير إلى المسار إلى الملف، فإننا نقوم بتحميل بياناته فيه فدب ويتم إرسال المحتوى إلى الخادم
    client.TCPConnect(st, []byte(CMD_BUFFER_LENGTH + ":" + strconv.Itoa(*t) + "/" + strconv.Itoa(fdblen)), fdb)
  • إذا لم يتم تحديد الملف، فسيتم إرسال البيانات من العلامة ببساطة -d:
    client.TCPConnect(st, []byte(*data), nil)

كل هذا تمثيل مبسط يوضح هيكل البروتوكول. أثناء التطوير، تتم إضافة الوظائف الضرورية إلى هيكلها.

في الجزء الثاني سأتحدث عن هياكل البيانات للكتل والمعاملات، في 3 عن خادم WebSocket للاتصال من JavaScript، في 4 سألقي نظرة على جدولة المزامنة، ثم آلة المكدس التي تعالج الكود الثانوي من المدخلات والمخرجات والتشفير و حمامات للمخرجات.

المصدر: www.habr.com

إضافة تعليق