Πώς να δημιουργήσετε ένα Blockchain από το Scratch with Go

Εισαγωγή

Με το Web 3.0 και το blockchain να γίνονται πιο mainstream καθημερινά, ξέρετε τι είναι το blockchain; Γνωρίζετε τα τεχνικά του πλεονεκτήματα και τις περιπτώσεις χρήσης;

Ο στόχος αυτού του σεμιναρίου είναι να εισαγάγει τεχνολογία blockchain από τεχνική άποψη δημιουργώντας μία από την αρχή.

Ξεχάστε όλα όσα έχετε ακούσει για το blockchain από τα κοινωνικά μέσα. Τώρα, θα δημιουργήσετε ένα σύστημα blockchain από το μηδέν για να κατανοήσετε πραγματικά τα πλεονεκτήματα αυτής της ομότιμης, κατανεμημένης τεχνολογίας.

Στη συνέχεια, κάντε το μυαλό σας για το μέλλον και τα πλεονεκτήματά του. Ειδοποίηση Spoiler: θα ερωτευτείτε τον προγραμματισμό λογισμικού blockchain.

Πως?

Θα ακολουθήσετε την ιστορία ενός προγραμματιστή λογισμικού που θέλει να φέρει επανάσταση στην τοπική του μπάρα εφαρμόζοντας την τεχνολογία blockchain για το σύστημα πληρωμών της.

Παρόλο που το blockchain έχει πολλές αναμφισβήτητες περιπτώσεις χρήσης, αυτή τη στιγμή, η νούμερο ένα εφαρμογή είναι πληρωμές. Αυτό συμβαίνει επειδή οι τράπεζες εξακολουθούν να λειτουργούν σε μια αναποτελεσματική υποδομή, 40 ετών, που τροφοδοτείται από αρχεία CSV και FTP.

Η ιστορία έρχεται με πολλά διασκεδαστικά και ενδιαφέροντα γεγονότα σχετικά με το συνολικό οικοσύστημα blockchain και διάφορα πρωτόκολλα όπως το Bitcoin, το Ethereum και το XRP.

Τι θα δημιουργήσετε, μάθετε και θα κάνετε σε αυτό το σεμινάριο;

  • Θα ρυθμίσετε ένα έργο Go στον τοπικό σας υπολογιστή χωρίς προηγούμενη εμπειρία στο GoLang
  • Θα δημιουργήσετε και θα διανείμετε τα πρώτα σας μάρκα blockchain
  • Θα αναπτύξετε μια ελεγχόμενη βάση δεδομένων CLI στο Go από το μηδέν
  • Θα μάθετε πόσο λίγα δικαιώματα έχουν οι χρήστες στις αγαπημένες τους εφαρμογές
  • Θα ανακαλύψετε την κύρια πρόταση αξίας του blockchain
  • Θα κάνετε το DB σας αμετάβλητο χρησιμοποιώντας μια ασφαλή λειτουργία κρυπτογράφησης κατακερματισμού

Ας ξεκινήσουμε λοιπόν και πηδούμε στην ιστορία μας.

⭐ Γνωρίστε τον πρωταγωνιστή, Αντρέι.

Ο Andrej είναι ιδιοκτήτης μπαρ το βράδυ και προγραμματιστής λογισμικού τη μέρα σε μια μικρή πόλη της Σλοβακίας που ονομάζεται Bardejov.

Ο Andrej είναι κουρασμένος από:

  • Προγραμματισμός στερεών εφαρμογών PHP / Java / Javascript
  • Ξεχνώντας πόσα χρήματα του οφείλουν οι φίλοι και οι πελάτες του για όλες τις απλήρωτες βολάν της Παρασκευής το βράδυ
  • Αφιερώνοντας χρόνο συλλογής και καταμέτρησης κερμάτων, επιστροφής αλλαγών και γενικά αγγίζοντας τους τραπεζικούς λογαριασμούς που εκτίθενται στο COVID-19
  • Διατήρηση διαφορετικών πλαστικών μαρκών για επιτραπέζιο ποδόσφαιρο, βελάκια, μπιλιάρδο και πόκερ

Ο Αντρέι θα ήθελε:

  • Έχετε μια τέλεια ελεγχόμενη ιστορία των δραστηριοτήτων και των πωλήσεων του μπαρ, ώστε το μπαρ να συμμορφώνεται με τους φορολογικούς κανονισμούς
  • Μεταμορφώστε τη γραμμή του σε ένα αυτόνομο, αποδοτικό στις πληρωμές, αποκεντρωμένο και ασφαλές περιβάλλον που μπορούν να εμπιστεύονται και να επωφελούνται οι πελάτες του

Στόχος του είναι να γράψει ένα απλό πρόγραμμα και να διατηρήσει όλα τα υπόλοιπα των πελατών του σε εικονική μορφή.

Ο Andrej μοιράζεται τις σκέψεις του εδώ:

"Κάθε νέος πελάτης θα μου δώσει μετρητά και θα τους πιστώσω ένα αντίστοιχο ποσό των ψηφιακών μου κουπονιών (νομίσματα / κρυπτονομίσματα). Τα διακριτικά θα αντιπροσωπεύουν μια νομισματική μονάδα εντός και εκτός της μπάρας.

Οι χρήστες θα χρησιμοποιήσουν τα κουπόνια για όλες τις λειτουργίες του μπαρ από την πληρωμή ποτών, το δανεισμό και το δανεισμό τους στους φίλους τους, και παίζοντας πινγκ-πονγκ, πόκερ και kicker.

Έχοντας μια μπάρα που τροφοδοτείται από μάρκες blockchain θα δημιουργήσει τόνους αξίας για τους πελάτες μου. Σε αντίθεση με τον ανταγωνισμό μου και με άλλα μπαρ σε αυτόν τον δρόμο, όπου οι πελάτες ξοδεύουν μόνο χρήματα και ανταλλάσσουν ένα hangover, οι πελάτες του μπαρ που κατέχουν μάρκες του μπαρ θα έχουν δικαιώματα μετόχων.

Παρόμοια με την κατοχή μεγάλου μέρους μετοχών σε μια εταιρεία όπως η Apple ή η Microsoft, οι πελάτες που κατέχουν αυτά τα bar tokens θα μπορούν να αποφασίσουν πώς θα λειτουργεί η μπάρα ψηφίζοντας και αποφασίζοντας:

  • τιμές ποτών
  • ώρες λειτουργίας
  • νέες δυνατότητες (TV, Jukebox ...)
  • εσωτερική και εξωτερική σχεδίαση
  • κατανομή κερδών
  • και τα λοιπά.

