区块链+golang学习日志12月10日
1. 查看变量类型和变量所占字节数
import (
"fmt"
"unsafe"
)
func main(){
var i int32 = 100
fmt.Printf("i的类型= %T,i所占的字节=%d", i, unsafe.Sizeof(i))
}
2.字符串
1)golang的字符串是由单个字节byte组成的,字符的格式化输出fmt.Printf("%c", c)。
2)若采用fmt.Println(" “)直接输出的是对应字符的码值,若该字符码值不在0-255的范围内,即单个byte所能表示的范围,则会出现溢出,此时应将字符声明里的数据类型改为int即可。
3)字符所对应的码值输出fmt.Printf(”%d", c)
func main(){
var (
c1 byte = '5'
c2 byte = 'g'
)
//用fmt.Println直接输出的是对应字符的码值
fmt.Println("c1=", c1, "c2=", c2)
//要输出对应字符,需要采用格式化输出fmt.Printf
fmt.Printf("c1= %c, c2= %c\n", c1, c2)
//若overflow溢出,则将数据类型改为int保存
var c3 int = '北'
fmt.Printf("c3= %c\n", c3)
//汉字三字节,直接指定一个码值,格式化输出其字符
var c4 = 26354
fmt.Printf("c4=%c\n",c4)
//字符类型是可以进行运算的,运算按码值进行运算
var n1 = 10 + 'a'
fmt.Println("n1=",n1)
}
3.布尔类型
bool类型只允许取true和false,占一个字节,适用于逻辑运算。bool值的格式化输出用%t
func main(){
var b = false
fmt.Println("b=",b)
fmt.Println("b占用的空间=",unsafe.Sizeof(b))
//同上句--fmt.Printf("b=%d",unsafe.Sizeof(b))
}
4.string类型
即一串固定长度的字符序列,采用UTF-8编码标识的Unicode文本,属于不可变类型,即字符串一旦赋值后,该字符串后面就不能修改了。
字符串的两种表示形式:
1)双引号表示:会识别转义字符
2)反引号表示:以字符串的原生形式输出,包括换行和特殊字符,可以实现防攻击、输出源码等效果
func main(){
var address string = "北京长城 2823 hello world"
fmt.Println("address=",address)
fmt.Println(address)//直接输出,不加双引号
var str1 = ` var address string = "北京长城 2823 hello world"
fmt.Println("address=",address)
fmt.Println(address)//直接输出,不加双引号`
fmt.Println(str1)
//字符串拼接方式
var (
str2 = "shuaige"
str3 = "meinv"
)
str4 := str2 + str3 //两种方式都行
var str5 = "shuaige" + "meinv"
fmt.Println(str4)
fmt.Println(str5)
//当一串字符过长需要换行处理时+号应保留在上一行
}
5.基本数据类型的默认值
整型和浮点型的默认值时0,字符串的默认值时空串,布尔类型的默认值是false
格式化输出中,按其原始值输出用的是%v,fmt.Printf("%v", x),即输入什么就直接输出什么。
6.基本类型转string类型
1)方式1:str = fmt.Sprintf("%参数",表达式)
2)方式2:使用strconv函数
var (
n1 int = 99
n2 float64 = 37.23141
b bool = true
c byte = 'f'
str1 string
)
str1 = fmt.Sprintf("%d",n1)
fmt.Printf("str1 type= %T str= %v\n",str1,str1)
str1 = fmt.Sprintf("%f",n2)
fmt.Printf("str1 type= %T str= %v\n",str1,str1)
str1 = fmt.Sprintf("%t",b)
fmt.Printf("str1 type= %T str= %v\n",str1,str1)
str1 = fmt.Sprintf("%c",c)
fmt.Printf("str1 type= %T str= %v\n",str1,str1)
str1 = strconv.FormatInt(int64(n1),10)
fmt.Printf("str1 type= %T str= %q\n",str1,str1)
str1 = strconv.FormatFloat(n2, 'f', 10, 64)
fmt.Printf("str1 type= %T str= %q\n",str1,str1)
str1 = strconv.FormatBool(b)
fmt.Printf("str1 type= %T str= %q\n",str1,str1)
str1 = strconv.Itoa(int(c))
fmt.Printf("str1 type= %T str= %q\n",str1,str1)
7.string类型转基本数据类型
区块链——比特币的数据结构
比特币采用的数据结构主要是哈希指针和默克尔树
Block Chain is a linked list using hash pointers
1.哈希指针
普通指针存放的是结构体的起始位置,而哈希指针不但要存储结构体的起始位置还要存储结构体的哈希值,此哈希值可检测内容是否被篡改。
举例一个简易区块链,从创世区块到最近产生区块,链接方向是从最近使用区块指向创世区块,除创世区块没有哈希值以外,其后的每一个区块都包含上一个区块及其哈希值整体计算得来的哈希值,最近使用区块作为整条区块链的末端将哈希值保存到本地。
通过此种数据结构可以实现tamper-evident log,即防篡改,在区块链上任意一处篡改都会牵一发而动全身,因为在区块链中任意一处发生篡改都会相继导致后边区块的哈希值发生改变,最终导致最后一个节点的哈希值也因此改变,和本地保存的哈希值不一样,说明被篡改。
2.merkle tree
merkle tree的好处:只需要记住根节点的哈希值,就可以检测树中任意部位是否发生了篡改。
merkle tree是一颗类满二叉树形式的树,其叶节点为data blocks即数据块,每个数据块都是一种交易–transaction,每两个叶节点分别计算得出该数据块的哈希值,从下至上,从叶结点依次到根节点,两两一组,得到根节点的哈希值。如下图所示:
merkle tree 的作用:
1) 提供merkle proof
2) 保存block header 和block body
merkle proof:从交易数据块到根节点的路径
而比特币中,每个区块分为两部分
1)block header:包含根哈希值,没有交易具体内容
2)block body:包含交易列表
比特币中的节点又分为
1)全节点(full node):包含block header 和block body
2)轻节点(light node):只含有 block header(某些手机中的比特币钱包使用)
问题:怎么通过轻节点终端证明某个交易是否包含于区块链中
答:通过merkle proof
merkle tree中由于使用了哈希函数,使得整棵树具有哈希函数的优良性质,比如collision resistance和hiding,均有助于区块链防篡改。
问题:证明merkle tree中不含某交易,即proof of non-membership
答:
1)方式1,遍历整棵merkle tree,复杂度为O(n)
2)方式2,将merkle tree所有叶节点的哈希值排序,在求出目标交易的哈希值,对跟目标交易哈希值响铃邻的两个交易块向上取哈希,直到root hash并验证此哈希值和本地保存的是否一样,若一样,则这两个交易块是相邻的,目标交易块本应出现在其中间,但没有,故不存在。