fcn从头开始_如何使用Go从头开始构建区块链

fcn从头开始

介绍 (Introduction)

With Web 3.0 and blockchain becoming more mainstream every day, do you know what blockchain is? Do you know its technical advantages and use-cases?

随着Web 3.0和区块链每天变得越来越主流,您知道什么是区块链吗? 您知道它的技术优势和用例吗?

The goal of this tutorial is to introduce blockchain technology from a technical perspective by building one from scratch.

本教程的目的是通过从头开始构建区块链技术,从技术角度介绍区块链技术。

Forget everything you've heard about blockchain from social media. Now, you will build a blockchain system from ground zero to really understand the ins and outs of this peer-to-peer, distributed technology.

忘记您从社交媒体上听到的有关区块链的所有信息。 现在,您将从零开始构建一个区块链系统,以真正了解这种对等分布式技术的来龙去脉。

Afterwards, make your own mind up about its future and advantages. Spoiler alert: you will fall in love with programming blockchain software.

然后,自己决定其未来和优势。 剧透警报:您将爱上编程区块链软件。

怎么样? (How?)

You will follow the story of a software developer who is looking to revolutionize his local bar by implementing blockchain technology for its payment system.

您将跟随一个软件开发人员的故事,该软件开发人员希望通过为其支付系统实施区块链技术来革新其本地律师事务所。

Although blockchain has several undeniable use-cases, at the moment, the number one application is payments. This is because banks are still running on an inefficient, 40 year old infrastructure powered by CSV files and FTP.

尽管区块链有多个不可否认的用例,但目前,排名第一的应用是支付。 这是因为银行仍在使用CSV文件和FTP的低效率,已有40年历史的基础架构上运行。

The story comes with a lot of fun and intriguing facts about the overall blockchain ecosystem and different protocols such as Bitcoin, Ethereum and XRP.

这个故事带来了关于整个区块链生态系统以及比特币,以太坊和XRP等不同协议的许多有趣有趣的事实。

您将在本教程中构建,学习和做什么? (What will you build, learn, and do in this tutorial?)

  • You'll setup a Go project on your local machine without any prior GoLang experience

    您将在没有任何GoLang经验的情况下在本地计算机上设置Go项目
  • You'll generate and distribute your first blockchain tokens

    您将生成并分发您的第一个区块链令牌
  • You'll develop a CLI controlled database in Go from scratch

    您将在Go中从头开始开发CLI控制的数据库
  • You'll find out how few rights users posses in their favourite apps

    您会发现在他们最喜欢的应用中,有多少位权限用户拥有
  • You'll discover the blockchain's main value proposition

    您会发现区块链的主要价值主张
  • You'll make your DB immutable using a secure cryptographic hash function

    您将使用安全的加密哈希函数使数据库不可变

So let's get started and jump into our story.

因此,让我们开始吧,进入我们的故事。

⭐认识主角安德烈(Andrej)。 (⭐ Meet the protagonist, Andrej.)

Andrej is a bar owner by night and a software developer by day in a small Slovakian town called Bardejov.

Andrej晚上在斯洛伐克的一个叫Bardejov的小镇里是酒吧的老板,白天是软件开发人员。

Andrej is tired of:

安德烈(Andrej)厌倦了:

  • Programming solid, old fashion PHP/Java/Javascript applications

    编程可靠的老式PHP / Java / Javascript应用程序

  • Forgetting how much money his friends and clients owe him for all the unpaid Friday night vodka shots

    忘记了他的朋友和客户欠他周五晚上所有未付的伏特加酒花多少钱
  • Spending time collecting and counting coins, returning change and generally touching COVID-19-exposed bank bills

    花费时间收集和计数硬币,退还找零钱并且通常接触COVID-19暴露的银行票据
  • Maintaining different plastic chips for table football, darts, billiard and poker

    维护用于桌上足球,Dart,台球和扑克的不同塑料芯片

Andrej would love to:

安德烈(Andrej)希望:

  • Have a perfect auditable history of the bar's activities and sales to make his bar compliant with tax regulations

    对酒吧的活动和销售有完善的可审计历史,以使其酒吧符合税收法规

  • Transform his bar into an autonomous, payment-efficient, decentralized and safe environment his customers can trust and profit from

    将他的律师事务所转变为客户可以信任并从中获利的自治,付款高效,去中心化和安全的环境

His goal is to write a simple program and keep all the balances of his clients in virtual form.

他的目标是编写一个简单的程序,并以虚拟形式保留其客户的所有余额。

Andrej shares his thoughts here:

安德烈(Andrej)在这里分享他的想法:

"Every new customer will give me cash, and I will credit them an equivalent amount of my digital tokens (coins/cryptocurrency). The tokens will represent a monetary unit within and outside the bar.

“每个新客户都会给我现金, 我会把他们等值的我的数字代币(硬币/加密货币)记入贷方。代币将代表条形图内外的货币单位。

The users will use the tokens for all bar functionalities from paying for drinks, borrowing and lending them to their friends, and playing table tennis, poker and kicker.

用户将把令牌用于所有酒吧功能,包括支付酒水,将其借贷给朋友,打乒乓球,玩扑克和踢球。

Having a bar powered by blockchain tokens will generate tons of value for my customers. Contrary to my competition and other bars on this street, where the customers only spend money and get a hangover in exchange, my bar customers holding bar's tokens will have shareholders rights.

拥有由区块链令牌驱动的酒吧将为我的客户带来大量价值。 与我在这条街上的竞争对手和其他酒吧相反,那里的顾客只花钱并得到宿醉作为交换, 我持有酒吧代币的酒吧顾客将拥有股东权利。

Similar to owning a large portion of stocks in a company like Apple or Microsoft, the customers holding these bar tokens will be able to decide how the bar will operate by voting and deciding on:

与在Apple或Microsoft这样的公司中拥有大量股票类似,持有这些条形码令牌的客户将能够通过投票并决定以下内容来决定条形码的运作方式:

  • drinks prices

    饮料价格
  • opening hours

    营业时间
  • new features (TV, Jukebox...)

    新功能(电视,自动点唱机...)
  • interior and exterior design

    室内和外部设计
  • profits allocation

    利润分配
  • etc.

    等等

Oh, this will be a programming dream!

哦,这将是一个编程梦想!

I will call the tokens: The Blockchain Bar tokens, TBB!"

我将这些代币称为:区块链酒吧代币, TBB!

Now that Andrej has shared his dream, we'll get started.

现在,安德烈(Andrej)分享了他的梦想,我们将开始。

目录 (Table of Contents)

要求 (Requirements)

Let's dive into our tutorial. I recommend 2+ years of programming experience in Java/PHP/Javascript, or another language similar to Go.

让我们深入研究我们的教程。 我推荐2年以上Java / PHP / Javascript或类似于Go的语言的编程经验。

If you want to get a good quick intro to go, here's a free course that'll get you started.

如果您想快速入门, 这里有一个免费课程 ,可以帮助您入门。

You can also complete the official 17 lectures of A Tour Of Go to get familiar with the language syntax and basic concepts (~20 mins).

您也可以完成A Tour Of Go的 17场官方讲座,以熟悉语言语法和基本概念(约20分钟)。

为什么去? (Why Go?)

Because like blockchain, it's a fantastic technology for your overall programming career. Go is a trendy language and Go devs are better paid than the average Java/PHP/Javascript positions.

因为像区块链一样,这对于您的整体编程职业来说是一种了不起的技术。 Go是一种流行的语言,Go开发人员的薪水比平均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.

Go针对多核CPU架构进行了优化。 您可以生成数千个轻量级线程(Go例程)而不会出现问题。 对于高度并行和并发的软件(例如区块链网络),这是极其实用的。

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编写软件,您可以立即获得接近C ++的性能,而不会因为忘记释放内存而丧生。

Go also compiles to binary which makes it very portable.

Go还可以编译为二进制文件,这使其非常易于移植。

