所有由chen发布的文章

Git 小技巧(一)

最近换笔记本,重新配置工作环境后发现,当windows提交完git之后,虚拟机中git status会出现大量的文件变更,反之也是如此。

git diff 后发现, 内容完全没有变更,只是权限发生变化。

解决方案就是设置git忽略文件属性就可以了

golang标准库 —— strconv包

strconv包为我们提供的方法可以分校几类:

  • Append类
  • Format类
  • Parse类
  • Quote类
  • 其他

Append类

将各种类型转换为字符串后追加到 dst 尾部。

示例:

将各种类型转换为带引号字符串后追加到 dst 尾部。

示例:

Format类

Format类的方法主要是格式化对应类型的值,然后返回字符串

示例:

Parse类

这些类型的方法提供了转换类型的功能,一般都会返回第二个返回值错误类型

示例:

Quote类

示例:

其他

对基础方法的再封装

将整数转换为十进制字符串形式(即:FormatInt(i, 10) 的简写)

将字符串转换为十进制整数(即: ParseInt(s, 10, 0) 的简写)

示例

判断字符串是否可以不被修改的表示为一个单行的反引号字符串。
字符串中不能含有控制字符(除了 \t)和“反引号”字符,否则返回 false

示例:

判断 r 是否为可打印字符

示例:

转载参考:https://blog.csdn.net/wangshubo1989/article/details/75222002

golang标准库 —— errors包

error 接口

Go语言引入了一个关于错误处理的标准模式,即error接口,该接口定义:

对于大多数函数,如果要返回错误,大致可以定义为如下模式,将error作为多种返回值中的最后一个,但这并非是强制要求:

通过errors下的New方法可以创建一个错误:

error 源码分析

errors/errors.go下定义了errorString,并且让其实现了Error方法。

所以New方法创建的errorString是一个error类型。

实现自己的错误类型

使用Truffle部署智能合约

简介

Truffle是一个世界级的开发环境,测试框架,以太坊的资源管理通道,致力于让以太坊上的开发变得简单,Truffle有以下:

  • 内置的智能合约编译,链接,部署和二进制文件的管理。

  • 快速开发下的自动合约测试。

  • 脚本化的,可扩展的部署与发布框架。

  • 部署到不管多少的公网或私网的网络环境管理功能

  • 使用EthPM&NPM提供的包管理,使用ERC190标准。

  • 与合约直接通信的直接交互控制台(写完合约就可以命令行里验证了)。

  • 可配的构建流程,支持紧密集成。

  • 在Truffle环境里支持执行外部的脚本。

安装Truffle

nodejs版本5.0以上。如果中断报错就多试几次吧。

构建一个Truffle项目

安装完truffle之后,我们使用官方的案例来走一遍流程。

创建项目目录:

使用官方安装官方metacoin示例,

安装完成后目录:

测试项目

编译智能合约

编译成功后项目目录下会多出一个build的目录,保存编译文件。

发布合约到本地环境

首先启动geth

启动成功后,我们开启开启挖矿。因为发布合约需要旷工挖矿才能生效。

truffle迁移合约

在迁移之前我们需要先编写我们的配置文件,主要设置网络配置。

设置网络环境为development,并且配置对应的ip:port

设置好配置之后,我们尽心迁移

此时我们已经将合约发布到我们本地的私有链上去了。

与智能合约交互

使用控制台通过下面的方式进行交互:

  • 查看账户余额

  • 看看有多少以太合适(并注意合约定义1个metacoin价值2以太)

  • 从一个账号转账到另一个账号

  • 检查是否收到metacoin

  • 检查给别人转账的账户

注意:

  1. MetaCoin 的合约地址如下:

  1. 配置文件中的network_id: "*"表示匹配所有网络。

  2. 配置文件中需要填写gasgasPrice的设置,否者迁移的时候会报错。

报错信息如下:

  1. 迁移的时候主账户必须解锁,否则会报错帐号未解锁。

搭建自己的Hello World

创建项目目录,

初始化项目

编写合约hello world

编写迁移文件

编译合约

设置配置文件

