区块链基础入门

1. 区块链定义 区块链技术本质上是一个去中心化的数据库,它是比特币的核心技术与基础架构,是分布式数据存储、点对点传输、共识机制、加密算法等计算机技术的新型应用模式。狭义来讲,区块链是一种按照时间顺序将数据区块以顺序相连的方式组合成的一种链式数据结构,并以密码学方式保证的不可篡改、不可伪造的分布式账本。广义来讲,区块链技术是利用块链式数据结构来验证与存储数据、利用分布式节点共识算法来生成和更新数据、利用密码学方式保证数据传输和访问的安全、利用由自动化脚本代码组成的智能合约来编程和操作数据的一种全新的分布式基础架构与计算范式。 1.1 区块链的技术特征 区块链上存储的数据需由全网节点共同维护,可以在缺乏信任的节点之间有效地传递价值。相比现有的数据库技术,区块链具有以下技术特征。 块链式数据结构 区块链利用块链式数据结构来验证和存储数据,通过上文对区块链基本概念的介绍可以知道,每个区块打包记录了一段时间内发生的交易是对当前账本的一次共识,并且通过记录上一个区块的哈希值进行关联,从而形成块链式的数据结构。 分布式共识算法 区块链系统利用分布式共识算法来生成和更新数据,从技术层面杜绝了非法篡改数据的可能性,从而取代了传统应用中保证信任和交易安全的第三方中介机构,降低了为维护信用而造成的时间成本、人力成本和资源耗用 密码学方式 区块链系统利用密码学的方式保证数据传输和访问的安全。存储在区块链上的交易信息是公开的,但账户的身份信息是高度加密的。区块链系统集成了对称加密、非对称加密及哈希算法的优点,并使用数字签名技术来保证交易的安全。 1.2 区块链的功能特征 区块链系统的以上技术特征决定了其应用具有如下功能特征。 多中心 不同于传统应用的中心化数据管理,区块链网络中有多个机构进行相互监督并实时对账,从而避免了单一记账人造假的可能性,提高了数据的安全性。 自动化 区块链系统中的智能合约是可以自动化执行一些预先定义好的规则和条款的一段计算机程序代码,它大大提高了经济活动与契约的自动化程度。 可信任 存储在区块链上的交易记录和其他数据是不可篡改并且可溯源的,所以能够很好地解决各方不信任的问题,无需第三方可信中介。 2. 区块链的相关概念 区块链以密码学的方式维护一份不可篡改和不可伪造的分布式账本,并通过基于协商一致的规范和协议(共识机制)解决了去中心化的记账系统的一致性问题,其相关概念主要包括以下三个。 交易(Transaction) 区块链上每一次导致区块状态变化的操作都称为交易,每一次交易对应唯一的交易哈希值,一段时间后便会对交易进行打包。 区块(Block) 打包记录一段时间内发生的交易和状态结果,是对当前账本的一次共识。每个区块以一个相对平稳的时间间隔加入到链上,在企业级区块链平台中,共识时间可以动态设置。 链(Chain) 区块按照时间顺序串联起来,通过每个区块记录上一个区块的哈希值关联,是整个状态改变的日志记录。 区块链的主要结构 如何解决交易中的信任和安全问题 区块链技术体系不是通过一个权威的中心化机构来保证交易的可信和安全,而是通过加密和分布式共识机制来解决信任和安全问题,其主要技术创新有以下4点。 分布式账本 交易是由分布式系统中的多个节点共同记录的。每一个节点都记录完整的交易记录,因此它们都可以参与监督交易合法性并验证交易的有效性。不同于传统的中心化技术方案,区块链中没有任何一个节点有权限单独记录交易,从而避免了因单一记账人或节点被控制而造假的可能性。另一方面,由于全网节点参与记录,理论上讲,除非所有的节点都被破坏,否则交易记录就不会丢失,从而保证了数据的安全性。 加密技术和授权技术 区块链技术很好地集成了当前对称加密、非对称加密和哈希算法的许多优点,并使用了数字签名技术来保证交易的安全性,其中最具代表性的是使用椭圆曲线加密算法生成用户的公私钥对和使用椭圆曲线数字签名算法来保证交易安全。打包在区块上的交易信息对于参与共识的所有节点是公开的,但是账户的身份信息是经过严格加密的。 共识机制 共识机制是区块链系统中各个节点达成一致的策略和方法。区块链的共识机制替代了传统应用中保证信任和交易安全的第三方中心机构,能够降低由于各方不信任而产生的第三方信用成本、时间成本和资本耗用。常用的共识机制主要有PoW、PoS、DPoS、Paxos、PBFT等,共识机制既是数据写入的方式,也是防止篡改的手段。 智能合约 智能合约是可以自动化执行预先定义规则的一段计算机程序代码,它自己就是一个系统参与者。它能够实现价值的存储、传递、控制和管理,为基于区块链的应用提供了创新性的解决方案。 3. 区块链分类 按照节点参与方式的不同,区块链技术可以分为:公有链(Public Blockchain)、联盟链(Consortium Blockchain)和私有链(Private Blockchain)。按照权限的不同,区块链技术可以分为:许可链(Permissioned Blockchain)和非许可链(Permissionless Blockchain)。前述的三大类区块链技术中,联盟链和私有链属于许可链,公有链属于非许可链。...

