分类 技术 下的文章

闲暇时开发的新产品BiBaBi

工作实在太忙了,最近正带领小伙伴们攻克一个新项目。很难挤出业余时间折腾其他东西了,所以原先准备国庆上线的一个新产品(BiBaBi)现在还只是一个半成品,很多Feature尚未开发完成。

因为已经有好几个小伙伴私下催问进度了,所以我准备先开放新产品入口,后面再持续完善、迭代,由于是内测期间,后续正式公测后数据可能会清空,大家可以在不违反相关法律法规的情况下友好和谐地畅所欲言,欢迎找八阿哥。

简单介绍下产品,BiBaBi,垂直圈子社交,圈主可以建立公开、加密、付费的圈子,在圈子内可以提供图文、视频等多种形式的交流,可以采用类似微信朋友圈的简单冒泡模式,也可以采用专业的长篇文章发布模式,用户可以加入圈子、打赏、查看冒泡/文章,在这里,圈主和用户均有获取收入的相关渠道,平台资产流通支持 人民币数字货币(以太坊),圈子完全独立,可以由圈主自主管理,正式上线后会提供PC\WAP\微信小程序\APP等多端产品。

系统架构方面,前后端完全分离,API Server层用的PHP,部分核心模块用的GoLang实现,服务均部署在Docker集群上,目前使用了几台阿里云的2x8云主机,9个后端API实例,6个前端实例,3个管理端实例,两台负载均衡Server实例,一个PXC数据库集群,一个丐版ElasticSearch集群,扛300~500QPS还是比较轻松的,短期看是足够用了。

屏幕快照 2018-12-16 上午2.49.55.png

BiBaBi和ROCBOSS是两套产品,定位完全不一样,BiBaBi更注重垂直圈子社交,准备投入成本持续运营、推广,并实现商业变现,因此BiBaBi暂时没有开源计划,但是会从其中拆离出部分Feature用于ROCBOSS 3.0开源版本,ROCBOSS 3.0 目前也在进行中,计划将在BiBaBi正式上线后发布,对BiBaBi感兴趣想合作的伙伴可以Email联系我。

随手截了些图,凑合着看看吧。

屏幕快照 2018-12-16 上午2.45.37.png

屏幕快照 2018-12-16 上午2.42.30.png

屏幕快照 2018-12-16 上午2.42.57.png

屏幕快照 2018-12-16 上午2.43.12.png

屏幕快照 2018-12-16 上午2.43.29.png

屏幕快照 2018-12-17 下午5.00.49.png

屏幕快照 2018-12-16 上午2.44.26.png

最后,抛出BiBaBi内测地址:https://bibabi.com

基于以太坊搭建私有链并部署智能合约

前言

最近有些懒了,好久没更新博客,前阵子研究以太坊智能合约,当时记录了些东西,不过是保存的草稿,这两天翻后台的时候才发现并发布了出来(o(╯□╰)o),以下内容可以作为以太坊的入门开发教程,有需要的伙伴可以瞧瞧(评论功能已开放,欢迎留言),后面我会开源几个DApp到时候分享出来,有时间的话会再写几篇相关文章抛转引玉。

如果你完全没听说过以太坊,那你需要先去搜索了解下它具体是什么\有什么用,网络wiki上有很详细标准的介绍,我就不阐述了。言归正传,为何需要搭建一个以太坊私有链呢?

因为在以太坊公有链上发起交易、部署智能合约等都需要消耗以太坊代币(ETH),而以太坊本身也是一个平台,我们可以直接在上面开发、部署分布式应用,搭建一个私有链既可以不用同步公有链庞大的数据,也不用花钱买代币,可以很好地满足智能合约的开发和测试要求,而且开发好的智能合约将来也可以很容易地切换接口部署到以太坊公有链上。

前期准备

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

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

  • 以太坊钱包
    以太坊提供了图形界面的钱包 Ethereum Wallet 和 Mist Dapp 浏览器。钱包的功能是 Mist 的一个子集,可用于管理账户和交易;Mist 在钱包基础上,还能操作智能合约。为了演示合约部署过程,本文使用了 Geth console 操作,没有用到 Mist,当然,使用 Mist 会更简单。

安装环境