Ω, αυτό θα είναι ένα όνειρο προγραμματισμού!

Θα καλέσω τα διακριτικά: Τα διακριτικά της γραμμής Blockchain, TBB! "

Τώρα που ο Andrej μοιράστηκε το όνειρό του, θα ξεκινήσουμε.

Πίνακας περιεχομένων

  • Απαιτήσεις
  • Ρυθμίστε το έργο
  • 01 | Η βάση δεδομένων MVP
  • 02 | Σίγαση παγκόσμιας κατάστασης DB
  • 03 | Μονολιθικό συμβάν έναντι συναλλαγής
  • 04 | Οι άνθρωποι είναι άπληστοι
  • 05 | Γιατί χρειαζόμαστε Blockchain
  • 06 | L'Hash de Αμετάβλητο
  • Επόμενα βήματα

Απαιτήσεις

Ας ρίξουμε μια ματιά στο σεμινάριό μας. Προτείνω 2+ χρόνια εμπειρίας προγραμματισμού σε Java / PHP / Javascript ή άλλη γλώσσα παρόμοια με το Go.

Αν θέλετε να πάρετε μια καλή γρήγορη εισαγωγή, ακολουθήστε ένα δωρεάν μάθημα που θα σας ξεκινήσει.

Μπορείτε επίσης να ολοκληρώσετε τις επίσημες 17 διαλέξεις του A Tour Of Go για να εξοικειωθείτε με τη σύνταξη της γλώσσας και τις βασικές έννοιες (~ 20 λεπτά).

Γιατί να πάτε;

Επειδή όπως το blockchain, είναι μια φανταστική τεχνολογία για τη συνολική καριέρα προγραμματισμού σας. Το Go είναι μια μοντέρνα γλώσσα και οι Go devs πληρώνονται καλύτερα από τις μέσες θέσεις Java / PHP / Javascript.

Go is optimized for multi-core CPU architecture. You can spawn thousands of light-weight threads (Go-routines) without problems. It's extremely practical for highly parallel and concurrent software such as blockchain networks.

By writing your software in Go, you achieve nearly C++ level of performance out of the box without killing yourself for that one time you forgot to free up memory.

Go also compiles to binary which makes it very portable.

Setup the project

This article has a dedicated open-sourced Github repository with full source code so you can compile the code and run the program on your own local machine.

If you get stuck at any chapter or a particular line of code, create a Github Issue in this repository describing your problem and I will help you out ASAP!

↓ Visit the Github repository and follow the installation instructions ↓

web3coach / the-blockchain-bar-newsletter-edition Ο πηγαίος κώδικας για τα πρώτα 7 κεφάλαια του: «Ο Blockchain Way of Programming» eBook. - web3coach / the-blockchain-bar-newsletter-edition web3coach GitHub

01 | Η βάση δεδομένων MVP

git checkout c1_genesis_json

Ο Andrej κατέκτησε σχεσιακές βάσεις δεδομένων SQL τη δεκαετία του '90. Ξέρει πώς να κάνει προηγμένα μοντέλα δεδομένων και πώς να βελτιστοποιήσει τα ερωτήματα SQL.

Ήρθε η ώρα για τον Andrej να καλύψει την καινοτομία και να αρχίσει να δημιουργεί λογισμικό Web 3.0.

Ευτυχώς, μετά την ανάγνωση του βιβλίου "The Lean Startup" την περασμένη εβδομάδα, ο Andrej αισθάνεται ότι δεν θα έπρεπε να σχεδιάσει ακόμη περισσότερο τη λύση. Ως εκ τούτου, επιλέγει ένα απλό αλλά αποτελεσματικό αρχείο JSON για τη βάση δεδομένων MVP της γραμμής.

Στην αρχή, υπήρχε μια πρωτόγονη κεντρική βάση δεδομένων.

; Περίληψη

Το Blockchain είναι μια βάση δεδομένων.

Χρήστης 1, Andrej

Δευτέρα 18 Μαρτίου

Ο Andrej δημιουργεί 1 μάρκες χρησιμότητας.

In the blockchain world, tokens are units inside the blockchain database. Their real value in dollars or euro fluctuates based on their demand and popularity.

Every blockchain has a "Genesis" file. The Genesis file is used to distribute the first tokens to early blockchain participants.

It all starts with a simple, dummy genesis.json.

Andrej creates the file ./database/genesis.json where he defines that The Blockchain Bar's database will have 1M tokens and all of them will belong to Andrej:

{ "genesis_time": "2019-03-18T00:00:00.000000000Z", "chain_id": "the-blockchain-bar-ledger", "balances": { "andrej": 1000000 } } 

The tokens need to have a real "utility", that is a use case. Users should be able to pay with them from day 1!

Andrej must comply with law regulators (the SEC). It is illegal to issue unregistered security. On the other hand, utility tokens are fine, so right away he prints and sticks a new pricing white p̶a̶p̶e̶r̶ poster on the bar's door.

Andrej assigns a starting monetary value to his tokens so he can exchange them for euro, dollars, or other fiat currency.

1 TBB token = 1€ | Item | Price | | ------------------------- | ------- | | Vodka shot | 1 TBB | | Orange juice | 5 TBB | | Burger | 2 TBB | | Crystal Head Vodka Bottle | 950 TBB | 

Andrej also decides he should be getting 100 tokens per day for maintaining the database and having such a brilliant disruptive idea.

?Fun Facts

