Logstash的多行输入以及自定义Pattern

前言

通常我们仅仅用logstash处理access log。这个时候logstash的配置如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
input {
stdin {}
}

filter {
grok {
match => { "message" => "%{HTTPD_COMMONLOG}" }
}
}

output {
stdout { codec => rubydebug }
}

我们知道,logstash的config内容分为input,filter和output三个部分。
这三个部分都集成了很多插件。我们可以从不同的地方进行input,通过filter对data进行整理,然后output。

在实际问题中,我遇到几个问题。

  • log的单位并不是一行,而是多行。

  • 我可以自定义match的pattern吗?

  • grok的match里面的message能省略掉吗?

接受以多行为单位输入的Log

我们知道,apache access log 和 nginx access log 以及大多数log都是以单行为单位输出的。

比如

1
[Fri Sep 09 10:42:29.902022 2011] [core:error] [pid 35708:tid 4328636416] [client 72.15.99.187] File does not exist: /usr/local/apache2/htdocs/favicon.ico

input的大多数插件默认是接受单行单位log输入。我们可以用multiline这个codec plugin 来接受多行输入。

1
2
3
4
5
6
7
8
input {
stdin {
codec => multiline {
pattern => "^\s"
what => "previous"
}
}
}

上面的配置的意思是,当以空格开头的行,我们把它和上面一行归并到一个log中。具体的其他用法可以查看multiline plugin的文档。

自定义grok的pattern

grok里面的match的message,其实是定义在这里的各种pattern。
我们可以自定义pattern。

形式如下

1
2
3
4
5
USERNAME [a-zA-Z0-9._-]+
USER %{USERNAME}
EMAILLOCALPART [a-zA-Z][a-zA-Z0-9_.+-=:]+
EMAILADDRESS %{EMAILLOCALPART}@%{HOSTNAME}
INT (?:[+-]?(?:[0-9]+))

将这些pattern保存在文件中,然后在logstash的config中制定读取pattern的目录即可。

1
2
3
4
5
6
filter {
grok {
patterns_dir => ["/usr/local/logstash/patterns"]
match => { "message" => "%{USER: user} %{INT: age} %{EMAILADDRESS: email}"}
}
}

这样,我们输出的时候可以获得到message,user,age,email这几个field。

省略grok解析出的一些field

可以用mutate这个plugin来移除一些field。

1
2
3
mutate {
remove_field => [ "message" ]
}

这样output的结果中就不会有message这个field了。

感想

logstash提供了丰富的插件。在遇到问题的时候除了善于搜索还要有耐心阅读插件文档,必要时候需要写demo进行测试。

Use Nem Blockchain to Store Your Hexo Blog

Hexo is a static blog generator which has large amount of handy plugins and themes.
I really enjoyed to write my blog using hexo. However I also have trouble sometimes.

Most of hexo users keep a backup of their blog using git, and however sometimes its forgetable for me to push the contents to remote and when I want to write my blog at another place, I hesitate to do so since I can not render all the blogs I wrote.

When I began to know blockchain technology and nem related development, It seems that you can use the message field of nem transaction to store your blog contents so that you can write your blog at anytime with just a nem transaction with messages of your blog contents.

That’s why I came out with a hexo plugin to fetch your blog contents on nem blockchain. Check Here for more detail.

Basic idea

Nem has provided convenient API for application developers.

When we write our blogs, we launch a transaction using your nem wallet or API, the message field should be your blog contents in markdown format.

When Hexo generate the contents, we first use nem api to fetch the contents from blockchain and save them to local files with the markdown extension. Then those contents get generated and rendered to html just same as your blogs stored on your file system.

One thing to take care is that the message field in nem can support at most 680 bytes of date and with a large message field, you are going to pay more transaction fee.

Usage

This plugin can be configured to use nem mainnet or testnet, Since it’s more easy to get some xem(currency name for nem blockchain), I suggest to use testnet first.

Prepare your testnet account

Use This script to create your testnet private key, public key and address.

You should install nem-sdk first.

Get some testnet XEM

Find a testnet faucet like This one.