April 17, 2021 · 1 min · 李昌

Go中的锁

1. sync.Mutex互斥锁 不同goroutine之间对公共资源进行访问需要使用互斥锁。例如在对银行账户的操作中,如果我们有两种操作,一个是查询余额,一个是存款。其操作如下: package bank // 存款余额 var balance int // 存款 func Deposit(amount int) { balance = balance + amount } // 查询 func Balance() int { return balance } // Alice: go func() { bank.Deposit(200) // A1 fmt.Println("=", bank.Balance()) // A2 }() // Bob: go bank.Deposit(100) // B 这其中,若把A1分为两个操作,A1r:把余额从内存中读出来;A2w:把修改后的余额写入内存。 若执行顺序为A1r → B → A1w → A2, 正常情况下,Alice和Bob分别存入了$200,$100,因此最后的存款应该是300,但最后输出结果为200。因为A在计算时是按照A1r读出的数值进行计算,忽略了B的操作,A与B之间发生了数据竞争。 数据竞争:无论任何时候,只要有两个goroutine并发访问同一变量,且至少其中的一个是写操作的时候就会发生数据竞争。 解决此问题的办法之一是使用互斥锁。 import "sync" var ( mu sync.Mutex // guards balance balance int ) func Deposit(amount int) { mu....

April 14, 2021 · 1 min · 李昌

面试题golang