Η πρώτη γένεση Ether (ETH) στο Ethereum blockchain δημιουργήθηκε και διανεμήθηκε σε πρώιμους επενδυτές και προγραμματιστές με τον ίδιο τρόπο όπως το βοηθητικό σήμα του Andrej. Το 2017, κατά τη διάρκεια μιας έκρηξης ICO (αρχικές προσφορές νομισμάτων) στο δίκτυο blockchain Ethereum, οι ιδρυτές έργων έγραψαν και παρουσίασαν λευκές βίβλους σε επενδυτές. Το whitepaper είναι ένα τεχνικό έγγραφο που περιγράφει ένα περίπλοκο ζήτημα και πιθανή λύση, που προορίζεται να εκπαιδεύσει και να διευκρινίσει ένα συγκεκριμένο θέμα. Στον κόσμο των blockchain, μια λευκή βίβλος χρησιμεύει για να περιγράψει τις προδιαγραφές για το πώς θα φαίνεται και θα συμπεριφέρεται το συγκεκριμένο blockchain μόλις αναπτυχθεί. Τα έργα blockchain αυξήθηκαν μεταξύ 10 εκατ. Ευρώ και 300 εκατ. Ευρώ ανά λευκή βίβλοidea.in σε αντάλλαγμα χρημάτων (η "χρηματοδότηση" του ICO), τα ονόματα των επενδυτών θα συμπεριληφθούν στα αρχικά "υπόλοιπα των γενεών", παρόμοια με το πώς το έκανε ο Andrej. Οι ελπίδες των επενδυτών μέσω ενός ICO είναι ότι τα κέρματα γεννήσεων αυξάνονται σε αξία και ότι οι ομάδες παραδίδουν το περιγραμμένο blockchain. Φυσικά, δεν υλοποιούνται όλες οι ιδέες του λευκού βιβλίου. Οι μαζικές επενδύσεις που χάθηκαν σε ασαφείς ή ελλιπείς ιδέες είναι γιατί το blockchain έλαβε αρνητική κάλυψη στα μέσα ενημέρωσης σε όλους αυτούς τους ICO και γιατί ορισμένοι εξακολουθούν να το θεωρούν διαφημιστική. Αλλά η βασική τεχνολογία blockchain είναι φανταστική και χρήσιμη, καθώς θα μάθετε περισσότερα σε αυτό το βιβλίο. Απλώς κακοποιήθηκε από μερικούς κακούς ηθοποιούς.

; Περίληψη

Το Blockchain είναι μια βάση δεδομένων.

Η προσφορά διακριτικών, τα αρχικά υπόλοιπα χρηστών και οι καθολικές ρυθμίσεις blockchain που ορίζετε σε ένα αρχείο Genesis.

02 | Σίγαση παγκόσμιας κατάστασης DB

git checkout c2_db_changes_txt

Νεκρό πάρτι

Monday, March 25.

After a week of work, the bar facilities are ready to accept tokens. Unfortunately, no one shows up, so Andrej orders three shots of vodka for himself and writes the database changes on a piece of paper:

andrej-3; // 3 shots of vodka andrej+3; // technically purchasing from his own bar andrej+700; // Reward for a week of work (7x100 per day) 

To avoid recalculating the latest state of each customer's balance, Andrej creates a ./database/state.json file storing the balances in an aggregated format.

New DB state:

{ "balances": { "andrej": 1000700 } } 

Bonus for BabaYaga

Tuesday, March 26.

To bring traffic to his bar, Andrej announces an exclusive 100% bonus for everyone who purchases the TBB tokens in the next 24 hours.

Bing! He gets his first customer called BabaYaga. BabaYaga pre-purchases 1000€ worth of tokens, and to celebrate, she immediately spends 1 TBB for a vodka shot. She has a drinking problem.

DB transactions written on a piece of paper:

andrej-2000; // transfer to BabaYaga babayaga+2000; // pre-purchase with 100% bonus babayaga-1; andrej+1; andrej+100; // 1 day of sun coming up 

New DB state:

{ "balances": { "andrej": 998801, "babayaga": 1999 } } 

?Fun Facts

Τα έργα Blockchain ICO (αρχικές προσφορές νομισμάτων με βάση τα λευκά χαρτιά) συχνά διανέμουν τα γενετικά διακριτικά με διαφορετικά μπόνους, ανάλογα με το πόσα από αυτά αγοράζετε και πόσο νωρίς το κάνετε. Οι ομάδες προσφέρουν, κατά μέσο όρο, 10-40% μπόνους σε πρώιμους "συμμετέχοντες". Η λέξη "επενδυτής" αποφεύγεται, επομένως οι ρυθμιστικές αρχές δεν θα θεωρούν τα σύμβολα ως ασφάλεια. Τα έργα θα δικαιολογούσαν το κύριο προϊόν τους, τα tokens blockchain, λειτουργούσαν ως "πόντοι πίστης, πίστης". Οι "συμμετέχοντες" αργότερα κέρδισαν ακόμη και 1000% στις επενδύσεις τους στο κοινό μέσω ανταλλαγής αρκετούς μήνες αργότερα.

?Περίληψη

Το Blockchain είναι μια βάση δεδομένων.

Η προσφορά διακριτικών, τα αρχικά υπόλοιπα χρηστών και οι καθολικές ρυθμίσεις blockchain που ορίζετε σε ένα αρχείο Genesis.

Τα υπόλοιπα Genesis δείχνουν ποια ήταν η αρχική κατάσταση blockchain και δεν ενημερώνονται ποτέ μετά.

The database state changes are called Transactions (TX).

03 | Monolithic Event vs Transaction

git checkout c3_state_blockchain_component

Developers used to event-sourcing architecture must have immediately recognized the familiar principles behind transactions. They are correct.

Blockchain transactions represent a series of events, and the database is a final aggregated, calculated state after replaying all the transactions in a specific sequence.

Andrej Programming

Tuesday evening, March 26.

It's a relaxing Tuesday evening for Andrej. Celebrating his first client, he decides to play some Starcraft and clean up his local development machine by removing some old pictures.

Unfortunately, he prematurely pressed enter when typing a removal command path in terminal sudo rm -rf /. Oops.

All his files, including the bar's genesis.json and state.json are gone.

Andrej, being a senior developer, repeatedly shouted some f* words very loudly for a few seconds, but he didn't panic!

While he didn't have a backup, he had something better — a piece of paper with all the database transactions. The only thing he needs to do is replay all the transactions one by one, and his database state will get recovered.

Impressed by the advantages of event-based architecture, he decides to extend his MVP database solution. Every bar's activity, such as individual drink purchases, MUST be recorded inside the blockchain database.

Each customer will be represented in DB using an Account Struct:

type Account string 

Each Transaction (TX - a database change) will have the following four attributes: from, to, value and data.

The data attribute with one possible value (reward) captures Andrej's bonus for inventing the blockchain and increases the initial TBB tokens total supply artificially (inflation).

type Tx struct { From Account `json:"from"` To Account `json:"to"` Value uint `json:"value"` Data string `json:"data"` } func (t Tx) IsReward() bool { return t.Data == "reward" } 

The Genesis DB will remain a JSON file:

{ "genesis_time": "2019-03-18T00:00:00.000000000Z", "chain_id": "the-blockchain-bar-ledger", "balances": { "andrej": 1000000 } } 

All the transactions, previously written on a piece of paper, will be stored in a local text-file database called tx.db, serialized in JSON format and separated by line-break character:

{"from":"andrej","to":"andrej","value":3,"data":""} {"from":"andrej","to":"andrej","value":700,"data":"reward"} {"from":"andrej","to":"babayaga","value":2000,"data":""} {"from":"andrej","to":"andrej","value":100,"data":"reward"} {"from":"babayaga","to":"andrej","value":1,"data":""} 

The most crucial database component encapsulating all the business logic will be State:

type State struct { Balances map[Account]uint txMempool []Tx dbFile *os.File } 

The State struct will know about all user balances and who transferred TBB tokens to whom, and how many were transferred.

It's constructed by reading the initial user balances from genesis.json file:

func NewStateFromDisk() (*State, error) { // get current working directory cwd, err := os.Getwd() if err != nil { return nil, err } genFilePath := filepath.Join(cwd, "database", "genesis.json") gen, err := loadGenesis(genFilePath) if err != nil { return nil, err } balances := make(map[Account]uint) for account, balance := range gen.Balances { balances[account] = balance } 

Afterwards, the genesis State balances are updated by sequentially replaying all the database events from tx.db:

 txDbFilePath := filepath.Join(cwd, "database", "tx.db") f, err := os.OpenFile(txDbFilePath, os.O_APPEND|os.O_RDWR, 0600) if err != nil { return nil, err } scanner := bufio.NewScanner(f) state := &State{balances, make([]Tx, 0), f} // Iterate over each the tx.db file's line for scanner.Scan() { if err := scanner.Err(); err != nil { return nil, err } // Convert JSON encoded TX into an object (struct) var tx Tx json.Unmarshal(scanner.Bytes(), &tx) // Rebuild the state (user balances), // as a series of events if err := state.apply(tx); err != nil { return nil, err } } return state, nil } 

The State component is responsible for:

  • Adding new transactions to Mempool
  • Validating transactions against the current State (sufficient sender balance)
  • Changing the state
  • Persisting transactions to disk
  • Calculating accounts balances by replaying all transactions since Genesis in a sequence

Adding new transactions to Mempool:

func (s *State) Add(tx Tx) error { if err := s.apply(tx); err != nil { return err } s.txMempool = append(s.txMempool, tx) return nil } 

Persisting the transactions to disk:

func (s *State) Persist() error { // Make a copy of mempool because the s.txMempool will be modified // in the loop below mempool := make([]Tx, len(s.txMempool)) copy(mempool, s.txMempool) for i := 0; i < len(mempool); i++ { txJson, err := json.Marshal(s.txMempool[i]) if err != nil { return err } if _, err = s.dbFile.Write(append(txJson, '\n')); err != nil { return err } // Remove the TX written to a file from the mempool // Yes... this particular Go syntax is a bit weird s.txMempool = append(s.txMempool[:i], s.txMempool[i+1:]...) } return nil }

Changing, Validating the state:

func (s *State) apply(tx Tx) error { if tx.IsReward() { s.Balances[tx.To] += tx.Value return nil } if tx.Value > s.Balances[tx.From] { return fmt.Errorf("insufficient balance") } s.Balances[tx.From] -= tx.Value s.Balances[tx.To] += tx.Value return nil } 

Building a Command-Line-Interface (CLI)

Tuesday evening, March 26.

Andrej wants to have a convenient way to add new transactions to his DB and list the latest balances of his customers. Because Go programs compile to binary, he builds a CLI for his program.

The easiest way to develop CLI based programs in Go is by using the third party github.com/spf13/cobra library.

Andrej initializes Go's built-in dependency manager for his project, called go modules:

cd $GOPATH/src/github.com/web3coach/the-blockchain-way-of-programming-newsletter-edition

go mod init github.com/web3coach/the-blockchain-way-of-programming-newsletter-edition

The Go modules command will automatically fetch any library you reference within your Go files.

Andrej creates a new directory called: cmd with a subdirectory tbb:

mkdir -p ./cmd/tbb

Inside he creates a main.go file, serving as the program's CLI entry point:

package main import ( "github.com/spf13/cobra" "os" "fmt" ) func main() { var tbbCmd = &cobra.Command{ Use: "tbb", Short: "The Blockchain Bar CLI", Run: func(cmd *cobra.Command, args []string) { }, } err := tbbCmd.Execute() if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } } 

The Go programs are compiled using the install cmd:

go install ./cmd/tbb/...

go: finding github.com/spf13/cobra v1.0.0 go: downloading github.com/spf13/cobra v1.0.0 go: extracting github.com/spf13/cobra v1.0.0

Go will detect missing libraries and automatically fetch them before compiling the program. Depending on your $GOPATH the resulting program will be saved in the $GOPATH/bin folder.

echo $GOPATH

/home/web3coach/go

which tbb

/home/web3coach/go/bin/tbb

You can run tbb from your terminal now, but it will not do anything because the Run function inside the main.go file is empty.

The first thing Andrej needs is versioning support for his tbb CLI program.

Next to the main.go file, he creates a version.go command:

package main import ( "fmt" "github.com/spf13/cobra" ) const Major = "0" const Minor = "1" const Fix = "0" const Verbal = "TX Add && Balances List" var versionCmd = &cobra.Command{ Use: "version", Short: "Describes version.", Run: func(cmd *cobra.Command, args []string) { fmt.Printf("Version: %s.%s.%s-beta %s", Major, Minor, Fix, Verbal) }, } 

Compiles and runs it:

go install ./cmd/tbb/...

tbb version

Version: 0.1.0-beta TX Add && Balances List

Perfect.

Identically to the version.go file, he creates a balances.go file:

func balancesCmd() *cobra.Command { var balancesCmd = &cobra.Command{ Use: "balances", Short: "Interact with balances (list...).", PreRunE: func(cmd *cobra.Command, args []string) error { return incorrectUsageErr() }, Run: func(cmd *cobra.Command, args []string) { }, } balancesCmd.AddCommand(balancesListCmd) return balancesCmd } 

The balances command will be responsible for loading the latest DB State and printing it to the standard output:

var balancesListCmd = &cobra.Command{ Use: "list", Short: "Lists all balances.", Run: func(cmd *cobra.Command, args []string) { state, err := database.NewStateFromDisk() if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } defer state.Close() fmt.Println("Accounts balances:") fmt.Println("__________________") fmt.Println("") for account, balance := range state.Balances { fmt.Println(fmt.Sprintf("%s: %d", account, balance)) } }, } 

