2021SC@SDUSC
目次
1.契約モデルのインターフェース
1.ContractAware
コントラクトによって実装されたサブインターフェイスは、実行時にライフサイクル イベントをリッスンできます。
public interface ContractAware {
}
2.ContractEventContext
インターフェイスは HashDigest インターフェイスをインポートし、このメソッドを使用して現在のレジャー ハッシュを取得します。
HashDigest getCurrentLedgerHash();
契約イベントのトランザクション要求の実行
TransactionRequest getTransactionRequest();
このコードは、トランザクションの署名者のセットを返します
Set<BlockchainIdentity> getTxSigners();
コードはイベント名を返します
String getEvent();
コードはパラメータ リストを返します
BytesValueList getArgs();
台帳操作のコンテキスト
LedgerContext getLedger();
契約所有者のコレクション、契約所有者は、契約に署名する際の署名者のコレクションです。
Set<BlockchainIdentity> getContractOwners();
各コントラクトまたはレジャーには最新バージョンを取得するためのメソッドが必要であり、このメソッドはコントラクトの最新バージョンを取得するために使用されます。
long getVersion();
現在、コミットされていないブロック データ台帳操作コンテキストが含まれています。
LedgerQueryService getUncommittedLedger();
3.ContractLifeCycleAware
コントラクトは、このインターフェースを実装して、コントラクト アプリケーションのライフ サイクル イベントを監視します。
public interface ContractLifecycleAware extends ContractAware {
void postConstruct();
void beforeDestroy();
}
4.契約処理者
これは、主に契約の合法性の検証、契約の分析、および契約のエントリと逆コンパイルの提供に使用される、契約プロセッサのインターフェイスです。
契約の有効性の検証。1 つ目は検証するユーザー名を入力することです。この方法ではフィードバック メッセージが表示されます。2 つ目はブロック パスワードを入力することで、フィードバックも得られます。
boolean verify(File carFile) throws Exception;
boolean verify(byte[] chainCode) throws Exception;
この2つの方法が契約の締結であり、それぞれユーザー名とパスワードを入力することで契約を締結することができます。
ContractEntrance analyse(File carFile) throws Exception;
ContractEntrance analyse(byte[] chainCode) throws Exception;
これら2つは逆コンパイルされたエントリです
String decompileEntranceClass(File carFile) throws Exception;
String decompileEntranceClass(byte[] chainCode) throws Exception;
2. コントラクト モデルのクラス
1.契約の種類
ここにそのインポートがあります
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import com.jd.blockchain.ledger.BytesValueEncoding;
import utils.IllegalDataException;
クラスが 3 つのプライベート変数、つまりコントラクト名とコントラクトの 2 つのハッシュ マップを作成したことがわかります。
private String name;
private Map<String, Method> events = new HashMap<>();
private Map<Method, String> handleMethods = new HashMap<>();
このメソッドは、コントラクトの名前を取得するために使用されます。
public String getName() {
return name;
}
メソッドは、宣言されたすべてのイベントを返します
public Set<String> getEvents() {
return events.keySet();
}
コードは、指定されたメソッドによって宣言されたイベントを返します。存在しない場合は null を返します。
public String getEvent(Method method) {
return handleMethods.get(method);
}
コードはイベント処理メソッドを返します。そうでない場合は null を返します
public Method getHandleMethod(String event) {
return events.get(event);
}
コントラクトの宣言を解析し、コントラクトのコンテンツ コードを入力してその解析作業を実行します。メソッドはまず、コントラクト メソッド宣言の型と戻り値の型をチェックします。クラスの場合は、まずそのインターフェイスを取得します。コードが長すぎるので他の部分にします 分析はコメントに書いてあります
public static ContractType resolve(Class<?> contractIntf) {
if (!contractIntf.isInterface()) {
Class<?> realIntf = null;
Class<?>[] interfaces = contractIntf.getInterfaces();
for (Class<?> intf : interfaces) {
if (intf.isAnnotationPresent(Contract.class)) {
realIntf = intf;
break;
}
}
if (realIntf == null) {
throw new IllegalDataException(String
.format("%s is not a Contract Type, because there is not @Contract !", contractIntf.getName()));
}
contractIntf = realIntf;
}
// 接口上必须有注解
Contract contract = contractIntf.getAnnotation(Contract.class);
if (contract == null) {
throw new IllegalDataException("It is not a Contract Type, because there is not @Contract !");
}
Method[] classMethods = contractIntf.getDeclaredMethods();
if (classMethods.length == 0) {
throw new IllegalDataException("This interface have not any methods !");
}
ContractType contractType = new ContractType();
// 设置合约显示名字为
contractType.name = contract.name();
for (Method method : classMethods) {
// if current method contains @ContractEvent,then put it in this map;
ContractEvent contractEvent = method.getAnnotation(ContractEvent.class);
if (contractEvent != null) {
String eventName = contractEvent.name();
// if annoMethodMap has contained the eventName, too many same eventNames exists
// probably, say NO!
if (contractType.events.containsKey(eventName)) {
throw new ContractException("there is repeat definition of contractEvent to @ContractEvent.");
}
// check param's type is fit for need.
Class<?>[] paramTypes = method.getParameterTypes();
for (Class<?> currParamType : paramTypes) {
if (!BytesValueEncoding.supportType(currParamType)) {
throw new IllegalStateException(
String.format("Param Type = %s can not support !!!", currParamType.getName()));
}
}
// 判断返回值是否可序列化
Class<?> returnType = method.getReturnType();
if (!BytesValueEncoding.supportType(returnType)) {
throw new IllegalStateException(
String.format("Return Type = %s can not support !!!", returnType.getName()));
}
contractType.events.put(eventName, method);
contractType.handleMethods.put(method, eventName);
}
}
// 最起码有一个ContractEvent
if (contractType.events.isEmpty()) {
throw new IllegalStateException(
String.format("Contract Interface[%s] have none method for annotation[@ContractEvent] !", contractIntf.getName()));
}
return contractType;
}
このコードは契約タイプを返します
public String toString() {
return "ContractType{" + "name='" + name + '\'' + ", events=" + events + ", handleMethods=" + handleMethods
+ '}';
}
2.ContractJarUtils
このクラスは、最初にこれらの変数と固定値を定義します。これは次のメソッドで使用します。
public static final String BLACK_CONF = "filter.black.conf";
private static final String CONTRACT_MF = "META-INF/CONTRACT.MF";
private static final Random FILE_RANDOM = new Random();
private static final byte[] JDCHAIN_MARK = "JDChain".getBytes(StandardCharsets.UTF_8);
public static final String JDCHAIN_PACKAGE = "com.jd.blockchain";
このメソッドは、パッケージがjdchainパッケージであるかどうかを判断するために使用され、パッケージの名前を入力し、コードは条件文によって判断され、そうであればtrueを返し、そうでなければJDCHAIN_PACKAGEを返します。
public static boolean isJDChainPackage(String packageName) {
if (packageName.equals(JDCHAIN_PACKAGE)) {
return true;
}
return packageName.startsWith(JDCHAIN_PACKAGE + ".");
}
このメソッドはコントラクトの構成問題を解決します. ファイルの名前を入力すると, メソッドは新しい配列リストを作成し, 対応するファイルをメソッドにインポートし, それが空かどうかを判断します. 空でない場合, の各文The file will be looped, and then add the "," delimiter will be loaded into a list created at the beginning of code. ファイルが空の場合は、エラー メッセージが返されます。
public static List<String> resolveConfig(String fileName) {
List<String> configs = new ArrayList<>();
try {
List<String> readLines = loadConfig(fileName);
if (!readLines.isEmpty()) {
for (String readLine : readLines) {
String[] lines = readLine.split(",");
configs.addAll(Arrays.asList(lines));
}
}
} catch (Exception e) {
throw new IllegalStateException(e);
}
return configs;
}
このメソッドは、入力ファイルの名前でもあるコントラクトの構成をロードするために使用され、コードは I OUTils でメソッドを呼び出してファイル情報を出力します。
public static List<String> loadConfig(String fileName) throws Exception {
return IOUtils.readLines(
ContractJarUtils.class.getResourceAsStream(File.separator + fileName));
}
このコードは、すべてのクラスをロードし、ファイルの jar パッケージを入力するために使用され、メソッドのループに入り、要素を取得し、名前を取得し、名前を確認した後、クラス情報を連続して出力できます。
public static Map<String, byte[]> loadAllClasses(final File jar) throws Exception {
Map<String, byte[]> allClasses = new HashMap<>();
JarFile jarFile = new JarFile(jar);
Enumeration<JarEntry> jarEntries = jarFile.entries();
while(jarEntries.hasMoreElements()){
JarEntry jarEntry = jarEntries.nextElement();
String entryName = jarEntry.getName();
if (verify(entryName)) {
byte[] classContent = readStream(jarFile.getInputStream(jarEntry));
if (classContent != null && classContent.length > 0) {
allClasses.put(entryName, classContent);
}
}
}
jarFile.close();
return allClasses;
}
このメソッドは、エントリ名を確認するために使用されます
private static boolean verify(String entryName) {
if (entryName.endsWith(".class")
&& !entryName.startsWith("META-INF")
&& !entryName.contains("-")
&& entryName.contains("/")) {
return true;
}
return false;
}
このメソッドは、クラスの前にドット (.) を追加するために使用されます。
public static String dotClassName(String className) {
String dotClassName = className;
if (className.endsWith(".class")) {
dotClassName = className.substring(0, className.length() - 6);
}
dotClassName = dotClassName.replaceAll("/", ".");
return dotClassName;
}
このメソッドは、ファイルなどのさまざまな jar を入力して、契約内の情報をコピーします。
public static void copy(File srcJar, File dstJar, JarEntry addEntry, byte[] addBytes, String filter) throws IOException {
JarFile jarFile = new JarFile(srcJar);
Enumeration<JarEntry> jarEntries = jarFile.entries();
JarOutputStream jarOut = new JarOutputStream(new BufferedOutputStream(new FileOutputStream(dstJar)));
while(jarEntries.hasMoreElements()){
JarEntry jarEntry = jarEntries.nextElement();
String entryName = jarEntry.getName();
if (filter != null && filter.equals(entryName)) {
continue;
}
jarOut.putNextEntry(jarEntry);
jarOut.write(readStream(jarFile.getInputStream(jarEntry)));
jarOut.closeEntry();
}
if (addEntry != null) {
jarOut.putNextEntry(addEntry);
jarOut.write(addBytes);
jarOut.closeEntry();
}
jarOut.flush();
jarOut.finish();
jarOut.close();
jarFile.close();
}