迁移合约

合约地址为

进入truffle的控制台,并且调用方法输出hello world

golang标准库 —— container包

container包实现了三个复杂的数据结构:堆(heap),链表(list),环(ring)

链表-List

List结构体为链表本身,Element结构体是链表下的每一个元素。

Element

Element 结构体包含上一个元素和下一个元素的指针指向,所属List的指向,以及当前Element的值。

Element 提供了两个方法,获取上一个元素和下一个元素。

List

List本身包含了root Element主节点以及链表的长度。

创建一个List

创建List时,会进行初始化将root的上下节点都指向root本身。

回过头来我们会发现Element获取上下元素时会判断,下一个或者上一个元素是否root本身,如果是这回返回nil

List操作抽象

链表的操作我们都可以抽象为insertremove

insert,在指定节点插入某个节点。

  • 将上一个节点的next指向插入节点,将下一个节点的的prev指向插入节点
  • 将插入节点的next指向下一个节点,将插入节点的的prev指向上一个节点
  • 列表长度++, 插入节点指向list

remove, 操作起来就更简单了,直接将上下两个节点互指就可以了,然后放置内存泄漏清空删除节点的指向关系。

有了insertremove两个操作以后,我们可以扩展衍生到所有操作。在这里找几个比较典型的例子来说,

  • 移动至最前端:先将指定节点移除,然后将节点插入到root节点后

  • 移动至最后个节点:将节点移除,然后插入到root节点的上一个几点。

我们可以套用l.insert(l.remove(e), &Element{}),然后将节点移动到任意各节点去。

环-Ring

结构体Ring指的是环上的节点。相比于List它并没有元素与结构之分。Ring首位相连,形成一个环。

New

创建一个拥有10各节点的环。

Link & Unlink

Link将两个环相连,原理与链表的插入类似。

  • 将环A的尾与环B的头相连
  • 将环A的头与环B的尾相连

Unlink移除环中的某一段。

这里它的使用了一个技巧,先用Move方法获取第N+1个节点,然后将该节点传入Link方法,是第一个节点与第第N+1个节点相连,那么第2个节点到第N个节点就被删除了。

Do

循环ring操作。

堆-heap

heap下只有interface,并没有struct的实现,所以需要我们去实现。

heap.Interface嵌套了sort.Interface,所以我们一共需要实现5个方法,

我们自定义一个IntHeap,然后让其完成heap的一系列操作。

在定义好结构体,以及实现接口之后,我们对其进行操作,发现IntHeap自动实现了最小堆的功能。

为什么会这样呢?

主要因为heap中有两个函数up上浮和down下沉。

当我们操作heap的时候,会根据情况自动调用updown方法,完成最小堆的排序。

updown方法中,调用了我们实现的LessSwap方法取做相关操作。

参考:

  • https://books.studygolang.com/The-Golang-Standard-Library-by-Example/chapter03/03.3.html
  • https://ieevee.com/tech/2018/01/29/go-heap.html

加密传输的一些知识点

提供端到端的加密方案有:

  • 网络层加密
  • 传输层加密
  • 应用层加密

在网络安全加密方案的比较中,最安全的方案一定是暴露用户信息最少的,换句话说:加密的越多,越安全!

所以对底层的网络层加密最安全,最山梗的应用加密层加密最不安全。

网络层加密(IPsec)加密了除IP之外的所有层,包括TCP/UDP及以上,加密用户信息最多。

传输层加密(TLS)加密了除IP/TCP/UDP之外,所有应用层数据,包括 HTTP/FTP/SMTP,加密内容次之

应用层加密,只是加密应用层里敏感的信息,如密码,以及其它需要加密保护的内容,那IP/TCP/HTTP内容都明文暴露在外,加密内容最少。

毫无疑问网络层加密是最安全的,但是IPsec需要预先配置,甚至安装客户端软件,严重影响了它的普及层度。

而基于TLS的安全加密如https,几乎不需要任何预先配置。只要浏览器拥有Root CA证书,或者二级RA签发证书,然后加密是自动进行的,无需用户任何干预。

