@@ -29,6 +29,11 @@ public enum TransactionState { | |||||
*/ | */ | ||||
LEDGER_ERROR((byte) 2), | LEDGER_ERROR((byte) 2), | ||||
/** | |||||
* 数据序列更新错误; | |||||
*/ | |||||
DATA_SEQUENCE_UPDATE_ERROR((byte) 3), | |||||
/** | /** | ||||
* 系统错误; | * 系统错误; | ||||
*/ | */ | ||||
@@ -1,8 +1,19 @@ | |||||
package com.jd.blockchain.peer.statetransfer; | package com.jd.blockchain.peer.statetransfer; | ||||
import com.jd.blockchain.crypto.hash.HashDigest; | |||||
import com.jd.blockchain.ledger.LedgerBlock; | |||||
import com.jd.blockchain.ledger.core.LedgerManage; | |||||
import com.jd.blockchain.ledger.core.LedgerRepository; | |||||
import com.jd.blockchain.ledger.core.TransactionSet; | |||||
import com.jd.blockchain.statetransfer.DataSequenceElement; | import com.jd.blockchain.statetransfer.DataSequenceElement; | ||||
import com.jd.blockchain.statetransfer.DataSequenceInfo; | import com.jd.blockchain.statetransfer.DataSequenceInfo; | ||||
import com.jd.blockchain.statetransfer.DataSequenceReader; | |||||
import com.jd.blockchain.statetransfer.callback.DataSequenceReader; | |||||
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.utils.codec.Base58Utils; | |||||
import com.jd.blockchain.utils.codec.HexUtils; | |||||
import org.springframework.beans.factory.annotation.Autowired; | |||||
/** | /** | ||||
*数据序列差异的提供者需要使用的回调接口实现类 | *数据序列差异的提供者需要使用的回调接口实现类 | ||||
@@ -13,13 +24,74 @@ import com.jd.blockchain.statetransfer.DataSequenceReader; | |||||
*/ | */ | ||||
public class DataSequenceReaderImpl implements DataSequenceReader { | public class DataSequenceReaderImpl implements DataSequenceReader { | ||||
private LedgerManage ledgerManager; | |||||
private DbConnectionFactory connFactory; | |||||
private LedgerBindingConfig config; | |||||
public DataSequenceReaderImpl(LedgerBindingConfig config, LedgerManage ledgerManager, DbConnectionFactory connFactory) { | |||||
this.config = config; | |||||
this.ledgerManager = ledgerManager; | |||||
this.connFactory = connFactory; | |||||
} | |||||
/** | |||||
* | |||||
* | |||||
*/ | |||||
@Override | @Override | ||||
public DataSequenceInfo getDSInfo(String id) { | public DataSequenceInfo getDSInfo(String id) { | ||||
return null; | |||||
byte[] hashBytes = Base58Utils.decode(id); | |||||
HashDigest ledgerHash = new HashDigest(hashBytes); | |||||
LedgerBindingConfig.BindingConfig bindingConfig = config.getLedger(ledgerHash); | |||||
DbConnection dbConnNew = connFactory.connect(bindingConfig.getDbConnection().getUri(), | |||||
bindingConfig.getDbConnection().getPassword()); | |||||
LedgerRepository ledgerRepository = ledgerManager.register(ledgerHash, dbConnNew.getStorageService()); | |||||
return new DataSequenceInfo(id, ledgerRepository.getLatestBlockHeight()); | |||||
} | } | ||||
/** | |||||
* | |||||
* | |||||
*/ | |||||
@Override | @Override | ||||
public DataSequenceElement[] getDSContent(String id, long from, long to) { | |||||
return null; | |||||
public DataSequenceElement[] getDSDiffContent(String id, long from, long to) { | |||||
DataSequenceElement[] dataSequenceElements = new DataSequenceElement[(int)(to - from + 1)]; | |||||
for (long i = from; i < to + 1; i++) { | |||||
dataSequenceElements[(int)(i - from)] = getDSDiffContent(id, i); | |||||
} | |||||
return dataSequenceElements; | |||||
} | |||||
/** | |||||
* | |||||
* | |||||
*/ | |||||
@Override | |||||
public DataSequenceElement getDSDiffContent(String id, long height) { | |||||
byte[] hashBytes = Base58Utils.decode(id); | |||||
HashDigest ledgerHash = new HashDigest(hashBytes); | |||||
LedgerBindingConfig.BindingConfig bindingConfig = config.getLedger(ledgerHash); | |||||
DbConnection dbConnNew = connFactory.connect(bindingConfig.getDbConnection().getUri(), | |||||
bindingConfig.getDbConnection().getPassword()); | |||||
LedgerRepository ledgerRepository = ledgerManager.register(ledgerHash, dbConnNew.getStorageService()); | |||||
LedgerBlock ledgerBlock = ledgerRepository.getBlock(height); | |||||
TransactionSet transactionSet = ledgerRepository.getTransactionSet(ledgerBlock); | |||||
//todo | |||||
return null; | |||||
} | } | ||||
} | } |
@@ -1,9 +1,14 @@ | |||||
package com.jd.blockchain.peer.statetransfer; | package com.jd.blockchain.peer.statetransfer; | ||||
import com.jd.blockchain.consensus.service.MessageHandle; | |||||
import com.jd.blockchain.ledger.TransactionState; | |||||
import com.jd.blockchain.statetransfer.DataSequenceElement; | import com.jd.blockchain.statetransfer.DataSequenceElement; | ||||
import com.jd.blockchain.statetransfer.DataSequenceInfo; | import com.jd.blockchain.statetransfer.DataSequenceInfo; | ||||
import com.jd.blockchain.statetransfer.DataSequenceReader; | |||||
import com.jd.blockchain.statetransfer.DataSequenceWriter; | |||||
import com.jd.blockchain.statetransfer.callback.DataSequenceWriter; | |||||
import com.jd.blockchain.statetransfer.comparator.DataSequenceComparator; | |||||
import java.util.ArrayList; | |||||
import java.util.Collections; | |||||
/** | /** | ||||
*数据序列差异的请求者需要使用的回调接口实现类 | *数据序列差异的请求者需要使用的回调接口实现类 | ||||
@@ -14,9 +19,146 @@ import com.jd.blockchain.statetransfer.DataSequenceWriter; | |||||
*/ | */ | ||||
public class DataSequenceWriterImpl implements DataSequenceWriter { | public class DataSequenceWriterImpl implements DataSequenceWriter { | ||||
private long currHeight; | |||||
private ArrayList<DataSequenceElement> deceidedElements = new ArrayList<DataSequenceElement>(); | |||||
private MessageHandle batchMessageHandle; | |||||
public DataSequenceWriterImpl(MessageHandle batchMessageHandle) { | |||||
this.batchMessageHandle = batchMessageHandle; | |||||
} | |||||
/** | |||||
* check height to data sequence diff elements | |||||
* | |||||
*/ | |||||
private int checkElementsHeight(long currHeight, ArrayList<DataSequenceElement> dsUpdateElements) { | |||||
boolean lossMiddleElements = false; | |||||
// lose first element | |||||
if (currHeight + 1 < dsUpdateElements.get(0).getHeight()){ | |||||
System.out.println("Diff response loss first element error!"); | |||||
return DataSequenceErrorType.DATA_SEQUENCE_LOSS_FIRST_ELEMENT.CODE; | |||||
} | |||||
else { | |||||
for (int i = 0; i < dsUpdateElements.size(); i++) { | |||||
if (dsUpdateElements.get(i).getHeight() == currHeight + 1 + i) { | |||||
deceidedElements.add(dsUpdateElements.get(i)); | |||||
} | |||||
// lose middle elements | |||||
else { | |||||
lossMiddleElements = true; | |||||
break; | |||||
} | |||||
} | |||||
if (lossMiddleElements) { | |||||
System.out.println("Diff response loss middle elements error!"); | |||||
return DataSequenceErrorType.DATA_SEQUENCE_LOSS_MIDDLE_ELEMENT.CODE; | |||||
} | |||||
System.out.println("Diff response elements height normal!"); | |||||
return DataSequenceErrorType.DATA_SEQUENCE_ELEMENT_HEIGHT_NORMAL.CODE; | |||||
} | |||||
} | |||||
/** | |||||
* | |||||
* | |||||
*/ | |||||
private void exeUpdate(String realmName) { | |||||
for (int i = 0; i < deceidedElements.size(); i++) { | |||||
byte[][] element = deceidedElements.get(i).getData(); | |||||
String batchId = batchMessageHandle.beginBatch(realmName); | |||||
try { | |||||
int msgId = 0; | |||||
for (byte[] txContent : element) { | |||||
batchMessageHandle.processOrdered(msgId++, txContent, realmName, batchId); | |||||
} | |||||
batchMessageHandle.completeBatch(realmName, batchId); | |||||
batchMessageHandle.commitBatch(realmName, batchId); | |||||
} catch (Exception e) { | |||||
// todo 需要处理应答码 404 | |||||
batchMessageHandle.rollbackBatch(realmName, batchId, TransactionState.DATA_SEQUENCE_UPDATE_ERROR.CODE); | |||||
} | |||||
} | |||||
} | |||||
/** | |||||
* | |||||
* | |||||
*/ | |||||
@Override | @Override | ||||
public void updateDSInfo(String id, DataSequenceElement[] diffContents) { | |||||
public int updateDSInfo(DataSequenceInfo id, DataSequenceElement[] diffContents) { | |||||
int result = 0; | |||||
try { | |||||
ArrayList<DataSequenceElement> dsUpdateElements = new ArrayList<DataSequenceElement>(); | |||||
//remove unexpected elements | |||||
for (int i = 0 ; i < diffContents.length; i++) { | |||||
if (diffContents[i].getId().equals(id.getId())) { | |||||
dsUpdateElements.add(diffContents[i]); | |||||
} | |||||
} | |||||
// sort elements by height | |||||
Collections.sort(dsUpdateElements, new DataSequenceComparator()); | |||||
currHeight = id.getHeight(); | |||||
// check element's height | |||||
result = checkElementsHeight(currHeight, dsUpdateElements); | |||||
// cann't exe update | |||||
if (result == DataSequenceErrorType.DATA_SEQUENCE_LOSS_FIRST_ELEMENT.CODE) { | |||||
return result; | |||||
} | |||||
// exe elements update | |||||
else { | |||||
exeUpdate(id.getId()); | |||||
return result; | |||||
} | |||||
} catch (Exception e) { | |||||
System.out.println(e.getMessage()); | |||||
e.printStackTrace(); | |||||
} | |||||
return result; | |||||
} | |||||
@Override | |||||
public int updateDSInfo(DataSequenceInfo id, DataSequenceElement diffContents) { | |||||
return 0; | |||||
} | } | ||||
/** | |||||
* data sequence transfer error type | |||||
* | |||||
*/ | |||||
public enum DataSequenceErrorType { | |||||
DATA_SEQUENCE_LOSS_FIRST_ELEMENT((byte) 0x1), | |||||
DATA_SEQUENCE_LOSS_MIDDLE_ELEMENT((byte) 0x2), | |||||
DATA_SEQUENCE_ELEMENT_HEIGHT_NORMAL((byte) 0x3), | |||||
; | |||||
public final int CODE; | |||||
private DataSequenceErrorType(byte code) { | |||||
this.CODE = code; | |||||
} | |||||
public static DataSequenceErrorType valueOf(byte code) { | |||||
for (DataSequenceErrorType errorType : DataSequenceErrorType.values()) { | |||||
if (errorType.CODE == code) { | |||||
return errorType; | |||||
} | |||||
} | |||||
throw new IllegalArgumentException("Unsupported code[" + code + "] of errorType!"); | |||||
} | |||||
} | |||||
} | } |
@@ -1,6 +1,7 @@ | |||||
package com.jd.blockchain.statetransfer.callback; | package com.jd.blockchain.statetransfer.callback; | ||||
import com.jd.blockchain.statetransfer.DataSequenceElement; | import com.jd.blockchain.statetransfer.DataSequenceElement; | ||||
import com.jd.blockchain.statetransfer.DataSequenceInfo; | |||||
/** | /** | ||||
*数据序列差异的请求者获得差异内容后需要回调该接口,通过接口提供的方法对指定数据序列执行差异内容的重放,并更新数据序列的当前状态; | *数据序列差异的请求者获得差异内容后需要回调该接口,通过接口提供的方法对指定数据序列执行差异内容的重放,并更新数据序列的当前状态; | ||||
@@ -14,12 +15,12 @@ public interface DataSequenceWriter { | |||||
*更新数据序列的当前状态,一次更新多个高度的差异 | *更新数据序列的当前状态,一次更新多个高度的差异 | ||||
* return void | * return void | ||||
*/ | */ | ||||
int updateDSInfo(String id, DataSequenceElement[] diffContents); | |||||
int updateDSInfo(DataSequenceInfo id, DataSequenceElement[] diffContents); | |||||
/** | /** | ||||
*更新数据序列的当前状态,一次更新一个高度的差异 | *更新数据序列的当前状态,一次更新一个高度的差异 | ||||
* return void | * return void | ||||
*/ | */ | ||||
int updateDSInfo(String id, DataSequenceElement diffContents); | |||||
int updateDSInfo(DataSequenceInfo id, DataSequenceElement diffContents); | |||||
} | } |
@@ -0,0 +1,24 @@ | |||||
package com.jd.blockchain.statetransfer.comparator; | |||||
import com.jd.blockchain.statetransfer.DataSequenceElement; | |||||
import java.util.Comparator; | |||||
/** | |||||
* | |||||
* | |||||
*/ | |||||
public class DataSequenceComparator implements Comparator<DataSequenceElement> { | |||||
// sort by data sequence height | |||||
@Override | |||||
public int compare(DataSequenceElement o1, DataSequenceElement o2) { | |||||
long height1; | |||||
long height2; | |||||
height1 = o1.getHeight(); | |||||
height2 = o2.getHeight(); | |||||
return (int) (height1 - height2); | |||||
} | |||||
} |
@@ -0,0 +1,15 @@ | |||||
package com.jd.blockchain.statetransfer.exception; | |||||
public class DataSequenceException extends RuntimeException { | |||||
private static final long serialVersionUID = -4090881296855827889L; | |||||
public DataSequenceException(String message) { | |||||
super(message); | |||||
} | |||||
public DataSequenceException(String message, Throwable cause) { | |||||
super(message, cause); | |||||
} | |||||
} |
@@ -127,7 +127,7 @@ public class DSProcessManager { | |||||
} | } | ||||
// step6: process data sequence diff response, update local data sequence state | // step6: process data sequence diff response, update local data sequence state | ||||
DataSequenceElement[] dataSequenceElements = dsTransferProcess.computeDiffElement(receiveDiffResponses.toArray(new byte[receiveDiffResponses.size()][])); | DataSequenceElement[] dataSequenceElements = dsTransferProcess.computeDiffElement(receiveDiffResponses.toArray(new byte[receiveDiffResponses.size()][])); | ||||
returnCode = dsWriter.updateDSInfo(dsInfo.getId(), dataSequenceElements); | |||||
returnCode = dsWriter.updateDSInfo(dsInfo, dataSequenceElements); | |||||
// data sequence transfer complete, close all sessions, end process life cycle | // data sequence transfer complete, close all sessions, end process life cycle | ||||