Andrej verifies if the cmd works as expected. It should print the exact balances defined in the Genesis file because the tx.db file is still empty.

go install ./cmd/tbb/...

tbb balances list

Accounts balances: __________________ andrej: 1000000 

Works well! Now he only needs a cmd for recording the bar's activity.

Andrej creates ./cmd/tbb/tx.go cmd:

func txCmd() *cobra.Command { var txsCmd = &cobra.Command{ Use: "tx", Short: "Interact with txs (add...).", PreRunE: func(cmd *cobra.Command, args []string) error { return incorrectUsageErr() }, Run: func(cmd *cobra.Command, args []string) { }, } txsCmd.AddCommand(txAddCmd()) return txsCmd } 

The tbb tx add cmd uses State.Add(tx) function for persisting the bar's events into the file system:

func txAddCmd() *cobra.Command { var cmd = &cobra.Command{ Use: "add", Short: "Adds new TX to database.", Run: func(cmd *cobra.Command, args []string) { from, _ := cmd.Flags().GetString(flagFrom) to, _ := cmd.Flags().GetString(flagTo) value, _ := cmd.Flags().GetUint(flagValue) fromAcc := database.NewAccount(from) toAcc := database.NewAccount(to) tx := database.NewTx(fromAcc, toAcc, value, "") state, err := database.NewStateFromDisk() if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } // defer means, at the end of this function execution, // execute the following statement (close DB file with all TXs) defer state.Close() // Add the TX to an in-memory array (pool) err = state.Add(tx) if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } // Flush the mempool TXs to disk err = state.Persist() if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } fmt.Println("TX successfully added to the ledger.") }, } 

The tbb tx add cmd has 3 mandatory flags: --from, --to and --value.

cmd.Flags().String(flagFrom, "", "From what account to send tokens") cmd.MarkFlagRequired(flagFrom) cmd.Flags().String(flagTo, "", "To what account to send tokens") cmd.MarkFlagRequired(flagTo) cmd.Flags().Uint(flagValue, 0, "How many tokens to send") cmd.MarkFlagRequired(flagValue) return cmd 

The CLI is done!

Andrej migrates all transactions from paper to his new DB:

tbb tx add --from=andrej --to=andrej --value=3

tbb tx add --from=andrej --to=andrej --value=700

tbb tx add --from=babayaga --to=andrej --value=2000

tbb tx add --from=andrej --to=andrej --value=100 --data=reward

tbb tx add --from=babayaga --to=andrej --value=1

Read all TXs from disk and calculate the latest state:

tbb balances list

Accounts balances: __________________ andrej: 998801 babayaga: 1999 

Bar data successfully restored! Phew, what a night!

About the Cobra CLI library

The good thing about the Cobra lib for CLI programming is the additional features it comes with. For example, you can now run: tbb help cmd and it will print out all TBB registered sub-commands with instructions on how to use them.

 tbb help The Blockchain Bar CLI Usage: tbb [flags] tbb [command] Available Commands: balances Interact with balances (list...). help Help about any command tx Interact with txs (add...). version Describes version. Flags: -h, --help help for tbb Use "tbb [command] --help" for more information about a command. 

?Fun Facts

Τυχαία απώλεια δεδομένων πελατών είναι ένα τυπικό Σάββατο στον εταιρικό κόσμο αυτές τις μέρες. Το Blockchain το επιδιορθώνει αποκεντρώνοντας την αποθήκευση δεδομένων. Το κόλπο του Andrej μπήκε στο πρόγραμμα παρακάμπτοντας την επαλήθευση υπολοίπου για TXs που σημειώθηκαν ως ανταμοιβές. Τα Bitcoin και Ethereum λειτουργούν με τον ίδιο τρόπο. Το υπόλοιπο του Λογαριασμού που εξόρυξε ένα μπλοκ αυξάνεται απότομα ως θέμα του συνολικού πληθωρισμού προσφοράς μαρκών που επηρεάζει ολόκληρη την αλυσίδα. Η συνολική προσφορά bitcoin είναι περιορισμένη στα 21M BTC. Θα μάθετε περισσότερα για την «εξόρυξη» και τα «μπλοκ» στα κεφάλαια 7 και 10. Τα στοιχεία State and Mempoolδεν είναι μοναδικά σε αυτό το πρόγραμμα. Ο Andrej επέλεξε τα ονόματα και τα σχέδια για να ταιριάζει με ένα απλοποιημένο μοντέλο Go-Ethereum, ώστε να έχετε μια ματιά στον βασικό πηγαίο κώδικα Ethereum.

; Περίληψη

Το Blockchain είναι μια βάση δεδομένων.

Η προσφορά διακριτικών, τα αρχικά υπόλοιπα χρηστών και οι καθολικές ρυθμίσεις blockchain καθορίζονται σε ένα αρχείο Genesis.

Τα υπόλοιπα Genesis δείχνουν ποια ήταν η αρχική κατάσταση blockchain και δεν ενημερώνονται ποτέ μετά.

Οι αλλαγές κατάστασης βάσης δεδομένων ονομάζονται Transactions (TX).

Οι συναλλαγές είναι παλιές εκδηλώσεις μόδας που αντιπροσωπεύουν ενέργειες εντός του συστήματος.

⚒ Κωδικός μελέτης

Δέσμευση: 5d4b0b

Ας μιλήσουμε για την απληστία.

04 | Οι άνθρωποι είναι άπληστοι

git checkout c4_caesar_transfer

Τυπική επιχειρηματική απληστία

Τετάρτη, 27 Μαρτίου.

Η BabaYaga επένδυσε πάρα πολύ. Ξέχτηκε ότι η κατ 'αποκοπή πληρωμή ενοικίου της ήταν πολύ κοντά και δεν έχει τα χρήματα. Η BabaYaga καλεί τον ιδιοκτήτη της, τον Καίσαρα.

BabaYaga: Hey Caesar, I am sorry, but I don't have the cash to pay you the rent this month…

Caesar: Why not?

BabaYaga: The Blockchain Bar ICO offered a massive bonus, and I purchased 2000€ worth of tokens for just 1000€. It was a great deal!

Caesar: What the heck are you talking about? What is an ICO? What on earth are tokens? Can you pay me in some other way?

BabaYaga: Oh, not again. I can give you 1000 TBB tokens worth 1000€, and you can use them in the bar to pay for your drinks! Let me call the bar owner, Andrej, and make the transfer!

Caesar: All right... I will take it.

Andrej performs the transfer, but decides to charge an extra 50 TBB tokens for his troubles. He doesn't want to, BUT the bar shareholders who invested in him a few years ago are forcing him to generate profit as soon as possible.

BabaYaga won't notice this relatively small fee most likely anyway, Andrej tells himself. In the end, only he has the DB access.

// Rent payment

tbb tx add --from=babayaga --to=caesar --value=1000

// hidden fee charge

tbb tx add --from=babayaga --to=andrej --value=50

// new reward for another day of maintaining the DB

tbb tx add --from=andrej --to=andrej --value=100 --data=reward

?Fun Facts

Η νούμερο ένα περίπτωση χρήσης blockchain είναι τραπεζική. Πολλά έργα blockchain στοχεύουν στη βελτιστοποίηση της εγχώριας και διεθνούς ανταλλαγής χρημάτων σε διαφορετικούς νομίσματα (XRP). Άλλα έργα επικεντρώνονται στην ελευθερία και την αυτόνομη ταυτότητα (SSI) - ένα ψηφιακό κίνημα που αναγνωρίζει ότι ένα άτομο πρέπει να κατέχει και να ελέγχει την ταυτότητα και τα χρήματά του χωρίς τις παρεμβαίνουσες διοικητικές αρχές ή άλλους κεντρικούς μεσάζοντες. Το SSI επιτρέπει στους ανθρώπους να αλληλεπιδρούν στον ψηφιακό κόσμο με την ίδια ελευθερία και ικανότητα εμπιστοσύνης όπως και στον κόσμο εκτός σύνδεσης. (Bitcoin / Ethereum) Εδώ είναι μερικά διασκεδαστικά γεγονότα για τους οποίους το blockchain είναι ιδανικό για την αντικατάσταση της τρέχουσας τραπεζικής υποδομής της τράπεζάς σας. Το καλό πράγμα για τα εικονικά tokens είναι η δυνατότητα λειτουργίας τους - δηλαδή, η ικανότητά τους να ανταλλάσσονται, με κάθε μονάδα να είναι τόσο χρήσιμη όσο η Επόμενο.Η εκτέλεση μεταφοράς από λογαριασμό σε λογαριασμό μπορεί να γίνει απλά αλλάζοντας την κατάσταση της βάσης δεδομένων. Τα κρυπτονομίσματα είναι εμπορεύσιμα 24/7. Δεν μπορείτε να ανταλλάξετε μετοχές άμεσα. Πρέπει να περάσετε από έναν μεσίτη που λαμβάνει μέρος ως ποσοστό της συνολικής συναλλαγής ως αμοιβή (1-3% έως 7% μέσο ετήσιο κέρδος). Μια διεθνής τραπεζική μεταφορά διαρκεί 3-10 εργάσιμες ημέρες και μπορεί να κοστίσει έως και 5% της μεταφερόμενης αξίας! Εάν στέλνετε 10.000 $, ίσως χρειαστεί να πληρώσετε έως και 500 $. Η τεχνολογία πίσω από τα τελευταία 40 χρόνια; Αρχεία FTP + CSV. Πιστεύετε ότι το χρηματιστήριο είναι δίκαιο; Οι τράπεζες, οι δείκτες και τα αποθέματα συγκεντρώνονται και ελέγχονται σε μεγάλο βαθμό από κυβερνήσεις και ιδιωτικούς ομίλους Wall Street. Ελεύθερη αγορά? Η Wall Street ελέγχει πόσες τιμές μπορούν να πηδήξουν / μειωθούν σε μία μέρα. Για παράδειγμα, η Wall Street σταμάτησε τις συναλλαγές του "S&P 500 Index"μετά από πτώση 7% για να προστατεύσουν τους επενδυτές τους και να αντισταθμίσουν τα αμοιβαία κεφάλαιά τους από την απώλεια χρημάτων από άτομα που πωλούν τις μετοχές τους τον Μάρτιο του 2020 μετά τις ειδήσεις COVID Στη συνέχεια, η FED εκτύπωσε τρισεκατομμύρια δολάρια για να υποστηρίξει την τιμή της μετοχής. Εάν είστε προγραμματιστής που του αρέσει να εξοικονομεί χρήματα και να αποφεύγει το χρέος, οι αποταμιεύσεις σας έχασαν την αξία τους κατά τη διάρκεια της νύχτας κατά ένα ακόμη άγνωστο ποσοστό. Πολλές χώρες εισέρχονται σε αρνητικές αποδόσεις, μια ανεξερεύνητη περιοχή με άγνωστες συνέπειες. Τι σημαίνει αυτό? Σύντομα θα πρέπει να πληρώσετε την τράπεζα για να διατηρήσετε τις αποταμιεύσεις σας. Ο πληθωρισμός στα καλύτερά του. Αναγκάζεστε να ξοδέψετε τα χρήματά σας για να υποστηρίξετε ένα σύστημα που δεν ελέγχετε.η FED εκτύπωσε τρισεκατομμύρια δολάρια για να υποστηρίξει την τιμή της μετοχής. Εάν είστε προγραμματιστής που του αρέσει να εξοικονομεί χρήματα και να αποφεύγει το χρέος, οι αποταμιεύσεις σας έχασαν την αξία τους κατά τη διάρκεια της νύχτας κατά ένα ακόμη άγνωστο ποσοστό. Πολλές χώρες εισέρχονται σε αρνητικές αποδόσεις, μια ανεξερεύνητη περιοχή με άγνωστες συνέπειες. Τι σημαίνει αυτό? Σύντομα θα πρέπει να πληρώσετε την τράπεζα για να διατηρήσετε τις αποταμιεύσεις σας. Ο πληθωρισμός στα καλύτερά του. Αναγκάζεστε να ξοδέψετε τα χρήματά σας για να υποστηρίξετε ένα σύστημα που δεν ελέγχετε.η FED εκτύπωσε τρισεκατομμύρια δολάρια για να υποστηρίξει την τιμή της μετοχής. Εάν είστε προγραμματιστής που του αρέσει να εξοικονομεί χρήματα και να αποφεύγει το χρέος, οι αποταμιεύσεις σας έχασαν την αξία τους κατά τη διάρκεια της νύχτας κατά ένα ακόμη άγνωστο ποσοστό. Πολλές χώρες εισέρχονται σε αρνητικές αποδόσεις, μια ανεξερεύνητη περιοχή με άγνωστες συνέπειες. Τι σημαίνει αυτό? Σύντομα θα πρέπει να πληρώσετε την τράπεζα για να διατηρήσετε τις αποταμιεύσεις σας. Ο πληθωρισμός στα καλύτερά του. Αναγκάζεστε να ξοδέψετε τα χρήματά σας για να υποστηρίξετε ένα σύστημα που δεν ελέγχετε.Αναγκάζεστε να ξοδέψετε τα χρήματά σας για να υποστηρίξετε ένα σύστημα που δεν ελέγχετε.Αναγκάζεστε να ξοδέψετε τα χρήματά σας για να υποστηρίξετε ένα σύστημα που δεν ελέγχετε.

⚒ Study Code

Commit: 00d6ed

05 | Why We Need Blockchain

git checkout c5_broken_trust

BabaYaga Seeks Justice

Thursday, March 28.

BabaYaga enters the bar for her birthday.

BabaYaga: Hey, Andrej! Today is my birthday! Get me your most expensive bottle!

Andrej: Happy birthday! Here you go: Crystal Head Vodka. But you need to purchase one additional TBB token. The bottle costs 950 tokens, and your balance is 949.

BabaYaga: What?! My balance is supposed to be 999 TBB!

Andrej: The funds transfer to Caesar you requested last week cost you 50 tokens.

BabaYaga: This is unacceptable! I would never agree to such a high fee. You can't do this, Andrej. I trusted your system, but you are as unreliable as every other business owner. Things must change!

Andrej: All right, look. You are my most loyal customer, and I didn't want to charge you, but my shareholders forced me.

Let me re-program my system and make it completely transparent and decentralized. After all, if everyone were able to interact with the bar without going through me, it would significantly improve the bar's efficiency and balance the level of trust!

  • Ordering drinks would take seconds instead of minutes
  • The customers who forgot their wallets at home could borrow or lend tokens to each other
  • I wouldn't have to worry about losing the clients data (again) as everyone would have a copy of it
  • The database would be immutable, so once everyone would agree on a specific state, no one else can change it or maliciously modify the history. Immutability would help with yearly tax audits as well!
  • If shareholders wanted to introduce new fees or raise the current ones, everyone involved in the blockchain system would notice and have to agree with it. The users and business owners would even have to engage in some decentralized governance system together, based on voting, probably. In case of a disagreement, the users walk away with all their data!

BabaYaga: Well, it certainly sounds good, but is this even possible?

Andrej: Yes, I think so. With a bit of hashing, linked lists, immutable data structure, distributed replication, and asymmetric cryptography!

BabaYaga: Δεν έχω ιδέα τι μόλις είπατε, αλλά πηγαίνετε και κάντε το geeky πράγμα σας, Andrej!

?ΑΣΤΕΙΑ ΓΕΓΟΝΟΤΑ

Οι ανθρακωρύχοι Bitcoin και Ethereum λαμβάνουν επίσης ανταμοιβές κάθε ~ 15 λεπτά για την εκτέλεση των διακομιστών blockchain (κόμβους) και την επικύρωση συναλλαγών. Κάθε 15 λεπτά, ένας ανθρακωρύχος Bitcoin λαμβάνει 12,5 BTC (100.000 $ τη στιγμή της σύνταξης αυτής της σελίδας) για να καλύψει το κόστος των διακομιστών του + κάντε κάποιο κέρδος. Το δίκτυο Bitcoin καταναλώνει τόσο ηλεκτρική ενέργεια όσο ολόκληρη η χώρα της Αυστρίας. Αντιπροσωπεύει το 0,29% της παγκόσμιας ετήσιας κατανάλωσης ηλεκτρικής ενέργειας. Κάθε χρόνο καταναλώνει 76,84 TWh, παράγοντας 36,50 Mt CO2 αποτύπωμα άνθρακα (Νέα Ζηλανδία). Πηγή. Γιατί; Θα μάθετε περισσότερα αργότερα (στο Κεφάλαιο 11) όπου θα προγραμματίσετε έναν αλγόριθμο εξόρυξης Bitcoin από το μηδέν! PS: Ο αλγόριθμός μας θα καταναλώνει λίγο λιγότερη ηλεκτρική ενέργεια :)

; Περίληψη

Closed software with centralized access to private data allows for just a handful of people to have a lot of power. Users don’t have a choice, and shareholders are in business to make money.

Blockchain developers aim to develop protocols where applications' entrepreneurs and users synergize in a transparent, auditable relationship. Specifications of the blockchain system should be well-defined from the beginning and only change if its users support it.

Blockchain is a database. The token supply, initial user balances, and global blockchain settings are defined in a Genesis file. The Genesis balances indicate what was the original blockchain state and are never updated afterwards.

The database state changes are called Transactions (TX). Transactions are old fashion Events representing actions within the system.

⚒ Study Code

Commit: 642045

06 | L'Hash de Immutable

git checkout c6_immutable_hash

The technical difficulty starts with this section! The concepts will only get more challenging but at the same time, very exciting. Buckle up :)