没有特别要求,可以去Geth官网下载操作系统对应的版本,本文演示环境为阿里云下Ubuntu 16.04 x64 2核4G的主机。

安装以太坊客户端

为了方便,我们直接从Geth官网下载已经编译完成的二进制文件

wget https://gethstore.blob.core.windows.net/builds/geth-linux-amd64-1.7.3-4bb3c89d.tar.gz
tar -zxvf geth-linux-amd64-1.7.3-4bb3c89d.tar.gz

编辑/etc/profile,配置环境变量

export PATH=$PATH:/root/geth/

通过source /etc/profile使得配置生效,可执行 geth version 查看版本,成功返回的结果如下

root@blockchain-node-sh:~# geth version
Geth
Version: 1.7.3-stable
Git Commit: 4bb3c89d44e372e6a9ab85a8be0c9345265c763a
Architecture: amd64
Protocol Versions: [63 62]
Network Id: 1
Go Version: go1.9.2
Operating System: linux
GOPATH=
GOROOT=/usr/local/go

私有链搭建

一、配置「创世纪块」

新建一个mychain的目录,在其中创建一个 genesis.json文件,内容如下

{
  "config": {
    "chainID": 1024,
    "homesteadBlock": 0,
    "eip155Block": 0,
    "eip158Block": 0
  },
  "alloc": {},
  "coinbase": "0x0000000000000000000000000000000000000000",
  "difficulty": "0x100",
  "extraData": "",
  "gasLimit": "0x2fe9a0",
  "nonce": "0xfeadbeefdeedceef",
  "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
  "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
  "timestamp": "0x00"
}

其中,chainID 指定了独立的区块链网络 ID。网络 ID 在连接到其他节点的时候会用到,以太坊公网的网络 ID 是 1,为了不与公有链网络冲突,运行私有链节点的时候要指定自己的网络 ID。不同 ID 网络的节点无法相互连接。配置文件还对当前挖矿难度 difficulty、区块 Gas 消耗限制 gasLimit 等参数进行了设置。

在 Geth 1.6+ 中,以太坊提供了一个生成创世块的向导工具:puppeth。并且提供了更适合在私有链中使用的 Clique PoA 共识算法。puppeth 的使用,可以参照《利用puppeth搭建POA共识的以太坊私链网络》

二、初始化「写入创世区块」

准备好创世区块配置文件后,需要初始化区块链,将上面的创世区块信息写入到区块链中。首先要新建一个目录用来存放区块链数据,我们在 ~/mychain 目录下新建 data 目录,创建完后目录结构应该是这样的:

root@blockchain-node-sh:~/mychain# tree -c
.
├── genesis.json
└── data

1 directory, 1 file

接下来进入 mychain 执行初始化命令

cd mychain
geth --datadir data init genesis.json

初始化区块链之后,会将「创世块」写入区块中,看到以下结果说明初始化成功了

root@blockchain-node-sh:~/mychain# geth --datadir data init genesis.json
WARN [02-06|11:15:02] No etherbase set and no accounts found as default
INFO [02-06|11:15:02] Allocated cache and file handles         database=/root/mychain/data/geth/chaindata cache=16 handles=16
INFO [02-06|11:15:02] Writing custom genesis block
INFO [02-06|11:15:02] Successfully wrote genesis state         database=chaindata                         hash=a9f2f3…9bfc24
INFO [02-06|11:15:02] Allocated cache and file handles         database=/root/mychain/data/geth/lightchaindata cache=16 handles=16
INFO [02-06|11:15:02] Writing custom genesis block
INFO [02-06|11:15:02] Successfully wrote genesis state         database=lightchaindata                         hash=a9f2f3…9bfc24

初始化成功后,会在数据目录 data 中生成 gethkeystore 两个文件夹,此时目录结构如下

root@blockchain-node-sh:~/mychain# tree -c
.
├── genesis.json
└── data
    ├── geth
    │   ├── chaindata
    │   │   ├── 000001.log
    │   │   ├── CURRENT
    │   │   ├── LOCK
    │   │   ├── LOG
    │   │   └── MANIFEST-000000
    │   └── lightchaindata
    │       ├── 000001.log
    │       ├── CURRENT
    │       ├── LOCK
    │       ├── LOG
    │       └── MANIFEST-000000
    └── keystore

