本文记录一下,如何写一个可以在sawtooth区块链中可用的智能合约(sawtooth里叫processor).
建一个项目,目录结构如下:
![](https://img.haomeiwen.com/i13099157/ebd3d852a3b5354a.png)
这两我们将使用docker的方式,同sawtooth的其它服务一起部署。 在InteliJ中开发并部署Docker的环境配置可以参考Docker自动部署.
这里我们将创建两个类: CertificationProcessor, certificationHandler.
CertificationProcessor: 是处理器入口, 实例化一个sawtooth.sdk.processor.TransactionProcessor, 监听来自 validator:4004 的MQ消息, TransactionProcessor 注册 certificationHandler 用于实际的业务处理。
package com.lifeccp.certification.processor;
import sawtooth.sdk.processor.TransactionHandler;
import sawtooth.sdk.processor.TransactionProcessor;
import com.lifeccp.certification.processor.CertificationHandler;
public class CertificationProcessor {
/**
* the method that runs a Thread with a TransactionProcessor in it.
*/
public static void main(String[] args) {
System.out.println("start processor !");
TransactionProcessor transactionProcessor =new TransactionProcessor(args[0]);
transactionProcessor.addHandler(new CertificationHandler());
Thread thread =new Thread(transactionProcessor);
thread.start();
}
}
在Handler 里我们需要实现TransactionHandler 定义的一些接口, 一方面注册时候告诉自己能处理哪个sawtooth bussiness familly, 另一方面实现具体的处理。
package com.lifeccp.certification.processor;
import sawtooth.sdk.processor.State;
import sawtooth.sdk.processor.TransactionHandler;
import sawtooth.sdk.processor.Utils;
import sawtooth.sdk.processor.exceptions.InternalError;
import sawtooth.sdk.processor.exceptions.InvalidTransactionException;
import sawtooth.sdk.protobuf.TpProcessRequest;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.logging.Logger;
public class CertificationHandlerimplements TransactionHandler {
private final Loggerlogger = Logger.getLogger(TransactionHandler.class.getName());
private StringcertNameSpace;
public CertificationHandler() {
System.out.println("start handler");
try {
this.certNameSpace = Utils.hash512(
this.transactionFamilyName().getBytes("UTF-8")).substring(0,6);
}catch (UnsupportedEncodingException usee) {
usee.printStackTrace();
this.certNameSpace ="";
}
}
@Override
public String transactionFamilyName() {
return "Doctor Certification familly";
}
@Override
public String getVersion() {
return "1.0";
}
@Override
public Collection getNameSpaces() {
ArrayList namespaces =new ArrayList<>();
namespaces.add(this.certNameSpace);
return namespaces;
}
@Override
public void apply(TpProcessRequest transactionRequest, State state)throws InvalidTransactionException, InternalError {
//get certification payload
logger.info("enter into processor");
// Tranlate to java Ojbejct
//valid the integration of certification
// update state
//emit event
}
}
我们注册了Doctor Certification familly的业务处理器, 实际只打出了一航信息,告知我们,已经进来了。
Demo代码很简单,实际的业务处理将在后文讨论, 这里我们接着要处理的是打包。有两个文件很重要:
build.gradle 我们需要用它来生成docker image.
Dockerfile 实际生成Image的定义文件。
build.gradle 文件定义:
需要注意的是,我们准备把新的代码,打成Jar包, 在和其它以来以其部署到Docker中, 这里我们将用到果然啊gradle Application 插件,需要注意的是Jar包的应以,确保名称小写。
jar{
archiveBaseName='certificationprocessor'
archiveVersion='1.0.0'
manifest{
attributes'Implementation-Title':'Application',
'Implementation-Version':'1.0.0',
'Main-Class':'com.lifeccp.certification.processor.CertificationProcessor'
}
application配置中也需要定义小写和程序入口。
application{
applicationName ='certificationprocessor'
mainClassName ='com.lifeccp.certification.processor.CertificationProcessor'
}
最后,我们将用Application生成Tar包使用Docker插件,打出Image。需要注意,我们需要将distTar任务生成的结果考到Docker的工作环境stageDir。
task buildDocker(type: Docker,dependsOn: build){
applicationName ='certificationprocessor'
tagVersion='1.0.0'
dockerfile = file('Dockerfile')
doFirst{
copy{
from distTar
into stageDir
}
}
}
build.gradle的全文参考:
=========================================================
buildscript{
repositories{
jcenter()
mavenCentral()
maven{url"https://maven.aliyun.com/repository/central"}
maven{ url"https://plugins.gradle.org/m2/" }
}
dependencies{
classpath'com.google.protobuf:protobuf-gradle-plugin:0.8.12'
classpath'se.transmode.gradle:gradle-docker:1.2'
}
}
plugins{
id'io.spring.dependency-management' version'1.0.9.RELEASE'
id'java'
}
applyplugin:'java'
applyplugin:'application'
applyplugin:'docker'
group ='com.lifeccp'
version ='1.0.0'
sourceCompatibility ='1.8'
configurations{
developmentOnly
runtimeClasspath{
extendsFrom developmentOnly
}
}
repositories{
mavenCentral()
maven{url"https://maven.aliyun.com/repository/central"}
}
jar{
archiveBaseName='certificationprocessor'
archiveVersion='1.0.0'
manifest{
attributes'Implementation-Title':'Application',
'Implementation-Version':'1.0.0',
'Main-Class':'com.lifeccp.certification.processor.CertificationProcessor'
}
}
dependencies{
compile(
'com.google.protobuf:protobuf-java:3.10.0',
'org.hyperledger.sawtooth:sawtooth-sdk-transaction-processor:v0.1.2',
'org.apache.commons:commons-lang3:3.0',
'org.web3j:core:4.5.12'
)
}
/**
distDocker {
applicationName = 'certificationprocessor'
tagVersion='1.0.0'
dockerfile = file('Dockerfile')
}
**/
application{
applicationName ='certificationprocessor'
mainClassName ='com.lifeccp.certification.processor.CertificationProcessor'
}
test{
useJUnitPlatform()
}
task buildDocker(type: Docker,dependsOn: build){
applicationName ='certificationprocessor'
tagVersion='1.0.0'
dockerfile = file('Dockerfile')
doFirst{
copy{
from distTar
into stageDir
}
}
}
=====================================================================================
DockerFile的全文定义:
DockerFile比较简单, 这里直接列出定义,需要注意的是,有必要根据连接的Docker仓库,更换From语句中的java基础镜像。
FROM daocloud.io/library/java:8-alpine
MAINTAINER Charles Lin"348703698@qq.com"
ADD certificationprocessor-1.0.0.tar/usr/src/myapp
WORKDIR /usr/src/myapp
RUN sh-c'touch certificationprocessor-1.0.0.tar'
ENTRYPOINT ["sh","-c","certificationprocessor-1.0.0/bin/CertificationProcessor tcp://validator:4004" ]
docker 将和其他sawtooth 组建一起部署到同一网络中, 默认需要连接validator的4004端口。
![](https://img.haomeiwen.com/i13099157/e4e5af2cd3e08624.png)
执行BuildDocker任务,自动生成Docker。通过服务视窗连接到Docker Damon,可以查看到新增加的Image。
![](https://img.haomeiwen.com/i13099157/3f2fc0ac3089d3b0.png)
现在根据sawtooth开发指南的内容在开发环境启动所有组建。一切正常的话会打出信息。
![](https://img.haomeiwen.com/i13099157/f678c4faaabc1a07.png)
现在我们手动启动新增加的certprocessor处理器。启动命令如下。
![](https://img.haomeiwen.com/i13099157/a1353e3b57545ae4.png)
从客户端发送一个第三方前面签名的请求。
![](https://img.haomeiwen.com/i13099157/73fe9d6e6578fb0e.png)
我们的处理器将接受到请求,并打印出日志:
![](https://img.haomeiwen.com/i13099157/39861fb704270ea9.png)
网友评论