How to Program an Immutable Database?

Friday, March 29.

If Andrej wants to figure out how to program an immutable DB, he has to realize why other database systems are mutable by design.

He decides to analyze an all-mighty MySQL DB Table:

| id | name | balance | | -- | -------- | ------- | | 1 | Andrej | 998951 | | 2 | BabaYaga | 949 | | 3 | Caesar | 1000 |

In MySQL DB, anyone with access and a good enough reason can perform a table update such as:

UPDATE user_balance SET balance = balance + 100 WHERE id > 1 

Updating values across different rows is possible because the table rows are independent, mutable, and the latest state is not apparent.

Ποια είναι η τελευταία αλλαγή DB; Η τελευταία στήλη άλλαξε; Έγινε εισαγωγή της τελευταίας σειράς; Εάν ναι, πώς μπορεί ο Andrej να γνωρίζει ποια σειρά διαγράφηκε πρόσφατα; Εάν οι σειρές και η κατάσταση του πίνακα ήταν σφιχτά συνδεδεμένες, εξαρτώμενες, ή αλλιώς, η ενημέρωση της σειράς 1 θα δημιουργούσε έναν εντελώς νέο, διαφορετικό πίνακα, ο Andrej θα πετύχαινε το αμετάβλητο.

Πώς μπορείτε να διαπιστώσετε εάν έχει αλλάξει κάποιο byte σε μια βάση δεδομένων;