设置项目 (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.

本文具有专用的开源Github存储库,其中包含完整的源代码,因此您可以编译代码并在自己的本地计算机上运行程序。

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!

如果您陷入任何一章或特定的代码行中,请在此存储库中创建一个描述您的问题的Github问题,我会尽快帮助您!

↓ Visit the Github repository and follow the installation instructions ↓

↓访问Github存储库并按照安装说明进行操作↓

01 | MVP数据库 (01 | The MVP Database)

git checkout c1_genesis_json

git checkout c1_genesis_json

Andrej mastered relational SQL databases in the 90s. He knows how to make advanced data models and how to optimize the SQL queries.

Andrej在90年代掌握了关系SQL数据库。 他知道如何制作高级数据模型以及如何优化SQL查询。

It's time for Andrej to catch up with innovation and start building Web 3.0 software.

现在是Andrej赶上创新并开始构建Web 3.0软件的时候了。

Luckily, after reading "The Lean Startup" book last week, Andrej feels like he shouldn't over-engineer the solution just yet. Hence, he chooses a simple but effective JSON file for the bar's MVP database.

幸运的是,安德烈(Andrej)在上周阅读了《精益创业》(The Lean Startup)一书后,觉得他现在还不应该过度设计解决方案。 因此,他为酒吧的MVP数据库选择了一个简单但有效的JSON文件。

In the beginning, there was a primitive centralized database.

最初,有一个原始的集中式数据库。

📌总结 (📌 Summary)

Blockchain is a database.

区块链是一个数据库。

用户1,Andrej (User 1, Andrej)

Monday, March 18.

3月18日,星期一

Andrej generates 1M utility tokens.

Andrej生成1M实用程序令牌。

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.

每个区块链都有一个“ Genesis”文件。 Genesis文件用于将第一个令牌分发给早期的区块链参与者。

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

这一切都始于一个简单的虚拟的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:

Andrej创建文件./database/genesis.json ,他在其中定义Blockchain Bar的数据库将具有1M令牌,并且所有令牌都属于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)必须遵守法律法规(SEC)。 发行未注册的安全性是非法的。 另一方面,实用程序令牌很好,因此他立即在酒吧的门上打印并粘贴了新的定价白色p̶a̶p̶e̶r̶海报。

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

安德烈(Andrej)为代币分配初始货币价值,以便他可以将其兑换为欧元,美元或其他法定货币。

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.

Andrej还决定, 他每天应该获得100个令牌,以维护数据库并拥有如此出色的破坏性想法。

💡有趣的事实 (💡Fun Facts)

The first genesis Ether (ETH) on Ethereum blockchain was created and distributed to early investors and developers in the same way as Andrej's utility token.
以太坊区块链上的第一个起源以太(ETH)是以与Andrej的效用代币相同的方式创建并分发给早期投资者和开发商的。
In 2017, during an ICO (initial coin offerings) boom on the Ethereum blockchain network, project founders wrote and presented whitepapers to investors. A whitepaper is a technical document outlining a complex issue and possible solution, meant to educate and elucidate a particular matter. In the world of blockchains, a white paper serves to outline the specifications of how that particular blockchain will look and behave once it is developed.
2017年,在以太坊区块链网络上的ICO(初始代币发行)热潮期间,项目创始人撰写并向投资者介绍了白皮书。 白皮书是一份技术文档,概述了一个复杂的问题和可能的解决方案,旨在教育和阐明特定问题。 在区块链领域,白皮书概述了该特定区块链一旦开发后将如何表现和行为的规范。

Blockchain projects raised between €10M to €300M per whitepaper idea.

区块链项目为每个白皮书构想筹集了1000万至3亿欧元。

in exchange for money (the ICO "funding"), investor names  would be included in the initial "genesis balances", similar to how Andrej did it. Investors' hopes through an ICO are the genesis coins go up in value and that the teams deliver the outlined blockchain.
为了换钱(ICO“资金”),投资者名称将包括在初始“创始余额”中,这与Andrej的做法类似。 投资者通过ICO寄予的希望是,创世币的价值有所增加,并且团队可以提供概述的区块链。
Naturally, not all whitepaper ideas come to fruition. Massive investments lost to unclear or incomplete ideas are why blockchain received negative coverage in the media throughout these ICOs, and why some still considered it a hype. But the underlying blockchain technology is fantastic and useful, as you will learn further in this book. It's just been abused by some bad actors.
自然,并非所有白皮书的想法都能实现。 由于不清楚或不完整的想法而损失的大量投资是为什么区块链在整个ICO中受到媒体的负面报道,以及为什么有些人仍将其视为炒作。 但是底层的区块链技术是神奇而有用的,因为您将在本书中进一步学习。 它只是被一些坏演员滥用。

📌总结 (📌 Summary)

Blockchain is a database.

区块链是一个数据库。

The token supply, initial user balances, and global blockchain settings you define in a Genesis file.

您在Genesis文件中定义的令牌供应,初始用户余额和全局区块链设置。

02 | 突变全球数据库状态 (02 | Mutating Global DB State)

git checkout c2_db_changes_txt

git checkout c2_db_changes_txt

死党 (Dead Party)

Monday, March 25.

3月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)为自己订购了三杯伏特加酒,并将数据库更改写在纸上:

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.

为了避免重新计算每个客户余额的最新状态,Andrej创建了一个./database/state.json文件,以汇总格式存储了余额。

New DB state:

新的数据库状态:

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

BabaYaga的奖励 (Bonus for BabaYaga)

Tuesday, March 26.

3月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.

为了将流量带入他的酒吧,Andrej宣布了在接下来的24小时内向购买TBB代币的每个人提供100%的独家奖励。

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.