IPsecTLS的认证加密由一下组成:

1.认证对端合法性(Authentication)

  • Pre-shared Password
  • PKI

2.密钥交换算法(Key Exchange)

  • RSA
  • ECDH

3.加密算法(Encryption)

  • AES
  • 3DES

4.MAC校验算法(Integrity)

  • MD5
  • SHA-1

5.放重放共计(Anti-Replay)

  • 一般使用序列号(Sequence Number)来杜绝重放攻击

虽然上面的方案已趋近于完美,但还是存在最薄弱的环节,认证对方合法性(中间人欺骗)。

如果客户端和服务端都是私有实现的,比如说统一公司开发的后端和前端APP,可以使用下面方案解决。

使用预共享秘钥生成 敏感数据加密 + MAC,将数据HTTP封装,然后由TLS加密,这样即使中间人欺骗,也无法解密应用层加密数据。

参考:https://www.zhihu.com/question/52790301

Solidity 基础知识

一个简单的例子

创建和编译智能合约

这个例子主要讲解如何发布、执行智能合约

vim testContract.sol编辑一个sol文件,主要功能是取两个值的乘积。

首先获取EVM的二进制编码

再获取智能合约的 JSON ABI(Application Binary Interface),其中指定了合约接口,包括可调用的合约方法、变量、事件等:

启动区块链,然后这2个值保存在变量中。

需要注意的是,二进制编码前面需要添加0x前缀:

具体操作如下,

部署智能合约

首先需要解锁自己的账户

发送部署合约的交易:

此时如果没有挖矿,用 txpool.status 命令可以看到本地交易池中有一个待确认的交易。使用下面的命令查看当前待确认的交易:

智能合约调用

使用以下命令发送交易,sendTransaction 方法的前几个参数应该与合约中 multiply 方法的输入参数对应。这种情况下,交易会通过挖矿记录到区块链中:

如果只是本地运行该方法查看返回结果,可以采用如下方式:

搭建remix浏览器

安装

推荐使用 npm 或者 cnpm 直接安装。使用 git clone 源代码然后npm install会有很多报错情况。

启动

启动后,会监听127.0.0.1:8080,访问该网址就可以了。如果使用虚拟机无法访问改地址,使用nginx转发请求就可以了。

或者直接修改/usr/local/bin/remix-ide 文件

共享目录

启动的时候添加参数路径即可,如下

如果说需要非本地访问需要修改源码2处:

1、修改websocket监听ip: 127.0.0.1 => 0.0.0.0

2、修改访问websocket地址,修改成外网本地ip地址。

这两处修改后,启动服务。点击共享图标,就可以看到文件目录下有localhost文件夹,为共享目录下的文件。

Solidity语法

基础类型

Solidity是一种静态类型语言,Solidity类型分为两类:

  • 值类型(Value Type) – 变量在赋值或传参时,总是进行值拷贝。
  • 引用类型(Reference Types)

值类型包含:

  • 布尔 booleans
  • 整形 intergers
  • 定长浮点 fixed point numbers
  • 定长字节数组 fixed-size byte arrays
  • 有理数和整型常量 retional and integer literals
  • 字符串常量 string literals
  • 十六进制常量 hexadecimal literals
  • 枚举 enums
  • 函数类型 function types
  • 地址类型 address
  • 地址常量 address literals

引用类型包含:

  • 数组 arrays
  • 结构体 struct
整型

int/uint: 表示有符号和无符号不同为数整数。支持关键字uint8 到 uint256 (以8步进),uint 和 int 默认对应的是 uint256 和 int256。

说明:

  • 整数除法总是截断的,但如果运算符是字面量(字面量稍后讲),则不会截断。
  • 整数除0会抛异常。
  • 移位运算的结果的正负取决于操作符左边的数。x << y 和 x^2y 是相等, x >> y 和 x / 2y 是相等的。
  • 不能进行负移位,即操作符右边的数不可以为负数,否则会抛出运行时异常。

注意:Solidity中,右移位是和除等价的,因此右移位一个负数,向下取整时会为0,而不像其他语言里为无限负小数。