5 directories, 11 files

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

三、启动私有链节点

初始化完成后,私有链的配置就已经完成了,在终端中输入以下命令即可启动节点:

geth --identity "MyChain" --rpc --rpcport "8545" --datadir data --port "30303" console

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

  • identity:指定节点 ID
  • rpc:表示开启 HTTP-RPC 服务
  • rpcport:指定 HTTP-RPC 服务监听端口号(默认为 8545)
  • datadir:指定区块链数据的存储位置
  • port:指定和其他节点连接所用的端口号(默认为 30303)

运行上面的命令后,就启动了区块链节点并进入了该节点的控制台:

···
INFO [02-06|11:21:27] HTTP endpoint opened: http://127.0.0.1:8545
INFO [02-06|11:21:27] IPC endpoint opened: /root/mychain/data/geth.ipc
Welcome to the Geth JavaScript console!

instance: Geth/MyChain/v1.7.3-stable-4bb3c89d/linux-amd64/go1.9.2
 modules: admin:1.0 debug:1.0 eth:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0

>
>

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

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

具体的用法可以前往参阅官网文档

控制台操作

进入以太坊 Javascript Console 后,就可以使用里面的内置对象做一些操作,这些内置对象提供的功能很丰富,比如查看区块和交易、创建账户、挖矿、发送交易、部署智能合约等。

常用命令有:

  • personal.newAccount():创建账户;
  • personal.unlockAccount():解锁账户;
  • eth.accounts:枚举系统中的账户;
  • eth.getBalance():查看账户余额,返回值的单位是 Wei(Wei 是以太坊中最小货币面额单位,类似比特币中的聪,1 ether = 10^18 Wei);
  • eth.blockNumber:列出区块总数;
  • eth.getTransaction():获取交易;
  • eth.getBlock():获取区块;
  • miner.start():开始挖矿;
  • miner.stop():停止挖矿;
  • web3.fromWei():Wei 换算成以太币;
  • web3.toWei():以太币换算成 Wei;
  • txpool.status:交易池中的状态;
  • admin.addPeer():连接到其他节点;

这些命令支持 Tab 键自动补全。

一、创建账户 personal.newAccount()

> personal.newAccount()
Passphrase:
Repeat passphrase:
"0x2b8e32e869ec17b120b8b866a7852b2d593c4a05"

输入两遍密码后会生成一个账户地址

再创建一个

> personal.newAccount()
Passphrase:
Repeat passphrase:
"0x7ff4850044c42e9895c9b5e966293d29cae7fa23"

查看刚刚创建的两个账户地址

> eth.accounts
["0x2b8e32e869ec17b120b8b866a7852b2d593c4a05", "0x7ff4850044c42e9895c9b5e966293d29cae7fa23"]

二、查看账户余额 eth.getBalance()

> eth.getBalance(eth.accounts[0])
0
> eth.getBalance(eth.accounts[1])
0

三、启动&停止挖矿

启动挖矿

miner.start(8)

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

停止挖矿

miner.stop()

挖到一个区块会奖励5个以太币,挖矿所得的奖励会进入矿工的账户,这个账户叫做 coinbase,默认情况下 coinbase 是本地账户中的第一个账户,可以通过 miner.setEtherbase() 将其他账户设置成 coinbase。

四、发送交易

在开启挖矿一阵子之后,可以查看到账户中已经有挖出块的奖励了

> eth.getBalance(eth.accounts[0])
8.845e+21
> web3.fromWei(eth.getBalance(eth.accounts[0]),'ether')
8845
> eth.getBalance(eth.accounts[1])
0

现在从「账户0」给「账户1」转账,要先解锁「账户0」,才能发起交易

> personal.unlockAccount(eth.accounts[0])
Unlock account 0x2b8e32e869ec17b120b8b866a7852b2d593c4a05
Passphrase:
true

发送一笔交易,「账户0」 -> 「账户1」

> amount = web3.toWei(500,'ether')
"500000000000000000000"
> eth.sendTransaction({from:eth.accounts[0], to:eth.accounts[1], value:amount})
INFO [02-07|10:30:24] Submitted transaction                    fullhash=0xe2d74696c4186c1fa0e09c439dd81e89142c67cddeacd833cff90cce76496246 recipient=0x7Ff4850044c42E9895C9B5e966293d29Cae7FA23
"0xe2d74696c4186c1fa0e09c439dd81e89142c67cddeacd833cff90cce76496246"

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