! 他得到了第一个客户BabaYaga 。 BabaYaga预购了价值1000欧元的代币,为了庆祝,她立即花了1汤匙TBB喝了伏特加。 她有饮酒问题。

DB transactions written on a piece of paper:

DB事务写在纸上:

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 (initial coin offerings based on whitepapers) projects often distribute the genesis tokens with different bonuses, depending on how many of them you buy and how early you do it. Teams offer, on average, 10-40% bonuses to early "participants".
区块链ICO(基于白皮书的初始代币发行)项目通常会分配具有不同奖励的创世代币,具体取决于您购买了多少代币以及您有多早完成了代币。 团队平均为早期的“参与者”提供10-40%的奖金。
The word "investor" is avoided, so law regulators won't consider the tokens as a security. Projects would reason their main product, blockchain tokens, function as "flying, loyalty points."
避免使用“投资者”这个词,因此法律监管机构不会将代币视为证券。 项目会推论其主要产品区块链令牌的作用是“飞行,忠诚度积分”。
The "participants" later made even 1000% on their investment selling to the public through an exchange several months later.
几个月后,“参与者”甚至通过交易所向公众出售其投资的1000%。

📌总结 (📌Summary)

Blockchain is a database.

区块链是一个数据库。

The token supply, initial user balances, and global blockchain settings you define in a Genesis file.

您在Genesis文件中定义的令牌供应,初始用户余额和全局区块链设置。

The Genesis balances indicate what was the original blockchain state and are never updated afterwards.

创世余额表明最初的区块链状态是什么,以后再也不会更新。

The database state changes are called Transactions (TX).

数据库状态更改称为事务(TX)。

03 | 整体事件与交易 (03 | Monolithic Event vs Transaction)

git checkout c3_state_blockchain_component

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)编程 (Andrej Programming)

Tuesday evening, March 26.

3月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.

这对安德烈(Andrej)来说是个轻松的星期二晚上。 为了庆祝他的第一个客户,他决定玩一些《 星际争霸》,并通过删除一些旧照片来清理自己的本地开发机器。

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

不幸的是,他在终端sudo rm -rf /键入删除命令路径时过早按下Enter键。 哎呀。

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

他的所有文件,包括酒吧的genesis.jsonstate.json都不见了。

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

作为高级开发人员的安德烈(Andrej)反复大声喊了几句f *字,但他并没有惊慌!

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.

他对基于事件的体系结构的优势印象深刻,因此决定扩展其MVP数据库解决方案。 每个酒吧的活动,例如个人饮料购买,都必须记录在区块链数据库中。

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.

每个事务 (TX-数据库更改)将具有以下四个属性: 从,到,值数据

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

具有一个可能值( 奖励 )的数据属性捕获了安德烈(Andrej)发明区块链的奖金,并人为地增加了初始TBB代币的总供应量(通货膨胀)。

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数据库将保留为JSON文件:

{
  "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:

所有以前写在纸上的交易都将存储在一个名为tx.db的本地文本文件数据库中,该数据库以JSON格式序列化并以换行符分隔:

{"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:

封装所有业务逻辑的最关键的数据库组件将是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.

State结构将了解所有用户余额以及谁将TBB令牌转让给了谁,以及转让了多少。

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

通过从genesis.json文件中读取初始用户余额来genesis.json

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:

然后,通过顺序重播tx.db所有数据库事件来更新创始State余额:

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:

State部门负责:

  • Adding new transactions to Mempool

    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:

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
}

构建命令行界面(CLI) (Building a Command-Line-Interface (CLI))

Tuesday evening, March 26.

3月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.

Andrej希望有一种方便的方法将新交易添加到他的数据库并列出其客户的最新余额。 由于Go程序会编译为二进制文件,因此他会为其程序构建一个CLI。

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

在Go中开发基于CLI的程序的最简单方法是使用第三方github.com/spf13/cobra库。

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

Andrej为其项目初始化Go的内置依赖项管理器,称为go modules

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

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

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.

Go modules命令将自动获取您在Go文件中引用的任何库。

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

Andrej创建了一个新目录: cmd和一个子目录tbb

mkdir -p ./cmd/tbb

mkdir -p ./cmd/tbb

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

在其中,他创建了一个main.go文件,用作该程序的CLI入口点:

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程序使用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.

Go将检测缺少的库并在编译程序之前自动获取它们。 根据您的$GOPATH ,结果程序将保存在$GOPATH/bin文件夹中。

echo $GOPATH

echo $GOPATH

/home/web3coach/go

which tbb

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.

您现在可以从终端运行tbb ,但由于main.go文件中的Run函数为空,因此它不会执行任何操作。

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

Andrej首先需要的是对其tbb CLI程序的版本控制。

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

main.go文件旁边,他创建了version.go命令:

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

编译并运行它:✍ go install ./cmd/tbb/... tbb version

Version: 0.1.0-beta TX Add && Balances List

Version: 0.1.0-beta TX Add && Balances List

Perfect.

完善。

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

version.go文件相同,他创建了balances.go文件:

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:

balances命令将负责加载最新的数据库状态并将其打印到标准输出:

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.

Andrej验证cmd是否按预期工作。 由于tx.db文件仍然为空,因此应打印在Genesis文件中定义的确切余额。

go install ./cmd/tbb/...

go install ./cmd/tbb/...

tbb balances list

tbb balances list

Accounts balances:
__________________
andrej: 1000000

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

效果很好! 现在,他只需要一个cmd即可记录酒吧的活动。

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

Andrej创建./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:

tbb tx add cmd使用State.Add(tx)函数将栏的事件持久化到文件系统中:

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.

tbb tx add cmd具有3个强制性标志: --from --to ,-- --to--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!

CLI已完成!

Andrej migrates all transactions from paper to his new DB:

Andrej将所有交易从纸本迁移到他的新数据库:

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

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

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

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

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

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

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

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

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

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

Read all TXs from disk and calculate the latest state:

从磁盘读取所有TX,并计算最新状态:

tbb balances list

tbb balances list

Accounts balances:
__________________
andrej: 998801
babayaga: 1999

Bar data successfully restored! Phew, what a night!

条数据成功恢复! ew,真是个晚上!

关于Cobra CLI库 (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.

关于Cobra lib进行CLI编程的好处是它附带的其他功能。 例如,您现在可以运行: tbb help cmd,它将打印出所有TBB注册的子命令以及有关如何使用它们的说明。

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)

Accidentally losing customers' data is a standard Saturday in the corporate world these days. Blockchain fixes this by decentralizing the data storage.
这些天,意外丢失客户数据是企业界的一个标准星期六。 区块链通过分散数据存储来解决此问题。

The trick Andrej baked into the program by skipping balance verification for TXs marked as rewards. Bitcoin and Ethereum work in the same way. The balance of the Account who mined a block increases out of the blue as a subject of total tokens supply inflation affecting the whole chain. The total supply of bitcoins is capped at 21M BTC. You will learn more about "mining" and "blocks" in chapters 7 and 10.

安德烈(Andrej)通过跳过标记为奖励的TX的余额验证来进入程序。 比特币和以太坊以相同的方式工作。 开采区块的账户余额突然增加,这是总代币供应膨胀影响整个链条的主题。 比特币的总供应量上限为2100万比特币。 您将在第7章和第10章中了解有关“采矿”和“障碍物”的更多信息。

The components State and Mempool are not unique to this program. Andrej chose the names and designs to match a simplified go-Ethereum, model so you have a glance inside the core Ethereum source code.

StateMempool组件不是此程序唯一的。 Andrej选择了名称和设计来匹配简化的以太坊模型,因此您可以一窥以太坊核心源代码。

📌总结 (📌 Summary)

Blockchain is a database.

区块链是一个数据库。

The token supply, initial user balances, and global blockchain settings are defined in a Genesis file.

代币供应,初始用户余额和全局区块链设置在Genesis文件中定义。

The Genesis balances indicate what the original blockchain state was and are never updated afterwards.

创世余额表明最初的区块链状态是什么,以后再也不会更新。

The database state changes are called Transactions (TX).

数据库状态更改称为事务(TX)。

Transactions are old fashion Events representing actions within the system.

事务是老式的事件,代表系统内的动作。

⚒学习代码 (⚒ Study Code)

Commit: 5d4b0b

提交: 5d4b0b

Let's talk about greed.

让我们谈谈贪婪。

04 | 人类贪婪 (04 | Humans Are Greedy)

git checkout c4_caesar_transfer

git checkout c4_caesar_transfer

典型的商业贪婪 (Typical business greediness)

Wednesday, March 27.

3月27日,星期三。

BabaYaga invested a bit too much. She forgot her flat rent payment was around the corner, and she doesn't have the money. BabaYaga calls her flat owner, Caesar.

BabaYaga投入了太多。 她忘记了即将支付的固定租金,而且她没有钱。 BabaYaga打电话给她的单位老板凯撒(Caesar)。

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

BabaYaga:凯撒,很抱歉,但我没有现金支付您本月的租金…

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!

BabaYaga:区块链酒吧ICO提供了巨大的奖金,我以1000欧元的价格购买了价值2000欧元的代币。 真是太好了!

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?

凯撒:你到底在说什么? 什么是ICO? 代币到底是什么? 你可以用其他方式付我钱吗?

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!

BabaYaga:哦,不再。 我可以给您1000枚价值1000欧元的TBB代币,您可以在酒吧使用它们来购买饮品! 让我打电话给酒吧老板安德烈(Andrej),进行转让!

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.

安德烈(Andrej)进行了转让, 但决定为自己的麻烦收取额外的50枚TBB代币。 他不想,但几年前投资他的律师大股东却强迫他尽快创造利润。

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

无论如何,BabaYaga最有可能不会注意到这笔相对较小的费用,Andrej告诉自己。 最后,只有他具有数据库访问权限。

// Rent payment

//租金支付

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

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

// hidden fee charge

//隐藏费用

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

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

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

💡有趣的事实 (💡Fun Facts)

The number one blockchain use-case is banking. Many blockchain projects aim to optimize the domestic and international exchange of money across different currency corridors (XRP).
区块链的第一个用例是银行业务。 许多区块链项目旨在优化跨不同货币通道(XRP)的国内和国际货币交换。
Other projects focus on freedom and self-sovereign identity (SSI) - a digital movement that recognizes an individual should own and control their identity and money without the intervening administrative authorities or other centralized intermediaries. SSI allows people to interact in the digital world with the same freedom and capacity for trust as they do in the offline world. (Bitcoin / Ethereum)
其他项目则侧重于自由和自我主权(SSI)-一种数字运动,它认识到个人应拥有并控制自己的身份和金钱,而无需干预行政当局或其他中央中介机构。 SSI允许人们在数字世界中以与离线世界相同的自由度和信任度进行交互。 (比特币/以太坊)
Here are few fun facts why blockchain is a perfect fit for replacing your bank's current banking infrastructure.
以下是一些有趣的事实,为什么区块链非常适合替代您银行现有的银行基础设施。
The good thing about virtual tokens is their fungibility - i.e., their ability to be traded, with each unit being as usable as the next. Performing a transfer from account to account can be done by simply changing the database state. Cryptocurrencies are tradeable 24/7.
虚拟代币的优点在于它们的可替代性-即它们的交易能力,每个单位都可以使用下一个单位。 只需更改数据库状态即可完成帐户之间的转移。 加密货币可以24/7交易。
You can't trade stocks directly. You need to go through a broker who takes part a percentage of the total transaction as a fee (1-3% to 7% average yearly profit).
您不能直接交易股票。 您需要经过一个经纪人,该经纪人作为费用收取总交易额的一部分(平均年利润的1-3%至7%)。

An international bank transfer takes between 3-10 business days and can cost as much 5% of the transferred value! If you’re sending $10,000, you may have to pay up to $500. The technology behind for the last 40 years? FTP + CSV files.

国际银行转账需要3到10个工作日,并且可能要花费转账金额的5%! 如果您要汇款$ 10,000,则可能最多需要支付$ 500。 过去40年中落后的技术? FTP + CSV文件。

Do you think the stock market is fair? Banks, indexes, and stocks are highly centralized and controlled by governments and private Wall Street groups. Free market? Wall Street controls how much can prices jump/fall in a single day.
您认为股市公平吗? 银行,指数和股票高度集中,并由政府和华尔街私人集团控制。 自由市场? 华尔街控制价格在一天之内可以上涨/下跌多少。
As an example, Wall Street halted the trading of "S&P 500 Index" after a 7% drop to protect their investors and hedge funds from losing money from people selling their stocks during March 2020 after COVID news. Afterward, the FED printed trillions of dollars for themselves to support the stock price. If you are a developer who likes to save money and avoid debt, your savings just lost value overnight by a yet unknown percentage.
例如,华尔街在下跌7%之后停止了“标准普尔500指数”的交易,以保护其投资者和对冲基金避免在2020年3月COVID消息传出后抛售股票的人蒙受损失。 后来,美联储自己印制了数万亿美元来支撑股价。 如果您是喜欢节省金钱并避免债务的开发人员,那么您的储蓄在一夜之间损失了价值,但未知的百分比。
Many countries are going into negative yields, an unexplored territory with unknown consequences. What does this mean? Soon you will have to pay the bank to keep your savings. Inflation at its best. You are being forced to spend your money to support a system you don't control.
许多国家正处于负收益状态,这是一个尚未开发的领域,后果不明。 这是什么意思? 很快,您将不得不向银行付款以保留您的积蓄。 通货膨胀处于最佳状态。 您被迫花钱支持不受控制的系统。

⚒学习代码 (⚒ Study Code)

Commit: 00d6ed

提交: 00d6ed

05 | 为什么我们需要区块链 (05 | Why We Need Blockchain)

git checkout c5_broken_trust

git checkout c5_broken_trust

BabaYaga寻求正义 (BabaYaga Seeks Justice)

Thursday, March 28.

3月28日,星期四。

BabaYaga enters the bar for her birthday.

BabaYaga生日那天进入酒吧。

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

BabaYaga:嗨,安德烈! 今天是我的生日! 给我你最贵的瓶子!

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.

安德烈:生日快乐! 在这里,您去了:水晶头伏特加酒。 但是您需要另外购买一个TBB令牌。 该瓶子的价格为950个令牌,您的余额为949。

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

BabaYaga:什么?! 我的余额应该是999 TBB!

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

安德烈(Andrej):您上周向凯撒(Caesar)进行的资金转帐花费了您50个令牌。

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!

BabaYaga:这是不可接受的! 我永远不会同意这么高的费用。 你不能做到这一点,安德烈(Andrej)。 我信任您的系统,但是您和其他企业主一样不可靠。 事情必须改变!

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?

BabaYaga:嗯,听起来确实不错,但这是否可能?

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

安德烈:是的,我是这样认为的。 带有一些散列,链表,不变的数据结构,分布式复制和非对称密码!

BabaYaga: I have no idea what you have just said but go and do your geeky thing, Andrej!

BabaYaga:我不知道你刚才说了什么,但是去做你的怪异事,Andrej!

💡有趣的事实 (💡Fun Facts)

Bitcoin and Ethereum miners also receive rewards every ~15 minutes for running the blockchain servers (nodes) and validating transactions.
比特币和以太坊矿工还通过运行区块链服务器(节点)和验证交易每15分钟获得奖励。
Every 15 minutes, one Bitcoin miner receives 12.5 BTC ($100k at the moment of writing this page) to cover his servers cost + make some profit.
每15分钟,一名比特币矿工获得12.5 BTC(在撰写此页面时为10万美元)以支付他的服务器成本+获利。
The Bitcoin network consumes as much electricity as the entire country of Austria. It accounts for 0.29% of the world's annual electricity consumption.
比特币网络消耗的电量与整个奥地利国家一样多。 它占世界年度用电量的0.29%。

Annually it consumes 76.84 TWh, producing 36.50 Mt CO2 carbon footprint (New Zealand). Source.

每年消耗76.84 TWh,产生36.50 Mt的二氧化碳足迹(新西兰)。 资源。

Why? You will learn more later (in Chapter 11) where you will program a Bitcoin mining algorithm from scratch!
为什么? 您将在后面的第11章中了解更多信息,从头开始编写比特币挖掘算法!
PS: Our algorithm will consume a bit less electricity :)
PS:我们的算法将消耗更少的电量:)