定长字节数组(Fixed-size byte arrays)

关键字有:bytes1, bytes2, bytes3, …, bytes32。(以步长1递增)
byte代表bytes1。

枚举(Enums)

在Solidity中,枚举可以用来自定义类型。它可以显示的转换与整数进行转换,但不能进行隐式转换。显示的转换会在运行时检查数值范围,如果不匹配,将会引起异常。枚举类型应至少有一名成员。

地址类型

地址类型address是一个值类型,

地址: 20字节(一个以太坊地址的长度),地址类型也有成员,地址是所有合约的基础

地址类型的成员

  • balance 属性及transfer() 函数

balance用来查询账户余额,transfer()用来发送以太币(以wei为单位)。

注解:如果x是合约地址,合约的回退函数(fallback 函数)会随transfer调用一起执行(这个是EVM特性),如果因gas耗光或其他原因失败,转移交易会还原并且合约会抛异常停止。

关于回退函数(fallback 函数),简单来说它是合约中无函数名函数,下面代码事例中,进进一步讲解回退函数(fallback) 的使用。

  • send() 函数

send 与transfer对应,但更底层。如果执行失败,transfer不会因异常停止,而send会返回false。

警告:send() 执行有一些风险:如果调用栈的深度超过1024或gas耗光,交易都会失败。因此,为了保证安全,必须检查send的返回值,如果交易失败,会回退以太币。如果用transfer会更好。

  • call(), callcode() 和 delegatecall() 函数

为了和非ABI协议的合约进行交互,可以使用call() 函数, 它用来向另一个合约发送原始数据,支持任何类型任意数量的参数,每个参数会按规则(ABI协议)打包成32字节并一一拼接到一起。一个例外是:如果第一个参数恰好4个字节,在这种情况下,会被认为根据ABI协议定义的函数器指定的函数签名而直接使用。如果仅想发送消息体,需要避免第一个参数是4个字节。

地址常量(Address Literals)

一个能通过地址合法性检查(address checksum test)十六进制常量就会被认为是地址,如0xdCad3a6d3569DF655070DEd06cb7A1b2Ccd1D3AF。而不能通过地址合法性检查的39到41位长的十六进制常量,会提示一个警告,被视为普通的有理数常量。

函数类型

函数类型定义如下:

  • 如果函数不需要返回,则省去returns ()
  • internal函数只能在当前合约内被调用(在当前的代码块内,包括内部库函数,和继承的函数中)。
  • external函数由地址和函数方法签名两部分组成,可作为外部函数调用的参数,或返回值。
  • public函数任何用户或者合约都能调用和访问。与external区别,external不能被内部调用。
  • private函数,只能在其所在的合约中调用和访问,即使是其子合约也没有权限访问。与internal区别,不能再集成合约中调用。
  • 函数类型默认是internal, 因此internal可以省去。合约中函数本身默认是public的。
  • 有两个方式访问函数,一种是直接用函数名f, 一种是this.f, 前者用于内部函数,后者用于外部函数。

成员: 属性 selector

public (或 external) 函数有一个特殊的成员selector, 它对应一个ABI 函数选择器。

函数可见性分析

  • public – 任意访问
  • private – 仅当前合约内
  • internal – 仅当前合约及所继承的合约
  • external – 仅外部访问(在内部也只能用外部访问方式访问)

数据位置

引用类型是一个复杂类型,占用的空间通常超过256位, 拷贝时开销很大,因此我们需要考虑将它们存储在什么位置,

  • 是memory(内存中,数据不是永久存在)
  • 还是storage(永久存储在区块链中)
  • 还有一个存储位置是:calldata,效果与memory差不多。
memory

函数参数(包含返回的参数)默认是memory。

storage

局部复杂类型变量(local variables)和 状态变量(state variables) 默认是storage。

calldata