三个goroutine分别输出张三、李四、王五,使其按上述顺序输出5遍。 package main import ( "fmt" "sync" ) var w sync.WaitGroup func main() { w.Add(15) chan1 := make(chan struct{}, 0) chan2 := make(chan struct{}, 0) for i := 0; i < 5; i++ { go func() { defer w.Done() fmt.Println("张三") chan1 <- struct{}{} }() go func() { defer w.Done() <- chan1 fmt.Println("李四") chan2 <- struct{}{} }() go func() { defer w.Done() <- chan2 fmt.Println("王五") }() } w.Wait() } 编写程序输出某目录下的所有文件(包括子目录) package main import ( "fmt" "io/ioutil" "os" ) func main() { dir := os....

April 14, 2021 · 1 min · 李昌

wsgi

转载自:https://segmentfault.com/a/1190000011365430 1. WSGI介绍 1.1 什么是WSGI 首先介绍几个关于WSGI相关的概念 WSGI:全称是Web Server Gateway Interface,WSGI不是服务器,python 模块,框架,API或者任何软件,只是一种规范,描述web server如何与web application通信的规范。server和application的规范在PEP 3333中有具体描述。要实现WSGI协议,必须同时实现web server和web application,当前运行在WSGI协议之上的web框架有Torando,Flask,Django uwsgi:与WSGI一样是一种通信协议,是uWSGI服务器的独占协议,用于定义传输信息的类型(type of information),每一个uwsgi packet前4byte为传输信息类型的描述,与WSGI协议是两种东西,据说该协议是fcgi协议的10倍快。 uWSGI:是一个web服务器,实现了WSGI协议、uwsgi协议、http协议等。 WSGI协议主要包括server和application两部分: WSGI server负责从客户端接收请求,将request转发给application,将application返回的response返回给客户端; WSGI application接收由server转发的request,处理请求,并将处理结果返回给server。application中可以包括多个栈式的中间件(middlewares),这些中间件需要同时实现server与application,因此可以在WSGI服务器与WSGI应用之间起调节作用:对服务器来说,中间件扮演应用程序,对应用程序来说,中间件扮演服务器。 WSGI协议其实是定义了一种server与application解耦的规范,即可以有多个实现WSGI server的服务器,也可以有多个实现WSGI application的框架,那么就可以选择任意的server和applicatiodn组合实现自己的web应用。例如uWSGI和Gunicorn都是实现了WSGI server协议的服务器,Django,Flask是实现了WSGI application协议的web框架,可以根据项目实际情况搭配使用。 以上介绍了相关的常识,接下来我们来看看如何简单实现WSGI协议。 1.2 怎么实现WSGI 上文说过,实现WSGI协议必须要有wsgi server和application,因此,我们就来实现这两个东西。 我们来看看官方WSGI使用WSGI的wsgiref模块实现的小demo def demo_app(environ,start_response): from StringIO import StringIO stdout = StringIO() print >>stdout, "Hello world!" print >>stdout h = environ.items(); h.sort() for k,v in h: print >>stdout, k,'=', repr(v) start_response("200 OK", [('Content-Type','text/plain')]) return [stdout....

April 9, 2021 · 3 min · 李昌

ORM简介

1. ORM是什么 面向对象编程把所有实体看成对象(object),关系型数据库则是采用实体之间的关系(relation)连接数据。很早就有人提出,关系也可以用对象表达,这样的话,就能使用面向对象编程,来操作关系型数据库。 简单的说,ORM 就是通过实例对象的语法,完成关系型数据库的操作的技术,是"对象-关系映射"(Object/Relational Mapping) 的缩写。 ORM把数据库映射为对象 数据库的表(table) –> 类(class) 记录(record,行数据)–> 对象(object) 字段(field)–> 对象的属性(attribute) 举例来说,下面是一行SQL语句 SELECT id, first_name, last_name, phone, birth_date, sex FROM persons WHERE id = 10 程序直接运行SQL,操作数据库的写法如下: res = db.execSql(sql) name = res[0]["FIRST_NAME"] 改成ORM的写法如下: p = Person.get(10) name = p.first_name 一比较就可以发现,ORM 使用对象,封装了数据库操作,因此可以不碰 SQL 语言。开发者只使用面向对象编程,与数据对象直接交互,不用关心底层数据库。 总结起来,ORM有如下优点: 数据模型都在一个地方定义,更容易更新和维护,也利于重用代码。 ORM 有现成的工具,很多功能都可以自动完成,比如数据消毒、预处理、事务等等。 它迫使你使用 MVC 架构,ORM 就是天然的 Model,最终使代码更清晰。 基于 ORM 的业务代码比较简单,代码量少,语义性好,容易理解。 你不必编写性能不佳的 SQL。 但是ORM也有很突出的缺点: ORM 库不是轻量级工具,需要花很多精力学习和设置。 对于复杂的查询,ORM 要么是无法表达,要么是性能不如原生的 SQL。 ORM 抽象掉了数据库层,开发者无法了解底层的数据库操作,也无法定制一些特殊的 SQL。 2....

April 6, 2021 · 2 min · 李昌

Ubuntu18(WSL2)安装redis

1. 安装并对redis进行配置 更新源并安装redis sudo apt-get update sudo apt-get install redis-server 将redis设置为systemctl sudo vim /etc/redis/redis.conf 找到supervised选项,设置为systemd # If you run Redis from upstart or systemd, Redis can interact with your # supervision tree. Options: # supervised no - no supervision interaction # supervised upstart - signal upstart by putting Redis into SIGSTOP mode # supervised systemd - signal systemd by writing READY=1 to $NOTIFY_SOCKET # supervised auto - detect upstart or systemd method based on # UPSTART_JOB or NOTIFY_SOCKET environment variables # Note: these supervision methods only signal "process is ready....

April 4, 2021 · 2 min · 李昌

多出几个通用非即插即用显示器

1. 问题现象 莫名其妙,多出来几个显示器。 从设备管理器中看,也是存在多个通用非即插即用显示器2. 解决办法 重新安装Intel显卡驱动,可以从电脑厂家官网下载。但需要注意的一点是:在重新安装显卡驱动后,需要禁用显卡驱动程序的自动更新,否则还有可能出现这个问题。 打开组策略gpedit.msc,选择计算机配置”->“管理模板”->“系统”->“设备安装”->“设备安装限制”,找到Intel显卡的类Guid添加到阻止使用与下列设备安装程序类相匹配的驱动程序安装设备中

April 4, 2021 · 1 min · 李昌

slice和数组的区别

1. 长度 数组 对于数组来说,它的长度是固定的,并且数组的长度是其类型的一部分,即对于以下两个数组来说,他们是不同的类型。 var a [5]int var b [6]int fmt.Printf("%v", reflect.TypeOf(a) == reflect.TypeOf(b)) // 输出: false 数组的长度必须是常量表达式,因为数组的长度需要在编译阶段确定。 对于数组来说,由于其长度是固定的,因此不能添加或删除元素。 切片 而对于切片,其长度是不固定的,不同长度的切片,只要其元素类型相同,则它们就是相同的切片类型。 a := make([]int, 5) b := make([]int, 6) fmt.Printf("%v\n", reflect.TypeOf(a) == reflect.TypeOf(b)) // 输出: true 如果切片操作超出cap(s)的上限将导致一个panic异常,但是超出len(s)则是意味着扩展了 slice,因为新slice的长度会变大: months := [...]string{1: "January", /* ... */, 12: "December"} summer := months[6:9] fmt.Println(summer[:20]) // panic: out of range endlessSummer := summer[:5] // extend a slice (within capacity) fmt.Println(endlessSummer) // "[June July August September October]" 2....

March 30, 2021 · 2 min · 李昌

Reader和Writer接口

1. Reader接口 type Reader interface { Read(p []byte) (n int, err error) } 接口说明 Read 将 len(p) 个字节读取到 p 中。它返回读取的字节数 n(0 <= n <= len(p)) 以及任何遇到的错误。即使 Read 返回的 n < len(p),它也会在调用过程中占用 len(p) 个字节作为暂存空间。若可读取的数据不到 len(p) 个字节,Read 会返回可用数据,而不是等待更多数据。 当 Read 在成功读取 n > 0 个字节后遇到一个错误或 EOF (end-of-file),它会返回读取的字节数。它可能会同时在本次的调用中返回一个non-nil错误,或在下一次的调用中返回这个错误(且 n 为 0)。 一般情况下, Reader会返回一个非0字节数n, 若 n = len(p) 个字节从输入源的结尾处由 Read 返回,Read可能返回 err == EOF 或者 err == nil。并且之后的 Read() 都应该返回 (n:0, err:EOF)。...

March 28, 2021 · 1 min · 李昌

goroutine和线程

1. 线程 在操作系统中,进程是分配资源的基本单位,但当进程作为调度的基本单位时,会造成较大的开销,频繁的进程调度将消耗大量时间。因此引出了线程:线程是处理器调度的基本单位,线程只拥有很小的运行时必要的资源。一个进程可拥有多个线程,同一个进程中的所有线程共享进程获得的主存空间和资源。 线程的实现 有些系统同时支持用户线程和内核线程,由此产生了不同的多线程模型,即实现用户级线程 和内核级线程的连接方式:多对一模型、一对一模型、多对多模型。 2. goroutine 在Go语言中,每一个并发的执行单元叫作一个goroutine,是一种轻量级的线程。 3. 线程与goroutine的区别 运行时栈的大小 每个系统级线程都会有一个固定大小的栈(一般为2MB),主要用于保存函数递归调用时参数和局部变量。这造成了两个问题: 对于某些需要很小的栈空间的线程来说是一个巨大的浪费 对于少数需要巨大栈空间的线程来说又面临栈溢出的风险 goroutine会以一个很小的栈启动(2KB或4KB),当遇到深度递归时导致当前栈空间不足,会根据需要动态的伸缩栈的大小。 调度 go的运行时还包括了其自己的调度器,可以在n个操作系统线程上多工调度m个goroutine(类似于多线程模型中的多对多模型)。 go调度器的工作和内核的调度时相似的,但是这个调度器只关注单独的go程序中的goroutine。 goroutinie采用的是半抢占式的协作调度,只有当当前goroutine发生阻塞时才会导致调度。 这种调度发生在用户态,调度器会根据具体函数只保存必要的寄存器,切换的代价比系统线程要低得多。 创建和销毁 Thread 创建和销毀都会有巨大的消耗,因为要和操作系统打交道,是内核级的,通常解决的办法就是线程池。- goroutine 因为是由 Go runtime 负责管理的,创建和销毁的消耗非常小,是用户级。

March 27, 2021 · 1 min · 李昌