Input your account address and get some testnet XEM.

The transaction should be ok in less than 5 minutes.

Create a Hexo blog and Config

Run hexo new your_blog_name to create a new hexo blog.

Go to the blog directory,
run npm install hexo-fetch-nem to install the plugin.

In _config.yaml add the config to use our nem plugin.

1
2
isMainnet: false 
nem_address: your_nem_address

your_nem_address is the nem address you transfer your contents into. You can run the above script again to get an empty account. Don’t mix up your account with XEM inside and the one you are going to write your blog to.

Write your markdown blog and make a transaction

Write down your blog for example like this.

1
2
3
4
### My title

* foo
* bar

and save your blog into a file which can be named for example my_blog.md

Use the following script to launch a tranaction to send the contents of the blog to nem blockchain.

The private key should be the one with XEM inside. You should install nem-ruby first by gem install nem-ruby and then run the script.

1
$ ruby transfer.rb my_blog.md

Generate the blog

Run hexo g to generate the blog and now have a check. Cool. I’s already there.

More

Hexo won’t generate your latest blog unless you run hexo g. To solve the problem, you can have a crontab to run generate repeatedly.

That’s all

I have a demo running. You can have a check. I am ready to write down what I have learned everyday on nem blockchain!

微信小程序IOS真机date的一个坑

给之前做的就职日历小程序添加列表功能,顺便发现了一个巨坑。

1
2
3
4
5
6
7
console.log(new Date('2018-03-01'))

// on android and pc simulator
// =>2018-03-01T00:00:00.000Z

// on ios
//=> null

WTF

原因很简单,三者的JS的引擎不一样。
修正也很简单,把所有的’yyyy-mm-dd’ 格式修正成’yyyy/mm/dd’格式既可。
防止于未然的策略就是,真机测试测试再测试。
以上。

在Terminal上快速预览Markdown

本文的起因

其实,对于Markdown预览这个需求,本来就是伪命题。

试想一下,发明Markdown的目的本来就是一种新的所见即所得的语言。

不过,在书写时候如果能够及时预览,也给我们避免了一些格式方面的错误,能让我们写得更顺手。

在诸如Atom之类的GUI编辑器中,我们可以很方便一遍书写markdown一遍即时预览。那么我们用vim书写Markdown的时候该如何即时预览呢?

几个工具

可以Parse markdown的格式,然后在terminal上输出的工具。Bug还比较多,觉得不顺手的话自己修改两下吧哈哈。

1
2
parsed = TTY::Markdown.parse('example.md')
puts parsed

可以监听文件是否有变化。然后可以处罚一个命令。用法如下。

1
$ filewatcher '**/*.js' 'jshint $FILENAME'
  • tmux

用来分割窗口。

在Termial上即时预览markdown

思路很简单,我们书写markdown的时候,用tmux分割窗口,在另一个窗口中,实用filewatcher 监听文件变化,
然后触发我们用tty-markdown书写的脚本即可,这个脚本的作用就是读取正在编辑的markdown文件,然后渲染输出到terminal上。

1
2
3
4
require 'tty-markdown'
parsed = TTY::Markdown.parse_file(ARGV[0])
puts "\e[H\e[2J"
puts parsed

保存这个脚本到PATH中,然后我们打开我们需要编辑的markdown文件。开始编辑,同时,在tmux的另一个窗口中,输入例如

1
filewatcher README.md 'tty-markdown  README.md'

哈哈,来一张截屏看看效果。

Todo

其实可以做成vim的插件,在vim中直接splitwindow来看渲染的内容。不过至今还没有大神来做这个事情,到底是为什么呢? 原因大概就是我在开头说的那几句话吧。本来就是所见即所得的东西,何必太过挑剔。

使用Ruby生成bitcoin的秘钥,公钥以及签名

TL;NR

  1. 随机生成不大于n = 1.158 * 1077(略小于2^256)的随机数作为秘钥k。

  2. 使用椭圆曲线算法从秘钥k生成公钥K。K = k * G(G是椭圆曲线上的点,*是定义在椭圆曲线上的乘法运算,G固定,相当于对G做k次椭圆上的加法运算)

  3. 使用SHA256以及RIPEMD160从公钥K生成地址A。