用来存储函数参数,是只读的,不会永久存储的一个数据位置。外部函数的参数(不包括返回参数)被强制指定为calldata。效果与memory差不多。

  • 在memory和storage之间或与状态变量之间相互赋值,总是会创建一个完全独立的拷贝。
  • 将一个storage的状态变量,赋值给一个storage的局部变量,是通过引用传递。所以对于局部变量的修改,同时修改关联的状态变量。
  • 将一个memory的引用类型赋值给另一个memory的引用,不会创建拷贝(即:memory之间是引用传递)。

注意:

  • 不能将memory赋值给局部变量。
  • 对于值类型,总是会进行拷贝。

总结
强制的数据位置(Forced data location)

  • 外部函数(External function)的参数(不包括返回参数)强制为:calldata
  • 状态变量(State variables)强制为: storage

默认数据位置(Default data location)

  • 函数参数及返回参数:memory
  • 复杂类型的局部变量:storage

关于栈(stack)

EVM是一个基于栈的语言,栈实际是在内存(memory)的一个数据结构,每个栈元素占为256位,栈最大长度为1024。
值类型的局部变量是存储在栈上。

不同存储的消耗(gas消耗)
– storage 会永久保存合约状态变量,开销最大
– memory 仅保存临时变量,函数调用之后释放,开销很小
– stack 保存很小的局部变量,几乎免费使用,但有数量限制。

数组

一个元素类型为T,固定长度为k的数组,可以声明为T[k],而一个动态大小(变长)的数组则声明为T[]。

bytes和string是一种特殊的数组。bytes类似byte[],但在外部函数作为参数调用中,bytes会进行压缩打包。string类似bytes,但不提供长度和按序号的访问方式(目前)。
所以应该尽量使用bytes而不是byte[]。

创建内存数组

可使用new关键字创建一个memory的数组。与stroage数组不同的是,你不能通过.length的长度来修改数组大小属性。我们来看看下面的例子:

成员

ength属性

数组有一个.length属性,表示当前的数组长度。storage的变长数组,可以通过给.length赋值调整数组长度。memory的变长数组不支持。
不能通过访问超出当前数组的长度的方式,来自动实现改变数组长度。memory数组虽然可以通过参数,灵活指定大小,但一旦创建,大小不可调整。

**push方法*

storage的变长数组和bytes都有一个push方法(string没有),用于附加新元素到数据末端,返回值为新的长度。

限制情况

当前在external函数中,不能使用多维数组。

另外,基于EVM的限制,不能通过外部函数返回动态的内容。

结构体

Solidity提供struct来定义自定义类型,自定义的类型是引用类型。

不能声明一个struct同时将自身struct作为成员,这个限制是基于结构体的大小必须是有限的。

映射

映射类型,一种键值对的映射关系存储结构。定义方式为mapping(_KeyType => _KeyValue)。键类型允许除映射、变长数组、合约、枚举、结构体外的几乎所有类型()。值类型没有任何限制,可以为任何类型包括映射类型。

映射并未提供迭代输出的方法,可以自行实现一个这样的数据结构。

货币单位(Ether Units)

一个数字常量(字面量)后面跟随一个后缀wei, finney,szabo或ether,这个后缀就是货币单位。不同的单位可以转换。不含任何后缀的默认单位是wei。

插曲:以太币单位其实是密码学家的名字,是以太坊创始人为了纪念他们在数字货币的领域的贡献。他们分别是:
wei: Wei Dai 戴伟 密码学家 ,发表 B-money
finney: Hal Finney 芬尼 密码学家、工作量证明机制(POW)提出
szabo: Nick Szabo 尼克萨博 密码学家、智能合约的提出者

时间单位(Time Units)

时间单位: seconds, minutes, hours, days, weeks, years均可做为后缀,并进行相互转换,规则如下:

使用这些单位进行日期计算需要特别小心,因为不是每年都是365天,且并不是每天都有24小时,因为还有闰秒。由于无法预测闰秒,必须由外部的预言(oracle)来更新从而得到一个精确的日历库。

错误处理

Solidity处理错误和我们常见的语言不一样,Solidity是通过回退状态的方式来处理错误。发生异常时会撤消当前调用(及其所有子调用)所改变的状态,同时给调用者返回一个错误标识。注意捕捉异常是不可能的,因此没有try … catch…

