@@ -4,7 +4,7 @@ import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.crypto.PubKey; | |||
import com.jd.blockchain.ledger.AccountHeader; | |||
import com.jd.blockchain.ledger.BytesValue; | |||
import com.jd.blockchain.ledger.BytesValueEntry; | |||
import com.jd.blockchain.ledger.BytesData; | |||
import com.jd.blockchain.utils.Bytes; | |||
public class ContractAccount implements AccountHeader { | |||
@@ -43,7 +43,7 @@ public class ContractAccount implements AccountHeader { | |||
} | |||
public long setChaincode(byte[] chaincode, long version) { | |||
BytesValue bytesValue = BytesValueEntry.fromBytes(chaincode); | |||
BytesValue bytesValue = BytesData.fromBytes(chaincode); | |||
return accBase.setBytes(CHAIN_CODE_KEY, bytesValue, version); | |||
} | |||
@@ -60,18 +60,18 @@ public class ContractAccount implements AccountHeader { | |||
} | |||
public long setProperty(Bytes key, String value, long version) { | |||
BytesValue bytesValue = BytesValueEntry.fromText(value); | |||
BytesValue bytesValue = BytesData.fromText(value); | |||
return accBase.setBytes(encodePropertyKey(key), bytesValue, version); | |||
} | |||
public String getProperty(Bytes key) { | |||
BytesValue bytesValue = accBase.getBytes(encodePropertyKey(key)); | |||
return BytesValueEntry.toText(bytesValue); | |||
return BytesData.toText(bytesValue); | |||
} | |||
public String getProperty(Bytes key, long version) { | |||
BytesValue bytesValue = accBase.getBytes(encodePropertyKey(key), version); | |||
return BytesValueEntry.toText(bytesValue); | |||
return BytesData.toText(bytesValue); | |||
} | |||
private Bytes encodePropertyKey(Bytes key) { | |||
@@ -6,7 +6,7 @@ import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.crypto.PubKey; | |||
import com.jd.blockchain.ledger.AccountHeader; | |||
import com.jd.blockchain.ledger.BytesValue; | |||
import com.jd.blockchain.ledger.BytesValueEntry; | |||
import com.jd.blockchain.ledger.BytesData; | |||
import com.jd.blockchain.ledger.KVDataEntry; | |||
import com.jd.blockchain.ledger.KVDataObject; | |||
import com.jd.blockchain.utils.Bytes; | |||
@@ -49,12 +49,12 @@ public class DataAccount implements AccountHeader, MerkleProvable { | |||
public long setBytes(Bytes key, String value, long version) { | |||
BytesValue bytesValue = BytesValueEntry.fromText(value); | |||
BytesValue bytesValue = BytesData.fromText(value); | |||
return baseAccount.setBytes(key, bytesValue, version); | |||
} | |||
public long setBytes(Bytes key, byte[] value, long version) { | |||
BytesValue bytesValue = BytesValueEntry.fromBytes(value); | |||
BytesValue bytesValue = BytesData.fromBytes(value); | |||
return baseAccount.setBytes(key, bytesValue, version); | |||
} | |||
@@ -3,7 +3,7 @@ package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.crypto.PubKey; | |||
import com.jd.blockchain.ledger.BytesValue; | |||
import com.jd.blockchain.ledger.BytesValueEntry; | |||
import com.jd.blockchain.ledger.BytesData; | |||
import com.jd.blockchain.ledger.UserInfo; | |||
import com.jd.blockchain.utils.Bytes; | |||
@@ -50,12 +50,12 @@ public class UserAccount implements UserInfo { | |||
public long setDataPubKey(PubKey pubKey) { | |||
byte[] pkBytes = pubKey.toBytes(); | |||
return baseAccount.setBytes(DATA_PUB_KEY, BytesValueEntry.fromBytes(pkBytes), -1); | |||
return baseAccount.setBytes(DATA_PUB_KEY, BytesData.fromBytes(pkBytes), -1); | |||
} | |||
public long setDataPubKey(PubKey pubKey, long version) { | |||
byte[] pkBytes = pubKey.toBytes(); | |||
return baseAccount.setBytes(DATA_PUB_KEY, BytesValueEntry.fromBytes(pkBytes), version); | |||
return baseAccount.setBytes(DATA_PUB_KEY, BytesData.fromBytes(pkBytes), version); | |||
} | |||
public long setProperty(String key, String value, long version) { | |||
@@ -63,7 +63,7 @@ public class UserAccount implements UserInfo { | |||
} | |||
public long setProperty(Bytes key, String value, long version) { | |||
return baseAccount.setBytes(encodePropertyKey(key), BytesValueEntry.fromText(value), version); | |||
return baseAccount.setBytes(encodePropertyKey(key), BytesData.fromText(value), version); | |||
} | |||
public String getProperty(Bytes key) { | |||
@@ -8,7 +8,7 @@ import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.AccountHeader; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.BytesValue; | |||
import com.jd.blockchain.ledger.BytesValueEntry; | |||
import com.jd.blockchain.ledger.BytesData; | |||
import com.jd.blockchain.ledger.DataAccountKVSetOperation; | |||
import com.jd.blockchain.ledger.DataAccountRegisterOperation; | |||
import com.jd.blockchain.ledger.KVDataEntry; | |||
@@ -279,7 +279,7 @@ public class ContractLedgerContext implements LedgerContext { | |||
@Override | |||
public DataAccountKVSetOperationBuilder setText(String key, String value, long expVersion) { | |||
BytesValue bytesValue = BytesValueEntry.fromText(value); | |||
BytesValue bytesValue = BytesData.fromText(value); | |||
this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion); | |||
handle(op); | |||
return this; | |||
@@ -287,7 +287,7 @@ public class ContractLedgerContext implements LedgerContext { | |||
@Override | |||
public DataAccountKVSetOperationBuilder setBytes(String key, Bytes value, long expVersion) { | |||
BytesValue bytesValue = BytesValueEntry.fromBytes(value); | |||
BytesValue bytesValue = BytesData.fromBytes(value); | |||
this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion); | |||
handle(op); | |||
return this; | |||
@@ -295,7 +295,7 @@ public class ContractLedgerContext implements LedgerContext { | |||
@Override | |||
public DataAccountKVSetOperationBuilder setInt64(String key, long value, long expVersion) { | |||
BytesValue bytesValue = BytesValueEntry.fromInt64(value); | |||
BytesValue bytesValue = BytesData.fromInt64(value); | |||
this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion); | |||
handle(op); | |||
return this; | |||
@@ -312,7 +312,7 @@ public class ContractLedgerContext implements LedgerContext { | |||
@Override | |||
public DataAccountKVSetOperationBuilder setJSON(String key, String value, long expVersion) { | |||
BytesValue bytesValue = BytesValueEntry.fromJSON(value); | |||
BytesValue bytesValue = BytesData.fromJSON(value); | |||
this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion); | |||
handle(op); | |||
return this; | |||
@@ -320,7 +320,7 @@ public class ContractLedgerContext implements LedgerContext { | |||
@Override | |||
public DataAccountKVSetOperationBuilder setXML(String key, String value, long expVersion) { | |||
BytesValue bytesValue = BytesValueEntry.fromXML(value); | |||
BytesValue bytesValue = BytesData.fromXML(value); | |||
this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion); | |||
handle(op); | |||
return this; | |||
@@ -328,7 +328,7 @@ public class ContractLedgerContext implements LedgerContext { | |||
@Override | |||
public DataAccountKVSetOperationBuilder setBytes(String key, byte[] value, long expVersion) { | |||
BytesValue bytesValue = BytesValueEntry.fromBytes(value); | |||
BytesValue bytesValue = BytesData.fromBytes(value); | |||
this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion); | |||
handle(op); | |||
return this; | |||
@@ -336,7 +336,7 @@ public class ContractLedgerContext implements LedgerContext { | |||
@Override | |||
public DataAccountKVSetOperationBuilder setImage(String key, byte[] value, long expVersion) { | |||
BytesValue bytesValue = BytesValueEntry.fromImage(value); | |||
BytesValue bytesValue = BytesData.fromImage(value); | |||
this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion); | |||
handle(op); | |||
return this; | |||
@@ -344,7 +344,7 @@ public class ContractLedgerContext implements LedgerContext { | |||
@Override | |||
public DataAccountKVSetOperationBuilder setTimestamp(String key, long value, long expVersion) { | |||
BytesValue bytesValue = BytesValueEntry.fromTimestamp(value); | |||
BytesValue bytesValue = BytesData.fromTimestamp(value); | |||
this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion); | |||
handle(op); | |||
return this; | |||
@@ -12,7 +12,7 @@ import com.jd.blockchain.crypto.service.classic.ClassicCryptoService; | |||
import com.jd.blockchain.crypto.service.sm.SMCryptoService; | |||
import com.jd.blockchain.ledger.BlockchainKeyGenerator; | |||
import com.jd.blockchain.ledger.BlockchainKeypair; | |||
import com.jd.blockchain.ledger.BytesValueEntry; | |||
import com.jd.blockchain.ledger.BytesData; | |||
import com.jd.blockchain.ledger.core.BaseAccount; | |||
import com.jd.blockchain.ledger.core.CryptoConfig; | |||
import com.jd.blockchain.storage.service.utils.MemoryKVStorage; | |||
@@ -53,33 +53,33 @@ public class BaseAccountTest { | |||
assertFalse(baseAccount.isReadonly()); | |||
// 在空白状态下写入数据; | |||
long v = baseAccount.setBytes(Bytes.fromString("A"), BytesValueEntry.fromText("VALUE_A"), 0); | |||
long v = baseAccount.setBytes(Bytes.fromString("A"), BytesData.fromText("VALUE_A"), 0); | |||
// 预期失败; | |||
assertEquals(-1, v); | |||
v = baseAccount.setBytes(Bytes.fromString("A"), BytesValueEntry.fromText("VALUE_A"), 1); | |||
v = baseAccount.setBytes(Bytes.fromString("A"), BytesData.fromText("VALUE_A"), 1); | |||
// 预期失败; | |||
assertEquals(-1, v); | |||
v = baseAccount.setBytes(Bytes.fromString("A"), BytesValueEntry.fromText("VALUE_A"), -1); | |||
v = baseAccount.setBytes(Bytes.fromString("A"), BytesData.fromText("VALUE_A"), -1); | |||
// 预期成功; | |||
assertEquals(0, v); | |||
v = baseAccount.setBytes(Bytes.fromString("A"), BytesValueEntry.fromText("VALUE_A-1"), -1); | |||
v = baseAccount.setBytes(Bytes.fromString("A"), BytesData.fromText("VALUE_A-1"), -1); | |||
// 已经存在版本,指定版本号-1,预期导致失败; | |||
assertEquals(-1, v); | |||
baseAccount.commit(); | |||
v = 0; | |||
for (int i = 0; i < 10; i++) { | |||
long s = baseAccount.setBytes(Bytes.fromString("A"), BytesValueEntry.fromText("VALUE_A_" + i), v); | |||
long s = baseAccount.setBytes(Bytes.fromString("A"), BytesData.fromText("VALUE_A_" + i), v); | |||
baseAccount.commit(); | |||
// 预期成功; | |||
assertEquals(v + 1, s); | |||
v++; | |||
} | |||
v = baseAccount.setBytes(Bytes.fromString("A"), BytesValueEntry.fromText("VALUE_A_" + v), v + 1); | |||
v = baseAccount.setBytes(Bytes.fromString("A"), BytesData.fromText("VALUE_A_" + v), v + 1); | |||
// 预期成功; | |||
assertEquals(-1, v); | |||
@@ -21,7 +21,7 @@ import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.BlockchainKeyGenerator; | |||
import com.jd.blockchain.ledger.BlockchainKeypair; | |||
import com.jd.blockchain.ledger.BytesValue; | |||
import com.jd.blockchain.ledger.BytesValueEntry; | |||
import com.jd.blockchain.ledger.BytesData; | |||
import com.jd.blockchain.ledger.EndpointRequest; | |||
import com.jd.blockchain.ledger.LedgerBlock; | |||
import com.jd.blockchain.ledger.LedgerInitSetting; | |||
@@ -103,6 +103,7 @@ public class ContractInvokingTest { | |||
Random rand = new Random(); | |||
TxBuilder txBuilder = new TxBuilder(ledgerHash); | |||
TestContract contractProxy = txBuilder.contract(contractAddress, TestContract.class); | |||
TestContract contractProxy1 = txBuilder.contract(contractAddress, TestContract.class); | |||
String asset = "AK"; | |||
long issueAmount = rand.nextLong(); | |||
@@ -120,7 +121,7 @@ public class ContractInvokingTest { | |||
assertEquals(1, opResults.length); | |||
assertEquals(0, opResults[0].getIndex()); | |||
byte[] expectedRetnBytes = BinaryProtocol.encode(BytesValueEntry.fromInt64(issueAmount), BytesValue.class); | |||
byte[] expectedRetnBytes = BinaryProtocol.encode(BytesData.fromInt64(issueAmount), BytesValue.class); | |||
byte[] reallyRetnBytes = BinaryProtocol.encode(opResults[0].getResult(), BytesValue.class); | |||
assertArrayEquals(expectedRetnBytes, reallyRetnBytes); | |||
@@ -1,5 +1,6 @@ | |||
package test.com.jd.blockchain.ledger; | |||
import static org.junit.Assert.assertArrayEquals; | |||
import static org.junit.Assert.assertEquals; | |||
import static org.junit.Assert.assertFalse; | |||
import static org.junit.Assert.assertNotNull; | |||
@@ -10,10 +11,13 @@ import java.util.Random; | |||
import org.junit.Test; | |||
import com.jd.blockchain.binaryproto.BinaryProtocol; | |||
import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.BlockchainKeyGenerator; | |||
import com.jd.blockchain.ledger.BlockchainKeypair; | |||
import com.jd.blockchain.ledger.BytesDataList; | |||
import com.jd.blockchain.ledger.BytesValueList; | |||
import com.jd.blockchain.ledger.ContractCodeDeployOperation; | |||
import com.jd.blockchain.ledger.ContractEventSendOperation; | |||
import com.jd.blockchain.ledger.CryptoSetting; | |||
@@ -67,8 +71,8 @@ public class TransactionSetTest { | |||
BlockchainKeypair dataKey = BlockchainKeyGenerator.getInstance().generate(); | |||
DataAccountRegisterOperation dataAccRegOp = txBuilder.dataAccounts().register(dataKey.getIdentity()); | |||
DataAccountKVSetOperation kvsetOP = txBuilder.dataAccount(dataKey.getAddress()) | |||
.setText("A", "Value_A_0", -1).setText("B", "Value_B_0", -1).getOperation(); | |||
DataAccountKVSetOperation kvsetOP = txBuilder.dataAccount(dataKey.getAddress()).setText("A", "Value_A_0", -1) | |||
.setText("B", "Value_B_0", -1).getOperation(); | |||
byte[] chainCode = new byte[128]; | |||
rand.nextBytes(chainCode); | |||
@@ -76,7 +80,7 @@ public class TransactionSetTest { | |||
ContractCodeDeployOperation contractDplOP = txBuilder.contracts().deploy(contractKey.getIdentity(), chainCode); | |||
ContractEventSendOperation contractEvtSendOP = txBuilder.contractEvents().send(contractKey.getAddress(), "test", | |||
"TestContractArgs".getBytes()); | |||
BytesDataList.singleText("TestContractArgs")); | |||
TransactionRequestBuilder txReqBuilder = txBuilder.prepareRequest(); | |||
@@ -98,7 +102,8 @@ public class TransactionSetTest { | |||
txSnapshot.setContractAccountSetHash(contractAccountSetHash); | |||
long blockHeight = 8922L; | |||
LedgerTransactionData tx = new LedgerTransactionData(blockHeight, txReq, TransactionState.SUCCESS, txSnapshot, null); | |||
LedgerTransactionData tx = new LedgerTransactionData(blockHeight, txReq, TransactionState.SUCCESS, txSnapshot, | |||
null); | |||
txset.add(tx); | |||
assertTrue(txset.isUpdated()); | |||
@@ -172,7 +177,8 @@ public class TransactionSetTest { | |||
for (int i = 0; i < acutualKVWriteSet.length; i++) { | |||
assertEquals(expKVWriteSet[i].getKey(), acutualKVWriteSet[i].getKey()); | |||
assertEquals(expKVWriteSet[i].getExpectedVersion(), acutualKVWriteSet[i].getExpectedVersion()); | |||
assertTrue(BytesUtils.equals(expKVWriteSet[i].getValue().getValue().toBytes(), acutualKVWriteSet[i].getValue().getValue().toBytes())); | |||
assertTrue(BytesUtils.equals(expKVWriteSet[i].getValue().getValue().toBytes(), | |||
acutualKVWriteSet[i].getValue().getValue().toBytes())); | |||
} | |||
ContractCodeDeployOperation actualContractDplOp = (ContractCodeDeployOperation) actualOperations[3]; | |||
@@ -184,8 +190,14 @@ public class TransactionSetTest { | |||
assertEquals(contractEvtSendOP.getContractAddress(), actualContractEvtSendOp.getContractAddress()); | |||
assertEquals(contractEvtSendOP.getEvent(), actualContractEvtSendOp.getEvent()); | |||
assertEquals("test", actualContractEvtSendOp.getEvent()); | |||
assertTrue(BytesUtils.equals(contractEvtSendOP.getArgs(), actualContractEvtSendOp.getArgs())); | |||
assertTrue(BytesUtils.equals("TestContractArgs".getBytes(), actualContractEvtSendOp.getArgs())); | |||
byte[] expectedBytes = BinaryProtocol.encode(contractEvtSendOP.getArgs(), BytesValueList.class); | |||
byte[] actualBytes = BinaryProtocol.encode(actualContractEvtSendOp.getArgs(), BytesValueList.class); | |||
assertArrayEquals(expectedBytes, actualBytes); | |||
expectedBytes = BinaryProtocol.encode(BytesDataList.singleText("TestContractArgs"), BytesValueList.class); | |||
actualBytes = BinaryProtocol.encode(actualContractEvtSendOp.getArgs(), BytesValueList.class); | |||
assertArrayEquals(expectedBytes, actualBytes); | |||
} | |||
} |
@@ -8,38 +8,38 @@ import com.jd.blockchain.utils.io.BytesUtils; | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public class BytesValueEntry implements BytesValue { | |||
public class BytesData implements BytesValue { | |||
DataType type; | |||
Bytes value; | |||
private BytesValueEntry(DataType type, byte[] bytes) { | |||
private BytesData(DataType type, byte[] bytes) { | |||
this.type = type; | |||
this.value = new Bytes(bytes); | |||
} | |||
private BytesValueEntry(DataType type, Bytes bytes) { | |||
private BytesData(DataType type, Bytes bytes) { | |||
this.type = type; | |||
this.value = bytes; | |||
} | |||
public static BytesValue fromType(DataType type, byte[] value) { | |||
return new BytesValueEntry(type, value); | |||
return new BytesData(type, value); | |||
} | |||
public static BytesValue fromBytes(byte[] value) { | |||
return new BytesValueEntry(DataType.BYTES, value); | |||
return new BytesData(DataType.BYTES, value); | |||
} | |||
public static BytesValue fromBytes(Bytes value) { | |||
return new BytesValueEntry(DataType.BYTES, value); | |||
return new BytesData(DataType.BYTES, value); | |||
} | |||
public static BytesValue fromImage(byte[] value) { | |||
return new BytesValueEntry(DataType.IMG, value); | |||
return new BytesData(DataType.IMG, value); | |||
} | |||
public static BytesValue fromImage(Bytes value) { | |||
return new BytesValueEntry(DataType.IMG, value); | |||
return new BytesData(DataType.IMG, value); | |||
} | |||
/** | |||
@@ -49,7 +49,7 @@ public class BytesValueEntry implements BytesValue { | |||
* @return | |||
*/ | |||
public static BytesValue fromText(String value) { | |||
return new BytesValueEntry(DataType.TEXT, BytesUtils.toBytes(value)); | |||
return new BytesData(DataType.TEXT, BytesUtils.toBytes(value)); | |||
} | |||
/** | |||
@@ -70,35 +70,35 @@ public class BytesValueEntry implements BytesValue { | |||
} | |||
public static BytesValue fromJSON(String value) { | |||
return new BytesValueEntry(DataType.JSON, BytesUtils.toBytes(value)); | |||
return new BytesData(DataType.JSON, BytesUtils.toBytes(value)); | |||
} | |||
public static BytesValue fromXML(String value) { | |||
return new BytesValueEntry(DataType.XML, BytesUtils.toBytes(value)); | |||
return new BytesData(DataType.XML, BytesUtils.toBytes(value)); | |||
} | |||
public static BytesValue fromInt32(int value) { | |||
return new BytesValueEntry(DataType.INT32, BytesUtils.toBytes(value)); | |||
return new BytesData(DataType.INT32, BytesUtils.toBytes(value)); | |||
} | |||
public static BytesValue fromInt64(long value) { | |||
return new BytesValueEntry(DataType.INT64, BytesUtils.toBytes(value)); | |||
return new BytesData(DataType.INT64, BytesUtils.toBytes(value)); | |||
} | |||
public static BytesValue fromInt16(short value) { | |||
return new BytesValueEntry(DataType.INT16, BytesUtils.toBytes(value)); | |||
return new BytesData(DataType.INT16, BytesUtils.toBytes(value)); | |||
} | |||
public static BytesValue fromInt8(byte value) { | |||
return new BytesValueEntry(DataType.INT8, BytesUtils.toBytes(value)); | |||
return new BytesData(DataType.INT8, BytesUtils.toBytes(value)); | |||
} | |||
public static BytesValue fromTimestamp(long value) { | |||
return new BytesValueEntry(DataType.TIMESTAMP, BytesUtils.toBytes(value)); | |||
return new BytesData(DataType.TIMESTAMP, BytesUtils.toBytes(value)); | |||
} | |||
public static BytesValue fromBoolean(boolean value) { | |||
return new BytesValueEntry(DataType.BOOLEAN, BytesUtils.toBytes(value)); | |||
return new BytesData(DataType.BOOLEAN, BytesUtils.toBytes(value)); | |||
} | |||
@Override |
@@ -0,0 +1,31 @@ | |||
package com.jd.blockchain.ledger; | |||
public class BytesDataList implements BytesValueList { | |||
private BytesValue[] bytesValues; | |||
public BytesDataList(BytesValue... bytesValues) { | |||
this.bytesValues = bytesValues; | |||
} | |||
@Override | |||
public BytesValue[] getValues() { | |||
return bytesValues; | |||
} | |||
public static BytesValueList singleText(String value) { | |||
return new BytesDataList(BytesData.fromText(value)); | |||
} | |||
public static BytesValueList singleLong(long value) { | |||
return new BytesDataList(BytesData.fromInt64(value)); | |||
} | |||
public static BytesValueList singleInt(int value) { | |||
return new BytesDataList(BytesData.fromInt32(value)); | |||
} | |||
public static BytesValueList singleBoolean(boolean value) { | |||
return new BytesDataList(BytesData.fromBoolean(value)); | |||
} | |||
} |
@@ -1,5 +1,7 @@ | |||
package com.jd.blockchain.ledger; | |||
import java.io.Closeable; | |||
import com.jd.blockchain.crypto.AsymmetricKeypair; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
@@ -9,7 +11,7 @@ import com.jd.blockchain.crypto.HashDigest; | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public interface PreparedTransaction extends HashObject { | |||
public interface PreparedTransaction extends HashObject, Closeable { | |||
/** | |||
* 交易内容的 Hash; | |||
@@ -55,8 +57,4 @@ public interface PreparedTransaction extends HashObject { | |||
*/ | |||
TransactionResponse commit(); | |||
/** | |||
* 取消交易;<br> | |||
*/ | |||
void cancel(); | |||
} |
@@ -1,5 +1,7 @@ | |||
package com.jd.blockchain.ledger; | |||
import java.io.Closeable; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.transaction.ClientOperator; | |||
@@ -9,7 +11,7 @@ import com.jd.blockchain.transaction.ClientOperator; | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public interface TransactionTemplate extends ClientOperator { | |||
public interface TransactionTemplate extends ClientOperator, Closeable { | |||
HashDigest getLedgerHash(); | |||
@@ -106,15 +106,15 @@ public class BlockchainOperationFactory implements ClientOperator, LedgerInitOpe | |||
* | |||
* @return | |||
*/ | |||
public Collection<OperationReturnValueHandler> getReturnValuetHandlers() { | |||
List<OperationReturnValueHandler> resultHandlers = new ArrayList<OperationReturnValueHandler>(); | |||
public Collection<OperationResultHandle> getReturnValuetHandlers() { | |||
List<OperationResultHandle> resultHandlers = new ArrayList<OperationResultHandle>(); | |||
int index = 0; | |||
for (Operation op : operationList) { | |||
if (op instanceof ContractEventSendOperation) { | |||
// 操作具有返回值,创建对应的结果处理器; | |||
ContractEventSendOpTemplate opTemp = (ContractEventSendOpTemplate) op; | |||
ContractInvocation invocation = opTemp.getInvocation(); | |||
OperationReturnValueHandler retnHandler; | |||
OperationResultHandle retnHandler; | |||
if (invocation == null) { | |||
retnHandler = new NullOperationReturnValueHandler(index); | |||
} else { | |||
@@ -278,7 +278,7 @@ public class BlockchainOperationFactory implements ClientOperator, LedgerInitOpe | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
private static class NullOperationReturnValueHandler implements OperationReturnValueHandler { | |||
private static class NullOperationReturnValueHandler implements OperationResultHandle { | |||
private int operationIndex; | |||
@@ -292,10 +292,14 @@ public class BlockchainOperationFactory implements ClientOperator, LedgerInitOpe | |||
} | |||
@Override | |||
public Object setReturnValue(BytesValue bytesValue) { | |||
public Object complete(BytesValue bytesValue) { | |||
return null; | |||
} | |||
@Override | |||
public void complete(Throwable error) { | |||
} | |||
} | |||
} |
@@ -1,43 +1,22 @@ | |||
package com.jd.blockchain.transaction; | |||
import java.util.concurrent.TimeUnit; | |||
import java.util.concurrent.TimeoutException; | |||
public class BooleanValueHolder extends ValueHolderWrapper { | |||
public class BooleanValueHolder extends ValueHolderBase { | |||
BooleanValueHolder(ContractInvocation invocation) { | |||
super(invocation); | |||
BooleanValueHolder(OperationResultHolder resultHolder) { | |||
super(resultHolder); | |||
} | |||
/** | |||
* 等待结果合约调用的结果返回; | |||
* 获取值;<br> | |||
* | |||
* @return | |||
*/ | |||
public boolean get() { | |||
return (boolean) super.getValue(); | |||
} | |||
/** | |||
* 等待结果合约调用的结果返回; | |||
* 此方法不堵塞,调用立即返回;<br> | |||
* | |||
* @param timeout | |||
* @return | |||
* @throws TimeoutException | |||
*/ | |||
public boolean get(long timeout) throws TimeoutException { | |||
return get(timeout, TimeUnit.MILLISECONDS); | |||
} | |||
/** | |||
* 等待结果合约调用的结果返回; | |||
* 如果未完成时( {@link #isCompleted()} 为 false ),总是返回 false; | |||
* | |||
* @param timeout | |||
* @param unit | |||
* @return | |||
* @throws TimeoutException | |||
*/ | |||
public boolean get(long timeout, TimeUnit unit) throws TimeoutException { | |||
return (boolean) super.getValue(timeout, unit); | |||
public boolean get() { | |||
return super.isCompleted() ? (boolean) super.getValue() : false; | |||
} | |||
} |
@@ -1,43 +1,22 @@ | |||
package com.jd.blockchain.transaction; | |||
import java.util.concurrent.TimeUnit; | |||
import java.util.concurrent.TimeoutException; | |||
public class ByteValueHolder extends ValueHolderWrapper { | |||
public class ByteValueHolder extends ValueHolderBase { | |||
ByteValueHolder(ContractInvocation invocation) { | |||
super(invocation); | |||
ByteValueHolder(OperationResultHolder resultHolder) { | |||
super(resultHolder); | |||
} | |||
/** | |||
* 等待结果合约调用的结果返回; | |||
* 获取值;<br> | |||
* | |||
* @return | |||
*/ | |||
public byte get() { | |||
return (byte) super.getValue(); | |||
} | |||
/** | |||
* 等待结果合约调用的结果返回; | |||
* 此方法不堵塞,调用立即返回;<br> | |||
* | |||
* @param timeout | |||
* @return | |||
* @throws TimeoutException | |||
*/ | |||
public byte get(long timeout) throws TimeoutException { | |||
return get(timeout, TimeUnit.MILLISECONDS); | |||
} | |||
/** | |||
* 等待结果合约调用的结果返回; | |||
* 如果未完成时( {@link #isCompleted()} 为 false ),总是返回 0; | |||
* | |||
* @param timeout | |||
* @param unit | |||
* @return | |||
* @throws TimeoutException | |||
*/ | |||
public byte get(long timeout, TimeUnit unit) throws TimeoutException { | |||
return (byte) super.getValue(timeout, unit); | |||
public byte get() { | |||
return super.isCompleted() ? (byte) super.getValue() : 0; | |||
} | |||
} |
@@ -1,8 +1,6 @@ | |||
package com.jd.blockchain.transaction; | |||
import java.lang.reflect.Method; | |||
import java.util.concurrent.CompletableFuture; | |||
import java.util.concurrent.Future; | |||
import com.jd.blockchain.contract.ContractType; | |||
import com.jd.blockchain.ledger.BytesValue; | |||
@@ -14,7 +12,7 @@ import com.jd.blockchain.ledger.BytesValueEncoding; | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
class ContractInvocation implements OperationReturnValueHandler { | |||
class ContractInvocation extends OperationResultHolder { | |||
private Method method; | |||
@@ -22,12 +20,9 @@ class ContractInvocation implements OperationReturnValueHandler { | |||
private int operationIndex = -1; | |||
private CompletableFuture<Object> returnValueFuture; | |||
public ContractInvocation(ContractType contractType, Method method) { | |||
this.contractType = contractType; | |||
this.method = method; | |||
this.returnValueFuture = new CompletableFuture<Object>(); | |||
} | |||
public ContractType getContractType() { | |||
@@ -47,16 +42,9 @@ class ContractInvocation implements OperationReturnValueHandler { | |||
return method.getReturnType(); | |||
} | |||
public Future<Object> getReturnValue() { | |||
return returnValueFuture; | |||
} | |||
@Override | |||
public Object setReturnValue(BytesValue bytesValue) { | |||
// Resolve BytesValue to an value object with the return type; | |||
Object returnValue = BytesValueEncoding.decode(bytesValue, method.getReturnType()); | |||
returnValueFuture.complete(returnValue); | |||
return returnValue; | |||
protected Object decodeResult(BytesValue bytesValue) { | |||
return BytesValueEncoding.decode(bytesValue, method.getReturnType()); | |||
} | |||
} |
@@ -4,10 +4,8 @@ import java.lang.reflect.Proxy; | |||
import java.util.Map; | |||
import java.util.concurrent.ConcurrentHashMap; | |||
import com.jd.blockchain.contract.EventResult; | |||
import com.jd.blockchain.contract.ContractType; | |||
import com.jd.blockchain.utils.Bytes; | |||
import com.jd.blockchain.utils.IllegalDataException; | |||
/** | |||
* 合约调用代理的构建器; | |||
@@ -19,8 +17,6 @@ public class ContractInvocationProxyBuilder { | |||
private Map<Class<?>, ContractType> contractTypes = new ConcurrentHashMap<>(); | |||
// private Map<Object, Integer> contractOperations = new ConcurrentHashMap<>(); | |||
public <T> T create(String address, Class<T> contractIntf, ContractEventSendOperationBuilder contractEventBuilder) { | |||
return create(Bytes.fromBase58(address), contractIntf, contractEventBuilder); | |||
} | |||
@@ -33,31 +29,9 @@ public class ContractInvocationProxyBuilder { | |||
T proxy = (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), | |||
new Class<?>[] { contractIntf }, proxyHandler); | |||
// // 创建关联关系 | |||
// contractOperations.put(proxy, proxyHandler.opIndex()); | |||
return proxy; | |||
} | |||
// public <T> EventResult<T> execute(ContractEventExecutor execute) { | |||
// Object contractProxy = execute.execute(); | |||
// if (contractProxy == null) { | |||
// // 该方法执行必须要有返回值 | |||
// throw new IllegalStateException( | |||
// String.format("ContractEventExecutor [%s] 's return must be not empty !!!", execute.toString())); | |||
// } | |||
// if (!(contractProxy instanceof Proxy)) { | |||
// throw new IllegalDataException( | |||
// String.format("ContractEventExecutor [%s] 's return must from TxTemplate.contract()'s result !!!", | |||
// execute.toString())); | |||
// } | |||
// | |||
// Integer opIndex = contractOperations.get(contractProxy); | |||
// if (opIndex != null && opIndex > -1) { | |||
// return new EventResult<>(opIndex); | |||
// } | |||
// return null; | |||
// } | |||
private ContractType resolveContractType(Class<?> contractIntf) { | |||
ContractType contractType = contractTypes.get(contractIntf); | |||
if (contractType != null) { | |||
@@ -26,9 +26,9 @@ public class ContractReturnValue { | |||
* @param call | |||
* @return | |||
*/ | |||
public static <T> ValueHolder<T> decode(T call) { | |||
public static <T> GenericValueHolder<T> decode(T call) { | |||
ContractInvocation invocation = ContractInvocationStub.take(); | |||
return new ValueHolder<T>(invocation); | |||
return new GenericValueHolder<T>(invocation); | |||
} | |||
/** | |||
@@ -1,7 +1,7 @@ | |||
package com.jd.blockchain.transaction; | |||
import com.jd.blockchain.ledger.BytesValue; | |||
import com.jd.blockchain.ledger.BytesValueEntry; | |||
import com.jd.blockchain.ledger.BytesData; | |||
import com.jd.blockchain.ledger.DataAccountKVSetOperation; | |||
import com.jd.blockchain.utils.Bytes; | |||
@@ -26,14 +26,14 @@ public class DataAccountKVSetOperationBuilderImpl implements DataAccountKVSetOpe | |||
@Override | |||
public DataAccountKVSetOperationBuilder setBytes(String key, byte[] value, long expVersion) { | |||
BytesValue bytesValue = BytesValueEntry.fromBytes(value); | |||
BytesValue bytesValue = BytesData.fromBytes(value); | |||
operation.set(key, bytesValue, expVersion); | |||
return this; | |||
} | |||
@Override | |||
public DataAccountKVSetOperationBuilder setImage(String key, byte[] value, long expVersion) { | |||
BytesValue bytesValue = BytesValueEntry.fromImage(value); | |||
BytesValue bytesValue = BytesData.fromImage(value); | |||
operation.set(key, bytesValue, expVersion); | |||
return this; | |||
} | |||
@@ -45,42 +45,42 @@ public class DataAccountKVSetOperationBuilderImpl implements DataAccountKVSetOpe | |||
@Override | |||
public DataAccountKVSetOperationBuilder setText(String key, String value, long expVersion) { | |||
BytesValue bytesValue = BytesValueEntry.fromText(value); | |||
BytesValue bytesValue = BytesData.fromText(value); | |||
operation.set(key, bytesValue, expVersion); | |||
return this; | |||
} | |||
@Override | |||
public DataAccountKVSetOperationBuilder setBytes(String key, Bytes value, long expVersion) { | |||
BytesValue bytesValue = BytesValueEntry.fromBytes(value); | |||
BytesValue bytesValue = BytesData.fromBytes(value); | |||
operation.set(key, bytesValue, expVersion); | |||
return this; | |||
} | |||
@Override | |||
public DataAccountKVSetOperationBuilder setInt64(String key, long value, long expVersion) { | |||
BytesValue bytesValue = BytesValueEntry.fromInt64(value); | |||
BytesValue bytesValue = BytesData.fromInt64(value); | |||
operation.set(key, bytesValue, expVersion); | |||
return this; | |||
} | |||
@Override | |||
public DataAccountKVSetOperationBuilder setJSON(String key, String value, long expVersion) { | |||
BytesValue bytesValue = BytesValueEntry.fromJSON(value); | |||
BytesValue bytesValue = BytesData.fromJSON(value); | |||
operation.set(key, bytesValue, expVersion); | |||
return this; | |||
} | |||
@Override | |||
public DataAccountKVSetOperationBuilder setXML(String key, String value, long expVersion) { | |||
BytesValue bytesValue = BytesValueEntry.fromXML(value); | |||
BytesValue bytesValue = BytesData.fromXML(value); | |||
operation.set(key, bytesValue, expVersion); | |||
return this; | |||
} | |||
@Override | |||
public DataAccountKVSetOperationBuilder setTimestamp(String key, long value, long expVersion) { | |||
BytesValue bytesValue = BytesValueEntry.fromTimestamp(value); | |||
BytesValue bytesValue = BytesData.fromTimestamp(value); | |||
operation.set(key, bytesValue, expVersion); | |||
return this; | |||
} | |||
@@ -0,0 +1,23 @@ | |||
package com.jd.blockchain.transaction; | |||
public class GenericValueHolder<T> extends ValueHolderWrapper { | |||
GenericValueHolder(OperationResultHolder resultHolder) { | |||
super(resultHolder); | |||
} | |||
/** | |||
* 获取值;<br> | |||
* | |||
* 此方法不堵塞,调用立即返回;<br> | |||
* | |||
* 如果未完成时( {@link #isCompleted()} 为 false ),总是返回 null; | |||
* | |||
* @return | |||
*/ | |||
@SuppressWarnings("unchecked") | |||
public T get() { | |||
return (T) super.getValue(); | |||
} | |||
} |
@@ -1,43 +1,22 @@ | |||
package com.jd.blockchain.transaction; | |||
import java.util.concurrent.TimeUnit; | |||
import java.util.concurrent.TimeoutException; | |||
public class IntValueHolder extends ValueHolderWrapper { | |||
public class IntValueHolder extends ValueHolderBase { | |||
IntValueHolder(ContractInvocation invocation) { | |||
super(invocation); | |||
IntValueHolder(OperationResultHolder resultHolder) { | |||
super(resultHolder); | |||
} | |||
/** | |||
* 等待结果合约调用的结果返回; | |||
* 获取值;<br> | |||
* | |||
* @return | |||
*/ | |||
public int get() { | |||
return (int) super.getValue(); | |||
} | |||
/** | |||
* 等待结果合约调用的结果返回; | |||
* 此方法不堵塞,调用立即返回;<br> | |||
* | |||
* @param timeout | |||
* @return | |||
* @throws TimeoutException | |||
*/ | |||
public int get(long timeout) throws TimeoutException { | |||
return get(timeout, TimeUnit.MILLISECONDS); | |||
} | |||
/** | |||
* 等待结果合约调用的结果返回; | |||
* 如果未完成时( {@link #isCompleted()} 为 false ),总是返回 0; | |||
* | |||
* @param timeout | |||
* @param unit | |||
* @return | |||
* @throws TimeoutException | |||
*/ | |||
public int get(long timeout, TimeUnit unit) throws TimeoutException { | |||
return (int) super.getValue(timeout, unit); | |||
public int get() { | |||
return super.isCompleted() ? (int) super.getValue() : 0; | |||
} | |||
} |
@@ -1,43 +1,22 @@ | |||
package com.jd.blockchain.transaction; | |||
import java.util.concurrent.TimeUnit; | |||
import java.util.concurrent.TimeoutException; | |||
public class LongValueHolder extends ValueHolderWrapper { | |||
public class LongValueHolder extends ValueHolderBase { | |||
LongValueHolder(ContractInvocation invocation) { | |||
super(invocation); | |||
LongValueHolder(OperationResultHolder resultHolder) { | |||
super(resultHolder); | |||
} | |||
/** | |||
* 等待结果合约调用的结果返回; | |||
* 获取值;<br> | |||
* | |||
* @return | |||
*/ | |||
public long get() { | |||
return (long) super.getValue(); | |||
} | |||
/** | |||
* 等待结果合约调用的结果返回; | |||
* 此方法不堵塞,调用立即返回;<br> | |||
* | |||
* @param timeout | |||
* @return | |||
* @throws TimeoutException | |||
*/ | |||
public long get(long timeout) throws TimeoutException { | |||
return get(timeout, TimeUnit.MILLISECONDS); | |||
} | |||
/** | |||
* 等待结果合约调用的结果返回; | |||
* 如果未完成时( {@link #isCompleted()} 为 false ),总是返回 0; | |||
* | |||
* @param timeout | |||
* @param unit | |||
* @return | |||
* @throws TimeoutException | |||
*/ | |||
public long get(long timeout, TimeUnit unit) throws TimeoutException { | |||
return (long) super.getValue(timeout, unit); | |||
public long get() { | |||
return super.isCompleted() ? (long) super.getValue() : 0; | |||
} | |||
} |
@@ -0,0 +1,24 @@ | |||
package com.jd.blockchain.transaction; | |||
import com.jd.blockchain.ledger.BytesValue; | |||
public class OperationCompletedContext { | |||
private int operationIndex; | |||
private BytesValue returnBytesValue; | |||
public OperationCompletedContext(int operationIndex, BytesValue returnBytesValue) { | |||
this.operationIndex = operationIndex; | |||
this.returnBytesValue = returnBytesValue; | |||
} | |||
public int getOperationIndex() { | |||
return operationIndex; | |||
} | |||
public BytesValue getReturnBytesValue() { | |||
return returnBytesValue; | |||
} | |||
} |
@@ -0,0 +1,20 @@ | |||
package com.jd.blockchain.transaction; | |||
/** | |||
* 操作完成监听器; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public interface OperationCompletedListener { | |||
/** | |||
* 当操作完成时发生; | |||
* | |||
* @param retnValue 返回值; | |||
* @param error 异常;如果值为非空,则表示由异常导致结束; | |||
* @param context 上下文对象; | |||
*/ | |||
void onCompleted(Object retnValue, Throwable error, OperationCompletedContext context); | |||
} |
@@ -0,0 +1,35 @@ | |||
package com.jd.blockchain.transaction; | |||
import com.jd.blockchain.ledger.BytesValue; | |||
/** | |||
* 操作返回值处理器; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
interface OperationResultHandle { | |||
/** | |||
* 操作的索引位置; | |||
* | |||
* @return | |||
*/ | |||
int getOperationIndex(); | |||
/** | |||
* 正常地完成; | |||
* | |||
* @param returnBytesValue | |||
* @return | |||
*/ | |||
Object complete(BytesValue returnBytesValue); | |||
/** | |||
* 以异常方式完成; | |||
* | |||
* @param error | |||
*/ | |||
void complete(Throwable error); | |||
} |
@@ -0,0 +1,81 @@ | |||
package com.jd.blockchain.transaction; | |||
import com.jd.blockchain.ledger.BytesValue; | |||
import com.jd.blockchain.utils.event.EventMulticaster; | |||
abstract class OperationResultHolder implements OperationResultHandle { | |||
private Object value; | |||
private Throwable error; | |||
private volatile boolean completed; | |||
private EventMulticaster<OperationCompletedListener> listenerMulticaster; | |||
/** | |||
* 导致结束的错误; | |||
* | |||
* @return | |||
*/ | |||
public Throwable getError() { | |||
return error; | |||
} | |||
/** | |||
* 是否已经处理完成; | |||
* | |||
* @return | |||
*/ | |||
public boolean isCompleted() { | |||
return completed; | |||
} | |||
/** | |||
* 获取操作的返回值; <br> | |||
* 在操作未完成之前,总是返回 null;<br> | |||
* 可以通过 {@link #isCompleted()} 方法判断操作是否已经完成;<br> | |||
* 可以通过 {@link #addCompletedListener(OperationCompletedListener)} | |||
* 方法添加监听器来监听操作完成的事件; | |||
* | |||
* @return | |||
*/ | |||
public Object getResult() { | |||
return value; | |||
} | |||
/** | |||
* 添加操作完成监听器; | |||
* | |||
* @param listener | |||
*/ | |||
public void addCompletedListener(OperationCompletedListener listener) { | |||
listenerMulticaster.addListener(listener); | |||
} | |||
protected abstract Object decodeResult(BytesValue bytesValue); | |||
@Override | |||
public Object complete(BytesValue bytesValue) { | |||
if (this.completed) { | |||
throw new IllegalStateException( | |||
"Contract invocation has been completed, and is not allowed to be completed again!"); | |||
} | |||
this.completed = true; | |||
this.value = decodeResult(bytesValue); | |||
OperationCompletedContext context = new OperationCompletedContext(getOperationIndex(), null); | |||
listenerMulticaster.getBroadcaster().onCompleted(value, null, context); | |||
return null; | |||
} | |||
@Override | |||
public void complete(Throwable error) { | |||
if (completed) { | |||
return; | |||
} | |||
this.completed = true; | |||
this.error = error; | |||
OperationCompletedContext context = new OperationCompletedContext(getOperationIndex(), null); | |||
listenerMulticaster.getBroadcaster().onCompleted(null, error, context); | |||
} | |||
} |
@@ -1,11 +0,0 @@ | |||
package com.jd.blockchain.transaction; | |||
import com.jd.blockchain.ledger.BytesValue; | |||
interface OperationReturnValueHandler { | |||
int getOperationIndex(); | |||
Object setReturnValue(BytesValue bytesValue); | |||
} |
@@ -1,9 +1,12 @@ | |||
package com.jd.blockchain.transaction; | |||
import java.io.IOException; | |||
import java.util.Arrays; | |||
import java.util.Collection; | |||
import java.util.Comparator; | |||
import org.springframework.cglib.proxy.UndeclaredThrowableException; | |||
import com.jd.blockchain.binaryproto.BinaryProtocol; | |||
import com.jd.blockchain.crypto.AsymmetricKeypair; | |||
import com.jd.blockchain.crypto.Crypto; | |||
@@ -25,7 +28,9 @@ public class PreparedTx implements PreparedTransaction { | |||
private TransactionService txProcessor; | |||
private OperationReturnValueHandler[] opReturnValueHandlers; | |||
private OperationResultHandle[] opReturnValueHandlers; | |||
private TxStateManager stateManager; | |||
/** | |||
* 创建一个“就绪交易”对象; | |||
@@ -34,17 +39,18 @@ public class PreparedTx implements PreparedTransaction { | |||
* @param txProcessor 交易处理服务; | |||
* @param opReturnValueHandlerList 操作返回值处理器列表; | |||
*/ | |||
public PreparedTx(TransactionRequestBuilder txReqBuilder, TransactionService txProcessor, | |||
Collection<OperationReturnValueHandler> opReturnValueHandlerList) { | |||
public PreparedTx(TxStateManager stateManager, TransactionRequestBuilder txReqBuilder, | |||
TransactionService txProcessor, Collection<OperationResultHandle> opReturnValueHandlerList) { | |||
this.stateManager = stateManager; | |||
this.txReqBuilder = txReqBuilder; | |||
this.txProcessor = txProcessor; | |||
this.opReturnValueHandlers = opReturnValueHandlerList | |||
.toArray(new OperationReturnValueHandler[opReturnValueHandlerList.size()]); | |||
.toArray(new OperationResultHandle[opReturnValueHandlerList.size()]); | |||
// 按照操作索引升序排列; | |||
Arrays.sort(opReturnValueHandlers, new Comparator<OperationReturnValueHandler>() { | |||
Arrays.sort(opReturnValueHandlers, new Comparator<OperationResultHandle>() { | |||
@Override | |||
public int compare(OperationReturnValueHandler o1, OperationReturnValueHandler o2) { | |||
public int compare(OperationResultHandle o1, OperationResultHandle o2) { | |||
return o1.getOperationIndex() - o2.getOperationIndex(); | |||
} | |||
}); | |||
@@ -78,31 +84,59 @@ public class PreparedTx implements PreparedTransaction { | |||
@Override | |||
public TransactionResponse commit() { | |||
stateManager.commit(); | |||
TransactionResponse txResponse = null; | |||
try { | |||
TransactionRequest txReq = txReqBuilder.buildRequest(); | |||
// 发起交易请求; | |||
TransactionResponse txResponse = txProcessor.process(txReq); | |||
// 解析返回值;正常的情况下,返回结果列表与结果处理器列表中元素对应的操作索引是一致的; | |||
OperationResult[] opResults = txResponse.getOperationResults(); | |||
if (opResults != null && opResults.length > 0) { | |||
if (opResults.length != opReturnValueHandlers.length) { | |||
throw new IllegalStateException(String.format( | |||
"The operation result list of tx doesn't match it's return value handler list! --[TX.Content.Hash=%s][NumOfResults=%s][NumOfHandlers=%s]", | |||
txReq.getTransactionContent().getHash(), opResults.length, opReturnValueHandlers.length)); | |||
} | |||
for (int i = 0; i < opResults.length; i++) { | |||
if (opResults[i].getIndex() != opReturnValueHandlers[i].getOperationIndex()) { | |||
throw new IllegalStateException( | |||
"The operation indexes of the items in the result list and in the handler list don't match!"); | |||
} | |||
opReturnValueHandlers[i].setReturnValue(opResults[i].getResult()); | |||
txResponse = txProcessor.process(txReq); | |||
stateManager.complete(); | |||
} catch (Exception ex) { | |||
stateManager.close(); | |||
handleError(ex); | |||
throw new UndeclaredThrowableException(ex); | |||
} | |||
if (txResponse != null) { | |||
handleResults(txResponse); | |||
} | |||
return txResponse; | |||
} | |||
@Override | |||
public void close() throws IOException { | |||
if (!stateManager.close()) { | |||
TransactionCancelledExeption error = new TransactionCancelledExeption( | |||
"Prepared transaction has been cancelled!"); | |||
handleError(error); | |||
} | |||
} | |||
private void handleError(Throwable error) { | |||
for (OperationResultHandle handle : opReturnValueHandlers) { | |||
handle.complete(error); | |||
} | |||
} | |||
private void handleResults(TransactionResponse txResponse) { | |||
// 解析返回值;正常的情况下,返回结果列表与结果处理器列表中元素对应的操作索引是一致的; | |||
OperationResult[] opResults = txResponse.getOperationResults(); | |||
if (opResults != null && opResults.length > 0) { | |||
if (opResults.length != opReturnValueHandlers.length) { | |||
throw new IllegalStateException(String.format( | |||
"The operation result list of tx doesn't match it's return value handler list! --[TX.Content.Hash=%s][NumOfResults=%s][NumOfHandlers=%s]", | |||
txResponse.getContentHash(), opResults.length, opReturnValueHandlers.length)); | |||
} | |||
for (int i = 0; i < opResults.length; i++) { | |||
if (opResults[i].getIndex() != opReturnValueHandlers[i].getOperationIndex()) { | |||
throw new IllegalStateException( | |||
"The operation indexes of the items in the result list and in the handler list don't match!"); | |||
} | |||
opReturnValueHandlers[i].complete(opResults[i].getResult()); | |||
} | |||
return txResponse; | |||
} catch (Exception e) { | |||
//TODO: 出错时清理交易上下文,释放与交易关联对异步等待资源,避免当前线程死锁; | |||
} | |||
} | |||
@@ -1,43 +1,22 @@ | |||
package com.jd.blockchain.transaction; | |||
import java.util.concurrent.TimeUnit; | |||
import java.util.concurrent.TimeoutException; | |||
public class ShortValueHolder extends ValueHolderWrapper { | |||
public class ShortValueHolder extends ValueHolderBase { | |||
ShortValueHolder(ContractInvocation invocation) { | |||
super(invocation); | |||
ShortValueHolder(OperationResultHolder resultHolder) { | |||
super(resultHolder); | |||
} | |||
/** | |||
* 等待结果合约调用的结果返回; | |||
* 获取值;<br> | |||
* | |||
* @return | |||
*/ | |||
public short get() { | |||
return (short) super.getValue(); | |||
} | |||
/** | |||
* 等待结果合约调用的结果返回; | |||
* 此方法不堵塞,调用立即返回;<br> | |||
* | |||
* @param timeout | |||
* @return | |||
* @throws TimeoutException | |||
*/ | |||
public short get(long timeout) throws TimeoutException { | |||
return get(timeout, TimeUnit.MILLISECONDS); | |||
} | |||
/** | |||
* 等待结果合约调用的结果返回; | |||
* 如果未完成时( {@link #isCompleted()} 为 false ),总是返回 0; | |||
* | |||
* @param timeout | |||
* @param unit | |||
* @return | |||
* @throws TimeoutException | |||
*/ | |||
public short get(long timeout, TimeUnit unit) throws TimeoutException { | |||
return (short) super.getValue(timeout, unit); | |||
public short get() { | |||
return super.isCompleted() ? (short) super.getValue() : 0; | |||
} | |||
} |
@@ -0,0 +1,15 @@ | |||
package com.jd.blockchain.transaction; | |||
public class TransactionCancelledExeption extends RuntimeException { | |||
private static final long serialVersionUID = -2577951411093171806L; | |||
public TransactionCancelledExeption(String message) { | |||
super(message); | |||
} | |||
public TransactionCancelledExeption(String message, Throwable cause) { | |||
super(message, cause); | |||
} | |||
} |
@@ -51,7 +51,7 @@ public class TxBuilder implements TransactionBuilder { | |||
return txContent; | |||
} | |||
public Collection<OperationReturnValueHandler> getReturnValuehandlers() { | |||
public Collection<OperationResultHandle> getReturnValuehandlers() { | |||
return opFactory.getReturnValuetHandlers(); | |||
} | |||
@@ -0,0 +1,76 @@ | |||
package com.jd.blockchain.transaction; | |||
class TxStateManager { | |||
private State state = State.OPERABLE; | |||
public void operate() { | |||
if (state != State.OPERABLE) { | |||
throw new IllegalStateException(String.format("Cannot define operations in %s state!", state)); | |||
} | |||
} | |||
public void prepare() { | |||
if (state != State.OPERABLE) { | |||
throw new IllegalStateException( | |||
String.format("Cannot switch to %s state in %s state!", State.PREPARED, state)); | |||
} | |||
state = State.PREPARED; | |||
} | |||
public void commit() { | |||
if (state != State.PREPARED) { | |||
throw new IllegalStateException( | |||
String.format("Cannot switch to %s state in %s state!", State.COMMITTED, state)); | |||
} | |||
state = State.COMMITTED; | |||
} | |||
public void complete() { | |||
if (state != State.COMMITTED) { | |||
throw new IllegalStateException(String.format("Cannot complete normally in %s state!", state)); | |||
} | |||
state = State.CLOSED; | |||
} | |||
/** | |||
* 关闭交易; | |||
* | |||
* @param error | |||
* @return 此次操作前是否已经处于关闭状态; <br> | |||
* 如果返回 true ,则表示之前已经处于关闭状态,此次操作将被忽略;<br> | |||
* 如果返回 fasle,则表示之前处于非关闭状态,此次操作将切换为关闭状态; | |||
*/ | |||
public boolean close() { | |||
if (state == State.CLOSED) { | |||
return true; | |||
} | |||
state = State.CLOSED; | |||
return false; | |||
} | |||
private static enum State { | |||
/** | |||
* 可操作; | |||
*/ | |||
OPERABLE, | |||
/** | |||
* 就绪; | |||
*/ | |||
PREPARED, | |||
/** | |||
* 已提交; | |||
*/ | |||
COMMITTED, | |||
/** | |||
* 已关闭; | |||
*/ | |||
CLOSED | |||
} | |||
} |
@@ -1,5 +1,8 @@ | |||
package com.jd.blockchain.transaction; | |||
import java.io.IOException; | |||
import java.util.Collection; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.PreparedTransaction; | |||
import com.jd.blockchain.ledger.TransactionRequestBuilder; | |||
@@ -12,8 +15,10 @@ public class TxTemplate implements TransactionTemplate { | |||
private TransactionService txService; | |||
private TxStateManager stateManager; | |||
public TxTemplate(HashDigest ledgerHash, TransactionService txService) { | |||
this.stateManager = new TxStateManager(); | |||
this.txBuilder = new TxBuilder(ledgerHash); | |||
this.txService = txService; | |||
} | |||
@@ -25,43 +30,63 @@ public class TxTemplate implements TransactionTemplate { | |||
@Override | |||
public PreparedTransaction prepare() { | |||
stateManager.prepare(); | |||
TransactionRequestBuilder txReqBuilder = txBuilder.prepareRequest(); | |||
return new PreparedTx(txReqBuilder, txService, txBuilder.getReturnValuehandlers()); | |||
return new PreparedTx(stateManager, txReqBuilder, txService, txBuilder.getReturnValuehandlers()); | |||
} | |||
@Override | |||
public UserRegisterOperationBuilder users() { | |||
stateManager.operate(); | |||
return txBuilder.users(); | |||
} | |||
@Override | |||
public DataAccountRegisterOperationBuilder dataAccounts() { | |||
stateManager.operate(); | |||
return txBuilder.dataAccounts(); | |||
} | |||
@Override | |||
public DataAccountKVSetOperationBuilder dataAccount(String accountAddress) { | |||
stateManager.operate(); | |||
return txBuilder.dataAccount(accountAddress); | |||
} | |||
@Override | |||
public DataAccountKVSetOperationBuilder dataAccount(Bytes accountAddress) { | |||
stateManager.operate(); | |||
return txBuilder.dataAccount(accountAddress); | |||
} | |||
@Override | |||
public ContractCodeDeployOperationBuilder contracts() { | |||
stateManager.operate(); | |||
return txBuilder.contracts(); | |||
} | |||
@Override | |||
public <T> T contract(Bytes address, Class<T> contractIntf) { | |||
stateManager.operate(); | |||
return txBuilder.contract(address, contractIntf); | |||
} | |||
@Override | |||
public <T> T contract(String address, Class<T> contractIntf) { | |||
stateManager.operate(); | |||
return txBuilder.contract(address, contractIntf); | |||
} | |||
@Override | |||
public void close() throws IOException { | |||
if (!stateManager.close()) { | |||
Collection<OperationResultHandle> handlers = txBuilder.getReturnValuehandlers(); | |||
if (handlers.size() > 0) { | |||
TransactionCancelledExeption error = new TransactionCancelledExeption("Transaction template has been cancelled!"); | |||
for (OperationResultHandle handle : handlers) { | |||
handle.complete(error); | |||
} | |||
} | |||
} | |||
} | |||
} |
@@ -1,45 +0,0 @@ | |||
package com.jd.blockchain.transaction; | |||
import java.util.concurrent.TimeUnit; | |||
import java.util.concurrent.TimeoutException; | |||
public class ValueHolder<T> extends ValueHolderBase { | |||
ValueHolder(ContractInvocation invocation) { | |||
super(invocation); | |||
} | |||
/** | |||
* 等待结果合约调用的结果返回; | |||
* | |||
* @return | |||
*/ | |||
@SuppressWarnings("unchecked") | |||
public T get() { | |||
return (T) super.getValue(); | |||
} | |||
/** | |||
* 等待结果合约调用的结果返回; | |||
* | |||
* @param timeout | |||
* @return | |||
* @throws TimeoutException | |||
*/ | |||
public T get(long timeout) throws TimeoutException { | |||
return get(timeout, TimeUnit.MILLISECONDS); | |||
} | |||
/** | |||
* 等待结果合约调用的结果返回; | |||
* | |||
* @param timeout | |||
* @param unit | |||
* @return | |||
* @throws TimeoutException | |||
*/ | |||
@SuppressWarnings("unchecked") | |||
public T get(long timeout, TimeUnit unit) throws TimeoutException { | |||
return (T) super.getValue(timeout, unit); | |||
} | |||
} |
@@ -1,42 +0,0 @@ | |||
package com.jd.blockchain.transaction; | |||
import java.util.concurrent.ExecutionException; | |||
import java.util.concurrent.TimeUnit; | |||
import java.util.concurrent.TimeoutException; | |||
class ValueHolderBase { | |||
private ContractInvocation invocation; | |||
protected ValueHolderBase(ContractInvocation invocation) { | |||
this.invocation = invocation; | |||
} | |||
/** | |||
* 等待结果合约调用的结果返回; | |||
* | |||
* @return | |||
*/ | |||
protected Object getValue() { | |||
try { | |||
return invocation.getReturnValue().get(); | |||
} catch (InterruptedException | ExecutionException e) { | |||
throw new IllegalStateException(e.getMessage(), e); | |||
} | |||
} | |||
/** | |||
* 等待结果合约调用的结果返回; | |||
* | |||
* @param timeout | |||
* @param unit | |||
* @return | |||
* @throws TimeoutException | |||
*/ | |||
protected Object getValue(long timeout, TimeUnit unit) throws TimeoutException { | |||
try { | |||
return invocation.getReturnValue().get(timeout, unit); | |||
} catch (InterruptedException | ExecutionException e) { | |||
throw new IllegalStateException(e.getMessage(), e); | |||
} | |||
} | |||
} |
@@ -0,0 +1,34 @@ | |||
package com.jd.blockchain.transaction; | |||
class ValueHolderWrapper { | |||
private OperationResultHolder valueHolder; | |||
protected ValueHolderWrapper(OperationResultHolder valueHolder) { | |||
this.valueHolder = valueHolder; | |||
} | |||
public boolean isCompleted() { | |||
return valueHolder.isCompleted(); | |||
} | |||
public Throwable getError() { | |||
return valueHolder.getError(); | |||
} | |||
/** | |||
* 获取值;<br> | |||
* | |||
* 此方法不堵塞,调用立即返回;<br> | |||
* | |||
* 如果未完成时( {@link #isCompleted()} 为 false ),总是返回 null; | |||
* | |||
* @return | |||
*/ | |||
protected Object getValue() { | |||
return valueHolder.getResult(); | |||
} | |||
public void addCompletedListener(OperationCompletedListener listener) { | |||
valueHolder.addCompletedListener(listener); | |||
} | |||
} |
@@ -8,21 +8,22 @@ | |||
*/ | |||
package test.com.jd.blockchain.ledger.data; | |||
import static org.junit.Assert.assertArrayEquals; | |||
import static org.junit.Assert.assertEquals; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
import com.jd.blockchain.binaryproto.BinaryProtocol; | |||
import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
import com.jd.blockchain.ledger.BytesData; | |||
import com.jd.blockchain.ledger.BytesDataList; | |||
import com.jd.blockchain.ledger.BytesValueList; | |||
import com.jd.blockchain.ledger.ContractEventSendOperation; | |||
import com.jd.blockchain.ledger.DataAccountKVSetOperation; | |||
import com.jd.blockchain.ledger.Operation; | |||
import com.jd.blockchain.transaction.ContractEventSendOpTemplate; | |||
import com.jd.blockchain.transaction.DataAccountKVSetOpTemplate; | |||
import com.jd.blockchain.utils.Bytes; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
import static org.junit.Assert.assertArrayEquals; | |||
import static org.junit.Assert.assertEquals; | |||
/** | |||
* | |||
* @author shaozhuguang | |||
@@ -32,34 +33,36 @@ import static org.junit.Assert.assertEquals; | |||
public class ContractEventSendOpTemplateTest { | |||
private ContractEventSendOpTemplate data; | |||
private ContractEventSendOpTemplate data; | |||
@Before | |||
public void initContractEventSendOpTemplate() { | |||
DataContractRegistry.register(ContractEventSendOperation.class); | |||
DataContractRegistry.register(Operation.class); | |||
String contractAddress = "zhangsan-address", event = "zhangsan-event"; | |||
byte[] args = "zhangsan-args".getBytes(); | |||
data = new ContractEventSendOpTemplate(Bytes.fromString(contractAddress), event, args); | |||
} | |||
@Before | |||
public void initContractEventSendOpTemplate() { | |||
DataContractRegistry.register(ContractEventSendOperation.class); | |||
DataContractRegistry.register(Operation.class); | |||
String contractAddress = "zhangsan-address", event = "zhangsan-event"; | |||
BytesValueList args = new BytesDataList(BytesData.fromText("zhangsan-args")); | |||
data = new ContractEventSendOpTemplate(Bytes.fromString(contractAddress), event, args); | |||
} | |||
@Test | |||
public void testSerialize_ContractEventSendOperation() throws Exception { | |||
byte[] serialBytes = BinaryProtocol.encode(data, ContractEventSendOperation.class); | |||
ContractEventSendOperation resolvedData = BinaryProtocol.decode(serialBytes); | |||
System.out.println("------Assert start ------"); | |||
assertEquals(resolvedData.getContractAddress(), data.getContractAddress()); | |||
assertEquals(resolvedData.getEvent(), data.getEvent()); | |||
assertArrayEquals(resolvedData.getArgs(), data.getArgs()); | |||
System.out.println("------Assert OK ------"); | |||
} | |||
@Test | |||
public void testSerialize_ContractEventSendOperation() throws Exception { | |||
byte[] serialBytes = BinaryProtocol.encode(data, ContractEventSendOperation.class); | |||
ContractEventSendOperation resolvedData = BinaryProtocol.decode(serialBytes); | |||
System.out.println("------Assert start ------"); | |||
assertEquals(resolvedData.getContractAddress(), data.getContractAddress()); | |||
assertEquals(resolvedData.getEvent(), data.getEvent()); | |||
byte[] expectedBytes = BinaryProtocol.encode(resolvedData.getArgs(), BytesValueList.class); | |||
byte[] actualBytes = BinaryProtocol.encode(data.getArgs(), BytesValueList.class); | |||
assertArrayEquals(expectedBytes, actualBytes); | |||
System.out.println("------Assert OK ------"); | |||
} | |||
@Test | |||
public void testSerialize_Operation() throws Exception { | |||
byte[] serialBytes = BinaryProtocol.encode(data, Operation.class); | |||
Operation resolvedData = BinaryProtocol.decode(serialBytes); | |||
System.out.println("------Assert start ------"); | |||
System.out.println(resolvedData); | |||
System.out.println("------Assert OK ------"); | |||
} | |||
@Test | |||
public void testSerialize_Operation() throws Exception { | |||
byte[] serialBytes = BinaryProtocol.encode(data, Operation.class); | |||
Operation resolvedData = BinaryProtocol.decode(serialBytes); | |||
System.out.println("------Assert start ------"); | |||
System.out.println(resolvedData); | |||
System.out.println("------Assert OK ------"); | |||
} | |||
} |
@@ -16,7 +16,7 @@ import org.junit.Test; | |||
import com.jd.blockchain.binaryproto.BinaryProtocol; | |||
import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
import com.jd.blockchain.ledger.BytesValueEntry; | |||
import com.jd.blockchain.ledger.BytesData; | |||
import com.jd.blockchain.ledger.DataAccountKVSetOperation; | |||
import com.jd.blockchain.ledger.Operation; | |||
import com.jd.blockchain.transaction.DataAccountKVSetOpTemplate; | |||
@@ -42,11 +42,11 @@ public class DataAccountKVSetOpTemplateTest { | |||
String accountAddress = "zhangsandhakhdkah"; | |||
data = new DataAccountKVSetOpTemplate(Bytes.fromString(accountAddress)); | |||
KVData kvData1 = | |||
new KVData("test1", BytesValueEntry.fromText("zhangsan"), 9999L); | |||
new KVData("test1", BytesData.fromText("zhangsan"), 9999L); | |||
KVData kvData2 = | |||
new KVData("test2", BytesValueEntry.fromText("lisi"), 9990L); | |||
new KVData("test2", BytesData.fromText("lisi"), 9990L); | |||
KVData kvData3 = | |||
new KVData("test3", BytesValueEntry.fromText("wangwu"), 1990L); | |||
new KVData("test3", BytesData.fromText("wangwu"), 1990L); | |||
data.set(kvData1); | |||
data.set(kvData2); | |||
data.set(kvData3); | |||
@@ -16,7 +16,7 @@ import org.junit.Test; | |||
import com.jd.blockchain.binaryproto.BinaryProtocol; | |||
import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
import com.jd.blockchain.ledger.BytesValueEntry; | |||
import com.jd.blockchain.ledger.BytesData; | |||
import com.jd.blockchain.ledger.DataAccountKVSetOperation; | |||
import com.jd.blockchain.transaction.DataAccountKVSetOpTemplate; | |||
import com.jd.blockchain.transaction.KVData; | |||
@@ -38,7 +38,7 @@ public class KVDataTest { | |||
byte[] value = "test-value".getBytes(); | |||
long expectedVersion = 9999L; | |||
kvData = new KVData(key, BytesValueEntry.fromBytes(value), expectedVersion); | |||
kvData = new KVData(key, BytesData.fromBytes(value), expectedVersion); | |||
} | |||
@Test | |||
@@ -31,346 +31,348 @@ import java.lang.reflect.Field; | |||
public class ClientResolveUtil { | |||
public static KVDataEntry[] read(KVDataEntry[] kvDataEntries) { | |||
if (kvDataEntries == null || kvDataEntries.length == 0) { | |||
return kvDataEntries; | |||
} | |||
KVDataEntry[] resolveKvDataEntries = new KVDataEntry[kvDataEntries.length]; | |||
// kvDataEntries是代理对象,需要处理 | |||
for (int i = 0; i < kvDataEntries.length; i++) { | |||
KVDataEntry kvDataEntry = kvDataEntries[i]; | |||
String key = kvDataEntry.getKey(); | |||
long version = kvDataEntry.getVersion(); | |||
DataType dataType = kvDataEntry.getType(); | |||
KvData innerKvData = new KvData(key, version, dataType); | |||
Object valueObj = kvDataEntry.getValue(); | |||
switch (dataType) { | |||
case NIL: | |||
break; | |||
case BYTES: | |||
case TEXT: | |||
case JSON: | |||
innerKvData.setValue(valueObj.toString()); | |||
break; | |||
case INT32: | |||
innerKvData.setValue(Integer.parseInt(valueObj.toString())); | |||
break; | |||
case INT64: | |||
innerKvData.setValue(Long.parseLong(valueObj.toString())); | |||
break; | |||
default: | |||
throw new IllegalStateException("Unsupported value type[" + dataType + "] to resolve!"); | |||
} | |||
resolveKvDataEntries[i] = innerKvData; | |||
} | |||
return resolveKvDataEntries; | |||
} | |||
public static Operation read(Operation operation) { | |||
try { | |||
// Class | |||
Class<?> clazz = operation.getClass(); | |||
Field field = clazz.getSuperclass().getDeclaredField("h"); | |||
field.setAccessible(true); | |||
Object object = field.get(operation); | |||
if (object instanceof JSONObject) { | |||
JSONObject jsonObject = (JSONObject) object; | |||
if (jsonObject.containsKey("accountID")) { | |||
return convertDataAccountRegisterOperation(jsonObject); | |||
} else if (jsonObject.containsKey("userID")) { | |||
return convertUserRegisterOperation(jsonObject); | |||
} else if (jsonObject.containsKey("contractID")) { | |||
return convertContractCodeDeployOperation(jsonObject); | |||
} else if (jsonObject.containsKey("writeSet")) { | |||
return convertDataAccountKVSetOperation(jsonObject); | |||
} else if (jsonObject.containsKey("initSetting")) { | |||
return convertLedgerInitOperation(jsonObject); | |||
} else if (jsonObject.containsKey("contractAddress")) { | |||
return convertContractEventSendOperation(jsonObject); | |||
} | |||
} | |||
} catch (Exception e) { | |||
throw new RuntimeException(e); | |||
} | |||
return null; | |||
} | |||
public static Object readValueByBytesValue(BytesValue bytesValue) { | |||
DataType dataType = bytesValue.getType(); | |||
Bytes saveVal = bytesValue.getValue(); | |||
Object showVal; | |||
switch (dataType) { | |||
case BYTES: | |||
// return hex | |||
showVal = HexUtils.encode(saveVal.toBytes()); | |||
break; | |||
case TEXT: | |||
case JSON: | |||
showVal = saveVal.toUTF8String(); | |||
break; | |||
case INT64: | |||
showVal = BytesUtils.toLong(saveVal.toBytes()); | |||
break; | |||
default: | |||
showVal = HexUtils.encode(saveVal.toBytes()); | |||
break; | |||
} | |||
return showVal; | |||
} | |||
public static DataAccountRegisterOperation convertDataAccountRegisterOperation(JSONObject jsonObject) { | |||
JSONObject account = jsonObject.getJSONObject("accountID"); | |||
return new DataAccountRegisterOpTemplate(blockchainIdentity(account)); | |||
} | |||
public static DataAccountKVSetOperation convertDataAccountKVSetOperation(JSONObject jsonObject) { | |||
// 写入集合处理 | |||
JSONArray writeSetObj = jsonObject.getJSONArray("writeSet"); | |||
JSONObject accountAddrObj = jsonObject.getJSONObject("accountAddress"); | |||
String addressBase58 = accountAddrObj.getString("value"); | |||
Bytes address = Bytes.fromBase58(addressBase58); | |||
DataAccountKVSetOpTemplate kvOperation = new DataAccountKVSetOpTemplate(address); | |||
for (int i = 0; i <writeSetObj.size(); i++) { | |||
JSONObject currWriteSetObj = writeSetObj.getJSONObject(i); | |||
long expectedVersion = currWriteSetObj.getLong("expectedVersion"); | |||
JSONObject valueObj = currWriteSetObj.getJSONObject("value"); | |||
String typeStr = valueObj.getString("type"); | |||
String realValBase58 = valueObj.getString("value"); | |||
String key = currWriteSetObj.getString("key"); | |||
DataType dataType = DataType.valueOf(typeStr); | |||
BytesValue bytesValue =BytesValueEntry.fromType(dataType, Base58Utils.decode(realValBase58)); | |||
KVData kvData = new KVData(key, bytesValue, expectedVersion); | |||
kvOperation.set(kvData); | |||
} | |||
return kvOperation; | |||
} | |||
public static LedgerInitOperation convertLedgerInitOperation(JSONObject jsonObject) { | |||
JSONObject legerInitObj = jsonObject.getJSONObject("initSetting"); | |||
LedgerInitSettingData ledgerInitSettingData = new LedgerInitSettingData(); | |||
String ledgerSeedStr = legerInitObj.getString("ledgerSeed"); | |||
// 种子需要做Base64转换 | |||
ledgerInitSettingData.setLedgerSeed(Base64.decodeBase64(BytesUtils.toBytes(ledgerSeedStr))); | |||
String consensusProvider = legerInitObj.getString("consensusProvider"); | |||
ledgerInitSettingData.setConsensusProvider(consensusProvider); | |||
JSONObject cryptoSettingObj = legerInitObj.getJSONObject("cryptoSetting"); | |||
boolean autoVerifyHash = cryptoSettingObj.getBoolean("autoVerifyHash"); | |||
short hashAlgorithm = cryptoSettingObj.getShort("hashAlgorithm"); | |||
CryptoConfig cryptoConfig = new CryptoConfig(); | |||
cryptoConfig.setAutoVerifyHash(autoVerifyHash); | |||
cryptoConfig.setHashAlgorithm(hashAlgorithm); | |||
ledgerInitSettingData.setCryptoSetting(cryptoConfig); | |||
JSONObject consensusSettingsObj = legerInitObj.getJSONObject("consensusSettings"); | |||
Bytes consensusSettings = Bytes.fromBase58(consensusSettingsObj.getString("value")); | |||
ledgerInitSettingData.setConsensusSettings(consensusSettings); | |||
JSONArray consensusParticipantsArray = legerInitObj.getJSONArray("consensusParticipants"); | |||
if (!consensusParticipantsArray.isEmpty()) { | |||
ParticipantNode[] participantNodes = new ParticipantNode[consensusParticipantsArray.size()]; | |||
for (int i = 0; i < consensusParticipantsArray.size(); i++) { | |||
JSONObject currConsensusParticipant = consensusParticipantsArray.getJSONObject(i); | |||
String addressBase58 = currConsensusParticipant.getString("address"); | |||
String name = currConsensusParticipant.getString("name"); | |||
int id = currConsensusParticipant.getInteger("id"); | |||
JSONObject pubKeyObj = currConsensusParticipant.getJSONObject("pubKey"); | |||
String pubKeyBase58 = pubKeyObj.getString("value"); | |||
// 生成ParticipantNode对象 | |||
ParticipantCertData participantCertData = new ParticipantCertData(id, addressBase58, name, new PubKey(Bytes.fromBase58(pubKeyBase58).toBytes())); | |||
participantNodes[i] = participantCertData; | |||
} | |||
ledgerInitSettingData.setConsensusParticipants(participantNodes); | |||
} | |||
return new LedgerInitOpTemplate(ledgerInitSettingData); | |||
} | |||
public static UserRegisterOperation convertUserRegisterOperation(JSONObject jsonObject) { | |||
JSONObject user = jsonObject.getJSONObject("userID"); | |||
return new UserRegisterOpTemplate(blockchainIdentity(user)); | |||
} | |||
public static ContractCodeDeployOperation convertContractCodeDeployOperation(JSONObject jsonObject) { | |||
JSONObject contract = jsonObject.getJSONObject("contractID"); | |||
BlockchainIdentityData blockchainIdentity = blockchainIdentity(contract); | |||
String chainCodeStr = jsonObject.getString("chainCode"); | |||
ContractCodeDeployOpTemplate contractCodeDeployOpTemplate = new ContractCodeDeployOpTemplate(blockchainIdentity, BytesUtils.toBytes(chainCodeStr)); | |||
return contractCodeDeployOpTemplate; | |||
} | |||
public static ContractEventSendOperation convertContractEventSendOperation(JSONObject jsonObject) { | |||
JSONObject contractAddressObj = jsonObject.getJSONObject("contractAddress"); | |||
String contractAddress = contractAddressObj.getString("value"); | |||
String argsStr = jsonObject.getString("args"); | |||
String event = jsonObject.getString("event"); | |||
return new ContractEventSendOpTemplate(Bytes.fromBase58(contractAddress), event, BytesUtils.toBytes(argsStr)); | |||
} | |||
private static BlockchainIdentityData blockchainIdentity(JSONObject jsonObject) { | |||
JSONObject addressObj = jsonObject.getJSONObject("address"); | |||
// base58值 | |||
String addressBase58 = addressObj.getString("value"); | |||
Bytes address = Bytes.fromBase58(addressBase58); | |||
JSONObject pubKeyObj = jsonObject.getJSONObject("pubKey"); | |||
// base58值 | |||
String pubKeyBase58 = pubKeyObj.getString("value"); | |||
PubKey pubKey = new PubKey(Bytes.fromBase58(pubKeyBase58).toBytes()); | |||
// 生成对应的对象 | |||
return new BlockchainIdentityData(address, pubKey); | |||
} | |||
public static class CryptoConfig implements CryptoSetting { | |||
private short hashAlgorithm; | |||
private boolean autoVerifyHash; | |||
@Override | |||
public CryptoProvider[] getSupportedProviders() { | |||
return new CryptoProvider[0]; | |||
} | |||
@Override | |||
public short getHashAlgorithm() { | |||
return hashAlgorithm; | |||
} | |||
@Override | |||
public boolean getAutoVerifyHash() { | |||
return autoVerifyHash; | |||
} | |||
public void setHashAlgorithm(short hashAlgorithm) { | |||
this.hashAlgorithm = hashAlgorithm; | |||
} | |||
public void setAutoVerifyHash(boolean autoVerifyHash) { | |||
this.autoVerifyHash = autoVerifyHash; | |||
} | |||
} | |||
public static class ParticipantCertData implements ParticipantNode{ | |||
private int id; | |||
private String address; | |||
private String name; | |||
private PubKey pubKey; | |||
public ParticipantCertData() { | |||
} | |||
public ParticipantCertData(ParticipantNode participantNode) { | |||
this.address = participantNode.getAddress(); | |||
this.name = participantNode.getName(); | |||
this.pubKey = participantNode.getPubKey(); | |||
} | |||
public ParticipantCertData(int id, String address, String name, PubKey pubKey) { | |||
this.id = id; | |||
this.address = address; | |||
this.name = name; | |||
this.pubKey = pubKey; | |||
} | |||
@Override | |||
public String getAddress() { | |||
return address; | |||
} | |||
@Override | |||
public String getName() { | |||
return name; | |||
} | |||
@Override | |||
public PubKey getPubKey() { | |||
return pubKey; | |||
} | |||
public int getId() { | |||
return id; | |||
} | |||
public void setId(int id) { | |||
this.id = id; | |||
} | |||
} | |||
public static class KvData implements KVDataEntry { | |||
private String key; | |||
private long version; | |||
private DataType dataType; | |||
private Object value; | |||
public KvData() { | |||
} | |||
public KvData(String key, long version, DataType dataType) { | |||
this(key, version, dataType, null); | |||
} | |||
public KvData(String key, long version, DataType dataType, Object value) { | |||
this.key = key; | |||
this.version = version; | |||
this.dataType = dataType; | |||
this.value = value; | |||
} | |||
public void setKey(String key) { | |||
this.key = key; | |||
} | |||
public void setVersion(long version) { | |||
this.version = version; | |||
} | |||
public void setDataType(DataType dataType) { | |||
this.dataType = dataType; | |||
} | |||
public void setValue(Object value) { | |||
this.value = value; | |||
} | |||
@Override | |||
public String getKey() { | |||
return key; | |||
} | |||
@Override | |||
public long getVersion() { | |||
return version; | |||
} | |||
@Override | |||
public DataType getType() { | |||
return dataType; | |||
} | |||
@Override | |||
public Object getValue() { | |||
return value; | |||
} | |||
} | |||
public static KVDataEntry[] read(KVDataEntry[] kvDataEntries) { | |||
if (kvDataEntries == null || kvDataEntries.length == 0) { | |||
return kvDataEntries; | |||
} | |||
KVDataEntry[] resolveKvDataEntries = new KVDataEntry[kvDataEntries.length]; | |||
// kvDataEntries是代理对象,需要处理 | |||
for (int i = 0; i < kvDataEntries.length; i++) { | |||
KVDataEntry kvDataEntry = kvDataEntries[i]; | |||
String key = kvDataEntry.getKey(); | |||
long version = kvDataEntry.getVersion(); | |||
DataType dataType = kvDataEntry.getType(); | |||
KvData innerKvData = new KvData(key, version, dataType); | |||
Object valueObj = kvDataEntry.getValue(); | |||
switch (dataType) { | |||
case NIL: | |||
break; | |||
case BYTES: | |||
case TEXT: | |||
case JSON: | |||
innerKvData.setValue(valueObj.toString()); | |||
break; | |||
case INT32: | |||
innerKvData.setValue(Integer.parseInt(valueObj.toString())); | |||
break; | |||
case INT64: | |||
innerKvData.setValue(Long.parseLong(valueObj.toString())); | |||
break; | |||
default: | |||
throw new IllegalStateException("Unsupported value type[" + dataType + "] to resolve!"); | |||
} | |||
resolveKvDataEntries[i] = innerKvData; | |||
} | |||
return resolveKvDataEntries; | |||
} | |||
public static Operation read(Operation operation) { | |||
try { | |||
// Class | |||
Class<?> clazz = operation.getClass(); | |||
Field field = clazz.getSuperclass().getDeclaredField("h"); | |||
field.setAccessible(true); | |||
Object object = field.get(operation); | |||
if (object instanceof JSONObject) { | |||
JSONObject jsonObject = (JSONObject) object; | |||
if (jsonObject.containsKey("accountID")) { | |||
return convertDataAccountRegisterOperation(jsonObject); | |||
} else if (jsonObject.containsKey("userID")) { | |||
return convertUserRegisterOperation(jsonObject); | |||
} else if (jsonObject.containsKey("contractID")) { | |||
return convertContractCodeDeployOperation(jsonObject); | |||
} else if (jsonObject.containsKey("writeSet")) { | |||
return convertDataAccountKVSetOperation(jsonObject); | |||
} else if (jsonObject.containsKey("initSetting")) { | |||
return convertLedgerInitOperation(jsonObject); | |||
} else if (jsonObject.containsKey("contractAddress")) { | |||
return convertContractEventSendOperation(jsonObject); | |||
} | |||
} | |||
} catch (Exception e) { | |||
throw new RuntimeException(e); | |||
} | |||
return null; | |||
} | |||
public static Object readValueByBytesValue(BytesValue bytesValue) { | |||
DataType dataType = bytesValue.getType(); | |||
Bytes saveVal = bytesValue.getValue(); | |||
Object showVal; | |||
switch (dataType) { | |||
case BYTES: | |||
// return hex | |||
showVal = HexUtils.encode(saveVal.toBytes()); | |||
break; | |||
case TEXT: | |||
case JSON: | |||
showVal = saveVal.toUTF8String(); | |||
break; | |||
case INT64: | |||
showVal = BytesUtils.toLong(saveVal.toBytes()); | |||
break; | |||
default: | |||
showVal = HexUtils.encode(saveVal.toBytes()); | |||
break; | |||
} | |||
return showVal; | |||
} | |||
public static DataAccountRegisterOperation convertDataAccountRegisterOperation(JSONObject jsonObject) { | |||
JSONObject account = jsonObject.getJSONObject("accountID"); | |||
return new DataAccountRegisterOpTemplate(blockchainIdentity(account)); | |||
} | |||
public static DataAccountKVSetOperation convertDataAccountKVSetOperation(JSONObject jsonObject) { | |||
// 写入集合处理 | |||
JSONArray writeSetObj = jsonObject.getJSONArray("writeSet"); | |||
JSONObject accountAddrObj = jsonObject.getJSONObject("accountAddress"); | |||
String addressBase58 = accountAddrObj.getString("value"); | |||
Bytes address = Bytes.fromBase58(addressBase58); | |||
DataAccountKVSetOpTemplate kvOperation = new DataAccountKVSetOpTemplate(address); | |||
for (int i = 0; i < writeSetObj.size(); i++) { | |||
JSONObject currWriteSetObj = writeSetObj.getJSONObject(i); | |||
long expectedVersion = currWriteSetObj.getLong("expectedVersion"); | |||
JSONObject valueObj = currWriteSetObj.getJSONObject("value"); | |||
String typeStr = valueObj.getString("type"); | |||
String realValBase58 = valueObj.getString("value"); | |||
String key = currWriteSetObj.getString("key"); | |||
DataType dataType = DataType.valueOf(typeStr); | |||
BytesValue bytesValue = BytesData.fromType(dataType, Base58Utils.decode(realValBase58)); | |||
KVData kvData = new KVData(key, bytesValue, expectedVersion); | |||
kvOperation.set(kvData); | |||
} | |||
return kvOperation; | |||
} | |||
public static LedgerInitOperation convertLedgerInitOperation(JSONObject jsonObject) { | |||
JSONObject legerInitObj = jsonObject.getJSONObject("initSetting"); | |||
LedgerInitSettingData ledgerInitSettingData = new LedgerInitSettingData(); | |||
String ledgerSeedStr = legerInitObj.getString("ledgerSeed"); | |||
// 种子需要做Base64转换 | |||
ledgerInitSettingData.setLedgerSeed(Base64.decodeBase64(BytesUtils.toBytes(ledgerSeedStr))); | |||
String consensusProvider = legerInitObj.getString("consensusProvider"); | |||
ledgerInitSettingData.setConsensusProvider(consensusProvider); | |||
JSONObject cryptoSettingObj = legerInitObj.getJSONObject("cryptoSetting"); | |||
boolean autoVerifyHash = cryptoSettingObj.getBoolean("autoVerifyHash"); | |||
short hashAlgorithm = cryptoSettingObj.getShort("hashAlgorithm"); | |||
CryptoConfig cryptoConfig = new CryptoConfig(); | |||
cryptoConfig.setAutoVerifyHash(autoVerifyHash); | |||
cryptoConfig.setHashAlgorithm(hashAlgorithm); | |||
ledgerInitSettingData.setCryptoSetting(cryptoConfig); | |||
JSONObject consensusSettingsObj = legerInitObj.getJSONObject("consensusSettings"); | |||
Bytes consensusSettings = Bytes.fromBase58(consensusSettingsObj.getString("value")); | |||
ledgerInitSettingData.setConsensusSettings(consensusSettings); | |||
JSONArray consensusParticipantsArray = legerInitObj.getJSONArray("consensusParticipants"); | |||
if (!consensusParticipantsArray.isEmpty()) { | |||
ParticipantNode[] participantNodes = new ParticipantNode[consensusParticipantsArray.size()]; | |||
for (int i = 0; i < consensusParticipantsArray.size(); i++) { | |||
JSONObject currConsensusParticipant = consensusParticipantsArray.getJSONObject(i); | |||
String addressBase58 = currConsensusParticipant.getString("address"); | |||
String name = currConsensusParticipant.getString("name"); | |||
int id = currConsensusParticipant.getInteger("id"); | |||
JSONObject pubKeyObj = currConsensusParticipant.getJSONObject("pubKey"); | |||
String pubKeyBase58 = pubKeyObj.getString("value"); | |||
// 生成ParticipantNode对象 | |||
ParticipantCertData participantCertData = new ParticipantCertData(id, addressBase58, name, | |||
new PubKey(Bytes.fromBase58(pubKeyBase58).toBytes())); | |||
participantNodes[i] = participantCertData; | |||
} | |||
ledgerInitSettingData.setConsensusParticipants(participantNodes); | |||
} | |||
return new LedgerInitOpTemplate(ledgerInitSettingData); | |||
} | |||
public static UserRegisterOperation convertUserRegisterOperation(JSONObject jsonObject) { | |||
JSONObject user = jsonObject.getJSONObject("userID"); | |||
return new UserRegisterOpTemplate(blockchainIdentity(user)); | |||
} | |||
public static ContractCodeDeployOperation convertContractCodeDeployOperation(JSONObject jsonObject) { | |||
JSONObject contract = jsonObject.getJSONObject("contractID"); | |||
BlockchainIdentityData blockchainIdentity = blockchainIdentity(contract); | |||
String chainCodeStr = jsonObject.getString("chainCode"); | |||
ContractCodeDeployOpTemplate contractCodeDeployOpTemplate = new ContractCodeDeployOpTemplate(blockchainIdentity, | |||
BytesUtils.toBytes(chainCodeStr)); | |||
return contractCodeDeployOpTemplate; | |||
} | |||
public static ContractEventSendOperation convertContractEventSendOperation(JSONObject jsonObject) { | |||
JSONObject contractAddressObj = jsonObject.getJSONObject("contractAddress"); | |||
String contractAddress = contractAddressObj.getString("value"); | |||
String argsStr = jsonObject.getString("args"); | |||
String event = jsonObject.getString("event"); | |||
return new ContractEventSendOpTemplate(Bytes.fromBase58(contractAddress), event, | |||
BytesDataList.singleText(argsStr)); | |||
} | |||
private static BlockchainIdentityData blockchainIdentity(JSONObject jsonObject) { | |||
JSONObject addressObj = jsonObject.getJSONObject("address"); | |||
// base58值 | |||
String addressBase58 = addressObj.getString("value"); | |||
Bytes address = Bytes.fromBase58(addressBase58); | |||
JSONObject pubKeyObj = jsonObject.getJSONObject("pubKey"); | |||
// base58值 | |||
String pubKeyBase58 = pubKeyObj.getString("value"); | |||
PubKey pubKey = new PubKey(Bytes.fromBase58(pubKeyBase58).toBytes()); | |||
// 生成对应的对象 | |||
return new BlockchainIdentityData(address, pubKey); | |||
} | |||
public static class CryptoConfig implements CryptoSetting { | |||
private short hashAlgorithm; | |||
private boolean autoVerifyHash; | |||
@Override | |||
public CryptoProvider[] getSupportedProviders() { | |||
return new CryptoProvider[0]; | |||
} | |||
@Override | |||
public short getHashAlgorithm() { | |||
return hashAlgorithm; | |||
} | |||
@Override | |||
public boolean getAutoVerifyHash() { | |||
return autoVerifyHash; | |||
} | |||
public void setHashAlgorithm(short hashAlgorithm) { | |||
this.hashAlgorithm = hashAlgorithm; | |||
} | |||
public void setAutoVerifyHash(boolean autoVerifyHash) { | |||
this.autoVerifyHash = autoVerifyHash; | |||
} | |||
} | |||
public static class ParticipantCertData implements ParticipantNode { | |||
private int id; | |||
private String address; | |||
private String name; | |||
private PubKey pubKey; | |||
public ParticipantCertData() { | |||
} | |||
public ParticipantCertData(ParticipantNode participantNode) { | |||
this.address = participantNode.getAddress(); | |||
this.name = participantNode.getName(); | |||
this.pubKey = participantNode.getPubKey(); | |||
} | |||
public ParticipantCertData(int id, String address, String name, PubKey pubKey) { | |||
this.id = id; | |||
this.address = address; | |||
this.name = name; | |||
this.pubKey = pubKey; | |||
} | |||
@Override | |||
public String getAddress() { | |||
return address; | |||
} | |||
@Override | |||
public String getName() { | |||
return name; | |||
} | |||
@Override | |||
public PubKey getPubKey() { | |||
return pubKey; | |||
} | |||
public int getId() { | |||
return id; | |||
} | |||
public void setId(int id) { | |||
this.id = id; | |||
} | |||
} | |||
public static class KvData implements KVDataEntry { | |||
private String key; | |||
private long version; | |||
private DataType dataType; | |||
private Object value; | |||
public KvData() { | |||
} | |||
public KvData(String key, long version, DataType dataType) { | |||
this(key, version, dataType, null); | |||
} | |||
public KvData(String key, long version, DataType dataType, Object value) { | |||
this.key = key; | |||
this.version = version; | |||
this.dataType = dataType; | |||
this.value = value; | |||
} | |||
public void setKey(String key) { | |||
this.key = key; | |||
} | |||
public void setVersion(long version) { | |||
this.version = version; | |||
} | |||
public void setDataType(DataType dataType) { | |||
this.dataType = dataType; | |||
} | |||
public void setValue(Object value) { | |||
this.value = value; | |||
} | |||
@Override | |||
public String getKey() { | |||
return key; | |||
} | |||
@Override | |||
public long getVersion() { | |||
return version; | |||
} | |||
@Override | |||
public DataType getType() { | |||
return dataType; | |||
} | |||
@Override | |||
public Object getValue() { | |||
return value; | |||
} | |||
} | |||
} |
@@ -11,7 +11,7 @@ import com.jd.blockchain.ledger.PreparedTransaction; | |||
import com.jd.blockchain.ledger.TransactionResponse; | |||
import com.jd.blockchain.ledger.TransactionTemplate; | |||
import com.jd.blockchain.transaction.LongValueHolder; | |||
import com.jd.blockchain.transaction.ValueHolder; | |||
import com.jd.blockchain.transaction.GenericValueHolder; | |||
import com.jd.blockchain.utils.Bytes; | |||
public class SDK_Contract_Demo extends SDK_Base_Demo { | |||
@@ -92,7 +92,7 @@ public class SDK_Contract_Demo extends SDK_Base_Demo { | |||
TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); | |||
// 使用合约创建 | |||
TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class); | |||
ValueHolder<String> result = decode(transferContract.readAll(address, account)); | |||
GenericValueHolder<String> result = decode(transferContract.readAll(address, account)); | |||
commit(txTpl); | |||
return result.get(); | |||
} | |||
@@ -122,7 +122,7 @@ public class SDK_Contract_Demo extends SDK_Base_Demo { | |||
TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); | |||
// 使用合约创建 | |||
TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class); | |||
ValueHolder<String> result = decode(transferContract.transfer(address, from, to, money)); | |||
GenericValueHolder<String> result = decode(transferContract.transfer(address, from, to, money)); | |||
commit(txTpl); | |||
return result.get(); | |||
} | |||
@@ -142,7 +142,7 @@ public class SDK_Contract_Demo extends SDK_Base_Demo { | |||
if (useContract) { | |||
// 使用合约创建 | |||
TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class); | |||
ValueHolder<String> result = decode(transferContract.create(address, account, money)); | |||
GenericValueHolder<String> result = decode(transferContract.create(address, account, money)); | |||
commit(txTpl); | |||
return result.get(); | |||
} else { | |||
@@ -20,7 +20,7 @@ import com.jd.blockchain.sdk.client.GatewayServiceFactory; | |||
import com.jd.blockchain.sdk.samples.SDKDemo_Constant; | |||
import com.jd.blockchain.tools.keygen.KeyGenCommand; | |||
import com.jd.blockchain.transaction.LongValueHolder; | |||
import com.jd.blockchain.transaction.ValueHolder; | |||
import com.jd.blockchain.transaction.GenericValueHolder; | |||
import com.jd.blockchain.utils.Bytes; | |||
public class SDKDemo_Contract_Test { | |||
@@ -108,7 +108,7 @@ public class SDKDemo_Contract_Test { | |||
TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); | |||
// 使用合约创建 | |||
TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class); | |||
ValueHolder<String> result = decode(transferContract.readAll(address, account)); | |||
GenericValueHolder<String> result = decode(transferContract.readAll(address, account)); | |||
commit(txTpl); | |||
return result.get(); | |||
} | |||
@@ -126,7 +126,7 @@ public class SDKDemo_Contract_Test { | |||
TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); | |||
// 使用合约创建 | |||
TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class); | |||
ValueHolder<String> result = decode(transferContract.transfer(address, from, to, money)); | |||
GenericValueHolder<String> result = decode(transferContract.transfer(address, from, to, money)); | |||
commit(txTpl); | |||
return result.get(); | |||
} | |||
@@ -146,7 +146,7 @@ public class SDKDemo_Contract_Test { | |||
if (useContract) { | |||
// 使用合约创建 | |||
TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class); | |||
ValueHolder<String> result = decode(transferContract.create(address, account, money)); | |||
GenericValueHolder<String> result = decode(transferContract.create(address, account, money)); | |||
commit(txTpl); | |||
return result.get(); | |||
} else { | |||
@@ -24,6 +24,7 @@ import com.jd.blockchain.crypto.PrivKey; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.BlockchainKeyGenerator; | |||
import com.jd.blockchain.ledger.BlockchainKeypair; | |||
import com.jd.blockchain.ledger.BytesDataList; | |||
import com.jd.blockchain.ledger.DataAccountKVSetOperation; | |||
import com.jd.blockchain.ledger.DataAccountRegisterOperation; | |||
import com.jd.blockchain.ledger.LedgerBlock; | |||
@@ -143,8 +144,9 @@ public class LedgerPerformanceTest { | |||
batchCount = Integer.parseInt(args[1]); | |||
} | |||
} | |||
if (contract){ | |||
testContract(ledgerHash, testNode.getPartiKey(), ledgerManager, opHandler, batchSize, batchCount, silent); | |||
if (contract) { | |||
testContract(ledgerHash, testNode.getPartiKey(), ledgerManager, opHandler, batchSize, batchCount, | |||
silent); | |||
} | |||
if (usertest) { | |||
@@ -177,8 +179,9 @@ public class LedgerPerformanceTest { | |||
* @param batchCount | |||
* @param silent | |||
*/ | |||
private static void testUserRegistering(HashDigest ledgerHash, AsymmetricKeypair adminKey, LedgerManager ledgerManager, | |||
DefaultOperationHandleRegisteration opHandler, int batchSize, int batchCount, boolean silent) { | |||
private static void testUserRegistering(HashDigest ledgerHash, AsymmetricKeypair adminKey, | |||
LedgerManager ledgerManager, DefaultOperationHandleRegisteration opHandler, int batchSize, int batchCount, | |||
boolean silent) { | |||
LedgerRepository ledger = ledgerManager.getLedger(ledgerHash); | |||
ConsoleUtils.info("\r\n\r\n================= 准备测试交易 [注册用户] ================="); | |||
@@ -273,7 +276,7 @@ public class LedgerPerformanceTest { | |||
* @param silent | |||
*/ | |||
private static void testContract(HashDigest ledgerHash, AsymmetricKeypair adminKey, LedgerManager ledgerManager, | |||
DefaultOperationHandleRegisteration opHandler, int batchSize, int batchCount, boolean silent) { | |||
DefaultOperationHandleRegisteration opHandler, int batchSize, int batchCount, boolean silent) { | |||
LedgerRepository ledger = ledgerManager.getLedger(ledgerHash); | |||
ConsoleUtils.info("\r\n\r\n================= 准备测试交易 [执行合约] ================="); | |||
@@ -285,8 +288,8 @@ public class LedgerPerformanceTest { | |||
// 准备请求 | |||
int totalCount = batchSize * batchCount; | |||
List<TransactionRequest> contractTxList = prepareContractRequests(ledgerHash, | |||
adminKey, totalCount, false, txProc); | |||
List<TransactionRequest> contractTxList = prepareContractRequests(ledgerHash, adminKey, totalCount, false, | |||
txProc); | |||
Prompter consolePrompter = new PresetAnswerPrompter("N"); | |||
@@ -303,6 +306,7 @@ public class LedgerPerformanceTest { | |||
} | |||
} | |||
private static void execPerformanceTest(int batchCount, int batchSize, List<TransactionRequest> txList, | |||
LedgerRepository ledger, LedgerManager ledgerManager, DefaultOperationHandleRegisteration opHandler, | |||
boolean statistic) { | |||
@@ -407,8 +411,7 @@ public class LedgerPerformanceTest { | |||
// BlockchainKeyPair dataAccountKey = | |||
// BlockchainKeyGenerator.getInstance().generate(); | |||
BlockchainIdentity targetAccount = dataAccounts[count % dataAccounts.length]; | |||
txbuilder.dataAccount(targetAccount.getAddress()).setText("key-" + startTs + "-" + i, | |||
"value-" + i, -1L); | |||
txbuilder.dataAccount(targetAccount.getAddress()).setText("key-" + startTs + "-" + i, "value-" + i, -1L); | |||
TransactionRequestBuilder reqBuilder = txbuilder.prepareRequest(); | |||
reqBuilder.signAsEndpoint(adminKey); | |||
txList.add(reqBuilder.buildRequest()); | |||
@@ -426,8 +429,9 @@ public class LedgerPerformanceTest { | |||
public static ConsensusProvider getConsensusProvider(String provider) { | |||
return ConsensusProviders.getProvider(provider); | |||
} | |||
public static List<TransactionRequest> prepareContractRequests(HashDigest ledgerHash, | |||
AsymmetricKeypair adminKey, int count, boolean statistic, TransactionBatchProcessor txProc) { | |||
public static List<TransactionRequest> prepareContractRequests(HashDigest ledgerHash, AsymmetricKeypair adminKey, | |||
int count, boolean statistic, TransactionBatchProcessor txProc) { | |||
// deploy contract | |||
byte[] chainCode; | |||
@@ -436,7 +440,7 @@ public class LedgerPerformanceTest { | |||
InputStream input = LedgerPerformanceTest.class.getClassLoader().getResourceAsStream("example1.jar"); | |||
chainCode = new byte[input.available()]; | |||
input.read(chainCode); | |||
}catch (IOException e){ | |||
} catch (IOException e) { | |||
e.printStackTrace(); | |||
return null; | |||
} | |||
@@ -457,10 +461,10 @@ public class LedgerPerformanceTest { | |||
System.out.println(resp.isSuccess()); | |||
TransactionBatchResultHandle handle = txProc.prepare(); | |||
handle.commit(); | |||
try{ | |||
try { | |||
Thread.sleep(1000); | |||
} catch (Exception e){ | |||
} catch (Exception e) { | |||
e.printStackTrace(); | |||
} | |||
@@ -468,8 +472,9 @@ public class LedgerPerformanceTest { | |||
List<TransactionRequest> txList = new ArrayList<>(); | |||
for (int i = 0; i < count; i++) { | |||
txbuilder = new TxBuilder(ledgerHash); | |||
String args = dataIdentity.getAddress().toString() + "##"+Integer.toString(i)+ "##"+Integer.toString(i); | |||
txbuilder.contractEvents().send(contractIdentity.getAddress(), "hello", args.getBytes()); | |||
String args = dataIdentity.getAddress().toString() + "##" + Integer.toString(i) + "##" | |||
+ Integer.toString(i); | |||
txbuilder.contractEvents().send(contractIdentity.getAddress(), "print", BytesDataList.singleText("hello")); | |||
// txbuilder.contractEvents().send(contractIdentity.getAddress(), "print", args.getBytes()); | |||
reqBuilder = txbuilder.prepareRequest(); | |||
reqBuilder.signAsEndpoint(adminKey); | |||
@@ -485,7 +490,8 @@ public class LedgerPerformanceTest { | |||
return txList; | |||
} | |||
public static NodeContext[] initLedgers(boolean optimized, CryptoAlgorithm hashAlg, DBType dbType, String provider, String config) { | |||
public static NodeContext[] initLedgers(boolean optimized, CryptoAlgorithm hashAlg, DBType dbType, String provider, | |||
String config) { | |||
Map<NetworkAddress, LedgerInitConsensusService> serviceRegisterMap = new ConcurrentHashMap<>(); | |||
Prompter consolePrompter = new PresetAnswerPrompter("N"); // new ConsolePrompter(); | |||
@@ -29,7 +29,6 @@ import org.apache.commons.io.FileUtils; | |||
import org.springframework.core.io.ClassPathResource; | |||
import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
import com.jd.blockchain.contract.ContractSerializeUtils; | |||
import com.jd.blockchain.contract.ReadContract; | |||
import com.jd.blockchain.crypto.AddressEncoding; | |||
import com.jd.blockchain.crypto.AsymmetricKeypair; | |||
@@ -51,7 +50,7 @@ import com.jd.blockchain.sdk.BlockchainService; | |||
import com.jd.blockchain.storage.service.DbConnection; | |||
import com.jd.blockchain.storage.service.DbConnectionFactory; | |||
import com.jd.blockchain.tools.initializer.LedgerBindingConfig; | |||
import com.jd.blockchain.transaction.ValueHolder; | |||
import com.jd.blockchain.transaction.GenericValueHolder; | |||
import com.jd.blockchain.utils.Bytes; | |||
import com.jd.blockchain.utils.concurrent.ThreadInvoker; | |||
import com.jd.blockchain.utils.net.NetworkAddress; | |||
@@ -586,7 +585,7 @@ public class IntegrationBase { | |||
ReadContract readContract1 = txContract.contract(contractDeployKey.getAddress(), ReadContract.class); | |||
ValueHolder<String> result1 = decode(readContract1.read(newDataAccount.getAddress().toBase58(), key1)); | |||
GenericValueHolder<String> result1 = decode(readContract1.read(newDataAccount.getAddress().toBase58(), key1)); | |||
ReadContract readContract2 = txContract.contract(contractDeployKey.getAddress(), ReadContract.class); | |||
@@ -594,7 +593,7 @@ public class IntegrationBase { | |||
ReadContract readContract3 = txContract.contract(contractDeployKey.getAddress(), ReadContract.class); | |||
ValueHolder<Long> result3 = decode(readContract3.readVersion(newDataAccount.getAddress().toBase58(), key2)); | |||
GenericValueHolder<Long> result3 = decode(readContract3.readVersion(newDataAccount.getAddress().toBase58(), key2)); | |||
// 签名; | |||
PreparedTransaction contractPtx = txContract.prepare(); | |||
@@ -610,10 +609,10 @@ public class IntegrationBase { | |||
System.out.printf("readContract3.result = %s \r\n", result3.get()); | |||
// 打印结果 | |||
for (OperationResult or : operationResults) { | |||
System.out.printf("操作[%s].Result = %s \r\n", or.getIndex(), ContractSerializeUtils.resolve(or.getResult())); | |||
} | |||
// // 打印结果 | |||
// for (OperationResult or : operationResults) { | |||
// System.out.printf("操作[%s].Result = %s \r\n", or.getIndex(), ContractSerializeUtils.resolve(or.getResult())); | |||
// } | |||
// | |||
// // 验证结果 | |||
// assertNotNull(contractReturn); | |||
@@ -6,7 +6,6 @@ import java.util.concurrent.ConcurrentHashMap; | |||
import com.jd.blockchain.contract.ContractEventContext; | |||
import com.jd.blockchain.contract.ContractException; | |||
import com.jd.blockchain.contract.ContractSerializeUtils; | |||
import com.jd.blockchain.contract.EventProcessingAware; | |||
import com.jd.blockchain.contract.LedgerContext; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
@@ -75,7 +74,7 @@ public class MockerContractExeHandle implements OperationHandle { | |||
} | |||
// No return value; | |||
return ContractSerializeUtils.serialize(result); | |||
return null; | |||
} | |||
@Override | |||
@@ -1,88 +1,88 @@ | |||
package com.jd.blockchain.mocker.proxy; | |||
import java.lang.annotation.Annotation; | |||
import java.lang.reflect.InvocationHandler; | |||
import java.lang.reflect.Method; | |||
import com.jd.blockchain.contract.Contract; | |||
import com.jd.blockchain.contract.ContractEvent; | |||
import com.jd.blockchain.contract.ContractSerializeUtils; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.BytesValueEncoding; | |||
import com.jd.blockchain.ledger.OperationResult; | |||
import com.jd.blockchain.ledger.OperationResultData; | |||
import com.jd.blockchain.ledger.TransactionRequest; | |||
import com.jd.blockchain.mocker.MockerNodeContext; | |||
import com.jd.blockchain.mocker.handler.MockerContractExeHandle; | |||
import com.jd.blockchain.transaction.TxBuilder; | |||
import java.lang.annotation.Annotation; | |||
import java.lang.reflect.InvocationHandler; | |||
import java.lang.reflect.Method; | |||
public class ContractProxy<T> implements InvocationHandler { | |||
private BlockchainIdentity identity; | |||
private BlockchainIdentity identity; | |||
private MockerNodeContext mockerNodeContext; | |||
private MockerNodeContext mockerNodeContext; | |||
private T instance; | |||
private T instance; | |||
private MockerContractExeHandle operationHandle; | |||
private MockerContractExeHandle operationHandle; | |||
public ContractProxy(BlockchainIdentity identity, MockerNodeContext mockerNodeContext, | |||
T instance, MockerContractExeHandle operationHandle) { | |||
this.identity = identity; | |||
this.mockerNodeContext = mockerNodeContext; | |||
this.instance = instance; | |||
this.operationHandle = operationHandle; | |||
} | |||
public ContractProxy(BlockchainIdentity identity, MockerNodeContext mockerNodeContext, T instance, | |||
MockerContractExeHandle operationHandle) { | |||
this.identity = identity; | |||
this.mockerNodeContext = mockerNodeContext; | |||
this.instance = instance; | |||
this.operationHandle = operationHandle; | |||
} | |||
@Override | |||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { | |||
// 实际执行时,首先判断执行的是否是添加注解的方法 | |||
if (!isExecuteContractMethod(method)) { | |||
return method.invoke(instance, args); | |||
} | |||
@Override | |||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { | |||
// 实际执行时,首先判断执行的是否是添加注解的方法 | |||
if (!isExecuteContractMethod(method)) { | |||
return method.invoke(instance, args); | |||
} | |||
// 首先发送一次执行的请求 | |||
TxBuilder txBuilder = mockerNodeContext.txBuilder(); | |||
// 首先发送一次执行的请求 | |||
TxBuilder txBuilder = mockerNodeContext.txBuilder(); | |||
Class<?> contractInft = null; | |||
Class<?> contractInft = null; | |||
Class<?>[] instanceInfts = instance.getClass().getInterfaces(); | |||
Class<?>[] instanceInfts = instance.getClass().getInterfaces(); | |||
for (Class<?> instanceInft : instanceInfts) { | |||
if (instanceInft.isAnnotationPresent(Contract.class)) { | |||
contractInft = instanceInft; | |||
break; | |||
} | |||
} | |||
for (Class<?> instanceInft : instanceInfts) { | |||
if (instanceInft.isAnnotationPresent(Contract.class)) { | |||
contractInft = instanceInft; | |||
break; | |||
} | |||
} | |||
if (contractInft == null) { | |||
throw new IllegalStateException("This object does not implement the interface for the @Contract annotation !!!"); | |||
} | |||
if (contractInft == null) { | |||
throw new IllegalStateException( | |||
"This object does not implement the interface for the @Contract annotation !!!"); | |||
} | |||
// 生成代理类 | |||
Object proxyInstance = txBuilder.contract(identity.getAddress().toBase58(), contractInft); | |||
// 代理方式执行一次 | |||
method.invoke(proxyInstance, args); | |||
// 生成代理类 | |||
Object proxyInstance = txBuilder.contract(identity.getAddress().toBase58(), contractInft); | |||
// 代理方式执行一次 | |||
method.invoke(proxyInstance, args); | |||
TransactionRequest txRequest = mockerNodeContext.txRequest(txBuilder); | |||
TransactionRequest txRequest = mockerNodeContext.txRequest(txBuilder); | |||
// 放入到Map中 | |||
HashDigest txHash = txRequest.getTransactionContent().getHash(); | |||
operationHandle.registerExecutorProxy(txHash, new ExecutorProxy(instance, method, args)); | |||
// 放入到Map中 | |||
HashDigest txHash = txRequest.getTransactionContent().getHash(); | |||
operationHandle.registerExecutorProxy(txHash, new ExecutorProxy(instance, method, args)); | |||
// 提交该请求至整个区块链系统 | |||
OperationResult[] operationResults = mockerNodeContext.txProcess(txRequest); | |||
if (operationResults == null || operationResults.length == 0) { | |||
return null; | |||
} | |||
OperationResult opResult = operationResults[0]; | |||
// 提交该请求至整个区块链系统 | |||
OperationResult[] operationResults = mockerNodeContext.txProcess(txRequest); | |||
if (operationResults == null || operationResults.length == 0) { | |||
return null; | |||
} | |||
OperationResult opResult = operationResults[0]; | |||
// 处理返回值 | |||
return ContractSerializeUtils.resolve(opResult.getResult()); | |||
} | |||
// 处理返回值 | |||
return BytesValueEncoding.encode(opResult.getResult(), method.getReturnType()); | |||
} | |||
private boolean isExecuteContractMethod(Method method) { | |||
Annotation annotation = method.getAnnotation(ContractEvent.class); | |||
return annotation != null; | |||
} | |||
private boolean isExecuteContractMethod(Method method) { | |||
Annotation annotation = method.getAnnotation(ContractEvent.class); | |||
return annotation != null; | |||
} | |||
} |
@@ -5,8 +5,6 @@ import java.lang.reflect.Method; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import com.jd.blockchain.utils.console.CommandConsole; | |||
public class DefaultExceptionHandle<TListener> implements ExceptionHandle<TListener> { | |||
@Override | |||
@@ -21,9 +19,8 @@ public class DefaultExceptionHandle<TListener> implements ExceptionHandle<TListe | |||
} | |||
argsValue = String.format(argsFormat.toString(), args); | |||
} | |||
String message = String.format("Error occurred on firing event!--[listener.class=%s][method=%s][args=%s]--[%s]%s", | |||
String message = String.format("Error occurred while firing event!--[listener.class=%s][method=%s][args=%s]--[%s]%s", | |||
listener.getClass().getName(), method.getName(), argsValue, ex.getClass().getName(), ex.getMessage()); | |||
// System.err.println(message); | |||
logger.error(message, ex); | |||
} | |||
private Logger logger = LoggerFactory.getLogger(DefaultExceptionHandle.class); | |||
@@ -3,11 +3,12 @@ package com.jd.blockchain.utils.event; | |||
import java.lang.reflect.InvocationHandler; | |||
import java.lang.reflect.Method; | |||
import java.lang.reflect.Proxy; | |||
import java.util.LinkedList; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import java.util.concurrent.CopyOnWriteArrayList; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import org.springframework.util.ReflectionUtils; | |||
import com.jd.blockchain.utils.Disposable; | |||
@@ -36,17 +37,22 @@ public class EventMulticaster<TListener> implements Disposable { | |||
} | |||
public EventMulticaster(Class<TListener> listenerClass, Logger errorLogger) { | |||
this(listenerClass, new ExceptionLoggingHandle<TListener>(errorLogger)); | |||
this(listenerClass, new RethrowExceptionHandler<TListener>(errorLogger)); | |||
} | |||
@SuppressWarnings("unchecked") | |||
public EventMulticaster(Class<TListener> listenerClass, ExceptionHandle<TListener> exHandle) { | |||
if (!listenerClass.isInterface()) { | |||
throw new IllegalArgumentException("The specified class of listener does not represent an interface!"); | |||
} | |||
// 初始化错误处理器; | |||
this.exHandle = exHandle == null ? new DefaultExceptionHandle<TListener>() : exHandle; | |||
this.exHandle = exHandle == null | |||
? new RethrowExceptionHandler<TListener>(LoggerFactory.getLogger(EventMulticaster.class)) | |||
: exHandle; | |||
// 解析出不支持的方法; | |||
Method[] methods = ReflectionUtils.getAllDeclaredMethods(listenerClass); | |||
List<Method> supMths = new LinkedList<Method>(); | |||
List<Method> supMths = new ArrayList<Method>(); | |||
for (Method method : methods) { | |||
if (method.getDeclaringClass() == Object.class) { | |||
// 不支持 Object 方法; | |||
@@ -86,14 +92,14 @@ public class EventMulticaster<TListener> implements Disposable { | |||
throw new UnsupportedOperationException("Unsupported method for event multicasting!"); | |||
} | |||
} | |||
protected void doNotify(List<TListener> listeners, Method method, Object[] args){ | |||
protected void doNotify(List<TListener> listeners, Method method, Object[] args) { | |||
for (TListener listener : listeners) { | |||
doNotifySingle(listener, method, args); | |||
} | |||
} | |||
protected void doNotifySingle(TListener listener, Method method, Object[] args){ | |||
protected void doNotifySingle(TListener listener, Method method, Object[] args) { | |||
try { | |||
ReflectionUtils.invokeMethod(method, listener, args); | |||
} catch (Exception e) { | |||
@@ -104,12 +110,12 @@ public class EventMulticaster<TListener> implements Disposable { | |||
public void addListener(TListener listener) { | |||
listeners.add(listener); | |||
} | |||
public void removeListener(TListener listener) { | |||
listeners.remove(listener); | |||
} | |||
public TListener broadcast() { | |||
public TListener getBroadcaster() { | |||
return listenerProxy; | |||
} | |||