智能合约定义业务对象的不同状态,并控制对象在这些不同状态之间转换的过程。
@Contract(...)
@Default
public class CommercialPaperContract implements ContractInterface {...}
@Contract注释为提供关于合约额外的信息提供了可能,比如许可、作者等。@Default注释将这个合约类声明为默认的合约类,这种做法在由多个合约类的智能合约中很有用。
import org.hyperledger.fabric.contract.Context;
import org.hyperledger.fabric.contract.ContractInterface;
import org.hyperledger.fabric.contract.annotation.Contact;
import org.hyperledger.fabric.contract.annotation.Contract;
import org.hyperledger.fabric.contract.annotation.Default;
import org.hyperledger.fabric.contract.annotation.Info;
import org.hyperledger.fabric.contract.annotation.License;
import org.hyperledger.fabric.contract.annotation.Transaction;
导入需要的类、注释、Context类。
通常一个文件中只有一个智能合约,因为不同的合约有不同的生命周期,所以最好将它们分开。然而有时,多智能合约能为应用程序提供语法的帮助,比如EuroBond,DollarBond,YenBond,但是本质上提供相同的函数。
@Transaction
public CommercialPaper issue(CommercialPaperContext ctx,
String issuer,
String paperNumber,
String issueDateTime,
String maturityDateTime,
int faceValue) {...}
@Transaction注释标注了这个方法是transaction定义。当应用程序请求issue一个商业票据的时候,该方法会自动调用,通过相应的变量传递对应的值。transaction context总是transaction方法的第一个参数,默认的,context包括了许多与transaction逻辑相关的信息。下面显示了这个智能合约如何通过实现自己的createContext()方法扩展默认的transaction context,而不是用默认的实现。
@Override
public Context createContext(ChaincodeStub stub) {
return new CommercialPaperContext(stub);
}
这个扩展的context在默认的基础上添加了一个自定义的属性paperList。
class CommercialPaperContext extends Context {
public CommercialPaperContext(ChaincodeStub stub) {
super(stub);
this.paperList = new PaperList(this);
}
public PaperList paperList;
}
buy方法和redeem方法。
@Transaction
public CommercialPaper buy(CommercialPaperContext ctx,
String issuer,
String paperNumber,
String currentOwner,
String newOwner,
int price,
String purchaseDateTime) {...}
@Transaction
public CommercialPaper redeem(CommercialPaperContext ctx,
String issuer,
String paperNumber,
String redeemingOwner,
String redeemDateTime) {...}
issue方法:
@Transaction
public CommercialPaper issue(CommercialPaperContext ctx,
String issuer,
String paperNumber,
String issueDateTime,
String maturityDateTime,
int faceValue) {
System.out.println(ctx);
// 创建一个paper对象
CommercialPaper paper = CommercialPaper.createInstance(issuer, paperNumber, issueDateTime, maturityDateTime,
faceValue,issuer,"");
// 将paper设置为issued状态
paper.setIssued();
// 设置paper的拥有者,新发行的拥有者为issuer
paper.setOwner(issuer);
System.out.println(paper);
// 将paper加入账本世界状态类似的paper的列表中
ctx.paperList.addPaper(paper);
// 返回paper
return paper;
}
buy方法:
@Transaction
public CommercialPaper buy(CommercialPaperContext ctx,
String issuer,
String paperNumber,
String currentOwner,
String newOwner,
int price,
String purchaseDateTime) {
// 通过下面代码从list中取回当前paper
String paperKey = State.makeKey(new String[] { paperNumber });
CommercialPaper paper = ctx.paperList.getPaper(paperKey);
// 验证当前的owner
if (!paper.getOwner().equals(currentOwner)) {
throw new RuntimeException("Paper " + issuer + paperNumber + " is not owned by " + currentOwner);
}
// 首先buy方法将状态从issued转换为trading
if (paper.isIssued()) {
paper.setTrading();
}
// 检查paper是否已经赎回
if (paper.isTrading()) {
paper.setOwner(newOwner);
} else {
throw new RuntimeException(
"Paper " + issuer + paperNumber + " is not trading. Current state = " + paper.getState());
}
// 更新paper
ctx.paperList.updatePaper(paper);
return paper;
}
redeem方法:
@Transaction
public CommercialPaper redeem(CommercialPaperContext ctx, String issuer, String paperNumber, String redeemingOwner,
String redeemDateTime) {
String paperKey = CommercialPaper.makeKey(new String[] { paperNumber });
CommercialPaper paper = ctx.paperList.getPaper(paperKey);
// 验证paper是否被赎回
if (paper.isRedeemed()) {
throw new RuntimeException("Paper " + issuer + paperNumber + " already redeemed");
}
// 确定被赎回的人在进行赎回前是paper的owner
if (paper.getOwner().equals(redeemingOwner)) {
paper.setOwner(paper.getIssuer());
paper.setRedeemed();
} else {
throw new RuntimeException("Redeeming owner does not own paper" + issuer + paperNumber);
}
ctx.paperList.updatePaper(paper);
return paper;
}
CommercialPaper类继承自State类。State类是一个应用定义的类,它创建了一个通用的状态抽象。所有的状态都有一个对应表示的业务对象,一个复合键,可以序列化或者去序列化。State在有多个业务对象在账本上时使代码更加清晰。
CommercialPaper类中主要定义了私有数据和一些简单的接口。
PaperList类用来管理fabric状态数据库中的所有商业票据,和CommercialPaper类一样,这个类也继承自一个应用程序定义的,用于为状态列表建立一个通用的抽象的类——StateList。
账本中的每一个状态数据都由两个基本元素构成:
Key:key由createCompositeKey()使用固定的名字和状态的key形成。在PaperList对象形成时key的名称分配完成,state.getSplitKey()决定每个状态的唯一key。
Data:data是通过State.serialize()方法建立的商业票据状态的序列化形式。State类通过JSON进行序列化和反序例化。
我的理解是PaperList感觉像是逻辑上的一个结构,具体的实现还是交给账本数据库和fabric API。