use of io.nuls.contract.dto.ContractResult in project nuls by nuls-io.
the class ConsensusProcess method doPacking.
private Block doPacking(MeetingMember self, MeetingRound round) throws NulsException, IOException {
Block bestBlock = chainManager.getBestBlock();
/**
********************************************************************************************************
*/
// pierre test comment out
// try {
// Log.info("");
// Log.info("****************************************************");
// Log.info("开始打包,获取当前bestblock, height:{},- {}", bestBlock.getHeader().getHeight(), bestBlock.getHeader().getHash());
// Log.info("开始打包,获取当前EndBlockHeader, height:{},- {}", chainManager.getMasterChain().getChain().getEndBlockHeader().getHeight(),
// chainManager.getMasterChain().getChain().getEndBlockHeader().getHash());
// Log.info("****************************************************");
// Log.info("");
//
// } catch (Exception e) {
// e.printStackTrace();
// }
/**
********************************************************************************************************
*/
BlockData bd = new BlockData();
bd.setHeight(bestBlock.getHeader().getHeight() + 1);
bd.setPreHash(bestBlock.getHeader().getHash());
bd.setTime(self.getPackEndTime());
BlockExtendsData extendsData = new BlockExtendsData();
extendsData.setRoundIndex(round.getIndex());
extendsData.setConsensusMemberCount(round.getMemberCount());
extendsData.setPackingIndexOfRound(self.getPackingIndexOfRound());
extendsData.setRoundStartTime(round.getStartTime());
// 添加版本升级相应协议数据
if (NulsVersionManager.getCurrentVersion() > 1) {
extendsData.setMainVersion(NulsVersionManager.getMainVersion());
extendsData.setCurrentVersion(NulsVersionManager.getCurrentVersion());
extendsData.setPercent(NulsVersionManager.getCurrentProtocolContainer().getPercent());
extendsData.setDelay(NulsVersionManager.getCurrentProtocolContainer().getDelay());
}
if (NulsVersionManager.getMainVersion() >= 3) {
RandomSeedStatusPo status = randomSeedsStorageService.getAddressStatus(self.getPackingAddress());
byte[] seed = ConsensusStorageConstant.EMPTY_SEED;
if (null != status && status.getNextSeed() != null) {
seed = status.getNextSeed();
}
extendsData.setSeed(seed);
byte[] nextSeed = RandomSeedUtils.createRandomSeed();
byte[] nextSeedHash = RandomSeedUtils.getLastDigestEightBytes(nextSeed);
extendsData.setNextSeedHash(nextSeedHash);
RandomSeedStatusPo po = new RandomSeedStatusPo();
po.setAddress(self.getPackingAddress());
// Log.info("{}====={}====={}", bd.getHeight(), Hex.encode(nextSeed), Hex.encode(nextSeedHash));
po.setSeedHash(nextSeedHash);
po.setNextSeed(nextSeed);
po.setHeight(bd.getHeight());
RandomSeedUtils.CACHE_SEED = po;
}
StringBuilder str = new StringBuilder();
str.append(AddressTool.getStringAddressByBytes(self.getPackingAddress()));
str.append(" ,order:" + self.getPackingIndexOfRound());
str.append(",packTime:" + new Date(self.getPackEndTime()));
str.append("\n");
Log.debug("pack round:" + str);
bd.setExtendsData(extendsData);
List<Transaction> packingTxList = new ArrayList<>();
Set<NulsDigestData> outHashSet = new HashSet<>();
long totalSize = 0L;
Map<String, Coin> toMaps = new HashMap<>();
Set<String> fromSet = new HashSet<>();
/**
* pierre add 智能合约相关
*/
byte[] stateRoot = ConsensusTool.getStateRoot(bestBlock.getHeader());
// 更新世界状态根
bd.setStateRoot(stateRoot);
long height = bestBlock.getHeader().getHeight();
ContractResult contractResult;
Map<String, Coin> contractUsedCoinMap = new HashMap<>();
int totalGasUsed = 0;
int count = 0;
long start = 0;
long ledgerUse = 0;
long verifyUse = 0;
long outHashSetUse = 0;
long getTxUse = 0;
long sleepTIme = 0;
long whileTime = 0;
long startWhile = System.currentTimeMillis();
long sizeTime = 0;
long failed1Use = 0;
long addTime = 0;
Block tempBlock = new Block();
BlockHeader tempHeader = new BlockHeader();
tempHeader.setTime(bd.getTime());
tempHeader.setHeight(bd.getHeight());
tempHeader.setPackingAddress(round.getLocalPacker().getAddress().getAddressBytes());
tempBlock.setHeader(tempHeader);
// 为本次打包区块增加一个合约的临时余额区,用于记录本次合约地址余额的变化
contractService.createContractTempBalance();
// 为本次打包区块创建一个批量执行合约的执行器
contractService.createBatchExecute(stateRoot);
// 为本地打包区块存储当前块的部分区块头信息(高度、时间、打包者地址)
contractService.createCurrentBlockHeader(tempHeader);
List<ContractResult> contractResultList = new ArrayList<>();
Set<String> redPunishAddress = new HashSet<>();
while (true) {
if ((self.getPackEndTime() - TimeService.currentTimeMillis()) <= 500L) {
break;
}
start = System.nanoTime();
Transaction tx = txMemoryPool.get();
getTxUse += (System.nanoTime() - start);
if (tx == null) {
try {
sleepTIme += 100;
Thread.sleep(100L);
} catch (InterruptedException e) {
Log.error("packaging error ", e);
}
continue;
}
start = System.nanoTime();
long txSize = tx.size();
sizeTime += (System.nanoTime() - start);
if ((totalSize + txSize) > ProtocolConstant.MAX_BLOCK_SIZE) {
txMemoryPool.addInFirst(tx, false);
break;
}
// 区块中可以消耗的最大Gas总量,超过这个值,则本区块中不再继续组装消耗GAS智能合约交易
if (totalGasUsed > ContractConstant.MAX_PACKAGE_GAS && ContractUtil.isGasCostContractTransaction(tx)) {
txMemoryPool.addInFirst(tx, false);
continue;
}
count++;
start = System.nanoTime();
Transaction repeatTx = ledgerService.getTx(tx.getHash());
ledgerUse += (System.nanoTime() - start);
if (repeatTx != null) {
continue;
}
ValidateResult result = ValidateResult.getSuccessResult();
if (tx.isSystemTx() && tx.getType() == ConsensusConstant.TX_TYPE_RED_PUNISH) {
RedPunishTransaction rpTx = (RedPunishTransaction) tx;
boolean con = redPunishAddress.add(AddressTool.getStringAddressByBytes(rpTx.getTxData().getAddress())) && PocConsensusContext.getChainManager().getMasterChain().getChain().getAgentByAddress(rpTx.getTxData().getAddress()) != null;
result.setSuccess(con);
} else if (tx.isSystemTx()) {
result = ValidateResult.getFailedResult(this.getClass().getSimpleName(), TransactionErrorCode.TX_NOT_EFFECTIVE);
} else {
start = System.nanoTime();
result = ledgerService.verifyCoinData(tx, toMaps, fromSet);
verifyUse += (System.nanoTime() - start);
}
start = System.nanoTime();
if (result.isFailed()) {
if (tx == null) {
continue;
}
if (result.getErrorCode().equals(TransactionErrorCode.ORPHAN_TX)) {
txMemoryPool.add(tx, true);
}
failed1Use += (System.nanoTime() - start);
continue;
}
start = System.nanoTime();
if (!outHashSet.add(tx.getHash())) {
outHashSetUse += (System.nanoTime() - start);
Log.warn("重复的交易");
continue;
}
outHashSetUse += (System.nanoTime() - start);
// 打包时发现智能合约交易就调用智能合约
if (ContractUtil.isContractTransaction(tx)) {
contractResult = contractService.batchPackageTx(tx, height, tempBlock, stateRoot, toMaps, contractUsedCoinMap).getData();
if (contractResult != null) {
totalGasUsed += contractResult.getGasUsed();
contractResultList.add(contractResult);
}
}
tx.setBlockHeight(bd.getHeight());
start = System.nanoTime();
packingTxList.add(tx);
addTime += (System.nanoTime() - start);
totalSize += txSize;
}
// 打包结束后移除临时余额区
contractService.removeContractTempBalance();
stateRoot = contractService.commitBatchExecute().getData();
// 打包结束后移除批量执行合约的执行器
contractService.removeBatchExecute();
// 打包结束后移除当前区块头信息
contractService.removeCurrentBlockHeader();
tempBlock.getHeader().setStateRoot(stateRoot);
for (ContractResult result : contractResultList) {
result.setStateRoot(stateRoot);
}
// 更新世界状态
bd.setStateRoot(stateRoot);
whileTime = System.currentTimeMillis() - startWhile;
ValidateResult validateResult = null;
int failedCount = 0;
long failedUse = 0;
start = System.nanoTime();
while (null == validateResult || validateResult.isFailed()) {
failedCount++;
validateResult = transactionService.conflictDetect(packingTxList);
if (validateResult.isFailed()) {
if (validateResult.getData() instanceof Transaction) {
packingTxList.remove(validateResult.getData());
} else if (validateResult.getData() instanceof List) {
List<Transaction> list = (List<Transaction>) validateResult.getData();
if (list.size() == 2) {
packingTxList.remove(list.get(1));
} else {
packingTxList.removeAll(list);
}
} else if (validateResult.getData() == null) {
Log.error("Cann't find the wrong transaction!");
}
}
}
// 组装CoinBase交易,另外合约调用退还剩余的Gas
failedUse = System.nanoTime() - start;
start = System.nanoTime();
addConsensusTx(bestBlock, packingTxList, self, round);
long consensusTxUse = System.nanoTime() - start;
bd.setTxList(packingTxList);
start = System.nanoTime();
// 更新本地打包最终世界状态根
bd.getExtendsData().setStateRoot(bd.getStateRoot());
Block newBlock = ConsensusTool.createBlock(bd, round.getLocalPacker());
long createBlockUser = System.nanoTime() - start;
Log.info("make block height:" + newBlock.getHeader().getHeight() + ",txCount: " + newBlock.getTxs().size() + " , block size: " + newBlock.size() + " , time:" + DateUtil.convertDate(new Date(newBlock.getHeader().getTime())) + ",packEndTime:" + DateUtil.convertDate(new Date(self.getPackEndTime())));
// pierre test comment out
Log.debug("\ncheck count:" + count + "\ngetTxUse:" + getTxUse / 1000000 + " ,\nledgerExistUse:" + ledgerUse / 1000000 + ", \nverifyUse:" + verifyUse / 1000000 + " ,\noutHashSetUse:" + outHashSetUse / 1000000 + " ,\nfailedTimes:" + failedCount + ", \nfailedUse:" + failedUse / 1000000 + " ,\nconsensusTx:" + consensusTxUse / 1000000 + ", \nblockUse:" + createBlockUser / 1000000 + ", \nsleepTIme:" + sleepTIme + ",\nwhileTime:" + whileTime + ", \naddTime:" + addTime / 1000000 + " ,\nsizeTime:" + sizeTime / 1000000 + " ,\nfailed1Use:" + failed1Use / 1000000);
return newBlock;
}
use of io.nuls.contract.dto.ContractResult in project nuls by nuls-io.
the class ConsensusTool method returnContractSenderNa.
private static List<Coin> returnContractSenderNa(List<Transaction> txList, long unlockHeight) {
// 去重, 可能存在同一个sender发出的几笔合约交易,需要把退还的GasNa累加到一起
Map<ByteArrayWrapper, Na> returnMap = new HashMap<>();
List<Coin> returnList = new ArrayList<>();
if (txList != null && txList.size() > 0) {
int txType;
for (Transaction tx : txList) {
txType = tx.getType();
if (txType == ContractConstant.TX_TYPE_CREATE_CONTRACT || txType == ContractConstant.TX_TYPE_CALL_CONTRACT || txType == ContractConstant.TX_TYPE_DELETE_CONTRACT) {
ContractTransaction contractTx = (ContractTransaction) tx;
ContractResult contractResult = contractTx.getContractResult();
if (contractResult == null) {
contractResult = contractService.getContractExecuteResult(tx.getHash());
if (contractResult == null) {
Log.error("get contract tx contractResult error: " + tx.getHash().getDigestHex());
continue;
}
}
contractTx.setContractResult(contractResult);
// 终止合约不消耗Gas,跳过
if (txType == ContractConstant.TX_TYPE_DELETE_CONTRACT) {
continue;
}
// 减差额作为退还Gas
ContractData contractData = (ContractData) tx.getTxData();
long realGasUsed = contractResult.getGasUsed();
long txGasUsed = contractData.getGasLimit();
long returnGas = 0;
Na returnNa = Na.ZERO;
if (txGasUsed > realGasUsed) {
returnGas = txGasUsed - realGasUsed;
returnNa = Na.valueOf(LongUtils.mul(returnGas, contractData.getPrice()));
// 用于计算本次矿工共识奖励 -> 需扣除退还给sender的Gas部分, Call,Create,DeleteContractTransaction 覆写getFee方法来处理
contractTx.setReturnNa(returnNa);
ByteArrayWrapper sender = new ByteArrayWrapper(contractData.getSender());
Na senderNa = returnMap.get(sender);
if (senderNa == null) {
senderNa = Na.ZERO.add(returnNa);
} else {
senderNa = senderNa.add(returnNa);
}
returnMap.put(sender, senderNa);
}
}
}
Set<Map.Entry<ByteArrayWrapper, Na>> entries = returnMap.entrySet();
Coin returnCoin;
for (Map.Entry<ByteArrayWrapper, Na> entry : entries) {
returnCoin = new Coin(entry.getKey().getBytes(), entry.getValue(), unlockHeight);
returnList.add(returnCoin);
}
}
return returnList;
}
use of io.nuls.contract.dto.ContractResult in project nuls by nuls-io.
the class ContractServiceImpl method createContract.
/**
* @param executor
* @param number 当前块编号
* @param prevStateRoot 上一区块状态根
* @param create 创建智能合约的参数
* @return
*/
private Result<ContractResult> createContract(ProgramExecutor executor, long number, byte[] prevStateRoot, CreateContractData create) {
if (number < 0) {
return Result.getFailed(ContractErrorCode.PARAMETER_ERROR);
}
// 不能同时为空,批量提交方式stateRoot为空
if (executor == null && prevStateRoot == null) {
return Result.getFailed(ContractErrorCode.NULL_PARAMETER);
}
try {
byte[] contractAddress = create.getContractAddress();
byte[] sender = create.getSender();
long price = create.getPrice();
ProgramCreate programCreate = new ProgramCreate();
programCreate.setContractAddress(contractAddress);
programCreate.setSender(sender);
programCreate.setValue(BigInteger.ZERO);
programCreate.setPrice(price);
programCreate.setGasLimit(create.getGasLimit());
programCreate.setNumber(number);
programCreate.setContractCode(create.getCode());
programCreate.setArgs(create.getArgs());
ProgramExecutor track;
if (executor == null) {
track = programExecutor.begin(prevStateRoot);
} else {
track = executor.startTracking();
}
ProgramResult programResult = track.create(programCreate);
// 批量提交方式,交易track放置到外部处理合约执行结果的方法里去提交
if (executor == null) {
track.commit();
}
// current state root
byte[] stateRoot = executor == null ? track.getRoot() : null;
ContractResult contractResult = new ContractResult();
contractResult.setNonce(programResult.getNonce());
contractResult.setGasUsed(programResult.getGasUsed());
contractResult.setPrice(price);
contractResult.setStateRoot(stateRoot);
contractResult.setBalance(programResult.getBalance());
contractResult.setContractAddress(contractAddress);
contractResult.setSender(sender);
contractResult.setRemark(ContractConstant.CREATE);
// 批量提交方式,交易track放置到外部处理合约执行结果的方法里去提交
contractResult.setTxTrack(track);
if (!programResult.isSuccess()) {
Result<ContractResult> result = Result.getFailed(ContractErrorCode.CONTRACT_EXECUTE_ERROR);
contractResult.setError(programResult.isError());
contractResult.setRevert(programResult.isRevert());
contractResult.setErrorMessage(programResult.getErrorMessage());
contractResult.setStackTrace(programResult.getStackTrace());
result.setMsg(programResult.getErrorMessage());
result.setData(contractResult);
return result;
}
// 返回已使用gas、状态根、消息事件、合约转账(从合约转出)
contractResult.setError(false);
contractResult.setRevert(false);
contractResult.setEvents(programResult.getEvents());
contractResult.setTransfers(generateContractTransfer(programResult.getTransfers()));
Result<ContractResult> result = Result.getSuccess();
result.setData(contractResult);
return result;
} catch (Exception e) {
Log.error(e);
Result result = Result.getFailed(ContractErrorCode.CONTRACT_EXECUTE_ERROR);
result.setMsg(e.getMessage());
return result;
}
}
use of io.nuls.contract.dto.ContractResult in project nuls by nuls-io.
the class ContractServiceImpl method callContract.
/**
* @param executor
* @param number 当前块编号
* @param prevStateRoot 上一区块状态根
* @param call 调用智能合约的参数
* @return
*/
private Result<ContractResult> callContract(ProgramExecutor executor, long number, byte[] prevStateRoot, CallContractData call) {
if (number < 0) {
return Result.getFailed(ContractErrorCode.PARAMETER_ERROR);
}
if (executor == null && prevStateRoot == null) {
return Result.getFailed(ContractErrorCode.NULL_PARAMETER);
}
try {
byte[] contractAddress = call.getContractAddress();
byte[] sender = call.getSender();
long price = call.getPrice();
ProgramCall programCall = new ProgramCall();
programCall.setContractAddress(contractAddress);
programCall.setSender(sender);
programCall.setValue(BigInteger.valueOf(call.getValue()));
programCall.setPrice(price);
programCall.setGasLimit(call.getGasLimit());
programCall.setNumber(number);
programCall.setMethodName(call.getMethodName());
programCall.setMethodDesc(call.getMethodDesc());
programCall.setArgs(call.getArgs());
ProgramExecutor track;
if (executor == null) {
track = programExecutor.begin(prevStateRoot);
} else {
track = executor.startTracking();
}
ProgramResult programResult = track.call(programCall);
// 批量提交方式,交易track放置到外部处理合约执行结果的方法里去提交
if (executor == null) {
track.commit();
}
// current state root
byte[] stateRoot = executor == null ? track.getRoot() : null;
ContractResult contractResult = new ContractResult();
contractResult.setNonce(programResult.getNonce());
contractResult.setGasUsed(programResult.getGasUsed());
contractResult.setPrice(price);
contractResult.setStateRoot(stateRoot);
contractResult.setBalance(programResult.getBalance());
contractResult.setContractAddress(contractAddress);
contractResult.setSender(sender);
contractResult.setValue(programCall.getValue().longValue());
contractResult.setRemark(ContractConstant.CALL);
// 批量提交方式,交易track放置到外部处理合约执行结果的方法里去提交
contractResult.setTxTrack(track);
if (!programResult.isSuccess()) {
Result<ContractResult> result = Result.getFailed(ContractErrorCode.CONTRACT_EXECUTE_ERROR);
contractResult.setError(programResult.isError());
contractResult.setRevert(programResult.isRevert());
contractResult.setErrorMessage(programResult.getErrorMessage());
contractResult.setStackTrace(programResult.getStackTrace());
result.setMsg(programResult.getErrorMessage());
result.setData(contractResult);
return result;
}
// 返回调用结果、已使用Gas、状态根、消息事件、合约转账(从合约转出)等
contractResult.setError(false);
contractResult.setRevert(false);
contractResult.setResult(programResult.getResult());
contractResult.setEvents(programResult.getEvents());
contractResult.setTransfers(generateContractTransfer(programResult.getTransfers()));
Result<ContractResult> result = Result.getSuccess();
result.setData(contractResult);
return result;
} catch (Exception e) {
Log.error(e);
Result result = Result.getFailed(ContractErrorCode.CONTRACT_EXECUTE_ERROR);
result.setMsg(e.getMessage());
return result;
}
}
use of io.nuls.contract.dto.ContractResult in project nuls by nuls-io.
the class ContractServiceImpl method batchProcessTx.
@Override
public Result<ContractResult> batchProcessTx(Transaction tx, long bestHeight, Block block, byte[] stateRoot, Map<String, Coin> toMaps, Map<String, Coin> contractUsedCoinMap, boolean isForkChain) {
if (stateRoot == null) {
return Result.getFailed();
}
BlockHeader blockHeader = block.getHeader();
long blockTime = blockHeader.getTime();
ProgramExecutor executor = localProgramExecutor.get();
if (executor == null) {
return Result.getFailed();
}
ContractTransaction contractTx = (ContractTransaction) tx;
contractTx.setBlockHeader(blockHeader);
// 验证区块时发现智能合约交易就调用智能合约
Result<ContractResult> invokeContractResult = this.invokeContract(executor, tx, bestHeight, null, isForkChain);
ContractResult contractResult = invokeContractResult.getData();
if (contractResult != null) {
Result<byte[]> handleContractResult;
if (isForkChain) {
handleContractResult = this.verifyContractResult(tx, contractResult, stateRoot, blockTime, toMaps, contractUsedCoinMap, bestHeight);
} else {
handleContractResult = this.verifyContractResult(tx, contractResult, stateRoot, blockTime, toMaps, contractUsedCoinMap);
}
}
return Result.getSuccess().setData(contractResult);
}
Aggregations