📌总结 (📌 Summary)

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.

区块链是一个数据库。 代币供应,初始用户余额和全局区块链设置在Genesis文件中定义。 创世余额表明最初的区块链状态是什么,以后再也不会更新。

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

数据库状态更改称为事务(TX)。 事务是老式的事件,代表系统内的动作。

⚒学习代码 (⚒ Study Code)

Commit: 642045

提交: 642045

06 | 不可改变的哈希 (06 | L'Hash de Immutable)

git checkout c6_immutable_hash

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.

3月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.

如果Andrej想弄清楚如何编写一个不变的DB,他必须意识到为什么其他数据库系统在设计上是可变的。

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

他决定分析一个全能MySQL数据库表:

| 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:

在MySQL DB中,具有访问权限并有充分理由的任何人都可以执行表更新,例如:

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.

跨表更新值是可能的,因为表行是独立的,可变的,并且最新状态不明显。

What’s the latest DB change? Last column changed? Last row inserted? If so, how can Andrej know what row was deleted recently? If the rows and table state were tightly coupled, dependent, a.k.a, updating row 1 would generate a completely new, different table, Andrej would achieve his immutability.

最新的数据库更改是什么? 最后一栏改变了? 最后插入行? 如果是这样,Andrej如何知道最近删除了哪一行? 如果行和表的状态紧密耦合,相互依赖(也称为更新),则更新第1行将生成一个全新的不同表,Andrej将实现其不变性。

How can you tell if any byte in a database has changed?
您如何判断数据库中的任何字节是否已更改?

通过哈希函数实现不变性 (Immutability via Hash Functions)

Hashing is process of taking a string input of arbitrary length and producing a hash string of fixed length. Any change in input, will result in a new, different hash.

散列是获取任意长度的字符串输入并生成固定长度的散列字符串的过程。 输入的任何更改都将导致新的不同哈希值。

package main

import (
	"crypto/sha256"
	"fmt"
)

func main() {
	balancesHash := sha256.Sum256([]byte("| 1 | Andrej | 99895 |"))
	fmt.Printf("%x\n", balancesHash)
	// Output: 6a04bd8e2...f70a3902374f21e089ae7cc3b200751
	
	// Change balance from 99895 -> 99896
	
	balancesHashDiff := sha256.Sum256([]byte("| 1 | Andrej | 99896 |"))
	fmt.Printf("%x\n", balancesHashDiff)
	// Output: d04279207...ec6d280f6c7b3e2285758030292d5e1
}

Try it: https://play.golang.org/p/FTPUa7IhOCE

尝试一下: https : //play.golang.org/p/FTPUa7IhOCE

Andrej also requires some level of security for his database, so he decides for a Cryptographic Hash Function with the following properties:

Andrej还要求其数据库具有某种程度的安全性,因此他决定使用具有以下属性的加密散列函数

  • it is deterministic - the same message always results in the same 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.

3月30日,星期六晚上。

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

每当新事务持久化时,Andrej都会修改Persist()函数以返回新的内容哈希Snapshot

type Snapshot [32]byte

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

Snapshot由此新的sha256 secure hashing函数生成:

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.

doSnapshot()由修改后的Persist()函数调用。 当将新事务写入tx.db文件时, Persist()将对整个文件内容进行哈希处理并返回其32个字节的“指纹”哈希值。

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

从这一刻起,每个人都可以100%自信和安全地使用特定的快照哈希引用任何特定的数据库状态(数据集)。

⚓实践时间 (⚓Practice time)

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

1/4运行tbb balances list cmd并检查余额是否匹配。

tbb balances list

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.

2/4./database/tx.db删除最后2行, ./database/tx.db再次检查余额。

tbb balances list

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

最后2天(3月28日至30日)的3/4奖励安德烈:

Reward Transaction 1:

奖励交易1:

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

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:

奖励交易2:

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

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.

4/4运行tbb balances list cmd,并确保余额和快照哈希与开头相同。

tbb balances list

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!

因为加密散列函数sha256产生相同的输出(给定相同的输入(当前tx.db和2x tbb tx add )),所以如果您在自己的计算机上执行确切的步骤,则将生成完全相同的数据库状态和哈希!

📌总结 (📌 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.

区块链是一个不变的数据库。 您在Genesis文件中定义的令牌供应,初始用户余额和全局区块链设置。 创世余额表明最初的区块链状态是什么,以后再也不会更新。

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

数据库状态更改称为事务(TX)。 事务是老式的事件,代表系统内的动作。

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

提交: b99e51

下一步 (Next steps)

You finished the first few chapters! Congratulations!

您完成了前几章! 恭喜你!

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

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

But this was just a quick warm-up. Blockchain is a very challenging and extensive technology, and you would need an entire book explaining how to build the full system and all of its components from scratch - so I wrote one.

但这只是一个快速的热身。 区块链是一项非常具有挑战性和广泛性的技术,您需要整本书来解释如何从头开始构建完整的系统及其所有组件-所以我写了一本。

You can continue reading in the next free chapter in my newsletter version of "The Blockchain Way of Programming" eBook.

您可以继续在我的通讯版本“ The Blockchain Way of Programming”电子书的下一个免费章节中继续阅读。

07 | The Blockchain Programming Model

07 | 区块链编程模型

  • Improving Performance of an Immutable DB

    提高不可变数据库的性能
  • Batch + Hash + Linked List ⇒ Blocks

    批处理+哈希+链接列表⇒块
  • Migrating from TX.db to BLOCKS.db

    从TX.db迁移到BLOCKS.db

Learning: You redesign and refactor your MVP database into a blockchain architecture.

学习:您将MVP数据库重新设计和重构为区块链架构。

继续本教程: https://web3.coach#book (Continue in the tutorial: https://web3.coach#book)

Thanks for reading!

谢谢阅读!

翻译自: https://www.freecodecamp.org/news/build-a-blockchain-in-golang-from-scratch/

fcn从头开始

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值