为什么Solidity处理错误要这样设计呢?

我们可以把区块链理解为是全球共享的分布式事务性数据库。全球共享意味着参与这个网络的每一个人都可以读写其中的记录。如果想修改这个数据库中的内容,就必须创建一个事务,事务意味着要做的修改(假如我们想同时修改两个值)只能被完全的应用或者一点都没有进行。
学习过数据库的同学,应该理解事务的含义,如果你对事务一词不是很理解,建议你搜索一下“数据库事务“。
Solidity错误处理就是要保证每次调用都是事务性的。

Solidity提供了两个函数assert和require来进行条件检查,如果条件不满足则抛出异常。assert函数通常用来检查(测试)内部错误,而require函数来检查输入变量或合同状态变量是否满足条件以及验证调用外部合约返回值。
另外,如果我们正确使用assert,有一个Solidity分析工具就可以帮我们分析出智能合约中的错误,帮助我们发现合约中有逻辑错误的bug。

  • revert函数可以用来标记错误并回退当前调用
  • 使用throw关键字抛出异常(从0.4.13版本,throw关键字已被弃用,将来会被淘汰。)

当子调用中发生异常时,异常会自动向上“冒泡”。 不过也有一些例外:send,和底层的函数调用call, delegatecall,callcode,当发生异常时,这些函数返回false。

注意:在一个不存在的地址上调用底层的函数call,delegatecall,callcode 也会返回成功,所以我们在进行调用时,应该总是优先进行函数存在性检查。

参考链接:

https://learnblockchain.cn/2018/06/07/remix-ide/https://blog.csdn.net/piqianming/article/details/79756900https://hiblock.net/topics/212https://blog.csdn.net/jerry81333/article/details/78118972https://learnblockchain.cn/categories/ethereum/Solidity/page/2/

搭建自己的以太坊区块链

一、基本概念

以太坊简单来说就是区块链与智能合约的结合,是基于solidity语言实现的。在以太坊中,智能合约也有一个帐户地址。

1.1、 EVM

  以太坊虚拟机(EVM)是以太坊中智能合约的运行环境。它不仅被沙箱封装起来,事实上它被完全隔离,运行在EVM内部的代码不能接触到网络、文件系统或者其它进程。甚至智能合约之间也只有有限的调用。

  以太坊支持两种智能合约的编程语言:Solidity 和 Serpent。Serpent 语言面临一些安全问题,现在已经不推荐使用了。Solidity 语法类似 JavaScript,它编译器 solc 可以把智能合约源码编译成以太坊虚拟机 EVM 可以执行的二进制码。
现在以太坊提供更方便的在线 IDE —— Remix https://remix.ethereum.org 使用 Remix,免去了安装 solc 和编译过程,它可以直接提供部署合约所需的二进制码和 ABI。

1.2、 Accounts

  以太坊中有两类账户,它们共用同一个地址空间。外部账户,该类账户被公钥-私钥对控制。合约账户,该类账户被存储在账户中的代码控制。 外部账户的地址是由公钥决定的,合约账户的地址是在创建合约时确定的

  每个账户都有一个以太币余额(单位是“Wei”),该账户余额可以通过向它发送带有以太币的交易来改变。

1.3、 Transactions

  每一笔交易都是一条信息,可以通过交易,将余额从一个帐户发至另一个帐户。

1.4、 Gas

  每一笔交易需要支付一定的gas。gas price是由创建者设置的,调用合约的发送账户需要交易费用 = gas price * gas amount。

1.5、 以太坊客户端

  以太坊客户端用于接入以太坊网络,进行账户管理、交易、挖矿、智能合约相关的操作。目前有多种语言实现的客户端,常用的有 Go 语言实现的 go-ethereum 客户端 Geth,支持接入以太坊网络并成为一个完整节点,也可作为一个 HTTP-RPC 服务器对外提供 JSON-RPC 接口。
  

二、搭建go-ethereum

两种安装方式:

  • ppa安装
  • 源码编译

2.1、ppa安装

2.2、源码编译

编译安装时 make geth 过程中可能会报错,可以通过下面方案进行修复