秘钥的生成

已经说过秘钥是一个不大于n = 1.158 * 1077(略小于2^256)的随机数。一般来说由操作系统的随机熵生成。很多钱包在生成秘钥的时候要求拖拽鼠标之类的行为,就是为了获取随机熵。

从秘钥生成公钥

采用特有的椭圆曲线secp256k1 curve从秘钥生成公钥。

1
k = K * G

在椭圆曲线上,我们可以定义一种加法,在这种加法下,两点的和相当于这两点在椭圆曲线上连线与椭圆曲线的交点。

这样,在椭圆曲线上的一个点的自相加,其和相当于从自己的位置做切线,切线与椭圆曲线相交的点的关于x轴的对称点。

下图就是把一个点G自相加多次的演示。

这样,从密钥生成公钥K就是重复上述的运算k次。

从公钥生成地址

地址相当于对数字签名。

1
A=RIPEMD160(SHA256(K))

SHA256和RIPEMD160是两个hash算法。具体就不展开了。

使用Ruby生成秘钥和公钥

已经有现成的gem可以使用,所以不需要自己重复造轮子。

1
gem install ecdsa

唯一需要注意的是,SecureRandom.random_number不一定secure和不一定非常random。

1
2
3
4
5
6
7
8
9
10
require 'ecdsa'
require 'securerandom'
group = ECDSA::Group::Secp256k1
private_key = 1 + SecureRandom.random_number(group.order - 1)
puts 'private key: %#x' % private_key

public_key = group.generator.multiply_by_scalar(private_key)
puts 'public key: '
puts ' x: %#x' % public_key.x
puts ' y: %#x' % public_key.y

以上。

使用webpack开发以太坊的前端应用

前情提要

使用Truffle开发以太坊智能合约一文中,我们建立了一个最基本的剪刀石头布的以太坊智能合约,并部署到了local的testnet上。

排除这个合约本身的不安全的问题,考虑到用户不可能在truffle的console上敲js代码来执行调用合约,我们还得得建立简单方便的前端应用。

游戏步骤

首先是完成后的简陋的UI的截图。

游戏时候,使用metamask连上local的testnet。然后自己扮演两个角色切换账户即可。

首先两个账户分别转账5wei进行注册。

然后两个用户分别选择是出石头,剪刀,还是布。

最后赢家被记录到LasterWinner这个项目里面。赢家还将获得对方的5wei。

boilerplate

建立一个新的目录。Truffle提供了很方便的已经成型的boilerplate来建立前端的应用。

1
2
3
$ mkdir rps-frontend
$ cd rps-frontend
$ truffle unbox webpack

一阵各种download之后,我们发现当前目录下多出来很多东西。
webpack的boilerplate是一个简单的基于ETH的Token的例子。
其中最主要的是app/这个文件。

1
2
3
4
5
6
app
├── index.html
├── javascripts
│   └── app.js
└── stylesheets
└── app.css

里面的内容由于不是我们需要部署的协议的内容,所以基本上我们都要移除。

首先删掉contracts里面除了Migration.sol以外的所有内容,然后再用这里的文件替换migrations里面的2_deploy_contracts.js的内容。这样理论上我们就可以部署我们的石头剪刀布协议了。

添加前端逻辑

打开app/javascripts/app.js进行修改。
具体可以参考这里, 我们只提几个注意点。

1
2
3
4
5
6
7
8
import "../stylesheets/app.css";

import { default as Web3} from 'web3'; // 用来与eth的节点交互的lib。这里我们需要用这个库来获取用户信息。
import { default as contract } from 'truffle-contract'

import rps_artifacts from '../../build/contracts/rps.json' // 协议的ABI接口。这个是通过truffle migrate之后生成的。

var Rps= contract(rps_artifacts);

