use of io.nuls.contract.entity.txdata.ContractData in project nuls by nuls-io.
the class ContractResource method getContractTx.
@GET
@Path("/tx/{hash}")
@Produces(MediaType.APPLICATION_JSON)
@ApiOperation(value = "获取智能合约交易详情")
@ApiResponses(value = { @ApiResponse(code = 200, message = "success", response = ContractTransactionDto.class) })
public RpcClientResult getContractTx(@ApiParam(name = "hash", value = "交易hash", required = true) @PathParam("hash") String hash) {
if (StringUtils.isBlank(hash)) {
return Result.getFailed(LedgerErrorCode.NULL_PARAMETER).toRpcClientResult();
}
if (!NulsDigestData.validHash(hash)) {
return Result.getFailed(LedgerErrorCode.PARAMETER_ERROR).toRpcClientResult();
}
Result result;
try {
NulsDigestData txHashObj = NulsDigestData.fromDigestHex(hash);
Transaction tx = ledgerService.getTx(txHashObj);
if (tx == null) {
result = Result.getFailed(TransactionErrorCode.TX_NOT_EXIST);
} else {
if (!ContractUtil.isContractTransaction(tx) && tx.getType() != NulsConstant.TX_TYPE_COINBASE) {
return Result.getFailed(ContractErrorCode.NON_CONTRACTUAL_TRANSACTION).toRpcClientResult();
}
tx.setStatus(TxStatusEnum.CONFIRMED);
ContractTransactionDto txDto = null;
CoinData coinData = tx.getCoinData();
byte[] txHashBytes = tx.getHash().serialize();
if (coinData != null) {
// 组装from数据
List<Coin> froms = coinData.getFrom();
if (froms != null && froms.size() > 0) {
byte[] fromHash, owner;
int fromIndex;
NulsDigestData fromHashObj;
Transaction fromTx;
Coin fromUtxo;
for (Coin from : froms) {
owner = from.getOwner();
// owner拆分出txHash和index
fromHash = LedgerUtil.getTxHashBytes(owner);
fromIndex = LedgerUtil.getIndex(owner);
// 查询from UTXO
fromHashObj = new NulsDigestData();
fromHashObj.parse(fromHash, 0);
fromTx = ledgerService.getTx(fromHashObj);
fromUtxo = fromTx.getCoinData().getTo().get(fromIndex);
from.setFrom(fromUtxo);
}
}
txDto = new ContractTransactionDto(tx);
List<OutputDto> outputDtoList = new ArrayList<>();
// 组装to数据
List<Coin> tos = coinData.getTo();
if (tos != null && tos.size() > 0) {
String txHash = hash;
OutputDto outputDto;
Coin to, temp;
long bestHeight = NulsContext.getInstance().getBestHeight();
long currentTime = TimeService.currentTimeMillis();
long lockTime;
for (int i = 0, length = tos.size(); i < length; i++) {
to = tos.get(i);
outputDto = new OutputDto(to);
outputDto.setTxHash(txHash);
outputDto.setIndex(i);
temp = ledgerService.getUtxo(org.spongycastle.util.Arrays.concatenate(txHashBytes, new VarInt(i).encode()));
if (temp == null) {
// 已花费
outputDto.setStatus(3);
} else {
lockTime = temp.getLockTime();
if (lockTime < 0) {
// 共识锁定
outputDto.setStatus(2);
} else if (lockTime == 0) {
// 正常未花费
outputDto.setStatus(0);
} else if (lockTime > NulsConstant.BlOCKHEIGHT_TIME_DIVIDE) {
// 判定是否时间高度锁定
if (lockTime > currentTime) {
// 时间高度锁定
outputDto.setStatus(1);
} else {
// 正常未花费
outputDto.setStatus(0);
}
} else {
// 判定是否区块高度锁定
if (lockTime > bestHeight) {
// 区块高度锁定
outputDto.setStatus(1);
} else {
// 正常未花费
outputDto.setStatus(0);
}
}
}
outputDtoList.add(outputDto);
}
}
txDto.setOutputs(outputDtoList);
// 计算交易实际发生的金额
calTransactionValue(txDto);
}
// 获取合约执行结果
if (tx.getType() != ContractConstant.TX_TYPE_CONTRACT_TRANSFER) {
ContractResult contractExecuteResult = contractService.getContractExecuteResult(txHashObj);
if (contractExecuteResult != null) {
Result<ContractAddressInfoPo> contractAddressInfoResult = contractAddressStorageService.getContractAddressInfo(contractExecuteResult.getContractAddress());
ContractAddressInfoPo po = contractAddressInfoResult.getData();
if (po != null && po.isNrc20()) {
contractExecuteResult.setNrc20(true);
if (contractExecuteResult.isSuccess()) {
txDto.setContractResult(new ContractResultDto(contractExecuteResult, tx, po));
} else {
ContractData contractData = (ContractData) tx.getTxData();
byte[] sender = contractData.getSender();
byte[] infoKey = ArraysTool.concatenate(sender, txHashBytes, new VarInt(0).encode());
Result<ContractTokenTransferInfoPo> tokenTransferResult = contractTokenTransferStorageService.getTokenTransferInfo(infoKey);
ContractTokenTransferInfoPo transferInfoPo = tokenTransferResult.getData();
txDto.setContractResult(new ContractResultDto(contractExecuteResult, tx, po, transferInfoPo));
}
} else {
txDto.setContractResult(new ContractResultDto(contractExecuteResult, tx));
}
ContractResultDto contractResultDto = txDto.getContractResult();
List<ContractTokenTransferDto> tokenTransfers = contractResultDto.getTokenTransfers();
List<ContractTokenTransferDto> realTokenTransfers = this.filterRealTokenTransfers(tokenTransfers);
contractResultDto.setTokenTransfers(realTokenTransfers);
}
}
result = Result.getSuccess();
result.setData(txDto);
}
} catch (NulsRuntimeException e) {
Log.error(e);
result = Result.getFailed(e.getErrorCode());
} catch (Exception e) {
Log.error(e);
result = Result.getFailed(LedgerErrorCode.SYS_UNKOWN_EXCEPTION);
}
return result.toRpcClientResult();
}
use of io.nuls.contract.entity.txdata.ContractData in project nuls by nuls-io.
the class ContractResource method getContractTxResult.
@GET
@Path("/result/{hash}")
@Produces(MediaType.APPLICATION_JSON)
@ApiOperation(value = "获取智能合约执行结果")
@ApiResponses(value = { @ApiResponse(code = 200, message = "success", response = ContractResultDto.class) })
public RpcClientResult getContractTxResult(@ApiParam(name = "hash", value = "交易hash", required = true) @PathParam("hash") String hash) {
if (StringUtils.isBlank(hash)) {
return Result.getFailed(LedgerErrorCode.NULL_PARAMETER).toRpcClientResult();
}
if (!NulsDigestData.validHash(hash)) {
return Result.getFailed(LedgerErrorCode.PARAMETER_ERROR).toRpcClientResult();
}
try {
ContractResultDto contractResultDto = null;
ContractResult contractExecuteResult;
boolean flag = true;
String msg = EMPTY;
// long confirmCount = 0L;
do {
NulsDigestData txHash = NulsDigestData.fromDigestHex(hash);
Transaction tx = ledgerService.getTx(txHash);
if (tx == null) {
flag = false;
msg = TransactionErrorCode.TX_NOT_EXIST.getMsg();
break;
} else {
if (!ContractUtil.isContractTransaction(tx)) {
flag = false;
msg = ContractErrorCode.NON_CONTRACTUAL_TRANSACTION.getMsg();
break;
}
}
contractExecuteResult = contractService.getContractExecuteResult(txHash);
if (contractExecuteResult != null) {
// long bestBlockHeight = NulsContext.getInstance().getBestHeight();
// confirmCount = bestBlockHeight - tx.getBlockHeight() + 1;
Result<ContractAddressInfoPo> contractAddressInfoResult = contractAddressStorageService.getContractAddressInfo(contractExecuteResult.getContractAddress());
ContractAddressInfoPo po = contractAddressInfoResult.getData();
if (po != null && po.isNrc20()) {
contractExecuteResult.setNrc20(true);
if (contractExecuteResult.isSuccess()) {
contractResultDto = new ContractResultDto(contractExecuteResult, tx, po);
} else {
ContractData contractData = (ContractData) tx.getTxData();
byte[] sender = contractData.getSender();
byte[] infoKey = ArraysTool.concatenate(sender, tx.getHash().serialize(), new VarInt(0).encode());
Result<ContractTokenTransferInfoPo> tokenTransferResult = contractTokenTransferStorageService.getTokenTransferInfo(infoKey);
ContractTokenTransferInfoPo transferInfoPo = tokenTransferResult.getData();
contractResultDto = new ContractResultDto(contractExecuteResult, tx, po, transferInfoPo);
}
} else {
contractResultDto = new ContractResultDto(contractExecuteResult, tx);
}
break;
} else {
flag = false;
msg = TransactionErrorCode.DATA_NOT_FOUND.getMsg();
break;
}
} while (false);
Map<String, Object> resultMap = MapUtil.createLinkedHashMap(2);
resultMap.put("flag", flag);
if (!flag && StringUtils.isNotBlank(msg)) {
resultMap.put("msg", msg);
}
if (flag && contractResultDto != null) {
List<ContractTokenTransferDto> tokenTransfers = contractResultDto.getTokenTransfers();
List<ContractTokenTransferDto> realTokenTransfers = this.filterRealTokenTransfers(tokenTransfers);
contractResultDto.setTokenTransfers(realTokenTransfers);
resultMap.put("data", contractResultDto);
}
return Result.getSuccess().setData(resultMap).toRpcClientResult();
} catch (Exception e) {
Log.error(e);
return Result.getFailed().setMsg(e.getMessage()).toRpcClientResult();
}
}
use of io.nuls.contract.entity.txdata.ContractData 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;
}
Aggregations