三、安装 Solidity 编译器

Solidity 编译器也有多种方法安装,参照 http://solidity.readthedocs.io/en/latest/installing-solidity.html 这里介绍最简单快捷的安装方式:PPA 直接安装。

3.1、ppa安装

四、搭建以太坊

4.1、创世区块

要运行以太坊私有链,需要定义自己的创世区块,创世区块信息写在一个 JSON 格式的配置文件中。首先将下面的内容保存到一个 JSON 文件中,例如 genesis.json

配置简单说明:

chainId指定了独立的区块链网络 ID。网络 ID 在连接到其他节点的时候会用到,以太坊公网的网络 ID 是 1,为了不与公有链网络冲突,运行私有链节点的时候要指定自己的网络 ID。不同 ID 网络的节点无法相互连接。

difficulty挖矿难度。

gasLimit区块 Gas 消耗限制。

4.2、初始化创世区块

目录结构

其中 geth/chaindata 中存放的是区块数据,keystore 中存放的是账户数据。

4.3、 启动以太坊区块链,并进入控制台模式

上面命令的主体是 geth console,表示启动节点并进入交互式控制台。
各选项含义如下:

  • datadir:指定区块链数据的存储位置;
  • identity:指定节点 ID
  • rpc:表示开启 HTTP-RPC 服务;
  • rpcport:指定 HTTP-RPC 服务监听端口号(默认为 8545);
  • port:指定和其他节点连接所用的端口号(默认为 30303);
  • nodiscover:关闭节点发现机制,防止加入有同样初始配置的陌生节点。

geth console进入一个交互式的 JavaScript 执行环境,在这里面可以执行 JavaScript 代码,其中 > 是命令提示符。在这个环境里也内置了一些用来操作以太坊的 JavaScript 对象,可以直接使用这些对象。这些对象主要包括:

  • eth:包含一些跟操作区块链相关的方法;
  • net:包含一些查看p2p网络状态的方法;
  • admin:包含一些与管理节点相关的方法;
  • miner:包含启动&停止挖矿的一些方法;
  • personal:主要包含一些管理账户的方法;
  • txpool:包含一些查看交易内存池的方法;
  • web3:包含了以上对象,还包含一些单位换算的方法。
4.3.1、创建账户

1)直接输入密码创建账户

2)交互式创建账户

4.3.2、查看账户余额

4.3.3、挖矿

开始挖矿

其中 start 的参数表示挖矿使用的线程数。第一次启动挖矿会先生成挖矿所需的 DAG 文件,这个过程有点慢,等进度达到 100% 后,就会开始挖矿,此时屏幕会被挖矿信息刷屏。

停止挖矿

4.3.4、交易

第一个账户已经有余额了了。第二个账户没有币。

账户解锁,只有先对账户解锁才能转账。

进行交易

此时如果没有挖矿,用 txpool.status 命令可以看到本地交易池中有一个待确认的交易,可以使用 eth.getBlock("pending", true).transactions 查看当前待确认交易。

进行挖矿交易。

新区块挖出后,挖矿结束,查看账户 1 的余额,已经收到了账户 0 的以太币

4.3.5、 查看交易与区块

1) 查看总区块数

2) 查看交易

3)通过区块号查看区块:

五、以太坊区块链网络

我们通过单机的不同端口来模拟不同的网络。

首先需要使用相同的创世区块来初始化一个链出来。

然后在chian2中创建一个账户

使用2个终端分别打开着2个链

目前启动了三个节点,但都默认关闭了发现功能,需要手动添加peer节点。

在每个终端输入admin.nodeInfo.enode, 把输出记录下来到static-nodes.json文件,我这里情况如下:

两个终端退出后重启。输入admin.peers可以查看节点信息

开始挖矿

chain2 链启动后会出现警告同步数据失败,等待的一段时间后就可以了。

增加节点还是使用admin.addPeer来处理。