也许我们已经习惯使用MetaMask来和基于Ethereum的网页应用交互。下面则是获取默认用户账号信息的代码,已经由这个boilderplate自动生成。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
web3.eth.getAccounts(function(err, accs) {
if (err != null) {
alert("There was an error fetching your accounts.");
return;
}

if (accs.length == 0) {
alert("Couldn't get any accounts! Make sure your Ethereum client is configured correctly.");
return;
}

accounts = accs;
account = accounts[0];

self.refreshWinner();
});

接下来是通过API查询blockchain获取最后赢家的函数。核心的是rps.getLastWinner.call({from: account}), 这和我们在truffle的console的输入一样。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
refreshWinner: function() {
var self = this;
var rps;
Rps.deployed().then(function(instance) {
rps = instance;
return rps.getLastWinner.call({from: account}); // 注意这里
}).then(function(value) {
var balance_element = document.getElementById("winner");
balance_element.innerHTML = value.valueOf();
}).catch(function(e) {
console.log(e);
self.setStatus("Error getting balance; see log.");
});
},

再然后是注册用户并转5wei的代码。同样核心是rps.register({value: amount, from: account})

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

register: function() {
var self = this;
var amount = parseInt(document.getElementById("amount").value);
this.setStatus("Initiating transaction... (please wait)");
var rps;
Rps.deployed().then(function(instance) {
rps= instance;
return rps.register({value: amount, from: account});
}).then(function() {
self.setStatus("Transaction complete!");
self.refreshWinner();
}).catch(function(e) {
console.log(e);
self.setStatus("Error sending coin; see log.");
});
},

最后是玩家执行游戏进行选择的代码。重点还是rps.play(selection, {from: account})

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
play: function() {
var self = this;
var selection = document.getElementById("selection").value;
var rps;
Rps.deployed().then(function(instance) {
rps= instance;
return rps.play(selection, {from: account}); //重点
}).then(function() {
self.setStatus("Transaction complete!");
self.refreshWinner();
}).catch(function(e) {
console.log(e);
self.setStatus("Error sending coin; see log.");
});

}

修改UI

接下来就是修改默认的boilerplate的index.html了。
我们得添加上显示最后赢家,输入转账数目,确认注册,选择出拳内容,确认出拳内容的一些东西。
由于boilerplate本来写得比较脏,我也只是适当修改,所以请自己参考下面完整的repo吧。

编译,部署,执行

最后就是打开truffle dev 然后依次compile,migrate --reset了。truffle dev会自动建立local的testrpc的testnet,所以这个时候npm run dev,打开浏览器就可以看到我们上面截图中的应用内容了。

最后的话

使用MetaMask大大方便了用户通过webapplication来执行智能合约。也使得我们可以顾虑很少地开发更加健全的智能合约。试想一下,如果没有MetaMask,你的智能合约就有可能需要用户去输入自己的private key。那你的应用大抵也就没人用了。

这里是整个完整的项目。

以上。

webpack 相关整理

webpack 的必要性

webpack 是一个Assets的打包工具。

通过webpack可以把css,js,json,raw text 等等依赖打包到一个bundle的js中,在html页面中,只需要引用这么一个bundle即可。

webpack的类似工具已经太多,早在Rails红极一时的年代,Sproket就已经具备了很强大的打包功能。

那么使用webpack到底有没有必要呢? 那当然是有必要的,因为很多时候你接手的项目已经倒入了webpack,这个时候,你也只有硬着头皮上了。

webpack 的配置

一般在项目root下面直接运行不带参数的webpack命令,webpack会自动寻找该目录下的config文件。 随便找了个网上的最简单的例子来看一下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

module.exports = {
context: __dirname + '/src',

entry: {
js: "./js/entry.js"
},

output: {
path: __dirname + '/dist',
filename: "./js/app.js"
},

module: {
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: ['es2015']
}
}
]
}
}

entry

总的文件js的入口。在这个文件里可以引用下面通过module loader 导入进来的模块。
比如

1
2
var my_style= require("mystyle.css")
var my_data = require("mydata.json")

output

这个就是最后生成的bundle文件。

modules loaders

通过loaders可以把任何assets通过上面类似require('xxx')的形式导入到entry文件中。