Αμετάβλητο μέσω των λειτουργιών Hash

Το κατακερματισμό είναι μια διαδικασία λήψης μιας συμβολοσειράς εισόδου αυθαίρετου μήκους και παραγωγής μιας κατακερματισμένης συμβολοσειράς σταθερού μήκους. Οποιαδήποτε αλλαγή στην εισαγωγή, θα έχει ως αποτέλεσμα ένα νέο, διαφορετικό κατακερματισμό.

package main import ( "crypto/sha256" "fmt" ) func main()  99896  

Δοκιμάστε το: //play.golang.org/p/FTPUa7IhOCE

Ο Andrej απαιτεί επίσης κάποιο επίπεδο ασφάλειας για τη βάση δεδομένων του, οπότε αποφασίζει για μια συνάρτηση Cryptographic Hash με τις ακόλουθες ιδιότητες:

  • είναι ντετερμινιστική - το ίδιο μήνυμα οδηγεί πάντα στον ίδιο κατακερματισμό
  • it is quick to compute the hash value for any given message
  • it is infeasible to generate a message from its hash value except by trying all possible messages
  • a small change to a message should change the hash value so extensively that the new hash value appears uncorrelated with the old hash value
  • it is infeasible to find two different messages with the same hash value

Implementing the DB Content Hashing

