use of io.nuls.contract.dto.ContractTransfer in project nuls by nuls-io.
the class ContractServiceImpl method createReturnFundsContractTransfer.
private List<ContractTransfer> createReturnFundsContractTransfer(Transaction tx, Na sendBack) {
// 合约执行失败而退回的转入金额暂时不收取手续费
Na transferFee = Na.ZERO;
if (sendBack.compareTo(transferFee) <= 0) {
transferFee = sendBack;
}
List<ContractTransfer> contractTransferList = new ArrayList<>();
try {
Set<String> addressFromTX = SignatureUtil.getAddressFromTX(tx);
if (addressFromTX == null || addressFromTX.size() == 0) {
return contractTransferList;
}
Object[] array = addressFromTX.toArray();
String fromAddress = (String) array[0];
byte[] fromAddressBytes = AddressTool.getAddress(fromAddress);
CoinData coinData = tx.getCoinData();
List<Coin> toList = coinData.getTo();
HashMap<String, Na> sendBackMap = MapUtil.createHashMap(toList.size());
String ownerStr;
for (Coin coin : toList) {
if (!ArraysTool.arrayEquals(fromAddressBytes, coin.getOwner())) {
ownerStr = AddressTool.getStringAddressByBytes(coin.getOwner());
Na addressNa = sendBackMap.get(ownerStr);
if (addressNa == null) {
sendBackMap.put(ownerStr, coin.getNa());
} else {
sendBackMap.put(ownerStr, addressNa.add(coin.getNa()));
}
}
}
if (sendBackMap.size() > 0) {
for (Map.Entry<String, Na> entry : sendBackMap.entrySet()) {
ContractTransfer transfer = new ContractTransfer(AddressTool.getAddress(entry.getKey()), fromAddressBytes, entry.getValue(), transferFee, true);
contractTransferList.add(transfer);
}
}
} catch (NulsException e) {
Log.error(e);
}
return contractTransferList;
}
use of io.nuls.contract.dto.ContractTransfer in project nuls by nuls-io.
the class ContractServiceImpl method generateContractTransfer.
private List<ContractTransfer> generateContractTransfer(List<ProgramTransfer> transfers) {
if (transfers == null || transfers.size() == 0) {
return new ArrayList<>(0);
}
List<ContractTransfer> resultList = new ArrayList<>(transfers.size());
ContractTransfer contractTransfer;
for (ProgramTransfer transfer : transfers) {
contractTransfer = new ContractTransfer();
contractTransfer.setFrom(transfer.getFrom());
contractTransfer.setTo(transfer.getTo());
contractTransfer.setValue(Na.valueOf(transfer.getValue().longValue()));
contractTransfer.setFee(Na.ZERO);
resultList.add(contractTransfer);
}
return resultList;
}
use of io.nuls.contract.dto.ContractTransfer in project nuls by nuls-io.
the class ContractServiceImpl method filterContractNa.
private LinkedHashMap<String, Na>[] filterContractNa(List<ContractTransfer> transfers) {
LinkedHashMap<String, Na> contractOutNa = MapUtil.createLinkedHashMap(4);
LinkedHashMap<String, Na> contractInNa = MapUtil.createLinkedHashMap(4);
LinkedHashMap<String, Na>[] contracts = new LinkedHashMap[2];
contracts[0] = contractOutNa;
contracts[1] = contractInNa;
byte[] from, to;
Na transferValue;
for (ContractTransfer transfer : transfers) {
from = transfer.getFrom();
to = transfer.getTo();
transferValue = transfer.getValue();
if (ContractUtil.isLegalContractAddress(from)) {
String contract = asString(from);
Na na = contractOutNa.get(contract);
if (na == null) {
contractOutNa.put(contract, transferValue);
} else {
contractOutNa.put(contract, na.add(transferValue));
}
}
if (ContractUtil.isLegalContractAddress(to)) {
String contract = asString(to);
Na na = contractInNa.get(contract);
if (na == null) {
contractInNa.put(contract, transferValue);
} else {
contractInNa.put(contract, na.add(transferValue));
}
}
}
return contracts;
}
use of io.nuls.contract.dto.ContractTransfer in project nuls by nuls-io.
the class ContractServiceImpl method handleContractTransferTxs.
private byte[] handleContractTransferTxs(CallContractTransaction tx, ContractResult contractResult, byte[] stateRoot, byte[] preStateRoot, List<ContractTransfer> transfers, long time, Map<String, Coin> toMaps, Map<String, Coin> contractUsedCoinMap, Long blockHeight) {
boolean isCorrectContractTransfer = true;
// 用于保存本次交易产生的合约转账(从合约转出)交易
Map<String, ContractTransferTransaction> successContractTransferTxs = new LinkedHashMap<>();
// 创建合约转账(从合约转出)交易
if (transfers != null && transfers.size() > 0) {
Result<ContractTransferTransaction> contractTransferResult;
do {
// 验证合约转账(从合约转出)交易的最小转移金额
Result result = this.verifyTransfer(transfers);
if (result.isFailed()) {
isCorrectContractTransfer = false;
contractResult.setError(true);
String errorMsg = contractResult.getErrorMessage();
errorMsg = errorMsg == null ? result.getErrorCode().getEnMsg() : (errorMsg + "," + result.getErrorCode().getEnMsg());
contractResult.setErrorMessage(errorMsg);
break;
}
// 合约转账(从合约转出)使用的交易时间为区块时间
ContractTransferTransaction contractTransferTx;
for (ContractTransfer transfer : transfers) {
// 保存外部合约交易hash
transfer.setOrginHash(tx.getHash());
contractTransferResult = this.createContractTransferTx(transfer, time, toMaps, contractUsedCoinMap, blockHeight);
if (contractTransferResult.isFailed()) {
this.rollbackContractTransferTxs(successContractTransferTxs, toMaps, contractUsedCoinMap);
isCorrectContractTransfer = false;
contractResult.setError(true);
String errorMsg = contractResult.getErrorMessage();
errorMsg = errorMsg == null ? contractTransferResult.getMsg() : (errorMsg + "," + contractTransferResult.getMsg());
contractResult.setErrorMessage(errorMsg);
break;
}
contractTransferTx = contractTransferResult.getData();
// 保存内部转账交易hash
transfer.setHash(contractTransferTx.getHash());
successContractTransferTxs.put(contractTransferTx.getHash().getDigestHex(), contractTransferTx);
}
} while (false);
// 如果合约转账(从合约转出)出现错误,整笔合约交易视作合约执行失败
if (!isCorrectContractTransfer) {
if (Log.isDebugEnabled()) {
Log.debug("contract transfer execution failed, reason: {}", contractResult.getErrorMessage());
}
// 执行合约产生的状态根回滚到上一个世界状态
stateRoot = preStateRoot;
contractResult.setStateRoot(stateRoot);
// 余额还原到上一次的余额
contractResult.setBalance(contractResult.getPreBalance());
// 清空成功转账列表
successContractTransferTxs.clear();
// 回滚临时余额
this.rollbackContractTempBalance(tx, contractResult);
// 清空内部转账列表
transfers.clear();
// 合约转账(从合约转出)交易失败,且调用者存在资金转入合约地址,创建一笔合约转账(从合约转出),退回这笔资金
if (contractResult.getValue() > 0) {
Na sendBack = Na.valueOf(contractResult.getValue());
List<ContractTransfer> transferList = this.createReturnFundsContractTransfer(tx, sendBack);
for (ContractTransfer transfer : transferList) {
transfer.setOrginHash(tx.getHash());
contractTransferResult = this.createContractTransferTx(transfer, time, toMaps, contractUsedCoinMap, blockHeight);
if (contractTransferResult.isFailed()) {
successContractTransferTxs.clear();
contractResult.setErrorMessage(contractResult.getErrorMessage() + ", " + contractTransferResult.getMsg());
break;
} else {
ContractTransferTransaction _contractTransferTx = contractTransferResult.getData();
// 保存内部转账交易hash和外部合约交易hash
transfer.setHash(_contractTransferTx.getHash());
transfers.add(transfer);
successContractTransferTxs.put(_contractTransferTx.getHash().getDigestHex(), _contractTransferTx);
}
}
}
} else {
// 归集转入合约地址的UTXOs
this.contractExchange(tx, contractResult, time, toMaps, contractUsedCoinMap, blockHeight, transfers, successContractTransferTxs);
}
// 保存内部转账子交易到父交易对象中
tx.setContractTransferTxs(successContractTransferTxs.values());
} else {
// `transfers.size() == 0` 智能合约在打包节点上只执行一次(打包区块和验证区块), 打包节点在打包时已处理过, 不重复处理
if (null != transfers && transfers.size() == 0) {
this.contractExchange(tx, contractResult, time, toMaps, contractUsedCoinMap, blockHeight, transfers, successContractTransferTxs);
tx.setContractTransferTxs(successContractTransferTxs.values());
}
}
// 合约执行成功并且合约转账(从合约转出)执行成功,提交这笔交易
if (contractResult.isSuccess() && isCorrectContractTransfer) {
Object txTrackObj = contractResult.getTxTrack();
if (txTrackObj != null && txTrackObj instanceof ProgramExecutor) {
ProgramExecutor txTrack = (ProgramExecutor) txTrackObj;
if (Log.isDebugEnabled()) {
Log.debug("===tx track commit.");
}
txTrack.commit();
}
}
return stateRoot;
}
use of io.nuls.contract.dto.ContractTransfer in project nuls by nuls-io.
the class ContractServiceImpl method doContractExchange.
private void doContractExchange(NulsDigestData hash, byte[] contractAddress, long transferValue, long time, Map<String, Coin> toMaps, Map<String, Coin> contractUsedCoinMap, Long blockHeight, List<ContractTransfer> transfers, Map<String, ContractTransferTransaction> successContractTransferTxs) {
BigInteger currentBalance = vmContext.getBalance(contractAddress, blockHeight);
long currentBalanceLongValue = currentBalance.longValue();
if (currentBalanceLongValue == 0 || currentBalanceLongValue == transferValue) {
// 余额等于0不归集
return;
}
ContractTransfer transfer = new ContractTransfer(contractAddress, contractAddress, Na.valueOf(currentBalanceLongValue), Na.ZERO, false);
transfer.setOrginHash(hash);
Result<ContractTransferTransaction> contractTransferResult = this.createContractTransferTx(transfer, time, toMaps, contractUsedCoinMap, blockHeight);
if (contractTransferResult.isSuccess()) {
ContractTransferTransaction _contractTransferTx = contractTransferResult.getData();
if (!this.needExchange(_contractTransferTx)) {
return;
}
Log.info("Contract UTXOs need exchange, orgin tx hash is {}, current tx hash is {}", hash.toString(), _contractTransferTx.getHash().toString());
// 保存内部转账交易hash和外部合约交易hash
transfer.setHash(_contractTransferTx.getHash());
transfers.add(transfer);
successContractTransferTxs.put(_contractTransferTx.getHash().getDigestHex(), _contractTransferTx);
}
}
Aggregations