智能合約定義業務對象的不同狀態,並控制對象在這些不同狀態之間轉換的過程。
1、Contract類
@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,但是本質上提供相同的函數。
2、Transaction定義
@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) {...}
3、transaction邏輯
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;
}
4、CommercialPaper類
CommercialPaper類繼承自State類。State類是一個應用定義的類,它創建了一個通用的狀態抽象。所有的狀態都有一個對應表示的業務對象,一個複合鍵,可以序列化或者去序列化。State在有多個業務對象在賬本上時使代碼更加清晰。
CommercialPaper類中主要定義了私有數據和一些簡單的接口。
5、PaperList類
PaperList類用來管理fabric狀態數據庫中的所有商業票據,和CommercialPaper類一樣,這個類也繼承自一個應用程序定義的,用於爲狀態列表建立一個通用的抽象的類——StateList。
賬本中的每一個狀態數據都由兩個基本元素構成:
Key:key由createCompositeKey()使用固定的名字和狀態的key形成。在PaperList對象形成時key的名稱分配完成,state.getSplitKey()決定每個狀態的唯一key。
Data:data是通過State.serialize()方法建立的商業票據狀態的序列化形式。State類通過JSON進行序列化和反序例化。
我的理解是PaperList感覺像是邏輯上的一個結構,具體的實現還是交給賬本數據庫和fabric API。