loaders 是一个数组,可以针对任何文件形式进行不同处理。比如上面的例子。

1
2
3
4
5
6
7
8
{
test: /\.js$/, // 所有符合条件的js文件
exclude: /node_modules/, // node_modules里面的js文件除外
loader: 'babel-loader', // 使用babel-loader处理这些js文件
query: {
presets: ['es2015'] // 处理时候带参数es2015,告诉babel使用es2015的preset进行编译。
}
}

loaders 可以拼接在一起形成pipeline。 比如

1
2
3
4
5
module: {
loaders: [{
test: /\.css$/,
loader: ‘style!css’ <--(style-loader!css-loader的省略表现)
}]

Plugin

除了module loader,我们还可以添加各种plugin。
plugin用于在我们生成bundle之后来对生成的bundle进行处理。比如下面的例子,我们对生成的bundle文件使用Uglify进行压缩。

1
2
3
4
5
6
7
8
9
10
11
12
//↑↑↑↑省略
output: {
path: __dirname + '/dist',
filename: "./js/app.js"
},

//↓↓↓↓追加
plugins: [
new webpack.optimize.UglifyJsPlugin()
],

//↓↓↓↓省略

除此之外我们还可以引入html模版的plugin,最后生成我们想要的index.html。所有的module loaders和 plugins都可以在文档的List的相关页面里找到。

webpack-dev server

webpack自带dev server。我们也可以在配置文件中进行相关配置。

1
2
3
4
devServer: {
contentBase: 'dist',
port: 3000
},

最后

使用webpack使得任何assets都可以模块化,管理和打包发布变得十分方便。但是有些时候,有些内容需要频繁变更的模块,就不太适合放进去打包到一起了。也许使用经验较深的enginner知道该怎么做吧。

对称密码的一些备忘

前言

本文涉及对自己长期混淆从来不想搞懂的四个术语进行梳理,并不会涉及加密算法以及加密细节。

IV

Initial Vector。初始矩阵。这个在不同的加密方法中用法和范畴也会有细微变化。总而言之是为了使同一明文生成的密文不同。
解密的时候需要用到IV。

Key

需要保密的内容。知道了Key就可以解密。

Nonce

一次性的随即值。用来防止重放攻击。IV在某些使用case中,也可以作为Nonce的一种。

在Prof of Work的的范畴中,Nonce 作为一个使得整个block的哈希值的前置0的个数大于指定个数的随机值。对整个blockchain生态圈的稳定性有着重要的作用。

Salt

严格来说不在对称加密范畴,Salt的目的是在真正的密码里面插入一些随机值。使得hash之后的密码无法通过彩虹表碰撞破解。
Salt是需要保存的。如果用来混淆每个用户密码的hash值,那么每个用户的Salt最好也是不一样的。

参考

使用Truffle开发以太坊智能合约

什么是Truffle

如果你的第一反应是什么是以太坊,那么谷歌应该会回答的很详细。

以太坊智能合约使用编程语言Solidity书写,很多开发者一看到要学习一门新语言就望而却步。然而其实仔细看Solidity的语法,就会发现对于大多数程序员来说还是比较容易上手的。

而其实开发以太坊智能合约的瓶颈在于如何部署,调试,测试。

使用Truffle,可以很好解决这一系列问题。

使用Truffle部署剪刀石头布智能合约

首先用npm 安装Truffle。

1
npm install truffle -g

我们用truffle来部署一个简单的见到石头布的游戏。

游戏规则如下:
游戏双方首先各自向合约地址转账至少5wei,然后当准备就绪之后,双方调用play函数输入剪刀石头布的选择,最后智能合约自动将钱转账给赢家。

由于本文目的是熟悉Truffle开发,部署,调试智能合约的步骤,所以智能合约我事先已经准备好了。
请直接使用这里的内容

不过由于我们要熟悉Truffle的使用步骤,所以请不要fork整个repo。

首先创建一个新的目录。初始化Truffle。

1
2
3
mkdir rps
cd rps
truffle init

这个时候会多出来几个东西。

1
2
3
4
5
6
7
8
9
10
.
├── contracts
│   ├── Migrations.sol
│  
├── migrations
│   ├── 1_initial_migration.js
│  
├── test
├── truffle-config.js
└── truffle.js

创建contracts/rps.sol 文件,把上面提供的智能合约的内容粘贴进去。

然后我们需要创建migrations/2_deploy_contracts.js。其中内容如下。

1
2
3
4
5
var  Rps = artifacts.require("rps");

module.exports = function(deployer) {
deployer.deploy(Rps);
};

解释一下。contracts目录下面存放的就是智能合约文件,而migrations下面则是存放的部署文件。
这里你也许会感到奇怪一开始就存在的Migration.sol1_initial_migration.js是什么东西。
这个官方解释是帮助你获取部署的合约地址的合约。所以我们放着不管就行了。

接下来就是部署。
输入truffle development, Truffle会自动调用testrpc开启一个独立的testnet环境。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
➜  rps truffle dev
Truffle Develop started at https://localhost:9545/

Accounts:
(0) 0x627306090abab3a6e1400e9345bc60c78a8bef57
(1) 0xf17f52151ebef6c7334fad080c5704d77216b732
(2) 0xc5fdf4076b8f3a5357c5e395ab970b5b54098fef
(3) 0x821aea9a577a9b44299b9c15c88cf3087f3b5544
(4) 0x0d1d4e623d10f9fba5db95830f7d3839406c6af2
(5) 0x2932b7a2355d6fecc4b5c0b6bd44cc31df247a2e
(6) 0x2191ef87e392377ec08e7c08eb105ef5448eced5
(7) 0x0f4f2ac550a1b4e2280d04c21cea7ebd822934b5
(8) 0x6330a553fc93768f612722bb8c2ec78ac90b3bbc
(9) 0x5aeda56215b167893e80b4fe645ba6d5bab767de

Mnemonic: candy maple cake sugar pudding cream honey rich smooth crumble sweet treat

下面的那串英文是用来恢复密钥,导入密钥的原始口令。不过不用担心,所有测试环境这串英文都一样。

首先编译

1
> compile

接下来部署。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
truffle(develop)> migrate --reset
Using network 'develop'.

Running migration: 1_initial_migration.js
Replacing Migrations...
... 0x9ff90a0b06bc3e9183807fe28a800030fa2b9330405eb3e86d29d16d147d83df
Migrations: 0x345ca3e014aaf5dca488057592ee47305d9b3e10
Saving successful migration to network...
... 0xcc6faa4193f59d7da676c7557e13271f41a8a97ca0ce171911aaf0355b92f11d
Saving artifacts...
Running migration: 2_deploy_contracts.js
Replacing rps...
... 0x44dbe0a34b7065946240a1bf14fe7b2e090aa976d5d5a8e649660952df4866fd
rps: 0x8f0483125fcb9aaaefa9209d8e9d7b9c8b9fb90f
Saving successful migration to network...
... 0x61826f086be719997aa398ef8cbc8ba8d3fb9cdd04f7486fb0f2e0c7565d2b59
Saving artifacts...

可以看到我们的智能合约倍部署到了rps: 0x8f0483125fcb9aaaefa9209d8e9d7b9c8b9fb90f这个地址。
我们引用这个地址并套上接口就可以调用智能合约里面的函数了。但是刚刚说过了,我们有migration.sol 这个合约来帮我们记住部署的地址,所以我们不需要关心这个地址,直接调用封装好的函数获取就行了。

Truffle的console中,默认使用第一个账户作为合约的调用者。

1
2
truffle(develop)> rps.deployed().then(function(instance){return instance.getMyBalance();});
BigNumber { s: 1, e: 19, c: [ 991693, 37699999999995 ] }

有一点比较在意的是,我们看到的blanance不是普通的整型,而是所谓的BigNumber。在Truffle里面可以直接调用bignumber.js的提供的扩展来将其转换成我们能理解的形式。

1
2
3
truffle(develop)> rps.deployed().then(function(instance){return instance.getMyBalance({from: "0xf17f52151ebef6c7334fad080c5704d77216b732"})}).then(function(value){return value.to
Number();});
99319236300000000000

我们再来看一下用户是否已经注册。

1
2
truffle(develop)> rps.deployed().then(function(instance){return instance.AmIPlayer1();});
false

可以看到用户还没有注册,现在我们开始注册用户。

1
2
3
4
5
6
7
8
9
10
11
12
truffle(develop)> rps.deployed().then(function(instance){return instance.register({value: 5});});
{ tx: '0x5d8ad0ba323971aef600d89cd9c7188edcf2b326265f9ff402be4626c7c2aba0',
receipt:
{ transactionHash: '0x5d8ad0ba323971aef600d89cd9c7188edcf2b326265f9ff402be4626c7c2aba0',
transactionIndex: 0,
blockHash: '0xaa5a88bc27b87e59556576fb4fcd613d4409c78308b957424bcafc42af9ad752',
blockNumber: 21,
gasUsed: 42526,
cumulativeGasUsed: 42526,
contractAddress: null,
logs: [] },
logs: [] }

value 表示转账的数目。这里转账数目是5wei。

接下来注册另一个用户。这个时候由于不是默认用户,所以我们在调用的时候需要带上。from 这个属性。

1
2
3
4
5
6
7
8
9
10
11
12
truffle(develop)> rps.deployed().then(function(instance){return instance.register({from: "0xf17f52151ebef6c7334fad080c5704d77216b732", value: 5});});
{ tx: '0x756985811c0543e8db681c47b500021dd1f3b202ddd090e837a5a8a11136a07e',
receipt:
{ transactionHash: '0x756985811c0543e8db681c47b500021dd1f3b202ddd090e837a5a8a11136a07e',
transactionIndex: 0,
blockHash: '0x96f175ead2a87824b556380923996cd96ce51ab02487c0ea1210a814493d6e26',
blockNumber: 22,
gasUsed: 42784,
cumulativeGasUsed: 42784,
contractAddress: null,
logs: [] },
logs: [] }

开始玩游戏。假设默认用户出石头,第二个用户出布。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
truffle(develop)> rps.deployed().then(function(instance){return instance.play("paper", {from: "0xf17f52151ebef6c7334fad080c5704d77216b732"});});
{ tx: '0x78a9447e2357db30a48eb5123d343d888571a6a4a43856ee5bd6be48c78963ec',
receipt:
{ transactionHash: '0x78a9447e2357db30a48eb5123d343d888571a6a4a43856ee5bd6be48c78963ec',
transactionIndex: 0,
blockHash: '0x3e9bfed42be281c84b6a8d9041a9e2d816cbec14ddd722afb25c10f94cadcd6e',
blockNumber: 23,
gasUsed: 44004,
cumulativeGasUsed: 44004,
contractAddress: null,
logs: [] },
logs: [] }

truffle(develop)> rps.deployed().then(function(instance){return instance.play("rock");});
{ tx: '0xac42883642732fa4fc6e62e9b7edc6d6a79a33c2331d3c1f7022ad4b706b96e6',
receipt:
{ transactionHash: '0xac42883642732fa4fc6e62e9b7edc6d6a79a33c2331d3c1f7022ad4b706b96e6',
transactionIndex: 0,
blockHash: '0x28b225671df0d97d734649def71d2a962c37cded0456d18fe665b4185685e020',
blockNumber: 24,
gasUsed: 60932,
cumulativeGasUsed: 60932,
contractAddress: null,
logs: [] },
logs: [] }

然后我们看一下谁是赢家。

1
2
truffle(develop)> rps.deployed().then(function(instance){return instance.getLastWinner();});
'0xf17f52151ebef6c7334fad080c5704d77216b732'

后话

Truffle的debug console 非常强大。如果熟悉JS,那么其实也十分容易上手。
本文没有涉及test。不过有兴趣的话可以看一下Truffle官网的教程,也是手把手,十分容易上手。
那么就先这样吧。

关于虚拟货币投资的一些胡言乱语-1

前言

最近来咨询Gyorou是否应该购买比特币的朋友逐渐增多。随着CME的比特币期货上市临近, 市场价格从今早的131万日元左右飙升到了写稿截止时的138万日元也是老实反应了群众对比特币的期待。试想一下,你今天什么都不干,仅需持有一个比特币,在家里卧躺一天,醒来发现已经赚了7w日元。在看看外面那些脚步匆匆的サラリマン,围在小角落里刷pokemon go 的大妈大叔,柏青哥房门前排队的老头老太以及无业游民,餐厅里对你说いらっしゃいませ心里想的却是特么今天客人怎么这么多的可爱的小姐姐,是不是优越感一下子上去了。是啊,没有什么比不劳而获更舒服的事情了。

自己也许是投资的天才?你开始坚信不疑,你越战越勇,直到有一天醒来一看盘满脸懵逼,交易所里的聊天室里有人在喊着庄家带着韭菜的钱和小姨子跑了。
你重新镇定,给自己倒杯凉水,在电脑前坐下。不妨先来老韭菜Gyorou的看法好了。

但是Gyorou本身比较懒,能写点东西已经是奇迹,懒得各种截图分析,全部嘴上胡扯。无论是被套牢了还是输光了都请自己负责。

2017.12.07 市场分析

现在市面上能够入手的虚拟货币真是多如牛毛。所以我基本只扯自己有兴趣或者持仓的货币,无法全面所以还请海涵。

BTC

CME 12月10日上架比特币先物。眼前没有其他大材料。如果现在持有的话,自然不必放手。如果想要入场,自然也不是一个坏的起点。
CME上架前后可以预计到有不小波浪。

BCH (比特币现金)

欧洲最大的在线赌场交易所BitStamp上市BCH的消息似乎并没有带来多少利好消息,相反我的第一反应是神马,居然现在还有大交易所没有上BCH?
作为有名的骗炮币,注意抄底时机,价格到达理想位置赶紧跑路就是。

ETH (以太坊)

抄底。这个不用多说。最近以太坊群众沉溺于吸猫游戏无法自拔。ETH也是因为被这个游戏占用大量的资源导致转账堵塞。本质上的吸猫游戏其实就是隐形的赌场而已。随着吸猫游戏带动以太坊的知名度,ETH价格死活不动的日子估计也快结束了。

XEM(NEM 新经币)

追涨。现在33日元的价格已经悄然接近历史最高的38日元。眼前是COMSA使用NEM的MOSAIC作为Token发行ICO,之后NEM会作为一款优秀的电子货币继续发挥更大的价值,大胆预测NEM近期冲破历史记录到达新高。

XRP(Ripple 瑞波币)

利好消息太多价格不见涨,不买除了没钱就是傻逼。理解Ripple可能需要很久时间,但是Ripple让人等待的时间也会很久。

LSK (LISK)

列出来只是我持了一小比LSK。声称取代以太坊的新一代智能合约平台,LISK因为使用Javascript开发,所以对于程序员来说是非常友好。但是至今SDK空洞,也找不到像样的智能合约Sample,LISK要走的路估计还很长。在坑外的就别跳了,钱太多可以适当入一点。

MONA (MonaCoin)

Mona的定位就是日本的DogeCoin。毫无使用价值的骗炮币(至少在Monapy出来之前)。我喜欢称之摸奶币。
Monapy(Mona发行Token的方法)的拉盘影响在短期把mona价格拉了三倍。想到当年我98日元入的5000个mona不到2倍就抛了,瞬间就感觉丢失了一辆17款保时捷911。从Monapy放出消息到Monapy影响到价格中间这段时间,Mona的价格一度在300日元左右徘徊,当我到处喊大家快买mona的时候,真正买了的人,能请我吃个什么烤肉定食吗。

MOSAIC.CMS(COMSA)

垃圾交易所Zaif发行的ICO token。现在基本是发行价触底位置。可惜资金不够无法加仓,如果资金充足,不如大量买入。反正我的911就靠它拉。

后话

以上,下期我高兴写的时候再见。