出家如初,成佛有余

Ethereum调用机制总结call/delegatecall/callcode/send/transfer

Posted in 技术相关 by chuanliang on 2018/04/02

Ethereum中涉及各种类型的方法调用。一个编程中常用的call概念,可能为Ethereum Vitrual Machine(EVM)内的call,又可能为EVM外的call,又涉及诸如Message/Transaction等基本概念;同时还包括call/delegatecall/callcode/send/transfer/sendTransaction等等方法。

对这些调用机制及基本概念的说明散落在 solidity文档黄皮书白皮书 中,初学者容易搞晕。这里对这些基本概念、调用机制及用法做一下整体梳理。

Ethereum调用机制总结

PDF版本:Ethereum调用机制总结

PNG版本:Ethereum调用机制总结

示例代码:测试代码下载

pragma solidity ^ 0.4.18;

contract A {
uint public var2;
uint public var1;
B b1;
address addrB;

function A() public {
b1 = new B();
addrB=address(b1);
}

function callSet(address addr, uint param) public returns(uint) {
//addr.call(bytes4(keccak256(“set(uint)”)), param); //使用了uint,调用不生效。应当使用uint256; uint是uint256的昵称,但在ABI调用时候,只能使用长类型。

//使用address.call
addr.call(bytes4(keccak256(“set(uint256)”)), param); //call 使用的是被调用者的存储,因此改变的是B.var1值

//使用实例方式,可以直接采用callee.method形式调用,从而直接获取函数返回值
/*
B b2 = B(addr);
uint result = b2.set(param);
return result;
*/

//使用 new B()方式方式调用
// uint  b1=b1.set(param);
// addrB.call(bytes4(keccak256(“set(uint256)”)), param);

return 1;
}

function delegatecallSet(address addr, uint param) {
//addr.delegatecall(bytes4(keccak256(“set(uint)”)), param); //使用了uint,调用不生效。应当使用uint256; uint是uint256的昵称,但在ABI调用时候,只能使用长类型。
addr.delegatecall(bytes4(keccak256(“set(uint256)”)), param); //delegatecall和callcode都是使用调用者的存储,特别要注意调用者和被调用者合约变量定义顺序,目前改变的是A.var2的值。
B b2 = B(addr);  //使用实例方式,可以直接采用callee.method形式调用,从而直接获取函数返回值
uint result = b2.set(param);
// uint  b1=b1.set(param);
// addrB.call(bytes4(keccak256(“set(uint256)”)), param);
}

function callcodeSet(address addr, uint param) {
addr.callcode(bytes4(keccak256(“set(uint256)”)), param);
}

function getVar1() public view returns(uint) {
return var1;
}

function getVar2() public view returns(uint) {
return var2;
}

function getAddr() public view returns(address) {
return addrB;
}
}

contract B {
uint public var1;
event MyEvent(uint param, uint result);

function set(uint param) public returns(uint) {
var1 = param;
MyEvent(param, 1);
return param;
}
}

Advertisements

R语言常用统计分布的蒙特卡洛模拟

Posted in 技术相关 by chuanliang on 2017/12/23

为加深对各种常用统计分布的理解,更好掌握R语言对应的各类分布的概率函数(d、p、q、r族)以及广义线性模型的使用,研究了一下常用统计分布数据的模拟生成方法,收获颇多。

各类常用统计分布蒙特卡洛模拟数据生成的大致思路:

1、构造自变量x的均匀分布
2、根据对应分布的均值函数,构造x变量对应的均值。(广义线性模型的link 函数参考
https://en.wikipedia.org/wiki/Generalized_linear_model#Link_function
3、将均值代入,R中对应分布的随机变量生成函数,得到因变量y(例如正态分布为rnorm、泊松分布为rpois)

代码:

#norm distribution simulation
set.seed(1234)
num=100
beta0=1
beta1=0.2
x=beta0+beta1*runif(n=num,-1,1)
y=rnorm(num,mean=x,sd=1)
model=glm(y~x,,family=gaussian(link=’identity’))

#possion distribution simulation
set.seed(1234)
num=100
beta0=1
beta1=0.2
x=beta0 + beta1*runif(n=num, min=0, max=5)
lambda=exp(x)
y=rpois(n=num, lambda=lambda)
model = glm(y~x, family=poisson(link = log))

#Exponential/Gamma distribution simulation
set.seed(1234)
num=100
beta0=1
beta1=0.2
x=beta0 + beta1*runif(n=num, min=0, max=5)
y=rexp(num,rate=exp(-x))
model=glm(y~x,,family=Gamma(link=’log’))
#使用nls模拟
df=data.frame(x,y)
model=nls(y~exp(a+b*x),data=df,start = list(a=0,b=0))

#logistic/probit distribution simulation
set.seed(1234)
num=100
beta0=1
beta1=0.2
x=beta0 + beta1*runif(n=num, min=0, max=5)
#logistic distribution logit=log(odds)=log(p/(1-p))
odds=exp(x)
probs=odds/(1+odds)
#probit distribution probit=Cumulative normal pdf
#probs=pnorm(x)

y=rbinom(n=num,size=1,prob=probs)
model=glm(y~x1+x2,family = binomial(link="logit"))

#bionimal/Categorical/Multinomial distribution simulation
library(nnet)
y=rbinom(n=num,size=3,prob=probs)
model <- multinom(y ~ x1 + x2)

代码下载


参考资料:《 Monte Carlo Simulation and Resampling Methods for Social Science》

https://www.sagepub.com/sites/default/files/upm-binaries/57233_Chapter_6.pdf

R中fitted()与predict()函数关系以及predict type参数解析

Posted in 技术相关 by chuanliang on 2017/12/17

R文档对fitted()、predict()函数以及predict函数type参数取值的具体含义说得很不清楚,网上也没有清晰的解释。总结一下。

一、说明

目的一、R中fitted和predict的关系
目的二、以logistic为例,解析predict中type参数不同取值的关系

1、R中fitted和predict的关系
fitted对无link函数模型(例如线性回归),fitted值和predict的值相同
对有link函数的模型(例如logistic、Binomial),
fitted是link函数作用前(或者link逆函数inverse of the link function作用后)的预测值
predict是link函数作用后(或link逆函数inverse of the link function作用前)的预测值
link function  https://en.wikipedia.org/wiki/Generalized_linear_modelLink_function

2、logistic中predict中type参数不同取值的关系
predict中type参数的可选项有:default, type="link",type="response",type="terms"

假设log(odds)=log(p/(1-p))=alpha+beta1*x1+beta2*x2+…+betan*xn
a.、type="link",type为缺省值
  type="link"为缺省值,给出logit线性函数预测值,link=alpha+beta1*x1+beta2*x2+…+betan*xn

b、 type="response"
  type="response" 给出概率预测值。
  response=predict(model,type = "response"),则
  log(response/(1-response))=alpha+beta1*x1+beta2*x2+…+betan*xn=link,或:link=exp(response)/(1+response)

c、type="terms"
  type="terms"表示各个变量的预测值(包括前面参数在模型中的值)。
  terms=predict(model, newdata = traindata,type = "terms")的结果为各个变量term的值
  term1=beta1*x1,term2=beta2*x2, …
  sum(term1,…,termn)+attr(terms,"constant")=log(odds)=log(response/(1-response))
  attr(terms,"constant")的含义 http://blog.minitab.com/blog/adventures-in-statistics-2/regression-analysis-how-to-interpret-the-constant-y-intercept

二、代码

代码下载

#fitted和predict的关系演示
#linear regression
#no link function
num=100
x1=rnorm(num)
x2=rnorm(num)
lr=1+2*x1+3*x2
model=lm(y~x+x2)

fit=fitted(model)
pred=predict(model)
print(all.equal(fit, pred))
#对无link函数的模型,fitted值与predict值相同

#possion
#link=log
num=100
x=rnorm(num)
y=rpois(num,lambda = exp(x))
model = glm(y~x, family="poisson")
fit=fitted(model)
pred=predict(model)
print(all.equal(log(fit),pred))
print(all.equal(fit,exp(pred)))
#对有link函数的模型,fitted值为link函数作用前的值,predict为link作用后的值

#logistic
#link=logit=log(p/(1-p))
num=100
x1=rnorm(num)
x2=rnorm(num)
lo=1+2*x1+3*x2
odds=exp(lo)
probs=odds/(1+odds)
y=rbinom(n=num,size=1,prob=probs)
model=glm(y~x1+x2,family = binomial(link="logit"))

fit=fitted(model)
pred=predict(model)
print(all.equal(log(fit/(1-fit)),pred))
print(all.equal(fit,exp(pred)/(1+exp(pred))))
#对有link函数的模型,fitted值为link函数作用前的值,predict为link作用后的值

#以logistic模型为例子,验证predict中type为缺省值,type="link",type="response",type="terms"关系
#predict中type="link"时的fitted及predict
link=predict(model,type="link")
print(link)
print(all.equal(pred,link))
#type=link为缺省值

#predict中type="response"时的fitted及predict
response=predict(model,type="response")
print(response)
print(all.equal(fit,response))
print(all.equal(pred,log(response/(1-response))))

#type="terms"时的fitted及predict
terms<- predict(model,type="terms")
term=terms[,1]+terms[,2]+attr(terms,"constant")
print(term)
print(all.equal(link,term))
print(all.equal(response,exp(term)/(1+exp(term))))

参考资料:

https://stackoverflow.com/questions/12201439/is-there-a-difference-between-the-r-functions-fitted-and-predict

R语言信用评分卡模型(脑图、代码)

Posted in 技术相关 by chuanliang on 2017/12/13

在消费金融中,风险模型组(申请评分卡、行为评分卡、催收评分卡、失联概率、违约概率PD模型等)、营销模型组(客户分层模型、客户响应模型、客户流失模型)、反欺诈模型组等都涉及了信用评分卡模型的应用。关于信用评分卡模型的使用及代码实现,网上公开的完整资料较少,且大都写得语焉不详。基于R语言做了一个完整例子,算是对最近一段时间工作总结。

分为两部分:

1、评分卡模型使用总结脑图

2、评分卡模型R语言代码

1、评分卡模型使用总结脑图(完整脑图点击下载)

2017-12-13_205830

《评分卡模型使用总结脑图》下载

2、R语言代码

scorecard.r

服务器部署Session Draining支持方案

Posted in 技术相关 by chuanliang on 2016/02/24

 

支付系统对账算法优化方案

Posted in 电子商务&互联网金融, 技术相关 by chuanliang on 2015/06/09

一、目前对账的算法:

1、从上游渠道(银行、银联等金融机构)获取对账文件,程序逐行解析入库

2、在存储过程中,以上游对账文件的表为基准,程序逐行读取并与我们系统的交易记录/账务记录(有账务系统情况下,合理方案应该是于账务记录)对比,查找出差异记录。

3、以我们系统的交易记录/账务记录为基准,程序逐行读取与上游对账文件对比,查找出差异记录

 

二、目前对账算法问题:

1、使用存储过程,对账过程都在数据库端完成,对数据库性能影响较大,而且对账逻辑扩展极为麻烦

2、逐行比对算法效率较低,但算法上并无好的优化余地。如果采用数据库INTERSECT、MINUS对数据库压力也高。

3、在业务量大的情况下(例如有上百家上游渠道需要对,每一家都有几十万条交易记录),对账服务器及数据库服务器负荷较高。即便采用读写分离,对账时候使用读库,压力一样很大。

4、导入批量文件,逐行入库效率较为低下(每一次都需要建立网络连接、关闭连接)

 

三、对账算法优化思路:

1、涉及网络传输的,尽量采用批量方式操作,减少网络消耗及时间消耗

2、使用Redis等NOSQL数据库,降低数据库服务器的压力。同时在扩展上也容易,一台Redis服务器不够,可以无限制增加用于对账用的服务器。

3、使用Redis的set集合的sdiff功能,利用Redis sdiff算法的高性能,比对上游记录和我方记录的差异

 

四、对账算法说明:

1、利用Oracle/Mysql的load data infile将对账文件批量导入到数据库

2、程序读取上游账务记录表,对上游账户记录执行select  concat(channel_id, “:” , order_id , “:” , HASH_MD5(channel_id , order_id , amount , status , timestamp1 , timestamp2 ,…) )  as hashid from table ,得到对应的SET集合。

这里思路是将需要对账的记录拼成格式为:channel_id:order_id:hashid形式的串,以便作为Redis SET集合的item。

其中channel_id和order_id用于标识对应的渠道及订单,只是例子,根据实际需要补充。之所以要在hashid前面带上channel_id和order_id,主要目的是在sdiff后,能够作为主键,根据set结合的item查找出对应的数据库记录。

3、对我方的交易记录表/账户历史表采用上一步的类似算法,得到对应的SET结合

4、采用Redis的pipeline功能(Redis的各种客户端,包括java客户端jedis 都提供此功能),将上游账务记录SET集合和我方的交易记录/账务历史记录SET集分别批量执行sadd插入Redis,得到两个SET集合。

由于单条记录sadd 插入Redis效率较差(每一次都涉及网络open、close、传输消耗),因此使用Redis的pipeline功能,已实现批量入库功能。

可以参考:http://redis.io/topics/mass-insert

5、利用redis的sdiff功能查找出上游账务集合与我方记录集合的差值

6、从sdiff 集合中channel_id:order_id:hash,定位对应的数据库记录,更新对账状态。

具体性能及实现可以在实现后测试对比一下,应该会有大幅的性能提升。

高并发交易驱动系统方案

Posted in 电子商务&互联网金融, 技术相关 by chuanliang on 2015/01/25

我在知乎就《现在有这样一个需求,在一秒中有3万的支付订单请求,有什么比较好的解决方案吗?》做的回答。

从交易角度来看,各种高并发系统可以粗略分为两大类:交易驱动的系统,内容驱动的系统。其中:
交易驱动的系统:包括支付系统、电信计费系统、银行核心交易系统等,此类系统强调数据库事务的ACID原则。
内容驱动的系统:包括SNS、微博、门户、视频、搜索引擎等系统,此类系统对数据库事务ACID的关注不是第一位的,更强调CAP原则:Consistency(一致性), Availability(可用性),Partition tolerance(分区容错性)。
与此对应,交易驱动的系统与内容驱动的系统在系统优化方法最大的差异在于:
交易驱动的系统:强 调事务的ACID,按照CAP原则做选择,更强调CA(Consistency(一致性)和Availability(可用性);因此交易驱动的系统一般 在核心交易上选择关系型数据库(包括采用内存数据库、缓存等涉及事务问题),当然这就导致交易系统最大的瓶颈一般都在关系数据库上。
内容驱动的系统:可以在CAP之间根据业务需要做选择三选二,因此一般选择NOSQL为主、RDBMS为辅的方案。
在优化策略上,内容驱动的系统采用的诸多优化手段交易驱动的系统也可以采用,上面各位回答都有所提及,这里重点说一下因事务导致的业务复杂性的处理。
3万笔/每秒这个级别的交易订单这个量级说实话挺大,但即便如此,也有诸多可优化的空间。由于题主未对具体场景说明,只能假定是典型的交易驱动系统,一些思考点:
1、3万笔/每秒是峰值最大交易量还是持续交易量?
2、3万笔/每秒是同一类型的订单还是诸多种类型的订单?
3、业务能否做拆分,例如从功能、从区域、从优先级等角度?
4、支付订单是实时交易还是非实时交易,能否延时入库?
5、支付订单能否延时批量处理?
6、支付订单是否涉及热点账户问题,也即对同一账户会有多个并发请求对其属性(例如账户余额)进行操作?
由此可以展开诸多优化策略,不在此处细述。
以前写过一篇 交易系统“热点账户”处理 ,供参考

知乎回答原文链接:http://www.zhihu.com/question/27590048/answer/38025567

交易系统和风控系统的架构怎么设计?

Posted in 电子商务&互联网金融, 技术相关, 产品管理 by chuanliang on 2015/01/19

我在知乎就《交易系统和风控系统的架构怎么设计?》做的回答。

交易系统和风控系统从架构角度设计,是应该设计成两个单独的系统,题主提到的问题,本质在于交易系统和风控系统之间数据共享及服务调用的问题。
一般通过如下几个层面来降低交易系统、风控系统的耦合度,提升系统性能和扩展性:读写分离、缓存/内存数据库、SOA架构、复合事件处理
数据库读写分离机制:在初期,风控系统一般都极为简单,此时侯一般通过数据库主从复制/读写分离/Sharding等机制来保证交易系统的数据库和风控系统数据的同步及读写分离。风控系统对所需要的客户/账户数据、交易数据一般都只进行读操作。
缓存/内存数据库机制:不 管是交易系统还是风控系统,高效的缓存系统是提升性能的大杀器,一般会把频繁使用的数据存放到Redis等缓存系统中。例如对风控系统,包括诸如风控规 则、风控案例库、中间结果集、黑白名单、预处理结果等数据;对交易系统而言,包括诸如交易参数、计费模板、清结算规则、分润规则、银行路由策略等。对一些 高频交易中,基于性能考虑,会采用内存数据库(一般会结合SSD硬盘)。
RPC/SOA架构:要降低交易系统和风控系统的 耦合度,在初期系统服务较少的情况下,一般直接采用RabbitMQ/ActiveMQ之类的消息中间件或RPC方式来实现系统间服务的调用。如果系统服 务较多,存在服务治理问题,会采用Dubbo之类的SOA中间件来实现系统服务调用。
复合事件处理(CEP):对实时/准实时交易风险控制,相对于纯基于规则的处理模式,采用复合事件处理(CEP)模式,性能及扩展性更好,开源的方案包括Esper、Storm、Spark等。
从风控系统构建角度,对应所谓的事前、事中、事后风险控制,作为风控系统最核心的风控引擎分为实时风控引擎、准实时风控引擎、定时风控引擎三种:
1、实时风控引擎&准实时风控引擎
实时风控主要在交易过程对交易过程进行实时监控,一个典型应用场景是甄别钓鱼、盗卡风险。
准实时风控典型应用场景是在T+1结算时候,对商户洗钱、跑路进行甄别。
实时/准实时风控引擎一般采用规则引擎+复杂事件处理(CEP)。
2、定时风控引擎
主要定时对支付/交易/账务等数据进行定时ETL、深度挖掘等处理,建立对应的风控模型,一个典型应用场景是商户的信用等级模型。此时侯一般采用Hadoop、ML等技术进行大数据建模
以前写过两篇关于第三方支付风控系统建设的文章,供参考
支付系统风控系统建设思考
复杂事件处理(Complex Event Processing)入门1

 

知乎回答原文链接:http://www.zhihu.com/question/20860347/answer/36328342

开发一个业务逻辑复杂的系统,应该怎么样设计才能使项目的扩展性更好?

Posted in 技术相关, 产品管理 by chuanliang on 2014/11/24

我在知乎关于《开发一个业务逻辑复杂的系统,应该怎么样设计才能使项目的扩展性更好?》做的回答。

既然业务逻辑复杂,那意味着项目前期的业务建模、需求分析、分析设计极为重要,直接抛开这几个阶段进入技术实施开发阶段,不管套用什么设计模式、架构模式,系统的扩展性肯定难以保证。
项目的扩展性虽然最终体现为系统架构、技术实现的扩展性,但系统扩展性的根源在于系统业务架构及业务模型的扩展性。大家经常骂xx系统烂、扩展性差,大都将原因归结为技术实现烂,但总结那些成功的大型项目或产品的最佳实践,原因都会有:某某是业务专家,对xx业务很熟悉,能够衔接业务与技术。因此一个好的项目角色中,应该有行业专家/领域专家、业务过程分析师、系统分析师、软件架构师等角色,从业务架构、信息架构、技术架构保证系统的扩展性。

具体怎样进行业务建模,搭建良好的业务架构和业务模型,从而为技术架构、信息架构、技术实现奠定良好基础,有一些较为成熟的软件开发过程可供参考。例如 RUP(Rational Unified Process,统一软件开发过程)。一个标准的RUP工作流程包括:业务建模,需求分析,分析设计,实施开发,测试,部署,配置和变更管理,项目管理,环境。当然RUP只是一个方法论,且过于庞大,大部分项目很难完整执行其过程,需要根据实际情况进行裁剪,但其方法论对于复杂业务逻辑系统的建设具有指导意义。像互联网产品设计中常用的用例分析技术就源于RUP。

因此对于题主描述的一个复杂系统,标准的过程应当在业务建模,需求分析,分析设计,实施开发,测试,部署完整过程的分析设计(与开发语言无关)或实施开发(分析设计的成果映射为具体语言,例如Java、.NET等)阶段才考虑设计模式、架构模式的引入。设计模式的使用会经历僵化->固化->优化的阶段,类似禅修中“看山是山、看水是水”的三个阶段,才能体会模式的运用之妙。

值得强调的是:如果是偏交易(例如支付、金融)的系统,在考虑扩展性时候,一定要将信息架构、信息模型的扩展性纳入到考虑范围,此类系统数据模型至关重要,也不可能频繁变动。

上面描述方法的特别适用与传统软件、系统集成等需求偏稳定的项目,对于互联网偏创新性的项目就不一定完全适用了,此类项目的现实情况如下:业务模式不确定,会不停试错,验证模式;需求不停变化,要求能够快速响应;全新的行业,没有行业专家,没有行业标杆可借鉴(至多有跨界标杆可参考);此时候,类似精益创业、Scrum之类的敏捷开发模式更适合,但对于复杂的业务而言,业务建模->需求分析->分析设计的理念仍然值得参考借鉴。

最后,最最重要的是:完美系统的架构和扩展性是管理出来的、持续重构出来的。正如各大城市马路不停翻了再修、修了再翻的命运一样,中国大部分公司后任会不停否定掉前任的架构、系统,推倒再来一遍,然后等新系统刚开发出来不久,尚未上线或上线运营一段时间后,再换一帮人继续折腾,然后。。。

总结这么多年的经历,深刻体会到:再烂的系统和架构,如果能够强化管理、持续积累、持续重构、持续完善,都能够有机会成为完美的系统,完美的系统不在于其架构的牛逼和完美,而在于:符合公司的业务模式,能够完美支撑公司业务的高速发展和市场需求的快速响应。

 

http://www.zhihu.com/question/26731781/answer/33906943

手机密号的原理是什么?

Posted in 移动互联网, 技术相关 by chuanliang on 2014/11/24

在知乎就《手机密号的原理是什么? 之前有安卓和微信版本,现在又有苹果版本了,它的实现原理是什么呢?》做的回答。

手机密号的功能并无太多新颖的东西,像58同城、赶集等也推过类似服务。这里大致说一下自己理解的主要技术,做过呼叫中心、VOIP的比较擅长。
类似服务一般涉及用户、互联网服务提供商、云呼叫中心服务提供商、电信运营商几个角色。
1、 互联网服务提供商:例如58同城之类,由于专业分工原因,互联网服务提供商一般是采用第三方云呼叫中心服务提供商提供的VOIP服务。像手机密号的功能, 诸如注册、微信绑定等功能属于互联网服务提供商的业务功能,而临时性虚拟号码的分配、外呼是由云呼叫中心服务提供商提供的,当然。
2、 云呼叫中心服务提供商:一般采用类似asterisk之类的VOIP及软交换开源项目进行改造,对外提供云呼叫中心服务。与传统呼叫中心基于语音+PBX 不同,一般采用IP+软交换方案。可以参考一下合力金桥、讯鸟的方案。当然云呼叫中心服务提供商也可以扮演互联网服务提供商角色。
3、运营商:为云呼叫中心提供号码池、外呼中继等相关服务。在运营商那端有一堆主叫号码池和外呼中继,这样使用手机密号用户注册绑定后会从不同的主叫池中选择分配(或者动态分配)一个不同的主叫号码并外呼出去。没错,与VOIP透传之类的套路一样。

 

http://www.zhihu.com/question/24816198/answer/29088983