> txpool.status
{
  pending: 1,
  queued: 0
}
> eth.getBlock("pending", true).transactions
[{
    blockHash: "0xda45c4ee7de84396f4ba562c666306ea97e4a7445fc36ffbb6a36c10c0fbf610",
    blockNumber: 1770,
    from: "0x2b8e32e869ec17b120b8b866a7852b2d593c4a05",
    gas: 90000,
    gasPrice: 18000000000,
    hash: "0xe2d74696c4186c1fa0e09c439dd81e89142c67cddeacd833cff90cce76496246",
    input: "0x",
    nonce: 0,
    r: "0xdadeb2f45f55e62c4d8068d4c167a98f246cc2c70ea654ef67a593aa77530081",
    s: "0x4ea040b97103fab958da4a760ae3f90b3c905def471699551a8b5f712f51f4f4",
    to: "0x7ff4850044c42e9895c9b5e966293d29cae7fa23",
    transactionIndex: 0,
    v: "0x824",
    value: 500000000000000000000
}]

使用 miner.start() 命令开始挖矿

> miner.start(1);admin.sleepBlocks(1);miner.stop();

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

> web3.fromWei(eth.getBalance(eth.accounts[1]),'ether')
500

五、查看交易和区块

查看当前区块总数

> eth.blockNumber
1770

根据上面交易返回的Hash查看交易详情

> eth.getTransaction("0xe2d74696c4186c1fa0e09c439dd81e89142c67cddeacd833cff90cce76496246")
{
  blockHash: "0xd58ac4d3434e8f485b1d4a8a741bebbfe3360e3b01c1f6380b9b1a8c1edbba7c",
  blockNumber: 1770,
  from: "0x2b8e32e869ec17b120b8b866a7852b2d593c4a05",
  gas: 90000,
  gasPrice: 18000000000,
  hash: "0xe2d74696c4186c1fa0e09c439dd81e89142c67cddeacd833cff90cce76496246",
  input: "0x",
  nonce: 0,
  r: "0xdadeb2f45f55e62c4d8068d4c167a98f246cc2c70ea654ef67a593aa77530081",
  s: "0x4ea040b97103fab958da4a760ae3f90b3c905def471699551a8b5f712f51f4f4",
  to: "0x7ff4850044c42e9895c9b5e966293d29cae7fa23",
  transactionIndex: 0,
  v: "0x824",
  value: 500000000000000000000
}

通过区块号查看区块

eth.getBlock(1770)
{
  difficulty: 259239,
  extraData: "0xd783010703846765746887676f312e392e32856c696e7578",
  gasLimit: 4712388,
  gasUsed: 21000,
  hash: "0xd58ac4d3434e8f485b1d4a8a741bebbfe3360e3b01c1f6380b9b1a8c1edbba7c",
  logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  miner: "0x2b8e32e869ec17b120b8b866a7852b2d593c4a05",
  mixHash: "0x56f43f7f8f3191177ce39d859bf470b79b09845bbce025483be8290802c0b0f9",
  nonce: "0x0888dfc33def060a",
  number: 1770,
  parentHash: "0xc0529ca39530fc4a759e839272aba82f028f7243d28441334cca8549cb3d06ae",
  receiptsRoot: "0x5cd1205318b43d21a6ad398c5ac833fb47705990d07c34988915f10201a893e4",
  sha3Uncles: "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
  size: 654,
  stateRoot: "0xa3f08a91d5f3a4bf16b2f5b722ac9030ba7feb9e2dd885d4e24e74d5aa79e843",
  timestamp: 1517971336,
  totalDifficulty: 355546930,
  transactions: ["0xe2d74696c4186c1fa0e09c439dd81e89142c67cddeacd833cff90cce76496246"],
  transactionsRoot: "0xc0f7643b406ad1aff74e9165a9e1db82295841a6921adf426d96ecc8cb4cbbee",
  uncles: []
}

六、节点互连