addPeer() 的参数就是节点二的 enode 信息,注意要把 enode 中的 [::] 替换成节点二的 IP 地址。连接成功后,节点二就会开始同步节点一的区块,同步完成后,任意一个节点开始挖矿,另一个节点会自动同步区块,向任意一个节点发送交易,另一个节点也会收到该笔交易。

通过 admin.peers 可以查看连接到的其他节点信息,通过 net.peerCount 可以查看已连接到的节点数量。

除了上面的方法,也可以在启动节点的时候指定 --bootnodes 选项连接到其他节点。

参考链接:

  • https://mshk.top/2017/11/go-ethereum-1-7-2/
  • https://g2ex.github.io/2017/09/12/ethereum-guidance/
  • https://github.com/xiaoping378/blog/blob/master/posts/%E4%BB%A5%E5%A4%AA%E5%9D%8A-%E7%A7%81%E6%9C%89%E9%93%BE%E6%90%AD%E5%BB%BA%E5%88%9D%E6%AD%A5%E5%AE%9E%E8%B7%B5.md

windows环境管理多版本jvm

1、下载jvms

解压后将jvms.exe放入c:\windows\下。

2、使用jvms

基础用法
  • jvms ls 查看受jvms管理的jdk
  • jvms ls-remote 查看jvms源里提供下载的jdk版本
  • jvms install 从jvms源里安装jdk
  • jvms uninstall 删除受jvms管理的jdk
  • jvms use 使用指定版本的jdk
  • jvms version 可看jvms的版本
安装jvm

1)查看有哪些发行版本

2)选择自己需要的版本进行安装

3) 初始化环境,设置环境变量

4)切换版本

golang new 和 make 区别

new(T) 返回的是 T 的指针

new(T) 为一个 T 类型新值分配空间并将此空间初始化为 T 的零值,返回的是新值的地址,也就是 T 类型的指针 *T,该指针指向 T 的新分配的零值。

上面的代码是等价的,new(int) 将分配的空间初始化为 int 的零值,也就是 0,并返回 int 的指针,这和直接声明指针并初始化的效果是相同的。

make 只能用于 slice,map,channel

make 只能用于 slice,map,channel 三种类型,make(T, args) 返回的是初始化之后的 T 类型的值,这个新值并不是 T 类型的零值,也不是指针 *T,是经过初始化之后的 T 的引用。

slice 的零值是 nil,使用 make 之后 slice 是一个初始化的 slice,即 slice 的长度、容量、底层指向的 array 都被 make 完成初始化,此时 slice 内容被类型 int 的零值填充,形式是 [0 0 0],map 和 channel 也是类似的。

make(T, args) 返回的是 T 的 引用

如果不特殊声明,go 的函数默认都是按值穿参,即通过函数传递的参数是值的副本,在函数内部对值修改不影响值的本身,但是 make(T, args) 返回的值通过函数传递参数之后可以直接修改,即 map,slice,channel 通过函数穿参之后在函数内部修改将影响函数外部的值。

这说明 make(T, args) 返回的是引用类型,在函数内部可以直接更改原始值,对 map 和 channel 也是如此。

很少需要使用 new

以下代码演示了 struct 初始化的过程,可以说明不使用 new 一样可以完成 struct 的初始化工作。

foo1 和 foo2 是同样的类型,都是 Foo 类型的值,foo1 是通过 var 声明,Foo 的 filed 自动初始化为每个类型的零值,foo2 是通过字面量的完成初始化。foo3,foo4 和 foo5 是一样的类型,都是 Foo 的指针 Foo。*但是所有 foo 都可以直接使用 Foo 的 filed,读取或修改,为什么?

如果 x 是可寻址的,&x 的 filed 集合包含 m,x.m 和 (&x).m 是等同的,go 自动做转换,也就是 foo1.age 和 foo3.age 调用是等价的,go 在下面自动做了转换。

因而可以直接使用 struct literal 的方式创建对象,能达到和 new 创建是一样的情况而不需要使用 new。

小结

new(T) 返回 T 的指针 *T 并指向 T 的零值。

make(T) 返回的初始化的 T,只能用于 slice,map,channel。

转载自: http://sanyuesha.com/2017/07/26/go-make-and-new/