Saturday Evening, March 30.

Andrej modifies the Persist() function to return a new content hash, Snapshot, every time a new transaction is persisted.

type Snapshot [32]byte 

The Snapshot is produced by this new sha256 secure hashing function:

func (s *State) doSnapshot() error { // Re-read the whole file from the first byte _, err := s.dbFile.Seek(0, 0) if err != nil { return err } txsData, err := ioutil.ReadAll(s.dbFile) if err != nil { return err } s.snapshot = sha256.Sum256(txsData) return nil } 

The doSnapshot() is called by the modified Persist() function. When a new transaction is written into the tx.db file, the Persist() hashes the entire file content and returns its 32 bytes "fingerprint" hash.

From this moment, everyone can 100% confidently and securely refer to any particular database state (set of data) with a specific snapshot hash.

⚓Practice time

1/4 Run the tbb balances list cmd and check the balances are matching.

tbb balances list

Account balances at 7d4a360f465d... | id | name | balance | | -- | -------- | ------- | | 1 | Andrej | 999251 | | 2 | BabaYaga | 949 | | 3 | Caesar | 1000 |

2/4 Remove the last 2 rows from ./database/tx.db and check the balances again.

tbb balances list

Account balances at 841770dcd3... | id | name | balance | | -- | -------- | ------- | | 1 | Andrej | 999051 | | 2 | BabaYaga | 949 | | 3 | Caesar | 1000 | 

3/4 Reward Andrej for the last 2 days (from 28th to 30th of March):

Reward Transaction 1:

tbb tx add --from=andrej --to=andrej --value=100 --data=reward

Persisting new TX to disk: {"from":"andrej","to":"andrej","value":100,"data":"reward"} New DB Snapshot: ff2470c7043f5a34169b5dd38921ba6825b03b3facb83e426 TX successfully persisted to the ledger. 

Reward Transaction 2:

tbb tx add --from=andrej --to=andrej --value=100 --data=reward

Persisting new TX to disk: {"from":"andrej","to":"andrej","value":100,"data":"reward"} New DB Snapshot: 7d4a360f468b837b662816bcdc52c1869f99327d53ab4a9ca TX successfully persisted to the ledger. 

4/4 Run the tbb balances list cmd and ensure the balances and the snapshot hash is the same as at the beginning.

tbb balances list

Account balances at 7d4a360f465d... | id | name | balance | | -- | -------- | ------- | | 1 | Andrej | 999251 | | 2 | BabaYaga | 949 | | 3 | Caesar | 1000 | 

Done!

Because the cryptographic hash function sha256 produces the same output (given the same inputs (current tx.db and 2x tbb tx add)), if you follow the exact steps on your own computer, you will generate the exact same database state and hashes!

? Summary

Closed software with centralized access to private data puts only a few people to the position of power. Users don’t have a choice, and shareholders are in business to make money.

Blockchain developers aim to develop protocols where applications' entrepreneurs and users synergize in a transparent, auditable relation. Specifications of the blockchain system should be well defined from the beginning and only change if its users support it.

Blockchain is an immutable database. The token supply, initial user balances, and global blockchain settings you define in a Genesis file. The Genesis balances indicate what was the original blockchain state and are never updated afterwards.

The database state changes are called Transactions (TX). Transactions are old fashion Events representing actions within the system.

The database content is hashed by a secure cryptographic hash function. The blockchain participants use the resulted hash to reference a specific database state.

⚒ Study Code

Commit: b99e51

Next steps

You finished the first few chapters! Congratulations!

█▒▒▒▒▒▒▒▒▒ 10%

Αλλά αυτό ήταν απλά μια γρήγορη προθέρμανση. Το Blockchain είναι μια πολύ απαιτητική και εκτεταμένη τεχνολογία και θα χρειαστείτε ένα ολόκληρο βιβλίο που θα εξηγεί πώς να φτιάξετε το πλήρες σύστημα και όλα τα συστατικά του από το μηδέν - έτσι έγραψα ένα.

Μπορείτε να συνεχίσετε να διαβάζετε στο επόμενο δωρεάν κεφάλαιο στην έκδοση του ενημερωτικού δελτίου του "The Blockchain Way of Programming" eBook.

07 | Το μοντέλο προγραμματισμού Blockchain

  • Βελτίωση της απόδοσης ενός αμετάβλητου DB
  • Batch + Hash + Linked List ⇒ Μπλοκ
  • Μετεγκατάσταση από TX.db στο BLOCKS.db

Εκμάθηση: Επανασχεδιάζετε και αναδιαμορφώνετε τη βάση δεδομένων MVP σε αρχιτεκτονική blockchain.

Συνεχίστε στο σεμινάριο: //web3.coach#book

Ευχαριστώ για την ανάγνωση!