use of io.nuls.contract.entity.tx.ContractTransferTransaction in project nuls by nuls-io.
the class CallContractTxProcessor method onRollback.
@Override
public Result onRollback(CallContractTransaction tx, Object secondaryData) {
try {
// 回滚代币转账交易
byte[] txHashBytes = null;
try {
txHashBytes = tx.getHash().serialize();
} catch (IOException e) {
Log.error(e);
}
ContractResult contractResult = tx.getContractResult();
if (contractResult == null) {
contractResult = contractService.getContractExecuteResult(tx.getHash());
}
CallContractData txData = tx.getTxData();
byte[] senderContractAddressBytes = txData.getContractAddress();
Result<ContractAddressInfoPo> senderContractAddressInfoResult = contractAddressStorageService.getContractAddressInfo(senderContractAddressBytes);
ContractAddressInfoPo po = senderContractAddressInfoResult.getData();
if (po != null) {
if (contractResult != null) {
// 处理合约执行失败 - 没有transferEvent的情况, 直接从数据库中删除
if (!contractResult.isSuccess()) {
if (ContractUtil.isTransferMethod(txData.getMethodName())) {
contractTokenTransferStorageService.deleteTokenTransferInfo(ArraysTool.concatenate(txData.getSender(), txHashBytes, new VarInt(0).encode()));
}
}
List<String> events = contractResult.getEvents();
int size = events.size();
// 目前只处理Transfer事件
String event;
ContractAddressInfoPo contractAddressInfo;
if (events != null && size > 0) {
for (int i = 0; i < size; i++) {
event = events.get(i);
// 按照NRC20标准,TransferEvent事件中第一个参数是转出地址-from,第二个参数是转入地址-to, 第三个参数是金额
ContractTokenTransferInfoPo tokenTransferInfoPo = ContractUtil.convertJsonToTokenTransferInfoPo(event);
if (tokenTransferInfoPo == null) {
continue;
}
String contractAddress = tokenTransferInfoPo.getContractAddress();
if (StringUtils.isBlank(contractAddress)) {
continue;
}
if (!AddressTool.validAddress(contractAddress)) {
continue;
}
byte[] contractAddressBytes = AddressTool.getAddress(contractAddress);
if (ArraysTool.arrayEquals(senderContractAddressBytes, contractAddressBytes)) {
contractAddressInfo = po;
} else {
Result<ContractAddressInfoPo> contractAddressInfoResult = contractAddressStorageService.getContractAddressInfo(contractAddressBytes);
contractAddressInfo = contractAddressInfoResult.getData();
}
if (contractAddressInfo == null) {
continue;
}
// 事件不是NRC20合约的事件
if (!contractAddressInfo.isNrc20()) {
continue;
}
// 回滚token余额
this.rollbackContractToken(tokenTransferInfoPo);
contractTokenTransferStorageService.deleteTokenTransferInfo(ArraysTool.concatenate(tokenTransferInfoPo.getFrom(), txHashBytes, new VarInt(i).encode()));
contractTokenTransferStorageService.deleteTokenTransferInfo(ArraysTool.concatenate(tokenTransferInfoPo.getTo(), txHashBytes, new VarInt(i).encode()));
}
}
}
}
// 删除子交易从全网账本
// 删除子交易从合约账本
// 删除子交易从本地账本
List<ContractTransferTransaction> contractTransferTxList = this.extractContractTransferTxs(contractResult);
if (contractTransferTxList != null && !contractTransferTxList.isEmpty()) {
// 用于回滚本地账本
List<Transaction> txList = new ArrayList<>();
for (ContractTransferTransaction transferTx : contractTransferTxList) {
try {
txList.add(transferTx);
Result result = ledgerService.rollbackTx(transferTx);
if (result.isFailed()) {
Log.error("rollback contract transfer tx from ledger error. msg: {}", result.getMsg());
return result;
}
result = contractService.rollbackContractTransferTx(transferTx);
if (result.isFailed()) {
Log.error("rollback contract transfer tx from contract ledger error. msg: {}", result.getMsg());
return Result.getFailed();
}
} catch (Exception e) {
Log.error("rollback contract transfer tx error. msg: {}", e.getMessage());
return Result.getFailed();
}
}
Result result = accountLedgerService.rollbackTransactions(txList);
if (result.isFailed()) {
Log.error("rollback contract transfer tx from account ledger error. msg: {}", result.getMsg());
return Result.getFailed();
}
}
// 删除合约调用交易的UTXO
contractUtxoService.deleteUtxoOfTransaction(tx);
// 删除合约执行结果
contractService.deleteContractExecuteResult(tx.getHash());
} catch (Exception e) {
Log.error("rollback call contract tx error.", e);
return Result.getFailed();
}
return Result.getSuccess();
}
use of io.nuls.contract.entity.tx.ContractTransferTransaction in project nuls by nuls-io.
the class ContractTransferTransactionStorageImpl method loadAllContractTransferTxList.
@Override
public List<ContractTransferTransaction> loadAllContractTransferTxList() throws NulsException {
List<ContractTransferTransaction> txList = new ArrayList<>();
List<Entry<byte[], byte[]>> entryList = dbService.entryList(ContractStorageConstant.DB_NAME_CONTRACT_SPECIAL_TX);
if (entryList == null || entryList.isEmpty()) {
return txList;
}
ContractTransferTransaction tx;
for (Entry<byte[], byte[]> entry : entryList) {
tx = new ContractTransferTransaction();
tx.parse(entry.getValue(), 0);
txList.add(tx);
}
return txList;
}
use of io.nuls.contract.entity.tx.ContractTransferTransaction in project nuls by nuls-io.
the class ContractTransferTransactionStorageImpl method getContractTransferTx.
@Override
public Result<ContractTransferTransaction> getContractTransferTx(NulsDigestData hash) {
try {
byte[] txBytes = dbService.get(ContractStorageConstant.DB_NAME_CONTRACT_SPECIAL_TX, hash.serialize());
if (txBytes == null) {
return Result.getSuccess();
}
ContractTransferTransaction contractTransferTransaction = new ContractTransferTransaction();
contractTransferTransaction.parse(txBytes, 0);
return Result.getSuccess().setData(contractTransferTransaction);
} catch (Exception e) {
Log.error(e);
return Result.getFailed();
}
}
use of io.nuls.contract.entity.tx.ContractTransferTransaction in project nuls by nuls-io.
the class CallContractTxProcessor method onCommit.
@Override
public Result onCommit(CallContractTransaction tx, Object secondaryData) {
try {
ContractResult contractResult = tx.getContractResult();
// 保存调用合约交易的UTXO
Result utxoResult = contractUtxoService.saveUtxoForContractAddress(tx);
if (utxoResult.isFailed()) {
Log.error("save confirmed contract utxo error, reason is {}.", utxoResult.getMsg());
return utxoResult;
}
long blockHeight = tx.getBlockHeight();
/**
* 保存子交易到全网账本、合约账本、本地账本
*/
Collection<ContractTransferTransaction> contractTransferTxs = tx.getContractTransferTxs();
if (contractTransferTxs != null && contractTransferTxs.size() > 0) {
for (ContractTransferTransaction transferTx : contractTransferTxs) {
try {
transferTx.setBlockHeight(blockHeight);
Result result = ledgerService.saveTx(transferTx);
if (result.isFailed()) {
Log.error("save contract transfer tx to ledger error. msg: {}", result.getMsg());
return result;
}
result = contractService.saveContractTransferTx(transferTx);
if (result.isFailed()) {
Log.error("save contract transfer tx to contract ledger error. msg: {}", result.getMsg());
return result;
}
result = accountLedgerService.saveConfirmedTransaction(transferTx);
if (result.isFailed()) {
Log.error("save contract transfer tx to account ledger error. msg: {}", result.getMsg());
return result;
}
} catch (Exception e) {
e.printStackTrace();
Log.error("save contract transfer tx error. msg: {}", e.getMessage());
return Result.getFailed();
}
}
}
// 保存代币交易
CallContractData callContractData = tx.getTxData();
byte[] contractAddress = callContractData.getContractAddress();
Result<ContractAddressInfoPo> contractAddressInfoPoResult = contractAddressStorageService.getContractAddressInfo(contractAddress);
if (contractAddressInfoPoResult.isFailed()) {
return contractAddressInfoPoResult;
}
ContractAddressInfoPo contractAddressInfoPo = contractAddressInfoPoResult.getData();
if (contractAddressInfoPo == null) {
return Result.getFailed(ContractErrorCode.CONTRACT_ADDRESS_NOT_EXIST);
}
contractResult.setNrc20(contractAddressInfoPo.isNrc20());
BlockHeader blockHeader = tx.getBlockHeader();
byte[] newestStateRoot = blockHeader.getStateRoot();
// 获取合约当前状态
ProgramStatus status = vmHelper.getContractStatus(newestStateRoot, contractAddress);
boolean isTerminatedContract = ContractUtil.isTerminatedContract(status.ordinal());
// 处理合约执行失败 - 没有transferEvent的情况, 直接从数据库中获取, 若是本地创建的交易,获取到修改为失败交易
if (isTerminatedContract || !contractResult.isSuccess()) {
if (contractAddressInfoPo != null && contractAddressInfoPo.isNrc20() && ContractUtil.isTransferMethod(callContractData.getMethodName())) {
byte[] txHashBytes = tx.getHash().serialize();
byte[] infoKey = ArraysTool.concatenate(callContractData.getSender(), txHashBytes, new VarInt(0).encode());
Result<ContractTokenTransferInfoPo> infoResult = contractTokenTransferStorageService.getTokenTransferInfo(infoKey);
ContractTokenTransferInfoPo po = infoResult.getData();
if (po != null) {
po.setStatus((byte) 2);
contractTokenTransferStorageService.saveTokenTransferInfo(infoKey, po);
// 刷新token余额
if (isTerminatedContract) {
// 终止的合约,回滚token余额
this.rollbackContractToken(po);
contractResult.setError(true);
contractResult.setErrorMessage("this contract has been terminated");
} else {
if (po.getFrom() != null) {
vmHelper.refreshTokenBalance(newestStateRoot, contractAddressInfoPo, AddressTool.getStringAddressByBytes(po.getFrom()), po.getContractAddress());
}
if (po.getTo() != null) {
vmHelper.refreshTokenBalance(newestStateRoot, contractAddressInfoPo, AddressTool.getStringAddressByBytes(po.getTo()), po.getContractAddress());
}
}
}
}
}
if (!isTerminatedContract) {
// 处理合约事件
vmHelper.dealEvents(newestStateRoot, tx, contractResult, contractAddressInfoPo);
}
// 保存合约执行结果
contractService.saveContractExecuteResult(tx.getHash(), contractResult);
} catch (Exception e) {
Log.error("save call contract tx error.", e);
return Result.getFailed();
}
return Result.getSuccess();
}
Aggregations