以上均是单节点操作,而实际一个健壮的区块链网络是由大量的节点构成,通过 admin.addPeer() 方法可以连接到其他节点,相同节点要指定相同的chainID。

在本地电脑安装好Geth环境后,需要指定相同的「创世块」genesis.json文件和相同的ChainID

假设上面我们搭建的那个节点为「节点一」,在本机电脑上搭建的为「节点二」

在「节点一」执行 admin.nodeInfo.enode 可以获取 enode 信息

> admin.nodeInfo.enode
"enode://0ceafcae30c783ddcbb3d0ad8a5dd5a061bfb96efc94a7bf7a4e431a80e52e662cdb5fe717c9de45342d0f75264d3799386ccc7da214c2118946391ce907ccaa@[::]:30303"

在「节点二」的 console 中执行 admin.addPeer(),就可以连接到「节点一」

> admin.addPeer("enode://0ceafcae30c783ddcbb3d0ad8a5dd5a061bfb96efc94a7bf7a4e431a80e52e662cdb5fe717c9de45342d0f75264d3799386ccc7da214c2118946391ce907ccaa@106.14.170.6:30303")
true

注意:「节点一」生成的enode中[::]需要换成相应的IP地址,且要注意防火墙是否开放相应端口。

连接成功后,「节点二」就会开始同步「节点一」的区块,同步完成后,任意一个节点开始挖矿,其他节点会自动同步区块,向任意一个节点发送交易,其他节点也会收到该笔交易。

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

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

智能合约操作

一、创建和编译智能合约

有多种方式来新建和编译智能合约,这里介绍两种常见的便捷方式:

  1. Remix,是一个Solidity开发语言的Ide,它是一款运行在浏览器端的在线solidity ide,也是官方推荐使用的ide,无需在本地安装搭建环境,可以方便快捷地在线编写、编译、部署智能合约。

  2. 通过npm来安装solc,npm i -g solc

环境安装成功后,接下来新建一个 Solidity 智能合约文件,命名为 testContract.sol,该合约包含一个方法 multiply(),将输入的两个数相乘后输出:

pragma solidity ^0.4.0;
contract TestContract
{
    function multiply(uint a, uint b) public pure returns (uint)
    {
        return a * b;
    }
}

编译智能合约,获得编译后的 EVM 十六进制码:

$ solcjs --bin testContract.sol

$ cat testContract_sol_TestContract.bin
6060604052341561000f57600080fd5b60ba8061001d6000396000f300606060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063165c4a16146044575b600080fd5b3415604e57600080fd5b606b60048080359060200190919080359060200190919050506081565b6040518082815260200191505060405180910390f35b60008183029050929150505600a165627a7a7230582089c979bfe42c5794d1b92af4acc41048cb266a1be566c9e3699e58a3cb6e9d800029

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

$ cat testContract_sol_TestContract.abi
[{"constant":true,"inputs":[{"name":"a","type":"uint256"},{"name":"b","type":"uint256"}],"name":"multiply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"}]

回到 Geth 的控制台,用变量 codeabi 来记录上面两个值,注意在 code 前加上 0x 前缀:

> code = "0x6060604052341561000f57600080fd5b60ba8061001d6000396000f300606060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063165c4a16146044575b600080fd5b3415604e57600080fd5b606b60048080359060200190919080359060200190919050506081565b6040518082815260200191505060405180910390f35b60008183029050929150505600a165627a7a7230582089c979bfe42c5794d1b92af4acc41048cb266a1be566c9e3699e58a3cb6e9d800029"
> abi = [{"constant":true,"inputs":[{"name":"a","type":"uint256"},{"name":"b","type":"uint256"}],"name":"multiply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"}]

二、部署智能合约

这里使用「账户0」来部署合约,首先解锁账户:

> personal.unlockAccount(eth.accounts[0])
Unlock account 0x132acf5dbb300cc8ccc03ee05d3e1e90409908fb
Passphrase:
true

发送部署合约的交易:

> myContract = eth.contract(abi)
...
> contract = myContract.new({from:eth.accounts[0],data:code,gas:1000000})
INFO [02-24|10:21:43] Submitted contract creation              fullhash=0x099a297160a071e3040bee1514c681bfc8cc1b002df60fc5975a2639634eed21 contract=0xA818D8384D86f1e0d9Cd355A279110b2ccA44DEC
{
  abi: [{
      constant: true,
      inputs: [{...}, {...}],
      name: "multiply",
      outputs: [{...}],
      payable: false,
      stateMutability: "pure",
      type: "function"
  }],
  address: undefined,
  transactionHash: "0x099a297160a071e3040bee1514c681bfc8cc1b002df60fc5975a2639634eed21"
}

此时如果没有挖矿,用 txpool.status 命令可以看到本地交易池中有一个待确认的交易

> txpool.status
{
  pending: 1,
  queued: 0
}

> eth.getBlock("pending", true).transactions
[{
    blockHash: "0xae0c63885ea0f9a8fda46e4568606eddb453a386c27213195a5b9649d0088aa2",
    blockNumber: 1989,
    from: "0x132acf5dbb300cc8ccc03ee05d3e1e90409908fb",
    gas: 1000000,
    gasPrice: 18000000000,
    hash: "0x099a297160a071e3040bee1514c681bfc8cc1b002df60fc5975a2639634eed21",
    input: "0x6060604052341561000f57600080fd5b60ba8061001d6000396000f300606060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063165c4a16146044575b600080fd5b3415604e57600080fd5b606b60048080359060200190919080359060200190919050506081565b6040518082815260200191505060405180910390f35b60008183029050929150505600a165627a7a7230582089c979bfe42c5794d1b92af4acc41048cb266a1be566c9e3699e58a3cb6e9d800029",
    nonce: 9,
    r: "0xe4c6ae4d28dedda6b7145dcd1fabc4016535180adecb34a0abb984bed9d8ee31",
    s: "0x4abc769013e775b97acf023a9f22fd672fdac23e48692127302d09efcfbd0b94",
    to: null,
    transactionIndex: 0,
    v: "0x823",
    value: 0
}]

使用 miner.start() 命令开始挖矿,一段时间后交易会被确认,随新区块进入区块链。

三、调用智能合约

使用以下命令发送交易,sendTransaction 方法的前几个参数应该与合约中 multiply 方法的输入参数对应。这种情况下,交易会通过挖矿记录到区块链中(注意:部署和「修改合约内数据」的调用本质都是发起一个交易):

> contract.multiply.sendTransaction(2, 4, {from:eth.accounts[0]})
INFO [02-24|10:27:01] Submitted transaction                    fullhash=0xa066b8dfe2f78296e6dd25518c3cf68b2489bcc571679f4bdfe92a4705ea2405 recipient=0xA818D8384D86f1e0d9Cd355A279110b2ccA44DEC
"0xa066b8dfe2f78296e6dd25518c3cf68b2489bcc571679f4bdfe92a4705ea2405"

如果只是本地运行该方法查看返回结果,可以采用如下方式(本地调用查询,不涉及修改合约内部数据,不需要广播至区块链,不会消耗手续费):

> contract.multiply.call(2, 4)
8

以上就是在以太坊上开发部署智能合约的简单示例。

附言

目前并非所有场景都需要使用区块链技术,从网络节点设计层面来看,当前技术水平的区块链网络为达到更高的安全性、更好的信任效果,会消耗更多资源,在使各方信任成本降低的同时,也导致全网网络运营总成本偏高,区块链技术应用场景应该遵循如下四个原则:

  第一,多信任主体:区块链是信任机器,应用环境最好是相互之间没有天然信任关系(如不同企业主体之间),需要通过区块链来搭建信任。反之,如果双方是强信任关系,或已有完善的制度保障,使用区块链的必要性就不大。

  第二,多方协作:如果该场景协作方多,对账成本高,区块链底层的共享账本之上搭建的智能合约能够降低对账成本,从而提升效率。

  第三,中低频交易:区块链目前的并发性和扩展性还不足以应用于大规模高频交易,比如股票交易所。

  第四,商业逻辑完备:区块链节点之间一定要有完备的商业逻辑,形成多赢局面,参与者才有动力使用整条区块链。

