Blockchain fejlesztés az ipar számára a Go használatával. 1. rész

Négy hónapja dolgozom a „Blokkláncon alapuló adatvédelmi és adatkezelési eszközök fejlesztése kormányzati és ipari szektorokban” című projekten.
Most arról szeretnék mesélni, hogyan kezdtem el ezt a projektet, és most részletesen leírom a programkódot.

Blockchain fejlesztés az ipar számára a Go használatával. 1. rész

Ez az első cikk egy cikksorozatban. Itt leírom a szervert és a protokollt. Valójában az olvasó akár saját verziót is írhat ezekről a blokklánc-elemekről.

És itt a második rész — a blokkláncról és a tranzakciós adatstruktúrákról, valamint az adatbázissal való interakciót megvalósító csomagról.

Tavaly a Digital Breakthrough hackathonon egy olyan ötlettel álltak elő, hogy az ipar és a digitális gazdaság számára hasznos rendszert készítsenek elosztott főkönyvi technológiával, a fejlesztésre az Innovációs Segítségnyújtás Alapítvány is pályázatot írt ki (külön kellene írnom). cikk a támogatásról, azoknak, akik most kezdik a startupokat ), és most rendben.

A fejlesztés Go nyelven történik, és a blokkokat tartalmazó adatbázis a LevelDB.
A fő részek a protokoll, a szerver (amely a TCP-t és a WebSocketet futtatja - az első a blokklánc szinkronizálására, a második a kliensek összekapcsolására, tranzakciók és parancsok küldésére például JavaScriptből.

Mint már említettük, erre a blokkláncra elsősorban a beszállítók és vásárlók közötti, vagy mindkettő egy személyben történő termékcseréjének automatizálása és védelme érdekében van szükség. Ezek az emberek nem sietnek megbízni egymásban. A feladat azonban nem csak egy beépített számológéppel ellátott „ellenőrző könyv” létrehozása, hanem egy olyan rendszer, amely automatizálja a legtöbb rutinfeladatot, amely a termék életciklusával való munka során felmerül. Az ezért felelős bájtkód, ahogy az a blokkláncoknál megszokott, a tranzakciók be- és kimenetein tárolódik (maguk a tranzakciók blokkokban, a LevelDB blokkjai GOB formátumban vannak előre kódolva). Először beszéljünk a protokollról és a szerverről (más néven csomópont).

A protokoll nem bonyolult, lényege, hogy egy speciális parancssor hatására átvált bizonyos adatok, általában egy blokk vagy tranzakció betöltésének módjára, és szükséges a készletcseréhez is, hogy a csomópont tudja, kiről van szó. csatlakozik, és hogyan van dolguk (a szinkronizálási munkamenethez csatlakoztatott csomópontokat „szomszédnak” is nevezik, mivel az IP-jük ismert, állapotadatai pedig a memóriában vannak tárolva).

A mappákat (könyvtárakat, ahogyan Linux nevezi) a Go programozók felfogásában csomagoknak nevezik, ezért minden fájl elejére, amely ebből a könyvtárból van Go kóddal, azt írják, hogy mappa_név_ahol_ez a fájl található. Ellenkező esetben nem tudja továbbítani a csomagot a fordítónak. Nos, ez nem titok azok számára, akik ismerik ezt a nyelvet. Ezek a csomagok:

  • Hálózati kommunikáció (szerver, kliens, protokoll)
  • A tárolt és továbbított adatok struktúrái (blokk, tranzakció)
  • Adatbázis (blokklánc)
  • Konszenzus
  • Halmozott virtuális gép (xvm)
  • Kiegészítő (kripto, típusok) egyelőre ennyi.

Itt a link a githubhoz

Ez egy oktatási változat, hiányzik belőle a folyamatok közötti interakció és több kísérleti komponens, de a struktúra megfelel annak, amelyen a fejlesztés folyik. Ha van valami javaslatotok kommentben, azt szívesen figyelembe veszem a további fejlesztés során. És most egy magyarázat a szerver és protokoll.

Nézzük először a szervert.

A szerver szubrutin adatszerverként működik, amely a TCP-protokoll tetején fut a protokollcsomagból származó adatstruktúrák használatával.

A rutin a következő csomagokat használja: szerver, protokoll, típusok. Magában a csomagban tcp_server.go adatstruktúrát tartalmaz Szolgál.

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

A következő paramétereket tudja elfogadni:

  • Hálózati port, amelyen keresztül adatcsere történik
  • A szerver konfigurációs fájlja JSON formátumban
  • Megjelölés hibakeresési módban való futtatáshoz (privát blokklánc)

Előrehalad:

  • Beolvassa a konfigurációt a JSON-fájlból
  • A hibakeresési mód jelzője be van jelölve: ha be van állítva, a hálózati szinkronizálás ütemezője nem indul el és a blokklánc nem töltődik be
  • A konfigurációs adatstruktúra inicializálása és a szerver indítása

szerver

  • A TCP szerver elindítását és a hálózati interakciót a protokollnak megfelelően végzi.
  • Kiszolgálási adatstruktúrával rendelkezik, amely portszámból, pufferméretből és a szerkezetre mutató mutatóból áll típusok.Beállítások
  • A Run metódus elindítja a hálózati interakciót (egy adott porton bejövő kapcsolatok figyelése, új kapcsolat fogadásakor a feldolgozása egy új szálban átkerül a privát kezelő metódusba)
  • В fogantyú A kapcsolat adatait a rendszer beolvassa egy pufferbe, karakterlánc-reprezentációvá alakítja és továbbítja protokoll.Választás
  • protokoll.Választás visszatér eredményez vagy hibát okoz. eredményez majd átkerült a protokoll.Interpreteami visszatér intrpr - típusú objektum InterpreteData, vagy hibát okoz a kiválasztási eredmény feldolgozása során
  • Ezután a váltás végrehajtódik intrpr.Commands[0] amely a következők egyikét ellenőrzi: eredmény, bev., hiba és van egy szakasz alapértelmezett
  • A szakaszban eredményez kapcsolót érték alapján találjuk meg intrpr.Commands[1] amely ellenőrzi az értékeket pufferhossz и változat (minden esetben a megfelelő függvényt hívjuk meg)

függvények GetVersion и PufferLength vannak a fájlban srvlib.go szerver csomag

GetVersion(conn net.Conn, version string)

egyszerűen kinyomtatja a konzolra, és elküldi a paraméterben átadott verziót a kliensnek:

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

.
Funkció

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

blokkot, tranzakciót vagy más konkrét adatot tölt be az alábbiak szerint:

  • Kinyomtatja a konzolra a protokollban megadott típusú adatokat, amelyeket el kell fogadni:
    fmt.Println("DataType:", intrpr.Commands[2])
  • Beolvassa az értéket intrpr.Body numerikus változóhoz buf_len
  • Puffert hoz létre newbuf megadott méret:
    make([]byte, buf_len)
  • Rendben választ küld:
    conn.Write([]byte("result:ok"))
  • Teljesen kitölti a puffert az olvasási adatfolyamból:
    io.ReadFull(conn, newbuf)

    .

  • Kinyomtatja a puffer tartalmát a konzolra
    fmt.Println(string(newbuf))

    és az olvasott bájtok száma

    fmt.Println("Bytes length:", n)
  • Rendben választ küld:
    conn.Write([]byte("result:ok"))

A szervercsomag módszerei úgy vannak beállítva, hogy a csomag függvényei segítségével dolgozzák fel a fogadott adatokat protokoll.

Protokoll

A protokoll eszközként szolgál az adatok megjelenítésére a hálózati cserében.

Választás(karakterlánc) (karakterlánc, hiba) elvégzi a szerver által fogadott adatok elsődleges feldolgozását, bemenetként megkapja az adatok sztring reprezentációját, és visszaadja a Tolmács:

  • A bemeneti karakterlánc fejre és testre van osztva ReqParseN2(str)
  • A fej elemre oszlik, és a ReqParseHead(head) segítségével parancsszeletbe helyezi
  • В kapcsoló (parancsok[0]) válassza ki a kapott parancsot (cmd, kulcs, cím vagy a szakasz kioldódik alapértelmezett)
  • 2 parancs van bejelölve a cmd-ben kapcsoló(parancsok[1]) — hossza и getversion.
  • hossz ellenőrzi az adattípust parancsok[2] és elmenti adattípus
  • Azt ellenőrzi test karakterlánc-értéket tartalmaz
    len(body) < 1
  • A válasz karakterláncát adja vissza:
    "result:bufferlength:" + datatype + "/" + body
  • getversion karakterláncot ad vissza
    return "result:version/auto"

Tolmács

Tartalmazza az InterpreteData struktúrát, és másodlagos feldolgozását végzi a visszaküldött adatokon Választás húrok és tárgyképzés InterpreteData.

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

Funkció

Interprete(str string) (*InterpreteData, error)

elfogad egy karakterláncot eredményez és hivatkozást hoz létre és visszaad az objektumra InterpreteData.

Előrehalad:

  • hasonlóképpen Választás fejét és testét segítségével vonják ki ReqParseN2(str)
  • segítségével a fejet elemekre osztjuk ReqParseHead(fej)
  • Az objektum inicializálva van InterpreteData és egy mutatót ad vissza:

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

Ezt az objektumot használják szerver.go csomag fő.

Vásárló

A kliens csomag tartalmazza a funkciókat TCPConnect и TCPResponseData.

Funkció

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

a következőképpen működik:

  • Létrejön a kapcsolat az átadott beállítások objektumban megadott kapcsolattal
    net.Dial("tcp", s.Host + ":" + s.Port)
  • Az adatparaméterben átadott adatok átvitele:
    conn.Write(data)
  • A válasz olvasható
    resp, n, _ := TCPResponseData(conn, s.BufSize)

    és a konzolra nyomtatva

    fmt.Println(string(resp[:n]))
  • Ha áthelyezik hasznos teher majd továbbadja
    conn.Write(payload)

    és beolvassa a szerver választ is, és kinyomtatja a konzolra

Funkció

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

létrehoz egy meghatározott méretű puffert, beolvassa a szerver válaszát és visszaadja ezt a puffert és az olvasott bájtok számát, valamint egy hibaobjektumot.

Kliens szubrutin

Parancsok küldésére szolgál a csomóponti kiszolgálóknak, valamint rövid statisztikák és tesztelések lekérésére.

A következő paramétereket tudja elfogadni: konfigurációs fájl JSON formátumban, a szerverre sztringként küldendő adatok, a rakományba küldendő fájl elérési útja, csomópont-ütemező emulációs jelző, numerikus értékként átvitt adatok típusa.

  • A konfiguráció lekérése
    st := types.ParseConfig(*config)
  • Ha az emu zászlót átadjuk, elindul ütemező
  • Ha megadjuk a fájl elérési útját jelző f jelzőt, akkor betöltjük az adatait FDB és a tartalom elküldésre kerül a szerverre
    client.TCPConnect(st, []byte(CMD_BUFFER_LENGTH + ":" + strconv.Itoa(*t) + "/" + strconv.Itoa(fdblen)), fdb)
  • Ha a fájl nincs megadva, akkor a zászlóból származó adatok egyszerűen elküldésre kerülnek -d:
    client.TCPConnect(st, []byte(*data), nil)

Mindez a protokoll szerkezetét bemutató leegyszerűsített ábrázolás. A fejlesztés során a szükséges funkcionalitás hozzáadódik a szerkezetéhez.

A második részben a blokkok és tranzakciók adatstruktúráiról fogok beszélni, a 3-ban a WebSocket szerverről a JavaScript-ből való csatlakozáshoz, a 4-ben a szinkronizálás ütemezőt, majd egy veremgépet, amely a bemenetek és kimenetek bájtkódját dolgozza fel, kriptográfia ill. medencék a kimenetekhez.

Forrás: will.com

Hozzászólás