相关术语说明

  • ABI(Application Binary Interface)应用二进制接口,其中指定了合约接口,包括可调用的合约方法、变量、事件等。
  • DApp(Decentralized App)去中心化的应用程序,基于智能合约的应用称为去中心化的应用程序。
  • EVM(Ethereum Virtual Machine),以太坊虚拟机,以太坊智能合约的运行环境。
  • Gas(消耗的)汽油,在以太坊上发起交易、部署合约和调用合约都要消耗一定量的以太币,这些消耗的以太币称为 Gas。
  • Geth 以太坊客户端 go-ethereum,使用 Go 语言编写,是最常用的以太坊客户端之一。
  • Solidity 以太坊智能合约的一种编程语言,类似 JavaScript。
  • Remix IDE 在线地址,基于浏览器的 Solidity 集成开发环境,在浏览器中编写和调试智能合约。

参考资料

记一次EV SSL证书申请的折腾经历

花了几百美刀买了两年的证书,前后折腾了一周多,先看下效果吧。
dfgdf2.png

手里屯了不少域名,有的是激情消费,有的纯粹就是喜欢,还有的在域名市场看着顺眼的,统统给顺下来了。

最近准备有空的时候用一个域名来折腾个金融性质的系统,当时想着金融嘛,要加强用户的信任度,那EV SSL证书好像得搞一个,而且我自己有个公司,资料也都齐全,于是乎,想着想着就踏上了这条贼船。

首先买完证书后,系统很快发邮件来了,意思让我确认一些信息,并且填入验证码
屏幕快照 2017-11-20 23.13.21.png
屏幕快照 2017-11-20 23.10.04.png

填完后,过了一天COMODO就发邮件来了,也就是这时候开始,气人的地方出现了。

开始他们直接将我公司名称逐字翻译了一通(惨不忍睹),和我提交的名字差的十万八千里,然后居然让我确认

屏幕快照 2017-11-20 23.15.45.png

我直接拒绝了,然后提出要用我申请的公司英文名称

屏幕快照 2017-11-20 23.22.30.png

又过了一天,他们回复如果要用这个名称,必须要去申请邓氏编码,并且把公司注册号添加进去

屏幕快照 2017-11-20 23.57.15.png

好吧,接下来花了几天时间后,走Apple开发者通道终于把邓氏编码申请下来了,结果他们居然又和我说还是不可以用,只可以用他们不知从哪儿搞来的名称,相当荒唐

屏幕快照 2017-11-21 00.04.24.png

最后我很气愤地申请退款,结果这时他们另外一个客服又告诉我可以用我提交的名称了......在我特意确认后,他们终于给了我肯定的答案。走到这边,后面的流程总算顺畅了,填了两个表格,打印盖章扫描给他们。

屏幕快照 2017-11-21 00.14.43.png


屏幕快照 2017-11-21 00.14.56.png

他们表示会有人联系我核实信息,第二天中午,我收到了一个来自俄罗斯的电话,一个英语腔调特别奇怪的哥们向我核实了一些基本信息,主要是域名名称,所属人姓名等等,通话过程大概一分钟左右。

核实通过,又过了两天,证书终于下发了。

前前后后一共折腾了10天左右,想申请EV证书的伙伴可以参考下,如非必要不建议入坑。

机器学习神器 TensorFlow

前阵子公司在做以图搜图和以图搜物的功能模块,刚开始只是简单的算图片phash值来计算比较汉明距离给出相似结果,后面发现一是速度不够快,从几百万张图片中搜索效率实在不高,二是准确度也并不高,于是乎开始寻找更好的解决方案,先是看了阿里云的机器学习PAI,目前还在公测阶段,因为对之前OpenSearch定价费用过高的印象,了解了一阵子后还是决定暂时放弃,太贵了~

- Read More -

基于vue+vuex+vux+vue-router构建大型单页电商应用

前阵子给老蔡开发他的新系统,到手机站这边的时候,原先想着还是用传统的套模板模式给他开发,省时又省事,后面看着时间还算充裕,加上老蔡不停地叮嘱用户体验一定要好,于是改了想法,准备开发单页应用,采用前后端完全分离的模式。

- Read More -

Docker 学习笔记

0X00 安装并开启 docker

在绝大多数 Linux 发行版中都有 docker 的源,所以可以很轻松的装上。不过要使用 docker,必须启动 docker 的守护进程,在 CentOS7 中使用systemctl命令。

- Read More -